diff --git a/apps/client/src/common/components/client-modal/RedirectClientModal.tsx b/apps/client/src/common/components/client-modal/RedirectClientModal.tsx index 50b67ee10..3fd9dc251 100644 --- a/apps/client/src/common/components/client-modal/RedirectClientModal.tsx +++ b/apps/client/src/common/components/client-modal/RedirectClientModal.tsx @@ -1,22 +1,15 @@ import { useState } from 'react'; import { IoArrowForward } from 'react-icons/io5'; -import { - IconButton, - Input, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalHeader, - ModalOverlay, - Select, -} from '@chakra-ui/react'; import { navigatorConstants } from '../../../viewerConfig'; import { setClientRemote } from '../../hooks/useSocket'; import useUrlPresets from '../../hooks-query/useUrlPresets'; +import Button from '../buttons/Button'; import Info from '../info/Info'; +import Input from '../input/input/Input'; import AppLink from '../link/app-link/AppLink'; +import Modal from '../modal/Modal'; +import Select from '../select/Select'; import style from './RedirectClientModal.module.scss'; @@ -29,8 +22,7 @@ interface RedirectClientModalProps { onClose: () => void; } -export function RedirectClientModal(props: RedirectClientModalProps) { - const { id, isOpen, name, currentPath, origin, onClose } = props; +export function RedirectClientModal({ id, isOpen, name, currentPath, origin, onClose }: RedirectClientModalProps) { const { data } = useUrlPresets(); const [path, setPath] = useState(currentPath); const [selected, setSelected] = useState('/'); @@ -47,13 +39,26 @@ export function RedirectClientModal(props: RedirectClientModalProps) { const enabledPresets = data.filter((preset) => preset.enabled); + const viewOptions = [ + ...navigatorConstants.map((view) => ({ + value: `/${view.url}`, + label: view.label, + })), + ...enabledPresets.map((preset) => ({ + value: preset.pathAndParams, + label: `Preset: ${preset.alias}`, + })), + ]; + return ( - - - - Redirect: {name} - - + Remotely redirect the client to a different URL.
Either by selecting a URL Preset or entering a custom path. @@ -65,36 +70,21 @@ export function RedirectClientModal(props: RedirectClientModalProps) { Select View or URL Preset
- setSelected(value)} + disabled={enabledPresets.length === 0} + /> +
@@ -102,25 +92,24 @@ export function RedirectClientModal(props: RedirectClientModalProps) { - } onClick={() => handleRedirect(path)} - /> + > + Redirect +
-
-
-
+ + } + /> ); } diff --git a/apps/client/src/common/components/modal/Modal.module.scss b/apps/client/src/common/components/modal/Modal.module.scss index 57b2b6373..11256f68a 100644 --- a/apps/client/src/common/components/modal/Modal.module.scss +++ b/apps/client/src/common/components/modal/Modal.module.scss @@ -1,13 +1,13 @@ .modal { position: fixed; - top: 50%; + top: 10vh; left: 50%; - - transform: translate(-50%, -50%); - + transform: translateX(-50%); + padding-inline: 1rem; min-width: min(680px, 90vw); min-height: min(200px, 10vh); + max-width: min(680px, 90vw); background-color: $gray-1250; color: $ui-white; @@ -19,7 +19,6 @@ .backdrop { position: fixed; inset: 0; - z-index: $zindex-backdrop; background-color: $backdrop-color; transition: opacity 300ms cubic-bezier(0.45, 1.005, 0, 1.005); @@ -44,7 +43,7 @@ flex-direction: column; gap: 0.5rem; - max-height: min(80vh, 600px); + max-height: 60vh; overflow-y: auto; } diff --git a/apps/client/src/common/components/modal/Modal.tsx b/apps/client/src/common/components/modal/Modal.tsx index f1817820a..9b6ca7068 100644 --- a/apps/client/src/common/components/modal/Modal.tsx +++ b/apps/client/src/common/components/modal/Modal.tsx @@ -8,7 +8,7 @@ import style from './Modal.module.scss'; interface ModalProps { isOpen: boolean; - title: string; + title?: string; showCloseButton?: boolean; showBackdrop?: boolean; bodyElements: ReactNode; diff --git a/apps/client/src/common/components/select/Select.module.scss b/apps/client/src/common/components/select/Select.module.scss index 232c4fd4d..d28061eec 100644 --- a/apps/client/src/common/components/select/Select.module.scss +++ b/apps/client/src/common/components/select/Select.module.scss @@ -33,6 +33,10 @@ opacity: 0.4; cursor: not-allowed; } + + &.fluid { + width: 100%; + } } .selectIcon { diff --git a/apps/client/src/common/components/select/Select.tsx b/apps/client/src/common/components/select/Select.tsx index 3f67f4f87..ce2f1b8dc 100644 --- a/apps/client/src/common/components/select/Select.tsx +++ b/apps/client/src/common/components/select/Select.tsx @@ -2,6 +2,8 @@ import { IoCheckmark } from 'react-icons/io5'; import { LuChevronsUpDown } from 'react-icons/lu'; import { Select as BaseSelect } from '@base-ui-components/react/select'; +import { cx } from '../../utils/styleUtils'; + import styles from './Select.module.scss'; interface SelectProps extends Omit, 'items'> { @@ -10,12 +12,13 @@ interface SelectProps extends Omit, 'items'> { value: T; label: string; }[]; + fluid?: boolean; } -export default function Select({ options, ...selectRootProps }: SelectProps) { +export default function Select({ options, fluid, ...selectRootProps }: SelectProps) { return ( - + diff --git a/apps/client/src/features/app-settings/panel/general-panel/StyleEditorModal.module.scss b/apps/client/src/features/app-settings/panel/general-panel/StyleEditorModal.module.scss index 75dc36904..37112ff57 100644 --- a/apps/client/src/features/app-settings/panel/general-panel/StyleEditorModal.module.scss +++ b/apps/client/src/features/app-settings/panel/general-panel/StyleEditorModal.module.scss @@ -8,5 +8,8 @@ } .column { + width: 100%; + display: flex; + gap: 1rem; flex-direction: column; } diff --git a/apps/client/src/features/app-settings/panel/general-panel/StyleEditorModal.tsx b/apps/client/src/features/app-settings/panel/general-panel/StyleEditorModal.tsx index fbed556b3..bbe3fb0c5 100644 --- a/apps/client/src/features/app-settings/panel/general-panel/StyleEditorModal.tsx +++ b/apps/client/src/features/app-settings/panel/general-panel/StyleEditorModal.tsx @@ -1,17 +1,9 @@ import { lazy, useEffect, useRef, useState } from 'react'; -import { - Button, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalFooter, - ModalHeader, - ModalOverlay, -} from '@chakra-ui/react'; import { getCSSContents, postCSSContents, restoreCSSContents } from '../../../../common/api/assets'; +import Button from '../../../../common/components/buttons/Button'; import Info from '../../../../common/components/info/Info'; +import Modal from '../../../../common/components/modal/Modal'; import * as Panel from '../../panel-utils/PanelUtils'; import style from './StyleEditorModal.module.scss'; @@ -27,9 +19,7 @@ interface CSSRef { getCss: () => string; } -export default function CodeEditorModal(props: CodeEditorModalProps) { - const { isOpen, onClose } = props; - +export default function CodeEditorModal({ isOpen, onClose }: CodeEditorModalProps) { const [css, setCSS] = useState(''); const [isDirty, setIsDirty] = useState(false); const [saveLoading, setSaveLoading] = useState(false); @@ -84,46 +74,43 @@ export default function CodeEditorModal(props: CodeEditorModalProps) { }, [isOpen]); return ( - - - - Edit CSS override - - - - - - + + } + footerElements={ +
Invalid CSS will be refused by the browser {error && {`Error: ${error}`}} - - - - - - +
+ } + /> ); } diff --git a/apps/client/src/features/app-settings/quick-start/QuickStart.module.scss b/apps/client/src/features/app-settings/quick-start/QuickStart.module.scss deleted file mode 100644 index 2f20ed9fa..000000000 --- a/apps/client/src/features/app-settings/quick-start/QuickStart.module.scss +++ /dev/null @@ -1,8 +0,0 @@ -.scrollContainer { - max-height: 70vh; - overflow: auto; - - display: flex; - flex-direction: column; - gap: 1rem; -} diff --git a/apps/client/src/features/app-settings/quick-start/QuickStart.tsx b/apps/client/src/features/app-settings/quick-start/QuickStart.tsx index 501ca7af5..5286a7884 100644 --- a/apps/client/src/features/app-settings/quick-start/QuickStart.tsx +++ b/apps/client/src/features/app-settings/quick-start/QuickStart.tsx @@ -1,45 +1,35 @@ -import { Controller, useForm } from 'react-hook-form'; -import { - Button, - Input, - Modal, - ModalBody, - ModalCloseButton, - ModalContent, - ModalFooter, - ModalHeader, - ModalOverlay, - Select, - Switch, -} from '@chakra-ui/react'; +import { useForm } from 'react-hook-form'; import { QuickStartData } from 'ontime-types'; import { parseUserTime } from 'ontime-utils'; import { quickProject } from '../../../common/api/db'; import { invalidateAllCaches, maybeAxiosError } from '../../../common/api/utils'; +import Button from '../../../common/components/buttons/Button'; +import Input from '../../../common/components/input/input/Input'; import TimeInput from '../../../common/components/input/time-input/TimeInput'; +import Modal from '../../../common/components/modal/Modal'; +import Select from '../../../common/components/select/Select'; +import Switch from '../../../common/components/switch/Switch'; import { editorSettingsDefaults, useEditorSettings } from '../../../common/stores/editorSettings'; import * as Panel from '../panel-utils/PanelUtils'; import { quickStartDefaults } from './quickStart.utils'; -import style from './QuickStart.module.scss'; - interface QuickStartProps { isOpen: boolean; onClose: () => void; } -export default function QuickStart(props: QuickStartProps) { - const { isOpen, onClose } = props; +export default function QuickStart({ isOpen, onClose }: QuickStartProps) { const { defaultWarnTime, defaultDangerTime, setDangerTime, setWarnTime } = useEditorSettings(); const { - control, handleSubmit, register, formState: { errors, isSubmitting, isValid }, + watch, setError, + setValue, } = useForm({ defaultValues: quickStartDefaults, values: quickStartDefaults, @@ -65,123 +55,114 @@ export default function QuickStart(props: QuickStartProps) { const dangerTimeInMs = parseUserTime(defaultDangerTime); return ( - - - - + - Create new project... - - - - - - - - - - - - - - - - + + + + + + + + + + - - - - - name='warnTime' - submitHandler={(_field, value) => setWarnTime(value)} - time={warnTimeInMs} - placeholder={editorSettingsDefaults.warnTime} - /> - - - - - name='dangerTime' - submitHandler={(_field, value) => setDangerTime(value)} - time={dangerTimeInMs} - placeholder={editorSettingsDefaults.dangerTime} - /> - - + + + + + name='warnTime' + submitHandler={(_field, value) => setWarnTime(value)} + time={warnTimeInMs} + placeholder={editorSettingsDefaults.warnTime} + /> + + + + + name='dangerTime' + submitHandler={(_field, value) => setDangerTime(value)} + time={dangerTimeInMs} + placeholder={editorSettingsDefaults.dangerTime} + /> + + - - - - ( - - )} - /> - - - - - - - - - {errors?.root && {errors.root.message}} - - - + + + + setValue('viewSettings.freezeEnd', checked)} + /> + + + + + + - - + } + footerElements={ + <> + {errors?.root && {errors.root.message}} + + + + } + /> ); } diff --git a/apps/client/src/views/editor/finder/Finder.tsx b/apps/client/src/views/editor/finder/Finder.tsx index a6f30f8d2..851869cf0 100644 --- a/apps/client/src/views/editor/finder/Finder.tsx +++ b/apps/client/src/views/editor/finder/Finder.tsx @@ -1,8 +1,9 @@ import { KeyboardEvent, useState } from 'react'; -import { Input, Modal, ModalBody, ModalContent, ModalFooter, ModalOverlay } from '@chakra-ui/react'; import { useDebouncedCallback } from '@mantine/hooks'; import { SupportedEntry } from 'ontime-types'; +import Input from '../../../common/components/input/input/Input'; +import Modal from '../../../common/components/modal/Modal'; import { useEventSelection } from '../../../features/rundown/useEventSelection'; import useFinder from './useFinder'; @@ -14,8 +15,7 @@ interface FinderProps { onClose: () => void; } -export default function Finder(props: FinderProps) { - const { isOpen, onClose } = props; +export default function Finder({ isOpen, onClose }: FinderProps) { const { find, results, error } = useFinder(); const [selected, setSelected] = useState(0); @@ -56,11 +56,14 @@ export default function Finder(props: FinderProps) { }; return ( - - - - - + +
    {error &&
  • {error}
  • } {results.length === 0 &&
  • No results
  • } @@ -91,12 +94,14 @@ export default function Finder(props: FinderProps) { ); })}
-
- + + } + footerElements={ +
Use the keywords cue, index or title to filter search - - - +
+ } + /> ); } diff --git a/apps/client/src/views/editor/welcome/Welcome.module.scss b/apps/client/src/views/editor/welcome/Welcome.module.scss index 2696135de..efdee592e 100644 --- a/apps/client/src/views/editor/welcome/Welcome.module.scss +++ b/apps/client/src/views/editor/welcome/Welcome.module.scss @@ -8,10 +8,25 @@ display: flex; flex-direction: column; gap: 1rem; + width: 100%; +} + +.about { + @extend .column; + font-size: calc(1rem - 2px); +} + +.inline { + display: flex; + align-items: center; + gap: 0.5rem; } .header { font-size: 1.5rem; + display: flex; + align-items: center; + justify-content: space-between; } .logo { @@ -20,7 +35,6 @@ } .buttonRow { - margin-top: 1rem; display: flex; gap: 1rem; justify-content: end; @@ -38,6 +52,7 @@ .table { width: 100%; + font-size: calc(1rem - 2px); tbody { background-color: $gray-1300; diff --git a/apps/client/src/views/editor/welcome/Welcome.tsx b/apps/client/src/views/editor/welcome/Welcome.tsx index 5d588da04..d787b7f91 100644 --- a/apps/client/src/views/editor/welcome/Welcome.tsx +++ b/apps/client/src/views/editor/welcome/Welcome.tsx @@ -1,11 +1,15 @@ +import { IoClose } from 'react-icons/io5'; import { useNavigate } from 'react-router-dom'; -import { Button, Checkbox, Modal, ModalBody, ModalCloseButton, ModalContent, ModalOverlay } from '@chakra-ui/react'; import { loadDemo, loadProject } from '../../../common/api/db'; import { postShowWelcomeDialog } from '../../../common/api/settings'; import { invalidateAllCaches } from '../../../common/api/utils'; +import Button from '../../../common/components/buttons/Button'; +import IconButton from '../../../common/components/buttons/IconButton'; +import Checkbox from '../../../common/components/checkbox/Checkbox'; import * as Editor from '../../../common/components/editor-utils/EditorUtils'; import ExternalLink from '../../../common/components/link/external-link/ExternalLink'; +import Modal from '../../../common/components/modal/Modal'; import { appVersion, discordUrl, documentationUrl, websiteUrl } from '../../../externals'; import ImportProjectButton from './composite/ImportProjectButton'; @@ -17,8 +21,7 @@ interface WelcomeProps { onClose: () => void; } -export default function Welcome(props: WelcomeProps) { - const { onClose } = props; +export default function Welcome({ onClose }: WelcomeProps) { const navigate = useNavigate(); /** handle cleanup actions before request closing the modal */ @@ -55,54 +58,56 @@ export default function Welcome(props: WelcomeProps) { }; return ( - - - - - -
-
- ontime -
Ontime v{appVersion}
- Website - Read the docs - Discord server + +
+ ontime +
Ontime v{appVersion}
+ Website + Read the docs + Discord server +
+
+
+ Welcome to Ontime + + +
-
-
Welcome to Ontime
- Select project -
- - - - - - - - -
File NameLast Used
-
+ Select project +
+ + + + + + + + +
File NameLast Used
+
+ } + footerElements={ +
- + -
- postShowWelcomeDialog(event.target.checked)} - > + + postShowWelcomeDialog(checked)} /> Show this modal on next startup - - - - + +
+ } + /> ); } diff --git a/apps/client/src/views/editor/welcome/composite/ImportProjectButton.tsx b/apps/client/src/views/editor/welcome/composite/ImportProjectButton.tsx index 7ab6f4f70..1863479d3 100644 --- a/apps/client/src/views/editor/welcome/composite/ImportProjectButton.tsx +++ b/apps/client/src/views/editor/welcome/composite/ImportProjectButton.tsx @@ -4,18 +4,18 @@ */ import { ChangeEvent, useRef } from 'react'; -import { Button, Input } from '@chakra-ui/react'; +import { Input } from '@chakra-ui/react'; import { uploadProjectFile } from '../../../../common/api/db'; import { invalidateAllCaches } from '../../../../common/api/utils'; +import Button from '../../../../common/components/buttons/Button'; import { validateProjectFile } from '../../../../common/utils/uploadUtils'; interface ImportProjectButtonProps { onFinish: () => void; } -export default function ImportProjectButton(props: ImportProjectButtonProps) { - const { onFinish } = props; +export default function ImportProjectButton({ onFinish }: ImportProjectButtonProps) { const fileInputRef = useRef(null); const handleSelectFile = () => { @@ -50,9 +50,7 @@ export default function ImportProjectButton(props: ImportProjectButtonProps) { data-testid='file-input' /> - + ); }