mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-12 04:18:54 +00:00
refactor(core): set edgeless theme on doc created (#8670)
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import { AffineContext } from '@affine/component/context';
|
||||
import { AppFallback } from '@affine/core/components/affine/app-container';
|
||||
import { AffineContext } from '@affine/core/components/context';
|
||||
import { Telemetry } from '@affine/core/components/telemetry';
|
||||
import { configureMobileModules } from '@affine/core/mobile/modules';
|
||||
import { router } from '@affine/core/mobile/router';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AffineContext } from '@affine/component/context';
|
||||
import { GlobalLoading } from '@affine/component/global-loading';
|
||||
import { AppFallback } from '@affine/core/components/affine/app-container';
|
||||
import { AffineContext } from '@affine/core/components/context';
|
||||
import { WindowsAppControls } from '@affine/core/components/pure/header/windows-app-controls';
|
||||
import { Telemetry } from '@affine/core/components/telemetry';
|
||||
import { router } from '@affine/core/desktop/router';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { ThemeProvider } from '@affine/component/theme-provider';
|
||||
import { ShellAppFallback } from '@affine/core/components/affine/app-container';
|
||||
import { useAppSettingHelper } from '@affine/core/components/hooks/affine/use-app-setting-helper';
|
||||
import { ThemeProvider } from '@affine/core/components/theme-provider';
|
||||
import { configureAppSidebarModule } from '@affine/core/modules/app-sidebar';
|
||||
import {
|
||||
AppTabsHeader,
|
||||
@@ -9,9 +9,9 @@ import {
|
||||
import { configureDesktopApiModule } from '@affine/core/modules/desktop-api';
|
||||
import { configureI18nModule, I18nProvider } from '@affine/core/modules/i18n';
|
||||
import { configureElectronStateStorageImpls } from '@affine/core/modules/storage';
|
||||
import { configureAppThemeModule } from '@affine/core/modules/theme';
|
||||
import { SplitViewFallback } from '@affine/core/modules/workbench/view/split-view/split-view';
|
||||
import {
|
||||
configureAppThemeModule,
|
||||
configureGlobalStorageModule,
|
||||
Framework,
|
||||
FrameworkRoot,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AffineContext } from '@affine/component/context';
|
||||
import { AppFallback } from '@affine/core/components/affine/app-container';
|
||||
import { AffineContext } from '@affine/core/components/context';
|
||||
import { Telemetry } from '@affine/core/components/telemetry';
|
||||
import { configureMobileModules } from '@affine/core/mobile/modules';
|
||||
import { router } from '@affine/core/mobile/router';
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import { AffineContext } from '@affine/component/context';
|
||||
import { AppFallback } from '@affine/core/components/affine/app-container';
|
||||
import { AffineContext } from '@affine/core/components/context';
|
||||
import { Telemetry } from '@affine/core/components/telemetry';
|
||||
import { configureMobileModules } from '@affine/core/mobile/modules';
|
||||
import { router } from '@affine/core/mobile/router';
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { AffineContext } from '@affine/component/context';
|
||||
import { GlobalLoading } from '@affine/component/global-loading';
|
||||
import { AppFallback } from '@affine/core/components/affine/app-container';
|
||||
import { AffineContext } from '@affine/core/components/context';
|
||||
import { Telemetry } from '@affine/core/components/telemetry';
|
||||
import { router } from '@affine/core/desktop/router';
|
||||
import { configureCommonModules } from '@affine/core/modules';
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
AIPageRootBlockSpec,
|
||||
} from '@affine/core/blocksuite/presets/ai';
|
||||
import { EditorSettingService } from '@affine/core/modules/editor-setting';
|
||||
import { AppThemeService } from '@affine/core/modules/theme';
|
||||
import { mixpanel } from '@affine/track';
|
||||
import {
|
||||
ConfigExtension,
|
||||
@@ -32,7 +33,6 @@ import {
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import type { Container } from '@blocksuite/global/di';
|
||||
import {
|
||||
AppThemeService,
|
||||
DocService,
|
||||
DocsService,
|
||||
type FrameworkProvider,
|
||||
|
||||
@@ -2,26 +2,22 @@ import type { WeekDatePickerHandle } from '@affine/component';
|
||||
import { WeekDatePicker } from '@affine/component';
|
||||
import { useJournalRouteHelper } from '@affine/core/components/hooks/use-journal';
|
||||
import { JournalService } from '@affine/core/modules/journal';
|
||||
import type { Doc, DocCollection } from '@blocksuite/affine/store';
|
||||
import type { Doc } from '@blocksuite/affine/store';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import dayjs from 'dayjs';
|
||||
import { useEffect, useRef, useState } from 'react';
|
||||
|
||||
export interface JournalWeekDatePickerProps {
|
||||
docCollection: DocCollection;
|
||||
page: Doc;
|
||||
}
|
||||
|
||||
const weekStyle = { maxWidth: 800, width: '100%' };
|
||||
export const JournalWeekDatePicker = ({
|
||||
docCollection,
|
||||
page,
|
||||
}: JournalWeekDatePickerProps) => {
|
||||
export const JournalWeekDatePicker = ({ page }: JournalWeekDatePickerProps) => {
|
||||
const handleRef = useRef<WeekDatePickerHandle>(null);
|
||||
const journalService = useService(JournalService);
|
||||
const journalDateStr = useLiveData(journalService.journalDate$(page.id));
|
||||
const journalDate = journalDateStr ? dayjs(journalDateStr) : null;
|
||||
const { openJournal } = useJournalRouteHelper(docCollection);
|
||||
const { openJournal } = useJournalRouteHelper();
|
||||
const [date, setDate] = useState(
|
||||
(journalDate ?? dayjs()).format('YYYY-MM-DD')
|
||||
);
|
||||
|
||||
@@ -1,18 +1,11 @@
|
||||
import { Button } from '@affine/component';
|
||||
import { useJournalRouteHelper } from '@affine/core/components/hooks/use-journal';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import type { DocCollection } from '@blocksuite/affine/store';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
export interface JournalTodayButtonProps {
|
||||
docCollection: DocCollection;
|
||||
}
|
||||
|
||||
export const JournalTodayButton = ({
|
||||
docCollection,
|
||||
}: JournalTodayButtonProps) => {
|
||||
export const JournalTodayButton = () => {
|
||||
const t = useI18n();
|
||||
const journalHelper = useJournalRouteHelper(docCollection);
|
||||
const journalHelper = useJournalRouteHelper();
|
||||
|
||||
const onToday = useCallback(() => {
|
||||
journalHelper.openToday();
|
||||
|
||||
@@ -5,11 +5,8 @@ import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import { type DocMode } from '@blocksuite/affine/blocks';
|
||||
import type { DocCollection } from '@blocksuite/affine/store';
|
||||
import { type DocProps, DocsService, useServices } from '@toeverything/infra';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
import { getValueByDefaultTheme } from '../../hooks/use-journal';
|
||||
|
||||
export const usePageHelper = (docCollection: DocCollection) => {
|
||||
const {
|
||||
docsService,
|
||||
@@ -25,7 +22,6 @@ export const usePageHelper = (docCollection: DocCollection) => {
|
||||
const workbench = workbenchService.workbench;
|
||||
const docRecordList = docsService.list;
|
||||
const appSidebar = appSidebarService.sidebar;
|
||||
const { resolvedTheme } = useTheme();
|
||||
|
||||
const createPageAndOpen = useCallback(
|
||||
(mode?: DocMode, open?: boolean | 'new-tab') => {
|
||||
@@ -35,14 +31,6 @@ export const usePageHelper = (docCollection: DocCollection) => {
|
||||
};
|
||||
const page = docsService.createDoc({ docProps });
|
||||
|
||||
const value = getValueByDefaultTheme(
|
||||
editorSettingService.editorSetting.settings$.value.edgelessDefaultTheme,
|
||||
resolvedTheme || 'light'
|
||||
);
|
||||
docRecordList
|
||||
.doc$(page.id)
|
||||
.value?.setProperty('edgelessColorTheme', value);
|
||||
|
||||
if (mode) {
|
||||
docRecordList.doc$(page.id).value?.setPrimaryMode(mode);
|
||||
}
|
||||
@@ -58,7 +46,6 @@ export const usePageHelper = (docCollection: DocCollection) => {
|
||||
docRecordList,
|
||||
docsService,
|
||||
editorSettingService.editorSetting,
|
||||
resolvedTheme,
|
||||
workbench,
|
||||
]
|
||||
);
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
import { ConfirmModalProvider } from '@affine/component';
|
||||
import { ProviderComposer } from '@affine/component/provider-composer';
|
||||
import { ThemeProvider } from '@affine/component/theme-provider';
|
||||
import { ThemeProvider } from '@affine/core/components/theme-provider';
|
||||
import type { createStore } from 'jotai';
|
||||
import { Provider } from 'jotai';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { useMemo } from 'react';
|
||||
|
||||
import { ConfirmModalProvider } from '../../ui/modal';
|
||||
|
||||
export type AffineContextProps = PropsWithChildren<{
|
||||
store?: ReturnType<typeof createStore>;
|
||||
}>;
|
||||
@@ -1,9 +1,8 @@
|
||||
import { EditorSettingService } from '@affine/core/modules/editor-setting';
|
||||
import type { EdgelessDefaultTheme } from '@affine/core/modules/editor-setting/schema';
|
||||
import { JournalService } from '@affine/core/modules/journal';
|
||||
import { i18nTime } from '@affine/i18n';
|
||||
import { track } from '@affine/track';
|
||||
import { type DocCollection, Text } from '@blocksuite/affine/store';
|
||||
import { Text } from '@blocksuite/affine/store';
|
||||
import {
|
||||
type DocProps,
|
||||
DocsService,
|
||||
@@ -12,29 +11,9 @@ import {
|
||||
useServices,
|
||||
} from '@toeverything/infra';
|
||||
import dayjs from 'dayjs';
|
||||
import { useTheme } from 'next-themes';
|
||||
import { useCallback, useMemo } from 'react';
|
||||
|
||||
import { WorkbenchService } from '../../modules/workbench';
|
||||
import { useDocCollectionHelper } from './use-block-suite-workspace-helper';
|
||||
|
||||
export const getValueByDefaultTheme = (
|
||||
defaultTheme: EdgelessDefaultTheme,
|
||||
currentAppTheme: string
|
||||
) => {
|
||||
switch (defaultTheme) {
|
||||
case 'dark':
|
||||
return 'dark';
|
||||
case 'light':
|
||||
return 'light';
|
||||
case 'specified':
|
||||
return currentAppTheme === 'dark' ? 'dark' : 'light';
|
||||
case 'auto':
|
||||
return 'system';
|
||||
default:
|
||||
return 'system';
|
||||
}
|
||||
};
|
||||
|
||||
type MaybeDate = Date | string | number;
|
||||
export const JOURNAL_DATE_FORMAT = 'YYYY-MM-DD';
|
||||
@@ -53,9 +32,7 @@ function toDayjs(j?: string | false) {
|
||||
/**
|
||||
* @deprecated use `JournalService` directly
|
||||
*/
|
||||
export const useJournalHelper = (docCollection: DocCollection) => {
|
||||
const bsWorkspaceHelper = useDocCollectionHelper(docCollection);
|
||||
const { resolvedTheme } = useTheme();
|
||||
export const useJournalHelper = () => {
|
||||
const { docsService, editorSettingService, journalService } = useServices({
|
||||
DocsService,
|
||||
EditorSettingService,
|
||||
@@ -69,17 +46,11 @@ export const useJournalHelper = (docCollection: DocCollection) => {
|
||||
(maybeDate: MaybeDate) => {
|
||||
const day = dayjs(maybeDate);
|
||||
const title = day.format(JOURNAL_DATE_FORMAT);
|
||||
const page = bsWorkspaceHelper.createDoc();
|
||||
const value = getValueByDefaultTheme(
|
||||
editorSettingService.editorSetting.settings$.value.edgelessDefaultTheme,
|
||||
resolvedTheme || 'light'
|
||||
);
|
||||
docsService.list
|
||||
.doc$(page.id)
|
||||
.value?.setProperty('edgelessColorTheme', value);
|
||||
docsService.list.setPrimaryMode(page.id, 'page');
|
||||
const docRecord = docsService.createDoc();
|
||||
const { doc, release } = docsService.open(docRecord.id);
|
||||
docsService.list.setPrimaryMode(docRecord.id, 'page');
|
||||
// set created date to match the journal date
|
||||
page.collection.setDocMeta(page.id, {
|
||||
docRecord.setMeta({
|
||||
createDate: dayjs()
|
||||
.set('year', day.year())
|
||||
.set('month', day.month())
|
||||
@@ -91,17 +62,12 @@ export const useJournalHelper = (docCollection: DocCollection) => {
|
||||
page: { title: new Text(title) },
|
||||
note: editorSettingService.editorSetting.get('affine:note'),
|
||||
};
|
||||
initDocFromProps(page, docProps);
|
||||
journalService.setJournalDate(page.id, title);
|
||||
return page;
|
||||
initDocFromProps(doc.blockSuiteDoc, docProps);
|
||||
release();
|
||||
journalService.setJournalDate(docRecord.id, title);
|
||||
return docRecord;
|
||||
},
|
||||
[
|
||||
bsWorkspaceHelper,
|
||||
editorSettingService.editorSetting,
|
||||
resolvedTheme,
|
||||
docsService.list,
|
||||
journalService,
|
||||
]
|
||||
[docsService, editorSettingService.editorSetting, journalService]
|
||||
);
|
||||
|
||||
/**
|
||||
@@ -138,8 +104,8 @@ export const useJournalHelper = (docCollection: DocCollection) => {
|
||||
};
|
||||
|
||||
// split useJournalRouteHelper since it requires a <Route /> context, which may not work in lit
|
||||
export const useJournalRouteHelper = (docCollection: DocCollection) => {
|
||||
const { getJournalByDate } = useJournalHelper(docCollection);
|
||||
export const useJournalRouteHelper = () => {
|
||||
const { getJournalByDate } = useJournalHelper();
|
||||
const workbench = useService(WorkbenchService).workbench;
|
||||
/**
|
||||
* open journal by date, create one if not exist
|
||||
|
||||
@@ -149,9 +149,7 @@ export const RootAppSidebar = (): ReactElement => {
|
||||
{t['com.affine.workspaceSubPath.all']()}
|
||||
</span>
|
||||
</MenuLinkItem>
|
||||
<AppSidebarJournalButton
|
||||
docCollection={currentWorkspace.docCollection}
|
||||
/>
|
||||
<AppSidebarJournalButton />
|
||||
<MenuItem
|
||||
data-testid="slider-bar-workspace-setting-button"
|
||||
icon={<SettingsIcon />}
|
||||
|
||||
@@ -8,23 +8,16 @@ import { DocDisplayMetaService } from '@affine/core/modules/doc-display-meta';
|
||||
import { WorkbenchService } from '@affine/core/modules/workbench';
|
||||
import { isNewTabTrigger } from '@affine/core/utils';
|
||||
import { useI18n } from '@affine/i18n';
|
||||
import type { DocCollection } from '@blocksuite/affine/store';
|
||||
import { TodayIcon } from '@blocksuite/icons/rc';
|
||||
import { useLiveData, useService } from '@toeverything/infra';
|
||||
import { type MouseEvent } from 'react';
|
||||
|
||||
interface AppSidebarJournalButtonProps {
|
||||
docCollection: DocCollection;
|
||||
}
|
||||
|
||||
export const AppSidebarJournalButton = ({
|
||||
docCollection,
|
||||
}: AppSidebarJournalButtonProps) => {
|
||||
export const AppSidebarJournalButton = () => {
|
||||
const t = useI18n();
|
||||
const docDisplayMetaService = useService(DocDisplayMetaService);
|
||||
const workbench = useService(WorkbenchService).workbench;
|
||||
const location = useLiveData(workbench.location$);
|
||||
const { openToday } = useJournalRouteHelper(docCollection);
|
||||
const { openToday } = useJournalRouteHelper();
|
||||
const maybeDocId = location.pathname.split('/')[1];
|
||||
const { isJournal } = useJournalInfoHelper(maybeDocId);
|
||||
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
import { AppThemeService, useService } from '@toeverything/infra';
|
||||
import { AppThemeService } from '@affine/core/modules/theme';
|
||||
import { useService } from '@toeverything/infra';
|
||||
import { ThemeProvider as NextThemeProvider, useTheme } from 'next-themes';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import { useEffect } from 'react';
|
||||
|
||||
const themes = ['dark', 'light'];
|
||||
|
||||
export function ThemeObserver() {
|
||||
function ThemeObserver() {
|
||||
const { resolvedTheme } = useTheme();
|
||||
const service = useService(AppThemeService);
|
||||
|
||||
@@ -67,14 +67,9 @@ export function JournalPageHeader({ page, workspace }: PageHeaderProps) {
|
||||
<ViewIcon icon="journal" />
|
||||
<EditorModeSwitch />
|
||||
<div className={styles.journalWeekPicker}>
|
||||
<JournalWeekDatePicker
|
||||
docCollection={workspace.docCollection}
|
||||
page={page}
|
||||
/>
|
||||
<JournalWeekDatePicker page={page} />
|
||||
</div>
|
||||
{hideToday ? null : (
|
||||
<JournalTodayButton docCollection={workspace.docCollection} />
|
||||
)}
|
||||
{hideToday ? null : <JournalTodayButton />}
|
||||
<HeaderDivider />
|
||||
<PageHeaderMenuButton
|
||||
isJournal
|
||||
|
||||
@@ -21,7 +21,6 @@ import {
|
||||
DocsService,
|
||||
useLiveData,
|
||||
useService,
|
||||
WorkspaceService,
|
||||
} from '@toeverything/infra';
|
||||
import { assignInlineVars } from '@vanilla-extract/dynamic';
|
||||
import clsx from 'clsx';
|
||||
@@ -100,12 +99,11 @@ const mobile = environment.isMobile;
|
||||
export const EditorJournalPanel = () => {
|
||||
const t = useI18n();
|
||||
const doc = useService(DocService).doc;
|
||||
const workspace = useService(WorkspaceService).workspace;
|
||||
const journalService = useService(JournalService);
|
||||
const journalDateStr = useLiveData(journalService.journalDate$(doc.id));
|
||||
const journalDate = journalDateStr ? dayjs(journalDateStr) : null;
|
||||
const isJournal = !!journalDate;
|
||||
const { openJournal } = useJournalRouteHelper(workspace.docCollection);
|
||||
const { openJournal } = useJournalRouteHelper();
|
||||
|
||||
const onDateSelect = useCallback(
|
||||
(date: string) => {
|
||||
|
||||
@@ -26,6 +26,7 @@ import { configureShareSettingModule } from './share-setting';
|
||||
import { configureSystemFontFamilyModule } from './system-font-family';
|
||||
import { configureTagModule } from './tag';
|
||||
import { configureTelemetryModule } from './telemetry';
|
||||
import { configureAppThemeModule } from './theme';
|
||||
import { configureThemeEditorModule } from './theme-editor';
|
||||
import { configureUrlModule } from './url';
|
||||
import { configureUserspaceModule } from './userspace';
|
||||
@@ -61,4 +62,5 @@ export function configureCommonModules(framework: Framework) {
|
||||
configureAppSidebarModule(framework);
|
||||
configureJournalModule(framework);
|
||||
configureUrlModule(framework);
|
||||
configureAppThemeModule(framework);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,5 @@
|
||||
import { Entity, LiveData } from '@toeverything/infra';
|
||||
|
||||
export class AppTheme extends Entity {
|
||||
theme$ = new LiveData<string | undefined>(undefined);
|
||||
}
|
||||
16
packages/frontend/core/src/modules/theme/index.ts
Normal file
16
packages/frontend/core/src/modules/theme/index.ts
Normal file
@@ -0,0 +1,16 @@
|
||||
export { AppThemeService } from './services/theme';
|
||||
|
||||
import { type Framework, WorkspaceScope } from '@toeverything/infra';
|
||||
|
||||
import { EditorSettingService } from '../editor-setting';
|
||||
import { AppTheme } from './entities/theme';
|
||||
import { EdgelessThemeService } from './services/edgeless-theme';
|
||||
import { AppThemeService } from './services/theme';
|
||||
|
||||
export function configureAppThemeModule(framework: Framework) {
|
||||
framework
|
||||
.service(AppThemeService)
|
||||
.entity(AppTheme)
|
||||
.scope(WorkspaceScope)
|
||||
.service(EdgelessThemeService, [AppThemeService, EditorSettingService]);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
import type { DocRecord } from '@toeverything/infra';
|
||||
import { DocCreated, OnEvent, Service } from '@toeverything/infra';
|
||||
|
||||
import type { EditorSettingService } from '../../editor-setting';
|
||||
import type { EdgelessDefaultTheme } from '../../editor-setting/schema';
|
||||
import type { AppThemeService } from './theme';
|
||||
|
||||
const getValueByDefaultTheme = (
|
||||
defaultTheme: EdgelessDefaultTheme,
|
||||
currentAppTheme: string
|
||||
) => {
|
||||
switch (defaultTheme) {
|
||||
case 'dark':
|
||||
return 'dark';
|
||||
case 'light':
|
||||
return 'light';
|
||||
case 'specified':
|
||||
return currentAppTheme === 'dark' ? 'dark' : 'light';
|
||||
case 'auto':
|
||||
return 'system';
|
||||
default:
|
||||
return 'system';
|
||||
}
|
||||
};
|
||||
|
||||
@OnEvent(DocCreated, i => i.onDocCreated)
|
||||
export class EdgelessThemeService extends Service {
|
||||
constructor(
|
||||
private readonly appThemeService: AppThemeService,
|
||||
private readonly editorSettingService: EditorSettingService
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
onDocCreated(docRecord: DocRecord) {
|
||||
const value = getValueByDefaultTheme(
|
||||
this.editorSettingService.editorSetting.get('edgelessDefaultTheme'),
|
||||
this.appThemeService.appTheme.theme$.value ?? 'light'
|
||||
);
|
||||
docRecord.setProperty('edgelessColorTheme', value);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
import { Service } from '@toeverything/infra';
|
||||
|
||||
import { AppTheme } from '../entities/theme';
|
||||
|
||||
export class AppThemeService extends Service {
|
||||
appTheme = this.framework.createEntity(AppTheme);
|
||||
}
|
||||
Reference in New Issue
Block a user