From 0b0efa5bab88be050e6aafca09333e5dc18d02f7 Mon Sep 17 00:00:00 2001 From: Nathan Vasse Date: Thu, 28 Nov 2024 11:29:37 +0100 Subject: [PATCH] =?UTF-8?q?=F0=9F=92=84(front)=20improve=20menu=20and=20se?= =?UTF-8?q?lect=20ui?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit We want to introduce two variant for this lists, so it was needed to create a slot recipe. --- .../src/features/home/routes/Home.tsx | 6 +- .../rooms/components/InviteDialog.tsx | 4 +- .../controls/Options/OptionsMenuItems.tsx | 8 +- src/frontend/src/layout/Header.tsx | 3 +- src/frontend/src/primitives/MenuList.tsx | 14 +++- src/frontend/src/primitives/Select.tsx | 4 +- src/frontend/src/primitives/Tabs.tsx | 2 +- src/frontend/src/primitives/menuItemRecipe.ts | 54 -------------- src/frontend/src/primitives/menuRecipe.ts | 74 +++++++++++++++++++ 9 files changed, 98 insertions(+), 71 deletions(-) delete mode 100644 src/frontend/src/primitives/menuItemRecipe.ts create mode 100644 src/frontend/src/primitives/menuRecipe.ts diff --git a/src/frontend/src/features/home/routes/Home.tsx b/src/frontend/src/features/home/routes/Home.tsx index 1dc924c7..bb715932 100644 --- a/src/frontend/src/features/home/routes/Home.tsx +++ b/src/frontend/src/features/home/routes/Home.tsx @@ -10,7 +10,6 @@ import { JoinMeetingDialog } from '../components/JoinMeetingDialog' import { ProConnectButton } from '@/components/ProConnectButton' import { useCreateRoom } from '@/features/rooms' import { usePersistentUserChoices } from '@livekit/components-react' -import { menuItemRecipe } from '@/primitives/menuItemRecipe' import { RiAddLine, RiLink } from '@remixicon/react' import { LaterMeetingDialog } from '@/features/home/components/LaterMeetingDialog' import { IntroSlider } from '@/features/home/components/IntroSlider' @@ -18,6 +17,7 @@ import { MoreLink } from '@/features/home/components/MoreLink' import { ReactNode, useState } from 'react' import { css } from '@/styled-system/css' +import { menuRecipe } from '@/primitives/menuRecipe.ts'; const Columns = ({ children }: { children?: ReactNode }) => { return ( @@ -173,7 +173,7 @@ export const Home = () => { { const slug = generateRoomId() createRoom({ slug, username }).then((data) => @@ -188,7 +188,7 @@ export const Home = () => { {t('createMenu.instantOption')} { const slug = generateRoomId() createRoom({ slug, username }).then((data) => diff --git a/src/frontend/src/features/rooms/components/InviteDialog.tsx b/src/frontend/src/features/rooms/components/InviteDialog.tsx index bfa18202..197bc23b 100644 --- a/src/frontend/src/features/rooms/components/InviteDialog.tsx +++ b/src/frontend/src/features/rooms/components/InviteDialog.tsx @@ -7,7 +7,7 @@ import { Text, text } from '@/primitives/Text' import { RiCheckLine, RiCloseLine, - RiFileCopyLine, RiLink, + RiFileCopyLine, RiSpam2Fill, } from '@remixicon/react'; import { useEffect, useState } from 'react' @@ -49,8 +49,6 @@ export const InviteDialog = ({ } }, [isCopied]) - const [isHovered, setIsHovered] = useState(false) - return ( {({ close }) => ( diff --git a/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx b/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx index d84e4cb6..48379fef 100644 --- a/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx +++ b/src/frontend/src/features/rooms/livekit/components/controls/Options/OptionsMenuItems.tsx @@ -1,4 +1,3 @@ -import { menuItemRecipe } from '@/primitives/menuItemRecipe' import { RiAccountBoxLine, RiMegaphoneLine, @@ -10,6 +9,7 @@ import { Dispatch, SetStateAction } from 'react' import { DialogState } from './OptionsButton' import { Separator } from '@/primitives/Separator' import { useSidePanel } from '../../../hooks/useSidePanel' +import { menuRecipe } from '@/primitives/menuRecipe.ts'; // @todo try refactoring it to use MenuList component export const OptionsMenuItems = ({ @@ -29,7 +29,7 @@ export const OptionsMenuItems = ({
toggleEffects()} - className={menuItemRecipe({ icon: true })} + className={menuRecipe({ icon: true }).item} > {t('effects')} @@ -40,13 +40,13 @@ export const OptionsMenuItems = ({ {t('feedbacks')} onOpenDialog('settings')} > diff --git a/src/frontend/src/layout/Header.tsx b/src/frontend/src/layout/Header.tsx index ff84fc53..c199e6e0 100644 --- a/src/frontend/src/layout/Header.tsx +++ b/src/frontend/src/layout/Header.tsx @@ -66,7 +66,7 @@ export const Header = () => { { if (value === 'logout') { diff --git a/src/frontend/src/primitives/MenuList.tsx b/src/frontend/src/primitives/MenuList.tsx index dc05503a..280abd96 100644 --- a/src/frontend/src/primitives/MenuList.tsx +++ b/src/frontend/src/primitives/MenuList.tsx @@ -1,6 +1,11 @@ import { ReactNode } from 'react' import { Menu, MenuProps, MenuItem } from 'react-aria-components' -import { menuItemRecipe } from './menuItemRecipe' +import { menuRecipe } from '@/primitives/menuRecipe.ts'; +import type { RecipeVariantProps } from '@/styled-system/types'; + + + + /** * render a Button primitive that shows a popover showing a list of pressable items @@ -14,11 +19,14 @@ export const MenuList = ({ onAction: (key: T) => void selectedItem?: T items: Array -} & MenuProps) => { +} & MenuProps & RecipeVariantProps) => { + const [variantProps] = menuRecipe.splitVariantProps(menuProps) + const classes = menuRecipe({extraPadding: true, ...variantProps}) return ( {items.map((item) => { @@ -26,7 +34,7 @@ export const MenuList = ({ const label = typeof item === 'string' ? item : item.label return ( { diff --git a/src/frontend/src/primitives/Select.tsx b/src/frontend/src/primitives/Select.tsx index 1c592522..ae29148d 100644 --- a/src/frontend/src/primitives/Select.tsx +++ b/src/frontend/src/primitives/Select.tsx @@ -11,7 +11,7 @@ import { } from 'react-aria-components' import { Box } from './Box' import { StyledPopover } from './Popover' -import { menuItemRecipe } from './menuItemRecipe' +import { menuRecipe } from '@/primitives/menuRecipe.ts'; const StyledButton = styled(Button, { base: { @@ -75,7 +75,7 @@ export const Select = ({ {items.map((item) => ( diff --git a/src/frontend/src/primitives/Tabs.tsx b/src/frontend/src/primitives/Tabs.tsx index 33863288..1a43b126 100644 --- a/src/frontend/src/primitives/Tabs.tsx +++ b/src/frontend/src/primitives/Tabs.tsx @@ -66,7 +66,7 @@ const StyledTab = styled(RACTab, { color: 'box.text', }, '&[data-selected]': { - backgroundColor: 'primaryDark.50', + backgroundColor: 'primary.800', color: 'white', }, }, diff --git a/src/frontend/src/primitives/menuItemRecipe.ts b/src/frontend/src/primitives/menuItemRecipe.ts deleted file mode 100644 index 21b785ac..00000000 --- a/src/frontend/src/primitives/menuItemRecipe.ts +++ /dev/null @@ -1,54 +0,0 @@ -import { cva } from '@/styled-system/css' - -/** - * reusable styles for a menu item, select item, etc… to be used with panda `css()` or `styled()` - * - * these are in their own files because react hot refresh doesn't like exporting stuff - * that aren't components in component files - */ -export const menuItemRecipe = cva({ - base: { - paddingY: 0.125, - paddingX: 0.5, - textAlign: 'left', - width: 'full', - borderRadius: 4, - cursor: 'pointer', - color: 'box.text', - border: '1px solid transparent', - position: 'relative', - '&[data-selected]': { - '&::before': { - content: '"✓"', - position: 'absolute', - top: '2px', - left: '6px', - }, - }, - '&[data-focused]': { - color: 'primary.text', - backgroundColor: 'primaryDark.50', - outline: 'none!', - }, - '&[data-hovered]': { - color: 'primary.text', - backgroundColor: 'primaryDark.50', - outline: 'none!', - }, - }, - variants: { - icon: { - true: { - display: 'flex', - alignItems: 'center', - gap: '1rem', - paddingY: '0.4rem', - }, - }, - extraPadding: { - true: { - paddingLeft: 1.5, - }, - }, - }, -}) diff --git a/src/frontend/src/primitives/menuRecipe.ts b/src/frontend/src/primitives/menuRecipe.ts new file mode 100644 index 00000000..4e3e5eab --- /dev/null +++ b/src/frontend/src/primitives/menuRecipe.ts @@ -0,0 +1,74 @@ +import { sva } from '@/styled-system/css'; + +export const menuRecipe = sva({ + slots: ['root', 'item'], + base: { + root: { }, + item: { + paddingY: 0.125, + paddingX: 0.5, + textAlign: 'left', + width: 'full', + borderRadius: 4, + cursor: 'pointer', + color: 'box.text', + border: '1px solid transparent', + position: 'relative', + '&[data-selected]': { + '&::before': { + content: '"✓"', + position: 'absolute', + top: '2px', + left: '6px', + }, + }, + '&[data-focused]': { + color: 'primary.text', + backgroundColor: 'primaryDark.100', + outline: 'none!', + }, + '&[data-hovered]': { + color: 'primary.text', + backgroundColor: 'primaryDark.100', + outline: 'none!', + }, + } + }, + variants: { + variant: { + light: { + item: { + '&[data-focused]': { + backgroundColor: 'primary.800', + }, + '&[data-hovered]': { + backgroundColor: 'primary.800', + }, + } + }, + dark: { + + } + }, + extraPadding: { + true: { + item: { + paddingLeft: 1.5, + } + }, + }, + icon: { + true: { + item: { + display: 'flex', + alignItems: 'center', + gap: '1rem', + paddingY: '0.4rem', + } + }, + }, + }, + defaultVariants: { + variant: 'dark' + } +})