@refrakt-md/editor 0.7.2 → 0.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/app/dist/assets/{index-4SP4_AaD.js → index-BBinZAiy.js} +1 -1
- package/app/dist/assets/index-BD2EBUrQ.css +1 -0
- package/app/dist/assets/{index-D77rckeh.js → index-BLuaHLN3.js} +1 -1
- package/app/dist/assets/{index-30gAspk8.js → index-BgCNqcSo.js} +1 -1
- package/app/dist/assets/index-BlAOhWAQ.js +453 -0
- package/app/dist/assets/{index-BZ4adnS0.js → index-BwFn9q4x.js} +1 -1
- package/app/dist/assets/{index-DFkteo0w.js → index-C72UC2ga.js} +1 -1
- package/app/dist/assets/{index-x67KGOIr.js → index-COIPZ34u.js} +1 -1
- package/app/dist/assets/{index-BEFUVB_B.js → index-CW02bulk.js} +1 -1
- package/app/dist/assets/{index-CI5PewQM.js → index-CXFMPmtf.js} +1 -1
- package/app/dist/assets/{index-ByHhigzw.js → index-CeU_s7BB.js} +1 -1
- package/app/dist/assets/{index-DvgOtlru.js → index-CqHjo2YT.js} +1 -1
- package/app/dist/assets/{index-DKnhR16N.js → index-D3TQo8gu.js} +1 -1
- package/app/dist/assets/{index-Baf7ZSct.js → index-DVM3uoxc.js} +1 -1
- package/app/dist/assets/{index-C9w1RpYY.js → index-DW2zI-Ss.js} +1 -1
- package/app/dist/assets/{index--rGC9bba.js → index-D_Y6J00B.js} +1 -1
- package/app/dist/assets/{index-kPhFxtn-.js → index-DgIg-QAA.js} +2 -2
- package/app/dist/assets/{index-DIuFNfTc.js → index-DmY6uqAw.js} +1 -1
- package/app/dist/assets/{index-D1WOi3EN.js → index-DzHt8ZRh.js} +1 -1
- package/app/dist/assets/{index-BwWzfQVn.js → index-ZLvRNfLb.js} +1 -1
- package/app/dist/index.html +2 -2
- package/app/src/lib/api/client.ts +49 -0
- package/app/src/lib/components/ActionEditPopover.svelte +245 -0
- package/app/src/lib/components/BlockCard.svelte +255 -1
- package/app/src/lib/components/BlockEditPanel.svelte +697 -138
- package/app/src/lib/components/BlockEditor.svelte +467 -389
- package/app/src/lib/components/CodeEditPopover.svelte +226 -0
- package/app/src/lib/components/ContentModelTree.svelte +562 -0
- package/app/src/lib/components/ContentTree.svelte +181 -0
- package/app/src/lib/components/EditorLayout.svelte +1 -6
- package/app/src/lib/components/FrontmatterEditPanel.svelte +0 -1
- package/app/src/lib/components/HeaderBar.svelte +38 -0
- package/app/src/lib/components/InlineEditPopover.svelte +593 -0
- package/app/src/lib/components/InsertBlockDialog.svelte +429 -0
- package/app/src/lib/components/PageCard.svelte +3 -4
- package/app/src/lib/components/PreviewPane.svelte +19 -1
- package/app/src/lib/components/RuneAttributes.svelte +249 -100
- package/app/src/lib/editor/block-parser.ts +463 -0
- package/app/src/lib/preview/block-renderer.ts +30 -14
- package/dist/community-tags-builder.d.ts.map +1 -1
- package/dist/community-tags-builder.js +5 -1
- package/dist/community-tags-builder.js.map +1 -1
- package/dist/server.d.ts +1 -0
- package/dist/server.d.ts.map +1 -1
- package/dist/server.js +92 -6
- package/dist/server.js.map +1 -1
- package/package.json +6 -6
- package/preview-runtime/App.svelte +2 -0
- package/app/dist/assets/index-DlrXwdpb.css +0 -1
- package/app/dist/assets/index-GlUHQ_jL.js +0 -324
|
@@ -8,12 +8,21 @@
|
|
|
8
8
|
buildRuneMap,
|
|
9
9
|
blockLabel,
|
|
10
10
|
extractRuneInner,
|
|
11
|
+
rebuildRuneSource,
|
|
11
12
|
type ParsedBlock,
|
|
13
|
+
type RuneBlock,
|
|
12
14
|
} from '../editor/block-parser.js';
|
|
15
|
+
import { findSectionMapping, applySectionEdit, findActionMapping, applyActionEdit, findCommandMapping, applyCommandEdit, type SectionMapping, type ActionMapping, type CommandMapping } from '../editor/section-mapper.js';
|
|
16
|
+
import { stripInlineMarkdown } from '../editor/inline-markdown.js';
|
|
13
17
|
import { editorState } from '../state/editor.svelte.js';
|
|
14
18
|
import BlockCard from './BlockCard.svelte';
|
|
19
|
+
import type { SectionClickInfo } from './BlockCard.svelte';
|
|
15
20
|
import BlockEditPanel from './BlockEditPanel.svelte';
|
|
16
21
|
import FrontmatterEditPanel from './FrontmatterEditPanel.svelte';
|
|
22
|
+
import InsertBlockDialog from './InsertBlockDialog.svelte';
|
|
23
|
+
import InlineEditPopover from './InlineEditPopover.svelte';
|
|
24
|
+
import ActionEditPopover from './ActionEditPopover.svelte';
|
|
25
|
+
import CodeEditPopover from './CodeEditPopover.svelte';
|
|
17
26
|
|
|
18
27
|
interface Props {
|
|
19
28
|
bodyContent: string;
|
|
@@ -28,6 +37,7 @@
|
|
|
28
37
|
readOnly?: boolean;
|
|
29
38
|
communityTags?: Record<string, unknown> | null;
|
|
30
39
|
communityPostTransforms?: Record<string, Function> | null;
|
|
40
|
+
communityStyles?: Record<string, Record<string, unknown>> | null;
|
|
31
41
|
aggregated?: Record<string, unknown>;
|
|
32
42
|
}
|
|
33
43
|
|
|
@@ -44,6 +54,7 @@
|
|
|
44
54
|
readOnly = false,
|
|
45
55
|
communityTags = null,
|
|
46
56
|
communityPostTransforms = null,
|
|
57
|
+
communityStyles = null,
|
|
47
58
|
aggregated = {},
|
|
48
59
|
}: Props = $props();
|
|
49
60
|
|
|
@@ -96,17 +107,14 @@
|
|
|
96
107
|
reconcileIds(blocks, newBlocks);
|
|
97
108
|
blocks = newBlocks;
|
|
98
109
|
lastParsedSource = body;
|
|
99
|
-
// Close edit panel when switching files
|
|
110
|
+
// Close edit panel and inline popover when switching files
|
|
100
111
|
activeIndex = null;
|
|
112
|
+
editingFrontmatter = false;
|
|
113
|
+
anchorPoint = null;
|
|
114
|
+
inlineEdit = null;
|
|
101
115
|
}
|
|
102
116
|
});
|
|
103
117
|
|
|
104
|
-
// Sync edit panel open state to global state (for layout adjustments)
|
|
105
|
-
$effect(() => {
|
|
106
|
-
editorState.editPanelOpen = !readOnly && (activeIndex !== null || editingFrontmatter);
|
|
107
|
-
return () => { editorState.editPanelOpen = false; };
|
|
108
|
-
});
|
|
109
|
-
|
|
110
118
|
/** Sync blocks back to source text */
|
|
111
119
|
function syncToSource() {
|
|
112
120
|
const newSource = serializeBlocks(blocks);
|
|
@@ -126,29 +134,99 @@
|
|
|
126
134
|
// ── Active block (rail selection) ────────────────────────────
|
|
127
135
|
|
|
128
136
|
let activeIndex: number | null = $state(null);
|
|
137
|
+
let hoveredIndex: number | null = $state(null);
|
|
138
|
+
let anchorPoint: { x: number; y: number } | null = $state(null);
|
|
139
|
+
let pendingRuneIndex: number | null = $state(null);
|
|
140
|
+
let editSessionId: number = $state(0);
|
|
141
|
+
|
|
142
|
+
// ── Popover positioning ─────────────────────────────────────
|
|
143
|
+
|
|
144
|
+
const POPOVER_WIDTH = 420;
|
|
145
|
+
const POPOVER_GAP = 12;
|
|
129
146
|
|
|
130
|
-
|
|
147
|
+
let popoverStyle = $derived.by(() => {
|
|
148
|
+
if (!anchorPoint) return '';
|
|
149
|
+
|
|
150
|
+
const vw = window.innerWidth;
|
|
151
|
+
const vh = window.innerHeight;
|
|
152
|
+
|
|
153
|
+
// Prefer placing to the right of the click point
|
|
154
|
+
let left = anchorPoint.x + POPOVER_GAP;
|
|
155
|
+
if (left + POPOVER_WIDTH > vw - 16) {
|
|
156
|
+
left = anchorPoint.x - POPOVER_WIDTH - POPOVER_GAP;
|
|
157
|
+
}
|
|
158
|
+
if (left < 16) {
|
|
159
|
+
left = vw - POPOVER_WIDTH - 16;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Vertical: start at click Y, clamped to viewport
|
|
163
|
+
let top = anchorPoint.y;
|
|
164
|
+
const maxH = vh - 120;
|
|
165
|
+
const maxTop = vh - Math.min(600, maxH) - 16;
|
|
166
|
+
if (top > maxTop) top = maxTop;
|
|
167
|
+
if (top < 60) top = 60;
|
|
168
|
+
|
|
169
|
+
return `left: ${left}px; top: ${top}px; max-height: min(600px, ${maxH}px);`;
|
|
170
|
+
});
|
|
171
|
+
|
|
172
|
+
function toggleBlock(index: number, x: number, y: number) {
|
|
131
173
|
editingFrontmatter = false;
|
|
132
|
-
|
|
174
|
+
if (activeIndex === index) {
|
|
175
|
+
activeIndex = null;
|
|
176
|
+
anchorPoint = null;
|
|
177
|
+
pendingRuneIndex = null;
|
|
178
|
+
} else {
|
|
179
|
+
editSessionId++;
|
|
180
|
+
activeIndex = index;
|
|
181
|
+
anchorPoint = { x, y };
|
|
182
|
+
pendingRuneIndex = null;
|
|
183
|
+
}
|
|
133
184
|
}
|
|
134
185
|
|
|
135
|
-
function
|
|
186
|
+
function handleRuneClick(index: number, x: number, y: number, nestedRuneIndex?: number) {
|
|
187
|
+
editingFrontmatter = false;
|
|
188
|
+
editSessionId++;
|
|
189
|
+
activeIndex = index;
|
|
190
|
+
anchorPoint = { x, y };
|
|
191
|
+
pendingRuneIndex = nestedRuneIndex ?? null;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
function toggleFrontmatter(e: MouseEvent) {
|
|
136
195
|
activeIndex = null;
|
|
137
|
-
editingFrontmatter
|
|
196
|
+
if (editingFrontmatter) {
|
|
197
|
+
editingFrontmatter = false;
|
|
198
|
+
anchorPoint = null;
|
|
199
|
+
} else {
|
|
200
|
+
editingFrontmatter = true;
|
|
201
|
+
anchorPoint = { x: e.clientX, y: e.clientY };
|
|
202
|
+
}
|
|
138
203
|
}
|
|
139
204
|
|
|
140
205
|
function handleKeydown(e: KeyboardEvent) {
|
|
141
206
|
if (readOnly) return;
|
|
142
207
|
if (e.key === 'Escape') {
|
|
143
|
-
if (
|
|
144
|
-
closeInsertMenu();
|
|
145
|
-
} else if (activeIndex !== null || editingFrontmatter) {
|
|
208
|
+
if (activeIndex !== null || editingFrontmatter) {
|
|
146
209
|
activeIndex = null;
|
|
147
210
|
editingFrontmatter = false;
|
|
211
|
+
anchorPoint = null;
|
|
212
|
+
pendingRuneIndex = null;
|
|
148
213
|
}
|
|
149
214
|
}
|
|
150
215
|
}
|
|
151
216
|
|
|
217
|
+
function handleListScroll() {
|
|
218
|
+
if (activeIndex !== null || editingFrontmatter) {
|
|
219
|
+
activeIndex = null;
|
|
220
|
+
editingFrontmatter = false;
|
|
221
|
+
anchorPoint = null;
|
|
222
|
+
pendingRuneIndex = null;
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
function handleResize() {
|
|
227
|
+
if (anchorPoint) anchorPoint = { ...anchorPoint };
|
|
228
|
+
}
|
|
229
|
+
|
|
152
230
|
// ── Block operations ─────────────────────────────────────────
|
|
153
231
|
|
|
154
232
|
function handleUpdateBlock(index: number, updated: ParsedBlock) {
|
|
@@ -176,6 +254,9 @@
|
|
|
176
254
|
|
|
177
255
|
function handleDragStart(e: DragEvent, index: number) {
|
|
178
256
|
dragIndex = index;
|
|
257
|
+
activeIndex = null;
|
|
258
|
+
editingFrontmatter = false;
|
|
259
|
+
anchorPoint = null;
|
|
179
260
|
if (e.dataTransfer) {
|
|
180
261
|
e.dataTransfer.effectAllowed = 'move';
|
|
181
262
|
e.dataTransfer.setData('text/plain', String(index));
|
|
@@ -235,13 +316,6 @@
|
|
|
235
316
|
insertAtIndex = null;
|
|
236
317
|
}
|
|
237
318
|
|
|
238
|
-
function handleClickOutside(e: MouseEvent) {
|
|
239
|
-
if (!showInsertMenu) return;
|
|
240
|
-
const target = e.target as HTMLElement;
|
|
241
|
-
if (target.closest('.insert-menu--floating') || target.closest('.block-editor__insert-dot')) return;
|
|
242
|
-
closeInsertMenu();
|
|
243
|
-
}
|
|
244
|
-
|
|
245
319
|
function insertBlock(type: 'heading' | 'paragraph' | 'fence' | 'hr' | 'rune', runeName?: string) {
|
|
246
320
|
let newBlock: ParsedBlock;
|
|
247
321
|
const id = `blk_new_${Date.now()}`;
|
|
@@ -343,6 +417,182 @@
|
|
|
343
417
|
syncToSource();
|
|
344
418
|
}
|
|
345
419
|
|
|
420
|
+
// ── Inline section editing ──────────────────────────────────
|
|
421
|
+
|
|
422
|
+
let inlineEdit: {
|
|
423
|
+
blockIndex: number;
|
|
424
|
+
dataName: string;
|
|
425
|
+
inlineSource: string;
|
|
426
|
+
rect: DOMRect;
|
|
427
|
+
mapping: SectionMapping;
|
|
428
|
+
} | null = $state(null);
|
|
429
|
+
|
|
430
|
+
function handleSectionClick(index: number, info: SectionClickInfo) {
|
|
431
|
+
const block = blocks[index];
|
|
432
|
+
if (block.type !== 'rune') return;
|
|
433
|
+
const rb = block as RuneBlock;
|
|
434
|
+
|
|
435
|
+
if (info.editType === 'link') {
|
|
436
|
+
const mapping = findActionMapping(rb.innerContent, info.text, info.href ?? '');
|
|
437
|
+
if (!mapping) return;
|
|
438
|
+
|
|
439
|
+
actionEdit = {
|
|
440
|
+
blockIndex: index,
|
|
441
|
+
rect: info.rect,
|
|
442
|
+
mapping,
|
|
443
|
+
};
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (info.editType === 'code') {
|
|
448
|
+
const mapping = findCommandMapping(rb.innerContent, info.text);
|
|
449
|
+
if (!mapping) return;
|
|
450
|
+
|
|
451
|
+
commandEdit = {
|
|
452
|
+
blockIndex: index,
|
|
453
|
+
rect: info.rect,
|
|
454
|
+
mapping,
|
|
455
|
+
};
|
|
456
|
+
return;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
// Default: inline text editing
|
|
460
|
+
const mapping = findSectionMapping(rb.innerContent, info.dataName, info.text);
|
|
461
|
+
if (!mapping) return;
|
|
462
|
+
|
|
463
|
+
inlineEdit = {
|
|
464
|
+
blockIndex: index,
|
|
465
|
+
dataName: info.dataName,
|
|
466
|
+
inlineSource: mapping.inlineSource,
|
|
467
|
+
rect: info.rect,
|
|
468
|
+
mapping,
|
|
469
|
+
};
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
function handleInlineEditChange(newInlineSource: string) {
|
|
473
|
+
if (!inlineEdit) return;
|
|
474
|
+
const block = blocks[inlineEdit.blockIndex];
|
|
475
|
+
if (block.type !== 'rune') return;
|
|
476
|
+
const rb = block as RuneBlock;
|
|
477
|
+
|
|
478
|
+
const newInner = applySectionEdit(rb.innerContent, inlineEdit.mapping, newInlineSource);
|
|
479
|
+
const updated: RuneBlock = { ...rb, innerContent: newInner, source: '' };
|
|
480
|
+
updated.source = rebuildRuneSource(updated);
|
|
481
|
+
|
|
482
|
+
// Update the mapping to reflect the new source so subsequent edits work
|
|
483
|
+
inlineEdit = {
|
|
484
|
+
...inlineEdit,
|
|
485
|
+
inlineSource: newInlineSource,
|
|
486
|
+
mapping: {
|
|
487
|
+
...inlineEdit.mapping,
|
|
488
|
+
text: stripInlineMarkdown(newInlineSource),
|
|
489
|
+
source: inlineEdit.mapping.sourcePrefix + newInlineSource,
|
|
490
|
+
inlineSource: newInlineSource,
|
|
491
|
+
},
|
|
492
|
+
};
|
|
493
|
+
|
|
494
|
+
handleUpdateBlock(inlineEdit.blockIndex, updated);
|
|
495
|
+
}
|
|
496
|
+
|
|
497
|
+
function closeInlineEdit() {
|
|
498
|
+
inlineEdit = null;
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
// ── Action item editing ────────────────────────────────────
|
|
502
|
+
|
|
503
|
+
let actionEdit: {
|
|
504
|
+
blockIndex: number;
|
|
505
|
+
rect: DOMRect;
|
|
506
|
+
mapping: ActionMapping;
|
|
507
|
+
} | null = $state(null);
|
|
508
|
+
|
|
509
|
+
function handleActionEditChange(newText: string, newHref: string) {
|
|
510
|
+
if (!actionEdit) return;
|
|
511
|
+
const block = blocks[actionEdit.blockIndex];
|
|
512
|
+
if (block.type !== 'rune') return;
|
|
513
|
+
const rb = block as RuneBlock;
|
|
514
|
+
|
|
515
|
+
const newInner = applyActionEdit(rb.innerContent, actionEdit.mapping, newText, newHref);
|
|
516
|
+
const updated: RuneBlock = { ...rb, innerContent: newInner, source: '' };
|
|
517
|
+
updated.source = rebuildRuneSource(updated);
|
|
518
|
+
|
|
519
|
+
handleUpdateBlock(actionEdit.blockIndex, updated);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function handleActionRemove() {
|
|
523
|
+
if (!actionEdit) return;
|
|
524
|
+
const blockIndex = actionEdit.blockIndex;
|
|
525
|
+
const block = blocks[blockIndex];
|
|
526
|
+
if (block.type !== 'rune') return;
|
|
527
|
+
const rb = block as RuneBlock;
|
|
528
|
+
|
|
529
|
+
// Remove the entire list item line from the inner content
|
|
530
|
+
const newInner = rb.innerContent.replace(actionEdit.mapping.source + '\n', '').replace(actionEdit.mapping.source, '');
|
|
531
|
+
const updated: RuneBlock = { ...rb, innerContent: newInner, source: '' };
|
|
532
|
+
updated.source = rebuildRuneSource(updated);
|
|
533
|
+
|
|
534
|
+
actionEdit = null;
|
|
535
|
+
handleUpdateBlock(blockIndex, updated);
|
|
536
|
+
}
|
|
537
|
+
|
|
538
|
+
function closeActionEdit() {
|
|
539
|
+
actionEdit = null;
|
|
540
|
+
}
|
|
541
|
+
|
|
542
|
+
// ── Command (code block) editing ──────────────────────────
|
|
543
|
+
|
|
544
|
+
let commandEdit: {
|
|
545
|
+
blockIndex: number;
|
|
546
|
+
rect: DOMRect;
|
|
547
|
+
mapping: CommandMapping;
|
|
548
|
+
} | null = $state(null);
|
|
549
|
+
|
|
550
|
+
function handleCommandEditChange(newCode: string) {
|
|
551
|
+
if (!commandEdit) return;
|
|
552
|
+
const block = blocks[commandEdit.blockIndex];
|
|
553
|
+
if (block.type !== 'rune') return;
|
|
554
|
+
const rb = block as RuneBlock;
|
|
555
|
+
|
|
556
|
+
const newInner = applyCommandEdit(rb.innerContent, commandEdit.mapping, newCode);
|
|
557
|
+
const updated: RuneBlock = { ...rb, innerContent: newInner, source: '' };
|
|
558
|
+
updated.source = rebuildRuneSource(updated);
|
|
559
|
+
|
|
560
|
+
handleUpdateBlock(commandEdit.blockIndex, updated);
|
|
561
|
+
}
|
|
562
|
+
|
|
563
|
+
function handleCommandRemove() {
|
|
564
|
+
if (!commandEdit) return;
|
|
565
|
+
const blockIndex = commandEdit.blockIndex;
|
|
566
|
+
const block = blocks[blockIndex];
|
|
567
|
+
if (block.type !== 'rune') return;
|
|
568
|
+
const rb = block as RuneBlock;
|
|
569
|
+
|
|
570
|
+
// Remove the entire fenced code block from the inner content
|
|
571
|
+
const newInner = rb.innerContent.replace(commandEdit.mapping.source + '\n', '').replace(commandEdit.mapping.source, '');
|
|
572
|
+
const updated: RuneBlock = { ...rb, innerContent: newInner, source: '' };
|
|
573
|
+
updated.source = rebuildRuneSource(updated);
|
|
574
|
+
|
|
575
|
+
commandEdit = null;
|
|
576
|
+
handleUpdateBlock(blockIndex, updated);
|
|
577
|
+
}
|
|
578
|
+
|
|
579
|
+
function closeCommandEdit() {
|
|
580
|
+
commandEdit = null;
|
|
581
|
+
}
|
|
582
|
+
|
|
583
|
+
// ── Field edit from Structure tab ──────────────────────────────
|
|
584
|
+
|
|
585
|
+
function handleFieldEdit(dataName: string, inlineSource: string, rect: DOMRect, mapping: SectionMapping) {
|
|
586
|
+
if (activeIndex === null) return;
|
|
587
|
+
inlineEdit = {
|
|
588
|
+
blockIndex: activeIndex,
|
|
589
|
+
dataName,
|
|
590
|
+
inlineSource,
|
|
591
|
+
rect,
|
|
592
|
+
mapping,
|
|
593
|
+
};
|
|
594
|
+
}
|
|
595
|
+
|
|
346
596
|
// Group runes by category for the insert menu
|
|
347
597
|
let runesByCategory = $derived.by(() => {
|
|
348
598
|
const map = new Map<string, RuneInfo[]>();
|
|
@@ -355,7 +605,7 @@
|
|
|
355
605
|
});
|
|
356
606
|
</script>
|
|
357
607
|
|
|
358
|
-
<svelte:window onkeydown={handleKeydown}
|
|
608
|
+
<svelte:window onkeydown={handleKeydown} onresize={handleResize} />
|
|
359
609
|
|
|
360
610
|
<div class="block-editor">
|
|
361
611
|
{#if blocks.length === 0 && !readOnly}
|
|
@@ -367,14 +617,14 @@
|
|
|
367
617
|
<line x1="14" y1="30" x2="22" y2="30" />
|
|
368
618
|
</svg>
|
|
369
619
|
<span class="block-editor__empty-text">No content blocks yet</span>
|
|
370
|
-
<span class="block-editor__empty-hint">
|
|
620
|
+
<span class="block-editor__empty-hint">Use the + button to add your first block</span>
|
|
371
621
|
</div>
|
|
372
622
|
{/if}
|
|
373
623
|
|
|
374
|
-
<div class="block-editor__stage"
|
|
375
|
-
<!-- Scrollable list
|
|
376
|
-
<div class="block-editor__scroll"
|
|
377
|
-
<div class="block-editor__list-wrap">
|
|
624
|
+
<div class="block-editor__stage">
|
|
625
|
+
<!-- Scrollable block list -->
|
|
626
|
+
<div class="block-editor__scroll">
|
|
627
|
+
<div class="block-editor__list-wrap" onscroll={handleListScroll}>
|
|
378
628
|
<!-- Frontmatter summary header (blocks mode only) -->
|
|
379
629
|
{#if !readOnly}
|
|
380
630
|
<div class="block-editor__fm-header">
|
|
@@ -387,7 +637,7 @@
|
|
|
387
637
|
<button
|
|
388
638
|
class="block-editor__fm-edit"
|
|
389
639
|
class:active={editingFrontmatter}
|
|
390
|
-
onclick={toggleFrontmatter}
|
|
640
|
+
onclick={(e) => toggleFrontmatter(e)}
|
|
391
641
|
title="Edit frontmatter"
|
|
392
642
|
>
|
|
393
643
|
<svg width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
@@ -398,90 +648,15 @@
|
|
|
398
648
|
</div>
|
|
399
649
|
{/if}
|
|
400
650
|
|
|
401
|
-
{#snippet insertMenuContent()}
|
|
402
|
-
<div class="insert-menu__section">
|
|
403
|
-
<span class="insert-menu__label">Content</span>
|
|
404
|
-
<div class="insert-menu__grid">
|
|
405
|
-
<button class="insert-menu__btn" onclick={() => insertBlock('heading')}>
|
|
406
|
-
<svg class="insert-menu__icon" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
|
|
407
|
-
<path d="M3 3v10M13 3v10M3 8h10" />
|
|
408
|
-
</svg>
|
|
409
|
-
Heading
|
|
410
|
-
</button>
|
|
411
|
-
<button class="insert-menu__btn" onclick={() => insertBlock('paragraph')}>
|
|
412
|
-
<svg class="insert-menu__icon" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
|
|
413
|
-
<line x1="2" y1="4" x2="14" y2="4" />
|
|
414
|
-
<line x1="2" y1="8" x2="14" y2="8" />
|
|
415
|
-
<line x1="2" y1="12" x2="10" y2="12" />
|
|
416
|
-
</svg>
|
|
417
|
-
Paragraph
|
|
418
|
-
</button>
|
|
419
|
-
<button class="insert-menu__btn" onclick={() => insertBlock('fence')}>
|
|
420
|
-
<svg class="insert-menu__icon" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round">
|
|
421
|
-
<polyline points="5 4 2 8 5 12" />
|
|
422
|
-
<polyline points="11 4 14 8 11 12" />
|
|
423
|
-
</svg>
|
|
424
|
-
Code Block
|
|
425
|
-
</button>
|
|
426
|
-
<button class="insert-menu__btn" onclick={() => insertBlock('hr')}>
|
|
427
|
-
<svg class="insert-menu__icon" width="14" height="14" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
|
|
428
|
-
<line x1="2" y1="8" x2="14" y2="8" />
|
|
429
|
-
</svg>
|
|
430
|
-
Divider
|
|
431
|
-
</button>
|
|
432
|
-
</div>
|
|
433
|
-
</div>
|
|
434
|
-
{#each [...runesByCategory.entries()] as [category, categoryRunes]}
|
|
435
|
-
<div class="insert-menu__section">
|
|
436
|
-
<span class="insert-menu__label">{category}</span>
|
|
437
|
-
<div class="insert-menu__grid">
|
|
438
|
-
{#each categoryRunes as rune}
|
|
439
|
-
<button
|
|
440
|
-
class="insert-menu__btn insert-menu__btn--rune"
|
|
441
|
-
onclick={() => insertBlock('rune', rune.name)}
|
|
442
|
-
>
|
|
443
|
-
<span class="insert-menu__rune-dot"></span>
|
|
444
|
-
<span class="insert-menu__rune-info">
|
|
445
|
-
<span class="insert-menu__rune-name">{rune.name}</span>
|
|
446
|
-
{#if rune.description}
|
|
447
|
-
<span class="insert-menu__rune-desc">{rune.description}</span>
|
|
448
|
-
{/if}
|
|
449
|
-
</span>
|
|
450
|
-
</button>
|
|
451
|
-
{/each}
|
|
452
|
-
</div>
|
|
453
|
-
</div>
|
|
454
|
-
{/each}
|
|
455
|
-
<button class="insert-menu__close" onclick={closeInsertMenu}>× Close</button>
|
|
456
|
-
{/snippet}
|
|
457
|
-
|
|
458
|
-
{#snippet insertZone(pos: number)}
|
|
459
|
-
<div class="block-editor__insert-zone">
|
|
460
|
-
<div class="block-editor__insert-zone-spacer"></div>
|
|
461
|
-
<button
|
|
462
|
-
class="block-editor__insert-dot"
|
|
463
|
-
onclick={() => openInsertAt(pos)}
|
|
464
|
-
title="Insert block"
|
|
465
|
-
>
|
|
466
|
-
<span class="block-editor__dot-icon"></span>
|
|
467
|
-
</button>
|
|
468
|
-
{#if showInsertMenu && insertAtIndex === pos}
|
|
469
|
-
<div class="insert-menu insert-menu--floating">
|
|
470
|
-
{@render insertMenuContent()}
|
|
471
|
-
</div>
|
|
472
|
-
{/if}
|
|
473
|
-
</div>
|
|
474
|
-
{/snippet}
|
|
475
|
-
|
|
476
|
-
{#if !readOnly && showInsertMenuProp}
|
|
477
|
-
{@render insertZone(0)}
|
|
478
|
-
{/if}
|
|
479
|
-
|
|
480
651
|
{#each blocks as block, i (block.id)}
|
|
481
652
|
<div
|
|
482
653
|
class="block-editor__row"
|
|
654
|
+
class:hovered={!readOnly && hoveredIndex === i}
|
|
655
|
+
class:active={!readOnly && activeIndex === i}
|
|
483
656
|
class:drag-source={!readOnly && dragIndex === i}
|
|
484
657
|
class:drag-over={!readOnly && dropIndex === i && dragIndex !== i}
|
|
658
|
+
onmouseenter={() => { if (!readOnly) hoveredIndex = i; }}
|
|
659
|
+
onmouseleave={() => { if (!readOnly && hoveredIndex === i) hoveredIndex = null; }}
|
|
485
660
|
>
|
|
486
661
|
<div class="block-editor__block-cell">
|
|
487
662
|
<BlockCard
|
|
@@ -492,51 +667,126 @@
|
|
|
492
667
|
{highlightTransform}
|
|
493
668
|
{communityTags}
|
|
494
669
|
{communityPostTransforms}
|
|
670
|
+
{communityStyles}
|
|
495
671
|
{aggregated}
|
|
672
|
+
{readOnly}
|
|
673
|
+
onsectionclick={readOnly ? undefined : (info) => handleSectionClick(i, info)}
|
|
674
|
+
onruneclick={readOnly ? undefined : (info) => handleRuneClick(i, info.x, info.y, info.nestedRuneIndex)}
|
|
496
675
|
ondragstart={readOnly ? undefined : (e) => handleDragStart(e, i)}
|
|
497
676
|
ondragover={readOnly ? undefined : (e) => handleDragOver(e, i)}
|
|
498
677
|
ondrop={readOnly ? undefined : (e) => handleDrop(e, i)}
|
|
499
678
|
/>
|
|
500
679
|
</div>
|
|
680
|
+
{#if !readOnly && showInsertMenuProp}
|
|
681
|
+
<!-- Insert markers — top and bottom edges -->
|
|
682
|
+
<button
|
|
683
|
+
class="block-editor__insert-marker block-editor__insert-marker--top"
|
|
684
|
+
onclick={() => openInsertAt(i)}
|
|
685
|
+
title="Insert block above"
|
|
686
|
+
>
|
|
687
|
+
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
|
|
688
|
+
<line x1="5" y1="2" x2="5" y2="8" />
|
|
689
|
+
<line x1="2" y1="5" x2="8" y2="5" />
|
|
690
|
+
</svg>
|
|
691
|
+
</button>
|
|
692
|
+
<button
|
|
693
|
+
class="block-editor__insert-marker block-editor__insert-marker--bottom"
|
|
694
|
+
onclick={() => openInsertAt(i + 1)}
|
|
695
|
+
title="Insert block below"
|
|
696
|
+
>
|
|
697
|
+
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round">
|
|
698
|
+
<line x1="5" y1="2" x2="5" y2="8" />
|
|
699
|
+
<line x1="2" y1="5" x2="8" y2="5" />
|
|
700
|
+
</svg>
|
|
701
|
+
</button>
|
|
702
|
+
{/if}
|
|
501
703
|
{#if !readOnly}
|
|
704
|
+
<!-- Block label — slides in from right on hover, pinned when active -->
|
|
502
705
|
<button
|
|
503
|
-
class="block-
|
|
504
|
-
|
|
505
|
-
onclick={() => toggleBlock(i)}
|
|
706
|
+
class="block-editor__hover-label"
|
|
707
|
+
onclick={(e) => toggleBlock(i, e.clientX, e.clientY)}
|
|
506
708
|
aria-pressed={activeIndex === i}
|
|
507
709
|
>
|
|
508
710
|
{blockLabel(block)}
|
|
509
711
|
</button>
|
|
510
712
|
{/if}
|
|
511
713
|
</div>
|
|
512
|
-
{#if !readOnly && showInsertMenuProp}
|
|
513
|
-
{@render insertZone(i + 1)}
|
|
514
|
-
{/if}
|
|
515
714
|
{/each}
|
|
516
715
|
</div>
|
|
517
716
|
</div>
|
|
518
717
|
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
718
|
+
</div>
|
|
719
|
+
|
|
720
|
+
<!-- Popover edit panel — anchored to click position -->
|
|
721
|
+
{#if !readOnly && (activeIndex !== null || editingFrontmatter)}
|
|
722
|
+
<!-- svelte-ignore a11y_no_static_element_interactions -->
|
|
723
|
+
<div
|
|
724
|
+
class="block-editor__popover-backdrop"
|
|
725
|
+
onmousedown={() => { activeIndex = null; editingFrontmatter = false; anchorPoint = null; pendingRuneIndex = null; }}
|
|
726
|
+
></div>
|
|
727
|
+
<div class="block-editor__popover" style={popoverStyle}>
|
|
728
|
+
{#if editingFrontmatter}
|
|
729
|
+
<FrontmatterEditPanel
|
|
730
|
+
onclose={() => { editingFrontmatter = false; anchorPoint = null; }}
|
|
731
|
+
/>
|
|
732
|
+
{:else if activeIndex !== null && blocks[activeIndex]}
|
|
733
|
+
{#key editSessionId}
|
|
527
734
|
<BlockEditPanel
|
|
528
735
|
block={blocks[activeIndex]}
|
|
529
736
|
{runeMap}
|
|
530
737
|
runes={() => runes}
|
|
531
|
-
|
|
738
|
+
{aggregated}
|
|
739
|
+
initialRuneIndex={pendingRuneIndex}
|
|
532
740
|
onupdate={(updated) => handleUpdateBlock(activeIndex!, updated)}
|
|
533
|
-
onremove={() => { const idx = activeIndex!; activeIndex = null; handleRemoveBlock(idx); }}
|
|
534
|
-
onclose={() => { activeIndex = null; }}
|
|
741
|
+
onremove={() => { const idx = activeIndex!; activeIndex = null; anchorPoint = null; pendingRuneIndex = null; handleRemoveBlock(idx); }}
|
|
742
|
+
onclose={() => { activeIndex = null; anchorPoint = null; pendingRuneIndex = null; }}
|
|
743
|
+
oneditfield={handleFieldEdit}
|
|
535
744
|
/>
|
|
536
|
-
{/
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
745
|
+
{/key}
|
|
746
|
+
{/if}
|
|
747
|
+
</div>
|
|
748
|
+
{/if}
|
|
749
|
+
|
|
750
|
+
{#if showInsertMenu}
|
|
751
|
+
<InsertBlockDialog
|
|
752
|
+
{runes}
|
|
753
|
+
{runesByCategory}
|
|
754
|
+
oninsert={insertBlock}
|
|
755
|
+
onclose={closeInsertMenu}
|
|
756
|
+
/>
|
|
757
|
+
{/if}
|
|
758
|
+
|
|
759
|
+
{#if inlineEdit}
|
|
760
|
+
<InlineEditPopover
|
|
761
|
+
anchorRect={inlineEdit.rect}
|
|
762
|
+
dataName={inlineEdit.dataName}
|
|
763
|
+
inlineSource={inlineEdit.inlineSource}
|
|
764
|
+
onchange={handleInlineEditChange}
|
|
765
|
+
onclose={closeInlineEdit}
|
|
766
|
+
/>
|
|
767
|
+
{/if}
|
|
768
|
+
|
|
769
|
+
{#if actionEdit}
|
|
770
|
+
<ActionEditPopover
|
|
771
|
+
anchorRect={actionEdit.rect}
|
|
772
|
+
text={actionEdit.mapping.text}
|
|
773
|
+
href={actionEdit.mapping.href}
|
|
774
|
+
onchange={handleActionEditChange}
|
|
775
|
+
onremove={handleActionRemove}
|
|
776
|
+
onclose={closeActionEdit}
|
|
777
|
+
/>
|
|
778
|
+
{/if}
|
|
779
|
+
|
|
780
|
+
{#if commandEdit}
|
|
781
|
+
<CodeEditPopover
|
|
782
|
+
anchorRect={commandEdit.rect}
|
|
783
|
+
code={commandEdit.mapping.code}
|
|
784
|
+
language={commandEdit.mapping.language}
|
|
785
|
+
onchange={handleCommandEditChange}
|
|
786
|
+
onremove={handleCommandRemove}
|
|
787
|
+
onclose={closeCommandEdit}
|
|
788
|
+
/>
|
|
789
|
+
{/if}
|
|
540
790
|
</div>
|
|
541
791
|
|
|
542
792
|
|
|
@@ -557,58 +807,28 @@
|
|
|
557
807
|
position: relative;
|
|
558
808
|
}
|
|
559
809
|
|
|
560
|
-
/* Scrollable block list
|
|
810
|
+
/* Scrollable block list */
|
|
561
811
|
.block-editor__scroll {
|
|
562
812
|
flex: 1;
|
|
563
813
|
min-height: 0;
|
|
564
814
|
display: flex;
|
|
565
815
|
flex-direction: column;
|
|
566
|
-
transition: margin-right var(--ed-transition-slow);
|
|
567
816
|
}
|
|
568
817
|
|
|
569
818
|
.block-editor__list-wrap {
|
|
570
819
|
width: 100%;
|
|
571
|
-
padding:
|
|
572
|
-
padding-right: 0;
|
|
820
|
+
padding: 0;
|
|
573
821
|
flex: 1;
|
|
574
822
|
min-height: 0;
|
|
575
823
|
overflow-y: auto;
|
|
576
824
|
}
|
|
577
825
|
|
|
578
|
-
/* Rail column: vertical border + diagonal stripe background */
|
|
579
|
-
.block-editor__scroll.has-rail .block-editor__list-wrap {
|
|
580
|
-
background-origin: content-box;
|
|
581
|
-
background-clip: border-box;
|
|
582
|
-
background:
|
|
583
|
-
/* Vertical border at left edge of rail */
|
|
584
|
-
linear-gradient(to right,
|
|
585
|
-
transparent calc(100% - 91px),
|
|
586
|
-
var(--ed-border-default) calc(100% - 91px),
|
|
587
|
-
var(--ed-border-default) calc(100% - 90px),
|
|
588
|
-
transparent calc(100% - 90px)
|
|
589
|
-
),
|
|
590
|
-
/* Solid background masking stripes in the content area */
|
|
591
|
-
linear-gradient(to right,
|
|
592
|
-
var(--ed-surface-0) calc(100% - 90px),
|
|
593
|
-
transparent calc(100% - 90px)
|
|
594
|
-
),
|
|
595
|
-
/* Stripe pattern */
|
|
596
|
-
repeating-linear-gradient(
|
|
597
|
-
-45deg,
|
|
598
|
-
transparent,
|
|
599
|
-
transparent 4px,
|
|
600
|
-
rgba(0, 0, 0, 0.04) 4px,
|
|
601
|
-
rgba(0, 0, 0, 0.04) 5px
|
|
602
|
-
);
|
|
603
|
-
}
|
|
604
|
-
|
|
605
826
|
/* Frontmatter summary header */
|
|
606
827
|
.block-editor__fm-header {
|
|
607
828
|
display: flex;
|
|
608
829
|
align-items: center;
|
|
609
830
|
gap: var(--ed-space-3);
|
|
610
|
-
padding: var(--ed-space-
|
|
611
|
-
border-bottom: 1px solid var(--ed-border-subtle);
|
|
831
|
+
padding: var(--ed-space-5) var(--ed-space-5);
|
|
612
832
|
margin-bottom: var(--ed-space-2);
|
|
613
833
|
}
|
|
614
834
|
|
|
@@ -665,15 +885,13 @@
|
|
|
665
885
|
color: var(--ed-accent);
|
|
666
886
|
}
|
|
667
887
|
|
|
668
|
-
/* Block row
|
|
888
|
+
/* Block row */
|
|
669
889
|
.block-editor__row {
|
|
670
|
-
|
|
671
|
-
align-items: flex-start;
|
|
890
|
+
position: relative;
|
|
672
891
|
transition: transform var(--ed-transition-fast), opacity var(--ed-transition-fast);
|
|
673
892
|
}
|
|
674
893
|
|
|
675
894
|
.block-editor__block-cell {
|
|
676
|
-
flex: 1;
|
|
677
895
|
min-width: 0;
|
|
678
896
|
}
|
|
679
897
|
|
|
@@ -688,145 +906,124 @@
|
|
|
688
906
|
padding-top: 2px;
|
|
689
907
|
}
|
|
690
908
|
|
|
691
|
-
/*
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
909
|
+
/* ── Hover controls (insert markers + label) ─────────────── */
|
|
910
|
+
|
|
911
|
+
/* Shared base for insert markers and label */
|
|
912
|
+
.block-editor__insert-marker,
|
|
913
|
+
.block-editor__hover-label {
|
|
914
|
+
position: absolute;
|
|
915
|
+
right: 20px;
|
|
916
|
+
z-index: 2;
|
|
917
|
+
border: none;
|
|
918
|
+
cursor: pointer;
|
|
919
|
+
border-radius: 9999px;
|
|
920
|
+
background: var(--ed-surface-2);
|
|
921
|
+
color: var(--ed-text-muted);
|
|
697
922
|
font-size: 10px;
|
|
698
923
|
font-weight: 600;
|
|
699
|
-
color: var(--ed-text-muted);
|
|
700
924
|
text-transform: uppercase;
|
|
701
925
|
letter-spacing: 0.03em;
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
cursor: pointer;
|
|
706
|
-
white-space: nowrap;
|
|
707
|
-
overflow: hidden;
|
|
708
|
-
text-overflow: ellipsis;
|
|
709
|
-
transition: color var(--ed-transition-fast);
|
|
710
|
-
align-self: stretch;
|
|
711
|
-
line-height: 1.3;
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
.block-editor__rail-label:hover {
|
|
715
|
-
color: var(--ed-text-secondary);
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
.block-editor__rail-label.active {
|
|
719
|
-
color: var(--ed-accent);
|
|
720
|
-
font-weight: 700;
|
|
926
|
+
opacity: 0;
|
|
927
|
+
pointer-events: none;
|
|
928
|
+
transition: opacity 100ms ease-out, transform 100ms ease-out, background 100ms ease-out, color 100ms ease-out;
|
|
721
929
|
}
|
|
722
930
|
|
|
723
|
-
/* Insert
|
|
724
|
-
.block-editor__insert-
|
|
931
|
+
/* Insert markers — top/bottom edges */
|
|
932
|
+
.block-editor__insert-marker {
|
|
725
933
|
display: flex;
|
|
726
934
|
align-items: center;
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
935
|
+
justify-content: center;
|
|
936
|
+
width: 22px;
|
|
937
|
+
height: 22px;
|
|
938
|
+
padding: 0;
|
|
939
|
+
color: var(--ed-text-tertiary);
|
|
731
940
|
}
|
|
732
941
|
|
|
733
|
-
.block-editor__insert-
|
|
734
|
-
|
|
942
|
+
.block-editor__insert-marker--top {
|
|
943
|
+
top: -11px;
|
|
735
944
|
}
|
|
736
945
|
|
|
737
|
-
.block-editor__insert-
|
|
738
|
-
|
|
739
|
-
flex-shrink: 0;
|
|
740
|
-
margin-left: var(--ed-space-5);
|
|
741
|
-
display: flex;
|
|
742
|
-
align-items: center;
|
|
743
|
-
justify-content: flex-start;
|
|
744
|
-
border: none;
|
|
745
|
-
background: transparent;
|
|
746
|
-
cursor: pointer;
|
|
747
|
-
height: 100%;
|
|
748
|
-
padding: 0;
|
|
749
|
-
position: relative;
|
|
750
|
-
overflow: visible;
|
|
946
|
+
.block-editor__insert-marker--bottom {
|
|
947
|
+
bottom: -11px;
|
|
751
948
|
}
|
|
752
949
|
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
left: 1px;
|
|
950
|
+
/* Label — right side, vertically centered */
|
|
951
|
+
.block-editor__hover-label {
|
|
756
952
|
top: 50%;
|
|
757
|
-
transform:
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
background: var(--ed-text-muted);
|
|
762
|
-
transition: width var(--ed-transition-fast), height var(--ed-transition-fast), background var(--ed-transition-fast);
|
|
953
|
+
transform: translateX(6px) translateY(-50%);
|
|
954
|
+
padding: 4px 10px;
|
|
955
|
+
white-space: nowrap;
|
|
956
|
+
line-height: 1.3;
|
|
763
957
|
}
|
|
764
958
|
|
|
765
|
-
|
|
766
|
-
|
|
767
|
-
|
|
768
|
-
|
|
959
|
+
/* Show controls on hover */
|
|
960
|
+
.block-editor__row.hovered .block-editor__insert-marker,
|
|
961
|
+
.block-editor__row.hovered .block-editor__hover-label {
|
|
962
|
+
opacity: 1;
|
|
963
|
+
pointer-events: auto;
|
|
769
964
|
}
|
|
770
965
|
|
|
771
|
-
.block-
|
|
772
|
-
|
|
773
|
-
content: '';
|
|
774
|
-
position: absolute;
|
|
775
|
-
background: white;
|
|
776
|
-
border-radius: 1px;
|
|
777
|
-
opacity: 0;
|
|
778
|
-
transition: opacity var(--ed-transition-fast);
|
|
966
|
+
.block-editor__row.hovered .block-editor__hover-label {
|
|
967
|
+
transform: translateX(0) translateY(-50%);
|
|
779
968
|
}
|
|
780
969
|
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
970
|
+
/* Pinned label when edit panel is open */
|
|
971
|
+
.block-editor__row.active .block-editor__hover-label {
|
|
972
|
+
opacity: 1;
|
|
973
|
+
pointer-events: auto;
|
|
974
|
+
transform: translateX(0) translateY(-50%);
|
|
975
|
+
background: var(--ed-accent-muted);
|
|
976
|
+
color: var(--ed-accent);
|
|
977
|
+
font-weight: 700;
|
|
787
978
|
}
|
|
788
979
|
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
left: 50%;
|
|
794
|
-
transform: translate(-50%, -50%);
|
|
980
|
+
/* Insert marker hover */
|
|
981
|
+
.block-editor__insert-marker:hover {
|
|
982
|
+
background: var(--ed-accent);
|
|
983
|
+
color: white;
|
|
795
984
|
}
|
|
796
985
|
|
|
797
|
-
|
|
798
|
-
.block-
|
|
799
|
-
|
|
986
|
+
/* Label hover */
|
|
987
|
+
.block-editor__hover-label:hover {
|
|
988
|
+
color: var(--ed-text-secondary);
|
|
989
|
+
background: var(--ed-surface-3, var(--ed-border-default));
|
|
800
990
|
}
|
|
801
991
|
|
|
802
|
-
|
|
803
|
-
|
|
804
|
-
|
|
805
|
-
|
|
806
|
-
|
|
807
|
-
|
|
808
|
-
|
|
809
|
-
|
|
810
|
-
|
|
992
|
+
.block-editor__row.active .block-editor__hover-label:hover {
|
|
993
|
+
background: var(--ed-accent);
|
|
994
|
+
color: white;
|
|
995
|
+
}
|
|
996
|
+
|
|
997
|
+
/* Popover backdrop — transparent click target */
|
|
998
|
+
.block-editor__popover-backdrop {
|
|
999
|
+
position: fixed;
|
|
1000
|
+
inset: 0;
|
|
1001
|
+
z-index: 9;
|
|
811
1002
|
}
|
|
812
1003
|
|
|
813
|
-
/*
|
|
814
|
-
.block-
|
|
1004
|
+
/* Popover container — anchored to block card */
|
|
1005
|
+
.block-editor__popover {
|
|
815
1006
|
position: fixed;
|
|
816
|
-
|
|
817
|
-
right: 0;
|
|
818
|
-
bottom: 0;
|
|
819
|
-
width: 480px;
|
|
1007
|
+
width: 420px;
|
|
820
1008
|
overflow-y: auto;
|
|
821
|
-
background: var(--ed-surface-
|
|
822
|
-
border-
|
|
823
|
-
|
|
824
|
-
|
|
1009
|
+
background: var(--ed-surface-0);
|
|
1010
|
+
border-radius: var(--ed-radius-lg);
|
|
1011
|
+
border: 1px solid var(--ed-border-default);
|
|
1012
|
+
box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1),
|
|
1013
|
+
0 8px 10px -6px rgba(0, 0, 0, 0.1);
|
|
825
1014
|
z-index: 10;
|
|
1015
|
+
animation: popover-enter 0.15s ease-out;
|
|
826
1016
|
}
|
|
827
1017
|
|
|
828
|
-
|
|
829
|
-
|
|
1018
|
+
@keyframes popover-enter {
|
|
1019
|
+
from {
|
|
1020
|
+
opacity: 0;
|
|
1021
|
+
transform: translateY(4px) scale(0.98);
|
|
1022
|
+
}
|
|
1023
|
+
to {
|
|
1024
|
+
opacity: 1;
|
|
1025
|
+
transform: translateY(0) scale(1);
|
|
1026
|
+
}
|
|
830
1027
|
}
|
|
831
1028
|
|
|
832
1029
|
/* Empty state */
|
|
@@ -855,123 +1052,4 @@
|
|
|
855
1052
|
font-size: var(--ed-text-sm);
|
|
856
1053
|
}
|
|
857
1054
|
|
|
858
|
-
/* Insert menu (shared between floating and any future inline) */
|
|
859
|
-
.insert-menu {
|
|
860
|
-
border: 1px solid var(--ed-border-default);
|
|
861
|
-
border-radius: 10px;
|
|
862
|
-
background: var(--ed-surface-0);
|
|
863
|
-
padding: var(--ed-space-4);
|
|
864
|
-
display: flex;
|
|
865
|
-
flex-direction: column;
|
|
866
|
-
gap: var(--ed-space-3);
|
|
867
|
-
box-shadow: var(--ed-shadow-lg);
|
|
868
|
-
animation: menu-enter var(--ed-transition-normal);
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
@keyframes menu-enter {
|
|
872
|
-
from { opacity: 0; transform: translateY(4px); }
|
|
873
|
-
to { opacity: 1; transform: translateY(0); }
|
|
874
|
-
}
|
|
875
|
-
|
|
876
|
-
.insert-menu__section {
|
|
877
|
-
display: flex;
|
|
878
|
-
flex-direction: column;
|
|
879
|
-
gap: 0.4rem;
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
.insert-menu__label {
|
|
883
|
-
font-size: var(--ed-text-xs);
|
|
884
|
-
font-weight: 600;
|
|
885
|
-
color: var(--ed-text-muted);
|
|
886
|
-
text-transform: uppercase;
|
|
887
|
-
letter-spacing: 0.05em;
|
|
888
|
-
}
|
|
889
|
-
|
|
890
|
-
.insert-menu__grid {
|
|
891
|
-
display: grid;
|
|
892
|
-
grid-template-columns: repeat(auto-fill, minmax(120px, 1fr));
|
|
893
|
-
gap: 0.35rem;
|
|
894
|
-
}
|
|
895
|
-
|
|
896
|
-
.insert-menu__btn {
|
|
897
|
-
display: flex;
|
|
898
|
-
align-items: center;
|
|
899
|
-
gap: 0.4rem;
|
|
900
|
-
padding: var(--ed-space-2) var(--ed-space-2);
|
|
901
|
-
border: 1px solid var(--ed-border-default);
|
|
902
|
-
border-radius: var(--ed-radius-sm);
|
|
903
|
-
background: var(--ed-surface-1);
|
|
904
|
-
color: var(--ed-text-secondary);
|
|
905
|
-
font-size: var(--ed-text-sm);
|
|
906
|
-
cursor: pointer;
|
|
907
|
-
transition: background var(--ed-transition-fast), border-color var(--ed-transition-fast);
|
|
908
|
-
text-align: left;
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
.insert-menu__btn:hover {
|
|
912
|
-
background: var(--ed-accent-muted);
|
|
913
|
-
border-color: var(--ed-accent);
|
|
914
|
-
color: var(--ed-heading);
|
|
915
|
-
}
|
|
916
|
-
|
|
917
|
-
.insert-menu__icon {
|
|
918
|
-
flex-shrink: 0;
|
|
919
|
-
opacity: 0.6;
|
|
920
|
-
}
|
|
921
|
-
|
|
922
|
-
/* Rune buttons */
|
|
923
|
-
.insert-menu__btn--rune {
|
|
924
|
-
align-items: flex-start;
|
|
925
|
-
padding: var(--ed-space-2);
|
|
926
|
-
}
|
|
927
|
-
|
|
928
|
-
.insert-menu__rune-dot {
|
|
929
|
-
width: 6px;
|
|
930
|
-
height: 6px;
|
|
931
|
-
border-radius: 50%;
|
|
932
|
-
background: var(--ed-warning);
|
|
933
|
-
flex-shrink: 0;
|
|
934
|
-
margin-top: 0.3rem;
|
|
935
|
-
}
|
|
936
|
-
|
|
937
|
-
.insert-menu__rune-info {
|
|
938
|
-
display: flex;
|
|
939
|
-
flex-direction: column;
|
|
940
|
-
gap: 0.15rem;
|
|
941
|
-
min-width: 0;
|
|
942
|
-
}
|
|
943
|
-
|
|
944
|
-
.insert-menu__rune-name {
|
|
945
|
-
font-weight: 500;
|
|
946
|
-
}
|
|
947
|
-
|
|
948
|
-
.insert-menu__rune-desc {
|
|
949
|
-
font-size: 10px;
|
|
950
|
-
color: var(--ed-text-muted);
|
|
951
|
-
overflow: hidden;
|
|
952
|
-
text-overflow: ellipsis;
|
|
953
|
-
white-space: nowrap;
|
|
954
|
-
}
|
|
955
|
-
|
|
956
|
-
.insert-menu__btn--rune:hover {
|
|
957
|
-
background: var(--ed-warning-subtle);
|
|
958
|
-
border-color: var(--ed-warning);
|
|
959
|
-
}
|
|
960
|
-
|
|
961
|
-
.insert-menu__close {
|
|
962
|
-
align-self: flex-end;
|
|
963
|
-
padding: var(--ed-space-1) var(--ed-space-2);
|
|
964
|
-
border: none;
|
|
965
|
-
border-radius: var(--ed-radius-sm);
|
|
966
|
-
background: transparent;
|
|
967
|
-
color: var(--ed-text-muted);
|
|
968
|
-
font-size: var(--ed-text-sm);
|
|
969
|
-
cursor: pointer;
|
|
970
|
-
transition: background var(--ed-transition-fast), color var(--ed-transition-fast);
|
|
971
|
-
}
|
|
972
|
-
|
|
973
|
-
.insert-menu__close:hover {
|
|
974
|
-
background: var(--ed-surface-2);
|
|
975
|
-
color: var(--ed-text-secondary);
|
|
976
|
-
}
|
|
977
1055
|
</style>
|