mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-25 18:26:05 +08:00
refactor(electron): tab title/icon update logic (#7675)
fix AF-1122 fix AF-1136
This commit is contained in:
@@ -7,21 +7,8 @@ import {
|
||||
import { appSidebarWidthAtom } from '@affine/core/components/app-sidebar/index.jotai';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { useAsyncCallback } from '@affine/core/hooks/affine-async-hooks';
|
||||
import { DesktopStateSynchronizer } from '@affine/core/modules/workbench/services/desktop-state-synchronizer';
|
||||
import type { WorkbenchMeta } from '@affine/electron-api';
|
||||
import { apis, events } from '@affine/electron-api';
|
||||
import {
|
||||
AllDocsIcon,
|
||||
CloseIcon,
|
||||
DeleteIcon,
|
||||
EdgelessIcon,
|
||||
PageIcon,
|
||||
PlusIcon,
|
||||
RightSidebarIcon,
|
||||
TagIcon,
|
||||
TodayIcon,
|
||||
ViewLayersIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
import { CloseIcon, PlusIcon, RightSidebarIcon } from '@blocksuite/icons/rc';
|
||||
import {
|
||||
useLiveData,
|
||||
useService,
|
||||
@@ -38,25 +25,14 @@ import {
|
||||
useState,
|
||||
} from 'react';
|
||||
|
||||
import { iconNameToIcon } from '../../workbench/constants';
|
||||
import { DesktopStateSynchronizer } from '../../workbench/services/desktop-state-synchronizer';
|
||||
import {
|
||||
AppTabsHeaderService,
|
||||
type TabStatus,
|
||||
} from '../services/app-tabs-header-service';
|
||||
import * as styles from './styles.css';
|
||||
|
||||
type ModuleName = NonNullable<WorkbenchMeta['views'][0]['moduleName']>;
|
||||
|
||||
const moduleNameToIcon = {
|
||||
all: <AllDocsIcon />,
|
||||
collection: <ViewLayersIcon />,
|
||||
doc: <PageIcon />,
|
||||
page: <PageIcon />,
|
||||
edgeless: <EdgelessIcon />,
|
||||
journal: <TodayIcon />,
|
||||
tag: <TagIcon />,
|
||||
trash: <DeleteIcon />,
|
||||
} satisfies Record<ModuleName, ReactNode>;
|
||||
|
||||
const WorkbenchTab = ({
|
||||
workbench,
|
||||
active: tabActive,
|
||||
@@ -66,6 +42,7 @@ const WorkbenchTab = ({
|
||||
active: boolean;
|
||||
tabsLength: number;
|
||||
}) => {
|
||||
useServiceOptional(DesktopStateSynchronizer);
|
||||
const tabsHeaderService = useService(AppTabsHeaderService);
|
||||
const activeViewIndex = workbench.activeViewIndex ?? 0;
|
||||
const onContextMenu = useAsyncCallback(
|
||||
@@ -115,7 +92,7 @@ const WorkbenchTab = ({
|
||||
>
|
||||
<div className={styles.labelIcon}>
|
||||
{workbench.ready || !workbench.loaded ? (
|
||||
moduleNameToIcon[view.moduleName ?? 'all']
|
||||
iconNameToIcon[view.iconName ?? 'allDocs']
|
||||
) : (
|
||||
<Loading />
|
||||
)}
|
||||
@@ -194,8 +171,6 @@ export const AppTabsHeader = ({
|
||||
await tabsHeaderService.onToggleRightSidebar();
|
||||
}, [tabsHeaderService]);
|
||||
|
||||
useServiceOptional(DesktopStateSynchronizer);
|
||||
|
||||
useEffect(() => {
|
||||
if (mode === 'app') {
|
||||
apis?.ui.pingAppLayoutReady().catch(console.error);
|
||||
|
||||
@@ -80,7 +80,7 @@ export const tab = style({
|
||||
boxShadow: cssVar('shadow1'),
|
||||
},
|
||||
'&[data-pinned="false"]': {
|
||||
paddingRight: 8,
|
||||
paddingRight: 20,
|
||||
},
|
||||
'&[data-pinned="true"]': {
|
||||
flexShrink: 0,
|
||||
|
||||
23
packages/frontend/core/src/modules/workbench/constants.tsx
Normal file
23
packages/frontend/core/src/modules/workbench/constants.tsx
Normal file
@@ -0,0 +1,23 @@
|
||||
import {
|
||||
AllDocsIcon,
|
||||
DeleteIcon,
|
||||
EdgelessIcon,
|
||||
PageIcon,
|
||||
TagIcon,
|
||||
TodayIcon,
|
||||
ViewLayersIcon,
|
||||
} from '@blocksuite/icons/rc';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
export const iconNameToIcon = {
|
||||
allDocs: <AllDocsIcon />,
|
||||
collection: <ViewLayersIcon />,
|
||||
doc: <PageIcon />,
|
||||
page: <PageIcon />,
|
||||
edgeless: <EdgelessIcon />,
|
||||
journal: <TodayIcon />,
|
||||
tag: <TagIcon />,
|
||||
trash: <DeleteIcon />,
|
||||
} satisfies Record<string, ReactNode>;
|
||||
|
||||
export type ViewIconName = keyof typeof iconNameToIcon;
|
||||
@@ -3,12 +3,15 @@ import type { Location, To } from 'history';
|
||||
import { Observable } from 'rxjs';
|
||||
|
||||
import { createNavigableHistory } from '../../../utils/navigable-history';
|
||||
import type { ViewIconName } from '../constants';
|
||||
import { ViewScope } from '../scopes/view';
|
||||
import { SidebarTab } from './sidebar-tab';
|
||||
|
||||
export class View extends Entity<{
|
||||
id: string;
|
||||
defaultLocation?: To | undefined;
|
||||
title?: string;
|
||||
icon?: ViewIconName;
|
||||
}> {
|
||||
scope = this.framework.createScope(ViewScope, {
|
||||
view: this as View,
|
||||
@@ -70,6 +73,10 @@ export class View extends Entity<{
|
||||
|
||||
size$ = new LiveData(100);
|
||||
|
||||
title$ = new LiveData(this.props.title ?? '');
|
||||
|
||||
icon$ = new LiveData(this.props.icon ?? 'allDocs');
|
||||
|
||||
push(path: To) {
|
||||
this.history.push(path);
|
||||
}
|
||||
@@ -105,4 +112,12 @@ export class View extends Entity<{
|
||||
activeSidebarTab(id: string | null) {
|
||||
this._activeSidebarTabId$.next(id);
|
||||
}
|
||||
|
||||
setTitle(title: string) {
|
||||
this.title$.next(title);
|
||||
}
|
||||
|
||||
setIcon(icon: ViewIconName) {
|
||||
this.icon$.next(icon);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,17 +3,16 @@ export { ViewScope } from './scopes/view';
|
||||
export { WorkbenchService } from './services/workbench';
|
||||
export { useIsActiveView } from './view/use-is-active-view';
|
||||
export { ViewBody, ViewHeader, ViewSidebarTab } from './view/view-islands';
|
||||
export { ViewIcon, ViewTitle } from './view/view-meta';
|
||||
export { WorkbenchLink } from './view/workbench-link';
|
||||
export { WorkbenchRoot } from './view/workbench-root';
|
||||
|
||||
import {
|
||||
DocsService,
|
||||
type Framework,
|
||||
GlobalStateService,
|
||||
WorkspaceScope,
|
||||
} from '@toeverything/infra';
|
||||
|
||||
import { WorkspacePropertiesAdapter } from '../properties';
|
||||
import { SidebarTab } from './entities/sidebar-tab';
|
||||
import { View } from './entities/view';
|
||||
import { Workbench } from './entities/workbench';
|
||||
@@ -52,9 +51,5 @@ export function configureDesktopWorkbenchModule(services: Framework) {
|
||||
.impl(WorkbenchDefaultState, DesktopWorkbenchDefaultState, [
|
||||
GlobalStateService,
|
||||
])
|
||||
.service(DesktopStateSynchronizer, [
|
||||
WorkbenchService,
|
||||
WorkspacePropertiesAdapter,
|
||||
DocsService,
|
||||
]);
|
||||
.service(DesktopStateSynchronizer, [WorkbenchService]);
|
||||
}
|
||||
|
||||
@@ -1,35 +1,13 @@
|
||||
import {
|
||||
apis,
|
||||
appInfo,
|
||||
events,
|
||||
type WorkbenchViewMeta,
|
||||
} from '@affine/electron-api';
|
||||
import { I18n, type I18nKeys, i18nTime } from '@affine/i18n';
|
||||
import type { DocsService } from '@toeverything/infra';
|
||||
import { Service } from '@toeverything/infra';
|
||||
import { combineLatest, filter, map, of, switchMap } from 'rxjs';
|
||||
import { apis, appInfo, events } from '@affine/electron-api';
|
||||
import { LiveData, Service } from '@toeverything/infra';
|
||||
|
||||
import { resolveRouteLinkMeta } from '../../navigation';
|
||||
import type { RouteModulePath } from '../../navigation/utils';
|
||||
import type { WorkspacePropertiesAdapter } from '../../properties';
|
||||
import type { WorkbenchService } from '../../workbench';
|
||||
|
||||
const routeModuleToI18n = {
|
||||
all: 'All pages',
|
||||
collection: 'Collections',
|
||||
tag: 'Tags',
|
||||
trash: 'Trash',
|
||||
} satisfies Record<RouteModulePath, I18nKeys>;
|
||||
|
||||
/**
|
||||
* Synchronize workbench state with state stored in main process
|
||||
*/
|
||||
export class DesktopStateSynchronizer extends Service {
|
||||
constructor(
|
||||
private readonly workbenchService: WorkbenchService,
|
||||
private readonly workspaceProperties: WorkspacePropertiesAdapter,
|
||||
private readonly docsService: DocsService
|
||||
) {
|
||||
constructor(private readonly workbenchService: WorkbenchService) {
|
||||
super();
|
||||
this.startSync();
|
||||
}
|
||||
@@ -80,70 +58,31 @@ export class DesktopStateSynchronizer extends Service {
|
||||
|
||||
// sync workbench state with main process
|
||||
// also fill tab view meta with title & moduleName
|
||||
this.workspaceProperties.workspace.engine.rootDocState$
|
||||
.pipe(
|
||||
filter(v => v.ready),
|
||||
switchMap(() => workbench.views$),
|
||||
switchMap(views => {
|
||||
return combineLatest(
|
||||
views.map(view =>
|
||||
view.location$.map(location => {
|
||||
return {
|
||||
view,
|
||||
location,
|
||||
};
|
||||
})
|
||||
)
|
||||
);
|
||||
}),
|
||||
map(viewLocations => {
|
||||
if (!apis || !appInfo?.viewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
const viewMetas = viewLocations.map(({ view, location }) => {
|
||||
return {
|
||||
id: view.id,
|
||||
path: location,
|
||||
};
|
||||
});
|
||||
|
||||
return viewMetas.map(viewMeta => this.fillTabViewMeta(viewMeta));
|
||||
}),
|
||||
filter(v => !!v),
|
||||
switchMap(viewMetas => {
|
||||
return this.docsService.list.docs$.pipe(
|
||||
switchMap(docs => {
|
||||
return combineLatest(
|
||||
viewMetas.map(vm => {
|
||||
return (
|
||||
docs
|
||||
.find(doc => doc.id === vm.docId)
|
||||
?.mode$.asObservable() ?? of('page')
|
||||
).pipe(
|
||||
map(mode => ({
|
||||
...vm,
|
||||
moduleName:
|
||||
vm.moduleName === 'page' ? mode : vm.moduleName,
|
||||
}))
|
||||
);
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
})
|
||||
)
|
||||
.subscribe(viewMetas => {
|
||||
if (!apis || !appInfo?.viewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
apis.ui
|
||||
.updateWorkbenchMeta(appInfo.viewId, {
|
||||
views: viewMetas,
|
||||
})
|
||||
.catch(console.error);
|
||||
LiveData.computed(get => {
|
||||
return get(workbench.views$).map(view => {
|
||||
const location = get(view.location$);
|
||||
return {
|
||||
id: view.id,
|
||||
title: get(view.title$),
|
||||
iconName: get(view.icon$),
|
||||
path: {
|
||||
pathname: location.pathname,
|
||||
search: location.search,
|
||||
hash: location.hash,
|
||||
},
|
||||
};
|
||||
});
|
||||
}).subscribe(views => {
|
||||
if (!apis || !appInfo?.viewId) {
|
||||
return;
|
||||
}
|
||||
|
||||
apis.ui
|
||||
.updateWorkbenchMeta(appInfo.viewId, {
|
||||
views,
|
||||
})
|
||||
.catch(console.error);
|
||||
});
|
||||
|
||||
workbench.activeViewIndex$.subscribe(activeViewIndex => {
|
||||
if (!apis || !appInfo?.viewId) {
|
||||
@@ -169,59 +108,4 @@ export class DesktopStateSynchronizer extends Service {
|
||||
.catch(console.error);
|
||||
});
|
||||
};
|
||||
|
||||
private toFullUrl(
|
||||
basename: string,
|
||||
location: { hash?: string; pathname?: string; search?: string }
|
||||
) {
|
||||
return basename + location.pathname + location.search + location.hash;
|
||||
}
|
||||
|
||||
// fill tab view meta with title & moduleName
|
||||
private fillTabViewMeta(
|
||||
view: WorkbenchViewMeta
|
||||
): WorkbenchViewMeta & { docId?: string } {
|
||||
if (!view.path) {
|
||||
return view;
|
||||
}
|
||||
|
||||
const url = this.toFullUrl(
|
||||
this.workbenchService.workbench.basename$.value,
|
||||
view.path
|
||||
);
|
||||
const linkMeta = resolveRouteLinkMeta(url);
|
||||
|
||||
if (!linkMeta) {
|
||||
return view;
|
||||
}
|
||||
|
||||
const journalString =
|
||||
linkMeta.moduleName === 'doc'
|
||||
? this.workspaceProperties.getJournalPageDateString(linkMeta.docId)
|
||||
: undefined;
|
||||
const isJournal = !!journalString;
|
||||
|
||||
const title = (() => {
|
||||
// todo: resolve more module types like collections?
|
||||
if (linkMeta?.moduleName === 'doc') {
|
||||
if (journalString) {
|
||||
return i18nTime(journalString, { absolute: { accuracy: 'day' } });
|
||||
}
|
||||
return (
|
||||
this.workspaceProperties.workspace.docCollection.meta.getDocMeta(
|
||||
linkMeta.docId
|
||||
)?.title || I18n['Untitled']()
|
||||
);
|
||||
} else {
|
||||
return I18n[routeModuleToI18n[linkMeta.moduleName]]();
|
||||
}
|
||||
})();
|
||||
|
||||
return {
|
||||
...view,
|
||||
title: title,
|
||||
docId: linkMeta.docId,
|
||||
moduleName: isJournal ? 'journal' : linkMeta.moduleName,
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -21,6 +21,7 @@ export function useBindWorkbenchToDesktopRouter(
|
||||
basename: string
|
||||
) {
|
||||
const browserLocation = useLocation();
|
||||
|
||||
useEffect(() => {
|
||||
const newLocation = browserLocationToViewLocation(
|
||||
browserLocation,
|
||||
@@ -36,6 +37,7 @@ export function useBindWorkbenchToDesktopRouter(
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
workbench.open(newLocation);
|
||||
}, [basename, browserLocation, workbench]);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
import { useServiceOptional } from '@toeverything/infra';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import type { ViewIconName } from '../constants';
|
||||
import { ViewService } from '../services/view';
|
||||
|
||||
export const ViewTitle = ({ title }: { title: string }) => {
|
||||
const view = useServiceOptional(ViewService)?.view;
|
||||
|
||||
useEffect(() => {
|
||||
if (view) {
|
||||
view.setTitle(title);
|
||||
}
|
||||
}, [title, view]);
|
||||
|
||||
return null;
|
||||
};
|
||||
|
||||
export const ViewIcon = ({ icon }: { icon: ViewIconName }) => {
|
||||
const view = useServiceOptional(ViewService)?.view;
|
||||
|
||||
useEffect(() => {
|
||||
if (view) {
|
||||
view.setIcon(icon);
|
||||
}
|
||||
}, [icon, view]);
|
||||
|
||||
return null;
|
||||
};
|
||||
@@ -6,6 +6,10 @@ import {
|
||||
VirtualizedCollectionList,
|
||||
} from '@affine/core/components/page-list';
|
||||
import { useNavigateHelper } from '@affine/core/hooks/use-navigate-helper';
|
||||
import {
|
||||
ViewIcon,
|
||||
ViewTitle,
|
||||
} from '@affine/core/modules/workbench/view/view-meta';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { useLiveData, useService, WorkspaceService } from '@toeverything/infra';
|
||||
import { nanoid } from 'nanoid';
|
||||
@@ -55,6 +59,8 @@ export const AllCollection = () => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewTitle title={t['Collections']()} />
|
||||
<ViewIcon icon="collection" />
|
||||
<ViewHeader>
|
||||
<AllCollectionHeader
|
||||
showCreateNew={!hideHeaderCreateNew}
|
||||
|
||||
@@ -6,6 +6,7 @@ import {
|
||||
import { useBlockSuiteDocMeta } from '@affine/core/hooks/use-block-suite-page-meta';
|
||||
import { performanceRenderLogger } from '@affine/core/shared';
|
||||
import type { Filter } from '@affine/env/filter';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import {
|
||||
GlobalContextService,
|
||||
useService,
|
||||
@@ -17,6 +18,8 @@ import {
|
||||
useIsActiveView,
|
||||
ViewBody,
|
||||
ViewHeader,
|
||||
ViewIcon,
|
||||
ViewTitle,
|
||||
} from '../../../modules/workbench';
|
||||
import { EmptyPageList } from '../page-list-empty';
|
||||
import * as styles from './all-page.css';
|
||||
@@ -47,8 +50,12 @@ export const AllPage = () => {
|
||||
return;
|
||||
}, [globalContext, isActiveView]);
|
||||
|
||||
const t = useI18n();
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewTitle title={t['All pages']()} />
|
||||
<ViewIcon icon="allDocs" />
|
||||
<ViewHeader>
|
||||
<AllPageHeader
|
||||
showCreateNew={!hideHeaderCreateNew}
|
||||
|
||||
@@ -5,10 +5,16 @@ import {
|
||||
import { CreateOrEditTag } from '@affine/core/components/page-list/tags/create-tag';
|
||||
import type { TagMeta } from '@affine/core/components/page-list/types';
|
||||
import { DeleteTagConfirmModal, TagService } from '@affine/core/modules/tag';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { useCallback, useState } from 'react';
|
||||
|
||||
import { ViewBody, ViewHeader } from '../../../modules/workbench';
|
||||
import {
|
||||
ViewBody,
|
||||
ViewHeader,
|
||||
ViewIcon,
|
||||
ViewTitle,
|
||||
} from '../../../modules/workbench';
|
||||
import { EmptyTagList } from '../page-list-empty';
|
||||
import * as styles from './all-tag.css';
|
||||
import { AllTagHeader } from './header';
|
||||
@@ -54,8 +60,12 @@ export const AllTag = () => {
|
||||
[setOpen, setSelectedTagIds]
|
||||
);
|
||||
|
||||
const t = useI18n();
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewTitle title={t['Tags']()} />
|
||||
<ViewIcon icon="tag" />
|
||||
<ViewHeader>
|
||||
<AllTagHeader />
|
||||
</ViewHeader>
|
||||
|
||||
@@ -29,6 +29,8 @@ import {
|
||||
useIsActiveView,
|
||||
ViewBody,
|
||||
ViewHeader,
|
||||
ViewIcon,
|
||||
ViewTitle,
|
||||
} from '../../../modules/workbench';
|
||||
import { WorkspaceSubPath } from '../../../shared';
|
||||
import * as styles from './collection.css';
|
||||
@@ -155,6 +157,8 @@ const Placeholder = ({ collection }: { collection: Collection }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewTitle title={collection.name} />
|
||||
<ViewIcon icon="collection" />
|
||||
<ViewHeader>
|
||||
<div
|
||||
style={{
|
||||
|
||||
@@ -13,9 +13,16 @@ import { PageHeaderMenuButton } from '@affine/core/components/blocksuite/block-s
|
||||
import { DetailPageHeaderPresentButton } from '@affine/core/components/blocksuite/block-suite-header/present/detail-header-present-button';
|
||||
import { EditorModeSwitch } from '@affine/core/components/blocksuite/block-suite-mode-switch';
|
||||
import { useRegisterCopyLinkCommands } from '@affine/core/hooks/affine/use-register-copy-link-commands';
|
||||
import { useDocCollectionPageTitle } from '@affine/core/hooks/use-block-suite-workspace-page-title';
|
||||
import { useJournalInfoHelper } from '@affine/core/hooks/use-journal';
|
||||
import { ViewIcon, ViewTitle } from '@affine/core/modules/workbench';
|
||||
import type { Doc } from '@blocksuite/store';
|
||||
import { type Workspace } from '@toeverything/infra';
|
||||
import {
|
||||
DocService,
|
||||
useLiveData,
|
||||
useService,
|
||||
type Workspace,
|
||||
} from '@toeverything/infra';
|
||||
import { useAtom, useAtomValue } from 'jotai';
|
||||
import { forwardRef, useCallback, useEffect, useRef, useState } from 'react';
|
||||
|
||||
@@ -68,8 +75,11 @@ export function JournalPageHeader({ page, workspace }: PageHeaderProps) {
|
||||
|
||||
const { hideShare, hideToday } =
|
||||
useDetailPageHeaderResponsive(containerWidth);
|
||||
const title = useDocCollectionPageTitle(workspace.docCollection, page?.id);
|
||||
return (
|
||||
<Header className={styles.header} ref={containerRef}>
|
||||
<ViewTitle title={title} />
|
||||
<ViewIcon icon="journal" />
|
||||
<EditorModeSwitch
|
||||
docCollection={workspace.docCollection}
|
||||
pageId={page?.id}
|
||||
@@ -115,8 +125,15 @@ export function NormalPageHeader({ page, workspace }: PageHeaderProps) {
|
||||
const onRename = useCallback(() => {
|
||||
setTimeout(() => titleInputHandleRef.current?.triggerEdit());
|
||||
}, []);
|
||||
|
||||
const title = useDocCollectionPageTitle(workspace.docCollection, page?.id);
|
||||
const doc = useService(DocService).doc;
|
||||
const currentMode = useLiveData(doc.mode$);
|
||||
|
||||
return (
|
||||
<Header className={styles.header} ref={containerRef}>
|
||||
<ViewTitle title={title} />
|
||||
<ViewIcon icon={currentMode ?? 'page'} />
|
||||
<EditorModeSwitch
|
||||
docCollection={workspace.docCollection}
|
||||
pageId={page?.id}
|
||||
|
||||
@@ -8,6 +8,8 @@ import {
|
||||
useIsActiveView,
|
||||
ViewBody,
|
||||
ViewHeader,
|
||||
ViewIcon,
|
||||
ViewTitle,
|
||||
} from '@affine/core/modules/workbench';
|
||||
import {
|
||||
GlobalContextService,
|
||||
@@ -39,6 +41,7 @@ export const TagDetail = ({ tagId }: { tagId?: string }) => {
|
||||
}, [pageIds, pageMetas]);
|
||||
|
||||
const isActiveView = useIsActiveView();
|
||||
const tagName = useLiveData(currentTag?.value$);
|
||||
|
||||
useEffect(() => {
|
||||
if (isActiveView && currentTag) {
|
||||
@@ -59,6 +62,8 @@ export const TagDetail = ({ tagId }: { tagId?: string }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<ViewTitle title={tagName ?? 'Untitled'} />
|
||||
<ViewIcon icon="tag" />
|
||||
<ViewHeader>
|
||||
<TagDetailHeader />
|
||||
</ViewHeader>
|
||||
|
||||
@@ -14,7 +14,13 @@ import {
|
||||
} from '@toeverything/infra';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
import { useIsActiveView, ViewBody, ViewHeader } from '../../modules/workbench';
|
||||
import {
|
||||
useIsActiveView,
|
||||
ViewBody,
|
||||
ViewHeader,
|
||||
ViewIcon,
|
||||
ViewTitle,
|
||||
} from '../../modules/workbench';
|
||||
import { EmptyPageList } from './page-list-empty';
|
||||
import * as styles from './trash-page.css';
|
||||
|
||||
@@ -56,8 +62,11 @@ export const TrashPage = () => {
|
||||
return;
|
||||
}, [globalContextService.globalContext.isTrash, isActiveView]);
|
||||
|
||||
const t = useI18n();
|
||||
return (
|
||||
<>
|
||||
<ViewTitle title={t['Trash']()} />
|
||||
<ViewIcon icon={'trash'} />
|
||||
<ViewHeader>
|
||||
<TrashHeader />
|
||||
</ViewHeader>
|
||||
|
||||
Reference in New Issue
Block a user