feat(core): readwise integration tags setting (#10946)

close AF-2307, AF-2262
This commit is contained in:
CatsJuice
2025-03-20 23:20:58 +00:00
parent f1c8a88a7c
commit e37328c83b
9 changed files with 185 additions and 8 deletions
@@ -79,3 +79,28 @@ export const updateStrategyGroup = style({
export const updateStrategyGroupContent = style({
overflow: 'hidden',
});
export const tagsLabel = style({
fontSize: 14,
fontWeight: 500,
lineHeight: '22px',
color: cssVarV2.text.primary,
marginBottom: 2,
});
export const tagsEditor = style({
padding: '6px 8px',
borderRadius: 4,
border: `1px solid ${cssVarV2.layer.insideBorder.border}`,
fontSize: 14,
});
export const tagsPlaceholder = style({
fontSize: 14,
lineHeight: '22px',
color: cssVarV2.text.placeholder,
});
export const tagsMenu = style({
left: -1,
top: 'calc(-1px + var(--radix-popper-anchor-height) * -1)',
width: 'calc(2px + var(--radix-popper-anchor-width))',
});
@@ -1,11 +1,13 @@
import { Button, Modal } from '@affine/component';
import { type TagLike, TagsInlineEditor } from '@affine/core/components/tags';
import {
IntegrationService,
IntegrationTypeIcon,
} from '@affine/core/modules/integration';
import type { ReadwiseConfig } from '@affine/core/modules/integration/type';
import { TagService } from '@affine/core/modules/tag';
import { useI18n } from '@affine/i18n';
import { useLiveData, useService } from '@toeverything/infra';
import { LiveData, useLiveData, useService } from '@toeverything/infra';
import { useCallback, useMemo } from 'react';
import { IntegrationCardIcon } from '../card';
@@ -45,6 +47,8 @@ export const SettingDialog = ({
</div>
</header>
<ul className={styles.settings}>
<TagsSetting />
<Divider />
<NewHighlightSetting />
<Divider />
<UpdateStrategySetting />
@@ -174,3 +178,105 @@ const StartImport = ({ onImport }: { onImport: () => void }) => {
</IntegrationSettingItem>
);
};
const TagsSetting = () => {
const t = useI18n();
const tagService = useService(TagService);
const readwise = useService(IntegrationService).readwise;
const allTags = useLiveData(tagService.tagList.tags$);
const tagColors = tagService.tagColors;
const tagIds = useLiveData(
useMemo(() => readwise.setting$('tags'), [readwise])
);
const adaptedTags = useLiveData(
useMemo(() => {
return LiveData.computed(get => {
return allTags.map(tag => ({
id: tag.id,
value: get(tag.value$),
color: get(tag.color$),
}));
});
}, [allTags])
);
const adaptedTagColors = useMemo(() => {
return tagColors.map(color => ({
id: color[0],
value: color[1],
name: color[0],
}));
}, [tagColors]);
const updateReadwiseTags = useCallback(
(tagIds: string[]) => {
readwise.updateSetting(
'tags',
tagIds.filter(id => !!allTags.some(tag => tag.id === id))
);
},
[allTags, readwise]
);
const onCreateTag = useCallback(
(name: string, color: string) => {
const tag = tagService.tagList.createTag(name, color);
return { id: tag.id, value: tag.value$.value, color: tag.color$.value };
},
[tagService.tagList]
);
const onSelectTag = useCallback(
(tagId: string) => {
updateReadwiseTags([...(tagIds ?? []), tagId]);
},
[tagIds, updateReadwiseTags]
);
const onDeselectTag = useCallback(
(tagId: string) => {
updateReadwiseTags(tagIds?.filter(id => id !== tagId) ?? []);
},
[tagIds, updateReadwiseTags]
);
const onDeleteTag = useCallback(
(tagId: string) => {
tagService.tagList.deleteTag(tagId);
updateReadwiseTags(tagIds ?? []);
},
[tagIds, updateReadwiseTags, tagService.tagList]
);
const onTagChange = useCallback(
(id: string, property: keyof TagLike, value: string) => {
if (property === 'value') {
tagService.tagList.tagByTagId$(id).value?.rename(value);
} else if (property === 'color') {
tagService.tagList.tagByTagId$(id).value?.changeColor(value);
}
},
[tagService.tagList]
);
return (
<li>
<h6 className={styles.tagsLabel}>
{t['com.affine.integration.readwise.setting.tags-label']()}
</h6>
<TagsInlineEditor
placeholder={
<span className={styles.tagsPlaceholder}>
{t['com.affine.integration.readwise.setting.tags-placeholder']()}
</span>
}
className={styles.tagsEditor}
tagMode="inline-tag"
tags={adaptedTags}
selectedTags={tagIds ?? []}
onCreateTag={onCreateTag}
onSelectTag={onSelectTag}
onDeselectTag={onDeselectTag}
tagColors={adaptedTagColors}
onTagChange={onTagChange}
onDeleteTag={onDeleteTag}
modalMenu={true}
menuClassName={styles.tagsMenu}
/>
</li>
);
};