refactor(component): migrate design components (#5000)

```[tasklist]
### Tasks
- [x] Migrate components from [design](https://github.com/toeverything/design)
- [x] Replace all imports from `@toeverything/components`
- [x] Clean up `@toeverything/components` dependencies
- [x] Storybook
```

### Influence

Here are all the components that are influenced by `@toeverything/components`

- `@affine/component`
    - App update `Button` `Tooltip`
    - App sidebar header `IconButton`, `Tooltip`
    - Back `Button`
    - Auth
      - Change email page save `Button`
      - Change password page all `Button`s (Save, Later, Open)
      - Confirm change email `Button`
      - Set password page `Button`
      - Sign in success page `Button`
      - Sign up page `Button`
      - Auth `Modal`
    - Workspace card `Avatar`, `Divider`, `Tooltip`, `IconButton`
    - Share
      - Disable shared public link `Modal`
    - Import page `IconButton`, `Tooltip`
    - Accept invite page `Avatar`, `Button`
    - Invite member `Modal`
    - 404 Page `Avatar`, `Button`, `IconButton`, `Tooltip`
    - Notification center `IconButton`
    - Page list
      - operation cell `IconButton`, `Menu`, `ConfirmModal`, `Tooltip`
      - tags more `Menu`
      - favorite `IconButton`, `Tooltip`
      - new page dropdown `Menu`
      - filter `Menu`, `Button`, `IconButton`
    - Page operation `Menu`
      - export `MenuItem`
      - move to trash `MenuItem`, `ConfirmModal`
    - Workspace header filter `Menu`, `Button`
    - Collection bar `Button`, `Tooltip` (*⚠️ seems not used*)
    - Collection operation `Menu`, `MenuItem`
      - Create collection `Modal`, `Button`
      - Edit collection `Modal`, `Button`
      - Page mode filter `Menu`
      - Page mode `Button`, `Menu`
    - Setting modal
      - storage usage progress `Button`, `Tooltip`
    - On boarding tour `Modal`
- `@affine/core`
  - Bookmark `Menu`
  - Affine error boundary `Button`
  - After sign in send email `Button`
  - After sign up send email `Button`
  - Send email `Button`
  - Sign in `Button`
  - Subscription redirect `Loading`, `Button`
  - Setting `Modal`
    - User plan button `Tooltip`
    - Members `Avatar`, `Button`, `IconButton`, `Loading`, `Tooltip`, `Menu`
    - Profile `Button`, `Avatar`
    - Workspace
      - publish panel `Button`, `Tooltip`
      - export panel `Button`
      - storage panel `Button`, `Tooltip`
      - delete `ConfirmModal`
    - Language `Menu`
    - Account setting `Avatar`, `Button`
    - Date format setting `Menu`
    - Billing `Button`, `IconButton`, `Loading`
    - Payment plans `Button`, `ConfirmModal`, `Modal`, `Tooltip`
  - Create workspace `Modal`, `ConfirmModal`, `Button`
  - Payment disabled `ConfirmModal`
  - Share/Export `Menu`, `Button`, `Divider`
  - Sign out `ConfirmModal`
  - Temp disable affine cloud `Modal`
  - Page detail operation `Menu`
  - Blocksuite mode switch `Tooltip`
  - Login card `Avatar`
  - Help island `Tooltip`
- `plugin`
  - copilot
  - hello world
  - image preview
  - outline
This commit is contained in:
Cats Juice
2023-12-04 08:32:12 +00:00
parent 33c53217c3
commit 0abadbe7bb
34 changed files with 2080 additions and 3 deletions
@@ -0,0 +1,47 @@
import { DialogTrigger } from '@radix-ui/react-dialog';
import clsx from 'clsx';
import type { ButtonProps } from '../button';
import { Button } from '../button';
import { Modal, type ModalProps } from './modal';
import * as styles from './styles.css';
export interface ConfirmModalProps extends ModalProps {
confirmButtonOptions?: ButtonProps;
onConfirm?: () => void;
cancelText?: string;
cancelButtonOptions?: ButtonProps;
}
export const ConfirmModal = ({
children,
confirmButtonOptions,
// FIXME: we need i18n
cancelText = 'Cancel',
cancelButtonOptions,
onConfirm,
width = 480,
...props
}: ConfirmModalProps) => {
return (
<Modal
contentOptions={{ className: styles.confirmModalContainer }}
width={width}
{...props}
>
{children ? (
<div className={styles.confirmModalContent}>{children}</div>
) : null}
<div
className={clsx(styles.modalFooter, {
modalFooterWithChildren: !!children,
})}
>
<DialogTrigger asChild>
<Button {...cancelButtonOptions}>{cancelText}</Button>
</DialogTrigger>
<Button onClick={onConfirm} {...confirmButtonOptions}></Button>
</div>
</Modal>
);
};
@@ -0,0 +1,2 @@
export * from './confirm-modal';
export * from './modal';
@@ -0,0 +1,111 @@
import { CloseIcon } from '@blocksuite/icons';
import type {
DialogContentProps,
DialogOverlayProps,
DialogPortalProps,
DialogProps,
} from '@radix-ui/react-dialog';
import * as Dialog from '@radix-ui/react-dialog';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx';
import { type CSSProperties, forwardRef } from 'react';
import { IconButton, type IconButtonProps } from '../button';
import * as styles from './styles.css';
export interface ModalProps extends DialogProps {
width?: CSSProperties['width'];
height?: CSSProperties['height'];
minHeight?: CSSProperties['minHeight'];
title?: string;
description?: string;
withoutCloseButton?: boolean;
portalOptions?: DialogPortalProps;
contentOptions?: DialogContentProps;
overlayOptions?: DialogOverlayProps;
closeButtonOptions?: IconButtonProps;
}
const getVar = (style: number | string = '', defaultValue = '') => {
return style
? typeof style === 'number'
? `${style}px`
: style
: defaultValue;
};
export const Modal = forwardRef<HTMLDivElement, ModalProps>(
(
{
width,
height,
minHeight = 194,
title,
description,
withoutCloseButton = false,
portalOptions,
contentOptions: {
style: contentStyle,
className: contentClassName,
...otherContentOptions
} = {},
overlayOptions: {
className: overlayClassName,
...otherOverlayOptions
} = {},
closeButtonOptions = {},
children,
...props
},
ref
) => (
<Dialog.Root {...props}>
<Dialog.Portal {...portalOptions}>
<Dialog.Overlay
className={clsx(styles.modalOverlay, overlayClassName)}
{...otherOverlayOptions}
/>
<Dialog.Content
className={clsx(styles.modalContent, contentClassName)}
style={{
...assignInlineVars({
[styles.widthVar]: getVar(width, '50vw'),
[styles.heightVar]: getVar(height, 'unset'),
[styles.minHeightVar]: getVar(minHeight, '26px'),
}),
...contentStyle,
}}
{...otherContentOptions}
ref={ref}
>
{withoutCloseButton ? null : (
<Dialog.Close asChild>
<IconButton
className={styles.closeButton}
aria-label="Close"
type="plain"
{...closeButtonOptions}
>
<CloseIcon />
</IconButton>
</Dialog.Close>
)}
{title ? (
<Dialog.Title className={styles.modalHeader}>{title}</Dialog.Title>
) : null}
{description ? (
<Dialog.Description className={styles.modalDescription}>
{description}
</Dialog.Description>
) : null}
{children}
</Dialog.Content>
</Dialog.Portal>
</Dialog.Root>
)
);
Modal.displayName = 'Modal';
@@ -0,0 +1,79 @@
import { createVar, style } from '@vanilla-extract/css';
export const widthVar = createVar('widthVar');
export const heightVar = createVar('heightVar');
export const minHeightVar = createVar('minHeightVar');
export const modalOverlay = style({
position: 'fixed',
inset: 0,
backgroundColor: 'var(--affine-background-modal-color)',
zIndex: 'var(--affine-z-index-modal)',
});
export const modalContent = style({
vars: {
[widthVar]: '',
[heightVar]: '',
[minHeightVar]: '',
},
width: widthVar,
height: heightVar,
minHeight: minHeightVar,
boxSizing: 'border-box',
fontSize: 'var(--affine-font-base)',
fontWeight: '400',
lineHeight: '1.6',
padding: '20px 24px',
backgroundColor: 'var(--affine-background-overlay-panel-color)',
boxShadow: 'var(--affine-popover-shadow)',
borderRadius: '12px',
maxHeight: 'calc(100vh - 32px)',
// :focus-visible will set outline
outline: 'none',
position: 'fixed',
zIndex: 'var(--affine-z-index-modal)',
top: ' 50%',
left: '50%',
transform: 'translate(-50%, -50%)',
});
export const closeButton = style({
position: 'absolute',
top: '22px',
right: '20px',
});
export const modalHeader = style({
fontSize: 'var(--affine-font-h-6)',
fontWeight: '600',
lineHeight: '1.45',
marginBottom: '12px',
});
export const modalDescription = style({
// marginBottom: '20px',
});
export const modalFooter = style({
display: 'flex',
justifyContent: 'flex-end',
alignItems: 'center',
paddingTop: '40px',
marginTop: 'auto',
gap: '20px',
selectors: {
'&.modalFooterWithChildren': {
paddingTop: '20px',
},
},
});
export const confirmModalContent = style({
marginTop: '12px',
marginBottom: '20px',
});
export const confirmModalContainer = style({
display: 'flex',
flexDirection: 'column',
});