refactor: remove React.FC for affine core (#3617)
This commit is contained in:
@@ -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;
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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']()}>
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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(
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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(() => {
|
||||||
|
|||||||
@@ -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={
|
||||||
|
|||||||
@@ -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 />;
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|||||||
@@ -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 })}
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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 (
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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',
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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,35 +128,39 @@ 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 }) {
|
}
|
||||||
return (
|
|
||||||
<div
|
|
||||||
className={pluginContainer}
|
|
||||||
ref={useCallback(
|
|
||||||
(ref: HTMLDivElement | null) => {
|
|
||||||
if (ref) {
|
|
||||||
const div = document.createElement('div');
|
|
||||||
const cleanup = windowItem(div);
|
|
||||||
ref.appendChild(div);
|
|
||||||
addCleanup(pluginName, () => {
|
|
||||||
cleanup();
|
|
||||||
ref.removeChild(div);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
[pluginName, windowItem]
|
|
||||||
)}
|
|
||||||
/>
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
type LayoutPanelProps = {
|
const PluginContentAdapter = memo<PluginContentAdapterProps>(
|
||||||
|
function PluginContentAdapter({ windowItem, pluginName }) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
className={pluginContainer}
|
||||||
|
ref={useCallback(
|
||||||
|
(ref: HTMLDivElement | null) => {
|
||||||
|
if (ref) {
|
||||||
|
const div = document.createElement('div');
|
||||||
|
const cleanup = windowItem(div);
|
||||||
|
ref.appendChild(div);
|
||||||
|
addCleanup(pluginName, () => {
|
||||||
|
cleanup();
|
||||||
|
ref.removeChild(div);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
[pluginName, windowItem]
|
||||||
|
)}
|
||||||
|
/>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
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) {
|
||||||
|
|||||||
@@ -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>}
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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;
|
||||||
| {
|
|
||||||
title: string;
|
interface ConfigItem {
|
||||||
icon: FC<SVGProps<SVGSVGElement>>;
|
title: string;
|
||||||
subPath: WorkspaceSubPath;
|
icon: IconComponent;
|
||||||
}
|
onClick: () => void;
|
||||||
| {
|
}
|
||||||
title: string;
|
|
||||||
icon: FC<SVGProps<SVGSVGElement>>;
|
interface ConfigPathItem {
|
||||||
onClick: () => void;
|
title: string;
|
||||||
};
|
icon: IconComponent;
|
||||||
|
subPath: WorkspaceSubPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type Config = ConfigItem | ConfigPathItem;
|
||||||
|
|
||||||
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(
|
||||||
() => [
|
() => [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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"
|
||||||
|
|||||||
@@ -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}
|
||||||
|
|||||||
@@ -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 (
|
||||||
<>
|
<>
|
||||||
|
|||||||
@@ -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
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -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}>
|
||||||
|
|||||||
@@ -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,39 +120,41 @@ export const CurrentWorkspaceContext = ({
|
|||||||
return <>{children}</>;
|
return <>{children}</>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export const WorkspaceLayout: FC<PropsWithChildren> =
|
export const WorkspaceLayout = function WorkspacesSuspense({
|
||||||
function WorkspacesSuspense({ children }) {
|
children,
|
||||||
const currentWorkspaceId = useAtomValue(currentWorkspaceIdAtom);
|
}: PropsWithChildren) {
|
||||||
const jotaiWorkspaces = useAtomValue(rootWorkspacesMetadataAtom);
|
const currentWorkspaceId = useAtomValue(currentWorkspaceIdAtom);
|
||||||
const meta = useMemo(
|
const jotaiWorkspaces = useAtomValue(rootWorkspacesMetadataAtom);
|
||||||
() => jotaiWorkspaces.find(x => x.id === currentWorkspaceId),
|
const meta = useMemo(
|
||||||
[currentWorkspaceId, jotaiWorkspaces]
|
() => jotaiWorkspaces.find(x => x.id === currentWorkspaceId),
|
||||||
);
|
[currentWorkspaceId, jotaiWorkspaces]
|
||||||
|
);
|
||||||
|
|
||||||
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 */}
|
<>
|
||||||
<Suspense fallback={null}>
|
{/* load all workspaces is costly, do not block the whole UI */}
|
||||||
<AllWorkspaceModals />
|
<Suspense fallback={null}>
|
||||||
<CurrentWorkspaceContext>
|
<AllWorkspaceModals />
|
||||||
{/* fixme(himself65): don't re-render whole modals */}
|
|
||||||
<CurrentWorkspaceModals key={currentWorkspaceId} />
|
|
||||||
</CurrentWorkspaceContext>
|
|
||||||
</Suspense>
|
|
||||||
<CurrentWorkspaceContext>
|
<CurrentWorkspaceContext>
|
||||||
<Suspense fallback={<WorkspaceFallback />}>
|
{/* fixme(himself65): don't re-render whole modals */}
|
||||||
<Provider>
|
<CurrentWorkspaceModals key={currentWorkspaceId} />
|
||||||
<WorkspaceLayoutInner>{children}</WorkspaceLayoutInner>
|
|
||||||
</Provider>
|
|
||||||
</Suspense>
|
|
||||||
</CurrentWorkspaceContext>
|
</CurrentWorkspaceContext>
|
||||||
</>
|
</Suspense>
|
||||||
);
|
<CurrentWorkspaceContext>
|
||||||
};
|
<Suspense fallback={<WorkspaceFallback />}>
|
||||||
|
<Provider>
|
||||||
|
<WorkspaceLayoutInner>{children}</WorkspaceLayoutInner>
|
||||||
|
</Provider>
|
||||||
|
</Suspense>
|
||||||
|
</CurrentWorkspaceContext>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
export const WorkspaceLayoutInner: FC<PropsWithChildren> = ({ children }) => {
|
export const WorkspaceLayoutInner = ({ children }: PropsWithChildren) => {
|
||||||
const [currentWorkspace] = useCurrentWorkspace();
|
const [currentWorkspace] = useCurrentWorkspace();
|
||||||
const { openPage } = useNavigateHelper();
|
const { openPage } = useNavigateHelper();
|
||||||
|
|
||||||
|
|||||||
@@ -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>
|
||||||
|
|||||||
Reference in New Issue
Block a user