Skip to content

Commit

Permalink
V2 beta1 (#326)
Browse files Browse the repository at this point in the history
* style: labels on added time

* style: remove mentions of PiP

* refactor: unify usage of ms for timers

* refactor: create events with 0 duration

* style: several small tweaks

* refactor: keep block when applying delays

* feat: blocks have titles

* style: improvements in time entry warnings

* style: override progress bar styles

* style: prevent overflow

* feat: show character count in editor

* refactor: provide initial payload

* refactor: lower test boundary

* refactor: get colour from swatches

* style: rename title block

* chore: version bump
  • Loading branch information
cpvalente authored Apr 5, 2023
1 parent 0a68377 commit 5e481d4
Show file tree
Hide file tree
Showing 57 changed files with 556 additions and 276 deletions.
2 changes: 1 addition & 1 deletion apps/client/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ontime-ui",
"version": "2.0.0-beta1",
"version": "2.0.0-beta2",
"private": true,
"dependencies": {
"@chakra-ui/react": "^2.5.1",
Expand Down
2 changes: 0 additions & 2 deletions apps/client/src/appConstants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ const minimalLocation = 'minimal';
const speakerLocation = 'speaker';
const smLocation = 'sm';
const publicLocation = 'public';
const pipLocation = 'pip';
const studioLocation = 'studio';
const cuesheetLocation = 'cuesheet';
const countdownLocation = 'countdown';
Expand All @@ -17,7 +16,6 @@ export const viewerLocations = [
{ link: smLocation, label: 'Backstage screen' },
{ link: publicLocation, label: 'Public screen' },
{ link: lowerLocation, label: 'Lower thirds' },
{ link: pipLocation, label: 'Picture in Picture' },
{ link: studioLocation, label: 'Studio clock' },
{ link: countdownLocation, label: 'Countdown' },
{ link: cuesheetLocation, label: 'Cuesheet' },
Expand Down

This file was deleted.

This file was deleted.

26 changes: 26 additions & 0 deletions apps/client/src/common/components/input/colour-input/Swatch.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
import { IoBan } from '@react-icons/all-files/io5/IoBan';

import { cx } from '../../../utils/styleUtils';

import style from './SwatchSelect.module.scss';

interface SwatchProps {
color: string;
onClick: (color: string) => void;
isSelected?: boolean;
}

export default function Swatch(props: SwatchProps) {
const { color, isSelected, onClick } = props;

const classes = cx([style.swatch, isSelected ? style.selected : null]);

if (!color) {
return (
<div className={`${classes} ${style.center}`}>
<IoBan />
</div>
);
}
return <div className={classes} style={{ backgroundColor: `${color}` }} onClick={() => onClick(color)} />;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@

.list {
display: flex;
gap: 4px;
}

.swatch {
cursor: pointer;
aspect-ratio: 1;
width: 2rem;
height: 2rem;
border-radius: 16px;
border: 4px solid #262626;

&.selected {
border: 2px solid #578AF4;
}
}

.center {
display: grid;
place-content: center;
color: #578AF4;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { useCallback } from 'react';

import { EventEditorSubmitActions } from '../../../../features/event-editor/EventEditor';

import Swatch from './Swatch';

import style from './SwatchSelect.module.scss';

interface ColourInputProps {
value: string;
name: EventEditorSubmitActions;
handleChange: (newValue: EventEditorSubmitActions, name: string) => void;
}

const colours = [
'',
'#FFCC78', // $orange-400
'#FFAB33', // $orange-600
'#77C785', // $green-400
'#339E4E', // $green-600
'#779BE7', // $blue-400
'#3E75E8', // $blue-600
'#FF7878', // $red-400
'#ED3333', // $red-600
'#A790F5', // $violet-400
'#8064E1', // $violet-600
'#9d9d9d', // $gray-500
'#ececec', // $gray-100
];

export default function SwatchSelect(props: ColourInputProps) {
const { value, name, handleChange } = props;

const setColour = useCallback(
(newValue: string) => {
if (newValue !== value) {
handleChange(name, newValue);
}
},
[handleChange, name, value],
);

return (
<div className={style.list}>
{colours.map((colour) => (
<Swatch key={colour} color={colour} onClick={setColour} isSelected={value === colour} />
))}
</div>
);
}
28 changes: 17 additions & 11 deletions apps/client/src/common/components/input/delay-input/DelayInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ const inputStyleProps = {
size: 'sm',
color: '#E69056',
variant: 'ontime-filled',
fontSize: '15px',
letterSpacing: '0.3px',
};

interface DelayInputProps {
Expand All @@ -24,7 +26,9 @@ export default function DelayInput(props: DelayInputProps) {
const inputRef = useRef<HTMLInputElement | null>(null);

useEffect(() => {
if (value == null) return;
if (!value) {
return;
}
setValue(value);
}, [value]);

Expand All @@ -36,7 +40,6 @@ export default function DelayInput(props: DelayInputProps) {
(newValue?: string) => {
if (newValue === '') setValue(0);
const delayValue = clamp(Number(newValue), -60, 60);

if (delayValue === value) return;
setValue(delayValue);

Expand All @@ -49,15 +52,18 @@ export default function DelayInput(props: DelayInputProps) {
* @description Handles common keys for submit and cancel
* @param {KeyboardEvent} event
*/
const onKeyDownHandler = useCallback((key: string) => {
if (key === 'Enter') {
inputRef.current?.blur();
validate(inputRef.current?.value);
} else if (key === 'Escape') {
inputRef.current?.blur();
setValue(value);
}
}, [validate, value]);
const onKeyDownHandler = useCallback(
(key: string) => {
if (key === 'Enter') {
inputRef.current?.blur();
validate(inputRef.current?.value);
} else if (key === 'Escape') {
inputRef.current?.blur();
setValue(value);
}
},
[validate, value],
);

const labelText = `${Math.abs(value) !== 1 ? 'minutes' : 'minute'} ${
value !== undefined && value >= 0 ? 'delayed' : 'ahead'
Expand Down
17 changes: 13 additions & 4 deletions apps/client/src/common/components/input/text-input/TextInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,31 @@ interface BaseProps {
submitHandler: (field: EventEditorSubmitActions, newValue: string) => void;
}

interface TextAreaProps {
interface TextInputProps extends BaseProps {
isTextArea?: false;
}

interface TextAreaProps extends BaseProps {
isTextArea: true;
resize?: 'horizontal' | 'vertical' | 'none';
}

type TextInputProps = BaseProps & TextAreaProps;
type InputProps = TextInputProps | TextAreaProps;

export default function TextInput(props: TextInputProps) {
const { isTextArea, isFullHeight, size = 'sm', field, initialText = '', submitHandler, resize = 'none' } = props;
export default function TextInput(props: InputProps) {
const { isTextArea, isFullHeight, size = 'sm', field, initialText = '', submitHandler } = props;
const inputRef = useRef(null);

const submitCallback = useCallback((newValue: string) => submitHandler(field, newValue), [field, submitHandler]);

const textInputProps = useReactiveTextInput(initialText, submitCallback, { submitOnEnter: true });
const textAreaProps = useReactiveTextInput(initialText, submitCallback);

let resize = 'none';
if (isTextArea) {
resize = (props as TextAreaProps)?.resize ?? 'none';
}

return isTextArea ? (
<Textarea
ref={inputRef}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { ChangeEvent, useCallback, useEffect, useState } from 'react';
import { ChangeEvent, KeyboardEvent, useCallback, useEffect, useState } from 'react';

interface UseReactiveTextInputReturn {
value: string;
Expand All @@ -14,8 +14,7 @@ export default function useReactiveTextInput(
submitOnEnter?: boolean;
},
): UseReactiveTextInputReturn {
const [text, setText] = useState(initialText);

const [text, setText] = useState<string>(initialText);

useEffect(() => {
if (typeof initialText === 'undefined') {
Expand Down Expand Up @@ -58,7 +57,6 @@ export default function useReactiveTextInput(
[initialText, submitCallback],
);


/**
* @description Handles common keys for submit and cancel
* @param {string} key
Expand All @@ -81,8 +79,8 @@ export default function useReactiveTextInput(

return {
value: text,
onChange: (event) => handleChange((event.target as HTMLInputElement).value),
onBlur: (event) => handleSubmit((event.target as HTMLInputElement).value),
onKeyDown: (event) => keyHandler(event.key),
onChange: (event: ChangeEvent) => handleChange((event.target as HTMLInputElement).value),
onBlur: (event: ChangeEvent) => handleSubmit((event.target as HTMLInputElement).value),
onKeyDown: (event: KeyboardEvent) => keyHandler(event.key),
};
}
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
@use "../../../../theme/v2Styles" as *;

$input-font-size: 15px;
$input-delayed-border-color: #E69056;

.timeInput {
width: fit-content !important;

.inputLeft {
max-width: fit-content;
}

.inputLeft,
.inputButton {
aspect-ratio: 1;
}
Expand All @@ -15,6 +22,13 @@ $input-delayed-border-color: #E69056;
padding: 0 0 0 2.6em;
}

.warn {
&::after {
content: "*";
color: $warning-orange;
}
}

&.delayed {
.inputField {
border: 1px solid $input-delayed-border-color;
Expand Down
23 changes: 13 additions & 10 deletions apps/client/src/common/components/input/time-input/TimeInput.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,27 @@ import { FocusEvent, KeyboardEvent, useCallback, useEffect, useRef, useState } f
import { Button, Input, InputGroup, InputLeftElement, Tooltip } from '@chakra-ui/react';
import { millisToString } from 'ontime-utils';

import { EventEditorSubmitActions } from '../../../../features/event-editor/EventEditor';
import { tooltipDelayFast } from '../../../../ontimeConfig';
import { useEmitLog } from '../../../stores/logger';
import { forgivingStringToMillis } from '../../../utils/dateConfig';
import { cx } from '../../../utils/styleUtils';
import { TimeEntryField } from '../../../utils/timesManager';

import style from './TimeInput.module.scss';

interface TimeInputProps {
name: TimeEntryField;
submitHandler: (field: EventEditorSubmitActions, value: number) => void;
submitHandler: (field: TimeEntryField, value: number) => void;
time?: number;
delay?: number;
placeholder: string;
validationHandler: (entry: TimeEntryField, val: number) => boolean;
previousEnd?: number;
warning?: string;
}

export default function TimeInput(props: TimeInputProps) {
const { name, submitHandler, time = 0, delay = 0, placeholder, validationHandler, previousEnd = 0 } = props;
const { name, submitHandler, time = 0, delay = 0, placeholder, validationHandler, previousEnd = 0, warning } = props;
const { emitError } = useEmitLog();
const inputRef = useRef<HTMLInputElement | null>(null);
const [value, setValue] = useState('');
Expand All @@ -30,7 +31,6 @@ export default function TimeInput(props: TimeInputProps) {
* @description Resets input value to given
*/
const resetValue = useCallback(() => {
// Todo: check if change is necessary
try {
setValue(millisToString(time + delay));
} catch (error) {
Expand Down Expand Up @@ -149,20 +149,23 @@ export default function TimeInput(props: TimeInputProps) {
};

const ButtonTooltip = () => {
if (name === 'timeStart') return 'Start';
if (name === 'timeEnd') return 'End';
if (name === 'durationOverride') return 'Duration';
if (name === 'timeStart') return `Start${warning ? `: ${warning}` : ''}`;
if (name === 'timeEnd') return `End${warning ? `: ${warning}` : ''}`;
if (name === 'durationOverride') return `Duration${warning ? `: ${warning}` : ''}`;
return '';
};

const inputClasses = cx([style.timeInput, isDelayed ? style.delayed : null]);
const buttonClasses = cx([style.inputButton, isDelayed ? style.delayed : null, warning ? style.warn : null]);

return (
<InputGroup size='sm' className={`${style.timeInput} ${isDelayed ? style.delayed : ''}`}>
<InputLeftElement width='fit-content'>
<InputGroup size='sm' className={inputClasses}>
<InputLeftElement className={style.inputLeft}>
<Tooltip label={ButtonTooltip()} openDelay={tooltipDelayFast} variant='ontime-ondark'>
<Button
size='sm'
variant='ontime-subtle-white'
className={`${style.inputButton} ${isDelayed ? style.delayed : ''}`}
className={buttonClasses}
tabIndex={-1}
border={isDelayed ? '1px solid #E69056' : '1px solid transparent'}
borderRight='1px solid transparent'
Expand Down
Loading

0 comments on commit 5e481d4

Please sign in to comment.