mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-20 18:54:03 +08:00
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 type { EditorContainer } from '@blocksuite/editor';
|
||||
import type { Page } from '@blocksuite/store';
|
||||
import type React from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { BlockSuiteEditor } from '../../blocksuite/block-suite-editor';
|
||||
@@ -15,7 +14,7 @@ const blockSuiteWorkspace = getOrCreateWorkspace(
|
||||
|
||||
const page = blockSuiteWorkspace.createPage({ id: 'page0' });
|
||||
|
||||
const Editor: React.FC = () => {
|
||||
const Editor = () => {
|
||||
const onLoad = useCallback((page: Page, editor: EditorContainer) => {
|
||||
// @ts-expect-error
|
||||
globalThis.page = page;
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Modal, ModalWrapper, Wrapper } from '@affine/component';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { CloseIcon } from '@blocksuite/icons';
|
||||
import { Button, IconButton } from '@toeverything/components/button';
|
||||
import type React from 'react';
|
||||
|
||||
import { Content, ContentTitle, Header, StyleTips } from './style';
|
||||
|
||||
@@ -12,11 +11,11 @@ interface EnableAffineCloudModalProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const EnableAffineCloudModal: React.FC<EnableAffineCloudModalProps> = ({
|
||||
export const EnableAffineCloudModal = ({
|
||||
onConfirm,
|
||||
open,
|
||||
onClose,
|
||||
}) => {
|
||||
}: EnableAffineCloudModalProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
return (
|
||||
|
||||
@@ -2,17 +2,20 @@ import { Menu, MenuItem, MenuTrigger, styled } from '@affine/component';
|
||||
import { LOCALES } from '@affine/i18n';
|
||||
import { useI18N } from '@affine/i18n';
|
||||
import type { ButtonProps } from '@toeverything/components/button';
|
||||
import type { FC, ReactElement } from 'react';
|
||||
import type { ReactElement } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export const StyledListItem = styled(MenuItem)(() => ({
|
||||
width: '132px',
|
||||
height: '38px',
|
||||
textTransform: 'capitalize',
|
||||
}));
|
||||
|
||||
const LanguageMenuContent: FC<{
|
||||
interface LanguageMenuContentProps {
|
||||
currentLanguage?: string;
|
||||
}> = ({ currentLanguage }) => {
|
||||
}
|
||||
|
||||
const LanguageMenuContent = ({ currentLanguage }: LanguageMenuContentProps) => {
|
||||
const i18n = useI18N();
|
||||
const changeLanguage = useCallback(
|
||||
(event: string) => {
|
||||
@@ -20,6 +23,7 @@ const LanguageMenuContent: FC<{
|
||||
},
|
||||
[i18n]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{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 currentLanguage = LOCALES.find(item => item.tag === i18n.language);
|
||||
|
||||
+9
-3
@@ -1,23 +1,29 @@
|
||||
import { SettingRow } from '@affine/component/setting-components';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ArrowRightSmallIcon } from '@blocksuite/icons';
|
||||
import { type FC, useState } from 'react';
|
||||
import { useState } from 'react';
|
||||
|
||||
import type { AffineOfficialWorkspace } from '../../../../shared';
|
||||
import type { WorkspaceSettingDetailProps } from '../index';
|
||||
import { WorkspaceDeleteModal } from './delete';
|
||||
import { WorkspaceLeave } from './leave';
|
||||
|
||||
export const DeleteLeaveWorkspace: FC<{
|
||||
interface DeleteLeaveWorkspaceProps {
|
||||
workspace: AffineOfficialWorkspace;
|
||||
onDeleteWorkspace: WorkspaceSettingDetailProps['onDeleteWorkspace'];
|
||||
}> = ({ workspace, onDeleteWorkspace }) => {
|
||||
}
|
||||
|
||||
export const DeleteLeaveWorkspace = ({
|
||||
workspace,
|
||||
onDeleteWorkspace,
|
||||
}: DeleteLeaveWorkspaceProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
// fixme: cloud regression
|
||||
const isOwner = true;
|
||||
|
||||
const [showDelete, setShowDelete] = useState(false);
|
||||
const [showLeave, setShowLeave] = useState(false);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingRow
|
||||
|
||||
@@ -3,7 +3,7 @@ import { SettingRow } from '@affine/component/setting-components';
|
||||
import { isDesktop } from '@affine/env/constant';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { Button } from '@toeverything/components/button';
|
||||
import { type FC, useCallback } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import type { AffineOfficialWorkspace } from '../../../shared';
|
||||
|
||||
@@ -28,9 +28,11 @@ async function syncBlobsToSqliteDb(workspace: AffineOfficialWorkspace) {
|
||||
}
|
||||
}
|
||||
|
||||
export const ExportPanel: FC<{
|
||||
interface ExportPanelProps {
|
||||
workspace: AffineOfficialWorkspace;
|
||||
}> = ({ workspace }) => {
|
||||
}
|
||||
|
||||
export const ExportPanel = ({ workspace }: ExportPanelProps) => {
|
||||
const workspaceId = workspace.id;
|
||||
const t = useAFFiNEI18N();
|
||||
const onExport = useCallback(async () => {
|
||||
@@ -42,6 +44,7 @@ export const ExportPanel: FC<{
|
||||
toast(t['Export success']());
|
||||
}
|
||||
}, [t, workspace, workspaceId]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingRow name={t['Export']()} desc={t['Export Description']()}>
|
||||
|
||||
@@ -9,7 +9,7 @@ import type {
|
||||
} from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
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 { DeleteLeaveWorkspace } from './delete-leave-workspace';
|
||||
@@ -18,7 +18,7 @@ import { ProfilePanel } from './profile';
|
||||
import { PublishPanel } from './publish';
|
||||
import { StoragePanel } from './storage';
|
||||
|
||||
export type WorkspaceSettingDetailProps = {
|
||||
export interface WorkspaceSettingDetailProps {
|
||||
workspaceId: string;
|
||||
onDeleteWorkspace: (id: string) => Promise<void>;
|
||||
onTransferWorkspace: <
|
||||
@@ -29,13 +29,13 @@ export type WorkspaceSettingDetailProps = {
|
||||
to: To,
|
||||
workspace: WorkspaceRegistry[From]
|
||||
) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export const WorkspaceSettingDetail: FC<WorkspaceSettingDetailProps> = ({
|
||||
export const WorkspaceSettingDetail = ({
|
||||
workspaceId,
|
||||
onDeleteWorkspace,
|
||||
...props
|
||||
}) => {
|
||||
}: WorkspaceSettingDetailProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const workspace = useWorkspace(workspaceId);
|
||||
const [name] = useBlockSuiteWorkspaceName(workspace.blockSuiteWorkspace);
|
||||
|
||||
@@ -5,7 +5,7 @@ import { DoneIcon } from '@blocksuite/icons';
|
||||
import { IconButton } from '@toeverything/components/button';
|
||||
import { useBlockSuiteWorkspaceAvatarUrl } from '@toeverything/hooks/use-block-suite-workspace-avatar-url';
|
||||
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 { Upload } from '../../pure/file-upload';
|
||||
@@ -30,9 +30,11 @@ const CameraIcon = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const ProfilePanel: FC<{
|
||||
interface ProfilePanelProps {
|
||||
workspace: AffineOfficialWorkspace;
|
||||
}> = ({ workspace }) => {
|
||||
}
|
||||
|
||||
export const ProfilePanel = ({ workspace }: ProfilePanelProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const [, update] = useBlockSuiteWorkspaceAvatarUrl(
|
||||
|
||||
@@ -9,7 +9,6 @@ import { WorkspaceFlavour } from '@affine/env/workspace';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { Button } from '@toeverything/components/button';
|
||||
import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-workspace-name';
|
||||
import type { FC } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import type { AffineOfficialWorkspace } from '../../../shared';
|
||||
@@ -19,26 +18,20 @@ import { TmpDisableAffineCloudModal } from '../tmp-disable-affine-cloud-modal';
|
||||
import type { WorkspaceSettingDetailProps } from './index';
|
||||
import * as style from './style.css';
|
||||
|
||||
export type PublishPanelProps = Omit<
|
||||
WorkspaceSettingDetailProps,
|
||||
'workspaceId'
|
||||
> & {
|
||||
export interface PublishPanelProps
|
||||
extends Omit<WorkspaceSettingDetailProps, 'workspaceId'> {
|
||||
workspace: AffineOfficialWorkspace;
|
||||
};
|
||||
export type PublishPanelLocalProps = Omit<
|
||||
WorkspaceSettingDetailProps,
|
||||
'workspaceId'
|
||||
> & {
|
||||
}
|
||||
export interface PublishPanelLocalProps
|
||||
extends Omit<WorkspaceSettingDetailProps, 'workspaceId'> {
|
||||
workspace: LocalWorkspace;
|
||||
};
|
||||
export type PublishPanelAffineProps = Omit<
|
||||
WorkspaceSettingDetailProps,
|
||||
'workspaceId'
|
||||
> & {
|
||||
}
|
||||
export interface PublishPanelAffineProps
|
||||
extends Omit<WorkspaceSettingDetailProps, 'workspaceId'> {
|
||||
workspace: AffineCloudWorkspace;
|
||||
};
|
||||
}
|
||||
|
||||
const PublishPanelAffine: FC<PublishPanelAffineProps> = props => {
|
||||
const PublishPanelAffine = (props: PublishPanelAffineProps) => {
|
||||
const { workspace } = props;
|
||||
const t = useAFFiNEI18N();
|
||||
// const toggleWorkspacePublish = useToggleWorkspacePublish(workspace);
|
||||
@@ -58,6 +51,7 @@ const PublishPanelAffine: FC<PublishPanelAffineProps> = props => {
|
||||
await navigator.clipboard.writeText(shareUrl);
|
||||
toast(t['Copied link to clipboard']());
|
||||
}, [shareUrl, t]);
|
||||
|
||||
return (
|
||||
<>
|
||||
<SettingRow
|
||||
@@ -91,10 +85,13 @@ const PublishPanelAffine: FC<PublishPanelAffineProps> = props => {
|
||||
);
|
||||
};
|
||||
|
||||
const FakePublishPanelAffine: FC<{
|
||||
interface FakePublishPanelAffineProps {
|
||||
workspace: AffineOfficialWorkspace;
|
||||
}> = () => {
|
||||
}
|
||||
|
||||
const FakePublishPanelAffine = (_props: FakePublishPanelAffineProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
return (
|
||||
<Tooltip
|
||||
content={t['com.affine.settings.workspace.publish.local-tooltip']()}
|
||||
@@ -108,10 +105,11 @@ const FakePublishPanelAffine: FC<{
|
||||
</Tooltip>
|
||||
);
|
||||
};
|
||||
const PublishPanelLocal: FC<PublishPanelLocalProps> = ({
|
||||
|
||||
const PublishPanelLocal = ({
|
||||
workspace,
|
||||
onTransferWorkspace,
|
||||
}) => {
|
||||
}: PublishPanelLocalProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
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) {
|
||||
return <PublishPanelAffine {...props} workspace={props.workspace} />;
|
||||
} 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 { Button } from '@toeverything/components/button';
|
||||
import { useMemo } from 'react';
|
||||
import { type FC, useCallback, useEffect, useState } from 'react';
|
||||
import { useCallback, useEffect, useState } from 'react';
|
||||
|
||||
import type { AffineOfficialWorkspace } from '../../../shared';
|
||||
import * as style from './style.css';
|
||||
@@ -31,9 +31,11 @@ const useDBFileSecondaryPath = (workspaceId: string) => {
|
||||
return path;
|
||||
};
|
||||
|
||||
export const StoragePanel: FC<{
|
||||
interface StoragePanelProps {
|
||||
workspace: AffineOfficialWorkspace;
|
||||
}> = ({ workspace }) => {
|
||||
}
|
||||
|
||||
export const StoragePanel = ({ workspace }: StoragePanelProps) => {
|
||||
const workspaceId = workspace.id;
|
||||
const t = useAFFiNEI18N();
|
||||
const secondaryPath = useDBFileSecondaryPath(workspaceId);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { TourModal } from '@affine/component/tour-modal';
|
||||
import { useAtom } from 'jotai';
|
||||
import type { FC } from 'react';
|
||||
import { memo, useCallback } from 'react';
|
||||
|
||||
import { openOnboardingModalAtom } from '../../atoms';
|
||||
import { guideOnboardingAtom } from '../../atoms/guide';
|
||||
|
||||
export const OnboardingModal: FC = memo(function OnboardingModal() {
|
||||
export const OnboardingModal = memo(function OnboardingModal() {
|
||||
const [open, setOpen] = useAtom(openOnboardingModalAtom);
|
||||
const [guideOpen, setShowOnboarding] = useAtom(guideOnboardingAtom);
|
||||
const onCloseTourModal = useCallback(() => {
|
||||
|
||||
+10
-3
@@ -1,6 +1,6 @@
|
||||
import { Menu, MenuItem, MenuTrigger } from '@affine/component';
|
||||
import dayjs from 'dayjs';
|
||||
import { type FC, useCallback } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import {
|
||||
dateFormatOptions,
|
||||
@@ -8,10 +8,15 @@ import {
|
||||
useAppSetting,
|
||||
} from '../../../../../atoms/settings';
|
||||
|
||||
const DateFormatMenuContent: FC<{
|
||||
interface DateFormatMenuContentProps {
|
||||
currentOption: DateFormats;
|
||||
onSelect: (option: DateFormats) => void;
|
||||
}> = ({ onSelect, currentOption }) => {
|
||||
}
|
||||
|
||||
const DateFormatMenuContent = ({
|
||||
onSelect,
|
||||
currentOption,
|
||||
}: DateFormatMenuContentProps) => {
|
||||
return (
|
||||
<>
|
||||
{dateFormatOptions.map(option => {
|
||||
@@ -30,6 +35,7 @@ const DateFormatMenuContent: FC<{
|
||||
</>
|
||||
);
|
||||
};
|
||||
|
||||
export const DateFormatSetting = () => {
|
||||
const [appearanceSettings, setAppSettings] = useAppSetting();
|
||||
const handleSelect = useCallback(
|
||||
@@ -38,6 +44,7 @@ export const DateFormatSetting = () => {
|
||||
},
|
||||
[setAppSettings]
|
||||
);
|
||||
|
||||
return (
|
||||
<Menu
|
||||
content={
|
||||
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
InformationIcon,
|
||||
KeyboardIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import type { FC, SVGProps } from 'react';
|
||||
import type { ReactElement, SVGProps } from 'react';
|
||||
|
||||
import { AboutAffine } from './about';
|
||||
import { AppearanceSettings } from './appearance';
|
||||
@@ -18,15 +18,18 @@ export type GeneralSettingKeys =
|
||||
| 'plugins'
|
||||
| 'about';
|
||||
|
||||
export type GeneralSettingList = {
|
||||
interface GeneralSettingListItem {
|
||||
key: GeneralSettingKeys;
|
||||
title: string;
|
||||
icon: FC<SVGProps<SVGSVGElement>>;
|
||||
icon: (props: SVGProps<SVGSVGElement>) => ReactElement;
|
||||
testId: string;
|
||||
}[];
|
||||
}
|
||||
|
||||
export type GeneralSettingList = GeneralSettingListItem[];
|
||||
|
||||
export const useGeneralSettingList = (): GeneralSettingList => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
return [
|
||||
{
|
||||
key: 'appearance',
|
||||
@@ -55,11 +58,11 @@ export const useGeneralSettingList = (): GeneralSettingList => {
|
||||
];
|
||||
};
|
||||
|
||||
export const GeneralSetting = ({
|
||||
generalKey,
|
||||
}: {
|
||||
interface GeneralSettingProps {
|
||||
generalKey: GeneralSettingKeys;
|
||||
}) => {
|
||||
}
|
||||
|
||||
export const GeneralSetting = ({ generalKey }: GeneralSettingProps) => {
|
||||
switch (generalKey) {
|
||||
case 'shortcuts':
|
||||
return <Shortcuts />;
|
||||
|
||||
@@ -1,10 +1,9 @@
|
||||
import {
|
||||
SettingModal as SettingModalBase,
|
||||
type SettingModalProps,
|
||||
type SettingModalProps as SettingModalBaseProps,
|
||||
} from '@affine/component/setting-components';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { ContactWithUsIcon } from '@blocksuite/icons';
|
||||
import type React from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { AccountSetting } from './account-setting';
|
||||
@@ -18,21 +17,25 @@ import { settingContent } from './style.css';
|
||||
import { WorkspaceSetting } from './workspace-setting';
|
||||
|
||||
type ActiveTab = GeneralSettingKeys | 'workspace' | 'account';
|
||||
export type SettingProps = {
|
||||
|
||||
export interface SettingProps {
|
||||
activeTab: ActiveTab;
|
||||
workspaceId: string | null;
|
||||
onSettingClick: (params: {
|
||||
activeTab: ActiveTab;
|
||||
workspaceId: string | null;
|
||||
}) => void;
|
||||
};
|
||||
export const SettingModal: React.FC<SettingModalProps & SettingProps> = ({
|
||||
}
|
||||
|
||||
type SettingModalProps = SettingModalBaseProps & SettingProps;
|
||||
|
||||
export const SettingModal = ({
|
||||
open,
|
||||
setOpen,
|
||||
activeTab = 'appearance',
|
||||
workspaceId = null,
|
||||
onSettingClick,
|
||||
}) => {
|
||||
}: SettingModalProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
const generalSettingList = useGeneralSettingList();
|
||||
|
||||
@@ -11,7 +11,6 @@ import { useBlockSuiteWorkspaceName } from '@toeverything/hooks/use-block-suite-
|
||||
import { useStaticBlockSuiteWorkspace } from '@toeverything/infra/__internal__/react';
|
||||
import clsx from 'clsx';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import type { FC } from 'react';
|
||||
import { Suspense } from 'react';
|
||||
|
||||
import { useCurrentWorkspace } from '../../../../hooks/current/use-current-workspace';
|
||||
@@ -28,21 +27,24 @@ import {
|
||||
sidebarTitle,
|
||||
} from './style.css';
|
||||
|
||||
export const SettingSidebar: FC<{
|
||||
interface SettingSidebarProps {
|
||||
generalSettingList: GeneralSettingList;
|
||||
onGeneralSettingClick: (key: GeneralSettingKeys) => void;
|
||||
onWorkspaceSettingClick: (workspaceId: string) => void;
|
||||
selectedWorkspaceId: string | null;
|
||||
selectedGeneralKey: string | null;
|
||||
onAccountSettingClick: () => void;
|
||||
}> = ({
|
||||
}
|
||||
|
||||
export const SettingSidebar = ({
|
||||
generalSettingList,
|
||||
onGeneralSettingClick,
|
||||
onWorkspaceSettingClick,
|
||||
selectedWorkspaceId,
|
||||
selectedGeneralKey,
|
||||
}) => {
|
||||
}: SettingSidebarProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
return (
|
||||
<div className={settingSlideBar} data-testid="settings-sidebar">
|
||||
<div className={sidebarTitle}>{t['Settings']()}</div>
|
||||
@@ -88,10 +90,15 @@ export const SettingSidebar: FC<{
|
||||
);
|
||||
};
|
||||
|
||||
export const WorkspaceList: FC<{
|
||||
interface WorkspaceListProps {
|
||||
onWorkspaceSettingClick: (workspaceId: string) => void;
|
||||
selectedWorkspaceId: string | null;
|
||||
}> = ({ onWorkspaceSettingClick, selectedWorkspaceId }) => {
|
||||
}
|
||||
|
||||
export const WorkspaceList = ({
|
||||
onWorkspaceSettingClick,
|
||||
selectedWorkspaceId,
|
||||
}: WorkspaceListProps) => {
|
||||
const workspaces = useAtomValue(rootWorkspacesMetadataAtom);
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
return (
|
||||
@@ -114,19 +121,22 @@ export const WorkspaceList: FC<{
|
||||
);
|
||||
};
|
||||
|
||||
interface WorkspaceListItemProps {
|
||||
meta: RootWorkspaceMetadata;
|
||||
onClick: () => void;
|
||||
isCurrent: boolean;
|
||||
isActive: boolean;
|
||||
}
|
||||
|
||||
const WorkspaceListItem = ({
|
||||
meta,
|
||||
onClick,
|
||||
isCurrent,
|
||||
isActive,
|
||||
}: {
|
||||
meta: RootWorkspaceMetadata;
|
||||
onClick: () => void;
|
||||
isCurrent: boolean;
|
||||
isActive: boolean;
|
||||
}) => {
|
||||
}: WorkspaceListItemProps) => {
|
||||
const workspace = useStaticBlockSuiteWorkspace(meta.id);
|
||||
const [workspaceName] = useBlockSuiteWorkspaceName(workspace);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={clsx(sidebarSelectItem, { active: isActive })}
|
||||
|
||||
@@ -3,7 +3,6 @@ import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { CloseIcon } from '@blocksuite/icons';
|
||||
import { IconButton } from '@toeverything/components/button';
|
||||
import type React from 'react';
|
||||
|
||||
import {
|
||||
Content,
|
||||
@@ -20,10 +19,12 @@ interface TmpDisableAffineCloudModalProps {
|
||||
onClose: () => void;
|
||||
}
|
||||
|
||||
export const TmpDisableAffineCloudModal: React.FC<
|
||||
TmpDisableAffineCloudModalProps
|
||||
> = ({ open, onClose }) => {
|
||||
export const TmpDisableAffineCloudModal = ({
|
||||
open,
|
||||
onClose,
|
||||
}: TmpDisableAffineCloudModalProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
return (
|
||||
<Modal
|
||||
data-testid="disable-affine-cloud-modal"
|
||||
|
||||
@@ -2,19 +2,20 @@ import { Modal, ModalWrapper } from '@affine/component';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { CloseIcon } from '@blocksuite/icons';
|
||||
import { IconButton } from '@toeverything/components/button';
|
||||
import type React from 'react';
|
||||
|
||||
import { Content, ContentTitle, Header, StyleButton, StyleTips } from './style';
|
||||
|
||||
export type TransformWorkspaceToAffineModalProps = {
|
||||
export interface TransformWorkspaceToAffineModalProps {
|
||||
open: boolean;
|
||||
onClose: () => void;
|
||||
onConform: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
export const TransformWorkspaceToAffineModal: React.FC<
|
||||
TransformWorkspaceToAffineModalProps
|
||||
> = ({ open, onClose, onConform }) => {
|
||||
export const TransformWorkspaceToAffineModal = ({
|
||||
open,
|
||||
onClose,
|
||||
onConform,
|
||||
}: TransformWorkspaceToAffineModalProps) => {
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
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 { useBlockSuiteWorkspacePage } from '@toeverything/hooks/use-block-suite-workspace-page';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
import type React from 'react';
|
||||
import { Suspense, useCallback, useMemo } from 'react';
|
||||
|
||||
import { allPageModeSelectAtom } from '../../../atoms';
|
||||
@@ -23,13 +22,13 @@ import { filterPage } from '../../../utils/filter';
|
||||
import { emptyDescButton, emptyDescKbd, pageListEmptyStyle } from './index.css';
|
||||
import { usePageHelper } from './utils';
|
||||
|
||||
export type BlockSuitePageListProps = {
|
||||
export interface BlockSuitePageListProps {
|
||||
blockSuiteWorkspace: BlockSuiteWorkspace;
|
||||
listType: 'all' | 'trash' | 'shared' | 'public';
|
||||
isPublic?: true;
|
||||
isPublic?: boolean;
|
||||
onOpenPage: (pageId: string, newTab?: boolean) => void;
|
||||
collection?: Collection;
|
||||
};
|
||||
}
|
||||
|
||||
const filter = {
|
||||
all: (pageMeta: PageMeta) => !pageMeta.trash,
|
||||
@@ -41,13 +40,12 @@ const filter = {
|
||||
shared: (pageMeta: PageMeta) => pageMeta.isPublic && !pageMeta.trash,
|
||||
};
|
||||
|
||||
const PagePreviewInner = ({
|
||||
workspace,
|
||||
pageId,
|
||||
}: {
|
||||
interface PagePreviewInnerProps {
|
||||
workspace: Workspace;
|
||||
pageId: string;
|
||||
}) => {
|
||||
}
|
||||
|
||||
const PagePreviewInner = ({ workspace, pageId }: PagePreviewInnerProps) => {
|
||||
const page = useBlockSuiteWorkspacePage(workspace, pageId);
|
||||
assertExists(page);
|
||||
const previewAtom = useBlockSuitePagePreview(page);
|
||||
@@ -55,13 +53,12 @@ const PagePreviewInner = ({
|
||||
return preview;
|
||||
};
|
||||
|
||||
const PagePreview = ({
|
||||
workspace,
|
||||
pageId,
|
||||
}: {
|
||||
interface PagePreviewProps {
|
||||
workspace: Workspace;
|
||||
pageId: string;
|
||||
}) => {
|
||||
}
|
||||
|
||||
const PagePreview = ({ workspace, pageId }: PagePreviewProps) => {
|
||||
return (
|
||||
<Suspense>
|
||||
<PagePreviewInner workspace={workspace} pageId={pageId} />
|
||||
@@ -69,10 +66,12 @@ const PagePreview = ({
|
||||
);
|
||||
};
|
||||
|
||||
const PageListEmpty = (props: {
|
||||
interface PageListEmptyProps {
|
||||
createPage?: ReturnType<typeof usePageHelper>['createPage'];
|
||||
listType: BlockSuitePageListProps['listType'];
|
||||
}) => {
|
||||
}
|
||||
|
||||
const PageListEmpty = (props: PageListEmptyProps) => {
|
||||
const { listType, createPage } = props;
|
||||
const t = useAFFiNEI18N();
|
||||
|
||||
@@ -124,13 +123,13 @@ const PageListEmpty = (props: {
|
||||
);
|
||||
};
|
||||
|
||||
export const BlockSuitePageList: React.FC<BlockSuitePageListProps> = ({
|
||||
export const BlockSuitePageList = ({
|
||||
blockSuiteWorkspace,
|
||||
onOpenPage,
|
||||
listType,
|
||||
isPublic = false,
|
||||
collection,
|
||||
}) => {
|
||||
}: BlockSuitePageListProps) => {
|
||||
const pageMetas = useBlockSuitePageMeta(blockSuiteWorkspace);
|
||||
const {
|
||||
toggleFavorite,
|
||||
@@ -262,6 +261,7 @@ export const BlockSuitePageList: React.FC<BlockSuitePageListProps> = ({
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
return (
|
||||
<PageList
|
||||
workspaceId={blockSuiteWorkspace.id}
|
||||
|
||||
+10
-3
@@ -3,10 +3,10 @@ import { LOCALES } from '@affine/i18n';
|
||||
import { useI18N } from '@affine/i18n';
|
||||
import { ArrowDownSmallIcon, LanguageIcon } from '@blocksuite/icons';
|
||||
import { Button } from '@toeverything/components/button';
|
||||
import type { FC, ReactElement } from 'react';
|
||||
import type { ReactElement } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
const LanguageMenuContent: FC = () => {
|
||||
const LanguageMenuContent = () => {
|
||||
const i18n = useI18N();
|
||||
const changeLanguage = useCallback(
|
||||
(event: string) => {
|
||||
@@ -16,6 +16,7 @@ const LanguageMenuContent: FC = () => {
|
||||
},
|
||||
[i18n]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
{LOCALES.map(option => {
|
||||
@@ -34,7 +35,8 @@ const LanguageMenuContent: FC = () => {
|
||||
</>
|
||||
);
|
||||
};
|
||||
export const LanguageMenu: React.FC = () => {
|
||||
|
||||
export const LanguageMenu = () => {
|
||||
const i18n = useI18N();
|
||||
|
||||
const currentLanguage = LOCALES.find(item => item.tag === i18n.language);
|
||||
@@ -87,6 +89,7 @@ const StyledContainer = styled('div')(() => {
|
||||
padding: '0 14px',
|
||||
};
|
||||
});
|
||||
|
||||
const StyledIconContainer = styled('div')(() => {
|
||||
return {
|
||||
width: '20px',
|
||||
@@ -96,6 +99,7 @@ const StyledIconContainer = styled('div')(() => {
|
||||
...displayFlex('flex-start', 'center'),
|
||||
};
|
||||
});
|
||||
|
||||
const StyledButtonContainer = styled('div')(() => {
|
||||
return {
|
||||
width: '100%',
|
||||
@@ -107,6 +111,7 @@ const StyledButtonContainer = styled('div')(() => {
|
||||
marginLeft: '12px',
|
||||
};
|
||||
});
|
||||
|
||||
const StyledButton = styled(Button)(() => {
|
||||
return {
|
||||
width: '100%',
|
||||
@@ -118,6 +123,7 @@ const StyledButton = styled(Button)(() => {
|
||||
padding: '0',
|
||||
};
|
||||
});
|
||||
|
||||
const StyledArrowDownContainer = styled('div')(() => {
|
||||
return {
|
||||
height: '32px',
|
||||
@@ -128,6 +134,7 @@ const StyledArrowDownContainer = styled('div')(() => {
|
||||
fontSize: '24px',
|
||||
};
|
||||
});
|
||||
|
||||
const StyledCurrentLanguage = styled('div')(() => {
|
||||
return {
|
||||
marginLeft: '12px',
|
||||
|
||||
@@ -13,7 +13,7 @@ import {
|
||||
} from '@toeverything/infra/__internal__/plugin';
|
||||
import clsx from 'clsx';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
import type { FC, HTMLAttributes, PropsWithChildren, ReactNode } from 'react';
|
||||
import type { HTMLAttributes, ReactElement, ReactNode } from 'react';
|
||||
import {
|
||||
forwardRef,
|
||||
startTransition,
|
||||
@@ -32,21 +32,21 @@ import { EditorOptionMenu } from './header-right-items/editor-option-menu';
|
||||
import * as styles from './styles.css';
|
||||
import { OSWarningMessage, shouldShowWarning } from './utils';
|
||||
|
||||
export type BaseHeaderProps<
|
||||
export interface BaseHeaderProps<
|
||||
Workspace extends AffineOfficialWorkspace = AffineOfficialWorkspace,
|
||||
> = {
|
||||
> {
|
||||
workspace: Workspace;
|
||||
currentPage: Page | null;
|
||||
isPublic: boolean;
|
||||
leftSlot?: ReactNode;
|
||||
};
|
||||
}
|
||||
|
||||
export enum HeaderRightItemName {
|
||||
EditorOptionMenu = 'editorOptionMenu',
|
||||
}
|
||||
|
||||
type HeaderItem = {
|
||||
Component: FC<BaseHeaderProps>;
|
||||
interface HeaderItem {
|
||||
Component: (props: BaseHeaderProps) => ReactElement;
|
||||
// todo: public workspace should be one of the flavour
|
||||
availableWhen: (
|
||||
workspace: AffineOfficialWorkspace,
|
||||
@@ -55,7 +55,7 @@ type HeaderItem = {
|
||||
isPublic: boolean;
|
||||
}
|
||||
) => boolean;
|
||||
};
|
||||
}
|
||||
|
||||
const HeaderRightItems: Record<HeaderRightItemName, HeaderItem> = {
|
||||
[HeaderRightItemName.EditorOptionMenu]: {
|
||||
@@ -68,7 +68,6 @@ const HeaderRightItems: Record<HeaderRightItemName, HeaderItem> = {
|
||||
},
|
||||
};
|
||||
|
||||
export type HeaderProps = BaseHeaderProps;
|
||||
const WindowsAppControls = () => {
|
||||
const handleMinimizeApp = useCallback(() => {
|
||||
window.apis?.ui.handleMinimizeApp().catch(err => {
|
||||
@@ -85,6 +84,7 @@ const WindowsAppControls = () => {
|
||||
console.error(err);
|
||||
});
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div
|
||||
data-platform-target="win32"
|
||||
@@ -118,6 +118,7 @@ const WindowsAppControls = () => {
|
||||
const PluginHeader = () => {
|
||||
const headerItem = useAtomValue(pluginHeaderItemAtom);
|
||||
const pluginsRef = useRef<string[]>([]);
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.pluginHeaderItems}
|
||||
@@ -151,10 +152,13 @@ const PluginHeader = () => {
|
||||
);
|
||||
};
|
||||
|
||||
export const Header = forwardRef<
|
||||
HTMLDivElement,
|
||||
PropsWithChildren<HeaderProps> & HTMLAttributes<HTMLDivElement>
|
||||
>((props, ref) => {
|
||||
export interface HeaderProps
|
||||
extends BaseHeaderProps,
|
||||
HTMLAttributes<HTMLDivElement> {
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export const Header = forwardRef<HTMLDivElement, HeaderProps>((props, ref) => {
|
||||
const [showWarning, setShowWarning] = useState(false);
|
||||
const [showDownloadTip, setShowDownloadTip] = useAtom(
|
||||
guideDownloadClientTipAtom
|
||||
@@ -167,6 +171,7 @@ export const Header = forwardRef<
|
||||
|
||||
const mode = useAtomValue(currentModeAtom);
|
||||
const isWindowsDesktop = globalThis.platform === 'win32' && isDesktop;
|
||||
|
||||
return (
|
||||
<div
|
||||
className={styles.headerContainer}
|
||||
|
||||
@@ -5,12 +5,7 @@ import {
|
||||
usePageMetaHelper,
|
||||
} from '@toeverything/hooks/use-block-suite-page-meta';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import type {
|
||||
FC,
|
||||
HTMLAttributes,
|
||||
PropsWithChildren,
|
||||
ReactElement,
|
||||
} from 'react';
|
||||
import type { HTMLAttributes, ReactElement, ReactNode } from 'react';
|
||||
import { useCallback, useRef, useState } from 'react';
|
||||
|
||||
import { openQuickSearchModalAtom } from '../../../atoms';
|
||||
@@ -20,11 +15,15 @@ import type { BaseHeaderProps } from './header';
|
||||
import { Header } from './header';
|
||||
import * as styles from './styles.css';
|
||||
|
||||
export type WorkspaceHeaderProps = BaseHeaderProps;
|
||||
export interface WorkspaceHeaderProps
|
||||
extends BaseHeaderProps,
|
||||
HTMLAttributes<HTMLDivElement> {
|
||||
children?: ReactNode;
|
||||
}
|
||||
|
||||
export const BlockSuiteEditorHeader: FC<
|
||||
PropsWithChildren<WorkspaceHeaderProps> & HTMLAttributes<HTMLDivElement>
|
||||
> = (props): ReactElement => {
|
||||
export const BlockSuiteEditorHeader = (
|
||||
props: WorkspaceHeaderProps
|
||||
): ReactElement => {
|
||||
const { workspace, currentPage, children, isPublic } = props;
|
||||
// fixme(himself65): remove this atom and move it to props
|
||||
const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom);
|
||||
@@ -50,6 +49,7 @@ export const BlockSuiteEditorHeader: FC<
|
||||
const headerRef = useRef<HTMLDivElement>(null);
|
||||
assertExists(pageMeta);
|
||||
const title = pageMeta?.title;
|
||||
|
||||
return (
|
||||
<Header ref={headerRef} {...props}>
|
||||
{children}
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import { isDesktop } from '@affine/env/constant';
|
||||
import { Trans } from '@affine/i18n';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import type React from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
|
||||
const minimumChromeVersion = 102;
|
||||
@@ -23,7 +22,7 @@ export const shouldShowWarning = () => {
|
||||
}
|
||||
};
|
||||
|
||||
export const OSWarningMessage: React.FC = () => {
|
||||
export const OSWarningMessage = () => {
|
||||
const t = useAFFiNEI18N();
|
||||
const [notChrome, setNotChrome] = useState(false);
|
||||
const [notGoodVersion, setNotGoodVersion] = useState(false);
|
||||
|
||||
@@ -16,7 +16,7 @@ import {
|
||||
import { contentLayoutAtom, rootStore } from '@toeverything/infra/atom';
|
||||
import clsx from 'clsx';
|
||||
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 { 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 { pluginContainer } from './page-detail-editor.css';
|
||||
|
||||
export type PageDetailEditorProps = {
|
||||
export interface PageDetailEditorProps {
|
||||
isPublic?: boolean;
|
||||
workspace: Workspace;
|
||||
pageId: string;
|
||||
onInit: (page: Page, editor: Readonly<EditorContainer>) => void;
|
||||
onLoad?: (page: Page, editor: EditorContainer) => () => void;
|
||||
};
|
||||
}
|
||||
|
||||
const EditorWrapper = memo(function EditorWrapper({
|
||||
workspace,
|
||||
@@ -128,35 +128,39 @@ const EditorWrapper = memo(function EditorWrapper({
|
||||
);
|
||||
});
|
||||
|
||||
const PluginContentAdapter = memo<{
|
||||
interface PluginContentAdapterProps {
|
||||
windowItem: (div: HTMLDivElement) => () => void;
|
||||
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;
|
||||
editorProps: PageDetailEditorProps;
|
||||
};
|
||||
}
|
||||
|
||||
const LayoutPanel = memo(function LayoutPanel(
|
||||
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 page = useBlockSuiteWorkspacePage(workspace, pageId);
|
||||
if (!page) {
|
||||
|
||||
@@ -1,22 +1,21 @@
|
||||
import { styled } from '@affine/component';
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { Button } from '@toeverything/components/button';
|
||||
import type { ChangeEvent } from 'react';
|
||||
import type React from 'react';
|
||||
import type { ChangeEvent, PropsWithChildren } from 'react';
|
||||
import { useRef } from 'react';
|
||||
|
||||
export type UploadProps = React.PropsWithChildren<{
|
||||
export interface UploadProps {
|
||||
uploadType?: string;
|
||||
accept?: string;
|
||||
fileChange: (file: File) => void;
|
||||
}>;
|
||||
}
|
||||
|
||||
export const Upload: React.FC<UploadProps> = ({
|
||||
export const Upload = ({
|
||||
fileChange,
|
||||
accept,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
}: PropsWithChildren<UploadProps>) => {
|
||||
const t = useAFFiNEI18N();
|
||||
const input_ref = useRef<HTMLInputElement>(null);
|
||||
const _chooseFile = () => {
|
||||
@@ -35,6 +34,7 @@ export const Upload: React.FC<UploadProps> = ({
|
||||
input_ref.current.value = '';
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<UploadStyle onClick={_chooseFile}>
|
||||
{children ?? <Button>{t['Upload']()}</Button>}
|
||||
|
||||
@@ -1,15 +1,16 @@
|
||||
import { useAFFiNEI18N } from '@affine/i18n/hooks';
|
||||
import { CloudWorkspaceIcon } from '@blocksuite/icons';
|
||||
import { useSetAtom } from 'jotai';
|
||||
import { type CSSProperties, type FC, forwardRef } from 'react';
|
||||
import { type CSSProperties, forwardRef } from 'react';
|
||||
|
||||
import { openDisableCloudAlertModalAtom } from '../../../atoms';
|
||||
import { stringToColour } from '../../../utils';
|
||||
import { StyledFooter, StyledSignInButton } from './styles';
|
||||
|
||||
export const Footer: FC = () => {
|
||||
export const Footer = () => {
|
||||
const t = useAFFiNEI18N();
|
||||
const setOpen = useSetAtom(openDisableCloudAlertModalAtom);
|
||||
|
||||
return (
|
||||
<StyledFooter data-testid="workspace-list-modal-footer">
|
||||
<StyledSignInButton
|
||||
|
||||
@@ -6,26 +6,31 @@ import {
|
||||
SettingsIcon,
|
||||
} from '@blocksuite/icons';
|
||||
import { useAtom } from 'jotai';
|
||||
import type { FC, SVGProps } from 'react';
|
||||
import type { ReactElement, SVGProps } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { openSettingModalAtom } from '../../../atoms';
|
||||
|
||||
export type Config =
|
||||
| {
|
||||
title: string;
|
||||
icon: FC<SVGProps<SVGSVGElement>>;
|
||||
subPath: WorkspaceSubPath;
|
||||
}
|
||||
| {
|
||||
title: string;
|
||||
icon: FC<SVGProps<SVGSVGElement>>;
|
||||
onClick: () => void;
|
||||
};
|
||||
type IconComponent = (props: SVGProps<SVGSVGElement>) => ReactElement;
|
||||
|
||||
interface ConfigItem {
|
||||
title: string;
|
||||
icon: IconComponent;
|
||||
onClick: () => void;
|
||||
}
|
||||
|
||||
interface ConfigPathItem {
|
||||
title: string;
|
||||
icon: IconComponent;
|
||||
subPath: WorkspaceSubPath;
|
||||
}
|
||||
|
||||
export type Config = ConfigItem | ConfigPathItem;
|
||||
|
||||
export const useSwitchToConfig = (workspaceId: string): Config[] => {
|
||||
const t = useAFFiNEI18N();
|
||||
const [, setOpenSettingModalAtom] = useAtom(openSettingModalAtom);
|
||||
|
||||
return useMemo(
|
||||
() => [
|
||||
{
|
||||
|
||||
@@ -6,24 +6,23 @@ import { PlusIcon } from '@blocksuite/icons';
|
||||
import { nanoid } from '@blocksuite/store';
|
||||
import { useBlockSuiteWorkspaceHelper } from '@toeverything/hooks/use-block-suite-workspace-helper';
|
||||
import { Command } from 'cmdk';
|
||||
import type React from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useNavigateHelper } from '../../../hooks/use-navigate-helper';
|
||||
import type { BlockSuiteWorkspace } from '../../../shared';
|
||||
import { StyledModalFooterContent } from './style';
|
||||
|
||||
export type FooterProps = {
|
||||
export interface FooterProps {
|
||||
query: string;
|
||||
onClose: () => void;
|
||||
blockSuiteWorkspace: BlockSuiteWorkspace;
|
||||
};
|
||||
}
|
||||
|
||||
export const Footer: React.FC<FooterProps> = ({
|
||||
export const Footer = ({
|
||||
query,
|
||||
onClose,
|
||||
blockSuiteWorkspace,
|
||||
}) => {
|
||||
}: FooterProps) => {
|
||||
const { createPage } = useBlockSuiteWorkspaceHelper(blockSuiteWorkspace);
|
||||
const t = useAFFiNEI18N();
|
||||
const { jumpToPage } = useNavigateHelper();
|
||||
@@ -32,6 +31,7 @@ export const Footer: React.FC<FooterProps> = ({
|
||||
query.length > MAX_QUERY_SHOW_LENGTH
|
||||
? query.slice(0, MAX_QUERY_SHOW_LENGTH) + '...'
|
||||
: query;
|
||||
|
||||
return (
|
||||
<Command.Item
|
||||
data-testid="quick-search-add-new-page"
|
||||
|
||||
@@ -16,17 +16,17 @@ import {
|
||||
StyledShortcut,
|
||||
} from './style';
|
||||
|
||||
export type QuickSearchModalProps = {
|
||||
export interface QuickSearchModalProps {
|
||||
workspace: AllWorkspace;
|
||||
open: boolean;
|
||||
setOpen: (value: boolean) => void;
|
||||
};
|
||||
}
|
||||
|
||||
export const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
|
||||
export const QuickSearchModal = ({
|
||||
open,
|
||||
setOpen,
|
||||
workspace,
|
||||
}) => {
|
||||
}: QuickSearchModalProps) => {
|
||||
const blockSuiteWorkspace = workspace?.blockSuiteWorkspace;
|
||||
const t = useAFFiNEI18N();
|
||||
const inputRef = useRef<HTMLInputElement>(null);
|
||||
@@ -40,6 +40,7 @@ export const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
|
||||
const handleClose = useCallback(() => {
|
||||
setOpen(false);
|
||||
}, [setOpen]);
|
||||
|
||||
// Add ‘⌘+K’ shortcut keys as switches
|
||||
useEffect(() => {
|
||||
const keydown = (e: KeyboardEvent) => {
|
||||
@@ -59,6 +60,7 @@ export const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
|
||||
return () =>
|
||||
document.removeEventListener('keydown', keydown, { capture: true });
|
||||
}, [open, setOpen, setQuery]);
|
||||
|
||||
useEffect(() => {
|
||||
if (open) {
|
||||
// Waiting for DOM rendering
|
||||
@@ -68,6 +70,7 @@ export const QuickSearchModal: React.FC<QuickSearchModalProps> = ({
|
||||
});
|
||||
}
|
||||
}, [open]);
|
||||
|
||||
return (
|
||||
<Modal
|
||||
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 { Command } from 'cmdk';
|
||||
import { useAtomValue } from 'jotai';
|
||||
import type { Dispatch, FC, SetStateAction } from 'react';
|
||||
import type { Dispatch, SetStateAction } from 'react';
|
||||
|
||||
import { recentPageSettingsAtom } from '../../../atoms';
|
||||
import { useNavigateHelper } from '../../../hooks/use-navigate-helper';
|
||||
@@ -14,18 +14,18 @@ import type { AllWorkspace } from '../../../shared';
|
||||
import { useSwitchToConfig } from './config';
|
||||
import { StyledListItem, StyledNotFound } from './style';
|
||||
|
||||
export type ResultsProps = {
|
||||
export interface ResultsProps {
|
||||
workspace: AllWorkspace;
|
||||
query: string;
|
||||
onClose: () => void;
|
||||
setShowCreatePage: Dispatch<SetStateAction<boolean>>;
|
||||
};
|
||||
export const Results: FC<ResultsProps> = ({
|
||||
}
|
||||
export const Results = ({
|
||||
query,
|
||||
workspace,
|
||||
setShowCreatePage,
|
||||
onClose,
|
||||
}) => {
|
||||
}: ResultsProps) => {
|
||||
const blockSuiteWorkspace = workspace.blockSuiteWorkspace;
|
||||
useBlockSuiteWorkspaceHelper(blockSuiteWorkspace);
|
||||
const pageList = useBlockSuitePageMeta(blockSuiteWorkspace);
|
||||
@@ -52,7 +52,9 @@ export const Results: FC<ResultsProps> = ({
|
||||
return page.trash !== true;
|
||||
}
|
||||
});
|
||||
|
||||
setShowCreatePage(resultsPageMeta.length === 0);
|
||||
|
||||
if (!query) {
|
||||
return (
|
||||
<>
|
||||
|
||||
+4
-4
@@ -14,19 +14,19 @@ import {
|
||||
StyledWorkspaceStatus,
|
||||
} from './styles';
|
||||
|
||||
export type WorkspaceSelectorProps = {
|
||||
export interface WorkspaceSelectorProps {
|
||||
currentWorkspace: AllWorkspace;
|
||||
onClick: () => void;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @todo-Doma Co-locate WorkspaceListModal with {@link WorkspaceSelector},
|
||||
* because it's never used elsewhere.
|
||||
*/
|
||||
export const WorkspaceSelector: React.FC<WorkspaceSelectorProps> = ({
|
||||
export const WorkspaceSelector = ({
|
||||
currentWorkspace,
|
||||
onClick,
|
||||
}) => {
|
||||
}: WorkspaceSelectorProps) => {
|
||||
const [name] = useBlockSuiteWorkspaceName(
|
||||
currentWorkspace?.blockSuiteWorkspace
|
||||
);
|
||||
|
||||
@@ -14,17 +14,16 @@ import { Header } from '../../blocksuite/workspace-header/header';
|
||||
import * as styles from '../../blocksuite/workspace-header/styles.css';
|
||||
import { QuickSearchButton } from '../quick-search-button';
|
||||
|
||||
export type WorkspaceTitleProps = React.PropsWithChildren<
|
||||
HeaderProps & {
|
||||
icon?: ReactNode;
|
||||
}
|
||||
>;
|
||||
export interface WorkspaceTitleProps
|
||||
extends React.PropsWithChildren<HeaderProps> {
|
||||
icon?: ReactNode;
|
||||
}
|
||||
|
||||
export const WorkspaceTitle: React.FC<WorkspaceTitleProps> = ({
|
||||
export const WorkspaceTitle = ({
|
||||
icon,
|
||||
children,
|
||||
...props
|
||||
}) => {
|
||||
}: WorkspaceTitleProps) => {
|
||||
const setOpenQuickSearch = useSetAtom(openQuickSearchModalAtom);
|
||||
return (
|
||||
<Header {...props}>
|
||||
@@ -50,6 +49,7 @@ export const WorkspaceModeFilterTab = ({ ...props }: WorkspaceTitleProps) => {
|
||||
}
|
||||
setMode(value);
|
||||
};
|
||||
|
||||
return (
|
||||
<Header {...props}>
|
||||
<div className={styles.allPageListTitleWrapper}>
|
||||
|
||||
@@ -29,7 +29,7 @@ import {
|
||||
import { usePassiveWorkspaceEffect } from '@toeverything/infra/__internal__/react';
|
||||
import { currentWorkspaceIdAtom } from '@toeverything/infra/atom';
|
||||
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 { useLocation, useParams } from 'react-router-dom';
|
||||
|
||||
@@ -69,15 +69,17 @@ function DefaultProvider({ children }: PropsWithChildren) {
|
||||
return <>{children}</>;
|
||||
}
|
||||
|
||||
export const QuickSearch: FC = () => {
|
||||
export const QuickSearch = () => {
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const [openQuickSearchModal, setOpenQuickSearchModalAtom] = useAtom(
|
||||
openQuickSearchModalAtom
|
||||
);
|
||||
const blockSuiteWorkspace = currentWorkspace?.blockSuiteWorkspace;
|
||||
|
||||
if (!blockSuiteWorkspace) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (
|
||||
<QuickSearchModal
|
||||
workspace={currentWorkspace}
|
||||
@@ -118,39 +120,41 @@ export const CurrentWorkspaceContext = ({
|
||||
return <>{children}</>;
|
||||
};
|
||||
|
||||
export const WorkspaceLayout: FC<PropsWithChildren> =
|
||||
function WorkspacesSuspense({ children }) {
|
||||
const currentWorkspaceId = useAtomValue(currentWorkspaceIdAtom);
|
||||
const jotaiWorkspaces = useAtomValue(rootWorkspacesMetadataAtom);
|
||||
const meta = useMemo(
|
||||
() => jotaiWorkspaces.find(x => x.id === currentWorkspaceId),
|
||||
[currentWorkspaceId, jotaiWorkspaces]
|
||||
);
|
||||
export const WorkspaceLayout = function WorkspacesSuspense({
|
||||
children,
|
||||
}: PropsWithChildren) {
|
||||
const currentWorkspaceId = useAtomValue(currentWorkspaceIdAtom);
|
||||
const jotaiWorkspaces = useAtomValue(rootWorkspacesMetadataAtom);
|
||||
const meta = useMemo(
|
||||
() => jotaiWorkspaces.find(x => x.id === currentWorkspaceId),
|
||||
[currentWorkspaceId, jotaiWorkspaces]
|
||||
);
|
||||
|
||||
const Provider =
|
||||
(meta && WorkspaceAdapters[meta.flavour].UI.Provider) ?? DefaultProvider;
|
||||
return (
|
||||
<>
|
||||
{/* load all workspaces is costly, do not block the whole UI */}
|
||||
<Suspense fallback={null}>
|
||||
<AllWorkspaceModals />
|
||||
<CurrentWorkspaceContext>
|
||||
{/* fixme(himself65): don't re-render whole modals */}
|
||||
<CurrentWorkspaceModals key={currentWorkspaceId} />
|
||||
</CurrentWorkspaceContext>
|
||||
</Suspense>
|
||||
const Provider =
|
||||
(meta && WorkspaceAdapters[meta.flavour].UI.Provider) ?? DefaultProvider;
|
||||
|
||||
return (
|
||||
<>
|
||||
{/* load all workspaces is costly, do not block the whole UI */}
|
||||
<Suspense fallback={null}>
|
||||
<AllWorkspaceModals />
|
||||
<CurrentWorkspaceContext>
|
||||
<Suspense fallback={<WorkspaceFallback />}>
|
||||
<Provider>
|
||||
<WorkspaceLayoutInner>{children}</WorkspaceLayoutInner>
|
||||
</Provider>
|
||||
</Suspense>
|
||||
{/* fixme(himself65): don't re-render whole modals */}
|
||||
<CurrentWorkspaceModals key={currentWorkspaceId} />
|
||||
</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 { openPage } = useNavigateHelper();
|
||||
|
||||
|
||||
@@ -7,7 +7,7 @@ import {
|
||||
currentWorkspaceIdAtom,
|
||||
} from '@toeverything/infra/atom';
|
||||
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 type { SettingAtom } from '../atoms';
|
||||
@@ -52,7 +52,7 @@ const OnboardingModal = lazy(() =>
|
||||
}))
|
||||
);
|
||||
|
||||
export const Setting: FC = () => {
|
||||
export const Setting = () => {
|
||||
const [currentWorkspace] = useCurrentWorkspace();
|
||||
const [{ open, workspaceId, activeTab }, setOpenSettingModalAtom] =
|
||||
useAtom(openSettingModalAtom);
|
||||
@@ -89,6 +89,7 @@ export function CurrentWorkspaceModals() {
|
||||
const [openDisableCloudAlertModal, setOpenDisableCloudAlertModal] = useAtom(
|
||||
openDisableCloudAlertModalAtom
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Suspense>
|
||||
@@ -139,6 +140,7 @@ export const AllWorkspaceModals = (): ReactElement => {
|
||||
},
|
||||
[setOpenSettingModalAtom, setOpenWorkspacesModal]
|
||||
);
|
||||
|
||||
return (
|
||||
<>
|
||||
<Suspense>
|
||||
|
||||
Reference in New Issue
Block a user