${when(
- this.insertIndex !== undefined,
+ this._insertIndex$.value !== undefined,
() =>
html`
{
- this._updateNoticeVisibility();
- })
- );
-
- this._docDisposables.add(
- effect(() => {
- this._updateNotes();
- })
- );
- }
-
- private _updateNotes() {
- if (this._dragging$.value) return;
-
- const isRenderableNote = (item: OutlineNoteItem) => {
- let hasHeadings = false;
-
- for (const block of item.note.children) {
- if (isHeadingBlock(block)) {
- hasHeadings = true;
- break;
- }
- }
-
- return hasHeadings || this.enableNotesSorting;
- };
-
- this._pageVisibleNoteItems$.value = getNotesFromDoc(this.doc, [
- NoteDisplayMode.DocAndEdgeless,
- NoteDisplayMode.DocOnly,
- ]).filter(isRenderableNote);
-
- this._edgelessOnlyNoteItems$.value = getNotesFromDoc(this.doc, [
- NoteDisplayMode.EdgelessOnly,
- ]).filter(isRenderableNote);
- }
-
- private _updateNoticeVisibility() {
- if (this.enableNotesSorting) {
- if (this.noticeVisible) {
- this.setNoticeVisibility(false);
- }
- return;
- }
-
- const shouldShowNotice =
- getNotesFromDoc(this.doc, [NoteDisplayMode.DocOnly]).length > 0;
-
- if (shouldShowNotice && !this.noticeVisible) {
- this.setNoticeVisibility(true);
- }
- }
-
private _watchSelectedNotes() {
+ return effect(() => {
+ const { std, doc, mode } = this.editor;
+ if (mode !== 'edgeless') return;
+
+ const currSelectedNotes = std.selection
+ .filter(SurfaceSelection)
+ .filter(({ blockId }) => {
+ const model = doc.getBlock(blockId)?.model;
+ return !!model && matchFlavours(model, ['affine:note']);
+ })
+ .map(({ blockId }) => blockId);
+
+ const preSelected = this._selectedNotes$.peek();
+ if (
+ preSelected.length !== currSelectedNotes.length ||
+ preSelected.some(id => !currSelectedNotes.includes(id))
+ ) {
+ this._selectedNotes$.value = currSelectedNotes;
+ }
+ });
+ }
+
+ private _watchNotes() {
this.disposables.add(
effect(() => {
- const { std, doc, mode } = this.editor;
- if (mode !== 'edgeless') return;
+ if (this._dragging$.value) return;
- const currSelectedNotes = std.selection
- .filter(SurfaceSelection)
- .filter(({ blockId }) => {
- const model = doc.getBlock(blockId)?.model;
- return !!model && matchFlavours(model, ['affine:note']);
- })
- .map(({ blockId }) => blockId);
+ const isRenderableNote = (item: OutlineNoteItem) => {
+ let hasHeadings = false;
- const preSelected = this._selectedNotes$.peek();
- if (
- preSelected.length !== currSelectedNotes.length ||
- preSelected.some(id => !currSelectedNotes.includes(id))
- ) {
- this._selectedNotes$.value = currSelectedNotes;
- }
+ for (const block of item.note.children) {
+ if (isHeadingBlock(block)) {
+ hasHeadings = true;
+ break;
+ }
+ }
+ return hasHeadings || this._context.enableSorting$.value;
+ };
+
+ this._pageVisibleNoteItems$.value = getNotesFromDoc(this.doc, [
+ NoteDisplayMode.DocAndEdgeless,
+ NoteDisplayMode.DocOnly,
+ ]).filter(isRenderableNote);
+
+ this._edgelessOnlyNoteItems$.value = getNotesFromDoc(this.doc, [
+ NoteDisplayMode.EdgelessOnly,
+ ]).filter(isRenderableNote);
})
);
}
@@ -507,12 +464,12 @@ export class OutlinePanelBody extends SignalWatcher(
}
)
);
+ this._watchNotes();
this._watchSelectedNotes();
}
override disconnectedCallback(): void {
super.disconnectedCallback();
- this._clearDocDisposables();
this._clearHighlightMask();
}
@@ -534,46 +491,11 @@ export class OutlinePanelBody extends SignalWatcher(
`;
}
- override willUpdate(_changedProperties: PropertyValues) {
- if (_changedProperties.has('editor')) {
- this._setDocDisposables();
- }
-
- if (_changedProperties.has('enableNotesSorting')) {
- this._updateNoticeVisibility();
- }
- }
-
@query('.page-visible-card-list')
private accessor _pageVisibleList!: HTMLElement;
- @consume({ context: editorContext })
- @property({ attribute: false })
- accessor editor!: AffineEditorContainer;
-
- @property({ attribute: false })
- accessor enableNotesSorting: boolean = false;
-
- @property({ attribute: false })
- accessor fitPadding!: number[];
-
- @property({ attribute: false })
- accessor insertIndex: number | undefined = undefined;
-
- @property({ attribute: false })
- accessor noticeVisible!: boolean;
-
- @property({ attribute: false })
- accessor renderEdgelessOnlyNotes: boolean = true;
-
- @property({ attribute: false })
- accessor setNoticeVisibility!: (visibility: boolean) => void;
-
- @property({ attribute: false })
- accessor showPreviewIcon!: boolean;
-
- @property({ attribute: false })
- accessor toggleNotesSorting!: () => void;
+ @consume({ context: tocContext })
+ private accessor _context!: TocContext;
}
declare global {
diff --git a/blocksuite/presets/src/fragments/outline/card/outline-card.css.ts b/blocksuite/presets/src/fragments/outline/card/outline-card.css.ts
index 38e4919df..38e0999a5 100644
--- a/blocksuite/presets/src/fragments/outline/card/outline-card.css.ts
+++ b/blocksuite/presets/src/fragments/outline/card/outline-card.css.ts
@@ -48,19 +48,23 @@ export const cardHeader = style({
alignItems: 'center',
gap: '8px',
boxSizing: 'border-box',
+
+ ':hover': {
+ cursor: 'grab',
+ },
selectors: {
[`${outlineCard}[data-sortable="true"] &`]: {
display: 'flex',
},
- [`${outlineCard}[data-invisible="false"] &:hover`]: {
- cursor: 'grab',
+ [`${outlineCard}[data-visibility="edgeless"] &:hover`]: {
+ cursor: 'default',
},
},
});
const invisibleCard = style({
selectors: {
- [`${outlineCard}[data-invisible="true"] &`]: {
+ [`${outlineCard}[data-visibility="edgeless"] &`]: {
color: cssVarV2('text/disable'),
pointerEvents: 'none',
},
diff --git a/blocksuite/presets/src/fragments/outline/card/outline-card.ts b/blocksuite/presets/src/fragments/outline/card/outline-card.ts
index cc96a7947..c53459847 100644
--- a/blocksuite/presets/src/fragments/outline/card/outline-card.ts
+++ b/blocksuite/presets/src/fragments/outline/card/outline-card.ts
@@ -9,9 +9,13 @@ import {
import { SignalWatcher, WithDisposable } from '@blocksuite/global/utils';
import { ArrowDownSmallIcon, InvisibleIcon } from '@blocksuite/icons/lit';
import type { BlockModel } from '@blocksuite/store';
+import { consume } from '@lit/context';
+import { signal } from '@preact/signals-core';
import { html } from 'lit';
-import { property, query, state } from 'lit/decorators.js';
+import { property, query } from 'lit/decorators.js';
+import { classMap } from 'lit/directives/class-map.js';
+import { type TocContext, tocContext } from '../config';
import type { SelectEvent } from '../utils/custom-events';
import * as styles from './outline-card.css';
@@ -23,6 +27,8 @@ export class OutlineNoteCard extends SignalWatcher(
private _displayModePopper: ReturnType
| null =
null;
+ private readonly _showPopper$ = signal(false);
+
private _dispatchClickBlockEvent(block: BlockModel) {
const event = new CustomEvent('clickblock', {
detail: {
@@ -49,7 +55,7 @@ export class OutlineNoteCard extends SignalWatcher(
private _dispatchDragEvent(e: MouseEvent) {
e.preventDefault();
- if (e.button !== 0 || !this.enableNotesSorting) return;
+ if (e.button !== 0 || !this._context.enableSorting$.peek()) return;
const { clientX: startX, clientY: startY } = e;
const disposeDragStart = on(this.ownerDocument, 'mousemove', e => {
@@ -122,7 +128,7 @@ export class OutlineNoteCard extends SignalWatcher(
this._displayModeButtonGroup,
this._displayModePanel,
({ display }) => {
- this._showPopper = display === 'show';
+ this._showPopper$.value = display === 'show';
},
{
mainAxis: 0,
@@ -136,11 +142,15 @@ export class OutlineNoteCard extends SignalWatcher(
override render() {
const { children, displayMode } = this.note;
const currentMode = this._getCurrentModeLabel(displayMode);
+ const invisible =
+ this.note.displayMode$.value === NoteDisplayMode.EdgelessOnly;
+
+ const enableSorting = this._context.enableSorting$.value;
return html`
@@ -152,7 +162,7 @@ export class OutlineNoteCard extends SignalWatcher(
>
${html`