fix(core): adjust new doc list filter style (#12629)

close AF-2678, AF-2677, AF-2674, AF-2655

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
  - Added customizable spacing for dividers.
  - Introduced a flexible filter value menu for easier filter editing.
- Added options to control visibility of creation actions in empty
document views.

- **Improvements**
- Enhanced menu components for filter values with a more declarative and
simplified interface.
  - Improved vertical alignment in some UI containers.
  - Updated divider spacing for more consistent UI appearance.

- **Bug Fixes**
  - Menu popups for filters now appear in correct positions.

- **Removals**
- Removed support for the "zotero" integration type from integration
settings and filters.

- **Style**
  - Updated CSS for better menu positioning and alignment.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
Cats Juice 2025-06-23 18:34:00 +08:00 committed by GitHub
parent 24b205ae83
commit ea92e2291d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
27 changed files with 197 additions and 238 deletions

View File

@ -1,3 +1,4 @@
import { assignInlineVars } from '@vanilla-extract/dynamic';
import clsx from 'clsx';
import type { HTMLAttributes, PropsWithChildren } from 'react';
import { forwardRef } from 'react';
@ -8,6 +9,7 @@ export type DividerProps = PropsWithChildren &
Omit<HTMLAttributes<HTMLDivElement>, 'type'> & {
orientation?: DividerOrientation;
size?: 'thinner' | 'default';
space?: number;
dividerColor?: string;
};
@ -16,6 +18,7 @@ export const Divider = forwardRef<HTMLDivElement, DividerProps>(
{
orientation = 'horizontal',
size = 'default',
space: propSpace,
dividerColor,
style,
className,
@ -23,6 +26,8 @@ export const Divider = forwardRef<HTMLDivElement, DividerProps>(
},
ref
) => {
const space = propSpace ?? (orientation === 'horizontal' ? 8 : 2);
return (
<div
data-divider
@ -38,6 +43,7 @@ export const Divider = forwardRef<HTMLDivElement, DividerProps>(
style={{
borderColor: dividerColor ? dividerColor : undefined,
...style,
...assignInlineVars({ [styles.dividerSpace]: `${space}px` }),
}}
{...otherProps}
/>

View File

@ -1,9 +1,15 @@
import { cssVar } from '@toeverything/theme';
import { style } from '@vanilla-extract/css';
import { createVar, style } from '@vanilla-extract/css';
export const dividerSpace = createVar('dividerSpace');
export const divider = style({
vars: {
[dividerSpace]: '8px',
},
borderBottom: `1px solid ${cssVar('borderColor')}`,
height: 0,
margin: '8px 0',
margin: `${dividerSpace} 0`,
width: '100%',
});
@ -11,7 +17,7 @@ export const verticalDivider = style({
borderLeft: `1px solid ${cssVar('borderColor')}`,
width: 0,
height: '100%',
margin: '0 2px',
margin: `0 ${dividerSpace}`,
});
export const thinner = style({

View File

@ -19,11 +19,13 @@ export interface EmptyDocsProps extends UniversalEmptyProps {
* Used for "New doc", if provided, new doc will be created with this tag.
*/
tagId?: string;
allowCreate?: boolean;
}
export const EmptyDocs = ({
type = 'all',
tagId,
allowCreate = true,
...props
}: EmptyDocsProps) => {
const t = useI18n();
@ -56,7 +58,7 @@ export const EmptyDocs = ({
: t['com.affine.empty.docs.all-description']()
}
action={
showActionButton ? (
allowCreate && showActionButton ? (
<ActionButton onClick={onCreate} prefix={<AllDocsIcon />}>
{t['com.affine.empty.docs.action.new-doc']()}
</ActionButton>

View File

@ -81,12 +81,13 @@ const ExplorerDisplayMenu = ({
</span>
</div>
</MenuSub>
<Divider size="thinner" />
<Divider space={4} size="thinner" />
<DisplayProperties
displayPreference={displayPreference}
onDisplayPreferenceChange={onDisplayPreferenceChange}
/>
<Divider size="thinner" />
<Divider space={4} size="thinner" />
<QuickActionsConfig
displayPreference={displayPreference}
onDisplayPreferenceChange={onDisplayPreferenceChange}

View File

@ -102,26 +102,30 @@ export const DisplayProperties = ({
);
})}
</div>
<Divider size="thinner" />
<section className={styles.sectionLabel}>
{t['com.affine.all-docs.display.list-view']()}
</section>
<div className={styles.properties}>
<Button
className={styles.property}
data-show={showIcon}
onClick={toggleIcon}
>
{t['com.affine.all-docs.display.list-view.icon']()}
</Button>
<Button
className={styles.property}
data-show={showBody}
onClick={toggleBody}
>
{t['com.affine.all-docs.display.list-view.body']()}
</Button>
</div>
{displayPreference.view === 'list' ? (
<>
<Divider space={4} size="thinner" />
<section className={styles.sectionLabel}>
{t['com.affine.all-docs.display.list-view']()}
</section>
<div className={styles.properties}>
<Button
className={styles.property}
data-show={showIcon}
onClick={toggleIcon}
>
{t['com.affine.all-docs.display.list-view.icon']()}
</Button>
<Button
className={styles.property}
data-show={showBody}
onClick={toggleBody}
>
{t['com.affine.all-docs.display.list-view.body']()}
</Button>
</div>
</>
) : null}
</div>
);
};

View File

@ -11,6 +11,7 @@ import { useLiveData, useService } from '@toeverything/infra';
import { cssVarV2 } from '@toeverything/theme/v2';
import { memo, useCallback, useContext, useEffect, useMemo } from 'react';
import { EmptyDocs } from '../../affine/empty';
import { ListFloatingToolbar } from '../../page-list/components/list-floating-toolbar';
import { SystemPropertyTypes } from '../../system-property-types';
import { WorkspacePropertyTypes } from '../../workspace-property-types';
@ -228,6 +229,12 @@ export const DocsExplorer = ({
[]
);
const isEmpty = masonryItems.length === 0;
if (isEmpty) {
return <EmptyDocs allowCreate={false} style={{ height: '100%' }} />;
}
return (
<>
<Masonry

View File

@ -0,0 +1,33 @@
import { Menu, type MenuProps, type MenuRef } from '@affine/component';
import { useEffect, useRef } from 'react';
export const FilterValueMenu = ({
isDraft,
rootOptions,
contentOptions,
onDraftCompleted,
...otherProps
}: { isDraft?: boolean; onDraftCompleted?: () => void } & MenuProps) => {
const menuRef = useRef<MenuRef>(null);
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
return (
<Menu
ref={menuRef}
rootOptions={{
onClose: onDraftCompleted,
...rootOptions,
}}
contentOptions={{
alignOffset: -4,
...contentOptions,
}}
{...otherProps}
/>
);
};

View File

@ -1,6 +1,7 @@
import { Menu, MenuItem, type MenuRef } from '@affine/component';
import { MenuItem } from '@affine/component';
import type { FilterParams } from '@affine/core/modules/collection-rules';
import { useEffect, useRef } from 'react';
import { FilterValueMenu } from '../filter/filter-value-menu';
export const FavoriteFilterValue = ({
filter,
@ -13,20 +14,10 @@ export const FavoriteFilterValue = ({
onDraftCompleted?: () => void;
onChange?: (filter: FilterParams) => void;
}) => {
const menuRef = useRef<MenuRef>(null);
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
return (
<Menu
ref={menuRef}
rootOptions={{
onClose: onDraftCompleted,
}}
<FilterValueMenu
isDraft={isDraft}
onDraftCompleted={onDraftCompleted}
items={
<>
<MenuItem
@ -55,6 +46,6 @@ export const FavoriteFilterValue = ({
}
>
<span>{filter.value === 'true' ? 'True' : 'False'}</span>
</Menu>
</FilterValueMenu>
);
};

View File

@ -1,14 +1,17 @@
import { Menu, MenuItem, type MenuRef } from '@affine/component';
import { MenuItem } from '@affine/component';
import type { FilterParams } from '@affine/core/modules/collection-rules';
import type { DocRecord } from '@affine/core/modules/doc';
import { IntegrationTypeIcon } from '@affine/core/modules/integration';
import { INTEGRATION_TYPE_NAME_MAP } from '@affine/core/modules/integration/constant';
import type { IntegrationType } from '@affine/core/modules/integration/type';
import { useI18n } from '@affine/i18n';
import { IntegrationsIcon, ReadwiseIcon } from '@blocksuite/icons/rc';
import { useLiveData } from '@toeverything/infra';
import { useEffect, useRef } from 'react';
import { PlainTextDocGroupHeader } from '../explorer/docs-view/group-header';
import { StackProperty } from '../explorer/docs-view/stack-property';
import type { GroupHeaderProps } from '../explorer/types';
import { FilterValueMenu } from '../filter/filter-value-menu';
export const IntegrationTypeFilterValue = ({
filter,
@ -22,41 +25,37 @@ export const IntegrationTypeFilterValue = ({
onChange?: (filter: FilterParams) => void;
}) => {
const t = useI18n();
const menuRef = useRef<MenuRef>(null);
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
return (
<Menu
ref={menuRef}
rootOptions={{
onClose: onDraftCompleted,
}}
items={
<MenuItem
onClick={() => {
onChange?.({
...filter,
value: 'readwise',
});
}}
prefixIcon={<ReadwiseIcon />}
selected={filter.value === 'readwise'}
>
{t['com.affine.integration.readwise.name']()}
</MenuItem>
}
<FilterValueMenu
isDraft={isDraft}
onDraftCompleted={onDraftCompleted}
items={Object.entries(INTEGRATION_TYPE_NAME_MAP).map(entries => {
const type = entries[0] as IntegrationType;
const i18nKey = entries[1];
return (
<MenuItem
key={type}
onClick={() => {
onChange?.({
...filter,
value: type,
});
}}
prefixIcon={<IntegrationTypeIcon type={type} />}
selected={filter.value === type}
>
{t.t(i18nKey)}
</MenuItem>
);
})}
>
<span>
{filter.value === 'readwise'
? t['com.affine.integration.readwise.name']()
{INTEGRATION_TYPE_NAME_MAP[filter.value as IntegrationType]
? t.t(INTEGRATION_TYPE_NAME_MAP[filter.value as IntegrationType])
: filter.value}
</span>
</Menu>
</FilterValueMenu>
);
};

View File

@ -1,6 +1,7 @@
import { Menu, MenuItem, type MenuRef } from '@affine/component';
import { MenuItem } from '@affine/component';
import type { FilterParams } from '@affine/core/modules/collection-rules';
import { useEffect, useRef } from 'react';
import { FilterValueMenu } from '../filter/filter-value-menu';
export const SharedFilterValue = ({
filter,
@ -13,20 +14,10 @@ export const SharedFilterValue = ({
onDraftCompleted?: () => void;
onChange?: (filter: FilterParams) => void;
}) => {
const menuRef = useRef<MenuRef>(null);
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
return (
<Menu
ref={menuRef}
rootOptions={{
onClose: onDraftCompleted,
}}
<FilterValueMenu
isDraft={isDraft}
onDraftCompleted={onDraftCompleted}
items={
<>
<MenuItem
@ -55,6 +46,6 @@ export const SharedFilterValue = ({
}
>
<span>{filter.value === 'true' ? 'True' : 'False'}</span>
</Menu>
</FilterValueMenu>
);
};

View File

@ -1,18 +1,13 @@
import {
Checkbox,
Menu,
MenuItem,
type MenuRef,
PropertyValue,
} from '@affine/component';
import { Checkbox, MenuItem, PropertyValue } from '@affine/component';
import type { FilterParams } from '@affine/core/modules/collection-rules';
import { useI18n } from '@affine/i18n';
import { CheckBoxCheckLinearIcon } from '@blocksuite/icons/rc';
import { useCallback, useEffect, useRef } from 'react';
import { useCallback } from 'react';
import { PlainTextDocGroupHeader } from '../explorer/docs-view/group-header';
import { StackProperty } from '../explorer/docs-view/stack-property';
import type { DocListPropertyProps, GroupHeaderProps } from '../explorer/types';
import { FilterValueMenu } from '../filter/filter-value-menu';
import type { PropertyValueProps } from '../properties/types';
import * as styles from './checkbox.css';
@ -55,20 +50,10 @@ export const CheckboxFilterValue = ({
onDraftCompleted?: () => void;
onChange?: (filter: FilterParams) => void;
}) => {
const menuRef = useRef<MenuRef>(null);
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
return (
<Menu
ref={menuRef}
rootOptions={{
onClose: onDraftCompleted,
}}
<FilterValueMenu
isDraft={isDraft}
onDraftCompleted={onDraftCompleted}
items={
<>
<MenuItem
@ -97,7 +82,7 @@ export const CheckboxFilterValue = ({
}
>
<span>{filter.value === 'true' ? 'True' : 'False'}</span>
</Menu>
</FilterValueMenu>
);
};

View File

@ -9,3 +9,7 @@ export const userLabelContainer = style({
display: 'flex',
alignItems: 'center',
});
export const filterValueMenu = style({
top: 'calc(var(--radix-popper-anchor-height) - 18px) !important',
});

View File

@ -160,6 +160,7 @@ export const CreatedByUpdatedByFilterValue = ({
onChange={handleChange}
ref={menuRef}
onEditorClose={onDraftCompleted}
menuClassName={styles.filterValueMenu}
/>
);
};

View File

@ -19,6 +19,7 @@ import {
import { PlainTextDocGroupHeader } from '../explorer/docs-view/group-header';
import { StackProperty } from '../explorer/docs-view/stack-property';
import type { DocListPropertyProps, GroupHeaderProps } from '../explorer/types';
import { FilterValueMenu } from '../filter/filter-value-menu';
import { FilterOptionsGroup } from '../filter/options';
import type { PropertyValueProps } from '../properties/types';
import * as styles from './date.css';
@ -123,11 +124,14 @@ const DateSelectorMenu = ({
);
return (
<Menu
<FilterValueMenu
rootOptions={{
open,
onOpenChange: handleOpenChange,
}}
contentOptions={{
style: { padding: '12px 16px' },
}}
items={<DatePicker value={value || undefined} onChange={handleChange} />}
>
{value ? (
@ -137,7 +141,7 @@ const DateSelectorMenu = ({
{t['com.affine.filter.empty']()}
</span>
)}
</Menu>
</FilterValueMenu>
);
};

View File

@ -1,7 +1,5 @@
import {
Menu,
MenuItem,
type MenuRef,
notify,
PropertyValue,
type RadioItem,
@ -12,11 +10,12 @@ import { useI18n } from '@affine/i18n';
import type { DocMode } from '@blocksuite/affine/model';
import { EdgelessIcon, PageIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { useCallback, useMemo } from 'react';
import { PlainTextDocGroupHeader } from '../explorer/docs-view/group-header';
import { StackProperty } from '../explorer/docs-view/stack-property';
import type { DocListPropertyProps, GroupHeaderProps } from '../explorer/types';
import { FilterValueMenu } from '../filter/filter-value-menu';
import type { PropertyValueProps } from '../properties/types';
import { PropertyRadioGroup } from '../properties/widgets/radio-group';
import * as styles from './doc-primary-mode.css';
@ -89,20 +88,11 @@ export const DocPrimaryModeFilterValue = ({
onChange?: (filter: FilterParams) => void;
}) => {
const t = useI18n();
const menuRef = useRef<MenuRef>(null);
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
return (
<Menu
ref={menuRef}
rootOptions={{
onClose: onDraftCompleted,
}}
<FilterValueMenu
isDraft={isDraft}
onDraftCompleted={onDraftCompleted}
items={
<>
<MenuItem
@ -131,7 +121,7 @@ export const DocPrimaryModeFilterValue = ({
}
>
<span>{filter.value === 'edgeless' ? t['Edgeless']() : t['Page']()}</span>
</Menu>
</FilterValueMenu>
);
};

View File

@ -1,20 +1,15 @@
import {
Menu,
MenuItem,
type MenuRef,
PropertyValue,
type RadioItem,
} from '@affine/component';
import { MenuItem, PropertyValue, type RadioItem } from '@affine/component';
import type { FilterParams } from '@affine/core/modules/collection-rules';
import { type DocRecord, DocService } from '@affine/core/modules/doc';
import { useI18n } from '@affine/i18n';
import { EdgelessIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { useCallback, useMemo } from 'react';
import { PlainTextDocGroupHeader } from '../explorer/docs-view/group-header';
import { StackProperty } from '../explorer/docs-view/stack-property';
import type { GroupHeaderProps } from '../explorer/types';
import { FilterValueMenu } from '../filter/filter-value-menu';
import type { PropertyValueProps } from '../properties/types';
import { PropertyRadioGroup } from '../properties/widgets/radio-group';
import * as styles from './edgeless-theme.css';
@ -97,20 +92,11 @@ export const EdgelessThemeFilterValue = ({
onChange?: (filter: FilterParams) => void;
}) => {
const t = useI18n();
const menuRef = useRef<MenuRef>(null);
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
return (
<Menu
ref={menuRef}
rootOptions={{
onClose: onDraftCompleted,
}}
<FilterValueMenu
isDraft={isDraft}
onDraftCompleted={onDraftCompleted}
items={
<>
<MenuItem
@ -156,7 +142,7 @@ export const EdgelessThemeFilterValue = ({
? t['com.affine.themeSettings.light']()
: t['com.affine.themeSettings.dark']()}
</span>
</Menu>
</FilterValueMenu>
);
};

View File

@ -3,7 +3,6 @@ import {
DatePicker,
Menu,
MenuItem,
type MenuRef,
PropertyValue,
} from '@affine/component';
import { MobileJournalConflictList } from '@affine/core/mobile/pages/workspace/detail/menu/journal-conflicts';
@ -25,6 +24,7 @@ import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
import { PlainTextDocGroupHeader } from '../explorer/docs-view/group-header';
import { StackProperty } from '../explorer/docs-view/stack-property';
import type { DocListPropertyProps, GroupHeaderProps } from '../explorer/types';
import { FilterValueMenu } from '../filter/filter-value-menu';
import type { PropertyValueProps } from '../properties/types';
import * as styles from './journal.css';
@ -192,20 +192,10 @@ export const JournalFilterValue = ({
onDraftCompleted?: () => void;
onChange?: (filter: FilterParams) => void;
}) => {
const menuRef = useRef<MenuRef>(null);
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
return (
<Menu
ref={menuRef}
rootOptions={{
onClose: onDraftCompleted,
}}
<FilterValueMenu
isDraft={isDraft}
onDraftCompleted={onDraftCompleted}
items={
<>
<MenuItem
@ -234,7 +224,7 @@ export const JournalFilterValue = ({
}
>
<span>{filter.value === 'true' ? 'True' : 'False'}</span>
</Menu>
</FilterValueMenu>
);
};

View File

@ -1,4 +1,4 @@
import { Input, Menu, type MenuRef, PropertyValue } from '@affine/component';
import { Input, PropertyValue } from '@affine/component';
import type { FilterParams } from '@affine/core/modules/collection-rules';
import { useI18n } from '@affine/i18n';
import { NumberIcon } from '@blocksuite/icons/rc';
@ -8,13 +8,13 @@ import {
type ChangeEventHandler,
useCallback,
useEffect,
useRef,
useState,
} from 'react';
import { PlainTextDocGroupHeader } from '../explorer/docs-view/group-header';
import { StackProperty } from '../explorer/docs-view/stack-property';
import type { GroupHeaderProps } from '../explorer/types';
import { FilterValueMenu } from '../filter/filter-value-menu';
import type { PropertyValueProps } from '../properties/types';
import * as styles from './number.css';
@ -77,15 +77,8 @@ export const NumberFilterValue = ({
}) => {
const [tempValue, setTempValue] = useState(filter.value || '');
const [valueMenuOpen, setValueMenuOpen] = useState(false);
const menuRef = useRef<MenuRef>(null);
const t = useI18n();
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
useEffect(() => {
// update temp value with new filter value
setTempValue(filter.value || '');
@ -126,8 +119,7 @@ export const NumberFilterValue = ({
}, [isDraft, filter.method, onDraftCompleted]);
return filter.method !== 'is-not-empty' && filter.method !== 'is-empty' ? (
<Menu
ref={menuRef}
<FilterValueMenu
rootOptions={{
open: valueMenuOpen,
onOpenChange: setValueMenuOpen,
@ -135,7 +127,6 @@ export const NumberFilterValue = ({
}}
contentOptions={{
onPointerDownOutside: submitTempValue,
sideOffset: -28,
}}
items={
<Input
@ -163,7 +154,7 @@ export const NumberFilterValue = ({
{t['com.affine.filter.empty']()}
</span>
)}
</Menu>
</FilterValueMenu>
) : null;
};

View File

@ -1,21 +1,16 @@
import {
Menu,
MenuItem,
type MenuRef,
PropertyValue,
type RadioItem,
} from '@affine/component';
import { MenuItem, PropertyValue, type RadioItem } from '@affine/component';
import type { FilterParams } from '@affine/core/modules/collection-rules';
import { type DocRecord, DocService } from '@affine/core/modules/doc';
import { EditorSettingService } from '@affine/core/modules/editor-setting';
import { useI18n } from '@affine/i18n';
import { LongerIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra';
import { useCallback, useEffect, useMemo, useRef } from 'react';
import { useCallback, useMemo } from 'react';
import { PlainTextDocGroupHeader } from '../explorer/docs-view/group-header';
import { StackProperty } from '../explorer/docs-view/stack-property';
import type { GroupHeaderProps } from '../explorer/types';
import { FilterValueMenu } from '../filter/filter-value-menu';
import type { PropertyValueProps } from '../properties/types';
import { PropertyRadioGroup } from '../properties/widgets/radio-group';
import { container } from './page-width.css';
@ -99,20 +94,11 @@ export const PageWidthFilterValue = ({
onChange?: (filter: FilterParams) => void;
}) => {
const t = useI18n();
const menuRef = useRef<MenuRef>(null);
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
return (
<Menu
ref={menuRef}
rootOptions={{
onClose: onDraftCompleted,
}}
<FilterValueMenu
isDraft={isDraft}
onDraftCompleted={onDraftCompleted}
items={
<>
<MenuItem
@ -153,7 +139,7 @@ export const PageWidthFilterValue = ({
'com.affine.settings.editorSettings.page.default-page-width.standard'
]()}
</span>
</Menu>
</FilterValueMenu>
);
};

View File

@ -24,3 +24,6 @@ export const groupHeaderLabel = style({
alignItems: 'center',
gap: 4,
});
export const filterValueMenu = style({
top: 'calc(var(--radix-popper-anchor-height) - 18px) !important',
});

View File

@ -118,6 +118,7 @@ export const TagsFilterValue = ({
selectedTags={selectedTags}
onSelectTag={handleSelectTag}
onDeselectTag={handleDeselectTag}
menuClassName={styles.filterValueMenu}
tagMode="inline-tag"
ref={menuRef}
onEditorClose={onDraftCompleted}

View File

@ -1,20 +1,15 @@
import {
Checkbox,
Menu,
MenuItem,
type MenuRef,
PropertyValue,
} from '@affine/component';
import { Checkbox, MenuItem, PropertyValue } from '@affine/component';
import type { FilterParams } from '@affine/core/modules/collection-rules';
import { type DocRecord, DocService } from '@affine/core/modules/doc';
import { useI18n } from '@affine/i18n';
import { TemplateIcon } from '@blocksuite/icons/rc';
import { useLiveData, useService } from '@toeverything/infra';
import { type ChangeEvent, useCallback, useEffect, useRef } from 'react';
import { type ChangeEvent, useCallback } from 'react';
import { PlainTextDocGroupHeader } from '../explorer/docs-view/group-header';
import { StackProperty } from '../explorer/docs-view/stack-property';
import type { GroupHeaderProps } from '../explorer/types';
import { FilterValueMenu } from '../filter/filter-value-menu';
import type { PropertyValueProps } from '../properties/types';
import * as styles from './template.css';
@ -95,20 +90,10 @@ export const TemplateFilterValue = ({
onDraftCompleted?: () => void;
onChange?: (filter: FilterParams) => void;
}) => {
const menuRef = useRef<MenuRef>(null);
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
return (
<Menu
ref={menuRef}
rootOptions={{
onClose: onDraftCompleted,
}}
<FilterValueMenu
isDraft={isDraft}
onDraftCompleted={onDraftCompleted}
items={
<>
<MenuItem
@ -137,6 +122,6 @@ export const TemplateFilterValue = ({
}
>
<span>{filter.value === 'true' ? 'True' : 'False'}</span>
</Menu>
</FilterValueMenu>
);
};

View File

@ -1,4 +1,4 @@
import { Input, Menu, type MenuRef, PropertyValue } from '@affine/component';
import { Input, PropertyValue } from '@affine/component';
import type { FilterParams } from '@affine/core/modules/collection-rules';
import { useI18n } from '@affine/i18n';
import { TextIcon, TextTypeIcon } from '@blocksuite/icons/rc';
@ -15,6 +15,7 @@ import {
import { PlainTextDocGroupHeader } from '../explorer/docs-view/group-header';
import { StackProperty } from '../explorer/docs-view/stack-property';
import type { GroupHeaderProps } from '../explorer/types';
import { FilterValueMenu } from '../filter/filter-value-menu';
import { ConfigModal } from '../mobile';
import type { PropertyValueProps } from '../properties/types';
import * as styles from './text.css';
@ -188,15 +189,8 @@ export const TextFilterValue = ({
}) => {
const [tempValue, setTempValue] = useState(filter.value || '');
const [valueMenuOpen, setValueMenuOpen] = useState(false);
const menuRef = useRef<MenuRef>(null);
const t = useI18n();
useEffect(() => {
if (isDraft) {
menuRef.current?.changeOpen(true);
}
}, [isDraft]);
useEffect(() => {
// update temp value with new filter value
setTempValue(filter.value || '');
@ -237,8 +231,8 @@ export const TextFilterValue = ({
}, [isDraft, filter.method, onDraftCompleted]);
return filter.method !== 'is-not-empty' && filter.method !== 'is-empty' ? (
<Menu
ref={menuRef}
<FilterValueMenu
isDraft={isDraft}
rootOptions={{
open: valueMenuOpen,
onOpenChange: setValueMenuOpen,
@ -246,7 +240,6 @@ export const TextFilterValue = ({
}}
contentOptions={{
onPointerDownOutside: submitTempValue,
sideOffset: -28,
}}
items={
<Input
@ -272,7 +265,7 @@ export const TextFilterValue = ({
{t['com.affine.filter.empty']()}
</span>
)}
</Menu>
</FilterValueMenu>
) : null;
};

View File

@ -45,4 +45,5 @@ export const container = style({
display: 'flex',
flexDirection: 'row',
gap: 4,
alignItems: 'center',
});

View File

@ -9,7 +9,7 @@ import { nanoid } from 'nanoid';
import type { WorkspacePropertyType } from '../../workspace-property';
const integrationType = f.enum('readwise', 'zotero');
const integrationType = f.enum('readwise');
export const AFFiNE_WORKSPACE_DB_SCHEMA = {
folders: {

View File

@ -13,7 +13,7 @@ import type { IntegrationProperty, IntegrationType } from './type';
// name
export const INTEGRATION_TYPE_NAME_MAP: Record<IntegrationType, I18nString> = {
readwise: 'com.affine.integration.name.readwise',
zotero: 'Zotero',
// zotero: 'Zotero',
};
// schema
@ -50,7 +50,7 @@ export const INTEGRATION_PROPERTY_SCHEMA: {
icon: HistoryIcon,
},
},
zotero: {},
// zotero: {},
};
// icon
@ -59,5 +59,5 @@ export const INTEGRATION_ICON_MAP: Record<
React.ComponentType<SVGProps<SVGSVGElement>>
> = {
readwise: ReadwiseLogoDuotoneIcon,
zotero: () => null,
// zotero: () => null,
};

View File

@ -9,7 +9,6 @@ export type IntegrationType = NonNullable<DocIntegrationRef['type']>;
export type IntegrationDocPropertiesMap = {
readwise: ReadwiseDocProperties;
zotero: never;
};
export type IntegrationProperty<T extends IntegrationType> = {