mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-17 06:16:59 +08:00
fix: a series of setting issues (#3032)
(cherry picked from commit 87ba71e77e)
This commit is contained in:
@@ -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',
|
|
||||||
};
|
|
||||||
@@ -2,13 +2,21 @@ import { atom } from 'jotai';
|
|||||||
import { atomFamily, atomWithStorage } from 'jotai/utils';
|
import { atomFamily, atomWithStorage } from 'jotai/utils';
|
||||||
|
|
||||||
import type { CreateWorkspaceMode } from '../components/affine/create-workspace-modal';
|
import type { CreateWorkspaceMode } from '../components/affine/create-workspace-modal';
|
||||||
|
import type { SettingProps } from '../components/affine/setting-modal';
|
||||||
|
|
||||||
// modal atoms
|
// modal atoms
|
||||||
export const openWorkspacesModalAtom = atom(false);
|
export const openWorkspacesModalAtom = atom(false);
|
||||||
export const openCreateWorkspaceModalAtom = atom<CreateWorkspaceMode>(false);
|
export const openCreateWorkspaceModalAtom = atom<CreateWorkspaceMode>(false);
|
||||||
export const openQuickSearchModalAtom = atom(false);
|
export const openQuickSearchModalAtom = atom(false);
|
||||||
export const openOnboardingModalAtom = 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);
|
export const openDisableCloudAlertModalAtom = atom(false);
|
||||||
|
|
||||||
|
|||||||
@@ -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 { LOCALES } from '@affine/i18n';
|
||||||
import { useI18N } from '@affine/i18n';
|
import { useI18N } from '@affine/i18n';
|
||||||
import type { FC, ReactElement } from 'react';
|
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 i18n = useI18N();
|
||||||
|
|
||||||
const currentLanguage = LOCALES.find(item => item.tag === i18n.language);
|
const currentLanguage = LOCALES.find(item => item.tag === i18n.language);
|
||||||
@@ -62,6 +70,7 @@ export const LanguageMenu: FC = () => {
|
|||||||
<MenuTrigger
|
<MenuTrigger
|
||||||
data-testid="language-menu-button"
|
data-testid="language-menu-button"
|
||||||
style={{ textTransform: 'capitalize' }}
|
style={{ textTransform: 'capitalize' }}
|
||||||
|
{...triggerProps}
|
||||||
>
|
>
|
||||||
{currentLanguage?.originalName}
|
{currentLanguage?.originalName}
|
||||||
</MenuTrigger>
|
</MenuTrigger>
|
||||||
|
|||||||
@@ -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',
|
||||||
|
},
|
||||||
|
];
|
||||||
@@ -1,5 +1,4 @@
|
|||||||
import { Switch } from '@affine/component';
|
import { Switch } from '@affine/component';
|
||||||
import { relatedLinks } from '@affine/component/contact-modal';
|
|
||||||
import { SettingHeader } from '@affine/component/setting-components';
|
import { SettingHeader } from '@affine/component/setting-components';
|
||||||
import { SettingRow } from '@affine/component/setting-components';
|
import { SettingRow } from '@affine/component/setting-components';
|
||||||
import { SettingWrapper } 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 { useCallback } from 'react';
|
||||||
|
|
||||||
import { type AppSetting, useAppSetting } from '../../../../../atoms/settings';
|
import { type AppSetting, useAppSetting } from '../../../../../atoms/settings';
|
||||||
|
import { relatedLinks } from './config';
|
||||||
import { communityItem, communityWrapper, link } from './style.css';
|
import { communityItem, communityWrapper, link } from './style.css';
|
||||||
|
|
||||||
export const AboutAffine = () => {
|
export const AboutAffine = () => {
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ export const ThemeSettings = () => {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<RadioButtonGroup
|
<RadioButtonGroup
|
||||||
|
width={250}
|
||||||
className={settingWrapper}
|
className={settingWrapper}
|
||||||
defaultValue={theme}
|
defaultValue={theme}
|
||||||
onValueChange={useCallback(
|
onValueChange={useCallback(
|
||||||
@@ -30,13 +31,17 @@ export const ThemeSettings = () => {
|
|||||||
[setTheme]
|
[setTheme]
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<RadioButton value="system" data-testid="system-theme-trigger">
|
<RadioButton
|
||||||
|
bold={true}
|
||||||
|
value="system"
|
||||||
|
data-testid="system-theme-trigger"
|
||||||
|
>
|
||||||
{t['system']()}
|
{t['system']()}
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
<RadioButton value="light" data-testid="light-theme-trigger">
|
<RadioButton bold={true} value="light" data-testid="light-theme-trigger">
|
||||||
{t['light']()}
|
{t['light']()}
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
<RadioButton value="dark" data-testid="dark-theme-trigger">
|
<RadioButton bold={true} value="dark" data-testid="dark-theme-trigger">
|
||||||
{t['dark']()}
|
{t['dark']()}
|
||||||
</RadioButton>
|
</RadioButton>
|
||||||
</RadioButtonGroup>
|
</RadioButtonGroup>
|
||||||
@@ -72,7 +77,7 @@ export const AppearanceSettings = () => {
|
|||||||
desc={t['Select the language for the interface.']()}
|
desc={t['Select the language for the interface.']()}
|
||||||
>
|
>
|
||||||
<div className={settingWrapper}>
|
<div className={settingWrapper}>
|
||||||
<LanguageMenu />
|
<LanguageMenu triggerProps={{ size: 'small' }} />
|
||||||
</div>
|
</div>
|
||||||
</SettingRow>
|
</SettingRow>
|
||||||
{runtimeConfig.enableNewSettingUnstableApi && environment.isDesktop ? (
|
{runtimeConfig.enableNewSettingUnstableApi && environment.isDesktop ? (
|
||||||
@@ -104,6 +109,7 @@ export const AppearanceSettings = () => {
|
|||||||
>
|
>
|
||||||
<RadioButtonGroup
|
<RadioButtonGroup
|
||||||
className={settingWrapper}
|
className={settingWrapper}
|
||||||
|
width={250}
|
||||||
defaultValue={appSettings.windowFrameStyle}
|
defaultValue={appSettings.windowFrameStyle}
|
||||||
onValueChange={(value: AppSetting['windowFrameStyle']) => {
|
onValueChange={(value: AppSetting['windowFrameStyle']) => {
|
||||||
setAppSettings({ windowFrameStyle: value });
|
setAppSettings({ windowFrameStyle: value });
|
||||||
|
|||||||
@@ -2,18 +2,15 @@ import {
|
|||||||
SettingModal as SettingModalBase,
|
SettingModal as SettingModalBase,
|
||||||
type SettingModalProps,
|
type SettingModalProps,
|
||||||
} from '@affine/component/setting-components';
|
} from '@affine/component/setting-components';
|
||||||
import type {
|
|
||||||
AffineCloudWorkspace,
|
|
||||||
LocalWorkspace,
|
|
||||||
} from '@affine/env/workspace';
|
|
||||||
import { WorkspaceFlavour } from '@affine/env/workspace';
|
import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { ContactWithUsIcon } from '@blocksuite/icons';
|
import { ContactWithUsIcon } from '@blocksuite/icons';
|
||||||
import type React from 'react';
|
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 { useCurrentWorkspace } from '../../../hooks/current/use-current-workspace';
|
||||||
import { useWorkspaces } from '../../../hooks/use-workspaces';
|
import { useWorkspaces } from '../../../hooks/use-workspaces';
|
||||||
|
import type { AllWorkspace } from '../../../shared';
|
||||||
import { AccountSetting } from './account-setting';
|
import { AccountSetting } from './account-setting';
|
||||||
import {
|
import {
|
||||||
GeneralSetting,
|
GeneralSetting,
|
||||||
@@ -22,80 +19,79 @@ import {
|
|||||||
} from './general-setting';
|
} from './general-setting';
|
||||||
import { SettingSidebar } from './setting-sidebar';
|
import { SettingSidebar } from './setting-sidebar';
|
||||||
import { settingContent } from './style.css';
|
import { settingContent } from './style.css';
|
||||||
import type { Workspace } from './type';
|
|
||||||
import { WorkSpaceSetting } from './workspace-setting';
|
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,
|
open,
|
||||||
setOpen,
|
setOpen,
|
||||||
|
activeTab = 'appearance',
|
||||||
|
workspace = null,
|
||||||
|
onSettingClick,
|
||||||
}) => {
|
}) => {
|
||||||
const t = useAFFiNEI18N();
|
const t = useAFFiNEI18N();
|
||||||
|
|
||||||
const workspaces = useWorkspaces();
|
const workspaces = useWorkspaces();
|
||||||
const [currentWorkspace] = useCurrentWorkspace();
|
const [currentWorkspace] = useCurrentWorkspace();
|
||||||
const generalSettingList = useGeneralSettingList();
|
const generalSettingList = useGeneralSettingList();
|
||||||
const workspaceList = useMemo(() => {
|
const workspaceList = useMemo(() => {
|
||||||
return workspaces.filter(
|
return workspaces.filter(
|
||||||
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
|
({ flavour }) => flavour !== WorkspaceFlavour.PUBLIC
|
||||||
) as Workspace[];
|
) as AllWorkspace[];
|
||||||
}, [workspaces]);
|
}, [workspaces]);
|
||||||
|
|
||||||
const [currentRef, setCurrentRef] = useState<{
|
const onGeneralSettingClick = useCallback(
|
||||||
workspace: Workspace | null;
|
(key: GeneralSettingKeys) => {
|
||||||
generalKey: GeneralSettingKeys | null;
|
onSettingClick({
|
||||||
isAccount: boolean;
|
activeTab: key,
|
||||||
}>({
|
});
|
||||||
workspace: null,
|
},
|
||||||
generalKey: generalSettingList[0].key,
|
[onSettingClick]
|
||||||
isAccount: false,
|
);
|
||||||
});
|
const onWorkspaceSettingClick = useCallback(
|
||||||
|
(workspace: AllWorkspace) => {
|
||||||
const onGeneralSettingClick = useCallback((key: GeneralSettingKeys) => {
|
onSettingClick({
|
||||||
setCurrentRef({
|
activeTab: 'workspace',
|
||||||
workspace: null,
|
workspace,
|
||||||
generalKey: key,
|
});
|
||||||
isAccount: false,
|
},
|
||||||
});
|
[onSettingClick]
|
||||||
}, []);
|
);
|
||||||
const onWorkspaceSettingClick = useCallback((workspace: Workspace) => {
|
|
||||||
setCurrentRef({
|
|
||||||
workspace: workspace,
|
|
||||||
generalKey: null,
|
|
||||||
isAccount: false,
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
const onAccountSettingClick = useCallback(() => {
|
const onAccountSettingClick = useCallback(() => {
|
||||||
setCurrentRef({
|
onSettingClick({ activeTab: 'account' });
|
||||||
workspace: null,
|
}, [onSettingClick]);
|
||||||
generalKey: null,
|
|
||||||
isAccount: true,
|
|
||||||
});
|
|
||||||
}, []);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<SettingModalBase open={open} setOpen={setOpen}>
|
<SettingModalBase open={open} setOpen={setOpen}>
|
||||||
<SettingSidebar
|
<SettingSidebar
|
||||||
generalSettingList={generalSettingList}
|
generalSettingList={generalSettingList}
|
||||||
onGeneralSettingClick={onGeneralSettingClick}
|
onGeneralSettingClick={onGeneralSettingClick}
|
||||||
currentWorkspace={
|
currentWorkspace={currentWorkspace as AllWorkspace}
|
||||||
currentWorkspace as AffineCloudWorkspace | LocalWorkspace
|
|
||||||
}
|
|
||||||
workspaceList={workspaceList}
|
workspaceList={workspaceList}
|
||||||
onWorkspaceSettingClick={onWorkspaceSettingClick}
|
onWorkspaceSettingClick={onWorkspaceSettingClick}
|
||||||
selectedGeneralKey={currentRef.generalKey}
|
selectedGeneralKey={activeTab}
|
||||||
selectedWorkspace={currentRef.workspace}
|
selectedWorkspace={workspace}
|
||||||
onAccountSettingClick={onAccountSettingClick}
|
onAccountSettingClick={onAccountSettingClick}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className={settingContent}>
|
<div className={settingContent}>
|
||||||
<div className="wrapper">
|
<div className="wrapper">
|
||||||
<div className="content">
|
<div className="content">
|
||||||
{currentRef.workspace ? (
|
{activeTab === 'workspace' && workspace ? (
|
||||||
<WorkSpaceSetting workspace={currentRef.workspace} />
|
<WorkSpaceSetting workspace={workspace} />
|
||||||
) : null}
|
) : null}
|
||||||
{currentRef.generalKey ? (
|
{generalSettingList.find(v => v.key === activeTab) ? (
|
||||||
<GeneralSetting generalKey={currentRef.generalKey} />
|
<GeneralSetting generalKey={activeTab as GeneralSettingKeys} />
|
||||||
) : null}
|
) : null}
|
||||||
{currentRef.isAccount ? <AccountSetting /> : null}
|
{activeTab === 'account' ? <AccountSetting /> : null}
|
||||||
</div>
|
</div>
|
||||||
<div className="footer">
|
<div className="footer">
|
||||||
<ContactWithUsIcon />
|
<ContactWithUsIcon />
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
import { UserAvatar } from '@affine/component/user-avatar';
|
import { UserAvatar } from '@affine/component/user-avatar';
|
||||||
import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
|
import { WorkspaceAvatar } from '@affine/component/workspace-avatar';
|
||||||
import type {
|
|
||||||
AffineCloudWorkspace,
|
|
||||||
LocalWorkspace,
|
|
||||||
} from '@affine/env/workspace';
|
|
||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||||
import clsx from 'clsx';
|
import clsx from 'clsx';
|
||||||
|
|
||||||
|
import type { AllWorkspace } from '../../../../shared';
|
||||||
import type {
|
import type {
|
||||||
GeneralSettingKeys,
|
GeneralSettingKeys,
|
||||||
GeneralSettingList,
|
GeneralSettingList,
|
||||||
} from '../general-setting';
|
} from '../general-setting';
|
||||||
import type { Workspace } from '../type';
|
|
||||||
import {
|
import {
|
||||||
accountButton,
|
accountButton,
|
||||||
settingSlideBar,
|
settingSlideBar,
|
||||||
@@ -34,13 +30,11 @@ export const SettingSidebar = ({
|
|||||||
}: {
|
}: {
|
||||||
generalSettingList: GeneralSettingList;
|
generalSettingList: GeneralSettingList;
|
||||||
onGeneralSettingClick: (key: GeneralSettingKeys) => void;
|
onGeneralSettingClick: (key: GeneralSettingKeys) => void;
|
||||||
currentWorkspace: Workspace;
|
currentWorkspace: AllWorkspace;
|
||||||
workspaceList: Workspace[];
|
workspaceList: AllWorkspace[];
|
||||||
onWorkspaceSettingClick: (
|
onWorkspaceSettingClick: (workspace: AllWorkspace) => void;
|
||||||
workspace: AffineCloudWorkspace | LocalWorkspace
|
|
||||||
) => void;
|
|
||||||
|
|
||||||
selectedWorkspace: Workspace | null;
|
selectedWorkspace: AllWorkspace | null;
|
||||||
selectedGeneralKey: string | null;
|
selectedGeneralKey: string | null;
|
||||||
onAccountSettingClick: () => void;
|
onAccountSettingClick: () => void;
|
||||||
}) => {
|
}) => {
|
||||||
@@ -118,7 +112,7 @@ const WorkspaceListItem = ({
|
|||||||
isCurrent,
|
isCurrent,
|
||||||
isActive,
|
isActive,
|
||||||
}: {
|
}: {
|
||||||
workspace: AffineCloudWorkspace | LocalWorkspace;
|
workspace: AllWorkspace;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
isCurrent: boolean;
|
isCurrent: boolean;
|
||||||
isActive: boolean;
|
isActive: boolean;
|
||||||
|
|||||||
@@ -34,6 +34,7 @@ export const sidebarItemsWrapper = style({
|
|||||||
selectors: {
|
selectors: {
|
||||||
'&.scroll': {
|
'&.scroll': {
|
||||||
flexGrow: 1,
|
flexGrow: 1,
|
||||||
|
overflowY: 'auto',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -1,6 +0,0 @@
|
|||||||
import type {
|
|
||||||
AffineCloudWorkspace,
|
|
||||||
LocalWorkspace,
|
|
||||||
} from '@affine/env/workspace';
|
|
||||||
|
|
||||||
export type Workspace = AffineCloudWorkspace | LocalWorkspace;
|
|
||||||
@@ -3,9 +3,13 @@ import { Suspense, useCallback } from 'react';
|
|||||||
import { getUIAdapter } from '../../../../adapters/workspace';
|
import { getUIAdapter } from '../../../../adapters/workspace';
|
||||||
import { useOnTransformWorkspace } from '../../../../hooks/root/use-on-transform-workspace';
|
import { useOnTransformWorkspace } from '../../../../hooks/root/use-on-transform-workspace';
|
||||||
import { useAppHelper } from '../../../../hooks/use-workspaces';
|
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 helper = useAppHelper();
|
||||||
const { NewSettingsDetail } = getUIAdapter(workspace.flavour);
|
const { NewSettingsDetail } = getUIAdapter(workspace.flavour);
|
||||||
|
|
||||||
|
|||||||
@@ -2,9 +2,9 @@ import { MuiFade, Tooltip } from '@affine/component';
|
|||||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||||
import { CloseIcon, NewIcon, UserGuideIcon } from '@blocksuite/icons';
|
import { CloseIcon, NewIcon, UserGuideIcon } from '@blocksuite/icons';
|
||||||
import { useAtom } from 'jotai';
|
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 { useCurrentMode } from '../../../hooks/current/use-current-mode';
|
||||||
import { ShortcutsModal } from '../shortcuts-modal';
|
import { ShortcutsModal } from '../shortcuts-modal';
|
||||||
import { ContactIcon, HelpIcon, KeyboardIcon } from './icons';
|
import { ContactIcon, HelpIcon, KeyboardIcon } from './icons';
|
||||||
@@ -14,11 +14,7 @@ import {
|
|||||||
StyledIsland,
|
StyledIsland,
|
||||||
StyledTriggerWrapper,
|
StyledTriggerWrapper,
|
||||||
} from './style';
|
} from './style';
|
||||||
const ContactModal = lazy(() =>
|
|
||||||
import('@affine/component/contact-modal').then(({ ContactModal }) => ({
|
|
||||||
default: ContactModal,
|
|
||||||
}))
|
|
||||||
);
|
|
||||||
const DEFAULT_SHOW_LIST: IslandItemNames[] = [
|
const DEFAULT_SHOW_LIST: IslandItemNames[] = [
|
||||||
'whatNew',
|
'whatNew',
|
||||||
'contact',
|
'contact',
|
||||||
@@ -33,6 +29,7 @@ export const HelpIsland = ({
|
|||||||
}) => {
|
}) => {
|
||||||
const mode = useCurrentMode();
|
const mode = useCurrentMode();
|
||||||
const [, setOpenOnboarding] = useAtom(openOnboardingModalAtom);
|
const [, setOpenOnboarding] = useAtom(openOnboardingModalAtom);
|
||||||
|
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
|
||||||
const [spread, setShowSpread] = useState(false);
|
const [spread, setShowSpread] = useState(false);
|
||||||
// const { triggerShortcutsModal, triggerContactModal } = useModal();
|
// const { triggerShortcutsModal, triggerContactModal } = useModal();
|
||||||
// const blockHub = useGlobalState(store => store.blockHub);
|
// const blockHub = useGlobalState(store => store.blockHub);
|
||||||
@@ -52,8 +49,18 @@ export const HelpIsland = ({
|
|||||||
// useEffect(() => {
|
// useEffect(() => {
|
||||||
// spread && blockHub?.toggleMenu(false);
|
// spread && blockHub?.toggleMenu(false);
|
||||||
// }, [blockHub, spread]);
|
// }, [blockHub, spread]);
|
||||||
const [open, setOpen] = useState(false);
|
|
||||||
const [openShortCut, setOpenShortCut] = useState(false);
|
const [openShortCut, setOpenShortCut] = useState(false);
|
||||||
|
|
||||||
|
const openAbout = useCallback(() => {
|
||||||
|
setShowSpread(false);
|
||||||
|
|
||||||
|
setOpenSettingModalAtom({
|
||||||
|
open: true,
|
||||||
|
activeTab: 'about',
|
||||||
|
});
|
||||||
|
}, [setOpenSettingModalAtom]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<StyledIsland
|
<StyledIsland
|
||||||
@@ -83,10 +90,7 @@ export const HelpIsland = ({
|
|||||||
<Tooltip content={t['Contact Us']()} placement="left-end">
|
<Tooltip content={t['Contact Us']()} placement="left-end">
|
||||||
<StyledIconWrapper
|
<StyledIconWrapper
|
||||||
data-testid="right-bottom-contact-us-icon"
|
data-testid="right-bottom-contact-us-icon"
|
||||||
onClick={() => {
|
onClick={openAbout}
|
||||||
setShowSpread(false);
|
|
||||||
setOpen(true);
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
<ContactIcon />
|
<ContactIcon />
|
||||||
</StyledIconWrapper>
|
</StyledIconWrapper>
|
||||||
@@ -136,13 +140,6 @@ export const HelpIsland = ({
|
|||||||
</StyledTriggerWrapper>
|
</StyledTriggerWrapper>
|
||||||
</MuiFade>
|
</MuiFade>
|
||||||
</StyledIsland>
|
</StyledIsland>
|
||||||
<Suspense>
|
|
||||||
<ContactModal
|
|
||||||
open={open}
|
|
||||||
onClose={() => setOpen(false)}
|
|
||||||
logoSrc="/imgs/affine-text-logo.png"
|
|
||||||
/>
|
|
||||||
</Suspense>
|
|
||||||
<ShortcutsModal
|
<ShortcutsModal
|
||||||
open={openShortCut}
|
open={openShortCut}
|
||||||
onClose={() => setOpenShortCut(false)}
|
onClose={() => setOpenShortCut(false)}
|
||||||
|
|||||||
@@ -54,6 +54,7 @@ export const WorkspaceModeFilterTab = ({ ...props }: WorkspaceTitleProps) => {
|
|||||||
<Header {...props}>
|
<Header {...props}>
|
||||||
<div className={styles.allPageListTitleWrapper}>
|
<div className={styles.allPageListTitleWrapper}>
|
||||||
<RadioButtonGroup
|
<RadioButtonGroup
|
||||||
|
width={300}
|
||||||
defaultValue={value}
|
defaultValue={value}
|
||||||
onValueChange={handleValueChange}
|
onValueChange={handleValueChange}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -38,6 +38,7 @@ import type { FC, PropsWithChildren, ReactElement } from 'react';
|
|||||||
import { lazy, Suspense, useCallback, useEffect, useMemo } from 'react';
|
import { lazy, Suspense, useCallback, useEffect, useMemo } from 'react';
|
||||||
|
|
||||||
import { WorkspaceAdapters } from '../adapters/workspace';
|
import { WorkspaceAdapters } from '../adapters/workspace';
|
||||||
|
import type { SettingAtom } from '../atoms';
|
||||||
import {
|
import {
|
||||||
openQuickSearchModalAtom,
|
openQuickSearchModalAtom,
|
||||||
openSettingModalAtom,
|
openSettingModalAtom,
|
||||||
@@ -100,14 +101,33 @@ export const QuickSearch: FC = () => {
|
|||||||
};
|
};
|
||||||
export const Setting: FC = () => {
|
export const Setting: FC = () => {
|
||||||
const [currentWorkspace] = useCurrentWorkspace();
|
const [currentWorkspace] = useCurrentWorkspace();
|
||||||
const [openSettingModal, setOpenSettingModalAtom] =
|
const [{ open, workspace, activeTab }, setOpenSettingModalAtom] =
|
||||||
useAtom(openSettingModalAtom);
|
useAtom(openSettingModalAtom);
|
||||||
const blockSuiteWorkspace = currentWorkspace?.blockSuiteWorkspace;
|
const blockSuiteWorkspace = currentWorkspace?.blockSuiteWorkspace;
|
||||||
|
|
||||||
|
const onSettingClick = useCallback(
|
||||||
|
({
|
||||||
|
activeTab,
|
||||||
|
workspace,
|
||||||
|
}: Pick<SettingAtom, 'activeTab' | 'workspace'>) => {
|
||||||
|
setOpenSettingModalAtom(prev => ({ ...prev, activeTab, workspace }));
|
||||||
|
},
|
||||||
|
[setOpenSettingModalAtom]
|
||||||
|
);
|
||||||
|
|
||||||
if (!blockSuiteWorkspace) {
|
if (!blockSuiteWorkspace) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
return (
|
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 [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
|
||||||
|
|
||||||
const handleOpenSettingModal = useCallback(() => {
|
const handleOpenSettingModal = useCallback(() => {
|
||||||
setOpenSettingModalAtom(true);
|
setOpenSettingModalAtom({ activeTab: 'appearance', open: true });
|
||||||
}, [setOpenSettingModalAtom]);
|
}, [setOpenSettingModalAtom]);
|
||||||
|
|
||||||
const resizing = useAtomValue(appSidebarResizingAtom);
|
const resizing = useAtomValue(appSidebarResizingAtom);
|
||||||
|
|||||||
@@ -13,10 +13,12 @@ import {
|
|||||||
openCreateWorkspaceModalAtom,
|
openCreateWorkspaceModalAtom,
|
||||||
openDisableCloudAlertModalAtom,
|
openDisableCloudAlertModalAtom,
|
||||||
openOnboardingModalAtom,
|
openOnboardingModalAtom,
|
||||||
|
openSettingModalAtom,
|
||||||
openWorkspacesModalAtom,
|
openWorkspacesModalAtom,
|
||||||
} from '../atoms';
|
} from '../atoms';
|
||||||
import { useRouterHelper } from '../hooks/use-router-helper';
|
import { useRouterHelper } from '../hooks/use-router-helper';
|
||||||
import { useWorkspaces } from '../hooks/use-workspaces';
|
import { useWorkspaces } from '../hooks/use-workspaces';
|
||||||
|
import type { AllWorkspace } from '../shared';
|
||||||
|
|
||||||
const WorkspaceListModal = lazy(() =>
|
const WorkspaceListModal = lazy(() =>
|
||||||
import('../components/pure/workspace-list-modal').then(module => ({
|
import('../components/pure/workspace-list-modal').then(module => ({
|
||||||
@@ -93,6 +95,20 @@ export const AllWorkspaceModals = (): ReactElement => {
|
|||||||
rootCurrentWorkspaceIdAtom
|
rootCurrentWorkspaceIdAtom
|
||||||
);
|
);
|
||||||
const [transitioning, transition] = useTransition();
|
const [transitioning, transition] = useTransition();
|
||||||
|
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
|
||||||
|
|
||||||
|
const handleOpenSettingModal = useCallback(
|
||||||
|
(workspace: AllWorkspace) => {
|
||||||
|
setOpenWorkspacesModal(false);
|
||||||
|
|
||||||
|
setOpenSettingModalAtom({
|
||||||
|
open: true,
|
||||||
|
activeTab: 'workspace',
|
||||||
|
workspace,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[setOpenSettingModalAtom, setOpenWorkspacesModal]
|
||||||
|
);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Suspense>
|
<Suspense>
|
||||||
@@ -129,18 +145,7 @@ export const AllWorkspaceModals = (): ReactElement => {
|
|||||||
},
|
},
|
||||||
[jumpToSubPath, setCurrentWorkspaceId, setOpenWorkspacesModal]
|
[jumpToSubPath, setCurrentWorkspaceId, setOpenWorkspacesModal]
|
||||||
)}
|
)}
|
||||||
onClickWorkspaceSetting={useCallback(
|
onClickWorkspaceSetting={handleOpenSettingModal}
|
||||||
workspace => {
|
|
||||||
setOpenWorkspacesModal(false);
|
|
||||||
setCurrentWorkspaceId(workspace.id);
|
|
||||||
jumpToSubPath(workspace.id, WorkspaceSubPath.SETTING).catch(
|
|
||||||
error => {
|
|
||||||
console.error(error);
|
|
||||||
}
|
|
||||||
);
|
|
||||||
},
|
|
||||||
[jumpToSubPath, setCurrentWorkspaceId, setOpenWorkspacesModal]
|
|
||||||
)}
|
|
||||||
onNewWorkspace={useCallback(() => {
|
onNewWorkspace={useCallback(() => {
|
||||||
setOpenCreateWorkspaceModal('new');
|
setOpenCreateWorkspaceModal('new');
|
||||||
}, [setOpenCreateWorkspaceModal])}
|
}, [setOpenCreateWorkspaceModal])}
|
||||||
|
|||||||
@@ -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 © {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>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
@@ -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)',
|
|
||||||
},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
});
|
|
||||||
@@ -31,7 +31,8 @@ export const SettingModal: FC<PropsWithChildren<SettingModalProps>> = ({
|
|||||||
maxWidth: '70vw',
|
maxWidth: '70vw',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
display: 'flex',
|
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} />
|
<ModalCloseButton top={16} right={20} onClick={handleClose} />
|
||||||
|
|||||||
@@ -3,33 +3,45 @@ import type {
|
|||||||
RadioGroupProps,
|
RadioGroupProps,
|
||||||
} from '@radix-ui/react-radio-group';
|
} from '@radix-ui/react-radio-group';
|
||||||
import * as RadioGroup 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';
|
import * as styles from './styles.css';
|
||||||
|
|
||||||
export const RadioButton = forwardRef<HTMLButtonElement, RadioGroupItemProps>(
|
export const RadioButton = forwardRef<
|
||||||
({ children, ...props }, ref) => {
|
HTMLButtonElement,
|
||||||
return (
|
RadioGroupItemProps & { bold?: boolean }
|
||||||
<RadioGroup.Item ref={ref} {...props}>
|
>(({ children, bold, className, ...props }, ref) => {
|
||||||
<span className={styles.radioUncheckedButton}>{children}</span>
|
return (
|
||||||
<RadioGroup.Indicator className={styles.radioButton}>
|
<RadioGroup.Item
|
||||||
{children}
|
ref={ref}
|
||||||
</RadioGroup.Indicator>
|
{...props}
|
||||||
</RadioGroup.Item>
|
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';
|
RadioButton.displayName = 'RadioButton';
|
||||||
|
|
||||||
export const RadioButtonGroup = forwardRef<HTMLDivElement, RadioGroupProps>(
|
export const RadioButtonGroup = forwardRef<
|
||||||
({ ...props }, ref) => {
|
HTMLDivElement,
|
||||||
return (
|
RadioGroupProps & { width?: CSSProperties['width'] }
|
||||||
<RadioGroup.Root
|
>(({ className, style, width, ...props }, ref) => {
|
||||||
ref={ref}
|
return (
|
||||||
className={styles.radioButtonGroup}
|
<RadioGroup.Root
|
||||||
{...props}
|
ref={ref}
|
||||||
></RadioGroup.Root>
|
className={clsx(styles.radioButtonGroup, className)}
|
||||||
);
|
style={{ width, ...style }}
|
||||||
}
|
{...props}
|
||||||
);
|
></RadioGroup.Root>
|
||||||
|
);
|
||||||
|
});
|
||||||
RadioButtonGroup.displayName = 'RadioButtonGroup';
|
RadioButtonGroup.displayName = 'RadioButtonGroup';
|
||||||
|
|||||||
@@ -54,11 +54,13 @@ export const dropdownIcon = style({
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const radioButton = style({
|
export const radioButton = style({
|
||||||
|
flexGrow: 1,
|
||||||
|
});
|
||||||
|
export const radioButtonContent = style({
|
||||||
fontSize: 'var(--affine-font-xs)',
|
fontSize: 'var(--affine-font-xs)',
|
||||||
display: 'flex',
|
display: 'flex',
|
||||||
justifyContent: 'center',
|
justifyContent: 'center',
|
||||||
alignItems: 'center',
|
alignItems: 'center',
|
||||||
padding: '0 30px',
|
|
||||||
height: '24px',
|
height: '24px',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
filter: 'drop-shadow(0px 0px 4px rgba(0, 0, 0, 0.1))',
|
filter: 'drop-shadow(0px 0px 4px rgba(0, 0, 0, 0.1))',
|
||||||
@@ -71,11 +73,14 @@ export const radioButton = style({
|
|||||||
'&[data-state="checked"]': {
|
'&[data-state="checked"]': {
|
||||||
background: 'var(--affine-white)',
|
background: 'var(--affine-white)',
|
||||||
},
|
},
|
||||||
|
'&.bold': {
|
||||||
|
fontWeight: 600,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const radioUncheckedButton = style([
|
export const radioUncheckedButton = style([
|
||||||
radioButton,
|
radioButtonContent,
|
||||||
{
|
{
|
||||||
selectors: {
|
selectors: {
|
||||||
'[data-state="checked"] > &': {
|
'[data-state="checked"] > &': {
|
||||||
@@ -87,7 +92,8 @@ export const radioUncheckedButton = style([
|
|||||||
|
|
||||||
export const radioButtonGroup = style({
|
export const radioButtonGroup = style({
|
||||||
display: 'inline-flex',
|
display: 'inline-flex',
|
||||||
alignItems: 'flex-start',
|
justifyContent: 'space-between',
|
||||||
|
alignItems: 'center',
|
||||||
background: 'var(--affine-hover-color)',
|
background: 'var(--affine-hover-color)',
|
||||||
borderRadius: '10px',
|
borderRadius: '10px',
|
||||||
padding: '2px',
|
padding: '2px',
|
||||||
|
|||||||
@@ -7,21 +7,21 @@ import { SIZE_DEFAULT, SIZE_MIDDLE, SIZE_SMALL } from './interface';
|
|||||||
export const SIZE_CONFIG = {
|
export const SIZE_CONFIG = {
|
||||||
[SIZE_SMALL]: {
|
[SIZE_SMALL]: {
|
||||||
iconSize: 16,
|
iconSize: 16,
|
||||||
fontSize: 16,
|
fontSize: 'var(--affine-font-xs)',
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
height: 26,
|
height: 28,
|
||||||
padding: 6,
|
padding: 6,
|
||||||
},
|
},
|
||||||
[SIZE_MIDDLE]: {
|
[SIZE_MIDDLE]: {
|
||||||
iconSize: 20,
|
iconSize: 20,
|
||||||
fontSize: 16,
|
fontSize: 'var(--affine-font-sm)',
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
height: 32,
|
height: 32,
|
||||||
padding: 12,
|
padding: 12,
|
||||||
},
|
},
|
||||||
[SIZE_DEFAULT]: {
|
[SIZE_DEFAULT]: {
|
||||||
iconSize: 24,
|
iconSize: 24,
|
||||||
fontSize: 16,
|
fontSize: 'var(--affine-font-base)',
|
||||||
height: 38,
|
height: 38,
|
||||||
padding: 24,
|
padding: 24,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
|
|||||||
@@ -105,12 +105,11 @@ export const StyledMenuItem = styled('button')<{
|
|||||||
export const StyledButton = styled(Button)(() => {
|
export const StyledButton = styled(Button)(() => {
|
||||||
return {
|
return {
|
||||||
width: '100%',
|
width: '100%',
|
||||||
height: '32px',
|
// height: '32px',
|
||||||
borderRadius: '8px',
|
borderRadius: '8px',
|
||||||
backgroundColor: 'transparent',
|
backgroundColor: 'transparent',
|
||||||
...displayFlex('space-between', 'center'),
|
...displayFlex('space-between', 'center'),
|
||||||
border: `1px solid var(--affine-border-color)`,
|
border: `1px solid var(--affine-border-color)`,
|
||||||
padding: '0 10px',
|
padding: '0 10px',
|
||||||
fontSize: 'var(--affine-font-base)',
|
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ test('Click right-bottom corner contact icon', async ({ page }) => {
|
|||||||
expect(await rightBottomContactUs.isVisible()).toEqual(true);
|
expect(await rightBottomContactUs.isVisible()).toEqual(true);
|
||||||
|
|
||||||
await rightBottomContactUs.click();
|
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();
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user