Skip to content

Commit

Permalink
feat(core): emoji as doc icon support with feature flag
Browse files Browse the repository at this point in the history
  • Loading branch information
CatsJuice committed Sep 24, 2024
1 parent d0f04d2 commit 978d671
Show file tree
Hide file tree
Showing 6 changed files with 96 additions and 21 deletions.
11 changes: 11 additions & 0 deletions packages/common/infra/src/modules/feature-flag/constant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,17 @@ export const AFFINE_FLAGS = {
configurable: true,
defaultState: true,
},
enable_emoji_doc_icon: {
category: 'affine',
displayName: 'Emoji Doc Icon',
description:
'Once enabled, you can use an emoji as the page icon. When the first character of the folder name is an emoji, it will be extracted and used as its icon.',
feedbackType: 'discord',
feedbackLink:
'https://discord.com/channels/959027316334407691/1280014319865696351',
configurable: true,
defaultState: true,
},
enable_editor_settings: {
category: 'affine',
displayName: 'Editor Settings',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,9 @@ export function AffinePageReference({
referenceToNode: linkToNode,
})
);
const title = useLiveData(docDisplayMetaService.title$(pageId));
const title = useLiveData(
docDisplayMetaService.title$(pageId, { reference: true })
);

const el = (
<>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,9 @@ export function createLinkedWidgetConfig(
return !meta.trash;
})
.map(meta => {
const title = docDisplayMetaService.title$(meta.id).value;
const title = docDisplayMetaService.title$(meta.id, {
reference: true,
}).value;
return {
...meta,
title: typeof title === 'string' ? title : I18n[title.key](),
Expand Down
7 changes: 6 additions & 1 deletion packages/frontend/core/src/modules/doc-display-meta/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
DocsService,
FeatureFlagService,
type Framework,
WorkspaceScope,
} from '@toeverything/infra';
Expand All @@ -12,5 +13,9 @@ export { DocDisplayMetaService };
export function configureDocDisplayMetaModule(framework: Framework) {
framework
.scope(WorkspaceScope)
.service(DocDisplayMetaService, [WorkspacePropertiesAdapter, DocsService]);
.service(DocDisplayMetaService, [
WorkspacePropertiesAdapter,
DocsService,
FeatureFlagService,
]);
}
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
import { extractEmojiIcon } from '@affine/core/utils';
import { i18nTime } from '@affine/i18n';
import {
BlockLinkIcon as LitBlockLinkIcon,
Expand All @@ -19,7 +20,11 @@ import {
TomorrowIcon,
YesterdayIcon,
} from '@blocksuite/icons/rc';
import type { DocRecord, DocsService } from '@toeverything/infra';
import type {
DocRecord,
DocsService,
FeatureFlagService,
} from '@toeverything/infra';
import { LiveData, Service } from '@toeverything/infra';
import type { Dayjs } from 'dayjs';
import dayjs from 'dayjs';
Expand All @@ -37,6 +42,18 @@ interface DocDisplayIconOptions<T extends IconType> {
mode?: 'edgeless' | 'page';
reference?: boolean;
referenceToNode?: boolean;
/**
* @default true
*/
enableEmojiIcon?: boolean;
}
interface DocDisplayTitleOptions {
originalTitle?: string;
reference?: boolean;
/**
* @default true
*/
enableEmojiIcon?: boolean;
}

const rcIcons = {
Expand Down Expand Up @@ -67,7 +84,8 @@ const icons = { rc: rcIcons, lit: litIcons } as {
export class DocDisplayMetaService extends Service {
constructor(
private readonly propertiesAdapter: WorkspacePropertiesAdapter,
private readonly docsService: DocsService
private readonly docsService: DocsService,
private readonly featureFlagService: FeatureFlagService
) {
super();
}
Expand All @@ -80,6 +98,7 @@ export class DocDisplayMetaService extends Service {

return LiveData.computed(get => {
const doc = get(this.docsService.list.doc$(docId));
const title = doc ? get(doc.title$) : '';
const mode = doc ? get(doc.primaryMode$) : undefined;
const finalMode = options?.mode ?? mode ?? 'page';
const referenceToNode = !!(options?.reference && options.referenceToNode);
Expand All @@ -89,10 +108,10 @@ export class DocDisplayMetaService extends Service {
return iconSet.BlockLinkIcon;
}

// journal icon
const journalDate = this._toDayjs(
this.propertiesAdapter.getJournalPageDateString(docId)
);

if (journalDate) {
if (!options?.compareDate) return iconSet.TodayIcon;
const compareDate = dayjs(options?.compareDate);
Expand All @@ -103,36 +122,65 @@ export class DocDisplayMetaService extends Service {
: iconSet.TodayIcon;
}

return options?.reference
? finalMode === 'edgeless'
// reference icon
if (options?.reference) {
return finalMode === 'edgeless'
? iconSet.LinkedEdgelessIcon
: iconSet.LinkedPageIcon
: finalMode === 'edgeless'
? iconSet.EdgelessIcon
: iconSet.PageIcon;
: iconSet.LinkedPageIcon;
}

// emoji icon
const enableEmojiIcon =
get(this.featureFlagService.flags.enable_emoji_doc_icon.$) &&
options?.enableEmojiIcon !== false;
if (enableEmojiIcon) {
const { emoji } = extractEmojiIcon(title);
if (emoji) return () => emoji;
}

// default icon
return finalMode === 'edgeless' ? iconSet.EdgelessIcon : iconSet.PageIcon;
});
}

title$(docId: string, originalTitle?: string) {
title$(docId: string, options?: DocDisplayTitleOptions) {
return LiveData.computed(get => {
const doc = get(this.docsService.list.doc$(docId));
const docTitle = doc ? get(doc.title$) : undefined;

const journalDateString =
this.propertiesAdapter.getJournalPageDateString(docId);
return journalDateString
? i18nTime(journalDateString, { absolute: { accuracy: 'day' } })
: originalTitle ||
docTitle ||
({
key: 'Untitled',
} as const);

// journal
if (journalDateString) {
return i18nTime(journalDateString, { absolute: { accuracy: 'day' } });
}

if (options?.originalTitle) return options.originalTitle;

// empty title
if (!docTitle) return { key: 'Untitled' } as const;

// reference
if (options?.reference) return docTitle;

// check emoji
const enableEmojiIcon =
get(this.featureFlagService.flags.enable_emoji_doc_icon.$) &&
options?.enableEmojiIcon !== false;
if (enableEmojiIcon) {
const { rest } = extractEmojiIcon(docTitle);
return rest;
}

// default
return docTitle;
});
}

getDocDisplayMeta(docRecord: DocRecord, originalTitle?: string) {
return {
title: this.title$(docRecord.id, originalTitle).value,
title: this.title$(docRecord.id, { originalTitle }).value,
icon: this.icon$(docRecord.id).value,
updatedDate: docRecord.meta$.value.updatedDate,
};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { useI18n } from '@affine/i18n';
import { track } from '@affine/track';
import {
DocsService,
FeatureFlagService,
GlobalContextService,
LiveData,
useLiveData,
Expand Down Expand Up @@ -47,11 +48,13 @@ export const ExplorerDocNode = ({
docsService,
globalContextService,
docDisplayMetaService,
featureFlagService,
} = useServices({
DocsSearchService,
DocsService,
GlobalContextService,
DocDisplayMetaService,
FeatureFlagService,
});
// const pageInfoAdapter = useCurrentWorkspacePropertiesAdapter();

Expand All @@ -67,6 +70,9 @@ export const ExplorerDocNode = ({
);
const docTitle = useLiveData(docDisplayMetaService.title$(docId));
const isInTrash = useLiveData(docRecord?.trash$);
const enableEmojiIcon = useLiveData(
featureFlagService.flags.enable_emoji_doc_icon.$
);

const Icon = useCallback(
({ className }: { className?: string }) => {
Expand Down Expand Up @@ -206,6 +212,7 @@ export const ExplorerDocNode = ({
dndData={dndData}
onDrop={handleDropOnDoc}
renameable
extractEmojiAsIcon={enableEmojiIcon}
collapsed={collapsed}
setCollapsed={setCollapsed}
canDrop={handleCanDrop}
Expand Down

0 comments on commit 978d671

Please sign in to comment.