mirror of
https://github.com/toeverything/AFFiNE.git
synced 2026-02-13 21:05:19 +00:00
chore(editor): cleanup dead code (#9904)
This commit is contained in:
@@ -32,6 +32,7 @@ import { effects as componentToggleButtonEffects } from '@blocksuite/affine-comp
|
||||
import { ToggleSwitch } from '@blocksuite/affine-components/toggle-switch';
|
||||
import { effects as componentToolbarEffects } from '@blocksuite/affine-components/toolbar';
|
||||
import { effects as widgetDragHandleEffects } from '@blocksuite/affine-widget-drag-handle/effects';
|
||||
import { effects as widgetEdgelessAutoConnectEffects } from '@blocksuite/affine-widget-edgeless-auto-connect/effects';
|
||||
import { effects as widgetFrameTitleEffects } from '@blocksuite/affine-widget-frame-title/effects';
|
||||
import { effects as widgetRemoteSelectionEffects } from '@blocksuite/affine-widget-remote-selection/effects';
|
||||
import { effects as widgetScrollAnchoringEffects } from '@blocksuite/affine-widget-scroll-anchoring/effects';
|
||||
@@ -152,10 +153,6 @@ import {
|
||||
AIPanelGenerating,
|
||||
AIPanelInput,
|
||||
} from './root-block/widgets/ai-panel/components/index.js';
|
||||
import {
|
||||
AFFINE_EDGELESS_AUTO_CONNECT_WIDGET,
|
||||
EdgelessAutoConnectWidget,
|
||||
} from './root-block/widgets/edgeless-auto-connect/edgeless-auto-connect.js';
|
||||
import { EdgelessCopilotPanel } from './root-block/widgets/edgeless-copilot-panel/index.js';
|
||||
import { AFFINE_EDGELESS_ZOOM_TOOLBAR_WIDGET } from './root-block/widgets/edgeless-zoom-toolbar/index.js';
|
||||
import { ZoomBarToggleButton } from './root-block/widgets/edgeless-zoom-toolbar/zoom-bar-toggle-button.js';
|
||||
@@ -223,6 +220,7 @@ export function effects() {
|
||||
widgetEdgelessElementToolbarEffects();
|
||||
widgetRemoteSelectionEffects();
|
||||
widgetDragHandleEffects();
|
||||
widgetEdgelessAutoConnectEffects();
|
||||
dataViewEffects();
|
||||
|
||||
customElements.define('affine-page-root', PageRootBlockComponent);
|
||||
@@ -392,10 +390,6 @@ export function effects() {
|
||||
AffineEdgelessZoomToolbarWidget
|
||||
);
|
||||
customElements.define(AFFINE_SURFACE_REF_TOOLBAR, AffineSurfaceRefToolbar);
|
||||
customElements.define(
|
||||
AFFINE_EDGELESS_AUTO_CONNECT_WIDGET,
|
||||
EdgelessAutoConnectWidget
|
||||
);
|
||||
customElements.define(AFFINE_FORMAT_BAR_WIDGET, AffineFormatBarWidget);
|
||||
}
|
||||
|
||||
|
||||
@@ -3,6 +3,7 @@ import {
|
||||
type ConnectionOverlay,
|
||||
ConnectorPathGenerator,
|
||||
EdgelessCRUDIdentifier,
|
||||
isNoteBlock,
|
||||
Overlay,
|
||||
OverlayIdentifier,
|
||||
type RoughCanvas,
|
||||
@@ -44,7 +45,6 @@ import { classMap } from 'lit/directives/class-map.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
import type { EdgelessRootBlockComponent } from '../../edgeless-root-block.js';
|
||||
import { isNoteBlock } from '../../utils/query.js';
|
||||
import { mountShapeTextEditor } from '../../utils/text.js';
|
||||
import type { SelectedRect } from '../rects/edgeless-selected-rect.js';
|
||||
import { EdgelessAutoCompletePanel } from './auto-complete-panel.js';
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isNoteBlock } from '@blocksuite/affine-block-surface';
|
||||
import { SmallScissorsIcon } from '@blocksuite/affine-components/icons';
|
||||
import { DEFAULT_NOTE_HEIGHT } from '@blocksuite/affine-model';
|
||||
import { EDGELESS_BLOCK_CHILD_PADDING } from '@blocksuite/affine-shared/consts';
|
||||
@@ -22,7 +23,6 @@ import type {
|
||||
NoteBlockModel,
|
||||
RootBlockModel,
|
||||
} from '../../../../index.js';
|
||||
import { isNoteBlock } from '../../utils/query.js';
|
||||
|
||||
const DIVIDING_LINE_OFFSET = 4;
|
||||
const NEW_NOTE_GAP = 40;
|
||||
|
||||
@@ -8,6 +8,7 @@ import {
|
||||
} from '@blocksuite/affine-block-embed';
|
||||
import {
|
||||
CanvasElementType,
|
||||
isNoteBlock,
|
||||
normalizeShapeBound,
|
||||
OverlayIdentifier,
|
||||
TextUtils,
|
||||
@@ -91,7 +92,6 @@ import {
|
||||
isFrameBlock,
|
||||
isImageBlock,
|
||||
isMindmapNode,
|
||||
isNoteBlock,
|
||||
} from '../../utils/query.js';
|
||||
import {
|
||||
HandleDirection,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { insertLinkByQuickSearchCommand } from '@blocksuite/affine-block-bookmark';
|
||||
import { EdgelessTextBlockComponent } from '@blocksuite/affine-block-edgeless-text';
|
||||
import { isNoteBlock } from '@blocksuite/affine-block-surface';
|
||||
import { toast } from '@blocksuite/affine-components/toast';
|
||||
import {
|
||||
ConnectorElementModel,
|
||||
@@ -45,7 +46,7 @@ import {
|
||||
} from './utils/consts.js';
|
||||
import { deleteElements } from './utils/crud.js';
|
||||
import { getNextShapeType } from './utils/hotkey-utils.js';
|
||||
import { isCanvasElement, isNoteBlock } from './utils/query.js';
|
||||
import { isCanvasElement } from './utils/query.js';
|
||||
import {
|
||||
mountConnectorLabelEditor,
|
||||
mountShapeTextEditor,
|
||||
|
||||
@@ -7,6 +7,7 @@ import {
|
||||
ThemeService,
|
||||
} from '@blocksuite/affine-shared/services';
|
||||
import { AFFINE_DRAG_HANDLE_WIDGET } from '@blocksuite/affine-widget-drag-handle';
|
||||
import { AFFINE_EDGELESS_AUTO_CONNECT_WIDGET } from '@blocksuite/affine-widget-edgeless-auto-connect';
|
||||
import { AFFINE_FRAME_TITLE_WIDGET } from '@blocksuite/affine-widget-frame-title';
|
||||
import {
|
||||
AFFINE_DOC_REMOTE_SELECTION_WIDGET,
|
||||
@@ -25,7 +26,6 @@ import { literal, unsafeStatic } from 'lit/static-html.js';
|
||||
|
||||
import { ExportManagerExtension } from '../../_common/export-manager/export-manager.js';
|
||||
import { RootBlockAdapterExtensions } from '../adapters/extension.js';
|
||||
import { AFFINE_EDGELESS_AUTO_CONNECT_WIDGET } from '../widgets/edgeless-auto-connect/edgeless-auto-connect.js';
|
||||
import { AFFINE_EDGELESS_ZOOM_TOOLBAR_WIDGET } from '../widgets/edgeless-zoom-toolbar/index.js';
|
||||
import { EDGELESS_ELEMENT_TOOLBAR_WIDGET } from '../widgets/element-toolbar/index.js';
|
||||
import { AFFINE_EMBED_CARD_TOOLBAR_WIDGET } from '../widgets/embed-card-toolbar/embed-card-toolbar.js';
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { insertEdgelessTextCommand } from '@blocksuite/affine-block-edgeless-text';
|
||||
import {
|
||||
ConnectorUtils,
|
||||
isNoteBlock,
|
||||
OverlayIdentifier,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import { focusTextModel } from '@blocksuite/affine-components/rich-text';
|
||||
@@ -56,7 +57,6 @@ import {
|
||||
isCanvasElement,
|
||||
isEdgelessTextBlock,
|
||||
isFrameBlock,
|
||||
isNoteBlock,
|
||||
} from '../utils/query.js';
|
||||
import type { EdgelessSnapManager } from '../utils/snap-manager.js';
|
||||
import {
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import { isNoteBlock } from '@blocksuite/affine-block-surface';
|
||||
import type {
|
||||
EdgelessTextBlockModel,
|
||||
EmbedSyncedDocModel,
|
||||
@@ -22,7 +23,6 @@ import {
|
||||
isEmbedSyncedDocBlock,
|
||||
isFrameBlock,
|
||||
isImageBlock,
|
||||
isNoteBlock,
|
||||
} from './query.js';
|
||||
|
||||
const offset = 10;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import { isNoteBlock } from '@blocksuite/affine-block-surface';
|
||||
|
||||
import type { Connectable } from '../../../_common/utils/index.js';
|
||||
import type { EdgelessRootBlockComponent } from '../index.js';
|
||||
import { isConnectable, isNoteBlock } from './query.js';
|
||||
import { isConnectable } from './query.js';
|
||||
|
||||
/**
|
||||
* Use deleteElementsV2 instead.
|
||||
|
||||
@@ -19,7 +19,6 @@ import {
|
||||
type FrameBlockModel,
|
||||
type ImageBlockModel,
|
||||
MindmapElementModel,
|
||||
type NoteBlockModel,
|
||||
ShapeElementModel,
|
||||
TextElementModel,
|
||||
} from '@blocksuite/affine-model';
|
||||
@@ -46,12 +45,6 @@ export function isMindmapNode(
|
||||
return element?.group instanceof MindmapElementModel;
|
||||
}
|
||||
|
||||
export function isNoteBlock(
|
||||
element: BlockModel | BlockSuite.EdgelessModel | null
|
||||
): element is NoteBlockModel {
|
||||
return !!element && 'flavour' in element && element.flavour === 'affine:note';
|
||||
}
|
||||
|
||||
export function isEdgelessTextBlock(
|
||||
element: BlockModel | BlockSuite.EdgelessModel | null
|
||||
): element is EdgelessTextBlockModel {
|
||||
|
||||
@@ -1,599 +0,0 @@
|
||||
import { EdgelessLegacySlotIdentifier } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
AutoConnectLeftIcon,
|
||||
AutoConnectRightIcon,
|
||||
HiddenIcon,
|
||||
SmallDocIcon,
|
||||
} from '@blocksuite/affine-components/icons';
|
||||
import {
|
||||
FrameBlockModel,
|
||||
NoteBlockModel,
|
||||
NoteDisplayMode,
|
||||
type RootBlockModel,
|
||||
type SurfaceRefBlockModel,
|
||||
} from '@blocksuite/affine-model';
|
||||
import { FeatureFlagService } from '@blocksuite/affine-shared/services';
|
||||
import {
|
||||
matchFlavours,
|
||||
stopPropagation,
|
||||
} from '@blocksuite/affine-shared/utils';
|
||||
import { WidgetComponent } from '@blocksuite/block-std';
|
||||
import { GfxControllerIdentifier } from '@blocksuite/block-std/gfx';
|
||||
import { Bound } from '@blocksuite/global/utils';
|
||||
import { css, html, nothing, type TemplateResult } from 'lit';
|
||||
import { state } from 'lit/decorators.js';
|
||||
import { repeat } from 'lit/directives/repeat.js';
|
||||
import { styleMap } from 'lit/directives/style-map.js';
|
||||
|
||||
import type { EdgelessRootBlockComponent } from '../../edgeless/edgeless-root-block.js';
|
||||
import type { EdgelessRootService } from '../../edgeless/edgeless-root-service.js';
|
||||
import { isNoteBlock } from '../../edgeless/utils/query.js';
|
||||
|
||||
const PAGE_VISIBLE_INDEX_LABEL_WIDTH = 44;
|
||||
const PAGE_VISIBLE_INDEX_LABEL_HEIGHT = 24;
|
||||
const EDGELESS_ONLY_INDEX_LABEL_WIDTH = 24;
|
||||
const EDGELESS_ONLY_INDEX_LABEL_HEIGHT = 24;
|
||||
const INDEX_LABEL_OFFSET = 16;
|
||||
|
||||
function calculatePosition(gap: number, count: number, iconWidth: number) {
|
||||
const positions = [];
|
||||
if (count === 1) {
|
||||
positions.push([0, 10]);
|
||||
return positions;
|
||||
}
|
||||
const middleIndex = (count - 1) / 2;
|
||||
const isEven = count % 2 === 0;
|
||||
const middleOffset = (gap + iconWidth) / 2;
|
||||
function getSign(num: number) {
|
||||
return num - middleIndex > 0 ? 1 : -1;
|
||||
}
|
||||
for (let j = 0; j < count; j++) {
|
||||
let left = 10;
|
||||
if (isEven) {
|
||||
if (Math.abs(j - middleIndex) < 1) {
|
||||
left = 10 + middleOffset * getSign(j);
|
||||
} else {
|
||||
left =
|
||||
10 +
|
||||
((Math.ceil(Math.abs(j - middleIndex)) - 1) * (gap + 24) +
|
||||
middleOffset) *
|
||||
getSign(j);
|
||||
}
|
||||
} else {
|
||||
const offset = gap + iconWidth;
|
||||
left = 10 + Math.ceil(Math.abs(j - middleIndex)) * offset * getSign(j);
|
||||
}
|
||||
positions.push([0, left]);
|
||||
}
|
||||
|
||||
return positions;
|
||||
}
|
||||
|
||||
function getIndexLabelTooltip(icon: TemplateResult, content: string) {
|
||||
const styles = css`
|
||||
.index-label-tooltip {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
flex-wrap: nowrap;
|
||||
gap: 10px;
|
||||
}
|
||||
|
||||
.index-label-tooltip-icon {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.index-label-tooltip-content {
|
||||
font-size: var(--affine-font-sm);
|
||||
|
||||
display: flex;
|
||||
height: 16px;
|
||||
line-height: 16px;
|
||||
}
|
||||
`;
|
||||
|
||||
return html`<style>
|
||||
${styles}
|
||||
</style>
|
||||
<div class="index-label-tooltip">
|
||||
<span class="index-label-tooltip-icon">${icon}</span>
|
||||
<span class="index-label-tooltip-content">${content}</span>
|
||||
</div>`;
|
||||
}
|
||||
|
||||
type AutoConnectElement = NoteBlockModel | FrameBlockModel;
|
||||
|
||||
function isAutoConnectElement(element: unknown): element is AutoConnectElement {
|
||||
return (
|
||||
element instanceof NoteBlockModel || element instanceof FrameBlockModel
|
||||
);
|
||||
}
|
||||
|
||||
export const AFFINE_EDGELESS_AUTO_CONNECT_WIDGET =
|
||||
'affine-edgeless-auto-connect-widget';
|
||||
|
||||
export class EdgelessAutoConnectWidget extends WidgetComponent<
|
||||
RootBlockModel,
|
||||
EdgelessRootBlockComponent,
|
||||
EdgelessRootService
|
||||
> {
|
||||
static override styles = css`
|
||||
.page-visible-index-label {
|
||||
box-sizing: border-box;
|
||||
padding: 0px 6px;
|
||||
border: 1px solid #0000001a;
|
||||
|
||||
width: fit-content;
|
||||
height: 24px;
|
||||
min-width: 24px;
|
||||
|
||||
color: var(--affine-white);
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
text-align: center;
|
||||
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
|
||||
border-radius: 25px;
|
||||
background: var(--affine-primary-color);
|
||||
}
|
||||
|
||||
.navigator {
|
||||
width: 48px;
|
||||
padding: 4px;
|
||||
border-radius: 58px;
|
||||
border: 1px solid rgba(227, 226, 228, 1);
|
||||
transition: opacity 0.5s ease-in-out;
|
||||
background: rgba(251, 251, 252, 1);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
opacity: 0;
|
||||
}
|
||||
|
||||
.navigator div {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.navigator span {
|
||||
display: inline-block;
|
||||
height: 8px;
|
||||
border: 1px solid rgba(227, 226, 228, 1);
|
||||
}
|
||||
|
||||
.navigator div:hover {
|
||||
background: var(--affine-hover-color);
|
||||
}
|
||||
|
||||
.navigator.show {
|
||||
opacity: 1;
|
||||
}
|
||||
`;
|
||||
|
||||
private readonly _updateLabels = () => {
|
||||
const service = this.service;
|
||||
if (!service.doc.root) return;
|
||||
|
||||
const pageVisibleBlocks = new Map<AutoConnectElement, number>();
|
||||
const notes = service.doc.root?.children.filter(child =>
|
||||
matchFlavours(child, ['affine:note'])
|
||||
);
|
||||
const edgelessOnlyNotesSet = new Set<NoteBlockModel>();
|
||||
|
||||
notes.forEach(note => {
|
||||
if (isNoteBlock(note)) {
|
||||
if (note.displayMode$.value === NoteDisplayMode.EdgelessOnly) {
|
||||
edgelessOnlyNotesSet.add(note);
|
||||
} else if (note.displayMode$.value === NoteDisplayMode.DocAndEdgeless) {
|
||||
pageVisibleBlocks.set(note, 1);
|
||||
}
|
||||
}
|
||||
|
||||
note.children.forEach(model => {
|
||||
if (matchFlavours(model, ['affine:surface-ref'])) {
|
||||
const reference = service.crud.getElementById(model.reference);
|
||||
|
||||
if (!isAutoConnectElement(reference)) return;
|
||||
|
||||
if (!pageVisibleBlocks.has(reference)) {
|
||||
pageVisibleBlocks.set(reference, 1);
|
||||
} else {
|
||||
pageVisibleBlocks.set(
|
||||
reference,
|
||||
pageVisibleBlocks.get(reference)! + 1
|
||||
);
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
this._edgelessOnlyNotesSet = edgelessOnlyNotesSet;
|
||||
this._pageVisibleElementsMap = pageVisibleBlocks;
|
||||
};
|
||||
|
||||
private _EdgelessOnlyLabels() {
|
||||
const { _edgelessOnlyNotesSet } = this;
|
||||
|
||||
if (!_edgelessOnlyNotesSet.size) return nothing;
|
||||
|
||||
return html`${repeat(
|
||||
_edgelessOnlyNotesSet,
|
||||
note => note.id,
|
||||
note => {
|
||||
const { viewport } = this.service;
|
||||
const { zoom } = viewport;
|
||||
const bound = Bound.deserialize(note.xywh);
|
||||
const [left, right] = viewport.toViewCoord(bound.x, bound.y);
|
||||
const [width, height] = [bound.w * zoom, bound.h * zoom];
|
||||
const style = styleMap({
|
||||
width: `${EDGELESS_ONLY_INDEX_LABEL_WIDTH}px`,
|
||||
height: `${EDGELESS_ONLY_INDEX_LABEL_HEIGHT}px`,
|
||||
borderRadius: '50%',
|
||||
backgroundColor: 'var(--affine-text-secondary-color)',
|
||||
border: '1px solid var(--affine-border-color)',
|
||||
color: 'var(--affine-white)',
|
||||
position: 'absolute',
|
||||
transform: `translate(${
|
||||
left + width / 2 - EDGELESS_ONLY_INDEX_LABEL_WIDTH / 2
|
||||
}px,
|
||||
${right + height + INDEX_LABEL_OFFSET}px)`,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
});
|
||||
|
||||
return html`<div style=${style} class="edgeless-only-index-label">
|
||||
${HiddenIcon}
|
||||
<affine-tooltip tip-position="bottom">
|
||||
${getIndexLabelTooltip(SmallDocIcon, 'Hidden on page')}
|
||||
</affine-tooltip>
|
||||
</div>`;
|
||||
}
|
||||
)}`;
|
||||
}
|
||||
|
||||
private _getElementsAndCounts() {
|
||||
const elements: AutoConnectElement[] = [];
|
||||
const counts: number[] = [];
|
||||
|
||||
for (const [key, value] of this._pageVisibleElementsMap.entries()) {
|
||||
elements.push(key);
|
||||
counts.push(value);
|
||||
}
|
||||
|
||||
return { elements, counts };
|
||||
}
|
||||
|
||||
private _initLabels() {
|
||||
const { service } = this.block;
|
||||
const surfaceRefs = service.doc
|
||||
.getBlocksByFlavour('affine:surface-ref')
|
||||
.map(block => block.model) as SurfaceRefBlockModel[];
|
||||
|
||||
const getVisibility = () => {
|
||||
const { selectedElements } = service.selection;
|
||||
|
||||
if (
|
||||
selectedElements.length === 1 &&
|
||||
!service.selection.editing &&
|
||||
(isNoteBlock(selectedElements[0]) ||
|
||||
surfaceRefs.some(ref => ref.reference === selectedElements[0].id))
|
||||
) {
|
||||
this._show = true;
|
||||
} else {
|
||||
this._show = false;
|
||||
}
|
||||
|
||||
return this._show;
|
||||
};
|
||||
|
||||
this._disposables.add(
|
||||
service.selection.slots.updated.on(() => {
|
||||
getVisibility();
|
||||
})
|
||||
);
|
||||
this._disposables.add(
|
||||
this.doc.slots.blockUpdated.on(payload => {
|
||||
if (payload.flavour === 'affine:surface-ref') {
|
||||
switch (payload.type) {
|
||||
case 'add':
|
||||
surfaceRefs.push(payload.model as SurfaceRefBlockModel);
|
||||
break;
|
||||
case 'delete':
|
||||
{
|
||||
const idx = surfaceRefs.indexOf(
|
||||
payload.model as SurfaceRefBlockModel
|
||||
);
|
||||
if (idx >= 0) {
|
||||
surfaceRefs.splice(idx, 1);
|
||||
}
|
||||
}
|
||||
break;
|
||||
case 'update':
|
||||
if (payload.props.key !== 'reference') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
this.requestUpdate();
|
||||
}
|
||||
})
|
||||
);
|
||||
this._disposables.add(
|
||||
service.surface.elementUpdated.on(payload => {
|
||||
if (
|
||||
payload.props['xywh'] &&
|
||||
surfaceRefs.some(ref => ref.reference === payload.id)
|
||||
) {
|
||||
this.requestUpdate();
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private _navigateToNext() {
|
||||
const { elements } = this._getElementsAndCounts();
|
||||
if (this._index >= elements.length - 1) return;
|
||||
this._index = this._index + 1;
|
||||
const element = elements[this._index];
|
||||
const bound = Bound.deserialize(element.xywh);
|
||||
this.service.selection.set({
|
||||
elements: [element.id],
|
||||
editing: false,
|
||||
});
|
||||
this.service.viewport.setViewportByBound(bound, [80, 80, 80, 80], true);
|
||||
}
|
||||
|
||||
private _navigateToPrev() {
|
||||
const { elements } = this._getElementsAndCounts();
|
||||
if (this._index <= 0) return;
|
||||
this._index = this._index - 1;
|
||||
const element = elements[this._index];
|
||||
const bound = Bound.deserialize(element.xywh);
|
||||
this.service.selection.set({
|
||||
elements: [element.id],
|
||||
editing: false,
|
||||
});
|
||||
this.service.viewport.setViewportByBound(bound, [80, 80, 80, 80], true);
|
||||
}
|
||||
|
||||
private _NavigatorComponent(elements: AutoConnectElement[]) {
|
||||
const { viewport } = this.service;
|
||||
const { zoom } = viewport;
|
||||
const className = `navigator ${this._index >= 0 ? 'show' : 'hidden'}`;
|
||||
const element = elements[this._index];
|
||||
const bound = Bound.deserialize(element.xywh);
|
||||
const [left, right] = viewport.toViewCoord(bound.x, bound.y);
|
||||
const [width, height] = [bound.w * zoom, bound.h * zoom];
|
||||
const navigatorStyle = styleMap({
|
||||
position: 'absolute',
|
||||
transform: `translate(${left + width / 2 - 26}px, ${
|
||||
right + height + 16
|
||||
}px)`,
|
||||
});
|
||||
|
||||
return html`<div class=${className} style=${navigatorStyle}>
|
||||
<div
|
||||
role="button"
|
||||
class="edgeless-auto-connect-previous-button"
|
||||
@pointerdown=${(e: PointerEvent) => {
|
||||
stopPropagation(e);
|
||||
this._navigateToPrev();
|
||||
}}
|
||||
>
|
||||
${AutoConnectLeftIcon}
|
||||
</div>
|
||||
<span></span>
|
||||
<div
|
||||
role="button"
|
||||
class="edgeless-auto-connect-next-button"
|
||||
@pointerdown=${(e: PointerEvent) => {
|
||||
stopPropagation(e);
|
||||
this._navigateToNext();
|
||||
}}
|
||||
>
|
||||
${AutoConnectRightIcon}
|
||||
</div>
|
||||
</div> `;
|
||||
}
|
||||
|
||||
private _PageVisibleIndexLabels(
|
||||
elements: AutoConnectElement[],
|
||||
counts: number[]
|
||||
) {
|
||||
const { viewport } = this.service;
|
||||
const { zoom } = viewport;
|
||||
let index = 0;
|
||||
|
||||
return html`${repeat(
|
||||
elements,
|
||||
element => element.id,
|
||||
(element, i) => {
|
||||
const bound = Bound.deserialize(element.xywh$.value);
|
||||
const [left, right] = viewport.toViewCoord(bound.x, bound.y);
|
||||
const [width, height] = [bound.w * zoom, bound.h * zoom];
|
||||
const style = styleMap({
|
||||
width: `${PAGE_VISIBLE_INDEX_LABEL_WIDTH}px`,
|
||||
maxWidth: `${PAGE_VISIBLE_INDEX_LABEL_WIDTH}px`,
|
||||
height: `${PAGE_VISIBLE_INDEX_LABEL_HEIGHT}px`,
|
||||
position: 'absolute',
|
||||
transform: `translate(${
|
||||
left + width / 2 - PAGE_VISIBLE_INDEX_LABEL_WIDTH / 2
|
||||
}px,
|
||||
${right + height + INDEX_LABEL_OFFSET}px)`,
|
||||
display: 'flex',
|
||||
justifyContent: 'center',
|
||||
alignItems: 'center',
|
||||
});
|
||||
const components: TemplateResult[] = [];
|
||||
const count = counts[i];
|
||||
const initGap = 24 / count - 24;
|
||||
const positions = calculatePosition(
|
||||
initGap,
|
||||
count,
|
||||
PAGE_VISIBLE_INDEX_LABEL_HEIGHT
|
||||
);
|
||||
|
||||
for (let j = 0; j < count; j++) {
|
||||
index++;
|
||||
components.push(html`
|
||||
<div
|
||||
style=${styleMap({
|
||||
position: 'absolute',
|
||||
top: positions[j][0] + 'px',
|
||||
left: positions[j][1] + 'px',
|
||||
transition: 'all 0.1s linear',
|
||||
})}
|
||||
index=${i}
|
||||
class="page-visible-index-label"
|
||||
@pointerdown=${(e: PointerEvent) => {
|
||||
stopPropagation(e);
|
||||
this._index = this._index === i ? -1 : i;
|
||||
}}
|
||||
>
|
||||
${index}
|
||||
<affine-tooltip tip-position="bottom">
|
||||
${getIndexLabelTooltip(SmallDocIcon, 'Page mode index')}
|
||||
</affine-tooltip>
|
||||
</div>
|
||||
`);
|
||||
}
|
||||
|
||||
function updateChildrenPosition(e: MouseEvent, positions: number[][]) {
|
||||
if (!e.target) return;
|
||||
const children = (e.target as HTMLElement).children;
|
||||
(Array.from(children) as HTMLElement[]).forEach((c, index) => {
|
||||
c.style.top = positions[index][0] + 'px';
|
||||
c.style.left = positions[index][1] + 'px';
|
||||
});
|
||||
}
|
||||
|
||||
return html`<div
|
||||
style=${style}
|
||||
@mouseenter=${(e: MouseEvent) => {
|
||||
const positions = calculatePosition(
|
||||
5,
|
||||
count,
|
||||
PAGE_VISIBLE_INDEX_LABEL_HEIGHT
|
||||
);
|
||||
updateChildrenPosition(e, positions);
|
||||
}}
|
||||
@mouseleave=${(e: MouseEvent) => {
|
||||
const positions = calculatePosition(
|
||||
initGap,
|
||||
count,
|
||||
PAGE_VISIBLE_INDEX_LABEL_HEIGHT
|
||||
);
|
||||
updateChildrenPosition(e, positions);
|
||||
}}
|
||||
>
|
||||
${components}
|
||||
</div>`;
|
||||
}
|
||||
)}`;
|
||||
}
|
||||
|
||||
private _setHostStyle() {
|
||||
this.style.position = 'absolute';
|
||||
this.style.top = '0';
|
||||
this.style.left = '0';
|
||||
this.style.zIndex = '1';
|
||||
}
|
||||
|
||||
override connectedCallback(): void {
|
||||
super.connectedCallback();
|
||||
|
||||
this._setHostStyle();
|
||||
this._initLabels();
|
||||
}
|
||||
|
||||
override firstUpdated(): void {
|
||||
const { _disposables, std } = this;
|
||||
const slots = std.get(EdgelessLegacySlotIdentifier);
|
||||
const gfx = std.get(GfxControllerIdentifier);
|
||||
|
||||
_disposables.add(
|
||||
gfx.viewport.viewportUpdated.on(() => {
|
||||
this.requestUpdate();
|
||||
})
|
||||
);
|
||||
|
||||
_disposables.add(
|
||||
gfx.selection.slots.updated.on(() => {
|
||||
const { selectedElements } = gfx.selection;
|
||||
if (
|
||||
!(selectedElements.length === 1 && isNoteBlock(selectedElements[0]))
|
||||
) {
|
||||
this._index = -1;
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
_disposables.add(
|
||||
std.event.add('dragStart', () => {
|
||||
this._dragging = true;
|
||||
})
|
||||
);
|
||||
_disposables.add(
|
||||
std.event.add('dragEnd', () => {
|
||||
this._dragging = false;
|
||||
})
|
||||
);
|
||||
_disposables.add(
|
||||
slots.elementResizeStart.on(() => {
|
||||
this._dragging = true;
|
||||
})
|
||||
);
|
||||
_disposables.add(
|
||||
slots.elementResizeEnd.on(() => {
|
||||
this._dragging = false;
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
override render() {
|
||||
const advancedVisibilityEnabled = this.doc
|
||||
.get(FeatureFlagService)
|
||||
.getFlag('enable_advanced_block_visibility');
|
||||
|
||||
if (!this._show || this._dragging || !advancedVisibilityEnabled) {
|
||||
return nothing;
|
||||
}
|
||||
|
||||
this._updateLabels();
|
||||
|
||||
const { elements, counts } = this._getElementsAndCounts();
|
||||
|
||||
return html`${this._PageVisibleIndexLabels(elements, counts)}
|
||||
${this._EdgelessOnlyLabels()}
|
||||
${this._index >= 0 && this._index < elements.length
|
||||
? this._NavigatorComponent(elements)
|
||||
: nothing} `;
|
||||
}
|
||||
|
||||
@state()
|
||||
private accessor _dragging = false;
|
||||
|
||||
@state()
|
||||
private accessor _edgelessOnlyNotesSet = new Set<NoteBlockModel>();
|
||||
|
||||
@state()
|
||||
private accessor _index = -1;
|
||||
|
||||
@state()
|
||||
private accessor _pageVisibleElementsMap: Map<AutoConnectElement, number> =
|
||||
new Map();
|
||||
|
||||
@state()
|
||||
private accessor _show = false;
|
||||
}
|
||||
|
||||
declare global {
|
||||
interface HTMLElementTagNameMap {
|
||||
'affine-edgeless-auto-connect-widget': EdgelessAutoConnectWidget;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
import type { BuiltInEmbedModel } from '@blocksuite/affine-block-bookmark';
|
||||
import { isNoteBlock } from '@blocksuite/affine-block-surface';
|
||||
import { ConnectorCWithArrowIcon } from '@blocksuite/affine-components/icons';
|
||||
import {
|
||||
cloneGroups,
|
||||
@@ -47,7 +48,6 @@ import {
|
||||
isEmbeddedBlock,
|
||||
isFrameBlock,
|
||||
isImageBlock,
|
||||
isNoteBlock,
|
||||
} from '../../edgeless/utils/query.js';
|
||||
import { renderAddFrameButton } from './add-frame-button.js';
|
||||
import { renderAddGroupButton } from './add-group-button.js';
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
import type { SurfaceBlockComponent } from '@blocksuite/affine-block-surface';
|
||||
import {
|
||||
isNoteBlock,
|
||||
type SurfaceBlockComponent,
|
||||
} from '@blocksuite/affine-block-surface';
|
||||
import { MenuContext } from '@blocksuite/affine-components/toolbar';
|
||||
import { getSelectedModelsCommand } from '@blocksuite/affine-shared/commands';
|
||||
import {
|
||||
@@ -17,7 +20,6 @@ import {
|
||||
isEmbedSyncedDocBlock,
|
||||
isFrameBlock,
|
||||
isImageBlock,
|
||||
isNoteBlock,
|
||||
} from '../../../edgeless/utils/query.js';
|
||||
|
||||
export class ElementToolbarMoreMenuContext extends MenuContext {
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { getSurfaceBlock } from '@blocksuite/affine-block-surface';
|
||||
import { getSurfaceBlock, isNoteBlock } from '@blocksuite/affine-block-surface';
|
||||
import type { FrameBlockModel, NoteBlockModel } from '@blocksuite/affine-model';
|
||||
import { NoteDisplayMode } from '@blocksuite/affine-model';
|
||||
import { DocModeProvider } from '@blocksuite/affine-shared/services';
|
||||
@@ -12,7 +12,7 @@ import {
|
||||
mapFrameIds,
|
||||
sortEdgelessElements,
|
||||
} from '../../../edgeless/utils/clone-utils.js';
|
||||
import { isFrameBlock, isNoteBlock } from '../../../edgeless/utils/query.js';
|
||||
import { isFrameBlock } from '../../../edgeless/utils/query.js';
|
||||
|
||||
function addBlocksToDoc(targetDoc: Store, model: BlockModel, parentId: string) {
|
||||
// Add current block to linked doc
|
||||
|
||||
Reference in New Issue
Block a user