refactor: remove React.FC for affine core (#3617)

This commit is contained in:
Garfield Lee
2023-08-08 14:54:31 +08:00
committed by GitHub
parent ceeabfeb00
commit 3009d729fa
32 changed files with 314 additions and 242 deletions

View File

@@ -3,7 +3,6 @@ import { WorkspaceFlavour } from '@affine/env/workspace';
import { getOrCreateWorkspace } from '@affine/workspace/manager'; import { getOrCreateWorkspace } from '@affine/workspace/manager';
import type { EditorContainer } from '@blocksuite/editor'; import type { EditorContainer } from '@blocksuite/editor';
import type { Page } from '@blocksuite/store'; import type { Page } from '@blocksuite/store';
import type React from 'react';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor'; import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor';
@@ -15,7 +14,7 @@ const blockSuiteWorkspace = getOrCreateWorkspace(
const page = blockSuiteWorkspace.createPage({ id: 'page0' }); const page = blockSuiteWorkspace.createPage({ id: 'page0' });
const Editor: React.FC = () => { const Editor = () => {
const onLoad = useCallback((page: Page, editor: EditorContainer) => { const onLoad = useCallback((page: Page, editor: EditorContainer) => {
// @ts-expect-error // @ts-expect-error
globalThis.page = page; globalThis.page = page;

View File

@@ -2,7 +2,6 @@ import { Modal, ModalWrapper, Wrapper } from '@affine/component';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { CloseIcon } from '@blocksuite/icons'; import { CloseIcon } from '@blocksuite/icons';
import { Button, IconButton } from '@toeverything/components/button'; import { Button, IconButton } from '@toeverything/components/button';
import type React from 'react';
import { Content, ContentTitle, Header, StyleTips } from './style'; import { Content, ContentTitle, Header, StyleTips } from './style';
@@ -12,11 +11,11 @@ interface EnableAffineCloudModalProps {
onClose: () => void; onClose: () => void;
} }
export const EnableAffineCloudModal: React.FC<EnableAffineCloudModalProps> = ({ export const EnableAffineCloudModal = ({
onConfirm, onConfirm,
open, open,
onClose, onClose,
}) => { }: EnableAffineCloudModalProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
return ( return (

View File

@@ -2,17 +2,20 @@ import { 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 { ButtonProps } from '@toeverything/components/button'; import type { ButtonProps } from '@toeverything/components/button';
import type { FC, ReactElement } from 'react'; import type { ReactElement } from 'react';
import { useCallback } from 'react'; import { useCallback } from 'react';
export const StyledListItem = styled(MenuItem)(() => ({ export const StyledListItem = styled(MenuItem)(() => ({
width: '132px', width: '132px',
height: '38px', height: '38px',
textTransform: 'capitalize', textTransform: 'capitalize',
})); }));
const LanguageMenuContent: FC<{ interface LanguageMenuContentProps {
currentLanguage?: string; currentLanguage?: string;
}> = ({ currentLanguage }) => { }
const LanguageMenuContent = ({ currentLanguage }: LanguageMenuContentProps) => {
const i18n = useI18N(); const i18n = useI18N();
const changeLanguage = useCallback( const changeLanguage = useCallback(
(event: string) => { (event: string) => {
@@ -20,6 +23,7 @@ const LanguageMenuContent: FC<{
}, },
[i18n] [i18n]
); );
return ( return (
<> <>
{LOCALES.map(option => { {LOCALES.map(option => {
@@ -41,9 +45,12 @@ const LanguageMenuContent: FC<{
</> </>
); );
}; };
export const LanguageMenu: FC<{ triggerProps?: ButtonProps }> = ({
triggerProps, interface LanguageMenuProps {
}) => { triggerProps?: ButtonProps;
}
export const LanguageMenu = ({ triggerProps }: LanguageMenuProps) => {
const i18n = useI18N(); const i18n = useI18N();
const currentLanguage = LOCALES.find(item => item.tag === i18n.language); const currentLanguage = LOCALES.find(item => item.tag === i18n.language);

View File

@@ -1,23 +1,29 @@
import { SettingRow } from '@affine/component/setting-components'; import { SettingRow } from '@affine/component/setting-components';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { ArrowRightSmallIcon } from '@blocksuite/icons'; import { ArrowRightSmallIcon } from '@blocksuite/icons';
import { type FC, useState } from 'react'; import { useState } from 'react';
import type { AffineOfficialWorkspace } from '../../../../shared'; import type { AffineOfficialWorkspace } from '../../../../shared';
import type { WorkspaceSettingDetailProps } from '../index'; import type { WorkspaceSettingDetailProps } from '../index';
import { WorkspaceDeleteModal } from './delete'; import { WorkspaceDeleteModal } from './delete';
import { WorkspaceLeave } from './leave'; import { WorkspaceLeave } from './leave';
export const DeleteLeaveWorkspace: FC<{ interface DeleteLeaveWorkspaceProps {
workspace: AffineOfficialWorkspace; workspace: AffineOfficialWorkspace;
onDeleteWorkspace: WorkspaceSettingDetailProps['onDeleteWorkspace']; onDeleteWorkspace: WorkspaceSettingDetailProps['onDeleteWorkspace'];
}> = ({ workspace, onDeleteWorkspace }) => { }
export const DeleteLeaveWorkspace = ({
workspace,
onDeleteWorkspace,
}: DeleteLeaveWorkspaceProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
// fixme: cloud regression // fixme: cloud regression
const isOwner = true; const isOwner = true;
const [showDelete, setShowDelete] = useState(false); const [showDelete, setShowDelete] = useState(false);
const [showLeave, setShowLeave] = useState(false); const [showLeave, setShowLeave] = useState(false);
return ( return (
<> <>
<SettingRow <SettingRow

View File

@@ -3,7 +3,7 @@ import { SettingRow } from '@affine/component/setting-components';
import { isDesktop } from '@affine/env/constant'; import { isDesktop } from '@affine/env/constant';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { Button } from '@toeverything/components/button'; import { Button } from '@toeverything/components/button';
import { type FC, useCallback } from 'react'; import { useCallback } from 'react';
import type { AffineOfficialWorkspace } from '../../../shared'; import type { AffineOfficialWorkspace } from '../../../shared';
@@ -28,9 +28,11 @@ async function syncBlobsToSqliteDb(workspace: AffineOfficialWorkspace) {
} }
} }
export const ExportPanel: FC<{ interface ExportPanelProps {
workspace: AffineOfficialWorkspace; workspace: AffineOfficialWorkspace;
}> = ({ workspace }) => { }
export const ExportPanel = ({ workspace }: ExportPanelProps) => {
const workspaceId = workspace.id; const workspaceId = workspace.id;
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const onExport = useCallback(async () => { const onExport = useCallback(async () => {
@@ -42,6 +44,7 @@ export const ExportPanel: FC<{
toast(t['Export success']()); toast(t['Export success']());
} }
}, [t, workspace, workspaceId]); }, [t, workspace, workspaceId]);
return ( return (
<> <>
<SettingRow name={t['Export']()} desc={t['Export Description']()}> <SettingRow name={t['Export']()} desc={t['Export Description']()}>

View File

@@ -9,7 +9,7 @@ import type {
} from '@affine/env/workspace'; } 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 { type FC, useMemo } from 'react'; import { useMemo } from 'react';
import { useWorkspace } from '../../../hooks/use-workspace'; import { useWorkspace } from '../../../hooks/use-workspace';
import { DeleteLeaveWorkspace } from './delete-leave-workspace'; import { DeleteLeaveWorkspace } from './delete-leave-workspace';
@@ -18,7 +18,7 @@ import { ProfilePanel } from './profile';
import { PublishPanel } from './publish'; import { PublishPanel } from './publish';
import { StoragePanel } from './storage'; import { StoragePanel } from './storage';
export type WorkspaceSettingDetailProps = { export interface WorkspaceSettingDetailProps {
workspaceId: string; workspaceId: string;
onDeleteWorkspace: (id: string) => Promise<void>; onDeleteWorkspace: (id: string) => Promise<void>;
onTransferWorkspace: < onTransferWorkspace: <
@@ -29,13 +29,13 @@ export type WorkspaceSettingDetailProps = {
to: To, to: To,
workspace: WorkspaceRegistry[From] workspace: WorkspaceRegistry[From]
) => void; ) => void;
}; }
export const WorkspaceSettingDetail: FC<WorkspaceSettingDetailProps> = ({ export const WorkspaceSettingDetail = ({
workspaceId, workspaceId,
onDeleteWorkspace, onDeleteWorkspace,
...props ...props
}) => { }: WorkspaceSettingDetailProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const workspace = useWorkspace(workspaceId); const workspace = useWorkspace(workspaceId);
const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace); const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace);

View File

@@ -5,7 +5,7 @@ import { DoneIcon } from '@blocksuite/icons';
import { IconButton } from '@toeverything/components/button'; import { IconButton } from '@toeverything/components/button';
import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-block-suite-workspace-avatar-url'; import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-block-suite-workspace-avatar-url';
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name'; import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
import { type FC, useCallback, useState } from 'react'; import { useCallback, useState } from 'react';
import type { AffineOfficialWorkspace } from '../../../shared'; import type { AffineOfficialWorkspace } from '../../../shared';
import { Upload } from '../../pure/file-upload'; import { Upload } from '../../pure/file-upload';
@@ -30,9 +30,11 @@ const CameraIcon = () => {
); );
}; };
export const ProfilePanel: FC<{ interface ProfilePanelProps {
workspace: AffineOfficialWorkspace; workspace: AffineOfficialWorkspace;
}> = ({ workspace }) => { }
export const ProfilePanel = ({ workspace }: ProfilePanelProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const [, update] = useBlockSuiteWorkspaceAvatarUrl( const [, update] = useBlockSuiteWorkspaceAvatarUrl(

View File

@@ -9,7 +9,6 @@ import { WorkspaceFlavour } from '@affine/env/workspace';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { Button } from '@toeverything/components/button'; import { Button } from '@toeverything/components/button';
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name'; import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
import type { FC } from 'react';
import { useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import type { AffineOfficialWorkspace } from '../../../shared'; import type { AffineOfficialWorkspace } from '../../../shared';
@@ -19,26 +18,20 @@ import { TmpDisableAffineCloudModal } from '../tmp-disable-affine-cloud-modal';
import type { WorkspaceSettingDetailProps } from './index'; import type { WorkspaceSettingDetailProps } from './index';
import * as style from './style.css'; import * as style from './style.css';
export type PublishPanelProps = Omit< export interface PublishPanelProps
WorkspaceSettingDetailProps, extends Omit<WorkspaceSettingDetailProps, 'workspaceId'> {
'workspaceId'
> & {
workspace: AffineOfficialWorkspace; workspace: AffineOfficialWorkspace;
}; }
export type PublishPanelLocalProps = Omit< export interface PublishPanelLocalProps
WorkspaceSettingDetailProps, extends Omit<WorkspaceSettingDetailProps, 'workspaceId'> {
'workspaceId'
> & {
workspace: LocalWorkspace; workspace: LocalWorkspace;
}; }
export type PublishPanelAffineProps = Omit< export interface PublishPanelAffineProps
WorkspaceSettingDetailProps, extends Omit<WorkspaceSettingDetailProps, 'workspaceId'> {
'workspaceId'
> & {
workspace: AffineCloudWorkspace; workspace: AffineCloudWorkspace;
}; }
const PublishPanelAffine: FC<PublishPanelAffineProps> = props => { const PublishPanelAffine = (props: PublishPanelAffineProps) => {
const { workspace } = props; const { workspace } = props;
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
// const toggleWorkspacePublish = useToggleWorkspacePublish(workspace); // const toggleWorkspacePublish = useToggleWorkspacePublish(workspace);
@@ -58,6 +51,7 @@ const PublishPanelAffine: FC<PublishPanelAffineProps> = props => {
await navigator.clipboard.writeText(shareUrl); await navigator.clipboard.writeText(shareUrl);
toast(t['Copied link to clipboard']()); toast(t['Copied link to clipboard']());
}, [shareUrl, t]); }, [shareUrl, t]);
return ( return (
<> <>
<SettingRow <SettingRow
@@ -91,10 +85,13 @@ const PublishPanelAffine: FC<PublishPanelAffineProps> = props => {
); );
}; };
const FakePublishPanelAffine: FC<{ interface FakePublishPanelAffineProps {
workspace: AffineOfficialWorkspace; workspace: AffineOfficialWorkspace;
}> = () => { }
const FakePublishPanelAffine = (_props: FakePublishPanelAffineProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
return ( return (
<Tooltip <Tooltip
content={t['com.affine.settings.workspace.publish.local-tooltip']()} content={t['com.affine.settings.workspace.publish.local-tooltip']()}
@@ -108,10 +105,11 @@ const FakePublishPanelAffine: FC<{
</Tooltip> </Tooltip>
); );
}; };
const PublishPanelLocal: FC<PublishPanelLocalProps> = ({
const PublishPanelLocal = ({
workspace, workspace,
onTransferWorkspace, onTransferWorkspace,
}) => { }: PublishPanelLocalProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace); const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace);
@@ -167,7 +165,7 @@ const PublishPanelLocal: FC<PublishPanelLocalProps> = ({
); );
}; };
export const PublishPanel: FC<PublishPanelProps> = props => { export const PublishPanel = (props: PublishPanelProps) => {
if (props.workspace.flavour === WorkspaceFlavour.AFFINE_CLOUD) { if (props.workspace.flavour === WorkspaceFlavour.AFFINE_CLOUD) {
return <PublishPanelAffine {...props} workspace={props.workspace} />; return <PublishPanelAffine {...props} workspace={props.workspace} />;
} else if (props.workspace.flavour === WorkspaceFlavour.LOCAL) { } else if (props.workspace.flavour === WorkspaceFlavour.LOCAL) {

View File

@@ -3,7 +3,7 @@ import { SettingRow } from '@affine/component/setting-components';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { Button } from '@toeverything/components/button'; import { Button } from '@toeverything/components/button';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { type FC, useCallback, useEffect, useState } from 'react'; import { useCallback, useEffect, useState } from 'react';
import type { AffineOfficialWorkspace } from '../../../shared'; import type { AffineOfficialWorkspace } from '../../../shared';
import * as style from './style.css'; import * as style from './style.css';
@@ -31,9 +31,11 @@ const useDBFileSecondaryPath = (workspaceId: string) => {
return path; return path;
}; };
export const StoragePanel: FC<{ interface StoragePanelProps {
workspace: AffineOfficialWorkspace; workspace: AffineOfficialWorkspace;
}> = ({ workspace }) => { }
export const StoragePanel = ({ workspace }: StoragePanelProps) => {
const workspaceId = workspace.id; const workspaceId = workspace.id;
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const secondaryPath = useDBFileSecondaryPath(workspaceId); const secondaryPath = useDBFileSecondaryPath(workspaceId);

View File

@@ -1,12 +1,11 @@
import { TourModal } from '@affine/component/tour-modal'; import { TourModal } from '@affine/component/tour-modal';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import type { FC } from 'react';
import { memo, useCallback } from 'react'; import { memo, useCallback } from 'react';
import { openOnboardingModalAtom } from '../../atoms'; import { openOnboardingModalAtom } from '../../atoms';
import { guideOnboardingAtom } from '../../atoms/guide'; import { guideOnboardingAtom } from '../../atoms/guide';
export const OnboardingModal: FC = memo(function OnboardingModal() { export const OnboardingModal = memo(function OnboardingModal() {
const [open, setOpen] = useAtom(openOnboardingModalAtom); const [open, setOpen] = useAtom(openOnboardingModalAtom);
const [guideOpen, setShowOnboarding] = useAtom(guideOnboardingAtom); const [guideOpen, setShowOnboarding] = useAtom(guideOnboardingAtom);
const onCloseTourModal = useCallback(() => { const onCloseTourModal = useCallback(() => {

View File

@@ -1,6 +1,6 @@
import { Menu, MenuItem, MenuTrigger } from '@affine/component'; import { Menu, MenuItem, MenuTrigger } from '@affine/component';
import dayjs from 'dayjs'; import dayjs from 'dayjs';
import { type FC, useCallback } from 'react'; import { useCallback } from 'react';
import { import {
dateFormatOptions, dateFormatOptions,
@@ -8,10 +8,15 @@ import {
useAppSetting, useAppSetting,
} from '../../../../../atoms/settings'; } from '../../../../../atoms/settings';
const DateFormatMenuContent: FC<{ interface DateFormatMenuContentProps {
currentOption: DateFormats; currentOption: DateFormats;
onSelect: (option: DateFormats) => void; onSelect: (option: DateFormats) => void;
}> = ({ onSelect, currentOption }) => { }
const DateFormatMenuContent = ({
onSelect,
currentOption,
}: DateFormatMenuContentProps) => {
return ( return (
<> <>
{dateFormatOptions.map(option => { {dateFormatOptions.map(option => {
@@ -30,6 +35,7 @@ const DateFormatMenuContent: FC<{
</> </>
); );
}; };
export const DateFormatSetting = () => { export const DateFormatSetting = () => {
const [appearanceSettings, setAppSettings] = useAppSetting(); const [appearanceSettings, setAppSettings] = useAppSetting();
const handleSelect = useCallback( const handleSelect = useCallback(
@@ -38,6 +44,7 @@ export const DateFormatSetting = () => {
}, },
[setAppSettings] [setAppSettings]
); );
return ( return (
<Menu <Menu
content={ content={

View File

@@ -5,7 +5,7 @@ import {
InformationIcon, InformationIcon,
KeyboardIcon, KeyboardIcon,
} from '@blocksuite/icons'; } from '@blocksuite/icons';
import type { FC, SVGProps } from 'react'; import type { ReactElement, SVGProps } from 'react';
import { AboutAffine } from './about'; import { AboutAffine } from './about';
import { AppearanceSettings } from './appearance'; import { AppearanceSettings } from './appearance';
@@ -18,15 +18,18 @@ export type GeneralSettingKeys =
| 'plugins' | 'plugins'
| 'about'; | 'about';
export type GeneralSettingList = { interface GeneralSettingListItem {
key: GeneralSettingKeys; key: GeneralSettingKeys;
title: string; title: string;
icon: FC<SVGProps<SVGSVGElement>>; icon: (props: SVGProps<SVGSVGElement>) => ReactElement;
testId: string; testId: string;
}[]; }
export type GeneralSettingList = GeneralSettingListItem[];
export const useGeneralSettingList = (): GeneralSettingList => { export const useGeneralSettingList = (): GeneralSettingList => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
return [ return [
{ {
key: 'appearance', key: 'appearance',
@@ -55,11 +58,11 @@ export const useGeneralSettingList = (): GeneralSettingList => {
]; ];
}; };
export const GeneralSetting = ({ interface GeneralSettingProps {
generalKey,
}: {
generalKey: GeneralSettingKeys; generalKey: GeneralSettingKeys;
}) => { }
export const GeneralSetting = ({ generalKey }: GeneralSettingProps) => {
switch (generalKey) { switch (generalKey) {
case 'shortcuts': case 'shortcuts':
return <Shortcuts />; return <Shortcuts />;

View File

@@ -1,10 +1,9 @@
import { import {
SettingModal as SettingModalBase, SettingModal as SettingModalBase,
type SettingModalProps, type SettingModalProps as SettingModalBaseProps,
} from '@affine/component/setting-components'; } from '@affine/component/setting-components';
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 { useCallback } from 'react'; import { useCallback } from 'react';
import { AccountSetting } from './account-setting'; import { AccountSetting } from './account-setting';
@@ -18,21 +17,25 @@ import { settingContent } from './style.css';
import { WorkspaceSetting } from './workspace-setting'; import { WorkspaceSetting } from './workspace-setting';
type ActiveTab = GeneralSettingKeys | 'workspace' | 'account'; type ActiveTab = GeneralSettingKeys | 'workspace' | 'account';
export type SettingProps = {
export interface SettingProps {
activeTab: ActiveTab; activeTab: ActiveTab;
workspaceId: string | null; workspaceId: string | null;
onSettingClick: (params: { onSettingClick: (params: {
activeTab: ActiveTab; activeTab: ActiveTab;
workspaceId: string | null; workspaceId: string | null;
}) => void; }) => void;
}; }
export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
type SettingModalProps = SettingModalBaseProps & SettingProps;
export const SettingModal = ({
open, open,
setOpen, setOpen,
activeTab = 'appearance', activeTab = 'appearance',
workspaceId = null, workspaceId = null,
onSettingClick, onSettingClick,
}) => { }: SettingModalProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const generalSettingList = useGeneralSettingList(); const generalSettingList = useGeneralSettingList();

View File

@@ -11,7 +11,6 @@ import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-
import { useStaticBlockSuiteWorkspace } from '@toeverything/infra/__internal__/react'; import { useStaticBlockSuiteWorkspace } from '@toeverything/infra/__internal__/react';
import clsx from 'clsx'; import clsx from 'clsx';
import { useAtomValue } from 'jotai'; import { useAtomValue } from 'jotai';
import type { FC } from 'react';
import { Suspense } from 'react'; import { Suspense } from 'react';
import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace'; import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
@@ -28,21 +27,24 @@ import {
sidebarTitle, sidebarTitle,
} from './style.css'; } from './style.css';
export const SettingSidebar: FC<{ interface SettingSidebarProps {
generalSettingList: GeneralSettingList; generalSettingList: GeneralSettingList;
onGeneralSettingClick: (key: GeneralSettingKeys) => void; onGeneralSettingClick: (key: GeneralSettingKeys) => void;
onWorkspaceSettingClick: (workspaceId: string) => void; onWorkspaceSettingClick: (workspaceId: string) => void;
selectedWorkspaceId: string | null; selectedWorkspaceId: string | null;
selectedGeneralKey: string | null; selectedGeneralKey: string | null;
onAccountSettingClick: () => void; onAccountSettingClick: () => void;
}> = ({ }
export const SettingSidebar = ({
generalSettingList, generalSettingList,
onGeneralSettingClick, onGeneralSettingClick,
onWorkspaceSettingClick, onWorkspaceSettingClick,
selectedWorkspaceId, selectedWorkspaceId,
selectedGeneralKey, selectedGeneralKey,
}) => { }: SettingSidebarProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
return ( return (
<div className={settingSlideBar} data-testid="settings-sidebar"> <div className={settingSlideBar} data-testid="settings-sidebar">
<div className={sidebarTitle}>{t['Settings']()}</div> <div className={sidebarTitle}>{t['Settings']()}</div>
@@ -88,10 +90,15 @@ export const SettingSidebar: FC<{
); );
}; };
export const WorkspaceList: FC<{ interface WorkspaceListProps {
onWorkspaceSettingClick: (workspaceId: string) => void; onWorkspaceSettingClick: (workspaceId: string) => void;
selectedWorkspaceId: string | null; selectedWorkspaceId: string | null;
}> = ({ onWorkspaceSettingClick, selectedWorkspaceId }) => { }
export const WorkspaceList = ({
onWorkspaceSettingClick,
selectedWorkspaceId,
}: WorkspaceListProps) => {
const workspaces = useAtomValue(rootWorkspacesMetadataAtom); const workspaces = useAtomValue(rootWorkspacesMetadataAtom);
const [currentWorkspace] = useCurrentWorkspace(); const [currentWorkspace] = useCurrentWorkspace();
return ( return (
@@ -114,19 +121,22 @@ export const WorkspaceList: FC<{
); );
}; };
interface WorkspaceListItemProps {
meta: RootWorkspaceMetadata;
onClick: () => void;
isCurrent: boolean;
isActive: boolean;
}
const WorkspaceListItem = ({ const WorkspaceListItem = ({
meta, meta,
onClick, onClick,
isCurrent, isCurrent,
isActive, isActive,
}: { }: WorkspaceListItemProps) => {
meta: RootWorkspaceMetadata;
onClick: () => void;
isCurrent: boolean;
isActive: boolean;
}) => {
const workspace = useStaticBlockSuiteWorkspace(meta.id); const workspace = useStaticBlockSuiteWorkspace(meta.id);
const [workspaceName] = useBlockSuiteWorkspaceName(workspace); const [workspaceName] = useBlockSuiteWorkspaceName(workspace);
return ( return (
<div <div
className={clsx(sidebarSelectItem, { active: isActive })} className={clsx(sidebarSelectItem, { active: isActive })}

View File

@@ -3,7 +3,6 @@ import { Trans } from '@affine/i18n';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { CloseIcon } from '@blocksuite/icons'; import { CloseIcon } from '@blocksuite/icons';
import { IconButton } from '@toeverything/components/button'; import { IconButton } from '@toeverything/components/button';
import type React from 'react';
import { import {
Content, Content,
@@ -20,10 +19,12 @@ interface TmpDisableAffineCloudModalProps {
onClose: () => void; onClose: () => void;
} }
export const TmpDisableAffineCloudModal: React.FC< export const TmpDisableAffineCloudModal = ({
TmpDisableAffineCloudModalProps open,
> = ({ open, onClose }) => { onClose,
}: TmpDisableAffineCloudModalProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
return ( return (
<Modal <Modal
data-testid="disable-affine-cloud-modal" data-testid="disable-affine-cloud-modal"

View File

@@ -2,19 +2,20 @@ import { Modal, ModalWrapper } from '@affine/component';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { CloseIcon } from '@blocksuite/icons'; import { CloseIcon } from '@blocksuite/icons';
import { IconButton } from '@toeverything/components/button'; import { IconButton } from '@toeverything/components/button';
import type React from 'react';
import { Content, ContentTitle, Header, StyleButton, StyleTips } from './style'; import { Content, ContentTitle, Header, StyleButton, StyleTips } from './style';
export type TransformWorkspaceToAffineModalProps = { export interface TransformWorkspaceToAffineModalProps {
open: boolean; open: boolean;
onClose: () => void; onClose: () => void;
onConform: () => void; onConform: () => void;
}; }
export const TransformWorkspaceToAffineModal: React.FC< export const TransformWorkspaceToAffineModal = ({
TransformWorkspaceToAffineModalProps open,
> = ({ open, onClose, onConform }) => { onClose,
onConform,
}: TransformWorkspaceToAffineModalProps) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
return ( return (

View File

@@ -11,7 +11,6 @@ import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-
import { useBlockSuitePagePreview } from '@toeverything/hooks/use-block-suite-page-preview'; import { useBlockSuitePagePreview } from '@toeverything/hooks/use-block-suite-page-preview';
import { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-block-suite-workspace-page'; import { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-block-suite-workspace-page';
import { useAtom, useAtomValue } from 'jotai'; import { useAtom, useAtomValue } from 'jotai';
import type React from 'react';
import { Suspense, useCallback, useMemo } from 'react'; import { Suspense, useCallback, useMemo } from 'react';
import { allPageModeSelectAtom } from '../../../atoms'; import { allPageModeSelectAtom } from '../../../atoms';
@@ -23,13 +22,13 @@ import { filterPage } from '../../../utils/filter';
import { emptyDescButton, emptyDescKbd, pageListEmptyStyle } from './index.css'; import { emptyDescButton, emptyDescKbd, pageListEmptyStyle } from './index.css';
import { usePageHelper } from './utils'; import { usePageHelper } from './utils';
export type BlockSuitePageListProps = { export interface BlockSuitePageListProps {
blockSuiteWorkspace: BlockSuiteWorkspace; blockSuiteWorkspace: BlockSuiteWorkspace;
listType: 'all' | 'trash' | 'shared' | 'public'; listType: 'all' | 'trash' | 'shared' | 'public';
isPublic?: true; isPublic?: boolean;
onOpenPage: (pageId: string, newTab?: boolean) => void; onOpenPage: (pageId: string, newTab?: boolean) => void;
collection?: Collection; collection?: Collection;
}; }
const filter = { const filter = {
all: (pageMeta: PageMeta) => !pageMeta.trash, all: (pageMeta: PageMeta) => !pageMeta.trash,
@@ -41,13 +40,12 @@ const filter = {
shared: (pageMeta: PageMeta) => pageMeta.isPublic && !pageMeta.trash, shared: (pageMeta: PageMeta) => pageMeta.isPublic && !pageMeta.trash,
}; };
const PagePreviewInner = ({ interface PagePreviewInnerProps {
workspace,
pageId,
}: {
workspace: Workspace; workspace: Workspace;
pageId: string; pageId: string;
}) => { }
const PagePreviewInner = ({ workspace, pageId }: PagePreviewInnerProps) => {
const page = useBlockSuiteWorkspacePage(workspace, pageId); const page = useBlockSuiteWorkspacePage(workspace, pageId);
assertExists(page); assertExists(page);
const previewAtom = useBlockSuitePagePreview(page); const previewAtom = useBlockSuitePagePreview(page);
@@ -55,13 +53,12 @@ const PagePreviewInner = ({
return preview; return preview;
}; };
const PagePreview = ({ interface PagePreviewProps {
workspace,
pageId,
}: {
workspace: Workspace; workspace: Workspace;
pageId: string; pageId: string;
}) => { }
const PagePreview = ({ workspace, pageId }: PagePreviewProps) => {
return ( return (
<Suspense> <Suspense>
<PagePreviewInner workspace={workspace} pageId={pageId} /> <PagePreviewInner workspace={workspace} pageId={pageId} />
@@ -69,10 +66,12 @@ const PagePreview = ({
); );
}; };
const PageListEmpty = (props: { interface PageListEmptyProps {
createPage?: ReturnType<typeof usePageHelper>['createPage']; createPage?: ReturnType<typeof usePageHelper>['createPage'];
listType: BlockSuitePageListProps['listType']; listType: BlockSuitePageListProps['listType'];
}) => { }
const PageListEmpty = (props: PageListEmptyProps) => {
const { listType, createPage } = props; const { listType, createPage } = props;
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
@@ -124,13 +123,13 @@ const PageListEmpty = (props: {
); );
}; };
export const BlockSuitePageList: React.FC<BlockSuitePageListProps> = ({ export const BlockSuitePageList = ({
blockSuiteWorkspace, blockSuiteWorkspace,
onOpenPage, onOpenPage,
listType, listType,
isPublic = false, isPublic = false,
collection, collection,
}) => { }: BlockSuitePageListProps) => {
const pageMetas = useBlockSuitePageMeta(blockSuiteWorkspace); const pageMetas = useBlockSuitePageMeta(blockSuiteWorkspace);
const { const {
toggleFavorite, toggleFavorite,
@@ -262,6 +261,7 @@ export const BlockSuitePageList: React.FC<BlockSuitePageListProps> = ({
}, },
}; };
}); });
return ( return (
<PageList <PageList
workspaceId={blockSuiteWorkspace.id} workspaceId={blockSuiteWorkspace.id}

View File

@@ -3,10 +3,10 @@ import { LOCALES } from '@affine/i18n';
import { useI18N } from '@affine/i18n'; import { useI18N } from '@affine/i18n';
import { ArrowDownSmallIcon, LanguageIcon } from '@blocksuite/icons'; import { ArrowDownSmallIcon, LanguageIcon } from '@blocksuite/icons';
import { Button } from '@toeverything/components/button'; import { Button } from '@toeverything/components/button';
import type { FC, ReactElement } from 'react'; import type { ReactElement } from 'react';
import { useCallback } from 'react'; import { useCallback } from 'react';
const LanguageMenuContent: FC = () => { const LanguageMenuContent = () => {
const i18n = useI18N(); const i18n = useI18N();
const changeLanguage = useCallback( const changeLanguage = useCallback(
(event: string) => { (event: string) => {
@@ -16,6 +16,7 @@ const LanguageMenuContent: FC = () => {
}, },
[i18n] [i18n]
); );
return ( return (
<> <>
{LOCALES.map(option => { {LOCALES.map(option => {
@@ -34,7 +35,8 @@ const LanguageMenuContent: FC = () => {
</> </>
); );
}; };
export const LanguageMenu: React.FC = () => {
export const LanguageMenu = () => {
const i18n = useI18N(); const i18n = useI18N();
const currentLanguage = LOCALES.find(item => item.tag === i18n.language); const currentLanguage = LOCALES.find(item => item.tag === i18n.language);
@@ -87,6 +89,7 @@ const StyledContainer = styled('div')(() => {
padding: '0 14px', padding: '0 14px',
}; };
}); });
const StyledIconContainer = styled('div')(() => { const StyledIconContainer = styled('div')(() => {
return { return {
width: '20px', width: '20px',
@@ -96,6 +99,7 @@ const StyledIconContainer = styled('div')(() => {
...displayFlex('flex-start', 'center'), ...displayFlex('flex-start', 'center'),
}; };
}); });
const StyledButtonContainer = styled('div')(() => { const StyledButtonContainer = styled('div')(() => {
return { return {
width: '100%', width: '100%',
@@ -107,6 +111,7 @@ const StyledButtonContainer = styled('div')(() => {
marginLeft: '12px', marginLeft: '12px',
}; };
}); });
const StyledButton = styled(Button)(() => { const StyledButton = styled(Button)(() => {
return { return {
width: '100%', width: '100%',
@@ -118,6 +123,7 @@ const StyledButton = styled(Button)(() => {
padding: '0', padding: '0',
}; };
}); });
const StyledArrowDownContainer = styled('div')(() => { const StyledArrowDownContainer = styled('div')(() => {
return { return {
height: '32px', height: '32px',
@@ -128,6 +134,7 @@ const StyledArrowDownContainer = styled('div')(() => {
fontSize: '24px', fontSize: '24px',
}; };
}); });
const StyledCurrentLanguage = styled('div')(() => { const StyledCurrentLanguage = styled('div')(() => {
return { return {
marginLeft: '12px', marginLeft: '12px',

View File

@@ -13,7 +13,7 @@ import {
} from '@toeverything/infra/__internal__/plugin'; } from '@toeverything/infra/__internal__/plugin';
import clsx from 'clsx'; import clsx from 'clsx';
import { useAtom, useAtomValue } from 'jotai'; import { useAtom, useAtomValue } from 'jotai';
import type { FC, HTMLAttributes, PropsWithChildren, ReactNode } from 'react'; import type { HTMLAttributes, ReactElement, ReactNode } from 'react';
import { import {
forwardRef, forwardRef,
startTransition, startTransition,
@@ -32,21 +32,21 @@ import { EditorOptionMenu } from './header-right-items/editor-option-menu';
import * as styles from './styles.css'; import * as styles from './styles.css';
import { OSWarningMessage, shouldShowWarning } from './utils'; import { OSWarningMessage, shouldShowWarning } from './utils';
export type BaseHeaderProps< export interface BaseHeaderProps<
Workspace extends AffineOfficialWorkspace = AffineOfficialWorkspace, Workspace extends AffineOfficialWorkspace = AffineOfficialWorkspace,
> = { > {
workspace: Workspace; workspace: Workspace;
currentPage: Page | null; currentPage: Page | null;
isPublic: boolean; isPublic: boolean;
leftSlot?: ReactNode; leftSlot?: ReactNode;
}; }
export enum HeaderRightItemName { export enum HeaderRightItemName {
EditorOptionMenu = 'editorOptionMenu', EditorOptionMenu = 'editorOptionMenu',
} }
type HeaderItem = { interface HeaderItem {
Component: FC<BaseHeaderProps>; Component: (props: BaseHeaderProps) => ReactElement;
// todo: public workspace should be one of the flavour // todo: public workspace should be one of the flavour
availableWhen: ( availableWhen: (
workspace: AffineOfficialWorkspace, workspace: AffineOfficialWorkspace,
@@ -55,7 +55,7 @@ type HeaderItem = {
isPublic: boolean; isPublic: boolean;
} }
) => boolean; ) => boolean;
}; }
const HeaderRightItems: Record<HeaderRightItemName, HeaderItem> = { const HeaderRightItems: Record<HeaderRightItemName, HeaderItem> = {
[HeaderRightItemName.EditorOptionMenu]: { [HeaderRightItemName.EditorOptionMenu]: {
@@ -68,7 +68,6 @@ const HeaderRightItems: Record<HeaderRightItemName, HeaderItem> = {
}, },
}; };
export type HeaderProps = BaseHeaderProps;
const WindowsAppControls = () => { const WindowsAppControls = () => {
const handleMinimizeApp = useCallback(() => { const handleMinimizeApp = useCallback(() => {
window.apis?.ui.handleMinimizeApp().catch(err => { window.apis?.ui.handleMinimizeApp().catch(err => {
@@ -85,6 +84,7 @@ const WindowsAppControls = () => {
console.error(err); console.error(err);
}); });
}, []); }, []);
return ( return (
<div <div
data-platform-target="win32" data-platform-target="win32"
@@ -118,6 +118,7 @@ const WindowsAppControls = () => {
const PluginHeader = () => { const PluginHeader = () => {
const headerItem = useAtomValue(pluginHeaderItemAtom); const headerItem = useAtomValue(pluginHeaderItemAtom);
const pluginsRef = useRef<string[]>([]); const pluginsRef = useRef<string[]>([]);
return ( return (
<div <div
className={styles.pluginHeaderItems} className={styles.pluginHeaderItems}
@@ -151,10 +152,13 @@ const PluginHeader = () => {
); );
}; };
export const Header = forwardRef< export interface HeaderProps
HTMLDivElement, extends BaseHeaderProps,
PropsWithChildren<HeaderProps> & HTMLAttributes<HTMLDivElement> HTMLAttributes<HTMLDivElement> {
>((props, ref) => { children?: ReactNode;
}
export const Header = forwardRef<HTMLDivElement, HeaderProps>((props, ref) => {
const [showWarning, setShowWarning] = useState(false); const [showWarning, setShowWarning] = useState(false);
const [showDownloadTip, setShowDownloadTip] = useAtom( const [showDownloadTip, setShowDownloadTip] = useAtom(
guideDownloadClientTipAtom guideDownloadClientTipAtom
@@ -167,6 +171,7 @@ export const Header = forwardRef<
const mode = useAtomValue(currentModeAtom); const mode = useAtomValue(currentModeAtom);
const isWindowsDesktop = globalThis.platform === 'win32' && isDesktop; const isWindowsDesktop = globalThis.platform === 'win32' && isDesktop;
return ( return (
<div <div
className={styles.headerContainer} className={styles.headerContainer}

View File

@@ -5,12 +5,7 @@ import {
usePageMetaHelper, usePageMetaHelper,
} from '@toeverything/hooks/use-block-suite-page-meta'; } from '@toeverything/hooks/use-block-suite-page-meta';
import { useSetAtom } from 'jotai'; import { useSetAtom } from 'jotai';
import type { import type { HTMLAttributes, ReactElement, ReactNode } from 'react';
FC,
HTMLAttributes,
PropsWithChildren,
ReactElement,
} from 'react';
import { useCallback, useRef, useState } from 'react'; import { useCallback, useRef, useState } from 'react';
import { openQuickSearchModalAtom } from '../../../atoms'; import { openQuickSearchModalAtom } from '../../../atoms';
@@ -20,11 +15,15 @@ import type { BaseHeaderProps } from './header';
import { Header } from './header'; import { Header } from './header';
import * as styles from './styles.css'; import * as styles from './styles.css';
export type WorkspaceHeaderProps = BaseHeaderProps; export interface WorkspaceHeaderProps
extends BaseHeaderProps,
HTMLAttributes<HTMLDivElement> {
children?: ReactNode;
}
export const BlockSuiteEditorHeader: FC< export const BlockSuiteEditorHeader = (
PropsWithChildren<WorkspaceHeaderProps> & HTMLAttributes<HTMLDivElement> props: WorkspaceHeaderProps
> = (props): ReactElement => { ): ReactElement => {
const { workspace, currentPage, children, isPublic } = props; const { workspace, currentPage, children, isPublic } = props;
// fixme(himself65): remove this atom and move it to props // fixme(himself65): remove this atom and move it to props
const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom); const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom);
@@ -50,6 +49,7 @@ export const BlockSuiteEditorHeader: FC<
const headerRef = useRef<HTMLDivElement>(null); const headerRef = useRef<HTMLDivElement>(null);
assertExists(pageMeta); assertExists(pageMeta);
const title = pageMeta?.title; const title = pageMeta?.title;
return ( return (
<Header ref={headerRef} {...props}> <Header ref={headerRef} {...props}>
{children} {children}

View File

@@ -1,7 +1,6 @@
import { isDesktop } from '@affine/env/constant'; import { isDesktop } from '@affine/env/constant';
import { Trans } from '@affine/i18n'; import { Trans } from '@affine/i18n';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import type React from 'react';
import { useEffect, useState } from 'react'; import { useEffect, useState } from 'react';
const minimumChromeVersion = 102; const minimumChromeVersion = 102;
@@ -23,7 +22,7 @@ export const shouldShowWarning = () => {
} }
}; };
export const OSWarningMessage: React.FC = () => { export const OSWarningMessage = () => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const [notChrome, setNotChrome] = useState(false); const [notChrome, setNotChrome] = useState(false);
const [notGoodVersion, setNotGoodVersion] = useState(false); const [notGoodVersion, setNotGoodVersion] = useState(false);

View File

@@ -16,7 +16,7 @@ import {
import { contentLayoutAtom, rootStore } from '@toeverything/infra/atom'; import { contentLayoutAtom, rootStore } from '@toeverything/infra/atom';
import clsx from 'clsx'; import clsx from 'clsx';
import { useAtomValue, useSetAtom } from 'jotai'; import { useAtomValue, useSetAtom } from 'jotai';
import type { CSSProperties, FC, ReactElement } from 'react'; import type { CSSProperties, ReactElement } from 'react';
import { memo, Suspense, useCallback, useMemo } from 'react'; import { memo, Suspense, useCallback, useMemo } from 'react';
import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels'; import { Panel, PanelGroup, PanelResizeHandle } from 'react-resizable-panels';
@@ -27,13 +27,13 @@ import { TrashButtonGroup } from './blocksuite/workspace-header/header-right-ite
import * as styles from './page-detail-editor.css'; import * as styles from './page-detail-editor.css';
import { pluginContainer } from './page-detail-editor.css'; import { pluginContainer } from './page-detail-editor.css';
export type PageDetailEditorProps = { export interface PageDetailEditorProps {
isPublic?: boolean; isPublic?: boolean;
workspace: Workspace; workspace: Workspace;
pageId: string; pageId: string;
onInit: (page: Page, editor: Readonly<EditorContainer>) => void; onInit: (page: Page, editor: Readonly<EditorContainer>) => void;
onLoad?: (page: Page, editor: EditorContainer) => () => void; onLoad?: (page: Page, editor: EditorContainer) => () => void;
}; }
const EditorWrapper = memo(function EditorWrapper({ const EditorWrapper = memo(function EditorWrapper({
workspace, workspace,
@@ -128,10 +128,13 @@ const EditorWrapper = memo(function EditorWrapper({
); );
}); });
const PluginContentAdapter = memo<{ interface PluginContentAdapterProps {
windowItem: (div: HTMLDivElement) => () => void; windowItem: (div: HTMLDivElement) => () => void;
pluginName: string; pluginName: string;
}>(function PluginContentAdapter({ windowItem, pluginName }) { }
const PluginContentAdapter = memo<PluginContentAdapterProps>(
function PluginContentAdapter({ windowItem, pluginName }) {
return ( return (
<div <div
className={pluginContainer} className={pluginContainer}
@@ -151,12 +154,13 @@ const PluginContentAdapter = memo<{
)} )}
/> />
); );
}); }
);
type LayoutPanelProps = { interface LayoutPanelProps {
node: LayoutNode; node: LayoutNode;
editorProps: PageDetailEditorProps; editorProps: PageDetailEditorProps;
}; }
const LayoutPanel = memo(function LayoutPanel( const LayoutPanel = memo(function LayoutPanel(
props: LayoutPanelProps props: LayoutPanelProps
@@ -199,7 +203,7 @@ const LayoutPanel = memo(function LayoutPanel(
} }
}); });
export const PageDetailEditor: FC<PageDetailEditorProps> = props => { export const PageDetailEditor = (props: PageDetailEditorProps) => {
const { workspace, pageId } = props; const { workspace, pageId } = props;
const page = useBlockSuiteWorkspacePage(workspace, pageId); const page = useBlockSuiteWorkspacePage(workspace, pageId);
if (!page) { if (!page) {

View File

@@ -1,22 +1,21 @@
import { styled } from '@affine/component'; import { styled } from '@affine/component';
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { Button } from '@toeverything/components/button'; import { Button } from '@toeverything/components/button';
import type { ChangeEvent } from 'react'; import type { ChangeEvent, PropsWithChildren } from 'react';
import type React from 'react';
import { useRef } from 'react'; import { useRef } from 'react';
export type UploadProps = React.PropsWithChildren<{ export interface UploadProps {
uploadType?: string; uploadType?: string;
accept?: string; accept?: string;
fileChange: (file: File) => void; fileChange: (file: File) => void;
}>; }
export const Upload: React.FC<UploadProps> = ({ export const Upload = ({
fileChange, fileChange,
accept, accept,
children, children,
...props ...props
}) => { }: PropsWithChildren<UploadProps>) => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const input_ref = useRef<HTMLInputElement>(null); const input_ref = useRef<HTMLInputElement>(null);
const _chooseFile = () => { const _chooseFile = () => {
@@ -35,6 +34,7 @@ export const Upload: React.FC<UploadProps> = ({
input_ref.current.value = ''; input_ref.current.value = '';
} }
}; };
return ( return (
<UploadStyle onClick={_chooseFile}> <UploadStyle onClick={_chooseFile}>
{children ?? <Button>{t['Upload']()}</Button>} {children ?? <Button>{t['Upload']()}</Button>}

View File

@@ -1,15 +1,16 @@
import { useAFFiNEI18N } from '@affine/i18n/hooks'; import { useAFFiNEI18N } from '@affine/i18n/hooks';
import { CloudWorkspaceIcon } from '@blocksuite/icons'; import { CloudWorkspaceIcon } from '@blocksuite/icons';
import { useSetAtom } from 'jotai'; import { useSetAtom } from 'jotai';
import { type CSSProperties, type FC, forwardRef } from 'react'; import { type CSSProperties, forwardRef } from 'react';
import { openDisableCloudAlertModalAtom } from '../../../atoms'; import { openDisableCloudAlertModalAtom } from '../../../atoms';
import { stringToColour } from '../../../utils'; import { stringToColour } from '../../../utils';
import { StyledFooter, StyledSignInButton } from './styles'; import { StyledFooter, StyledSignInButton } from './styles';
export const Footer: FC = () => { export const Footer = () => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const setOpen = useSetAtom(openDisableCloudAlertModalAtom); const setOpen = useSetAtom(openDisableCloudAlertModalAtom);
return ( return (
<StyledFooter data-testid="workspace-list-modal-footer"> <StyledFooter data-testid="workspace-list-modal-footer">
<StyledSignInButton <StyledSignInButton

View File

@@ -6,26 +6,31 @@ import {
SettingsIcon, SettingsIcon,
} from '@blocksuite/icons'; } from '@blocksuite/icons';
import { useAtom } from 'jotai'; import { useAtom } from 'jotai';
import type { FC, SVGProps } from 'react'; import type { ReactElement, SVGProps } from 'react';
import { useMemo } from 'react'; import { useMemo } from 'react';
import { openSettingModalAtom } from '../../../atoms'; import { openSettingModalAtom } from '../../../atoms';
export type Config = type IconComponent = (props: SVGProps<SVGSVGElement>) => ReactElement;
| {
interface ConfigItem {
title: string; title: string;
icon: FC<SVGProps<SVGSVGElement>>; icon: IconComponent;
onClick: () => void;
}
interface ConfigPathItem {
title: string;
icon: IconComponent;
subPath: WorkspaceSubPath; subPath: WorkspaceSubPath;
} }
| {
title: string; export type Config = ConfigItem | ConfigPathItem;
icon: FC<SVGProps<SVGSVGElement>>;
onClick: () => void;
};
export const useSwitchToConfig = (workspaceId: string): Config[] => { export const useSwitchToConfig = (workspaceId: string): Config[] => {
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom); const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
return useMemo( return useMemo(
() => [ () => [
{ {

View File

@@ -6,24 +6,23 @@ import { PlusIcon } from '@blocksuite/icons';
import { nanoid } from '@blocksuite/store'; import { nanoid } from '@blocksuite/store';
import { useBlockSuiteWorkspaceHelper } from '@toeverything/hooks/use-block-suite-workspace-helper'; import { useBlockSuiteWorkspaceHelper } from '@toeverything/hooks/use-block-suite-workspace-helper';
import { Command } from 'cmdk'; import { Command } from 'cmdk';
import type React from 'react';
import { useCallback } from 'react'; import { useCallback } from 'react';
import { useNavigateHelper } from '../../../hooks/use-navigate-helper'; import { useNavigateHelper } from '../../../hooks/use-navigate-helper';
import type { BlockSuiteWorkspace } from '../../../shared'; import type { BlockSuiteWorkspace } from '../../../shared';
import { StyledModalFooterContent } from './style'; import { StyledModalFooterContent } from './style';
export type FooterProps = { export interface FooterProps {
query: string; query: string;
onClose: () => void; onClose: () => void;
blockSuiteWorkspace: BlockSuiteWorkspace; blockSuiteWorkspace: BlockSuiteWorkspace;
}; }
export const Footer: React.FC<FooterProps> = ({ export const Footer = ({
query, query,
onClose, onClose,
blockSuiteWorkspace, blockSuiteWorkspace,
}) => { }: FooterProps) => {
const { createPage } = useBlockSuiteWorkspaceHelper(blockSuiteWorkspace); const { createPage } = useBlockSuiteWorkspaceHelper(blockSuiteWorkspace);
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const { jumpToPage } = useNavigateHelper(); const { jumpToPage } = useNavigateHelper();
@@ -32,6 +31,7 @@ export const Footer: React.FC<FooterProps> = ({
query.length > MAX_QUERY_SHOW_LENGTH query.length > MAX_QUERY_SHOW_LENGTH
? query.slice(0, MAX_QUERY_SHOW_LENGTH) + '...' ? query.slice(0, MAX_QUERY_SHOW_LENGTH) + '...'
: query; : query;
return ( return (
<Command.Item <Command.Item
data-testid="quick-search-add-new-page" data-testid="quick-search-add-new-page"

View File

@@ -16,17 +16,17 @@ import {
StyledShortcut, StyledShortcut,
} from './style'; } from './style';
export type QuickSearchModalProps = { export interface QuickSearchModalProps {
workspace: AllWorkspace; workspace: AllWorkspace;
open: boolean; open: boolean;
setOpen: (value: boolean) => void; setOpen: (value: boolean) => void;
}; }
export const QuickSearchModal: React.FC<QuickSearchModalProps> = ({ export const QuickSearchModal = ({
open, open,
setOpen, setOpen,
workspace, workspace,
}) => { }: QuickSearchModalProps) => {
const blockSuiteWorkspace = workspace?.blockSuiteWorkspace; const blockSuiteWorkspace = workspace?.blockSuiteWorkspace;
const t = useAFFiNEI18N(); const t = useAFFiNEI18N();
const inputRef = useRef<HTMLInputElement>(null); const inputRef = useRef<HTMLInputElement>(null);
@@ -40,6 +40,7 @@ export const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
const handleClose = useCallback(() => { const handleClose = useCallback(() => {
setOpen(false); setOpen(false);
}, [setOpen]); }, [setOpen]);
// Add ‘⌘+K’ shortcut keys as switches // Add ‘⌘+K’ shortcut keys as switches
useEffect(() => { useEffect(() => {
const keydown = (e: KeyboardEvent) => { const keydown = (e: KeyboardEvent) => {
@@ -59,6 +60,7 @@ export const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
return () => return () =>
document.removeEventListener('keydown', keydown, { capture: true }); document.removeEventListener('keydown', keydown, { capture: true });
}, [open, setOpen, setQuery]); }, [open, setOpen, setQuery]);
useEffect(() => { useEffect(() => {
if (open) { if (open) {
// Waiting for DOM rendering // Waiting for DOM rendering
@@ -68,6 +70,7 @@ export const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
}); });
} }
}, [open]); }, [open]);
return ( return (
<Modal <Modal
open={open} open={open}

View File

@@ -6,7 +6,7 @@ import { useBlockSuitePageMeta } from '@toeverything/hooks/use-block-suite-page-
import { useBlockSuiteWorkspaceHelper } from '@toeverything/hooks/use-block-suite-workspace-helper'; import { useBlockSuiteWorkspaceHelper } from '@toeverything/hooks/use-block-suite-workspace-helper';
import { Command } from 'cmdk'; import { Command } from 'cmdk';
import { useAtomValue } from 'jotai'; import { useAtomValue } from 'jotai';
import type { Dispatch, FC, SetStateAction } from 'react'; import type { Dispatch, SetStateAction } from 'react';
import { recentPageSettingsAtom } from '../../../atoms'; import { recentPageSettingsAtom } from '../../../atoms';
import { useNavigateHelper } from '../../../hooks/use-navigate-helper'; import { useNavigateHelper } from '../../../hooks/use-navigate-helper';
@@ -14,18 +14,18 @@ import type { AllWorkspace } from '../../../shared';
import { useSwitchToConfig } from './config'; import { useSwitchToConfig } from './config';
import { StyledListItem, StyledNotFound } from './style'; import { StyledListItem, StyledNotFound } from './style';
export type ResultsProps = { export interface ResultsProps {
workspace: AllWorkspace; workspace: AllWorkspace;
query: string; query: string;
onClose: () => void; onClose: () => void;
setShowCreatePage: Dispatch<SetStateAction<boolean>>; setShowCreatePage: Dispatch<SetStateAction<boolean>>;
}; }
export const Results: FC<ResultsProps> = ({ export const Results = ({
query, query,
workspace, workspace,
setShowCreatePage, setShowCreatePage,
onClose, onClose,
}) => { }: ResultsProps) => {
const blockSuiteWorkspace = workspace.blockSuiteWorkspace; const blockSuiteWorkspace = workspace.blockSuiteWorkspace;
useBlockSuiteWorkspaceHelper(blockSuiteWorkspace); useBlockSuiteWorkspaceHelper(blockSuiteWorkspace);
const pageList = useBlockSuitePageMeta(blockSuiteWorkspace); const pageList = useBlockSuitePageMeta(blockSuiteWorkspace);
@@ -52,7 +52,9 @@ export const Results: FC<ResultsProps> = ({
return page.trash !== true; return page.trash !== true;
} }
}); });
setShowCreatePage(resultsPageMeta.length === 0); setShowCreatePage(resultsPageMeta.length === 0);
if (!query) { if (!query) {
return ( return (
<> <>

View File

@@ -14,19 +14,19 @@ import {
StyledWorkspaceStatus, StyledWorkspaceStatus,
} from './styles'; } from './styles';
export type WorkspaceSelectorProps = { export interface WorkspaceSelectorProps {
currentWorkspace: AllWorkspace; currentWorkspace: AllWorkspace;
onClick: () => void; onClick: () => void;
}; }
/** /**
* @todo-Doma Co-locate WorkspaceListModal with {@link WorkspaceSelector}, * @todo-Doma Co-locate WorkspaceListModal with {@link WorkspaceSelector},
* because it's never used elsewhere. * because it's never used elsewhere.
*/ */
export const WorkspaceSelector: React.FC<WorkspaceSelectorProps> = ({ export const WorkspaceSelector = ({
currentWorkspace, currentWorkspace,
onClick, onClick,
}) => { }: WorkspaceSelectorProps) => {
const [name] = useBlockSuiteWorkspaceName( const [name] = useBlockSuiteWorkspaceName(
currentWorkspace?.blockSuiteWorkspace currentWorkspace?.blockSuiteWorkspace
); );

View File

@@ -14,17 +14,16 @@ import { Header } from '../../blocksuite/workspace-header/header';
import * as styles from '../../blocksuite/workspace-header/styles.css'; import * as styles from '../../blocksuite/workspace-header/styles.css';
import { QuickSearchButton } from '../quick-search-button'; import { QuickSearchButton } from '../quick-search-button';
export type WorkspaceTitleProps = React.PropsWithChildren< export interface WorkspaceTitleProps
HeaderProps & { extends React.PropsWithChildren<HeaderProps> {
icon?: ReactNode; icon?: ReactNode;
} }
>;
export const WorkspaceTitle: React.FC<WorkspaceTitleProps> = ({ export const WorkspaceTitle = ({
icon, icon,
children, children,
...props ...props
}) => { }: WorkspaceTitleProps) => {
const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom); const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom);
return ( return (
<Header {...props}> <Header {...props}>
@@ -50,6 +49,7 @@ export const WorkspaceModeFilterTab = ({ ...props }: WorkspaceTitleProps) => {
} }
setMode(value); setMode(value);
}; };
return ( return (
<Header {...props}> <Header {...props}>
<div className={styles.allPageListTitleWrapper}> <div className={styles.allPageListTitleWrapper}>

View File

@@ -29,7 +29,7 @@ import {
import { usePassiveWorkspaceEffect } from '@toeverything/infra/__internal__/react'; import { usePassiveWorkspaceEffect } from '@toeverything/infra/__internal__/react';
import { currentWorkspaceIdAtom } from '@toeverything/infra/atom'; import { currentWorkspaceIdAtom } from '@toeverything/infra/atom';
import { useAtom, useAtomValue, useSetAtom } from 'jotai'; import { useAtom, useAtomValue, useSetAtom } from 'jotai';
import type { FC, PropsWithChildren, ReactElement } from 'react'; import type { PropsWithChildren, ReactElement } from 'react';
import { lazy, Suspense, useCallback, useMemo } from 'react'; import { lazy, Suspense, useCallback, useMemo } from 'react';
import { useLocation, useParams } from 'react-router-dom'; import { useLocation, useParams } from 'react-router-dom';
@@ -69,15 +69,17 @@ function DefaultProvider({ children }: PropsWithChildren) {
return <>{children}</>; return <>{children}</>;
} }
export const QuickSearch: FC = () => { export const QuickSearch = () => {
const [currentWorkspace] = useCurrentWorkspace(); const [currentWorkspace] = useCurrentWorkspace();
const [openQuickSearchModal, setOpenQuickSearchModalAtom] = useAtom( const [openQuickSearchModal, setOpenQuickSearchModalAtom] = useAtom(
openQuickSearchModalAtom openQuickSearchModalAtom
); );
const blockSuiteWorkspace = currentWorkspace?.blockSuiteWorkspace; const blockSuiteWorkspace = currentWorkspace?.blockSuiteWorkspace;
if (!blockSuiteWorkspace) { if (!blockSuiteWorkspace) {
return null; return null;
} }
return ( return (
<QuickSearchModal <QuickSearchModal
workspace={currentWorkspace} workspace={currentWorkspace}
@@ -118,8 +120,9 @@ export const CurrentWorkspaceContext = ({
return <>{children}</>; return <>{children}</>;
}; };
export const WorkspaceLayout: FC<PropsWithChildren> = export const WorkspaceLayout = function WorkspacesSuspense({
function WorkspacesSuspense({ children }) { children,
}: PropsWithChildren) {
const currentWorkspaceId = useAtomValue(currentWorkspaceIdAtom); const currentWorkspaceId = useAtomValue(currentWorkspaceIdAtom);
const jotaiWorkspaces = useAtomValue(rootWorkspacesMetadataAtom); const jotaiWorkspaces = useAtomValue(rootWorkspacesMetadataAtom);
const meta = useMemo( const meta = useMemo(
@@ -129,6 +132,7 @@ export const WorkspaceLayout: FC<PropsWithChildren> =
const Provider = const Provider =
(meta && WorkspaceAdapters[meta.flavour].UI.Provider) ?? DefaultProvider; (meta && WorkspaceAdapters[meta.flavour].UI.Provider) ?? DefaultProvider;
return ( return (
<> <>
{/* load all workspaces is costly, do not block the whole UI */} {/* load all workspaces is costly, do not block the whole UI */}
@@ -150,7 +154,7 @@ export const WorkspaceLayout: FC<PropsWithChildren> =
); );
}; };
export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => { export const WorkspaceLayoutInner = ({ children }: PropsWithChildren) => {
const [currentWorkspace] = useCurrentWorkspace(); const [currentWorkspace] = useCurrentWorkspace();
const { openPage } = useNavigateHelper(); const { openPage } = useNavigateHelper();

View File

@@ -7,7 +7,7 @@ import {
currentWorkspaceIdAtom, currentWorkspaceIdAtom,
} from '@toeverything/infra/atom'; } from '@toeverything/infra/atom';
import { useAtom, useAtomValue, useSetAtom } from 'jotai'; import { useAtom, useAtomValue, useSetAtom } from 'jotai';
import type { FC, ReactElement } from 'react'; import type { ReactElement } from 'react';
import { lazy, Suspense, useCallback, useTransition } from 'react'; import { lazy, Suspense, useCallback, useTransition } from 'react';
import type { SettingAtom } from '../atoms'; import type { SettingAtom } from '../atoms';
@@ -52,7 +52,7 @@ const OnboardingModal = lazy(() =>
})) }))
); );
export const Setting: FC = () => { export const Setting = () => {
const [currentWorkspace] = useCurrentWorkspace(); const [currentWorkspace] = useCurrentWorkspace();
const [{ open, workspaceId, activeTab }, setOpenSettingModalAtom] = const [{ open, workspaceId, activeTab }, setOpenSettingModalAtom] =
useAtom(openSettingModalAtom); useAtom(openSettingModalAtom);
@@ -89,6 +89,7 @@ export function CurrentWorkspaceModals() {
const [openDisableCloudAlertModal, setOpenDisableCloudAlertModal] = useAtom( const [openDisableCloudAlertModal, setOpenDisableCloudAlertModal] = useAtom(
openDisableCloudAlertModalAtom openDisableCloudAlertModalAtom
); );
return ( return (
<> <>
<Suspense> <Suspense>
@@ -139,6 +140,7 @@ export const AllWorkspaceModals = (): ReactElement => {
}, },
[setOpenSettingModalAtom, setOpenWorkspacesModal] [setOpenSettingModalAtom, setOpenWorkspacesModal]
); );
return ( return (
<> <>
<Suspense> <Suspense>