diff --git a/blocksuite/affine/fragments/doc-title/src/doc-title.ts b/blocksuite/affine/fragments/doc-title/src/doc-title.ts index acf3baab4..61c966c58 100644 --- a/blocksuite/affine/fragments/doc-title/src/doc-title.ts +++ b/blocksuite/affine/fragments/doc-title/src/doc-title.ts @@ -19,6 +19,7 @@ const DOC_BLOCK_CHILD_PADDING = 24; export class DocTitle extends WithDisposable(ShadowlessElement) { static override styles = css` + .doc-icon-container, .doc-title-container { box-sizing: border-box; font-family: var(--affine-font-family); @@ -49,6 +50,7 @@ export class DocTitle extends WithDisposable(ShadowlessElement) { /* Extra small devices (phones, 640px and down) */ @container viewport (width <= 640px) { + .doc-icon-container, .doc-title-container { padding-left: ${DOC_BLOCK_CHILD_PADDING}px; padding-right: ${DOC_BLOCK_CHILD_PADDING}px; diff --git a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts index 1446acdc0..01431acbc 100644 --- a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts +++ b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.css.ts @@ -14,13 +14,19 @@ export const contentRoot = style({ }); export const iconPicker = style({ - border: `1px solid ${cssVarV2.layer.insideBorder.border}`, - width: 32, - height: 32, padding: 0, +}); +globalStyle(`${iconPicker} span:has(svg)`, { + lineHeight: 0, +}); + +export const iconNamePickerIcon = style({ flexShrink: 0, fontSize: 24, borderRadius: 4, + width: 32, + height: 32, + border: `1px solid ${cssVarV2.layer.insideBorder.border}`, selectors: { '&[data-icon-type="emoji"]': { fontSize: 20, diff --git a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx index 514b92f58..56f2f696f 100644 --- a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx +++ b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.stories.tsx @@ -16,10 +16,10 @@ export default { } satisfies Meta; export const Basic: StoryFn = () => { - const [icon, setIcon] = useState('👋'); + const [icon, setIcon] = useState('👋'); const [name, setName] = useState('Hello'); - const handleIconChange = useCallback((_: IconType, icon: string) => { + const handleIconChange = useCallback((_?: IconType, icon?: string) => { setIcon(icon); }, []); const handleNameChange = useCallback((name: string) => { diff --git a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.tsx b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.tsx index f477a933f..e177e6685 100644 --- a/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.tsx +++ b/packages/frontend/component/src/ui/icon-name-editor/icon-name-editor.tsx @@ -4,7 +4,7 @@ import clsx from 'clsx'; import { useTheme } from 'next-themes'; import { type ReactNode, useCallback, useState } from 'react'; -import { Button } from '../button'; +import { Button, type ButtonProps } from '../button'; import Input from '../input'; import { Menu, type MenuProps } from '../menu'; import * as styles from './icon-name-editor.css'; @@ -12,11 +12,11 @@ import * as styles from './icon-name-editor.css'; export type IconType = 'emoji' | 'affine-icon' | 'blob'; export interface IconEditorProps { - iconType: IconType; - icon: string; + iconType?: IconType; + icon?: string; closeAfterSelect?: boolean; iconPlaceholder?: ReactNode; - onIconChange?: (type: IconType, icon: string) => void; + onIconChange?: (type?: IconType, icon?: string) => void; triggerClassName?: string; } @@ -24,6 +24,8 @@ export interface IconAndNameEditorContentProps extends IconEditorProps { name: string; namePlaceholder?: string; onNameChange?: (name: string) => void; + onEnter?: () => void; + inputTestId?: string; } export interface IconAndNameEditorMenuProps @@ -33,20 +35,23 @@ export interface IconAndNameEditorMenuProps onOpenChange?: (open: boolean) => void; width?: string | number; + skipIfNotChanged?: boolean; } -const IconRenderer = ({ +export const IconRenderer = ({ iconType, icon, + fallback, }: { iconType: IconType; icon: string; + fallback?: ReactNode; }) => { switch (iconType) { case 'emoji': - return
{icon}
; + return
{icon ?? fallback}
; default: - throw new Error(`Unsupported icon type: ${iconType}`); + return
{fallback}
; } }; @@ -59,9 +64,11 @@ export const IconEditor = ({ onIconChange, alignOffset, sideOffset = 4, + triggerVariant, }: IconEditorProps & { alignOffset?: number; sideOffset?: number; + triggerVariant?: ButtonProps['variant']; }) => { const [isPickerOpen, setIsPickerOpen] = useState(false); const { resolvedTheme } = useTheme(); @@ -99,11 +106,18 @@ export const IconEditor = ({ } >