feat(core): info modal should render backlinks with preview (#9387)

fix AF-2033
This commit is contained in:
pengx17
2024-12-27 13:47:06 +00:00
parent cff3a73db4
commit 70e4c8feab
6 changed files with 171 additions and 132 deletions

View File

@@ -89,6 +89,14 @@ globalStyle(`${link} .affine-reference-title`, {
borderBottom: 'none', borderBottom: 'none',
}); });
globalStyle(`${link} svg`, {
color: cssVarV2('icon/secondary'),
});
globalStyle(`${link}:hover svg`, {
color: cssVarV2('icon/primary'),
});
export const linkPreviewContainer = style({ export const linkPreviewContainer = style({
display: 'flex', display: 'flex',
flexDirection: 'column', flexDirection: 'column',

View File

@@ -160,29 +160,13 @@ const usePreviewExtensions = () => {
return [extensions, portals] as const; return [extensions, portals] as const;
}; };
export const BiDirectionalLinkPanel = () => { const useBacklinkGroups = () => {
const { docLinksService, workspaceService, docService } = useServices({ const { docLinksService } = useServices({
DocLinksService, DocLinksService,
WorkspaceService,
DocService,
}); });
const [extensions, portals] = usePreviewExtensions();
const t = useI18n();
const [show, setShow] = useBiDirectionalLinkPanelCollapseState(
docService.doc.id
);
const links = useLiveData(
show ? docLinksService.links.links$ : new LiveData([] as Link[])
);
const backlinkGroups = useLiveData( const backlinkGroups = useLiveData(
LiveData.computed(get => { LiveData.computed(get => {
if (!show) {
return [];
}
const links = get(docLinksService.backlinks.backlinks$); const links = get(docLinksService.backlinks.backlinks$);
// group by docId // group by docId
@@ -202,17 +186,17 @@ export const BiDirectionalLinkPanel = () => {
}) })
); );
const backlinkCount = useMemo(() => { return backlinkGroups;
return backlinkGroups.reduce((acc, link) => acc + link.links.length, 0); };
}, [backlinkGroups]);
const handleClickShow = useCallback(() => { export const BacklinkGroups = () => {
setShow(!show); const [extensions, portals] = usePreviewExtensions();
track.doc.biDirectionalLinksPanel.$.toggle({ const { workspaceService, docService } = useServices({
type: show ? 'collapse' : 'expand', WorkspaceService,
DocService,
}); });
}, [show, setShow]);
const backlinkGroups = useBacklinkGroups();
const textRendererOptions = useMemo(() => { const textRendererOptions = useMemo(() => {
const docLinkBaseURLMiddleware: JobMiddleware = ({ adapterConfigs }) => { const docLinkBaseURLMiddleware: JobMiddleware = ({ adapterConfigs }) => {
adapterConfigs.set( adapterConfigs.set(
@@ -229,31 +213,7 @@ export const BiDirectionalLinkPanel = () => {
}, [extensions, workspaceService.workspace.id]); }, [extensions, workspaceService.workspace.id]);
return ( return (
<div className={styles.container}>
{!show && (
<div className={styles.dividerContainer}>
<div className={styles.divider}></div>
</div>
)}
<div className={styles.titleLine}>
<div className={styles.title}>Bi-Directional Links</div>
<Button className={styles.showButton} onClick={handleClickShow}>
{show
? t['com.affine.editor.bi-directional-link-panel.hide']()
: t['com.affine.editor.bi-directional-link-panel.show']()}
</Button>
</div>
{show && (
<> <>
<div className={styles.dividerContainer}>
<div className={styles.divider}></div>
</div>
<div className={styles.linksContainer}>
<div className={styles.linksTitles}>
{t['com.affine.page-properties.backlinks']()} · {backlinkCount}
</div>
{backlinkGroups.map(linkGroup => ( {backlinkGroups.map(linkGroup => (
<CollapsibleSection <CollapsibleSection
key={linkGroup.docId} key={linkGroup.docId}
@@ -337,6 +297,70 @@ export const BiDirectionalLinkPanel = () => {
</div> </div>
</CollapsibleSection> </CollapsibleSection>
))} ))}
<>
{portals.map(p => (
<Fragment key={p.id}>{p.portal}</Fragment>
))}
</>
</>
);
};
export const BiDirectionalLinkPanel = () => {
const { docLinksService, docService } = useServices({
DocLinksService,
DocService,
});
const t = useI18n();
const [show, setShow] = useBiDirectionalLinkPanelCollapseState(
docService.doc.id
);
const links = useLiveData(
show ? docLinksService.links.links$ : new LiveData([] as Link[])
);
const backlinkGroups = useBacklinkGroups();
const backlinkCount = useMemo(() => {
return backlinkGroups.reduce((acc, link) => acc + link.links.length, 0);
}, [backlinkGroups]);
const handleClickShow = useCallback(() => {
setShow(!show);
track.doc.biDirectionalLinksPanel.$.toggle({
type: show ? 'collapse' : 'expand',
});
}, [show, setShow]);
return (
<div className={styles.container}>
{!show && (
<div className={styles.dividerContainer}>
<div className={styles.divider}></div>
</div>
)}
<div className={styles.titleLine}>
<div className={styles.title}>Bi-Directional Links</div>
<Button className={styles.showButton} onClick={handleClickShow}>
{show
? t['com.affine.editor.bi-directional-link-panel.hide']()
: t['com.affine.editor.bi-directional-link-panel.show']()}
</Button>
</div>
{show && (
<>
<div className={styles.dividerContainer}>
<div className={styles.divider}></div>
</div>
<div className={styles.linksContainer}>
<div className={styles.linksTitles}>
{t['com.affine.page-properties.backlinks']()} · {backlinkCount}
</div>
<BacklinkGroups />
</div> </div>
<div className={styles.linksContainer}> <div className={styles.linksContainer}>
<div className={styles.linksTitles}> <div className={styles.linksTitles}>
@@ -354,13 +378,6 @@ export const BiDirectionalLinkPanel = () => {
</div> </div>
</> </>
)} )}
{
<>
{portals.map(p => (
<Fragment key={p.id}>{p.portal}</Fragment>
))}
</>
}
</div> </div>
); );
}; };

View File

@@ -5,6 +5,7 @@ import {
PropertyCollapsibleContent, PropertyCollapsibleContent,
PropertyCollapsibleSection, PropertyCollapsibleSection,
} from '@affine/component'; } from '@affine/component';
import { BacklinkGroups } from '@affine/core/components/blocksuite/block-suite-editor/bi-directional-link-panel';
import { CreatePropertyMenuItems } from '@affine/core/components/doc-properties/menu/create-doc-property'; import { CreatePropertyMenuItems } from '@affine/core/components/doc-properties/menu/create-doc-property';
import { DocPropertyRow } from '@affine/core/components/doc-properties/table'; import { DocPropertyRow } from '@affine/core/components/doc-properties/table';
import type { DocCustomPropertyInfo } from '@affine/core/modules/db'; import type { DocCustomPropertyInfo } from '@affine/core/modules/db';
@@ -162,7 +163,8 @@ export const InfoTable = ({
{backlinks && backlinks.length > 0 ? ( {backlinks && backlinks.length > 0 ? (
<> <>
<LinksRow <LinksRow
references={backlinks} count={backlinks.length}
references={<BacklinkGroups />}
onClick={onClose} onClick={onClose}
label={t['com.affine.page-properties.backlinks']()} label={t['com.affine.page-properties.backlinks']()}
/> />
@@ -172,6 +174,7 @@ export const InfoTable = ({
{links && links.length > 0 ? ( {links && links.length > 0 ? (
<> <>
<LinksRow <LinksRow
count={links.length}
references={links} references={links}
onClick={onClose} onClick={onClose}
label={t['com.affine.page-properties.outgoing-links']()} label={t['com.affine.page-properties.outgoing-links']()}

View File

@@ -5,7 +5,7 @@ import { globalStyle, style } from '@vanilla-extract/css';
export const wrapper = style({ export const wrapper = style({
width: '100%', width: '100%',
borderRadius: 4, borderRadius: 4,
color: cssVar('textPrimaryColor'), color: cssVarV2('text/primary'),
display: 'flex', display: 'flex',
flexDirection: 'row', flexDirection: 'row',
alignItems: 'center', alignItems: 'center',
@@ -16,10 +16,15 @@ export const wrapper = style({
}); });
globalStyle(`${wrapper} svg`, { globalStyle(`${wrapper} svg`, {
color: cssVar('iconSecondary'), color: cssVarV2('icon/secondary'),
fontSize: 16, fontSize: 16,
transform: 'none', transform: 'none',
}); });
globalStyle(`${wrapper}:hover svg`, {
color: cssVarV2('icon/primary'),
});
globalStyle(`${wrapper} span`, { globalStyle(`${wrapper} span`, {
fontSize: cssVar('fontSm'), fontSize: cssVar('fontSm'),
whiteSpace: 'nowrap', whiteSpace: 'nowrap',

View File

@@ -1,27 +1,30 @@
import { PropertyCollapsibleSection } from '@affine/component'; import { PropertyCollapsibleSection } from '@affine/component';
import { AffinePageReference } from '@affine/core/components/affine/reference-link'; import { AffinePageReference } from '@affine/core/components/affine/reference-link';
import type { Backlink, Link } from '@affine/core/modules/doc-link'; import type { Backlink, Link } from '@affine/core/modules/doc-link';
import type { MouseEvent } from 'react'; import type { MouseEvent, ReactNode } from 'react';
import * as styles from './links-row.css'; import * as styles from './links-row.css';
export const LinksRow = ({ export const LinksRow = ({
references, references,
count,
label, label,
className, className,
onClick, onClick,
}: { }: {
references: Backlink[] | Link[]; references: Backlink[] | Link[] | ReactNode;
count: number;
label: string; label: string;
className?: string; className?: string;
onClick?: (e: MouseEvent) => void; onClick?: (e: MouseEvent) => void;
}) => { }) => {
return ( return (
<PropertyCollapsibleSection <PropertyCollapsibleSection
title={`${label} · ${references.length}`} title={`${label} · ${count}`}
className={className} className={className}
> >
{references.map(link => ( {Array.isArray(references)
? references.map(link => (
<AffinePageReference <AffinePageReference
key={link.docId} key={link.docId}
pageId={link.docId} pageId={link.docId}
@@ -29,7 +32,8 @@ export const LinksRow = ({
className={styles.wrapper} className={styles.wrapper}
onClick={onClick} onClick={onClick}
/> />
))} ))
: references}
</PropertyCollapsibleSection> </PropertyCollapsibleSection>
); );
}; };

View File

@@ -131,6 +131,7 @@ export const DocInfoSheet = ({
<LinksRow <LinksRow
className={styles.linksRow} className={styles.linksRow}
references={backlinks} references={backlinks}
count={backlinks.length}
label={t['com.affine.page-properties.backlinks']()} label={t['com.affine.page-properties.backlinks']()}
/> />
<Divider size="thinner" /> <Divider size="thinner" />
@@ -141,6 +142,7 @@ export const DocInfoSheet = ({
<LinksRow <LinksRow
className={styles.linksRow} className={styles.linksRow}
references={links} references={links}
count={links.length}
label={t['com.affine.page-properties.outgoing-links']()} label={t['com.affine.page-properties.outgoing-links']()}
/> />
<Divider size="thinner" /> <Divider size="thinner" />