From e1e8410ba4b64e5751245ae6d929c246c080f4f7 Mon Sep 17 00:00:00 2001 From: Carlos Valente Date: Tue, 8 Jul 2025 20:50:49 +0200 Subject: [PATCH] refactor: migrate UI components and remove chakra migrate pin page migrate copy tag migrate pin input migrate dropdown menus migrate radio buttons migrate switch migrate select migrate textarea migrate colour picker migrate select migrate context menu migrate viewparams remove chakra --- apps/client/package.json | 5 - apps/client/src/App.tsx | 40 +- .../context-menu/ContextMenu.module.scss | 8 - .../components/context-menu/ContextMenu.tsx | 99 --- .../context-menu/ContextMenuOption.tsx | 12 - .../components/copy-tag/CopyTag.module.scss | 40 ++ .../common/components/copy-tag/CopyTag.tsx | 50 +- .../components/dialog/Dialog.module.scss | 2 - .../components/dropdown-menu/DropdownMenu.tsx | 22 +- .../IdentifyOverlay.module.scss | 1 - .../input/auto-text-area/AutoTextArea.tsx | 28 - .../input/auto-textarea/AutoTextarea.tsx | 26 + .../input/colour-input/SwatchPicker.tsx | 12 +- .../input/delay-input/BlockRadio.module.scss | 62 ++ .../input/delay-input/BlockRadio.tsx | 35 ++ .../input/delay-input/DelayInput.module.scss | 20 +- .../input/delay-input/DelayInput.tsx | 23 +- .../popover-picker/PopoverPicker.module.scss | 32 +- .../input/popover-picker/PopoverPicker.tsx | 17 +- .../input/text-input/useReactiveTextInput.tsx | 40 +- .../input/textarea/Textarea.module.scss | 3 +- .../NavigationMenu.module.scss | 2 - .../other-addresses/OtherAddresses.tsx | 7 +- .../protect-route/PinPage.module.scss | 50 ++ .../components/protect-route/PinPage.tsx | 74 +-- .../protect-route/ProtectRoute.module.scss | 49 -- .../radio-group/RadioGroup.module.scss | 74 +++ .../components/radio-group/RadioGroup.tsx | 40 ++ .../components/select/Select.module.scss | 14 +- .../src/common/components/select/Select.tsx | 18 +- .../components/switch/Switch.module.scss | 3 +- .../view-params-editor/ParamInput.module.scss | 42 ++ .../view-params-editor/ParamInput.tsx | 134 ++-- .../ViewParamsEditor.module.scss | 7 +- .../view-params-editor/ViewParamsEditor.tsx | 11 +- .../__tests__/viewParams.utils.test.ts | 79 ++- .../view-params-editor/viewParams.types.ts | 11 +- .../view-params-editor/viewParams.utils.ts | 52 +- .../src/common/hooks/useContextMenu.tsx | 7 +- .../panel-utils/PanelUtils.module.scss | 2 +- .../AutomationForm.module.scss | 5 - .../automations-panel/AutomationForm.tsx | 72 +-- .../AutomationSettingsForm.tsx | 27 +- .../panel/automations-panel/TriggerForm.tsx | 39 +- .../panel/feature-panel/GenerateLinkForm.tsx | 8 +- .../panel/feature-panel/UrlPresetsForm.tsx | 11 +- .../manage-panel/RundownDefaultSettings.tsx | 58 +- .../composite/CustomFieldEntry.tsx | 2 +- .../composite/CustomFieldForm.tsx | 28 +- .../sources-panel/GSheetSetup.tsx | 2 +- .../import-map/ImportMapForm.tsx | 21 +- .../panel/network-panel/NetworkInterfaces.tsx | 7 +- .../ClientControlPanel.module.scss | 5 + .../client-control/ClientList.tsx | 6 +- .../panel/project-panel/ProjectListItem.tsx | 66 +- .../panel/project-panel/ProjectMergeForm.tsx | 35 +- .../panel/settings-panel/GeneralSettings.tsx | 4 +- .../panel/settings-panel/ViewSettings.tsx | 26 +- .../composite/GeneralPinInput.module.scss | 9 + .../composite/GeneralPinInput.tsx | 36 +- .../app-settings/quick-start/QuickStart.tsx | 7 +- .../playback/tap-button/TapButton.module.scss | 24 +- .../control/playback/tap-button/TapButton.tsx | 9 +- apps/client/src/features/log/Log.module.scss | 6 + apps/client/src/features/log/Log.tsx | 5 +- .../operator/edit-modal/EditModal.module.scss | 1 - .../operator/edit-modal/EditModal.tsx | 1 - .../features/operator/operator.options.tsx | 5 +- .../src/features/rundown/RundownExport.tsx | 10 +- .../composite/EventEditorFooter.tsx | 8 +- .../entry-editor/composite/EventTextArea.tsx | 10 +- .../quick-add-cursor/QuickAddInline.tsx | 8 +- .../rundown/rundown-block/RundownBlock.tsx | 9 +- .../RundownContextMenu.tsx | 44 ++ .../rundown/rundown-event/RundownEvent.tsx | 30 +- .../features/viewers/clock/clock.options.ts | 12 +- .../lower-thirds/lowerThird.options.ts | 23 +- .../minimal-timer/minimalTimer.options.ts | 12 +- apps/client/src/index.scss | 76 ++- apps/client/src/theme/OntimeAlert.ts | 20 - apps/client/src/theme/ontimeButton.ts | 78 --- apps/client/src/theme/ontimeCheckbox.ts | 33 - apps/client/src/theme/ontimeDrawer.ts | 22 - apps/client/src/theme/ontimeEditable.ts | 14 - apps/client/src/theme/ontimeMenu.ts | 27 - apps/client/src/theme/ontimeModal.ts | 33 - apps/client/src/theme/ontimeRadio.ts | 48 -- apps/client/src/theme/ontimeSelect.ts | 25 - apps/client/src/theme/ontimeSwitch.ts | 12 - apps/client/src/theme/ontimeTab.ts | 19 - apps/client/src/theme/ontimeTextInputs.ts | 61 -- apps/client/src/theme/ontimeTooltip.ts | 12 - apps/client/src/theme/theme.ts | 146 ----- .../src/views/backstage/backstage.options.ts | 2 +- .../src/views/countdown/countdown.options.ts | 2 +- .../cuesheet-table-elements/MultiLineCell.tsx | 17 +- .../cuesheet-table-menu/CuesheetTableMenu.tsx | 14 +- apps/client/src/views/timer/timer.options.ts | 23 +- .../features/301-spreadsheet-import.spec.ts | 4 +- pnpm-lock.yaml | 580 +----------------- 100 files changed, 1222 insertions(+), 1990 deletions(-) delete mode 100644 apps/client/src/common/components/context-menu/ContextMenu.module.scss delete mode 100644 apps/client/src/common/components/context-menu/ContextMenu.tsx delete mode 100644 apps/client/src/common/components/context-menu/ContextMenuOption.tsx create mode 100644 apps/client/src/common/components/copy-tag/CopyTag.module.scss delete mode 100644 apps/client/src/common/components/input/auto-text-area/AutoTextArea.tsx create mode 100644 apps/client/src/common/components/input/auto-textarea/AutoTextarea.tsx create mode 100644 apps/client/src/common/components/input/delay-input/BlockRadio.module.scss create mode 100644 apps/client/src/common/components/input/delay-input/BlockRadio.tsx create mode 100644 apps/client/src/common/components/protect-route/PinPage.module.scss delete mode 100644 apps/client/src/common/components/protect-route/ProtectRoute.module.scss create mode 100644 apps/client/src/common/components/radio-group/RadioGroup.module.scss create mode 100644 apps/client/src/common/components/radio-group/RadioGroup.tsx create mode 100644 apps/client/src/common/components/view-params-editor/ParamInput.module.scss create mode 100644 apps/client/src/features/app-settings/panel/settings-panel/composite/GeneralPinInput.module.scss create mode 100644 apps/client/src/features/rundown/rundown-context-menu/RundownContextMenu.tsx delete mode 100644 apps/client/src/theme/OntimeAlert.ts delete mode 100644 apps/client/src/theme/ontimeButton.ts delete mode 100644 apps/client/src/theme/ontimeCheckbox.ts delete mode 100644 apps/client/src/theme/ontimeDrawer.ts delete mode 100644 apps/client/src/theme/ontimeEditable.ts delete mode 100644 apps/client/src/theme/ontimeMenu.ts delete mode 100644 apps/client/src/theme/ontimeModal.ts delete mode 100644 apps/client/src/theme/ontimeRadio.ts delete mode 100644 apps/client/src/theme/ontimeSelect.ts delete mode 100644 apps/client/src/theme/ontimeSwitch.ts delete mode 100644 apps/client/src/theme/ontimeTab.ts delete mode 100644 apps/client/src/theme/ontimeTextInputs.ts delete mode 100644 apps/client/src/theme/ontimeTooltip.ts delete mode 100644 apps/client/src/theme/theme.ts diff --git a/apps/client/package.json b/apps/client/package.json index 2ae7b96d0..f788953c3 100644 --- a/apps/client/package.json +++ b/apps/client/package.json @@ -5,13 +5,10 @@ "type": "module", "dependencies": { "@base-ui-components/react": "1.0.0-beta.1", - "@chakra-ui/react": "^2.7.0", "@dnd-kit/core": "^6.3.1", "@dnd-kit/sortable": "^10.0.0", "@dnd-kit/utilities": "^3.2.2", "@emotion/is-prop-valid": "^1.3.1", - "@emotion/react": "^11.10.6", - "@emotion/styled": "^11.10.6", "@fontsource/open-sans": "^5.0.28", "@mantine/hooks": "^8.1.2", "@sentry/react": "^8.43.0", @@ -22,7 +19,6 @@ "autosize": "^6.0.1", "axios": "^1.9.0", "csv-stringify": "^6.4.5", - "framer-motion": "^10.10.0", "prismjs": "^1.29.0", "react": "^18.3.1", "react-colorful": "^5.6.1", @@ -80,7 +76,6 @@ "eslint-plugin-react-compiler": "19.1.0-rc.2", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-simple-import-sort": "^8.0.0", - "happy-dom": "^16.7.2", "ontime-types": "workspace:*", "ontime-utils": "workspace:*", "prettier": "catalog:", diff --git a/apps/client/src/App.tsx b/apps/client/src/App.tsx index 81e140fe5..d63dd0a13 100644 --- a/apps/client/src/App.tsx +++ b/apps/client/src/App.tsx @@ -1,6 +1,5 @@ import { BrowserRouter } from 'react-router-dom'; import { Tooltip } from '@base-ui-components/react/tooltip'; -import { ChakraProvider } from '@chakra-ui/react'; import { QueryClientProvider } from '@tanstack/react-query'; import { ReactQueryDevtools } from '@tanstack/react-query-devtools'; @@ -9,7 +8,6 @@ import IdentifyOverlay from './common/components/identify-overlay/IdentifyOverla import { AppContextProvider } from './common/context/AppContext'; import { ontimeQueryClient } from './common/queryClient'; import { connectSocket } from './common/utils/socket'; -import theme from './theme/theme'; import { TranslationProvider } from './translation/TranslationProvider'; import AppRouter from './AppRouter'; import { baseURI } from './externals'; @@ -18,28 +16,26 @@ connectSocket(); function App() { return ( - - - - - -
- - - - - - - -
+ + + + +
-
+ + + + - - - - - + +
+ +
+ + + + + ); } diff --git a/apps/client/src/common/components/context-menu/ContextMenu.module.scss b/apps/client/src/common/components/context-menu/ContextMenu.module.scss deleted file mode 100644 index da0e345a0..000000000 --- a/apps/client/src/common/components/context-menu/ContextMenu.module.scss +++ /dev/null @@ -1,8 +0,0 @@ -.contextMenuButton { - position: absolute; -} - -.contextMenuBackdrop { - position: fixed; - inset: 0; -} diff --git a/apps/client/src/common/components/context-menu/ContextMenu.tsx b/apps/client/src/common/components/context-menu/ContextMenu.tsx deleted file mode 100644 index 331532ee4..000000000 --- a/apps/client/src/common/components/context-menu/ContextMenu.tsx +++ /dev/null @@ -1,99 +0,0 @@ -// logic (with some modifications) culled from: -// https://github.com/lukasbach/chakra-ui-contextmenu/blob/main/src/ContextMenu.tsx - -import { ReactElement } from 'react'; -import { IconType } from 'react-icons'; -import { Menu, MenuButton, MenuGroup, MenuList } from '@chakra-ui/react'; -import { create } from 'zustand'; - -import { ContextMenuOption } from './ContextMenuOption'; - -import style from './ContextMenu.module.scss'; - -type ContextMenuCoords = { - x: number; - y: number; -}; - -export type OptionWithoutGroup = { - label: string; - isDisabled?: boolean; - icon: IconType; - onClick: () => void; - withDivider?: boolean; -}; - -type OptionWithGroup = { - label: string; - group: Omit[]; -}; - -export type Option = OptionWithoutGroup | OptionWithGroup; - -const isOptionWithGroup = (option: Option): option is OptionWithGroup => 'group' in option; - -type ContextMenuStore = { - coords: ContextMenuCoords; - options: Option[]; - isOpen: boolean; - setContextMenu: (coords: ContextMenuCoords, options: Option[]) => void; - setIsOpen: (newIsOpen: boolean) => void; -}; - -export const useContextMenuStore = create((set) => ({ - coords: { x: 0, y: 0 }, - options: [], - isOpen: false, - setContextMenu: (coords, options) => set(() => ({ coords, options, isOpen: true })), - setIsOpen: (newIsOpen) => set(() => ({ isOpen: newIsOpen })), -})); - -interface ContextMenuProps { - // ReactElement type required due to early `return` (line 51) returning {children} - children: ReactElement; -} - -export const ContextMenu = ({ children }: ContextMenuProps) => { - const { coords, options, isOpen, setIsOpen } = useContextMenuStore(); - - const onClose = () => { - return setIsOpen(false); - }; - - if (!isOpen) { - return children; - } - - return ( - <> - {children} -
- - - - {options.map((option) => - isOptionWithGroup(option) ? ( - - {option.group.map((groupOption) => ( - - ))} - - ) : ( - - ), - )} - - - - ); -}; diff --git a/apps/client/src/common/components/context-menu/ContextMenuOption.tsx b/apps/client/src/common/components/context-menu/ContextMenuOption.tsx deleted file mode 100644 index 0518e2ebf..000000000 --- a/apps/client/src/common/components/context-menu/ContextMenuOption.tsx +++ /dev/null @@ -1,12 +0,0 @@ -import { MenuDivider, MenuItem } from '@chakra-ui/react'; - -import { OptionWithoutGroup } from './ContextMenu'; - -export const ContextMenuOption = ({ label, onClick, isDisabled, icon: Icon, withDivider }: OptionWithoutGroup) => ( - <> - {withDivider && } - } onClick={onClick} isDisabled={isDisabled}> - {label} - - -); diff --git a/apps/client/src/common/components/copy-tag/CopyTag.module.scss b/apps/client/src/common/components/copy-tag/CopyTag.module.scss new file mode 100644 index 000000000..ef4d711f3 --- /dev/null +++ b/apps/client/src/common/components/copy-tag/CopyTag.module.scss @@ -0,0 +1,40 @@ +.copytag { + display: flex; + align-items: center; +} + +.action { + border-top-right-radius: 0; + border-bottom-right-radius: 0; +} + +.label { + border-radius: 3px 0 0 3px; + border: 1px solid $gray-1200; + background-color: $white-3; + padding-inline: 0.5rem 1rem; + line-height: 1em; + display: flex; + align-items: center; + color: $label-gray; +} + +.small { + height: 1.5rem; + font-size: calc(1rem - 3px); +} + +.medium { + height: 2rem; + font-size: calc(1rem - 2px); +} + +.large { + height: 2.5rem; + font-weight: 600; +} + +.copy { + border-top-left-radius: 0; + border-bottom-left-radius: 0; +} diff --git a/apps/client/src/common/components/copy-tag/CopyTag.tsx b/apps/client/src/common/components/copy-tag/CopyTag.tsx index 308041bfb..9b9ab9957 100644 --- a/apps/client/src/common/components/copy-tag/CopyTag.tsx +++ b/apps/client/src/common/components/copy-tag/CopyTag.tsx @@ -1,22 +1,28 @@ import { PropsWithChildren, useState } from 'react'; import { IoCheckmark } from 'react-icons/io5'; import { IoCopy } from 'react-icons/io5'; -import { Button, ButtonGroup, IconButton, Tooltip } from '@chakra-ui/react'; -import { tooltipDelayFast } from '../../../ontimeConfig'; -import { Size } from '../../models/Util.type'; import copyToClipboard from '../../utils/copyToClipboard'; +import { cx } from '../../utils/styleUtils'; +import Button from '../buttons/Button'; +import IconButton from '../buttons/IconButton'; + +import style from './CopyTag.module.scss'; interface CopyTagProps { copyValue: string; - label: string; - size?: Size; disabled?: boolean; onClick?: () => void; + size?: 'small' | 'medium' | 'large'; } -export default function CopyTag(props: PropsWithChildren) { - const { copyValue, label, size = 'xs', disabled, children, onClick } = props; +export default function CopyTag({ + copyValue, + disabled, + size = 'medium', + children, + onClick, +}: PropsWithChildren) { const [copied, setCopied] = useState(false); const handleClick = () => { @@ -28,20 +34,24 @@ export default function CopyTag(props: PropsWithChildren) { }; return ( - - - - : } - variant='ontime-filled' - tabIndex={-1} - onClick={handleClick} - isDisabled={disabled} - /> - - + ) : ( +
{children}
+ )} + + {copied ? : } + +
); } diff --git a/apps/client/src/common/components/dialog/Dialog.module.scss b/apps/client/src/common/components/dialog/Dialog.module.scss index 8eab95871..a8370909e 100644 --- a/apps/client/src/common/components/dialog/Dialog.module.scss +++ b/apps/client/src/common/components/dialog/Dialog.module.scss @@ -3,7 +3,6 @@ top: 10%; left: 50%; - z-index: $zindex-dialog; transform: translateX(-50%); padding-inline: 1rem; @@ -19,7 +18,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); diff --git a/apps/client/src/common/components/dropdown-menu/DropdownMenu.tsx b/apps/client/src/common/components/dropdown-menu/DropdownMenu.tsx index b7f2a4e12..9181871fd 100644 --- a/apps/client/src/common/components/dropdown-menu/DropdownMenu.tsx +++ b/apps/client/src/common/components/dropdown-menu/DropdownMenu.tsx @@ -1,4 +1,5 @@ -import { PropsWithChildren, ReactNode } from 'react'; +import { PropsWithChildren } from 'react'; +import { IconType } from 'react-icons'; import { Menu as BaseMenu } from '@base-ui-components/react/menu'; import style from './DropdownMenu.module.scss'; @@ -7,13 +8,15 @@ type DropdownMenuItemDivider = { type: 'divider' }; type DropdownMenuItem = { type: 'item'; label: string; - icon?: ReactNode; + icon?: IconType; disabled?: boolean; onClick: () => void; }; +export type DropdownMenuOption = DropdownMenuItemDivider | DropdownMenuItem; + interface DropdownMenuProps extends BaseMenu.Trigger.Props { - items: Array; + items: DropdownMenuOption[]; } export function DropdownMenu({ items, children, ...triggerProps }: PropsWithChildren) { @@ -29,7 +32,8 @@ export function DropdownMenu({ items, children, ...triggerProps }: PropsWithChil } return ( - {item.icon} {item.label} + {item.icon && } + {item.label} ); })} @@ -55,12 +59,9 @@ export function PositionedDropdownMenu({ items, isOpen, position, onClose }: Pos if (!open) onClose(); }} > - + - + {items.map((item, index) => { if (item.type === 'divider') { @@ -68,7 +69,8 @@ export function PositionedDropdownMenu({ items, isOpen, position, onClose }: Pos } return ( - {item.icon} {item.label} + {item.icon && } + {item.label} ); })} diff --git a/apps/client/src/common/components/identify-overlay/IdentifyOverlay.module.scss b/apps/client/src/common/components/identify-overlay/IdentifyOverlay.module.scss index e37204230..85f0f8938 100644 --- a/apps/client/src/common/components/identify-overlay/IdentifyOverlay.module.scss +++ b/apps/client/src/common/components/identify-overlay/IdentifyOverlay.module.scss @@ -15,7 +15,6 @@ display: grid; place-content: center; text-align: center; - z-index: $zindex-modal; cursor: pointer; } diff --git a/apps/client/src/common/components/input/auto-text-area/AutoTextArea.tsx b/apps/client/src/common/components/input/auto-text-area/AutoTextArea.tsx deleted file mode 100644 index 9fc23c8ed..000000000 --- a/apps/client/src/common/components/input/auto-text-area/AutoTextArea.tsx +++ /dev/null @@ -1,28 +0,0 @@ -import { RefObject, useEffect } from 'react'; -import { Textarea, TextareaProps } from '@chakra-ui/react'; -// @ts-expect-error no types from library -import autosize from 'autosize/dist/autosize'; - -export const AutoTextArea = (props: TextareaProps & { inputref: RefObject }) => { - const { value, inputref } = props; - - useEffect(() => { - const node = inputref.current; - autosize(inputref.current); - return () => { - autosize.destroy(node); - }; - }, [inputref, value]); - - return ( -