fix: a series of setting issues (#3032)

This commit is contained in:
Qi 2023-07-05 22:11:42 +08:00 committed by GitHub
parent dec0c0d3d1
commit 87ba71e77e
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
24 changed files with 235 additions and 463 deletions

View File

@ -1,35 +0,0 @@
import { Button } from '@affine/component';
import type { ContactModalProps } from '@affine/component/contact-modal';
import { ContactModal } from '@affine/component/contact-modal';
import type { StoryFn } from '@storybook/react';
import { useState } from 'react';
export default {
title: 'AFFiNE/ContactModal',
component: ContactModal,
};
export const Basic: StoryFn<ContactModalProps> = args => {
const [open, setOpen] = useState(false);
return (
<>
<Button
onClick={() => {
setOpen(true);
}}
>
Open
</Button>
<ContactModal
{...args}
open={open}
onClose={() => {
setOpen(false);
}}
/>
</>
);
};
Basic.args = {
logoSrc: '/imgs/affine-text-logo.png',
};

View File

@ -2,13 +2,21 @@ import { atom } from 'jotai';
import { atomFamily, atomWithStorage } from 'jotai/utils';
import type { CreateWorkspaceMode } from '../components/affine/create-workspace-modal';
import type { SettingProps } from '../components/affine/setting-modal';
// modal atoms
export const openWorkspacesModalAtom = atom(false);
export const openCreateWorkspaceModalAtom = atom<CreateWorkspaceMode>(false);
export const openQuickSearchModalAtom = atom(false);
export const openOnboardingModalAtom = atom(false);
export const openSettingModalAtom = atom(false);
export type SettingAtom = Pick<SettingProps, 'activeTab' | 'workspace'> & {
open: boolean;
};
export const openSettingModalAtom = atom<SettingAtom>({
open: false,
});
export const openDisableCloudAlertModalAtom = atom(false);

View File

@ -1,4 +1,10 @@
import { Menu, MenuItem, MenuTrigger, styled } from '@affine/component';
import {
type ButtonProps,
Menu,
MenuItem,
MenuTrigger,
styled,
} from '@affine/component';
import { LOCALES } from '@affine/i18n';
import { useI18N } from '@affine/i18n';
import type { FC, ReactElement } from 'react';
@ -41,7 +47,9 @@ const LanguageMenuContent: FC<{
</>
);
};
export const LanguageMenu: FC = () => {
export const LanguageMenu: FC<{ triggerProps: ButtonProps }> = ({
triggerProps,
}) => {
const i18n = useI18N();
const currentLanguage = LOCALES.find(item => item.tag === i18n.language);
@ -62,6 +70,7 @@ export const LanguageMenu: FC = () => {
<MenuTrigger
data-testid="language-menu-button"
style={{ textTransform: 'capitalize' }}
{...triggerProps}
>
{currentLanguage?.originalName}
</MenuTrigger>

View File

@ -0,0 +1,35 @@
import {
DiscordIcon,
GithubIcon,
RedditIcon,
TelegramIcon,
TwitterIcon,
} from './icons';
export const relatedLinks = [
{
icon: <GithubIcon />,
title: 'GitHub',
link: 'https://github.com/toeverything/AFFiNE',
},
{
icon: <RedditIcon />,
title: 'Reddit',
link: 'https://www.reddit.com/r/Affine/',
},
{
icon: <TwitterIcon />,
title: 'Twitter',
link: 'https://twitter.com/AffineOfficial',
},
{
icon: <TelegramIcon />,
title: 'Telegram',
link: 'https://t.me/affineworkos',
},
{
icon: <DiscordIcon />,
title: 'Discord',
link: 'https://discord.gg/Arn7TqJBvG',
},
];

View File

@ -1,5 +1,4 @@
import { Switch } from '@affine/component';
import { relatedLinks } from '@affine/component/contact-modal';
import { SettingHeader } from '@affine/component/setting-components';
import { SettingRow } from '@affine/component/setting-components';
import { SettingWrapper } from '@affine/component/setting-components';
@ -8,6 +7,7 @@ import { ArrowRightSmallIcon, OpenInNewIcon } from '@blocksuite/icons';
import { useCallback } from 'react';
import { type AppSetting, useAppSetting } from '../../../../../atoms/settings';
import { relatedLinks } from './config';
import { communityItem, communityWrapper, link } from './style.css';
export const AboutAffine = () => {

View File

@ -21,6 +21,7 @@ export const ThemeSettings = () => {
return (
<RadioButtonGroup
width={250}
className={settingWrapper}
defaultValue={theme}
onValueChange={useCallback(
@ -30,13 +31,17 @@ export const ThemeSettings = () => {
[setTheme]
)}
>
<RadioButton value="system" data-testid="system-theme-trigger">
<RadioButton
bold={true}
value="system"
data-testid="system-theme-trigger"
>
{t['system']()}
</RadioButton>
<RadioButton value="light" data-testid="light-theme-trigger">
<RadioButton bold={true} value="light" data-testid="light-theme-trigger">
{t['light']()}
</RadioButton>
<RadioButton value="dark" data-testid="dark-theme-trigger">
<RadioButton bold={true} value="dark" data-testid="dark-theme-trigger">
{t['dark']()}
</RadioButton>
</RadioButtonGroup>
@ -72,7 +77,7 @@ export const AppearanceSettings = () => {
desc={t['Select the language for the interface.']()}
>
<div className={settingWrapper}>
<LanguageMenu />
<LanguageMenu triggerProps={{ size: 'small' }} />
</div>
</SettingRow>
{runtimeConfig.enableNewSettingUnstableApi && environment.isDesktop ? (
@ -104,6 +109,7 @@ export const AppearanceSettings = () => {
>
<RadioButtonGroup
className={settingWrapper}
width={250}
defaultValue={appSettings.windowFrameStyle}
onValueChange={(value: AppSetting['windowFrameStyle']) => {
setAppSettings({ windowFrameStyle: value });

View File

@ -2,18 +2,15 @@ import {
SettingModal as SettingModalBase,
type SettingModalProps,
} from '@affine/component/setting-components';
import type {
AffineCloudWorkspace,
LocalWorkspace,
} from '@affine/env/workspace';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { ContactWithUsIcon } from '@blocksuite/icons';
import type React from 'react';
import { useCallback, useMemo, useState } from 'react';
import { useCallback, useMemo } from 'react';
import { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
import { useWorkspaces } from '../../../hooks/use-workspaces';
import type { AllWorkspace } from '../../../shared';
import { AccountSetting } from './account-setting';
import {
GeneralSetting,
@ -22,80 +19,79 @@ import {
} from './general-setting';
import { SettingSidebar } from './setting-sidebar';
import { settingContent } from './style.css';
import type { Workspace } from './type';
import { WorkSpaceSetting } from './workspace-setting';
export const SettingModal: React.FC<SettingModalProps> = ({
type ActiveTab = GeneralSettingKeys | 'workspace' | 'account';
export type SettingProps = {
activeTab?: ActiveTab;
workspace?: AllWorkspace;
onSettingClick: (params: {
activeTab: ActiveTab;
workspace?: AllWorkspace;
}) => void;
};
export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
open,
setOpen,
activeTab = 'appearance',
workspace = null,
onSettingClick,
}) => {
const t = useAFFiNEI18N();
const workspaces = useWorkspaces();
const [currentWorkspace] = useCurrentWorkspace();
const generalSettingList = useGeneralSettingList();
const workspaceList = useMemo(() => {
return workspaces.filter(
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
) as Workspace[];
) as AllWorkspace[];
}, [workspaces]);
const [currentRef, setCurrentRef] = useState<{
workspace: Workspace | null;
generalKey: GeneralSettingKeys | null;
isAccount: boolean;
}>({
workspace: null,
generalKey: generalSettingList[0].key,
isAccount: false,
});
const onGeneralSettingClick = useCallback((key: GeneralSettingKeys) => {
setCurrentRef({
workspace: null,
generalKey: key,
isAccount: false,
});
}, []);
const onWorkspaceSettingClick = useCallback((workspace: Workspace) => {
setCurrentRef({
workspace: workspace,
generalKey: null,
isAccount: false,
});
}, []);
const onGeneralSettingClick = useCallback(
(key: GeneralSettingKeys) => {
onSettingClick({
activeTab: key,
});
},
[onSettingClick]
);
const onWorkspaceSettingClick = useCallback(
(workspace: AllWorkspace) => {
onSettingClick({
activeTab: 'workspace',
workspace,
});
},
[onSettingClick]
);
const onAccountSettingClick = useCallback(() => {
setCurrentRef({
workspace: null,
generalKey: null,
isAccount: true,
});
}, []);
onSettingClick({ activeTab: 'account' });
}, [onSettingClick]);
return (
<SettingModalBase open={open} setOpen={setOpen}>
<SettingSidebar
generalSettingList={generalSettingList}
onGeneralSettingClick={onGeneralSettingClick}
currentWorkspace={
currentWorkspace as AffineCloudWorkspace | LocalWorkspace
}
currentWorkspace={currentWorkspace as AllWorkspace}
workspaceList={workspaceList}
onWorkspaceSettingClick={onWorkspaceSettingClick}
selectedGeneralKey={currentRef.generalKey}
selectedWorkspace={currentRef.workspace}
selectedGeneralKey={activeTab}
selectedWorkspace={workspace}
onAccountSettingClick={onAccountSettingClick}
/>
<div className={settingContent}>
<div className="wrapper">
<div className="content">
{currentRef.workspace ? (
<WorkSpaceSetting workspace={currentRef.workspace} />
{activeTab === 'workspace' && workspace ? (
<WorkSpaceSetting workspace={workspace} />
) : null}
{currentRef.generalKey ? (
<GeneralSetting generalKey={currentRef.generalKey} />
{generalSettingList.find(v => v.key === activeTab) ? (
<GeneralSetting generalKey={activeTab as GeneralSettingKeys} />
) : null}
{currentRef.isAccount ? <AccountSetting /> : null}
{activeTab === 'account' ? <AccountSetting /> : null}
</div>
<div className="footer">
<ContactWithUsIcon />

View File

@ -1,18 +1,14 @@
import { UserAvatar } from '@affine/component/user-avatar';
import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
import type {
AffineCloudWorkspace,
LocalWorkspace,
} from '@affine/env/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
import clsx from 'clsx';
import type { AllWorkspace } from '../../../../shared';
import type {
GeneralSettingKeys,
GeneralSettingList,
} from '../general-setting';
import type { Workspace } from '../type';
import {
accountButton,
settingSlideBar,
@ -34,13 +30,11 @@ export const SettingSidebar = ({
}: {
generalSettingList: GeneralSettingList;
onGeneralSettingClick: (key: GeneralSettingKeys) => void;
currentWorkspace: Workspace;
workspaceList: Workspace[];
onWorkspaceSettingClick: (
workspace: AffineCloudWorkspace | LocalWorkspace
) => void;
currentWorkspace: AllWorkspace;
workspaceList: AllWorkspace[];
onWorkspaceSettingClick: (workspace: AllWorkspace) => void;
selectedWorkspace: Workspace | null;
selectedWorkspace: AllWorkspace | null;
selectedGeneralKey: string | null;
onAccountSettingClick: () => void;
}) => {
@ -118,7 +112,7 @@ const WorkspaceListItem = ({
isCurrent,
isActive,
}: {
workspace: AffineCloudWorkspace | LocalWorkspace;
workspace: AllWorkspace;
onClick: () => void;
isCurrent: boolean;
isActive: boolean;

View File

@ -34,6 +34,7 @@ export const sidebarItemsWrapper = style({
selectors: {
'&.scroll': {
flexGrow: 1,
overflowY: 'auto',
},
},
});

View File

@ -1,6 +0,0 @@
import type {
AffineCloudWorkspace,
LocalWorkspace,
} from '@affine/env/workspace';
export type Workspace = AffineCloudWorkspace | LocalWorkspace;

View File

@ -3,9 +3,13 @@ import { Suspense, useCallback } from 'react';
import { getUIAdapter } from '../../../../adapters/workspace';
import { useOnTransformWorkspace } from '../../../../hooks/root/use-on-transform-workspace';
import { useAppHelper } from '../../../../hooks/use-workspaces';
import type { Workspace } from '../type';
import type { AllWorkspace } from '../../../../shared';
export const WorkSpaceSetting = ({ workspace }: { workspace: Workspace }) => {
export const WorkSpaceSetting = ({
workspace,
}: {
workspace: AllWorkspace;
}) => {
const helper = useAppHelper();
const { NewSettingsDetail } = getUIAdapter(workspace.flavour);

View File

@ -2,9 +2,9 @@ import { MuiFade, Tooltip } from '@affine/component';
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { CloseIcon, NewIcon, UserGuideIcon } from '@blocksuite/icons';
import { useAtom } from 'jotai';
import { lazy, Suspense, useState } from 'react';
import { useCallback, useState } from 'react';
import { openOnboardingModalAtom } from '../../../atoms';
import { openOnboardingModalAtom, openSettingModalAtom } from '../../../atoms';
import { useCurrentMode } from '../../../hooks/current/use-current-mode';
import { ShortcutsModal } from '../shortcuts-modal';
import { ContactIcon, HelpIcon, KeyboardIcon } from './icons';
@ -14,11 +14,7 @@ import {
StyledIsland,
StyledTriggerWrapper,
} from './style';
const ContactModal = lazy(() =>
import('@affine/component/contact-modal').then(({ ContactModal }) => ({
default: ContactModal,
}))
);
const DEFAULT_SHOW_LIST: IslandItemNames[] = [
'whatNew',
'contact',
@ -33,6 +29,7 @@ export const HelpIsland = ({
}) => {
const mode = useCurrentMode();
const [, setOpenOnboarding] = useAtom(openOnboardingModalAtom);
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
const [spread, setShowSpread] = useState(false);
// const { triggerShortcutsModal, triggerContactModal } = useModal();
// const blockHub = useGlobalState(store => store.blockHub);
@ -52,8 +49,18 @@ export const HelpIsland = ({
// useEffect(() => {
// spread && blockHub?.toggleMenu(false);
// }, [blockHub, spread]);
const [open, setOpen] = useState(false);
const [openShortCut, setOpenShortCut] = useState(false);
const openAbout = useCallback(() => {
setShowSpread(false);
setOpenSettingModalAtom({
open: true,
activeTab: 'about',
});
}, [setOpenSettingModalAtom]);
return (
<>
<StyledIsland
@ -83,10 +90,7 @@ export const HelpIsland = ({
<Tooltip content={t['Contact Us']()} placement="left-end">
<StyledIconWrapper
data-testid="right-bottom-contact-us-icon"
onClick={() => {
setShowSpread(false);
setOpen(true);
}}
onClick={openAbout}
>
<ContactIcon />
</StyledIconWrapper>
@ -136,13 +140,6 @@ export const HelpIsland = ({
</StyledTriggerWrapper>
</MuiFade>
</StyledIsland>
<Suspense>
<ContactModal
open={open}
onClose={() => setOpen(false)}
logoSrc="/imgs/affine-text-logo.png"
/>
</Suspense>
<ShortcutsModal
open={openShortCut}
onClose={() => setOpenShortCut(false)}

View File

@ -54,6 +54,7 @@ export const WorkspaceModeFilterTab = ({ ...props }: WorkspaceTitleProps) => {
<Header {...props}>
<div className={styles.allPageListTitleWrapper}>
<RadioButtonGroup
width={300}
defaultValue={value}
onValueChange={handleValueChange}
>

View File

@ -38,6 +38,7 @@ import type { FC, PropsWithChildren, ReactElement } from 'react';
import { lazy, Suspense, useCallback, useEffect, useMemo } from 'react';
import { WorkspaceAdapters } from '../adapters/workspace';
import type { SettingAtom } from '../atoms';
import {
openQuickSearchModalAtom,
openSettingModalAtom,
@ -100,14 +101,33 @@ export const QuickSearch: FC = () => {
};
export const Setting: FC = () => {
const [currentWorkspace] = useCurrentWorkspace();
const [openSettingModal, setOpenSettingModalAtom] =
const [{ open, workspace, activeTab }, setOpenSettingModalAtom] =
useAtom(openSettingModalAtom);
const blockSuiteWorkspace = currentWorkspace?.blockSuiteWorkspace;
const onSettingClick = useCallback(
({
activeTab,
workspace,
}: Pick<SettingAtom, 'activeTab' | 'workspace'>) => {
setOpenSettingModalAtom(prev => ({ ...prev, activeTab, workspace }));
},
[setOpenSettingModalAtom]
);
if (!blockSuiteWorkspace) {
return null;
}
return (
<SettingModal open={openSettingModal} setOpen={setOpenSettingModalAtom} />
<SettingModal
open={open}
activeTab={activeTab || 'appearance'}
workspace={workspace}
onSettingClick={onSettingClick}
setOpen={open => {
setOpenSettingModalAtom(prev => ({ ...prev, open }));
}}
/>
);
};
@ -336,7 +356,7 @@ export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
const handleOpenSettingModal = useCallback(() => {
setOpenSettingModalAtom(true);
setOpenSettingModalAtom({ activeTab: 'appearance', open: true });
}, [setOpenSettingModalAtom]);
const resizing = useAtomValue(appSidebarResizingAtom);

View File

@ -13,10 +13,12 @@ import {
openCreateWorkspaceModalAtom,
openDisableCloudAlertModalAtom,
openOnboardingModalAtom,
openSettingModalAtom,
openWorkspacesModalAtom,
} from '../atoms';
import { useRouterHelper } from '../hooks/use-router-helper';
import { useWorkspaces } from '../hooks/use-workspaces';
import type { AllWorkspace } from '../shared';
const WorkspaceListModal = lazy(() =>
import('../components/pure/workspace-list-modal').then(module => ({
@ -93,6 +95,20 @@ export const AllWorkspaceModals = (): ReactElement => {
rootCurrentWorkspaceIdAtom
);
const [transitioning, transition] = useTransition();
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
const handleOpenSettingModal = useCallback(
(workspace: AllWorkspace) => {
setOpenWorkspacesModal(false);
setOpenSettingModalAtom({
open: true,
activeTab: 'workspace',
workspace,
});
},
[setOpenSettingModalAtom, setOpenWorkspacesModal]
);
return (
<>
<Suspense>
@ -129,18 +145,7 @@ export const AllWorkspaceModals = (): ReactElement => {
},
[jumpToSubPath, setCurrentWorkspaceId, setOpenWorkspacesModal]
)}
onClickWorkspaceSetting={useCallback(
workspace => {
setOpenWorkspacesModal(false);
setCurrentWorkspaceId(workspace.id);
jumpToSubPath(workspace.id, WorkspaceSubPath.SETTING).catch(
error => {
console.error(error);
}
);
},
[jumpToSubPath, setCurrentWorkspaceId, setOpenWorkspacesModal]
)}
onClickWorkspaceSetting={handleOpenSettingModal}
onNewWorkspace={useCallback(() => {
setOpenCreateWorkspaceModal('new');
}, [setOpenCreateWorkspaceModal])}

View File

@ -1,138 +0,0 @@
import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { FlexWrapper, Modal, ModalCloseButton, ModalWrapper } from '../..';
import {
DiscordIcon,
DocIcon,
GithubIcon,
LinkIcon,
LogoIcon,
RedditIcon,
TelegramIcon,
TwitterIcon,
} from './icons';
import {
StyledBigLink,
StyledLogo,
StyledModalFooter,
StyledModalHeader,
StyledPrivacyContainer,
StyledSmallLink,
StyledSubTitle,
} from './style';
export const relatedLinks = [
{
icon: <GithubIcon />,
title: 'GitHub',
link: 'https://github.com/toeverything/AFFiNE',
},
{
icon: <RedditIcon />,
title: 'Reddit',
link: 'https://www.reddit.com/r/Affine/',
},
{
icon: <TwitterIcon />,
title: 'Twitter',
link: 'https://twitter.com/AffineOfficial',
},
{
icon: <TelegramIcon />,
title: 'Telegram',
link: 'https://t.me/affineworkos',
},
{
icon: <DiscordIcon />,
title: 'Discord',
link: 'https://discord.gg/Arn7TqJBvG',
},
];
export type ContactModalProps = {
open: boolean;
onClose: () => void;
logoSrc: string;
};
export const ContactModal = ({
open,
onClose,
logoSrc,
}: ContactModalProps): JSX.Element => {
const t = useAFFiNEI18N();
const topLinkList = [
{
icon: <LogoIcon />,
title: t['Official Website'](),
subTitle: 'AFFiNE.pro',
link: 'https://affine.pro',
},
{
icon: <DocIcon />,
title: t['Check Our Docs'](),
subTitle: 'Open Source',
link: 'https://community.affine.pro',
},
];
const date = new Date();
const year = date.getFullYear();
return (
<Modal open={open} onClose={onClose} data-testid="contact-us-modal-content">
<ModalWrapper width={720} height={436} style={{ letterSpacing: '1px' }}>
<StyledModalHeader>
<StyledLogo src={logoSrc} alt="" />
<ModalCloseButton
onClick={() => {
onClose();
}}
/>
</StyledModalHeader>
<FlexWrapper alignItems="center" justifyContent="center">
{topLinkList.map(({ icon, title, subTitle, link }) => {
return (
<StyledBigLink key={title} href={link} target="_blank">
{icon}
<p>{title}</p>
<p>
{subTitle}
<LinkIcon />
</p>
</StyledBigLink>
);
})}
</FlexWrapper>
<StyledSubTitle>
{t['Get in touch! Join our communities']()}
</StyledSubTitle>
<FlexWrapper justifyContent="center">
{relatedLinks.map(({ icon, title, link }) => {
return (
<StyledSmallLink key={title} href={link} target="_blank">
{icon}
<p>{title}</p>
</StyledSmallLink>
);
})}
</FlexWrapper>
<StyledModalFooter>
<p>Copyright &copy; {year} Toeverything</p>
<StyledPrivacyContainer>
<a href="https://affine.pro/terms" target="_blank" rel="noreferrer">
Terms
</a>
<a
href="https://affine.pro/privacy"
target="_blank"
rel="noreferrer"
>
Privacy
</a>
</StyledPrivacyContainer>
</StyledModalFooter>
</ModalWrapper>
</Modal>
);
};

View File

@ -1,144 +0,0 @@
import { absoluteCenter, displayFlex, styled } from '../..';
export const StyledBigLink = styled('a')(() => {
return {
width: '268px',
height: '76px',
paddingLeft: '96px',
fontSize: '24px',
lineHeight: '36px',
color: 'var(--affine-text-primary-color)',
borderRadius: '10px',
flexDirection: 'column',
...displayFlex('center'),
position: 'relative',
transition: 'background .15s',
letterSpacing: '1px',
':visited': {
color: 'var(--affine-text-primary-color)',
},
':hover': {
background: 'rgba(68, 97, 242, 0.1)',
},
':not(:last-of-type)': {
marginRight: '48px',
},
svg: {
width: '48px',
height: '48px',
marginRight: '24px',
color: 'var(--affine-primary-color)',
...absoluteCenter({ vertical: true, position: { left: '26px' } }),
},
p: {
width: '100%',
height: '24px',
lineHeight: '24px',
...displayFlex('flex-start', 'center'),
':first-of-type': {
marginBottom: '4px',
fontSize: '18px',
fontWeight: '600',
},
':last-of-type': {
fontSize: '16px',
color: 'var(--affine-primary-color)',
fontWeight: '500',
},
svg: {
width: '20px',
height: '20px',
position: 'static',
transform: 'translate(0,0)',
marginLeft: '4px',
},
},
};
});
export const StyledSmallLink = styled('a')(() => {
return {
width: '124px',
height: '76px',
fontSize: '16px',
fontWeight: '500',
borderRadius: '5px',
color: 'var(--affine-text-primary-color)',
transition: 'background .15s, color .15s',
...displayFlex('center', 'center'),
flexWrap: 'wrap',
':visited': {
color: 'var(--affine-text-primary-color)',
},
':hover': {
color: 'var(--affine-primary-color)',
background: 'var(--affine-hover-color)',
},
svg: {
width: '22px',
color: 'var(--affine-primary-color)',
},
p: {
width: '100%',
textAlign: 'center',
},
};
});
export const StyledSubTitle = styled('div')(() => {
return {
fontSize: '18px',
fontWeight: '600',
color: 'var(--affine-text-primary-color)',
marginTop: '52px',
marginBottom: '8px',
textAlign: 'center',
};
});
export const StyledLogo = styled('img')({
height: '18px',
width: 'auto',
marginTop: '24px',
});
export const StyledModalHeader = styled('div')(() => {
return {
height: '72px',
padding: '0 40px',
marginBottom: '24px',
};
});
export const StyledModalFooter = styled('div')(() => {
return {
fontSize: '14px',
lineHeight: '20px',
textAlign: 'center',
color: 'var(--affine-text-primary-color)',
marginTop: '40px',
};
});
export const StyledPrivacyContainer = styled('div')(() => {
return {
marginTop: '4px',
position: 'relative',
a: {
height: '16px',
lineHeight: '16px',
color: 'var(--affine-icon-color)',
padding: '0 8px',
':visited': {
color: 'var(--affine-icon-color)',
},
':first-of-type': {
borderRight: '1px solid var(--affine-border-color)',
},
':hover': {
color: 'var(--affine-primary-color)',
},
},
};
});

View File

@ -31,7 +31,8 @@ export const SettingModal: FC<PropsWithChildren<SettingModalProps>> = ({
maxWidth: '70vw',
overflow: 'hidden',
display: 'flex',
backgroundColor: 'var(--affine-white)',
backgroundColor: 'var(--affine-background-overlay-panel-color)',
boxShadow: 'var(--affine-popover-shadow)',
}}
>
<ModalCloseButton top={16} right={20} onClick={handleClose} />

View File

@ -3,33 +3,45 @@ import type {
RadioGroupProps,
} from '@radix-ui/react-radio-group';
import * as RadioGroup from '@radix-ui/react-radio-group';
import { forwardRef } from 'react';
import clsx from 'clsx';
import { type CSSProperties, forwardRef } from 'react';
import * as styles from './styles.css';
export const RadioButton = forwardRef<HTMLButtonElement, RadioGroupItemProps>(
({ children, ...props }, ref) => {
return (
<RadioGroup.Item ref={ref} {...props}>
<span className={styles.radioUncheckedButton}>{children}</span>
<RadioGroup.Indicator className={styles.radioButton}>
{children}
</RadioGroup.Indicator>
</RadioGroup.Item>
);
}
);
export const RadioButton = forwardRef<
HTMLButtonElement,
RadioGroupItemProps & { bold?: boolean }
>(({ children, bold, className, ...props }, ref) => {
return (
<RadioGroup.Item
ref={ref}
{...props}
className={clsx(styles.radioButton, className)}
>
<span className={clsx(styles.radioUncheckedButton, { bold })}>
{children}
</span>
<RadioGroup.Indicator
className={clsx(styles.radioButtonContent, { bold })}
>
{children}
</RadioGroup.Indicator>
</RadioGroup.Item>
);
});
RadioButton.displayName = 'RadioButton';
export const RadioButtonGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
({ ...props }, ref) => {
return (
<RadioGroup.Root
ref={ref}
className={styles.radioButtonGroup}
{...props}
></RadioGroup.Root>
);
}
);
export const RadioButtonGroup = forwardRef<
HTMLDivElement,
RadioGroupProps & { width?: CSSProperties['width'] }
>(({ className, style, width, ...props }, ref) => {
return (
<RadioGroup.Root
ref={ref}
className={clsx(styles.radioButtonGroup, className)}
style={{ width, ...style }}
{...props}
></RadioGroup.Root>
);
});
RadioButtonGroup.displayName = 'RadioButtonGroup';

View File

@ -54,11 +54,13 @@ export const dropdownIcon = style({
});
export const radioButton = style({
flexGrow: 1,
});
export const radioButtonContent = style({
fontSize: 'var(--affine-font-xs)',
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
padding: '0 30px',
height: '24px',
borderRadius: '8px',
filter: 'drop-shadow(0px 0px 4px rgba(0, 0, 0, 0.1))',
@ -71,11 +73,14 @@ export const radioButton = style({
'&[data-state="checked"]': {
background: 'var(--affine-white)',
},
'&.bold': {
fontWeight: 600,
},
},
});
export const radioUncheckedButton = style([
radioButton,
radioButtonContent,
{
selectors: {
'[data-state="checked"] > &': {
@ -87,7 +92,8 @@ export const radioUncheckedButton = style([
export const radioButtonGroup = style({
display: 'inline-flex',
alignItems: 'flex-start',
justifyContent: 'space-between',
alignItems: 'center',
background: 'var(--affine-hover-color)',
borderRadius: '10px',
padding: '2px',

View File

@ -7,21 +7,21 @@ import { SIZE_DEFAULT, SIZE_MIDDLE, SIZE_SMALL } from './interface';
export const SIZE_CONFIG = {
[SIZE_SMALL]: {
iconSize: 16,
fontSize: 16,
fontSize: 'var(--affine-font-xs)',
borderRadius: 4,
height: 26,
height: 28,
padding: 6,
},
[SIZE_MIDDLE]: {
iconSize: 20,
fontSize: 16,
fontSize: 'var(--affine-font-sm)',
borderRadius: 4,
height: 32,
padding: 12,
},
[SIZE_DEFAULT]: {
iconSize: 24,
fontSize: 16,
fontSize: 'var(--affine-font-base)',
height: 38,
padding: 24,
borderRadius: 4,

View File

@ -105,12 +105,11 @@ export const StyledMenuItem = styled('button')<{
export const StyledButton = styled(Button)(() => {
return {
width: '100%',
height: '32px',
// height: '32px',
borderRadius: '8px',
backgroundColor: 'transparent',
...displayFlex('space-between', 'center'),
border: `1px solid var(--affine-border-color)`,
padding: '0 10px',
fontSize: 'var(--affine-font-base)',
};
});

View File

@ -14,6 +14,7 @@ test('Click right-bottom corner contact icon', async ({ page }) => {
expect(await rightBottomContactUs.isVisible()).toEqual(true);
await rightBottomContactUs.click();
const contactUsModal = page.locator('[data-testid=contact-us-modal-content]');
await expect(contactUsModal).toContainText('Check Our Docs');
const title = await page.getByTestId('about-title');
await expect(title).toBeVisible();
});