mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-09-07 01:09:54 +08:00
@@ -131,11 +131,13 @@ export const DocPropertyRow = ({
|
|||||||
typeInfo && 'value' in typeInfo ? typeInfo.value : undefined;
|
typeInfo && 'value' in typeInfo ? typeInfo.value : undefined;
|
||||||
|
|
||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(value: any) => {
|
(value: any, skipCommit?: boolean) => {
|
||||||
if (typeof value !== 'string') {
|
if (!skipCommit) {
|
||||||
throw new Error('only allow string value');
|
if (typeof value !== 'string') {
|
||||||
|
throw new Error('only allow string value');
|
||||||
|
}
|
||||||
|
docService.doc.record.setCustomProperty(propertyInfo.id, value);
|
||||||
}
|
}
|
||||||
docService.doc.record.setCustomProperty(propertyInfo.id, value);
|
|
||||||
onChange?.(value);
|
onChange?.(value);
|
||||||
},
|
},
|
||||||
[docService, onChange, propertyInfo]
|
[docService, onChange, propertyInfo]
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
import { TagService, useDeleteTagConfirmModal } from '@affine/core/modules/tag';
|
import { TagService, useDeleteTagConfirmModal } from '@affine/core/modules/tag';
|
||||||
import { useI18n } from '@affine/i18n';
|
import { useI18n } from '@affine/i18n';
|
||||||
import track from '@affine/track';
|
|
||||||
import { TagsIcon } from '@blocksuite/icons/rc';
|
import { TagsIcon } from '@blocksuite/icons/rc';
|
||||||
import {
|
import {
|
||||||
LiveData,
|
LiveData,
|
||||||
@@ -26,6 +25,7 @@ interface TagsEditorProps {
|
|||||||
interface TagsInlineEditorProps extends TagsEditorProps {
|
interface TagsInlineEditorProps extends TagsEditorProps {
|
||||||
placeholder?: string;
|
placeholder?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
|
onChange?: (value: unknown) => void;
|
||||||
}
|
}
|
||||||
|
|
||||||
export const TagsInlineEditor = ({
|
export const TagsInlineEditor = ({
|
||||||
@@ -33,19 +33,18 @@ export const TagsInlineEditor = ({
|
|||||||
readonly,
|
readonly,
|
||||||
placeholder,
|
placeholder,
|
||||||
className,
|
className,
|
||||||
|
onChange,
|
||||||
}: TagsInlineEditorProps) => {
|
}: TagsInlineEditorProps) => {
|
||||||
const workspace = useService(WorkspaceService);
|
const workspace = useService(WorkspaceService);
|
||||||
const tagService = useService(TagService);
|
const tagService = useService(TagService);
|
||||||
const tagIds = useLiveData(tagService.tagList.tagIdsByPageId$(pageId));
|
const tagIds$ = tagService.tagList.tagIdsByPageId$(pageId);
|
||||||
|
const tagIds = useLiveData(tagIds$);
|
||||||
const tags = useLiveData(tagService.tagList.tags$);
|
const tags = useLiveData(tagService.tagList.tags$);
|
||||||
const tagColors = tagService.tagColors;
|
const tagColors = tagService.tagColors;
|
||||||
|
|
||||||
const onCreateTag = useCallback(
|
const onCreateTag = useCallback(
|
||||||
(name: string, color: string) => {
|
(name: string, color: string) => {
|
||||||
const newTag = tagService.tagList.createTag(name, color);
|
const newTag = tagService.tagList.createTag(name, color);
|
||||||
track.doc.inlineDocInfo.property.editProperty({
|
|
||||||
type: 'tags',
|
|
||||||
});
|
|
||||||
return {
|
return {
|
||||||
id: newTag.id,
|
id: newTag.id,
|
||||||
value: newTag.value$.value,
|
value: newTag.value$.value,
|
||||||
@@ -58,21 +57,17 @@ export const TagsInlineEditor = ({
|
|||||||
const onSelectTag = useCallback(
|
const onSelectTag = useCallback(
|
||||||
(tagId: string) => {
|
(tagId: string) => {
|
||||||
tagService.tagList.tagByTagId$(tagId).value?.tag(pageId);
|
tagService.tagList.tagByTagId$(tagId).value?.tag(pageId);
|
||||||
track.doc.inlineDocInfo.property.editProperty({
|
onChange?.(tagIds$.value);
|
||||||
type: 'tags',
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[pageId, tagService.tagList]
|
[onChange, pageId, tagIds$, tagService.tagList]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onDeselectTag = useCallback(
|
const onDeselectTag = useCallback(
|
||||||
(tagId: string) => {
|
(tagId: string) => {
|
||||||
tagService.tagList.tagByTagId$(tagId).value?.untag(pageId);
|
tagService.tagList.tagByTagId$(tagId).value?.untag(pageId);
|
||||||
track.doc.inlineDocInfo.property.editProperty({
|
onChange?.(tagIds$.value);
|
||||||
type: 'tags',
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[pageId, tagService.tagList]
|
[onChange, pageId, tagIds$, tagService.tagList]
|
||||||
);
|
);
|
||||||
|
|
||||||
const onTagChange = useCallback(
|
const onTagChange = useCallback(
|
||||||
@@ -82,11 +77,9 @@ export const TagsInlineEditor = ({
|
|||||||
} else if (property === 'color') {
|
} else if (property === 'color') {
|
||||||
tagService.tagList.tagByTagId$(id).value?.changeColor(value);
|
tagService.tagList.tagByTagId$(id).value?.changeColor(value);
|
||||||
}
|
}
|
||||||
track.doc.inlineDocInfo.property.editProperty({
|
onChange?.(tagIds$.value);
|
||||||
type: 'tags',
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[tagService.tagList]
|
[onChange, tagIds$, tagService.tagList]
|
||||||
);
|
);
|
||||||
|
|
||||||
const deleteTags = useDeleteTagConfirmModal();
|
const deleteTags = useDeleteTagConfirmModal();
|
||||||
@@ -94,11 +87,9 @@ export const TagsInlineEditor = ({
|
|||||||
const onTagDelete = useAsyncCallback(
|
const onTagDelete = useAsyncCallback(
|
||||||
async (id: string) => {
|
async (id: string) => {
|
||||||
await deleteTags([id]);
|
await deleteTags([id]);
|
||||||
track.doc.inlineDocInfo.property.editProperty({
|
onChange?.(tagIds$.value);
|
||||||
type: 'tags',
|
|
||||||
});
|
|
||||||
},
|
},
|
||||||
[deleteTags]
|
[onChange, tagIds$, deleteTags]
|
||||||
);
|
);
|
||||||
|
|
||||||
const adaptedTags = useLiveData(
|
const adaptedTags = useLiveData(
|
||||||
|
|||||||
@@ -10,8 +10,9 @@ import { DocService, useLiveData, useService } from '@toeverything/infra';
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import * as styles from './doc-primary-mode.css';
|
import * as styles from './doc-primary-mode.css';
|
||||||
|
import type { PropertyValueProps } from './types';
|
||||||
|
|
||||||
export const DocPrimaryModeValue = () => {
|
export const DocPrimaryModeValue = ({ onChange }: PropertyValueProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const doc = useService(DocService).doc;
|
const doc = useService(DocService).doc;
|
||||||
|
|
||||||
@@ -44,8 +45,9 @@ export const DocPrimaryModeValue = () => {
|
|||||||
? t['com.affine.toastMessage.defaultMode.page.message']()
|
? t['com.affine.toastMessage.defaultMode.page.message']()
|
||||||
: t['com.affine.toastMessage.defaultMode.edgeless.message'](),
|
: t['com.affine.toastMessage.defaultMode.edgeless.message'](),
|
||||||
});
|
});
|
||||||
|
onChange?.(mode, true);
|
||||||
},
|
},
|
||||||
[doc, t]
|
[doc, t, onChange]
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<PropertyValue className={styles.container} hoverable={false}>
|
<PropertyValue className={styles.container} hoverable={false}>
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import { DocService, useLiveData, useService } from '@toeverything/infra';
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import * as styles from './edgeless-theme.css';
|
import * as styles from './edgeless-theme.css';
|
||||||
|
import type { PropertyValueProps } from './types';
|
||||||
|
|
||||||
const getThemeOptions = (t: ReturnType<typeof useI18n>) =>
|
const getThemeOptions = (t: ReturnType<typeof useI18n>) =>
|
||||||
[
|
[
|
||||||
@@ -21,7 +22,7 @@ const getThemeOptions = (t: ReturnType<typeof useI18n>) =>
|
|||||||
},
|
},
|
||||||
] satisfies RadioItem[];
|
] satisfies RadioItem[];
|
||||||
|
|
||||||
export const EdgelessThemeValue = () => {
|
export const EdgelessThemeValue = ({ onChange }: PropertyValueProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const doc = useService(DocService).doc;
|
const doc = useService(DocService).doc;
|
||||||
const edgelessTheme = useLiveData(doc.properties$).edgelessColorTheme;
|
const edgelessTheme = useLiveData(doc.properties$).edgelessColorTheme;
|
||||||
@@ -29,8 +30,9 @@ export const EdgelessThemeValue = () => {
|
|||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(theme: string) => {
|
(theme: string) => {
|
||||||
doc.record.setProperty('edgelessColorTheme', theme);
|
doc.record.setProperty('edgelessColorTheme', theme);
|
||||||
|
onChange?.(theme, true);
|
||||||
},
|
},
|
||||||
[doc]
|
[doc, onChange]
|
||||||
);
|
);
|
||||||
const themeItems = useMemo<RadioItem[]>(() => getThemeOptions(t), [t]);
|
const themeItems = useMemo<RadioItem[]>(() => getThemeOptions(t), [t]);
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,9 @@ import dayjs from 'dayjs';
|
|||||||
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
||||||
|
|
||||||
import * as styles from './journal.css';
|
import * as styles from './journal.css';
|
||||||
|
import type { PropertyValueProps } from './types';
|
||||||
|
|
||||||
export const JournalValue = () => {
|
export const JournalValue = ({ onChange }: PropertyValueProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
const journalService = useService(JournalService);
|
const journalService = useService(JournalService);
|
||||||
@@ -50,8 +51,9 @@ export const JournalValue = () => {
|
|||||||
const date = dayjs(day).format('YYYY-MM-DD');
|
const date = dayjs(day).format('YYYY-MM-DD');
|
||||||
setSelectedDate(date);
|
setSelectedDate(date);
|
||||||
journalService.setJournalDate(doc.id, date);
|
journalService.setJournalDate(doc.id, date);
|
||||||
|
onChange?.(date, true);
|
||||||
},
|
},
|
||||||
[journalService, doc.id]
|
[journalService, doc.id, onChange]
|
||||||
);
|
);
|
||||||
|
|
||||||
const handleCheck = useCallback(
|
const handleCheck = useCallback(
|
||||||
@@ -59,11 +61,12 @@ export const JournalValue = () => {
|
|||||||
if (!v) {
|
if (!v) {
|
||||||
journalService.removeJournalDate(doc.id);
|
journalService.removeJournalDate(doc.id);
|
||||||
setShowDatePicker(false);
|
setShowDatePicker(false);
|
||||||
|
onChange?.(null, true);
|
||||||
} else {
|
} else {
|
||||||
handleDateSelect(selectedDate);
|
handleDateSelect(selectedDate);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[handleDateSelect, journalService, doc.id, selectedDate]
|
[onChange, journalService, doc.id, handleDateSelect, selectedDate]
|
||||||
);
|
);
|
||||||
|
|
||||||
const workbench = useService(WorkbenchService).workbench;
|
const workbench = useService(WorkbenchService).workbench;
|
||||||
@@ -101,11 +104,7 @@ export const JournalValue = () => {
|
|||||||
onClick={toggle}
|
onClick={toggle}
|
||||||
>
|
>
|
||||||
<div className={styles.root}>
|
<div className={styles.root}>
|
||||||
<Checkbox
|
<Checkbox className={styles.checkbox} checked={checked} />
|
||||||
className={styles.checkbox}
|
|
||||||
checked={checked}
|
|
||||||
onChange={handleCheck}
|
|
||||||
/>
|
|
||||||
{checked ? (
|
{checked ? (
|
||||||
<Menu
|
<Menu
|
||||||
contentOptions={{
|
contentOptions={{
|
||||||
|
|||||||
@@ -5,9 +5,9 @@ import { DocService, useLiveData, useService } from '@toeverything/infra';
|
|||||||
import { useCallback, useMemo } from 'react';
|
import { useCallback, useMemo } from 'react';
|
||||||
|
|
||||||
import { container } from './page-width.css';
|
import { container } from './page-width.css';
|
||||||
import type { PageLayoutMode } from './types';
|
import type { PageLayoutMode, PropertyValueProps } from './types';
|
||||||
|
|
||||||
export const PageWidthValue = () => {
|
export const PageWidthValue = ({ onChange }: PropertyValueProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
const editorSetting = useService(EditorSettingService).editorSetting;
|
const editorSetting = useService(EditorSettingService).editorSetting;
|
||||||
const defaultPageWidth = useLiveData(editorSetting.settings$).fullWidthLayout;
|
const defaultPageWidth = useLiveData(editorSetting.settings$).fullWidthLayout;
|
||||||
@@ -44,8 +44,9 @@ export const PageWidthValue = () => {
|
|||||||
const handleChange = useCallback(
|
const handleChange = useCallback(
|
||||||
(value: PageLayoutMode) => {
|
(value: PageLayoutMode) => {
|
||||||
doc.record.setProperty('pageWidth', value);
|
doc.record.setProperty('pageWidth', value);
|
||||||
|
onChange?.(value, true);
|
||||||
},
|
},
|
||||||
[doc]
|
[doc, onChange]
|
||||||
);
|
);
|
||||||
return (
|
return (
|
||||||
<PropertyValue className={container} hoverable={false}>
|
<PropertyValue className={container} hoverable={false}>
|
||||||
|
|||||||
@@ -5,8 +5,9 @@ import { DocService, useLiveData, useService } from '@toeverything/infra';
|
|||||||
|
|
||||||
import { TagsInlineEditor } from '../tags-inline-editor';
|
import { TagsInlineEditor } from '../tags-inline-editor';
|
||||||
import * as styles from './tags.css';
|
import * as styles from './tags.css';
|
||||||
|
import type { PropertyValueProps } from './types';
|
||||||
|
|
||||||
export const TagsValue = () => {
|
export const TagsValue = ({ onChange }: PropertyValueProps) => {
|
||||||
const t = useI18n();
|
const t = useI18n();
|
||||||
|
|
||||||
const doc = useService(DocService).doc;
|
const doc = useService(DocService).doc;
|
||||||
@@ -27,6 +28,7 @@ export const TagsValue = () => {
|
|||||||
'com.affine.page-properties.property-value-placeholder'
|
'com.affine.page-properties.property-value-placeholder'
|
||||||
]()}
|
]()}
|
||||||
pageId={doc.id}
|
pageId={doc.id}
|
||||||
|
onChange={value => onChange(value, true)}
|
||||||
/>
|
/>
|
||||||
</PropertyValue>
|
</PropertyValue>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -69,7 +69,6 @@ export const textInvisible = style({
|
|||||||
visibility: 'hidden',
|
visibility: 'hidden',
|
||||||
fontSize: cssVar('fontSm'),
|
fontSize: cssVar('fontSm'),
|
||||||
lineHeight: '22px',
|
lineHeight: '22px',
|
||||||
padding: `6px`,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const mobileTextInvisible = style([textInvisible, mobileTextareaBase]);
|
export const mobileTextInvisible = style([textInvisible, mobileTextareaBase]);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ import type { DocCustomPropertyInfo } from '@toeverything/infra';
|
|||||||
export interface PropertyValueProps {
|
export interface PropertyValueProps {
|
||||||
propertyInfo?: DocCustomPropertyInfo;
|
propertyInfo?: DocCustomPropertyInfo;
|
||||||
value: any;
|
value: any;
|
||||||
onChange: (value: any) => void;
|
onChange: (value: any, skipCommit?: boolean) => void; // if skipCommit is true, the change will be handled in the component itself
|
||||||
}
|
}
|
||||||
|
|
||||||
export type PageLayoutMode = 'standard' | 'fullWidth';
|
export type PageLayoutMode = 'standard' | 'fullWidth';
|
||||||
|
|||||||
@@ -72,6 +72,15 @@ export const InfoTable = ({
|
|||||||
});
|
});
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
|
const onPropertyChange = useCallback(
|
||||||
|
(property: DocCustomPropertyInfo, _value: unknown) => {
|
||||||
|
track.$.docInfoPanel.property.editProperty({
|
||||||
|
type: property.type,
|
||||||
|
});
|
||||||
|
},
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{backlinks && backlinks.length > 0 ? (
|
{backlinks && backlinks.length > 0 ? (
|
||||||
@@ -122,6 +131,7 @@ export const InfoTable = ({
|
|||||||
key={property.id}
|
key={property.id}
|
||||||
propertyInfo={property}
|
propertyInfo={property}
|
||||||
defaultOpenEditMenu={newPropertyId === property.id}
|
defaultOpenEditMenu={newPropertyId === property.id}
|
||||||
|
onChange={value => onPropertyChange(property, value)}
|
||||||
/>
|
/>
|
||||||
))}
|
))}
|
||||||
<Menu
|
<Menu
|
||||||
|
|||||||
Reference in New Issue
Block a user