mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
feat: migrate workspace setting with new design to setting modal (#2900)
Co-authored-by: Alex Yang <himself65@outlook.com>
This commit is contained in:
@@ -0,0 +1,4 @@
|
||||
export { SettingModal, type SettingModalProps } from './modal';
|
||||
export { SettingHeader } from './setting-header';
|
||||
export { SettingRow } from './setting-row';
|
||||
export { SettingWrapper } from './wrapper';
|
||||
@@ -0,0 +1,42 @@
|
||||
import { Modal, ModalCloseButton, ModalWrapper } from '@affine/component';
|
||||
import type { FC, PropsWithChildren } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export type SettingModalProps = {
|
||||
open: boolean;
|
||||
setOpen: (value: boolean) => void;
|
||||
};
|
||||
|
||||
export const SettingModal: FC<PropsWithChildren<SettingModalProps>> = ({
|
||||
children,
|
||||
open,
|
||||
setOpen,
|
||||
}) => {
|
||||
const handleClose = useCallback(() => {
|
||||
setOpen(false);
|
||||
}, [setOpen]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
open={open}
|
||||
onClose={handleClose}
|
||||
wrapperPosition={['center', 'center']}
|
||||
data-testid="setting-modal"
|
||||
>
|
||||
<ModalWrapper
|
||||
width={1080}
|
||||
height={760}
|
||||
style={{
|
||||
maxHeight: '85vh',
|
||||
maxWidth: '70vw',
|
||||
overflow: 'hidden',
|
||||
display: 'flex',
|
||||
backgroundColor: 'var(--affine-white)',
|
||||
}}
|
||||
>
|
||||
<ModalCloseButton top={16} right={20} onClick={handleClose} />
|
||||
{children}
|
||||
</ModalWrapper>
|
||||
</Modal>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,14 @@
|
||||
import type { FC } from 'react';
|
||||
|
||||
import { settingHeader } from './share.css';
|
||||
export const SettingHeader: FC<{ title: string; subtitle?: string }> = ({
|
||||
title,
|
||||
subtitle,
|
||||
}) => {
|
||||
return (
|
||||
<div className={settingHeader}>
|
||||
<div className="title">{title}</div>
|
||||
<div className="subtitle">{subtitle}</div>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
import clsx from 'clsx';
|
||||
import type { CSSProperties, FC, PropsWithChildren, ReactElement } from 'react';
|
||||
|
||||
import { settingRow } from './share.css';
|
||||
|
||||
export const SettingRow: FC<
|
||||
PropsWithChildren<{
|
||||
name: string | ReactElement;
|
||||
desc: string | ReactElement;
|
||||
style?: CSSProperties;
|
||||
onClick?: () => void;
|
||||
spreadCol?: boolean;
|
||||
}>
|
||||
> = ({ name, desc, children, onClick, style, spreadCol = true }) => {
|
||||
return (
|
||||
<div
|
||||
className={clsx(settingRow, {
|
||||
'two-col': spreadCol,
|
||||
})}
|
||||
style={style}
|
||||
onClick={onClick}
|
||||
>
|
||||
<div className="left-col">
|
||||
<div className="name">{name}</div>
|
||||
<div className="desc">{desc}</div>
|
||||
</div>
|
||||
{spreadCol ? <div className="right-col">{children}</div> : children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
@@ -0,0 +1,82 @@
|
||||
import { globalStyle, style } from '@vanilla-extract/css';
|
||||
|
||||
export const settingHeader = style({
|
||||
height: '68px',
|
||||
borderBottom: '1px solid var(--affine-border-color)',
|
||||
marginBottom: '24px',
|
||||
});
|
||||
|
||||
globalStyle(`${settingHeader} .title`, {
|
||||
fontSize: 'var(--affine-font-base)',
|
||||
fontWeight: 600,
|
||||
lineHeight: '24px',
|
||||
marginBottom: '4px',
|
||||
});
|
||||
|
||||
globalStyle(`${settingHeader} .subtitle`, {
|
||||
fontSize: 'var(--affine-font-xs)',
|
||||
lineHeight: '16px',
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
});
|
||||
|
||||
export const wrapper = style({
|
||||
borderBottom: '1px solid var(--affine-border-color)',
|
||||
paddingBottom: '24px',
|
||||
marginBottom: '24px',
|
||||
selectors: {
|
||||
'&:last-of-type': {
|
||||
borderBottom: 'none',
|
||||
paddingBottom: '0',
|
||||
marginBottom: '0',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
globalStyle(`${wrapper} .title`, {
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
fontWeight: 600,
|
||||
lineHeight: '18px',
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
marginBottom: '16px',
|
||||
});
|
||||
|
||||
export const settingRow = style({
|
||||
marginBottom: '25px',
|
||||
color: 'var(--affine-text-primary-color)',
|
||||
borderRadius: '8px',
|
||||
selectors: {
|
||||
'&.two-col': {
|
||||
display: 'flex',
|
||||
justifyContent: 'space-between',
|
||||
alignItems: 'center',
|
||||
},
|
||||
'&:last-of-type': {
|
||||
marginBottom: '0',
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
globalStyle(`${settingRow} .left-col`, {
|
||||
flexShrink: 0,
|
||||
maxWidth: '100%',
|
||||
});
|
||||
globalStyle(`${settingRow}.two-col .left-col`, {
|
||||
flexShrink: 0,
|
||||
maxWidth: '80%',
|
||||
});
|
||||
globalStyle(`${settingRow} .name`, {
|
||||
marginBottom: '2px',
|
||||
fontSize: 'var(--affine-font-sm)',
|
||||
fontWeight: 600,
|
||||
});
|
||||
globalStyle(`${settingRow} .desc`, {
|
||||
fontSize: 'var(--affine-font-xs)',
|
||||
color: 'var(--affine-text-secondary-color)',
|
||||
});
|
||||
globalStyle(`${settingRow} .right-col`, {
|
||||
flexGrow: 1,
|
||||
display: 'flex',
|
||||
justifyContent: 'flex-end',
|
||||
paddingLeft: '15px',
|
||||
flexShrink: 0,
|
||||
});
|
||||
@@ -0,0 +1,15 @@
|
||||
import type { FC, PropsWithChildren } from 'react';
|
||||
|
||||
import { wrapper } from './share.css';
|
||||
export const SettingWrapper: FC<
|
||||
PropsWithChildren<{
|
||||
title?: string;
|
||||
}>
|
||||
> = ({ title, children }) => {
|
||||
return (
|
||||
<div className={wrapper}>
|
||||
{title ? <div className="title">{title}</div> : null}
|
||||
{children}
|
||||
</div>
|
||||
);
|
||||
};
|
||||
37
packages/component/src/components/user-avatar/index.tsx
Normal file
37
packages/component/src/components/user-avatar/index.tsx
Normal file
@@ -0,0 +1,37 @@
|
||||
import * as Avatar from '@radix-ui/react-avatar';
|
||||
import clsx from 'clsx';
|
||||
import type { CSSProperties, FC } from 'react';
|
||||
|
||||
import * as style from './style.css';
|
||||
|
||||
export type UserAvatar = {
|
||||
size?: number;
|
||||
url?: string;
|
||||
name?: string;
|
||||
className?: string;
|
||||
style?: CSSProperties;
|
||||
};
|
||||
|
||||
export const UserAvatar: FC<UserAvatar> = ({
|
||||
size = 20,
|
||||
style: propsStyles = {},
|
||||
url,
|
||||
name,
|
||||
className,
|
||||
}) => {
|
||||
return (
|
||||
<Avatar.Root
|
||||
style={{
|
||||
width: size,
|
||||
height: size,
|
||||
...propsStyles,
|
||||
}}
|
||||
className={clsx(style.avatarRoot, className)}
|
||||
>
|
||||
<Avatar.Image className={style.avatarImage} src={url} alt={name} />
|
||||
<Avatar.Fallback className={style.avatarFallback} delayMs={600}>
|
||||
{name?.slice(0, 1) || 'A'}
|
||||
</Avatar.Fallback>
|
||||
</Avatar.Root>
|
||||
);
|
||||
};
|
||||
31
packages/component/src/components/user-avatar/style.css.ts
Normal file
31
packages/component/src/components/user-avatar/style.css.ts
Normal file
@@ -0,0 +1,31 @@
|
||||
import { style } from '@vanilla-extract/css';
|
||||
|
||||
export const avatarRoot = style({
|
||||
display: 'inline-flex',
|
||||
flexShrink: 0,
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
verticalAlign: 'middle',
|
||||
overflow: 'hidden',
|
||||
userSelect: 'none',
|
||||
borderRadius: '100%',
|
||||
});
|
||||
|
||||
export const avatarImage = style({
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
objectFit: 'cover',
|
||||
borderRadius: 'inherit',
|
||||
});
|
||||
export const avatarFallback = style({
|
||||
width: '100%',
|
||||
height: '100%',
|
||||
display: 'flex',
|
||||
alignItems: 'center',
|
||||
justifyContent: 'center',
|
||||
backgroundColor: 'var(--affine-primary-color)',
|
||||
color: 'var(--affine-white)',
|
||||
fontSize: 'var(--affine-font-base)',
|
||||
lineHeight: '1',
|
||||
fontWeight: '500',
|
||||
});
|
||||
@@ -10,14 +10,14 @@ export const SIZE_CONFIG = {
|
||||
fontSize: 16,
|
||||
borderRadius: 4,
|
||||
height: 26,
|
||||
padding: 24,
|
||||
padding: 6,
|
||||
},
|
||||
[SIZE_MIDDLE]: {
|
||||
iconSize: 20,
|
||||
fontSize: 16,
|
||||
borderRadius: 4,
|
||||
height: 32,
|
||||
padding: 24,
|
||||
padding: 12,
|
||||
},
|
||||
[SIZE_DEFAULT]: {
|
||||
iconSize: 24,
|
||||
|
||||
Reference in New Issue
Block a user