V2 styles part2 (#233)

* style: create tag to display network messages
* style: create button style for playback
* style: review style for QuickEntry
* style: review style for Info panel
* style: review style for Event blocks
* style: review style for Message control panel
* style: review style for Playback control
* style: review application styles
* style: review block styles
* refactor: TapButton has active state
* style: small style tweaks
* refactor: type checks
This commit is contained in:
Carlos Valente
2022-10-26 15:12:57 +02:00
committed by GitHub
parent 1b1aced296
commit 54442dc9a1
42 changed files with 611 additions and 405 deletions
@@ -3,8 +3,6 @@ import { FiClock } from '@react-icons/all-files/fi/FiClock';
import { FiMinusCircle } from '@react-icons/all-files/fi/FiMinusCircle'; import { FiMinusCircle } from '@react-icons/all-files/fi/FiMinusCircle';
import { FiPlus } from '@react-icons/all-files/fi/FiPlus'; import { FiPlus } from '@react-icons/all-files/fi/FiPlus';
import { tooltipDelayMid } from '../../../ontimeConfig';
interface ActionButtonProps { interface ActionButtonProps {
showAdd?: boolean; showAdd?: boolean;
showDelay?: boolean; showDelay?: boolean;
@@ -22,14 +20,14 @@ export default function ActionButtons(props: ActionButtonProps) {
return ( return (
<Menu isLazy lazyBehavior='unmount'> <Menu isLazy lazyBehavior='unmount'>
<Tooltip label='Add ...' openDelay={tooltipDelayMid}> <Tooltip label='Add ...'>
<MenuButton <MenuButton
as={IconButton} as={IconButton}
aria-label='Options' aria-label='Options'
size='sm' size='sm'
icon={<FiPlus />} icon={<FiPlus />}
colorScheme='blue' colorScheme='white'
variant='ghost' variant='outline'
/> />
</Tooltip> </Tooltip>
<MenuList style={menuStyle}> <MenuList style={menuStyle}>
@@ -1,34 +0,0 @@
import { useCallback, useState } from 'react';
import { IconButton, Tooltip } from '@chakra-ui/react';
import PropTypes from 'prop-types';
export default function TooltipLoadingActionBtn(props) {
const { clickHandler, icon, size = 'xs', tooltip, ...rest } = props;
const [loading, setLoading] = useState(false);
const handleClick = useCallback(() => {
setLoading(true);
clickHandler();
}, [clickHandler, setLoading]);
return (
<Tooltip label={tooltip} shouldWrapChildren={loading}>
<IconButton
aria-label={tooltip}
size={size}
icon={icon}
onClick={handleClick}
disabled={loading}
isLoading={loading}
{...rest}
/>
</Tooltip>
);
}
TooltipLoadingActionBtn.propTypes = {
clickHandler: PropTypes.func,
icon: PropTypes.element,
size: PropTypes.oneOf(['xs', 'sm', 'md', 'lg']),
tooltip: PropTypes.string,
};
@@ -0,0 +1,33 @@
import { useCallback, useState } from 'react';
import { IconButton, IconButtonProps, Tooltip } from '@chakra-ui/react';
interface TooltipLoadingActionBtnProps extends IconButtonProps {
clickHandler: () => void;
tooltip: string;
openDelay?: number;
}
export default function TooltipLoadingActionBtn(props: TooltipLoadingActionBtnProps) {
const { clickHandler, icon, size = 'xs', tooltip, openDelay = 0, ...rest } = props;
const [loading, setLoading] = useState(false);
const handleClick = useCallback(() => {
setLoading(true);
clickHandler();
}, [clickHandler, setLoading]);
return (
<Tooltip label={tooltip} shouldWrapChildren={loading} openDelay={openDelay}>
<IconButton
{...rest}
aria-label={tooltip}
size={size}
icon={icon}
onClick={handleClick}
disabled={loading}
isLoading={loading}
/>
</Tooltip>
);
}
@@ -1,21 +1,14 @@
@use '../../../theme/main' as *; @use '../../../theme/main' as *;
.header, .header {
.headerRoll {
padding: 0; padding: 0;
margin: 0; margin: 0;
font-size: 0.9em; font-size: 0.9em;
display: flex; display: flex;
justify-content: space-between; justify-content: space-between;
}
.header {
color: $header-gray; color: $header-gray;
} }
.headerRoll {
color: $ontime-roll;
}
.moreExpanded, .moreExpanded,
.moreCollapsed { .moreCollapsed {
@@ -1,11 +1,12 @@
import { useCallback, useContext, useEffect, useRef, useState } from 'react'; import { useCallback, useContext, useEffect, useRef, useState } from 'react';
import { IconButton, Input, InputGroup, InputLeftElement } from '@chakra-ui/react'; import { Button, Input, InputGroup, InputLeftElement, Tooltip } from '@chakra-ui/react';
import { IoLink } from '@react-icons/all-files/io5/IoLink';
import { LoggingContext } from 'common/context/LoggingContext'; import { LoggingContext } from 'common/context/LoggingContext';
import { forgivingStringToMillis } from 'common/utils/dateConfig'; import { forgivingStringToMillis } from 'common/utils/dateConfig';
import { stringFromMillis } from 'common/utils/time'; import { stringFromMillis } from 'common/utils/time';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { tooltipDelayFast } from '../../../ontimeConfig';
import style from './TimeInput.module.scss'; import style from './TimeInput.module.scss';
export default function TimeInput(props) { export default function TimeInput(props) {
@@ -126,18 +127,46 @@ export default function TimeInput(props) {
const isDelayed = delay != null && delay !== 0; const isDelayed = delay != null && delay !== 0;
/*
<IconButton
size='sm'
icon="s"
aria-label='automate'
colorScheme='white'
style={{ borderRadius: '2px', width: 'min-content' }}
tabIndex={-1}
variant='ghost'
/>
*/
const buttonInitial = () => {
if (name === 'timeStart') return 'S';
if (name === 'timeEnd') return 'E';
if (name === 'duration') return 'D';
}
const buttonTooltip = () => {
if (name === 'timeStart') return 'Start';
if (name === 'timeEnd') return 'End';
if (name === 'duration') return 'Duration';
}
return ( return (
<InputGroup size='sm' className={`${style.timeInput} ${isDelayed ? style.delayed : ''}`}> <InputGroup size='sm' className={`${style.timeInput} ${isDelayed ? style.delayed : ''}`}>
<InputLeftElement width='fit-content'> <InputLeftElement width='fit-content'>
<IconButton <Tooltip label={buttonTooltip()} openDelay={tooltipDelayFast}>
<Button
size='sm' size='sm'
icon={<IoLink style={{ transform: 'rotate(-45deg)' }} />} variant='filled'
aria-label='automate'
colorScheme='blue'
style={{ borderRadius: '2px', width: 'min-content' }}
tabIndex={-1} tabIndex={-1}
variant='ghost' backgroundColor='#303030'
/> color='#fffffa'
borderRadius='2px 0 0 2px'
border={isDelayed ? "1px solid #d69e2e55" : "1px solid transparent"}
>
{buttonInitial()}
</Button>
</Tooltip>
</InputLeftElement> </InputLeftElement>
<Input <Input
ref={inputRef} ref={inputRef}
@@ -0,0 +1,26 @@
@use '../../../theme/main' as *;
.copyTag {
display: flex;
border-radius: 2px;
border: 1px solid $action-blue;
cursor: pointer;
font-size: 0.75em;
width: max-content;
&:active {
border: 1px solid $text-white;
}
}
.label {
background-color: $action-blue;
color: $text-white;
padding: 0 4px;
font-weight: 600;
}
.text {
color: $label-gray;
padding: 0 4px;
}
@@ -0,0 +1,34 @@
import { PropsWithChildren } from 'react';
import { Tooltip } from '@chakra-ui/react';
import { tooltipDelayFast } from '../../../ontimeConfig';
import style from './CopyTag.module.scss';
interface CopyTagProps {
label?: string;
className?: string;
}
export default function CopyTag(props: PropsWithChildren<CopyTagProps>) {
const { label, className, children } = props;
return (
<Tooltip label='Click to copy' openDelay={tooltipDelayFast}>
<button
className={`${style.copyTag} ${className}`}
onClick={() => navigator.clipboard.writeText(children as string)}
tabIndex={-1}
>
{label && (
<span className={style.label}>
{label}
</span>
)}
<span className={style.text}>
{children}
</span>
</button>
</Tooltip>
);
}
+4 -1
View File
@@ -28,10 +28,13 @@ export function formatDisplay(seconds, hideZero = false) {
/** /**
* @description Converts milliseconds to seconds * @description Converts milliseconds to seconds
* @param {number} millis - time in seconds * @param {number | null} millis - time in seconds
* @returns {number} Amount in seconds * @returns {number} Amount in seconds
*/ */
export const millisToSeconds = (millis) => { export const millisToSeconds = (millis) => {
if (millis === null) {
return 0;
}
return millis < 0 ? Math.ceil(millis / mts) : Math.floor(millis / mts); return millis < 0 ? Math.ceil(millis / mts) : Math.floor(millis / mts);
}; };
+1 -1
View File
@@ -24,7 +24,7 @@ export const nowInMillis = () => {
/** /**
* @description Converts milliseconds to string representing time * @description Converts milliseconds to string representing time
* @param {number} ms - time in milliseconds * @param {number | null} ms - time in milliseconds
* @param {boolean} showSeconds - weather to show the seconds * @param {boolean} showSeconds - weather to show the seconds
* @param {string} delim - character between HH MM SS * @param {string} delim - character between HH MM SS
* @param {string} ifNull - what to return if value is null * @param {string} ifNull - what to return if value is null
@@ -2,6 +2,7 @@ import { IconButton, Tooltip } from '@chakra-ui/react';
import { IoMicOffOutline } from '@react-icons/all-files/io5/IoMicOffOutline'; import { IoMicOffOutline } from '@react-icons/all-files/io5/IoMicOffOutline';
import { IoMicSharp } from '@react-icons/all-files/io5/IoMicSharp'; import { IoMicSharp } from '@react-icons/all-files/io5/IoMicSharp';
import CopyTag from '../../../common/components/osc-tag/CopyTag';
import { useMessageControlProvider } from '../../../common/hooks/useSocketProvider'; import { useMessageControlProvider } from '../../../common/hooks/useSocketProvider';
import { tooltipDelayMid } from '../../../ontimeConfig'; import { tooltipDelayMid } from '../../../ontimeConfig';
@@ -52,8 +53,11 @@ export default function MessageControl() {
aria-label='Toggle On Air' aria-label='Toggle On Air'
/> />
</Tooltip> </Tooltip>
<span className={style.onAirLabel}>On Air</span> <div className={style.onAirLabel}>On Air</div>
<span className={style.oscLabel}>{`/ontime/offAir << OSC >> /ontime/onAir`}</span> <div className={style.oscLabel}>
<CopyTag label='OSC'>/ontime/offAir</CopyTag>
<CopyTag label='OSC'>/ontime/offAir</CopyTag>
</div>
</div> </div>
</> </>
); );
@@ -1,15 +1,20 @@
@use '../../../theme/main' as *; @use '../../../theme/main' as *;
@use '../../../theme/mixins' as *; @use '../../../theme/mixins' as *;
@mixin message-control-label() {
font-size: 0.9em;
color: $label-gray;
}
.messageContainer, .messageContainer,
.onAirToggle { .onAirToggle {
display: flex; display: flex;
gap: 0.5em;
padding: 0.5em; padding: 0.5em;
} }
.messageContainer { .messageContainer {
flex-direction: column; flex-direction: column;
gap: 4px;
.inputItems { .inputItems {
display: grid; display: grid;
@@ -20,8 +25,7 @@
.label { .label {
padding: 0; padding: 0;
margin: 0; margin: 0;
font-size: 0.9em; @include message-control-label;
color: $label-gray;
} }
.inputRowActive { .inputRowActive {
@@ -33,25 +37,30 @@
.onAirToggle { .onAirToggle {
margin-top: 1em; margin-top: 1em;
align-items: center;
display: grid; display: grid;
grid-template-areas: grid-template-areas:
'btn label' 'btn label'
'btn osc'; 'btn osc';
grid-template-columns: 2.5em 1fr; grid-template-columns: auto 1fr;
grid-template-rows: 1.2em 0.8em; grid-template-rows: 1fr 1fr;
align-items: center;
.btn { .btn {
aspect-ratio: 1;
grid-area: btn; grid-area: btn;
height: 100%;
margin-right: 16px;
} }
.onAirLabel { .onAirLabel {
grid-area: label; grid-area: label;
font-size: 1.2em; @include message-control-label;
} }
.oscLabel { .oscLabel {
@include osc-label;
grid-area: osc; grid-area: osc;
display: flex;
gap: 4px;
} }
} }
@@ -1,43 +0,0 @@
import PropTypes from 'prop-types';
import PauseIconBtn from '../../../common/components/buttons/PauseIconBtn';
import RollIconBtn from '../../../common/components/buttons/RollIconBtn';
import StartIconBtn from '../../../common/components/buttons/StartIconBtn';
import style from './PlaybackControl.module.scss';
export default function Playback(props) {
const { playback, selectedId, playbackControl, noEvents } = props;
const isRolling = playback === 'roll';
return (
<div className={style.playbackContainer}>
<StartIconBtn
active={playback === 'start'}
clickhandler={() => playbackControl.start()}
disabled={!selectedId || isRolling || noEvents}
/>
<PauseIconBtn
active={playback === 'pause'}
clickhandler={() => playbackControl.pause()}
disabled={!selectedId || isRolling || noEvents || playback !== 'start'}
/>
<RollIconBtn
active={playback === 'roll'}
disabled={playback === 'roll' || noEvents}
clickhandler={() => playbackControl.roll()}
/>
</div>
);
}
Playback.propTypes = {
playback: PropTypes.string,
selectedId: PropTypes.string,
playbackControl: PropTypes.shape({
start: PropTypes.func,
pause: PropTypes.func,
roll: PropTypes.func,
}).isRequired,
noEvents: PropTypes.bool.isRequired,
};
@@ -0,0 +1,61 @@
import { Tooltip } from '@chakra-ui/react';
import { IoPause } from '@react-icons/all-files/io5/IoPause';
import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
import { IoTimeOutline } from '@react-icons/all-files/io5/IoTimeOutline';
import { usePlaybackControlProvider } from '../../../common/hooks/useSocketProvider';
import { Playstate } from '../../../common/models/OntimeTypes';
import { tooltipDelayMid } from '../../../ontimeConfig';
import TapButton from './TapButton';
import style from './PlaybackControl.module.scss';
interface PlaybackProps {
playback: Playstate;
selectedId: string;
noEvents: boolean;
}
export default function Playback(props: PlaybackProps) {
const { playback, selectedId, noEvents } = props;
const isRolling = playback === 'roll';
const { setPlayback } = usePlaybackControlProvider();
return (
<div className={style.playbackContainer}>
<Tooltip label='Start playback' openDelay={100}>
<TapButton
onClick={() => setPlayback.start()}
disabled={!selectedId || isRolling || noEvents}
theme='start'
active={playback === 'start'}
>
<IoPlay />
</TapButton>
</Tooltip>
<Tooltip label='Pause playback' openDelay={tooltipDelayMid}>
<TapButton
onClick={() => setPlayback.pause()}
disabled={!selectedId || isRolling || noEvents || playback !== 'start'}
theme='pause'
active={playback === 'pause'}
>
<IoPause />
</TapButton>
</Tooltip>
<Tooltip label='Start roll mode' openDelay={tooltipDelayMid}>
<TapButton
onClick={() => setPlayback.roll()}
disabled={playback === 'roll' || noEvents}
theme='roll'
active={isRolling}
>
<IoTimeOutline />
</TapButton>
</Tooltip>
</div>
);
}
@@ -8,9 +8,6 @@
gap: 4px; gap: 4px;
} }
.playbackContainer {
padding: 0.5em;
}
.timeContainer { .timeContainer {
display: grid; display: grid;
@@ -65,7 +62,7 @@
} }
.indNegativeActive { .indNegativeActive {
background-color: $ontime-pink; background-color: $ontime-pink-variant;
} }
.indDelayActive { .indDelayActive {
@@ -74,11 +71,11 @@
.btn { .btn {
grid-area: btn; grid-area: btn;
display: flex; display: grid;
flex-direction: row; grid-template-columns: 1fr 1fr;
flex-wrap: wrap; grid-template-rows: 1fr 1fr;
align-items: center; width: 100%;
justify-content: space-around; gap: 4px;
} }
.minus { .minus {
@@ -87,6 +84,12 @@
flex-direction: column; flex-direction: column;
} }
.start,
.finish,
.roll {
height: 24px;
}
.start { .start {
grid-area: sta; grid-area: sta;
} }
@@ -1,4 +1,5 @@
import { usePlaybackControlProvider } from '../../../common/hooks/useSocketProvider'; import { usePlaybackControlProvider } from '../../../common/hooks/useSocketProvider';
import { Playstate } from '../../../common/models/OntimeTypes';
import PlaybackButtons from './PlaybackButtons'; import PlaybackButtons from './PlaybackButtons';
import PlaybackTimer from './PlaybackTimer'; import PlaybackTimer from './PlaybackTimer';
@@ -6,20 +7,18 @@ import PlaybackTimer from './PlaybackTimer';
import style from './PlaybackControl.module.scss'; import style from './PlaybackControl.module.scss';
export default function PlaybackControl() { export default function PlaybackControl() {
const { data, setPlayback } = usePlaybackControlProvider(); const { data } = usePlaybackControlProvider();
return ( return (
<div className={style.mainContainer}> <div className={style.mainContainer}>
<PlaybackTimer <PlaybackTimer
playback={data.playback} playback={data.playback as Playstate}
selectedId={data.selectedEventId} selectedId={data.selectedEventId}
handleIncrement={(amount) => setPlayback.delay(amount)}
/> />
<PlaybackButtons <PlaybackButtons
playback={data.playback} playback={data.playback}
selectedId={data.selectedEventId} selectedId={data.selectedEventId}
noEvents={data.numEvents < 1} noEvents={data.numEvents < 1}
playbackControl={setPlayback}
/> />
</div> </div>
); );
@@ -1,39 +1,34 @@
import { memo } from 'react'; import { Tooltip } from '@chakra-ui/react';
import { Button, Tooltip } from '@chakra-ui/react';
import TimerDisplay from 'common/components/countdown/TimerDisplay'; import TimerDisplay from 'common/components/countdown/TimerDisplay';
import PropTypes from 'prop-types';
import { useTimerProvider } from '../../../common/hooks/useSocketProvider'; import {
usePlaybackControlProvider,
useTimerProvider,
} from '../../../common/hooks/useSocketProvider';
import { Playstate } from '../../../common/models/OntimeTypes';
import { millisToSeconds } from '../../../common/utils/dateConfig'; import { millisToSeconds } from '../../../common/utils/dateConfig';
import { stringFromMillis } from '../../../common/utils/time'; import { stringFromMillis } from '../../../common/utils/time';
import { tooltipDelayMid } from '../../../ontimeConfig'; import { tooltipDelayMid } from '../../../ontimeConfig';
import TapButton from './TapButton';
import style from './PlaybackControl.module.scss'; import style from './PlaybackControl.module.scss';
const areEqual = (prevProps, nextProps) => { interface PlaybackTimerProps {
return ( playback: Playstate;
prevProps.playback === nextProps.playback && selectedId: string | null;
prevProps.selectedId === nextProps.selectedId }
);
};
const incrementProps = { export default function PlaybackTimer(props: PlaybackTimerProps) {
size: 'sm', const { playback, selectedId } = props;
width: '2em', const { setPlayback } = usePlaybackControlProvider();
colorScheme: 'white',
variant: 'outline',
fontSize: '12px',
};
const PlaybackTimer = (props) => {
const { playback, handleIncrement, selectedId } = props;
const timerData = useTimerProvider(); const timerData = useTimerProvider();
const started = stringFromMillis(timerData.startedAt, true); const started = stringFromMillis(timerData.startedAt, true);
const finish = stringFromMillis(timerData.expectedFinish, true); const finish = stringFromMillis(timerData.expectedFinish, true);
const isRolling = playback === 'roll'; const isRolling = playback === 'roll';
const isWaiting = timerData.secondaryTimer > 0 && timerData.current == null; const isWaiting = timerData.secondaryTimer !== null && timerData.secondaryTimer > 0 && timerData.current === null;
const disableButtons = selectedId == null || isRolling; const disableButtons = selectedId == null || isRolling;
const isOvertime = timerData.current < 0; const isOvertime = timerData.current !== null && timerData.current < 0;
return ( return (
<div className={style.timeContainer}> <div className={style.timeContainer}>
@@ -68,55 +63,43 @@ const PlaybackTimer = (props) => {
</> </>
)} )}
<div className={style.btn}> <div className={style.btn}>
<Tooltip label='Remove 1 minute' openDelay={tooltipDelayMid} shouldWrapChildren={disableButtons}> <Tooltip label='Remove 1 minute' openDelay={tooltipDelayMid}
<Button shouldWrapChildren={disableButtons}>
{...incrementProps} <TapButton
onClick={() => setPlayback.delay(-5)}
disabled={disableButtons} disabled={disableButtons}
onClick={() => handleIncrement(-1)} square>
_hover={!disableButtons && { bg: '#ebedf0', color: '#333' }}
>
-1
</Button>
</Tooltip>
<Tooltip label='Add 1 minute' openDelay={tooltipDelayMid} shouldWrapChildren={disableButtons}>
<Button
{...incrementProps}
disabled={disableButtons}
onClick={() => handleIncrement(1)}
_hover={!disableButtons && { bg: '#ebedf0', color: '#333' }}
>
+1
</Button>
</Tooltip>
<Tooltip label='Remove 5 minutes' openDelay={tooltipDelayMid} shouldWrapChildren={disableButtons}>
<Button
{...incrementProps}
disabled={disableButtons}
onClick={() => handleIncrement(-5)}
_hover={!disableButtons && { bg: '#ebedf0', color: '#333' }}
>
-5 -5
</Button> </TapButton>
</Tooltip> </Tooltip>
<Tooltip label='Add 5 minutes' openDelay={tooltipDelayMid} shouldWrapChildren={disableButtons}> <Tooltip label='Remove 1 minute' openDelay={tooltipDelayMid}
<Button shouldWrapChildren={disableButtons}>
{...incrementProps} <TapButton
onClick={() => setPlayback.delay(-5)}
disabled={disableButtons} disabled={disableButtons}
onClick={() => handleIncrement(5)} square>
_hover={!disableButtons && { bg: '#ebedf0', color: '#333' }} -1
> </TapButton>
+5 </Tooltip>
</Button> <Tooltip label='Remove 1 minute' openDelay={tooltipDelayMid}
shouldWrapChildren={disableButtons}>
<TapButton
onClick={() => setPlayback.delay(-5)}
disabled={disableButtons}
square>
1
</TapButton>
</Tooltip>
<Tooltip label='Remove 1 minute' openDelay={tooltipDelayMid}
shouldWrapChildren={disableButtons}>
<TapButton
onClick={() => setPlayback.delay(-5)}
disabled={disableButtons}
square>
5
</TapButton>
</Tooltip> </Tooltip>
</div> </div>
</div> </div>
); );
}; };
export default memo(PlaybackTimer, areEqual);
PlaybackTimer.propTypes = {
playback: PropTypes.string,
handleIncrement: PropTypes.func.isRequired,
selectedId: PropTypes.string,
};
@@ -0,0 +1,65 @@
@use '../../../theme/main' as *;
@mixin tap-factory($theme-front, $theme-bg, $theme-high) {
font-family: "Open Sans", sans-serif;
font-size: 22px;
background-color: $theme-bg;
color: $theme-front;
border-radius: 3px;
width: 100%;
aspect-ratio: 3/1;
box-shadow: $theme-high 0 0 2px;
transition: background-color 0.3s;
display: grid;
place-content: center;
&:disabled {
cursor: not-allowed;
background-color: $opacity-disabled;
box-shadow: none;
opacity: $opacity-disabled;
}
&:hover:not(:disabled) {
background-color: $theme-high;
}
&:active:not(:disabled) {
color: $theme-bg;
background-color: $theme-front;
transition: background-color 0.15s;
}
&.active {
background-color: $theme-high;
}
}
.tapButton.neutral{
@include tap-factory(rgba(255, 255, 255, 0.867), #303030, #363636);
}
.tapButton.start {
@include tap-factory(rgba(255, 255, 255, 0.867), #303030, $ontime-accent);
}
.tapButton.roll {
@include tap-factory(rgba(255, 255, 255, 0.867), #303030, $ontime-roll);
}
.tapButton.pause {
@include tap-factory(rgba(255, 255, 255, 0.867), #303030, $ontime-paused);
}
.tapButton.ontime {
@include tap-factory(rgba(255, 255, 255, 0.867), #303030, $ontime-pink);
}
.tapButton.stop {
@include tap-factory(rgba(255, 255, 255, 0.867), #303030, $ontime-red);
}
.tapButton.square {
aspect-ratio: 1;
font-size: 14px;
}
@@ -0,0 +1,31 @@
import { ForwardedRef, forwardRef, PropsWithChildren } from 'react';
import { Playstate } from '../../../common/models/OntimeTypes';
import style from './TapButton.module.scss';
interface TapButtonProps {
disabled?: boolean;
square?: boolean;
onClick: () => void;
theme?: Playstate | 'neutral';
active?: boolean;
}
const TapButton = forwardRef((props: PropsWithChildren<TapButtonProps>, ref: ForwardedRef<HTMLButtonElement> ) => {
const { children, disabled, onClick, theme = 'neutral', square, active } = props;
return (
<button
className={`${style.tapButton} ${style[theme]} ${square ? style.square : ''} ${active ? style.active : ''}`}
disabled={disabled}
type='button'
onClick={onClick}
ref={ref}
>
{children}
</button>
);
});
TapButton.displayName = "TabButton";
export default TapButton;
@@ -1,53 +0,0 @@
import { IoPlayBack } from '@react-icons/all-files/io5/IoPlayBack';
import { IoPlaySkipBack } from '@react-icons/all-files/io5/IoPlaySkipBack';
import { IoPlaySkipForward } from '@react-icons/all-files/io5/IoPlaySkipForward';
import PropTypes from 'prop-types';
import TransportIconBtn from '../../../common/components/buttons/TransportIconBtn';
import UnloadIconBtn from '../../../common/components/buttons/UnloadIconBtn';
import style from './PlaybackControl.module.scss';
export default function Transport(props) {
const { playback, selectedId, playbackControl, noEvents } = props;
const isRolling = playback === 'roll';
return (
<div className={style.playbackContainer}>
<TransportIconBtn
clickHandler={() => playbackControl.previous()}
disabled={isRolling || noEvents}
tooltip='Previous event'
icon={<IoPlaySkipBack size='22px' />}
/>
<TransportIconBtn
clickHandler={() => playbackControl.next()}
disabled={isRolling || noEvents}
tooltip='Next event'
icon={<IoPlaySkipForward size='22px' />}
/>
<TransportIconBtn
clickHandler={() => playbackControl.reload()}
disabled={selectedId == null || isRolling || noEvents}
tooltip='Reload event'
icon={<IoPlayBack size='22px' />}
/>
<UnloadIconBtn
clickHandler={() => playbackControl.stop()}
disabled={(selectedId == null && !isRolling) || noEvents}
/>
</div>
);
}
Transport.propTypes = {
playback: PropTypes.string,
selectedId: PropTypes.string,
playbackControl: PropTypes.shape({
previous: PropTypes.func,
next: PropTypes.func,
reload: PropTypes.func,
stop: PropTypes.func,
}).isRequired,
noEvents: PropTypes.bool.isRequired,
};
@@ -0,0 +1,63 @@
import { Tooltip } from '@chakra-ui/react';
import { IoPlayBack } from '@react-icons/all-files/io5/IoPlayBack';
import { IoPlaySkipBack } from '@react-icons/all-files/io5/IoPlaySkipBack';
import { IoPlaySkipForward } from '@react-icons/all-files/io5/IoPlaySkipForward';
import { IoStop } from '@react-icons/all-files/io5/IoStop';
import { usePlaybackControlProvider } from '../../../common/hooks/useSocketProvider';
import { Playstate } from '../../../common/models/OntimeTypes';
import { tooltipDelayMid } from '../../../ontimeConfig';
import TapButton from './TapButton';
import style from './PlaybackControl.module.scss';
interface TransportProps {
playback: Playstate;
selectedId: string;
noEvents: boolean;
}
export default function Transport(props: TransportProps) {
const { playback, selectedId, noEvents } = props;
const { setPlayback } = usePlaybackControlProvider();
const isRolling = playback === 'roll';
return (
<div className={style.playbackContainer}>
<Tooltip label='Previous event' openDelay={tooltipDelayMid}>
<TapButton
onClick={() => setPlayback.previous()}
disabled={isRolling || noEvents}
>
<IoPlaySkipBack />
</TapButton>
</Tooltip>
<Tooltip label='Next event' openDelay={tooltipDelayMid}>
<TapButton
onClick={() => setPlayback.next()}
disabled={isRolling || noEvents}
>
<IoPlaySkipForward />
</TapButton>
</Tooltip>
<Tooltip label='Reload event' openDelay={tooltipDelayMid}>
<TapButton
onClick={() => setPlayback.reload()}
disabled={selectedId == null || isRolling || noEvents}
>
<IoPlayBack />
</TapButton>
</Tooltip>
<Tooltip label='Unload Event' openDelay={100}>
<TapButton
onClick={() => setPlayback.stop()}
disabled={(selectedId == null && !isRolling) || noEvents}
theme='stop'
>
<IoStop />
</TapButton>
</Tooltip>
</div>
);
}
@@ -131,7 +131,7 @@
.eventEditor { .eventEditor {
border-radius: 3px 3px 0 0; border-radius: 3px 3px 0 0;
background-color: $bg-container-l1; background-color: $bg-black;
border-top: 1px solid $bg-gray-900; border-top: 1px solid $bg-gray-900;
position: absolute; position: absolute;
bottom: 0; bottom: 0;
@@ -152,7 +152,7 @@
} }
.header { .header {
background-color: $bg-container-l2; background-color: $bg-black;
padding: 8px; padding: 8px;
border-left: 1px solid $bg-container-l3; border-left: 1px solid $bg-container-l3;
} }
@@ -186,8 +186,8 @@
.playback { .playback {
grid-area: play; grid-area: play;
min-height: 270px; min-height: 275px;
max-height: 270px; max-height: 380px;
min-width: 480px; min-width: 480px;
} }
@@ -14,7 +14,7 @@ $block-border-radius: 3px;
flex-direction: row; flex-direction: row;
flex-wrap: wrap; flex-wrap: wrap;
align-content: center; align-content: center;
opacity: 0.8; opacity: 0.6;
transition: linear 0.1s; transition: linear 0.1s;
} }
@@ -26,7 +26,7 @@ $block-border-radius: 3px;
@mixin drag-style() { @mixin drag-style() {
font-size: 20px; font-size: 20px;
text-align: center; text-align: center;
opacity: 0.1; opacity: 0.3;
cursor: grab; cursor: grab;
transition: opacity 0.3s; transition: opacity 0.3s;
&:hover { &:hover {
@@ -24,10 +24,10 @@ export default function BlockBlock(props) {
clickHandler={() => actionHandler('delete')} clickHandler={() => actionHandler('delete')}
icon={<IoRemove />} icon={<IoRemove />}
tooltip='Delete' tooltip='Delete'
variant='ghost' variant='outline'
_hover={{ bg: 'red.400', color: 'white' }} colorScheme='white'
color='red.500'
size='sm' size='sm'
aria-label='Delete'
/> />
<ActionButtons showAdd showDelay actionHandler={actionHandler} /> <ActionButtons showAdd showDelay actionHandler={actionHandler} />
</HStack> </HStack>
@@ -6,24 +6,21 @@
.block { .block {
@include block-spacing; @include block-spacing;
box-sizing: content-box;
display: grid; display: grid;
grid-template-columns: 40px 1fr; grid-template-columns: 40px 1fr;
align-items: center; align-items: center;
height: 40px; height: 40px;
border-radius: 2px;
border-radius: 2px 2px $block-border-radius $block-border-radius; border: $border-l3;
background-color: rgba(107, 70, 193, 0.4); border-bottom: 4px solid $block-block-color;
background: linear-gradient( background-color: $bg-container-l2;
0deg,
rgba(107, 70, 193, 0.4) 0%,
rgba(128, 90, 213, 0.4) 20%,
rgba(107, 70, 193, 0.15) 21%
);
} }
/* ================ DRAG ================ */ /* ================ DRAG ================ */
.drag { .drag {
@include drag-style; @include drag-style;
color: $block-block-color;
} }
/* ============== ACTION ================ */ /* ============== ACTION ================ */
@@ -55,9 +55,10 @@ export default function DelayBlock(props) {
<Button <Button
onClick={applyDelayHandler} onClick={applyDelayHandler}
size='sm' size='sm'
colorScheme='orange' color="#F57C13"
_hover={{ bg: 'orange.400' }} borderColor="#F57C13"
leftIcon={<FiCheck />} leftIcon={<FiCheck />}
variant='outline'
> >
Apply delay Apply delay
</Button> </Button>
@@ -65,9 +66,8 @@ export default function DelayBlock(props) {
clickHandler={deleteHandler} clickHandler={deleteHandler}
icon={<IoRemove />} icon={<IoRemove />}
tooltip='Delete' tooltip='Delete'
variant='ghost' variant='outline'
_hover={{ bg: 'red.400', color: 'white' }} colorScheme='white'
color='red.500'
size='sm' size='sm'
/> />
<ActionButtons showAdd actionHandler={actionHandler} /> <ActionButtons showAdd actionHandler={actionHandler} />
@@ -6,20 +6,17 @@
.delay { .delay {
@include block-spacing; @include block-spacing;
box-sizing: content-box;
display: grid; display: grid;
grid-template-columns: 32px 1fr auto; grid-template-columns: 32px 1fr auto;
grid-template-areas: 'drag inpt btns'; grid-template-areas: 'drag inpt btns';
align-items: center; align-items: center;
height: 40px; height: 40px;
border-radius: 2px;
border: $border-l3;
border-top: 4px solid $block-delay-color;
background-color: $bg-container-l2;
border-radius: $block-border-radius $block-border-radius 2px 2px;
background-color: rgba(214, 158, 46, 0.4);
background: linear-gradient(
180deg,
rgba(214, 158, 46, 0.4) 0%,
rgba(214, 158, 46, 0.4) 20%,
rgba(214, 158, 46, 0.17) 21%
);
} }
/* ================ DRAG ================ */ /* ================ DRAG ================ */
@@ -27,6 +24,7 @@
.drag { .drag {
grid-area: drag; grid-area: drag;
@include drag-style; @include drag-style;
color: $block-delay-color;
} }
/* =============== INPUT ================ */ /* =============== INPUT ================ */
@@ -12,7 +12,7 @@
grid-template-columns: $binder-width auto 1fr auto; grid-template-columns: $binder-width auto 1fr auto;
grid-template-rows: 36px 36px 36px $element-spacing; grid-template-rows: 36px 36px 36px $element-spacing;
align-items: center; align-items: center;
margin: 2px 2px; margin:4px 2px;
padding-right: $clearance; padding-right: $clearance;
// style - general // style - general
@@ -26,7 +26,6 @@
// variant // variant
&.selected { &.selected {
background-color: $bg-container-l3; background-color: $bg-container-l3;
box-shadow: 0 0 1px 2px $ontime-accent;
} }
&.skip { &.skip {
@@ -87,7 +86,7 @@
height: 100%; height: 100%;
.delayNote { .delayNote {
font-size: 10px; font-size: 11px;
color: $text-delay; color: $text-delay;
} }
} }
@@ -148,9 +147,8 @@
border: 1px solid transparent; border: 1px solid transparent;
&.enabled { &.enabled {
color: $ontime-accent; color: $text-white;
border: 1px solid $ontime-accent; background-color: $ontime-accent;
background-color: $bg-gray-1100;
} }
} }
@@ -3,7 +3,7 @@ import { Draggable } from 'react-beautiful-dnd';
import { Editable, EditableInput, EditablePreview, Tooltip } from '@chakra-ui/react'; import { Editable, EditableInput, EditablePreview, Tooltip } from '@chakra-ui/react';
import { FiUsers } from '@react-icons/all-files/fi/FiUsers'; import { FiUsers } from '@react-icons/all-files/fi/FiUsers';
import { IoOptions } from '@react-icons/all-files/io5/IoOptions'; import { IoOptions } from '@react-icons/all-files/io5/IoOptions';
import { IoPause } from '@react-icons/all-files/io5/IoPause'; import { IoPlay } from '@react-icons/all-files/io5/IoPlay';
import { IoPlayBackOutline } from '@react-icons/all-files/io5/IoPlayBackOutline'; import { IoPlayBackOutline } from '@react-icons/all-files/io5/IoPlayBackOutline';
import { IoPlayOutline } from '@react-icons/all-files/io5/IoPlayOutline'; import { IoPlayOutline } from '@react-icons/all-files/io5/IoPlayOutline';
import { IoReload } from '@react-icons/all-files/io5/IoReload'; import { IoReload } from '@react-icons/all-files/io5/IoReload';
@@ -108,7 +108,7 @@ export default function EventBlock(props: EventBlockProps) {
if (!skip && eventIsPlaying) { if (!skip && eventIsPlaying) {
playBtnStyles._hover = { bg: '#c05621' }; playBtnStyles._hover = { bg: '#c05621' };
} else if (!skip && !eventIsPlaying) { } else if (!skip && !eventIsPlaying) {
playBtnStyles._hover = { bg: '#4bffab' }; playBtnStyles._hover = { };
} }
return ( return (
@@ -161,19 +161,15 @@ export default function EventBlock(props: EventBlockProps) {
tabIndex={-1} tabIndex={-1}
/> />
<TooltipActionBtn <TooltipActionBtn
aria-label='Toggle start / pause event' aria-label='Start event'
tooltip={eventIsPlaying ? 'Pause event' : 'Start event'} tooltip='Start event'
openDelay={tooltipDelayMid} openDelay={tooltipDelayMid}
icon={eventIsPlaying ? <IoPause /> : <IoPlayOutline />} icon={eventIsPlaying ? <IoPlay /> : <IoPlayOutline />}
disabled={skip} disabled={skip}
{...blockBtnStyle} {...blockBtnStyle}
variant={eventIsPlaying ? 'solid' : 'ghost'} variant={eventIsPlaying ? 'solid' : 'ghost'}
clickHandler={ clickHandler={() => setPlayback.startEvent()}
eventIsPlaying backgroundColor={eventIsPlaying ? '#58A151' : undefined}
? () => setPlayback.pause()
: () => setPlayback.startEvent()
}
{...playBtnStyles}
tabIndex={-1} tabIndex={-1}
/> />
</div> </div>
@@ -27,8 +27,8 @@ export default function EventBlockActionMenu(props) {
const blockBtnStyle = { const blockBtnStyle = {
size: 'sm', size: 'sm',
variant: 'ghost', variant: 'outline',
colorScheme: 'blue', colorScheme: 'whiteAlpha',
}; };
return ( return (
@@ -15,7 +15,7 @@ import { useAtomValue } from 'jotai';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import useSubscription from '../../../common/hooks/useSubscription'; import useSubscription from '../../../common/hooks/useSubscription';
import EntryBlock from '../entry-block/EntryBlock'; import QuickAddBlock from '../quick-add-block/QuickAddBlock';
import EventListItem from './EventListItem'; import EventListItem from './EventListItem';
@@ -231,7 +231,7 @@ export default function EventList(props) {
/> />
</div> </div>
{((showQuickEntry && index === cursor) || isLast) && ( {((showQuickEntry && index === cursor) || isLast) && (
<EntryBlock <QuickAddBlock
showKbd={index === cursor} showKbd={index === cursor}
previousId={e.id} previousId={e.id}
previousEventId={previousEventId} previousEventId={previousEventId}
@@ -27,7 +27,7 @@
.bgElement { .bgElement {
&.delayed { &.delayed {
background: rgba(214, 158, 46, 0.3); background: rgba($block-delay-color, 0.3);
} }
} }
@@ -1,6 +1,6 @@
@use '../../../theme/main' as *; @use '../../../theme/main' as *;
.create { .quickAdd {
background-color: $bg-container-l2; background-color: $bg-container-l2;
display: flex; display: flex;
align-items: center; align-items: center;
@@ -81,4 +81,5 @@
border-color: $text-gray-disabled; border-color: $text-gray-disabled;
color: $text-gray-disabled; color: $text-gray-disabled;
pointer-events: none; pointer-events: none;
cursor: not-allowed;
} }
@@ -8,9 +8,9 @@ import { useAtomValue } from 'jotai';
import { tooltipDelayMid } from '../../../ontimeConfig'; import { tooltipDelayMid } from '../../../ontimeConfig';
import style from './EntryBlock.module.scss'; import style from './QuickAddBlock.module.scss';
interface EntryBlockProps { interface QuickAddBlockProps {
showKbd: boolean; showKbd: boolean;
previousId?: string; previousId?: string;
previousEventId: string | null; previousEventId: string | null;
@@ -18,7 +18,7 @@ interface EntryBlockProps {
disableAddBlock: boolean; disableAddBlock: boolean;
} }
export default function EntryBlock(props: EntryBlockProps) { export default function QuickAddBlock(props: QuickAddBlockProps) {
const { const {
showKbd, showKbd,
previousId, previousId,
@@ -61,7 +61,7 @@ export default function EntryBlock(props: EntryBlockProps) {
}, [addEvent, doPublic, doStartTime, emitError, previousId, previousEventId]); }, [addEvent, doPublic, doStartTime, emitError, previousId, previousEventId]);
return ( return (
<div className={style.create}> <div className={style.quickAdd}>
<Tooltip label='Add Event' openDelay={tooltipDelayMid}> <Tooltip label='Add Event' openDelay={tooltipDelayMid}>
<span <span
className={style.createEvent} className={style.createEvent}
@@ -1,5 +1,5 @@
import { useCallback, useContext, useEffect, useState } from 'react'; import { useCallback, useContext, useEffect, useState } from 'react';
import { Button } from '@chakra-ui/react'; import { Button, Select } from '@chakra-ui/react';
import { FiUsers } from '@react-icons/all-files/fi/FiUsers'; import { FiUsers } from '@react-icons/all-files/fi/FiUsers';
import { IoBan } from '@react-icons/all-files/io5/IoBan'; import { IoBan } from '@react-icons/all-files/io5/IoBan';
import { editorEventId } from 'common/atoms/LocalEventSettings'; import { editorEventId } from 'common/atoms/LocalEventSettings';
@@ -17,6 +17,7 @@ import { useAtom } from 'jotai';
import useEventsList from '../../common/hooks-query/useEventsList'; import useEventsList from '../../common/hooks-query/useEventsList';
import style from './EventEditor.module.scss'; import style from './EventEditor.module.scss';
import CopyTag from '../../common/components/osc-tag/CopyTag';
export default function EventEditor() { export default function EventEditor() {
const [openId] = useAtom(editorEventId); const [openId] = useAtom(editorEventId);
@@ -104,40 +105,57 @@ export default function EventEditor() {
return ( return (
<div className={style.eventEditor}> <div className={style.eventEditor}>
<div className={style.timers}> <div className={style.timeOptions}>
<label className={style.inputLabel}> <div className={style.timers}>
Start time {delayed && <span className={style.delayLabel}>{addedTime}</span>} <label className={style.inputLabel}>
{delayed && <div className={style.delayLabel}>{newStart}</div>} Start time {delayed && <span className={style.delayLabel}>{addedTime}</span>}
</label> {delayed && <div className={style.delayLabel}>{newStart}</div>}
<TimeInput </label>
name='timeStart' <TimeInput
submitHandler={handleSubmit} name='timeStart'
validationHandler={timerValidationHandler} submitHandler={handleSubmit}
time={event.timeStart} validationHandler={timerValidationHandler}
delay={0} time={event.timeStart}
placeholder='Start' delay={0}
/> placeholder='Start'
<label className={style.inputLabel}> />
End time {delayed && <span className={style.delayLabel}>{addedTime}</span>} <label className={style.inputLabel}>
{delayed && <div className={style.delayLabel}>{newEnd}</div>} End time {delayed && <span className={style.delayLabel}>{addedTime}</span>}
</label> {delayed && <div className={style.delayLabel}>{newEnd}</div>}
<TimeInput </label>
name='timeEnd' <TimeInput
submitHandler={handleSubmit} name='timeEnd'
validationHandler={timerValidationHandler} submitHandler={handleSubmit}
time={event.timeEnd} validationHandler={timerValidationHandler}
delay={0} time={event.timeEnd}
placeholder='End' delay={0}
/> placeholder='End'
<label className={style.inputLabel}>Duration</label> />
<TimeInput <label className={style.inputLabel}>Duration</label>
name='duration' <TimeInput
submitHandler={handleSubmit} name='duration'
validationHandler={timerValidationHandler} submitHandler={handleSubmit}
time={event.duration} validationHandler={timerValidationHandler}
delay={0} time={event.duration}
placeholder='Duration' delay={0}
/> placeholder='Duration'
/>
</div>
<div className={style.timeSettings}>
<label className={style.inputLabel}>Timer type</label>
<Select size='sm' variant='filled' color='black'>
<option value='option1'>Start to end</option>
<option value='option2'>Duration</option>
<option value='option3'>Follow previous</option>
<option value='option3'>Start only</option>
</Select>
<label className={style.inputLabel}>Countdown style</label>
<Select size='sm' variant='filled' color='black'>
<option value='option1'>Count down</option>
<option value='option2'>Count up</option>
<option value='option3'>Clock</option>
</Select>
</div>
</div> </div>
<div className={style.titles}> <div className={style.titles}>
<div className={style.left}> <div className={style.left}>
@@ -199,7 +217,7 @@ export default function EventEditor() {
/> />
</div> </div>
</div> </div>
<div className={style.osc}>{`OSC Trigger /ontime/gotoid/${event.id}`}</div> <CopyTag label='OSC trigger' className={style.osc}>{`/ontime/gotoid/${event.id}`}</CopyTag>
</div> </div>
</div> </div>
); );
@@ -8,26 +8,39 @@
gap: max(16px, 2vh); gap: max(16px, 2vh);
display: grid; display: grid;
grid-template-areas: 'timers titles'; grid-template-areas: 'timeOptions titles';
grid-template-columns: auto 1fr; grid-template-columns: auto 1fr;
.timers, .timeOptions,
.titles { .titles {
background-color: $bg-container-l2; background-color: $bg-container-over;
border-radius: 2px; border-radius: 2px;
padding: 8px 16px; padding: 8px 16px;
} }
.timers { .timeOptions {
grid-area: timers; grid-area: timeOptions;
display: flex;
gap: 24px;
}
.timers, .timeSettings {
display: flex; display: flex;
flex-direction: column; flex-direction: column;
gap: 8px; gap: 8px;
} }
.timers label:nth-child(1) { .timers label:nth-child(1),
.timeSettings label:nth-child(1),
{
margin-top: 4px; margin-top: 4px;
} }
.timeSettings {
display: flex;
flex-direction: column;
gap: 8px;
}
.titles { .titles {
grid-area: titles; grid-area: titles;
display: grid; display: grid;
@@ -57,10 +70,7 @@
.osc { .osc {
grid-area: tag; grid-area: tag;
font-size: 14px; justify-self: end;
color: $ontime-accent;
text-align: right;
user-select: text;
} }
} }
+2 -2
View File
@@ -36,8 +36,8 @@ export default function Info() {
<span>{selected}</span> <span>{selected}</span>
</div> </div>
<InfoNif /> <InfoNif />
<InfoTitle title='Now' data={titlesNow} /> <InfoTitle title='Playing Now' data={titlesNow} />
<InfoTitle title='Next' data={titlesNext} /> <InfoTitle title='Playing Next' data={titlesNext} />
<InfoLogger /> <InfoLogger />
</> </>
); );
-15
View File
@@ -11,7 +11,6 @@
@include container; @include container;
} }
.main { .main {
font-size: 0.9em; font-size: 0.9em;
color: $label-gray; color: $label-gray;
@@ -19,20 +18,6 @@
justify-content: space-between; justify-content: space-between;
} }
.header,
.headerRoll {
padding: 0;
margin: 0;
font-size: 0.9em;
color: $header-gray;
display: flex;
justify-content: space-between;
}
.header {
color: $header-gray;
}
.collapsedTitle { .collapsedTitle {
font-size: inherit; font-size: inherit;
@@ -18,7 +18,6 @@
overflow-y: scroll; overflow-y: scroll;
font-size: 0.8em; font-size: 0.8em;
user-select: text; user-select: text;
@include third-container;
padding: 0 0.5em; padding: 0 0.5em;
margin: 0 0.5em; margin: 0 0.5em;
@@ -78,8 +77,8 @@
} }
div.active { div.active {
background: $ontime-accent; background: $ontime-roll;
color: darken($ontime-accent, 70%); color: white;
} }
.clear { .clear {
@@ -4,3 +4,9 @@
gap: 8px; gap: 8px;
padding-top: 24px; padding-top: 24px;
} }
.labelledSwitch {
display: flex;
align-items: center;
gap: 8px;
}
+18 -21
View File
@@ -1,6 +1,5 @@
import { memo, useCallback, useContext } from 'react'; import { memo, useCallback, useContext } from 'react';
import { import {
Button,
Divider, Divider,
HStack, HStack,
IconButton, IconButton,
@@ -8,6 +7,7 @@ import {
MenuButton, MenuButton,
MenuItem, MenuItem,
MenuList, MenuList,
Switch,
Tooltip, Tooltip,
} from '@chakra-ui/react'; } from '@chakra-ui/react';
import { FiClock } from '@react-icons/all-files/fi/FiClock'; import { FiClock } from '@react-icons/all-files/fi/FiClock';
@@ -29,13 +29,10 @@ const EventListMenu = () => {
const { isCursorLocked, toggleCursorLocked } = useContext(CursorContext); const { isCursorLocked, toggleCursorLocked } = useContext(CursorContext);
const { addEvent, deleteAllEvents } = useEventAction(); const { addEvent, deleteAllEvents } = useEventAction();
type ActionTypes = 'event' | 'delay' | 'block' | 'delete-all' | 'toggle-lock'; type ActionTypes = 'event' | 'delay' | 'block' | 'delete-all';
const actionHandler = useCallback( const eventAction = useCallback(
(action: ActionTypes) => { (action: ActionTypes) => {
switch (action) { switch (action) {
case 'toggle-lock':
toggleCursorLocked();
break;
case 'event': case 'event':
addEvent({ type: action }); addEvent({ type: action });
break; break;
@@ -55,14 +52,14 @@ const EventListMenu = () => {
return ( return (
<HStack className={style.headerButtons}> <HStack className={style.headerButtons}>
<Button <label className={style.labelledSwitch}>
size='sm' <Switch
variant={isCursorLocked ? 'solid' : 'ghost'} defaultChecked={isCursorLocked}
onClick={() => actionHandler('toggle-lock')} onChange={(event) => toggleCursorLocked(event.target.checked)}
colorScheme='blue' colorScheme='blue'
> />
Lock cursor to current Lock cursor to current
</Button> </label>
<Menu isLazy lazyBehavior='unmount'> <Menu isLazy lazyBehavior='unmount'>
<Tooltip label='Add / Delete ...'> <Tooltip label='Add / Delete ...'>
<MenuButton <MenuButton
@@ -70,22 +67,22 @@ const EventListMenu = () => {
aria-label='Create Menu' aria-label='Create Menu'
size='sm' size='sm'
icon={<FiPlus />} icon={<FiPlus />}
colorScheme='blue' colorScheme='white'
variant='outline' variant='outline'
/> />
</Tooltip> </Tooltip>
<MenuList style={menuStyle}> <MenuList style={menuStyle}>
<MenuItem icon={<FiPlus />} onClick={() => actionHandler('event')}> <MenuItem icon={<FiPlus />} onClick={() => eventAction('event')}>
Add Event first Add Event at start
</MenuItem> </MenuItem>
<MenuItem icon={<FiClock />} onClick={() => actionHandler('delay')}> <MenuItem icon={<FiClock />} onClick={() => eventAction('delay')}>
Add Delay first Add Delay at start
</MenuItem> </MenuItem>
<MenuItem icon={<FiMinusCircle />} onClick={() => actionHandler('block')}> <MenuItem icon={<FiMinusCircle />} onClick={() => eventAction('block')}>
Add Block first Add Block at start
</MenuItem> </MenuItem>
<Divider /> <Divider />
<MenuItem icon={<FiTrash2 />} onClick={() => actionHandler('delete-all')} color='red.500'> <MenuItem icon={<FiTrash2 />} onClick={() => eventAction('delete-all')} color='red.500'>
Delete All Delete All
</MenuItem> </MenuItem>
</MenuList> </MenuList>
+12 -8
View File
@@ -17,15 +17,17 @@ $bg-gray-100: #c0c0c0; // borders and whatnot
$bg-overlay: rgba(0, 0, 0, 0.85); $bg-overlay: rgba(0, 0, 0, 0.85);
$ontime-accent: #4bffab; // $ontime-accent: #4bffab);
$ontime-accent: #58A151;
$ontime-accent-text: mix($bg-black, $ontime-accent, 10%); $ontime-accent-text: mix($bg-black, $ontime-accent, 10%);
$ontime-pink: #ff7597; $ontime-pink: #ff7597;
$ontime-pink-variant: #ff6969; $ontime-pink-variant: #ff6969;
$ontime-roll: #2b6cb0; $ontime-roll: #0274B6;
$ontime-delay: #dd6b20; $ontime-delay: #F57C13;
$action-blue: #3182ce; $action-blue: #3182ce;
$ontime-paused: #c05621; $ontime-paused: #c05621;
$opacity-disabled: 0.4; $opacity-disabled: 0.4;
$ontime-red: #E4281E;
//rgba(255, 255, 255, 0.39); - $bg-gray-700 //rgba(255, 255, 255, 0.39); - $bg-gray-700
//rgba(255, 255, 255, 0.13); - $bg-gray-900 //rgba(255, 255, 255, 0.13); - $bg-gray-900
@@ -40,15 +42,15 @@ $opacity-disabled: 0.4;
// outdent in level2 - $bg-gray-950 // outdent in level2 - $bg-gray-950
//////////////////////////////////// editor //////////////////////////////////// editor
$notes-color: #d69e2e; $notes-color: #9fd8ff;
$text-white: #fffffa; $text-white: #fffffa;
$text-gray-disabled: #505050; $text-gray-disabled: #505050;
$header-gray: #ccc;
$label-gray: #aaa; $label-gray: #aaa;
$header-gray: $label-gray;
$clocks: #ddd; $clocks: #ddd;
$bg-gray: #f4f4f8; $bg-gray: #f4f4f8;
$text-delay: #a97d24; $text-delay: #F57C13;
$light-bg: #2b6cb0; $light-bg: #2b6cb0;
$light-bg-transparent: #2b6cb055; $light-bg-transparent: #2b6cb055;
@@ -65,16 +67,18 @@ $title-gray: #ddd;
$subtitle-gray: #aaa; $subtitle-gray: #aaa;
//////////////////////////////////// block elements //////////////////////////////////// block elements
$bg-container-over: #0b1521;
$bg-container-over-l1: #132337;
$bg-container-l1: #202020; $bg-container-l1: #202020;
$bg-container-l2: #232323; $bg-container-l2: #232323;
$bg-container-l3: #2b2b2b; $bg-container-l3: #2b2b2b;
$border-l1: 1px solid $bg-gray-1000; $border-l1: 1px solid $bg-gray-1000;
$border-l3: 1px solid $bg-gray-900; $border-l3: 1px solid $bg-gray-900;
$block-delay-color: #ecc94b; $block-delay-color: #E2720D;
$delay-text: #d69e2e; $delay-text: #d69e2e;
$block-delay-border: #d69e2e55; $block-delay-border: #d69e2e55;
$block-block-color: #805ad5; $block-block-color: #7347AD;
$block-border: 1px solid $bg-gray-1100; $block-border: 1px solid $bg-gray-1100;
//////////////////////////////////// viewer cards //////////////////////////////////// viewer cards
-7
View File
@@ -18,10 +18,3 @@
border: 1px solid rgba(0, 0, 0, 0.05); border: 1px solid rgba(0, 0, 0, 0.05);
border-radius: 2px; border-radius: 2px;
} }
@mixin osc-label {
color: $ontime-accent-text;
font-size: 0.8em;
-webkit-user-select: text;
user-select: text;
}