feat(editor): update footnote node style and config (#10392)

[BS-2581](https://linear.app/affine-design/issue/BS-2581/优化-footnote-node-正文样式)
This commit is contained in:
donteatfriedrice
2025-02-24 08:15:04 +00:00
parent 8b4175c44d
commit 1b2a4377fd
6 changed files with 57 additions and 6 deletions
@@ -25,6 +25,7 @@ export interface FootNoteNodeConfig {
customPopupRenderer?: FootNotePopupRenderer;
interactive?: boolean;
hidePopup?: boolean;
disableHoverEffect?: boolean;
onPopupClick?: FootNotePopupClickHandler;
}
@@ -33,7 +34,9 @@ export class FootNoteNodeConfigProvider {
private _customPopupRenderer?: FootNotePopupRenderer;
private _hidePopup: boolean;
private _interactive: boolean;
private _disableHoverEffect: boolean;
private _onPopupClick?: FootNotePopupClickHandler;
get customNodeRenderer() {
return this._customNodeRenderer;
}
@@ -58,6 +61,10 @@ export class FootNoteNodeConfigProvider {
return this._interactive;
}
get disableHoverEffect() {
return this._disableHoverEffect;
}
constructor(
config: FootNoteNodeConfig,
readonly std: BlockStdScope
@@ -66,6 +73,7 @@ export class FootNoteNodeConfigProvider {
this._customPopupRenderer = config.customPopupRenderer;
this._hidePopup = config.hidePopup ?? false;
this._interactive = config.interactive ?? true;
this._disableHoverEffect = config.disableHoverEffect ?? false;
this._onPopupClick = config.onPopupClick;
}
@@ -85,6 +93,10 @@ export class FootNoteNodeConfigProvider {
this._interactive = interactive;
}
setDisableHoverEffect(disableHoverEffect: boolean) {
this._disableHoverEffect = disableHoverEffect;
}
setPopupClick(onPopupClick: FootNotePopupClickHandler) {
this._onPopupClick = onPopupClick;
}
@@ -19,6 +19,7 @@ import { shift } from '@floating-ui/dom';
import { baseTheme } from '@toeverything/theme';
import { css, html, nothing, unsafeCSS } from 'lit';
import { property } from 'lit/decorators.js';
import { classMap } from 'lit-html/directives/class-map.js';
import { ref } from 'lit-html/directives/ref.js';
import { HoverController } from '../../../../../hover/controller';
@@ -37,7 +38,7 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
.footnote-content-default {
display: inline-block;
background: ${unsafeCSSVarV2('button/primary')};
background: ${unsafeCSSVarV2('block/footnote/numberBgHover')};
color: ${unsafeCSSVarV2('button/pureWhiteText')};
width: 14px;
height: 14px;
@@ -48,6 +49,21 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
text-align: center;
text-overflow: ellipsis;
font-family: ${unsafeCSS(baseTheme.fontSansFamily)};
transition: background 0.3s ease-in-out;
}
.footnote-node.hover-effect {
.footnote-content-default {
color: var(--affine-text-primary-color);
background: ${unsafeCSSVarV2('block/footnote/numberBg')};
}
}
.footnote-node.hover-effect:hover {
.footnote-content-default {
color: ${unsafeCSSVarV2('button/pureWhiteText')};
background: ${unsafeCSSVarV2('block/footnote/numberBgHover')};
}
}
`;
@@ -67,6 +83,10 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
return this.config?.hidePopup;
}
get disableHoverEffect() {
return this.config?.disableHoverEffect;
}
get onPopupClick() {
return this.config?.onPopupClick;
}
@@ -142,7 +162,7 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
},
};
},
{ enterDelay: 500 }
{ enterDelay: 300 }
);
override render() {
@@ -156,9 +176,14 @@ export class AffineFootnoteNode extends WithDisposable(ShadowlessElement) {
? this.customNodeRenderer(footnote, this.std)
: this._FootNoteDefaultContent(footnote);
const nodeClasses = classMap({
'footnote-node': true,
'hover-effect': !this.disableHoverEffect,
});
return html`<span
${this.hidePopup ? '' : ref(this._whenHover.setReference)}
class="footnote-node"
class=${nodeClasses}
>${node}<v-text .str=${ZERO_WIDTH_NON_JOINER}></v-text
></span>`;
}
@@ -14,6 +14,7 @@ export class FootNotePopupChip extends LitElement {
gap: 4px;
box-sizing: border-box;
cursor: default;
transition: width 0.3s ease-in-out;
}
.prefix-icon,
@@ -26,7 +26,6 @@ export class FootNotePopup extends SignalWatcher(WithDisposable(LitElement)) {
.footnote-popup-container {
border-radius: 4px;
box-shadow: ${unsafeCSSVar('overlayPanelShadow')};
border-radius: 4px;
background-color: ${unsafeCSSVarV2('layer/background/primary')};
border: 0.5px solid ${unsafeCSSVarV2('layer/insideBorder/border')};
}
@@ -8,6 +8,7 @@ import { WorkspaceService } from '@affine/core/modules/workspace';
import {
createSignalFromObservable,
DocModeProvider,
FootNoteNodeConfigExtension,
RefNodeSlotsProvider,
} from '@blocksuite/affine/blocks';
import { useFramework } from '@toeverything/infra';
@@ -20,6 +21,11 @@ export interface SidebarTabProps {
onLoad?: ((component: HTMLElement) => void) | null;
}
// Disable hover effect for footnote node in chat panel
const FOOTNOTE_CONFIG = FootNoteNodeConfigExtension({
disableHoverEffect: true,
});
// A wrapper for CopilotPanel
export const EditorChatPanel = forwardRef(function EditorChatPanel(
{ editor, onLoad }: SidebarTabProps,
@@ -84,8 +90,9 @@ export const EditorChatPanel = forwardRef(function EditorChatPanel(
);
},
};
chatPanelRef.current.previewSpecBuilder =
createPageModePreviewSpecs(framework);
const previewSpecBuilder = createPageModePreviewSpecs(framework);
previewSpecBuilder.extend([FOOTNOTE_CONFIG]);
chatPanelRef.current.previewSpecBuilder = previewSpecBuilder;
} else {
chatPanelRef.current.host = editor.host;
chatPanelRef.current.doc = editor.doc;
@@ -4,6 +4,7 @@ import type { AIChatBlockModel } from '@affine/core/blocksuite/ai/blocks/ai-chat
import { createPageModePreviewSpecs } from '@affine/core/blocksuite/block-suite-editor/specs/preview';
import { AINetworkSearchService } from '@affine/core/modules/ai-button/services/network-search';
import type { EditorHost } from '@blocksuite/affine/block-std';
import { FootNoteNodeConfigExtension } from '@blocksuite/affine/blocks';
import { useFramework } from '@toeverything/infra';
import { useMemo } from 'react';
@@ -12,6 +13,11 @@ export type AIChatBlockPeekViewProps = {
host: EditorHost;
};
// Disable hover effect for footnote node in center peek preview mode
const FOOTNOTE_CONFIG = FootNoteNodeConfigExtension({
disableHoverEffect: true,
});
export const AIChatBlockPeekView = ({
model,
host,
@@ -20,6 +26,7 @@ export const AIChatBlockPeekView = ({
const searchService = framework.get(AINetworkSearchService);
return useMemo(() => {
const previewSpecBuilder = createPageModePreviewSpecs(framework);
previewSpecBuilder.extend([FOOTNOTE_CONFIG]);
const networkSearchConfig = {
visible: searchService.visible,
enabled: searchService.enabled,