diff --git a/src/app/components/emoji-board/EmojiBoard.css.tsx b/src/app/components/emoji-board/EmojiBoard.css.tsx deleted file mode 100644 index 271e3fb8..00000000 --- a/src/app/components/emoji-board/EmojiBoard.css.tsx +++ /dev/null @@ -1,48 +0,0 @@ -import { style } from '@vanilla-extract/css'; -import { DefaultReset, color, config, toRem } from 'folds'; - -export const Base = style({ - maxWidth: toRem(432), - width: `calc(100vw - 2 * ${config.space.S400})`, - height: toRem(450), - backgroundColor: color.Surface.Container, - color: color.Surface.OnContainer, - border: `${config.borderWidth.B300} solid ${color.Surface.ContainerLine}`, - borderRadius: config.radii.R400, - boxShadow: config.shadow.E200, - overflow: 'hidden', -}); - -export const NativeEmojiSidebarStack = style({ - position: 'sticky', - bottom: '-67%', - zIndex: 1, -}); - -export const Header = style({ - padding: config.space.S300, - paddingBottom: 0, -}); - -export const EmojiGroup = style({ - padding: `${config.space.S300} 0`, -}); - -export const EmojiGroupLabel = style({ - position: 'sticky', - top: config.space.S200, - zIndex: 1, - - margin: 'auto', - padding: `${config.space.S100} ${config.space.S200}`, - borderRadius: config.radii.Pill, - backgroundColor: color.SurfaceVariant.Container, - color: color.SurfaceVariant.OnContainer, -}); - -export const EmojiGroupContent = style([ - DefaultReset, - { - padding: `0 ${config.space.S200}`, - }, -]); diff --git a/src/app/components/emoji-board/EmojiBoard.tsx b/src/app/components/emoji-board/EmojiBoard.tsx index d7beb2e9..5785d657 100644 --- a/src/app/components/emoji-board/EmojiBoard.tsx +++ b/src/app/components/emoji-board/EmojiBoard.tsx @@ -3,20 +3,17 @@ import React, { FocusEventHandler, MouseEventHandler, UIEventHandler, - ReactNode, useCallback, useEffect, useMemo, useRef, } from 'react'; -import { Box, Icons, Line, Scroll, Text, as } from 'folds'; +import { Box, Icons, Scroll } from 'folds'; import FocusTrap from 'focus-trap-react'; import { isKeyHotkey } from 'is-hotkey'; -import classNames from 'classnames'; import { MatrixClient, Room } from 'matrix-js-sdk'; import { Atom, atom, useAtomValue, useSetAtom } from 'jotai'; -import * as css from './EmojiBoard.css'; import { IEmoji, IEmojiGroup, emojiGroups, emojis } from '../../plugins/emoji'; import { IEmojiGroupLabels, useEmojiGroupLabels } from './useEmojiGroupLabels'; import { IEmojiGroupIcons, useEmojiGroupIcons } from './useEmojiGroupIcons'; @@ -48,86 +45,16 @@ import { CustomEmojiItem, ImageGroupIcon, GroupIcon, + getEmojiItemInfo, + getDOMGroupId, + EmojiGroup, + EmojiBoardLayout, } from './components'; -import { EmojiBoardTab, EmojiItemInfo, EmojiType } from './types'; +import { EmojiBoardTab, EmojiType } from './types'; const RECENT_GROUP_ID = 'recent_group'; const SEARCH_GROUP_ID = 'search_group'; -const getDOMGroupId = (id: string): string => `EmojiBoardGroup-${id}`; - -const getEmojiItemInfo = (element: Element): EmojiItemInfo | undefined => { - const type = element.getAttribute('data-emoji-type') as EmojiType | undefined; - const data = element.getAttribute('data-emoji-data'); - const label = element.getAttribute('title'); - const shortcode = element.getAttribute('data-emoji-shortcode'); - - if (type && data && shortcode && label) - return { - type, - data, - shortcode, - label, - }; - return undefined; -}; - -const activeGroupIdAtom = atom(undefined); - -const EmojiBoardLayout = as< - 'div', - { - header: ReactNode; - sidebar?: ReactNode; - children: ReactNode; - } ->(({ className, header, sidebar, children, ...props }, ref) => ( - - - - {header} - - {children} - - - {sidebar} - -)); - -export const EmojiGroup = as< - 'div', - { - id: string; - label: string; - children: ReactNode; - } ->(({ className, id, label, children, ...props }, ref) => ( - - - {label} - -
- - {children} - -
-
-)); - type EmojiSidebarProps = { activeGroupAtom: Atom; handleOpenGroup: (groupId: string) => void; @@ -185,7 +112,13 @@ function EmojiSidebar({ })} )} - + {groups.map((group) => ( atom(undefined), []); const setActiveGroupId = useSetAtom(activeGroupIdAtom); + const mx = useMatrixClient(); const useAuthentication = useMediaAuthentication(); const emojiGroupLabels = useEmojiGroupLabels(); diff --git a/src/app/components/emoji-board/components/Group.tsx b/src/app/components/emoji-board/components/Group.tsx new file mode 100644 index 00000000..cf19c6e0 --- /dev/null +++ b/src/app/components/emoji-board/components/Group.tsx @@ -0,0 +1,34 @@ +import { as, Box, Text } from 'folds'; +import React, { ReactNode } from 'react'; +import classNames from 'classnames'; +import * as css from './styles.css'; + +export const getDOMGroupId = (id: string): string => `EmojiBoardGroup-${id}`; + +export const EmojiGroup = as< + 'div', + { + id: string; + label: string; + children: ReactNode; + } +>(({ className, id, label, children, ...props }, ref) => ( + + + {label} + +
+ + {children} + +
+
+)); diff --git a/src/app/components/emoji-board/components/Item.tsx b/src/app/components/emoji-board/components/Item.tsx index d033132d..c3fd3c3a 100644 --- a/src/app/components/emoji-board/components/Item.tsx +++ b/src/app/components/emoji-board/components/Item.tsx @@ -1,12 +1,28 @@ import React from 'react'; import { Box } from 'folds'; import { MatrixClient } from 'matrix-js-sdk'; -import { EmojiType } from '../types'; +import { EmojiItemInfo, EmojiType } from '../types'; import * as css from './styles.css'; import { PackImageReader } from '../../../plugins/custom-emoji'; import { IEmoji } from '../../../plugins/emoji'; import { mxcUrlToHttp } from '../../../utils/matrix'; +export const getEmojiItemInfo = (element: Element): EmojiItemInfo | undefined => { + const label = element.getAttribute('title'); + const type = element.getAttribute('data-emoji-type') as EmojiType | undefined; + const data = element.getAttribute('data-emoji-data'); + const shortcode = element.getAttribute('data-emoji-shortcode'); + + if (type && data && shortcode && label) + return { + type, + data, + shortcode, + label, + }; + return undefined; +}; + type EmojiItemProps = { emoji: IEmoji; }; diff --git a/src/app/components/emoji-board/components/Layout.tsx b/src/app/components/emoji-board/components/Layout.tsx new file mode 100644 index 00000000..392d4a31 --- /dev/null +++ b/src/app/components/emoji-board/components/Layout.tsx @@ -0,0 +1,30 @@ +import { as, Box, Line } from 'folds'; +import React, { ReactNode } from 'react'; +import classNames from 'classnames'; +import * as css from './styles.css'; + +export const EmojiBoardLayout = as< + 'div', + { + header: ReactNode; + sidebar?: ReactNode; + children: ReactNode; + } +>(({ className, header, sidebar, children, ...props }, ref) => ( + + + + {header} + + {children} + + + {sidebar} + +)); diff --git a/src/app/components/emoji-board/components/index.tsx b/src/app/components/emoji-board/components/index.tsx index 4aeae217..55506668 100644 --- a/src/app/components/emoji-board/components/index.tsx +++ b/src/app/components/emoji-board/components/index.tsx @@ -4,3 +4,5 @@ export * from './Sidebar'; export * from './NoStickerPacks'; export * from './Preview'; export * from './Item'; +export * from './Group'; +export * from './Layout'; diff --git a/src/app/components/emoji-board/components/styles.css.ts b/src/app/components/emoji-board/components/styles.css.ts index 7c9de007..c86a08d8 100644 --- a/src/app/components/emoji-board/components/styles.css.ts +++ b/src/app/components/emoji-board/components/styles.css.ts @@ -1,6 +1,31 @@ import { style } from '@vanilla-extract/css'; import { toRem, color, config, DefaultReset, FocusOutline } from 'folds'; +/** + * Layout + */ + +export const Base = style({ + maxWidth: toRem(432), + width: `calc(100vw - 2 * ${config.space.S400})`, + height: toRem(450), + backgroundColor: color.Surface.Container, + color: color.Surface.OnContainer, + border: `${config.borderWidth.B300} solid ${color.Surface.ContainerLine}`, + borderRadius: config.radii.R400, + boxShadow: config.shadow.E200, + overflow: 'hidden', +}); + +export const Header = style({ + padding: config.space.S300, + paddingBottom: 0, +}); + +/** + * Sidebar + */ + export const Sidebar = style({ width: toRem(54), backgroundColor: color.Surface.Container, @@ -27,6 +52,10 @@ export const SidebarBtnImg = style({ objectFit: 'contain', }); +/** + * Preview + */ + export const Preview = style({ padding: config.space.S200, margin: config.space.S300, @@ -56,6 +85,38 @@ export const PreviewImg = style([ }, ]); +/** + * Group + */ + +export const EmojiGroup = style({ + position: 'relative', + padding: `${config.space.S300} 0`, +}); + +export const EmojiGroupLabel = style({ + position: 'sticky', + top: config.space.S200, + zIndex: 1, + + margin: 'auto', + padding: `${config.space.S100} ${config.space.S200}`, + borderRadius: config.radii.Pill, + backgroundColor: color.SurfaceVariant.Container, + color: color.SurfaceVariant.OnContainer, +}); + +export const EmojiGroupContent = style([ + DefaultReset, + { + padding: `0 ${config.space.S200}`, + }, +]); + +/** + * Item + */ + export const EmojiItem = style([ DefaultReset, FocusOutline,