feat: add editor to article header

This commit is contained in:
DarkSky
2024-08-21 17:14:19 +08:00
parent 0417c70d54
commit 35ef9af264
7 changed files with 126 additions and 5 deletions
@@ -1,6 +1,38 @@
import { createContext } from 'react';
import { useQuery } from '@affine/core/hooks/use-query';
import type { PagePropertyType } from '@affine/core/modules/properties/services/schema';
import { WorkspaceFlavour } from '@affine/env/workspace';
import { getWorkspacePageMetaByIdQuery } from '@affine/graphql';
import { createContext, useContext } from 'react';
import type { Middleware } from 'swr';
import type { PagePropertiesManager } from './page-properties-manager';
// @ts-expect-error this should always be set
export const managerContext = createContext<PagePropertiesManager>();
export const useCloudPageMeta = (type: PagePropertyType) => {
const manager = useContext(managerContext);
const isCloud = manager.workspace.flavour === WorkspaceFlavour.AFFINE_CLOUD;
const { data, error, isLoading } = useQuery({
query: getWorkspacePageMetaByIdQuery,
variables: {
id: manager.workspace.id,
pageId: manager.pageId,
},
});
if (!!error || !data?.workspace?.pageMeta) return { isCloud, isLoading };
const pageMeta = data.workspace.pageMeta;
return {
isCloud,
isLoading,
metadata: pageMeta[type as keyof typeof pageMeta],
};
};
export const SWRCustomHandler: Middleware =
next => (key, fetcher: any, config: any) => {
const wrappedFetcher = (...args: any[]) =>
fetcher?.(...args).catch(() => null);
return next(key, wrappedFetcher, config);
};
@@ -109,6 +109,10 @@ export const getDefaultIconName = (
return 'checkBoxCheckLinear';
case 'number':
return 'number';
case 'createdBy':
return 'account';
case 'updatedBy':
return 'account';
default:
return 'text';
}
@@ -35,6 +35,8 @@ export const newPropertyTypes: PagePropertyType[] = [
PagePropertyType.Number,
PagePropertyType.Checkbox,
PagePropertyType.Date,
PagePropertyType.CreatedBy,
PagePropertyType.UpdatedBy,
// TODO(@Peng): add more
];
@@ -1,16 +1,25 @@
import { Checkbox, DatePicker, Menu } from '@affine/component';
import { Avatar, Checkbox, DatePicker, Menu } from '@affine/component';
import { AuthService } from '@affine/core/modules/cloud';
import type {
PageInfoCustomProperty,
PageInfoCustomPropertyMeta,
PagePropertyType,
} from '@affine/core/modules/properties/services/schema';
import { i18nTime, useI18n } from '@affine/i18n';
import { DocService, useService } from '@toeverything/infra';
import { DocService, useLiveData, useService } from '@toeverything/infra';
import { noop } from 'lodash-es';
import type { ChangeEventHandler } from 'react';
import { useCallback, useContext, useEffect, useRef, useState } from 'react';
import {
useCallback,
useContext,
useEffect,
useMemo,
useRef,
useState,
} from 'react';
import { SWRConfig } from 'swr';
import { managerContext } from './common';
import { managerContext, SWRCustomHandler, useCloudPageMeta } from './common';
import * as styles from './styles.css';
import { TagsInlineEditor } from './tags-inline-editor';
@@ -190,6 +199,63 @@ export const TagsValue = () => {
);
};
const CloudUserAvatar = (props: { type: PagePropertyType }) => {
const session = useService(AuthService).session;
const account = useLiveData(session.account$);
const { isCloud, isLoading, metadata } = useCloudPageMeta(props.type);
const user = useMemo(() => {
if (isCloud) {
if (!metadata || typeof metadata !== 'object') return null;
return metadata;
} else {
if (!account) return null;
return { name: account.label, avatarUrl: account.avatar };
}
}, [account, isCloud, metadata]);
const t = useI18n();
if (isLoading) return null;
if (isCloud) {
if (user) {
return (
<>
<Avatar url={user.avatarUrl || ''} name={user.name} size={20} />
<span>{user.name}</span>
</>
);
}
return (
<>
<Avatar name="?" size={20} />
<span>
{t['com.affine.page-properties.property-user-avatar-no-record']()}
</span>
</>
);
}
if (account) {
return (
<>
<Avatar url={account.avatar || ''} name={account.label} size={20} />
<span>{account.label}</span>
</>
);
}
return null;
};
export const UserValue = ({ meta }: PropertyRowValueProps) => {
return (
<div className={styles.propertyRowValueUserCell}>
<SWRConfig value={parent => ({ ...parent, use: [SWRCustomHandler] })}>
<CloudUserAvatar type={meta.type} />
</SWRConfig>
</div>
);
};
export const propertyValueRenderers: Record<
PagePropertyType,
typeof DateValue
@@ -198,6 +264,8 @@ export const propertyValueRenderers: Record<
checkbox: CheckboxValue,
text: TextValue,
number: NumberValue,
createdBy: UserValue,
updatedBy: UserValue,
// TODO(@Peng): fix following
tags: TagsValue,
progress: TextValue,
@@ -349,6 +349,16 @@ export const propertyRowValueTextCell = style([
},
]);
export const propertyRowValueUserCell = style([
propertyRowValueCell,
{
border: 'none',
height: '100%',
overflow: 'hidden',
columnGap: '0.5rem',
},
]);
export const propertyRowValueTextarea = style([
propertyRowValueCell,
{
@@ -21,6 +21,8 @@ export enum PagePropertyType {
Progress = 'progress',
Checkbox = 'checkbox',
Tags = 'tags',
CreatedBy = 'createdBy',
UpdatedBy = 'updatedBy',
}
export const PagePropertyMetaBaseSchema = z.object({
@@ -856,6 +856,7 @@
"com.affine.page-properties.page-info": "Info",
"com.affine.page-properties.page-info.view": "View Info",
"com.affine.page-properties.property-value-placeholder": "Empty",
"com.affine.page-properties.property-user-avatar-no-record": "No Record",
"com.affine.page-properties.property.always-hide": "Always hide",
"com.affine.page-properties.property.always-show": "Always show",
"com.affine.page-properties.property.checkbox": "Checkbox",
@@ -870,6 +871,8 @@
"com.affine.page-properties.property.show-in-view": "Show in view",
"com.affine.page-properties.property.tags": "Tags",
"com.affine.page-properties.property.text": "Text",
"com.affine.page-properties.property.createdBy": "Created by",
"com.affine.page-properties.property.updatedBy": "Updated by",
"com.affine.page-properties.settings.title": "customize properties",
"com.affine.page-properties.tags.open-tags-page": "Open tag page",
"com.affine.page-properties.tags.selector-header-title": "Select tag or create one",