@helping-ai-workflow/md2doc 3.9.1 → 3.11.0
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/lib/editor/client.js +1026 -437
- package/lib/editor/convert-md.js +18 -11
- package/lib/editor/icons.js +48 -0
- package/lib/editor/inline-md.js +8 -0
- package/lib/editor/list-md.js +26 -1
- package/lib/editor/server.js +14 -4
- package/lib/editor/toolbar-model.js +27 -80
- package/lib/highlight.js +35 -0
- package/lib/md2doc.js +234 -147
- package/lib/theme/runtime.js +80 -2
- package/lib/theme/tokens.js +74 -5
- package/package.json +4 -3
- package/lib/editor/docsource.js +0 -115
package/lib/md2doc.js
CHANGED
|
@@ -22,6 +22,7 @@ const fs = require('fs');
|
|
|
22
22
|
const path = require('path');
|
|
23
23
|
const drawio = require('./drawio.js');
|
|
24
24
|
const { applyReaderTheme } = require('./theme/tokens');
|
|
25
|
+
const { highlightCode } = require('./highlight');
|
|
25
26
|
|
|
26
27
|
// How long to let client-side WaveDrom / Mermaid scripts render before we
|
|
27
28
|
// snapshot the DOM (PDF print, or --bake-svg inert-SVG bake).
|
|
@@ -359,10 +360,14 @@ function renderEditModeList(listToken, blocks, biRef, out) {
|
|
|
359
360
|
const runStart = liRunStartsHere(biRef, b) ? ' data-run-start="1"' : '';
|
|
360
361
|
const listStartAttr = listStart ? ' data-list-start="1"' : '';
|
|
361
362
|
listStart = false;
|
|
363
|
+
// v3.11 (batch-2 §6): marked's own looseness for this list token, read
|
|
364
|
+
// by the lexer off the source (a blank line between items). The editor
|
|
365
|
+
// gives a NEW neighbour in this list the same spacing.
|
|
366
|
+
const looseAttr = listToken.loose ? ' data-list-loose="1"' : '';
|
|
362
367
|
parts.push(
|
|
363
368
|
`<div class="ed-block" data-block-id="${b.id}" data-block-type="li"` +
|
|
364
369
|
` data-list-type="${b.listType}" data-task="${b.task ? 1 : 0}" data-indent="${b.indent}"` +
|
|
365
|
-
runStart + listStartAttr + ` style="--ed-indent:${b.indent}">` +
|
|
370
|
+
runStart + listStartAttr + looseAttr + ` style="--ed-indent:${b.indent}">` +
|
|
366
371
|
`<span class="ed-li-marker" aria-hidden="true"></span>` + check +
|
|
367
372
|
`<div class="ed-li-text">${inner}</div>` +
|
|
368
373
|
`</div>`
|
|
@@ -1033,9 +1038,16 @@ ${itemsHtml}
|
|
|
1033
1038
|
const b64 = Buffer.from(code, 'utf8').toString('base64');
|
|
1034
1039
|
return '\n' + GRAPHVIZ_PLACEHOLDER.html([b64]) + '\n';
|
|
1035
1040
|
}
|
|
1036
|
-
// Default:
|
|
1041
|
+
// Default: fenced code. v3.10.0 colours registered languages here, at
|
|
1042
|
+
// render time (lib/highlight.js); an unknown or missing language stays
|
|
1043
|
+
// plain escaped text.
|
|
1044
|
+
const coloured = highlightCode(code, lang);
|
|
1045
|
+
// The info string goes into an attribute: escape it (an info string such
|
|
1046
|
+
// as x" onmouseover=… must stay text). Ordinary language names are unchanged.
|
|
1047
|
+
const langAttr = escapeHtml(lang);
|
|
1048
|
+
if (coloured !== null) return `<pre><code class="language-${langAttr} hljs">${coloured}</code></pre>\n`;
|
|
1037
1049
|
const escaped = code.replace(/&/g,'&').replace(/</g,'<').replace(/>/g,'>');
|
|
1038
|
-
return `<pre><code class="language-${
|
|
1050
|
+
return `<pre><code class="language-${langAttr}">${escaped}</code></pre>\n`;
|
|
1039
1051
|
};
|
|
1040
1052
|
|
|
1041
1053
|
renderer.heading = function(token) {
|
|
@@ -1070,7 +1082,18 @@ ${itemsHtml}
|
|
|
1070
1082
|
const baseListitem = renderer.listitem.bind(renderer);
|
|
1071
1083
|
renderer.listitem = function(token) {
|
|
1072
1084
|
appendSectionText(flattenTokenText(token.tokens));
|
|
1073
|
-
|
|
1085
|
+
const html = baseListitem(token);
|
|
1086
|
+
if (!token.task) return html;
|
|
1087
|
+
// v3.10.0: a task item drops its bullet and keeps its own text in a span,
|
|
1088
|
+
// so a checked item's strike-through stops at its own words — CSS
|
|
1089
|
+
// text-decoration cannot be undone on a nested child list. Shapes: tight
|
|
1090
|
+
// (text then an optional block child — a nested list, blockquote, code,
|
|
1091
|
+
// table…), loose (inside a <p>), leaf. The span ends at whichever comes
|
|
1092
|
+
// first: a block child's opening tag, the loose item's </p>, or </li>.
|
|
1093
|
+
const cls = token.checked ? 'task-item is-checked' : 'task-item';
|
|
1094
|
+
const m = html.match(/^<li>([\s\S]*?<input[^>]*>)([\s\S]*?)(<(?:ul|ol|blockquote|pre|table|div|p|h[1-6])[\s>][\s\S]*|<\/p>[\s\S]*|<\/li>\s*)$/);
|
|
1095
|
+
if (!m) return html.replace(/^<li>/, '<li class="' + cls + '">');
|
|
1096
|
+
return '<li class="' + cls + '">' + m[1] + ' <span class="task-text">' + m[2].trim() + '</span>' + m[3];
|
|
1074
1097
|
};
|
|
1075
1098
|
|
|
1076
1099
|
const baseBlockquote = renderer.blockquote.bind(renderer);
|
|
@@ -1305,7 +1328,10 @@ ${itemsHtml}
|
|
|
1305
1328
|
var __md2docWavedromSeq = 0;
|
|
1306
1329
|
window.__md2docInitDiagrams = function (rootEl) {
|
|
1307
1330
|
rootEl = rootEl || document;
|
|
1308
|
-
|
|
1331
|
+
// v3.10.0: with the theme runtime on the page (lib/theme/runtime.js), new
|
|
1332
|
+
// mermaid hosts are drawn through it, in the theme on screen, so a block
|
|
1333
|
+
// rebuilt after an edit does not come back light (or recoloured) in dark.
|
|
1334
|
+
if (typeof mermaid !== 'undefined' && !(window.__md2docThemeMermaid && window.__md2docThemeMermaid())) {
|
|
1309
1335
|
mermaid.initialize({ startOnLoad: false, ${MERMAID_CONFIG_JS} });
|
|
1310
1336
|
var mermaidNodes = rootEl.querySelectorAll ? rootEl.querySelectorAll('.mermaid') : [];
|
|
1311
1337
|
var pending = [];
|
|
@@ -1434,6 +1460,17 @@ ${itemsHtml}
|
|
|
1434
1460
|
'\n .ed-block[data-list-type="ol"][data-indent="' + d + '"] > .ed-li-marker::before' +
|
|
1435
1461
|
' { content: counter(ed-ol-' + d + ') "."; }';
|
|
1436
1462
|
}
|
|
1463
|
+
// v3.10.0: bullets change by depth like the reader's disc / circle / square,
|
|
1464
|
+
// cycling every three levels. Task items keep their own content:none rule
|
|
1465
|
+
// (same specificity, later in the sheet, so it still wins).
|
|
1466
|
+
const ED_UL_GLYPHS = ['\\2022', '\\25E6', '\\25AA'];
|
|
1467
|
+
// Depth-agnostic fallback first (deeper than ED_OL_MAX_DEPTH keeps a •
|
|
1468
|
+
// rather than going blank); the per-depth rules outrank it.
|
|
1469
|
+
let edUlMarkerCss = '\n .ed-block[data-list-type="ul"] > .ed-li-marker::before { content: "' + ED_UL_GLYPHS[0] + '"; }';
|
|
1470
|
+
for (let d = 0; d <= ED_OL_MAX_DEPTH; d++) {
|
|
1471
|
+
edUlMarkerCss += '\n .ed-block[data-list-type="ul"][data-indent="' + d + '"] > .ed-li-marker::before' +
|
|
1472
|
+
' { content: "' + ED_UL_GLYPHS[d % 3] + '"; }';
|
|
1473
|
+
}
|
|
1437
1474
|
|
|
1438
1475
|
const editModeLayoutCss = `
|
|
1439
1476
|
/* 56px, not 48px — spec §4.2's hit-test conflict 1 (gutter vs
|
|
@@ -1463,8 +1500,16 @@ ${itemsHtml}
|
|
|
1463
1500
|
comment above .ed-handle below. That still leaves 6px of clearance from
|
|
1464
1501
|
splitterRight (contentLeft-56), so the conflict-1 guard still holds.
|
|
1465
1502
|
Guarded by the elementFromPoint(splitter.right - 2, y) assertion §4.2
|
|
1466
|
-
asks for, in test/editor-client-runtime.test.js.
|
|
1467
|
-
|
|
1503
|
+
asks for, in test/editor-client-runtime.test.js.
|
|
1504
|
+
|
|
1505
|
+
v3.10.0: 62px. The B look makes the buttons 24px; with --ed-gutter-gap
|
|
1506
|
+
2px and the 10px shift the pair spans [contentLeft-60, contentLeft-12],
|
|
1507
|
+
and at 56px of padding the + hung back over the splitter again (the
|
|
1508
|
+
spec's gap 0 already did: measured 1400x900, splitter [324, 356], +
|
|
1509
|
+
[354, 378], elementFromPoint(355, +'s y) === .ed-insert). 62px restores
|
|
1510
|
+
2px of clearance: re-measured + [358, 382], ⠿ [382, 406], row grip
|
|
1511
|
+
[408, 428], contentLeft 418. */
|
|
1512
|
+
.content { padding-left: 62px; }
|
|
1468
1513
|
|
|
1469
1514
|
/* S1: every block is one full-width row, whatever its type or depth. The
|
|
1470
1515
|
indent is a property of the item's own MARKER, never of its box, so all
|
|
@@ -1510,7 +1555,7 @@ ${itemsHtml}
|
|
|
1510
1555
|
margin-left: calc(var(--ed-indent, 0) * 1.6em);
|
|
1511
1556
|
width: 1.2em;
|
|
1512
1557
|
display: flex; justify-content: flex-end;
|
|
1513
|
-
color:
|
|
1558
|
+
color: var(--md-muted); -webkit-user-select: none; user-select: none;
|
|
1514
1559
|
}
|
|
1515
1560
|
/* min-width: 0 so an unbreakable token inside an item cannot widen the row
|
|
1516
1561
|
past its siblings — that would break the equal-width guarantee above. */
|
|
@@ -1525,7 +1570,7 @@ ${itemsHtml}
|
|
|
1525
1570
|
.ed-block[data-block-type="li"] > .ed-editing { flex: 1 1 auto; min-width: 0; }
|
|
1526
1571
|
/* column-gap already provides the marker/checkbox separation. */
|
|
1527
1572
|
.ed-block[data-block-type="li"] > .ed-li-check { flex: 0 0 auto; margin-right: 0; }
|
|
1528
|
-
|
|
1573
|
+
${edUlMarkerCss}${edOlCounterCss}
|
|
1529
1574
|
/* A BULLETED task item's checkbox IS its marker, so the • is suppressed and
|
|
1530
1575
|
the marker box collapses (the indent lives on its margin and survives).
|
|
1531
1576
|
An ORDERED task item keeps its number — that is what GFM renders — and
|
|
@@ -1554,8 +1599,8 @@ ${itemsHtml}
|
|
|
1554
1599
|
whatever --ed-gutter-shift moved the pair by. Writing any of them as a
|
|
1555
1600
|
second literal is how the corridor comes back. */
|
|
1556
1601
|
:root {
|
|
1557
|
-
--ed-gutter-btn:
|
|
1558
|
-
--ed-gutter-gap:
|
|
1602
|
+
--ed-gutter-btn: 24px;
|
|
1603
|
+
--ed-gutter-gap: 2px;
|
|
1559
1604
|
--ed-gutter-w: calc(var(--ed-gutter-btn) * 2 + var(--ed-gutter-gap));
|
|
1560
1605
|
}
|
|
1561
1606
|
/* v3.0.1: the pair moves LEFT by --ed-gutter-shift so the table row grip
|
|
@@ -1567,15 +1612,21 @@ ${itemsHtml}
|
|
|
1567
1612
|
tableLeft=412; a 10px shift lands ⠿=[380,398] +=[362,380], grip
|
|
1568
1613
|
(straddling, 20px wide, centred on tableLeft) = [402,422], leaving
|
|
1569
1614
|
exactly --ed-gutter-gap (4px) between the ⠿'s right edge (398) and the
|
|
1570
|
-
grip's left edge (402), and +'s left edge (362) stays well clear of 0.
|
|
1615
|
+
grip's left edge (402), and +'s left edge (362) stays well clear of 0.
|
|
1616
|
+
v3.10.0 re-measured (same page, 24px buttons, --ed-gutter-gap 2px, 62px
|
|
1617
|
+
content padding): ⠿=[382,406] +=[358,382] tableLeft=418, grip=[408,428].
|
|
1618
|
+
The spec asked for gap 0; that left the ⠿ abutting the grip, and on CI's
|
|
1619
|
+
fractional layout the grip took the ⠿'s last half-pixel column (§4.2
|
|
1620
|
+
conflict 2, editor-client-runtime: x 73.5 in a [50, 74] box answered
|
|
1621
|
+
ROW-GRIP). 2px is the clearance that survives sub-pixel snapping. */
|
|
1571
1622
|
:root { --ed-gutter-shift: 10px; }
|
|
1572
1623
|
.ed-handle {
|
|
1573
1624
|
left: calc(-1 * (var(--ed-gutter-btn) + var(--ed-gutter-gap) + var(--ed-gutter-shift)));
|
|
1574
|
-
top:
|
|
1625
|
+
top: var(--ed-pair-top, 0px);
|
|
1575
1626
|
width: var(--ed-gutter-btn);
|
|
1576
1627
|
}
|
|
1577
1628
|
.ed-insert {
|
|
1578
|
-
left: calc(-1 * (var(--ed-gutter-w) + var(--ed-gutter-shift))); top:
|
|
1629
|
+
left: calc(-1 * (var(--ed-gutter-w) + var(--ed-gutter-shift))); top: var(--ed-pair-top, 0px);
|
|
1579
1630
|
width: var(--ed-gutter-btn);
|
|
1580
1631
|
}
|
|
1581
1632
|
/* v2.11.1: the gutter's HOVER ZONE, and it is the reason the pair could move
|
|
@@ -1705,22 +1756,6 @@ ${itemsHtml}
|
|
|
1705
1756
|
/* The reader bar is gone in edit mode, so its 52px anchor offset goes too
|
|
1706
1757
|
(it moved scrollIntoView landings under the edit toolbar). */
|
|
1707
1758
|
.content [id] { scroll-margin-top: 0; }
|
|
1708
|
-
/* T11-2 step 5: enterSourceMode() (lib/editor/client.js) sets
|
|
1709
|
-
contentEl.hidden = true and mounts a plain textarea in its place, and
|
|
1710
|
-
setDocMode() writes docMode onto body as data-ed-mode. Measured on that
|
|
1711
|
-
build: with ten TOC links listed, clicking the last one moved neither
|
|
1712
|
-
the (hidden) reading position nor the textarea's own scrollTop
|
|
1713
|
-
(3924 before and after) — the click target was a normal anchor jump /
|
|
1714
|
-
scrollIntoView() reaching into a subtree rooted at .content, and
|
|
1715
|
-
.content's own display:none is what absorbed it; the same subtree
|
|
1716
|
-
relationship holds for a search result's jump target. Hiding the TOC
|
|
1717
|
-
nav and the search-results panel while data-ed-mode="source" removes
|
|
1718
|
-
the two controls whose only reachable target sits in that hidden
|
|
1719
|
-
subtree; the search input row (.reader-tools) is left as-is — driving
|
|
1720
|
-
it against the textarea's own line numbers instead is a separate
|
|
1721
|
-
feasibility question, not answered here. */
|
|
1722
|
-
body[data-ed-mode="source"] .toc,
|
|
1723
|
-
body[data-ed-mode="source"] .search-results { display: none !important; }
|
|
1724
1759
|
|
|
1725
1760
|
/* ── v3.4.0 batch3 Task 6: the wavedrom editing surface ───────────────
|
|
1726
1761
|
Both of these are mounted on document.body by lib/editor/client.js, and
|
|
@@ -1735,10 +1770,10 @@ ${itemsHtml}
|
|
|
1735
1770
|
toolbar's own band, because the editor is modal over the document. */
|
|
1736
1771
|
.ed-wave-edit-btn {
|
|
1737
1772
|
position: fixed; z-index: 12; padding: 3px 10px; font-size: 12px;
|
|
1738
|
-
border: 1px solid
|
|
1739
|
-
color:
|
|
1773
|
+
border: 1px solid var(--md-border); border-radius: 4px; background: var(--md-ed-surface);
|
|
1774
|
+
color: var(--md-strong); cursor: pointer; box-shadow: 0 1px 3px var(--md-ed-shadow);
|
|
1740
1775
|
}
|
|
1741
|
-
.ed-wave-edit-btn:hover { background:
|
|
1776
|
+
.ed-wave-edit-btn:hover { background: var(--md-ed-surface); border-color: var(--md-border); }
|
|
1742
1777
|
.ed-wave-overlay {
|
|
1743
1778
|
position: fixed; inset: 0; z-index: 998; background: rgba(0,0,0,.45);
|
|
1744
1779
|
display: flex; align-items: center; justify-content: center;
|
|
@@ -2783,6 +2818,24 @@ const html = `<!DOCTYPE html>
|
|
|
2783
2818
|
overflow-wrap: anywhere;
|
|
2784
2819
|
word-break: break-word;
|
|
2785
2820
|
}
|
|
2821
|
+
/* v3.10.0: task items. The checkbox is the marker, so no bullet; a checked
|
|
2822
|
+
item's OWN text is struck — child selectors only, because a descendant
|
|
2823
|
+
rule would strike the nested child items too (text-decoration cannot be
|
|
2824
|
+
undone further down). */
|
|
2825
|
+
.content ul > li.task-item { list-style: none; }
|
|
2826
|
+
.content li.task-item > input[type="checkbox"],
|
|
2827
|
+
.content li.task-item > p > input[type="checkbox"] {
|
|
2828
|
+
appearance: none; -webkit-appearance: none; width: 16px; height: 16px; margin: 0 6px 0 0;
|
|
2829
|
+
vertical-align: -3px; border: 1.5px solid var(--md-muted); border-radius: 4px; background: transparent; }
|
|
2830
|
+
/* In a bulleted list the checkbox takes the bullet's place; an ORDERED task
|
|
2831
|
+
item keeps its number (what GFM renders, and what the editor does). */
|
|
2832
|
+
.content ul > li.task-item > input[type="checkbox"],
|
|
2833
|
+
.content ul > li.task-item > p > input[type="checkbox"] { margin-left: -22px; }
|
|
2834
|
+
.content li.task-item.is-checked > input[type="checkbox"],
|
|
2835
|
+
.content li.task-item.is-checked > p > input[type="checkbox"] {
|
|
2836
|
+
border-color: var(--md-accent); background: var(--md-accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / 12px no-repeat; }
|
|
2837
|
+
.content li.task-item.is-checked > .task-text,
|
|
2838
|
+
.content li.task-item.is-checked > p > .task-text { color: var(--md-muted); text-decoration: line-through; }
|
|
2786
2839
|
.content > * { max-width: 100%; }
|
|
2787
2840
|
.content iframe, .content video, .content canvas { max-width: 100%; height: auto; }
|
|
2788
2841
|
.doc-meta {
|
|
@@ -2837,6 +2890,16 @@ const html = `<!DOCTYPE html>
|
|
|
2837
2890
|
line-height: 1.45;
|
|
2838
2891
|
}
|
|
2839
2892
|
pre code { background: none; padding: 0; font-size: 0.875em; }
|
|
2893
|
+
/* v3.10.0: fenced-code syntax colour, written at render time by
|
|
2894
|
+
lib/highlight.js (no script on the page). Colours are the syn-* roles. */
|
|
2895
|
+
.hljs-keyword, .hljs-selector-tag, .hljs-literal { color: var(--md-syn-keyword); }
|
|
2896
|
+
.hljs-number, .hljs-attr, .hljs-attribute { color: var(--md-syn-number); }
|
|
2897
|
+
.hljs-comment, .hljs-quote { color: var(--md-syn-comment); font-style: italic; }
|
|
2898
|
+
.hljs-string, .hljs-regexp { color: var(--md-syn-string); }
|
|
2899
|
+
.hljs-type, .hljs-built_in, .hljs-meta { color: var(--md-syn-type); }
|
|
2900
|
+
.hljs-title, .hljs-variable, .hljs-params, .hljs-section { color: var(--md-syn-title); }
|
|
2901
|
+
.hljs-addition { color: var(--md-syn-string); }
|
|
2902
|
+
.hljs-deletion { color: var(--md-syn-keyword); }
|
|
2840
2903
|
.content :not(pre) > code {
|
|
2841
2904
|
background: none;
|
|
2842
2905
|
padding: 0;
|
|
@@ -3222,11 +3285,10 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3222
3285
|
above), so shipping this unconditionally is inert on normal HTML
|
|
3223
3286
|
output, same precedent as the lightbox selectors above. */
|
|
3224
3287
|
.ed-block { position: relative; cursor: pointer; }
|
|
3225
|
-
.ed-block:hover { outline: 1px dashed #b0b0b0; }
|
|
3226
3288
|
/* S3: the block-level multi-select tint (spec §3.6). rgba, never opaque —
|
|
3227
|
-
§3.6 says the text underneath stays readable.
|
|
3228
|
-
|
|
3229
|
-
.ed-te-hl).
|
|
3289
|
+
§3.6 says the text underneath stays readable. Since v3.10.0 the tint is
|
|
3290
|
+
the --md-ed-sel role, the reader accent at low alpha, shared with
|
|
3291
|
+
.ed-te-hl (focus rings and the checked box use --md-accent itself).
|
|
3230
3292
|
|
|
3231
3293
|
The descendant rules and their !important are not decoration, they are
|
|
3232
3294
|
the whole problem: <pre> (#f6f8fa) and the sticky first column (#ffffff)
|
|
@@ -3245,12 +3307,12 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3245
3307
|
:focus outline is suppressed because the roving tabindex below focuses a
|
|
3246
3308
|
.ed-block for real (spec §4.4 wants a real focus holder, not <body>) and
|
|
3247
3309
|
the tint — not a second ring — is the selection's affordance. */
|
|
3248
|
-
.ed-block.ed-selected { background:
|
|
3310
|
+
.ed-block.ed-selected { background: var(--md-ed-sel); }
|
|
3249
3311
|
.ed-block.ed-selected pre,
|
|
3250
3312
|
.ed-block.ed-selected th,
|
|
3251
3313
|
.ed-block.ed-selected tr:nth-child(even),
|
|
3252
3314
|
.ed-block.ed-selected tbody td:first-child,
|
|
3253
|
-
.ed-block.ed-selected thead th:first-child { background:
|
|
3315
|
+
.ed-block.ed-selected thead th:first-child { background: var(--md-ed-sel) !important; }
|
|
3254
3316
|
.ed-block.ed-selected:focus { outline: none; }
|
|
3255
3317
|
/* white-space: pre-line is LOAD-BEARING, not styling — do not relax it.
|
|
3256
3318
|
A hard-wrapped ("lazy continuation") list item's own content contains a
|
|
@@ -3270,9 +3332,10 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3270
3332
|
Task 5's and live in editModeLayoutCss (edit-mode only), fed by the hooks
|
|
3271
3333
|
renderEditModeList() emits here. */
|
|
3272
3334
|
.ed-block[data-block-type="li"] { cursor: text; }
|
|
3273
|
-
.ed-li-check { display: inline-block; width:
|
|
3274
|
-
border:
|
|
3275
|
-
.ed-li-check[data-checked="1"] {
|
|
3335
|
+
.ed-li-check { display: inline-block; width: 16px; height: 16px; margin-right: 6px; box-sizing: border-box;
|
|
3336
|
+
border: 1.5px solid var(--md-ed-glyph); border-radius: 4px; vertical-align: middle; cursor: pointer; }
|
|
3337
|
+
.ed-li-check[data-checked="1"] { border-color: var(--md-accent); background: var(--md-accent) url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' fill='none' stroke='white' stroke-width='3' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M20 6 9 17l-5-5'/%3E%3C/svg%3E") center / 12px no-repeat; }
|
|
3338
|
+
.ed-block[data-task="1"]:has(> .ed-li-check[data-checked="1"]) > .ed-li-text { color: var(--md-muted); text-decoration: line-through; }
|
|
3276
3339
|
/* Phase 3 Task 2: always-on paragraph/heading/list editing. Every eligible
|
|
3277
3340
|
block's content element is contenteditable from the moment it renders
|
|
3278
3341
|
(armEditables() in the client runtime) — no persistent outline (that
|
|
@@ -3283,8 +3346,8 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3283
3346
|
toggling. */
|
|
3284
3347
|
.ed-wys-armed { cursor: text; }
|
|
3285
3348
|
.ed-wys-armed:focus {
|
|
3286
|
-
outline: 2px solid
|
|
3287
|
-
caret-color:
|
|
3349
|
+
outline: 2px solid var(--md-accent); outline-offset: 2px;
|
|
3350
|
+
caret-color: var(--md-accent);
|
|
3288
3351
|
}
|
|
3289
3352
|
/* Task 5: table cells armed PERMANENTLY (one edit surface per CELL, not
|
|
3290
3353
|
per table root — see armEditables()'s 'table' branch in the client
|
|
@@ -3295,8 +3358,8 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3295
3358
|
table's horizontal edges. */
|
|
3296
3359
|
.ed-wys-cell { cursor: text; }
|
|
3297
3360
|
.ed-wys-cell:focus {
|
|
3298
|
-
outline: 2px solid
|
|
3299
|
-
caret-color:
|
|
3361
|
+
outline: 2px solid var(--md-accent); outline-offset: -2px;
|
|
3362
|
+
caret-color: var(--md-accent);
|
|
3300
3363
|
}
|
|
3301
3364
|
/* Phase 3 Task 2: the ⠿ block-actions handle — one real per-block node
|
|
3302
3365
|
(not a floating, JS-repositioned element like .ed-seltb/.ed-tb-insert),
|
|
@@ -3304,10 +3367,10 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3304
3367
|
visibility toggle (opacity), never display or pointer-events, so a
|
|
3305
3368
|
script-driven click still reaches it even without a real hover. */
|
|
3306
3369
|
.ed-handle {
|
|
3307
|
-
position: absolute; left: -22px; top: 0; width:
|
|
3370
|
+
position: absolute; left: -22px; top: 0; width: 24px; height: 24px;
|
|
3308
3371
|
display: flex; align-items: center; justify-content: center;
|
|
3309
3372
|
padding: 0; margin: 0; border: none; border-radius: 4px;
|
|
3310
|
-
background: transparent; color:
|
|
3373
|
+
background: transparent; color: var(--md-ed-glyph); font-size: 13px; line-height: 1;
|
|
3311
3374
|
cursor: pointer; opacity: 0; transition: opacity .12s ease, background .12s ease;
|
|
3312
3375
|
}
|
|
3313
3376
|
.ed-block:hover .ed-handle,
|
|
@@ -3323,7 +3386,7 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3323
3386
|
a recorded, unfixed residue. */
|
|
3324
3387
|
.ed-block.ed-keep-lit .ed-handle,
|
|
3325
3388
|
.ed-block.ed-keep-lit .ed-insert { opacity: 1; }
|
|
3326
|
-
.ed-handle:hover { background:
|
|
3389
|
+
.ed-handle:hover { background: var(--md-ed-hover); color: var(--md-strong); }
|
|
3327
3390
|
/* The ⠿ handle's menu: 轉換成 › / 建立副本 / 刪除 / MD 原始碼 (spec §3.7),
|
|
3328
3391
|
each led by a 16px currentColor icon (v2.12.0; drawn in
|
|
3329
3392
|
lib/editor/client.js's MENU_ICON_PATHS).
|
|
@@ -3341,8 +3404,8 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3341
3404
|
position: absolute; top: -4px; left: -4px; z-index: 6;
|
|
3342
3405
|
display: flex; flex-direction: column; align-items: stretch; gap: 2px;
|
|
3343
3406
|
padding: 4px; border-radius: 8px;
|
|
3344
|
-
background:
|
|
3345
|
-
box-shadow: 0
|
|
3407
|
+
background: var(--md-ed-surface); color: var(--md-strong);
|
|
3408
|
+
box-shadow: 0 0 0 1px var(--md-ed-ring), 0 8px 24px var(--md-ed-shadow);
|
|
3346
3409
|
}
|
|
3347
3410
|
.ed-handle-menu-btn {
|
|
3348
3411
|
/* v3.0.1: the icon sits FLUSH LEFT and the label sits one space-width
|
|
@@ -3350,8 +3413,8 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3350
3413
|
The right padding is untouched — it is what keeps the 轉換成 row's
|
|
3351
3414
|
chevron off the panel edge. */
|
|
3352
3415
|
min-width: 132px; height: 26px; padding: 0 10px 0 6px;
|
|
3353
|
-
border: 1px solid
|
|
3354
|
-
background:
|
|
3416
|
+
border: 1px solid transparent; border-radius: 6px;
|
|
3417
|
+
background: transparent; color: inherit;
|
|
3355
3418
|
font: inherit; font-size: 12px; line-height: 1;
|
|
3356
3419
|
text-align: left; white-space: nowrap; cursor: pointer;
|
|
3357
3420
|
/* v2.12.0: a flex ROW so the icon and the label share a baseline-free
|
|
@@ -3406,7 +3469,7 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3406
3469
|
tighter than the list at 18px per row. (No backticks in this comment:
|
|
3407
3470
|
it lives inside a JS template literal.) */
|
|
3408
3471
|
.ed-handle-submenu { left: 100%; margin-left: 4px; max-height: calc(100vh - 8px); overflow-y: auto; }
|
|
3409
|
-
.ed-handle-menu-btn:hover { background:
|
|
3472
|
+
.ed-handle-menu-btn:hover { background: var(--md-ed-hover); }
|
|
3410
3473
|
.ed-handle-menu-btn[hidden] { display: none; }
|
|
3411
3474
|
/* §10-gap fix: block-level INSERT — the + button sits NEXT TO the ⠿
|
|
3412
3475
|
handle in the left gutter, same node/visibility-toggle shape as
|
|
@@ -3430,32 +3493,32 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3430
3493
|
than deleted because it is the correct fallback if the gutter padding is
|
|
3431
3494
|
ever conditioned differently. */
|
|
3432
3495
|
.ed-insert {
|
|
3433
|
-
position: absolute; left: -22px;
|
|
3496
|
+
position: absolute; left: -22px; width: 24px; height: 24px;
|
|
3434
3497
|
display: flex; align-items: center; justify-content: center;
|
|
3435
3498
|
padding: 0; margin: 0; border: none; border-radius: 4px;
|
|
3436
|
-
background: transparent; color:
|
|
3499
|
+
background: transparent; color: var(--md-ed-glyph); font-size: 13px; line-height: 1;
|
|
3437
3500
|
cursor: pointer; opacity: 0; transition: opacity .12s ease, background .12s ease;
|
|
3438
3501
|
}
|
|
3439
3502
|
.ed-block:hover .ed-insert,
|
|
3440
3503
|
.ed-insert:focus { opacity: 1; }
|
|
3441
|
-
.ed-insert:hover { background:
|
|
3504
|
+
.ed-insert:hover { background: var(--md-ed-hover); color: var(--md-strong); }
|
|
3442
3505
|
/* The + button's small menu: 段落/標題/清單/表格/程式碼 — same dark
|
|
3443
3506
|
translucent pill language as .ed-handle-menu above. */
|
|
3444
3507
|
.ed-insert-menu {
|
|
3445
3508
|
position: absolute; top: -4px; left: -4px; z-index: 6;
|
|
3446
3509
|
display: flex; align-items: center; gap: 4px;
|
|
3447
3510
|
padding: 4px 6px; border-radius: 8px;
|
|
3448
|
-
background:
|
|
3449
|
-
box-shadow: 0
|
|
3511
|
+
background: var(--md-ed-surface); color: var(--md-strong);
|
|
3512
|
+
box-shadow: 0 0 0 1px var(--md-ed-ring), 0 8px 24px var(--md-ed-shadow);
|
|
3450
3513
|
}
|
|
3451
3514
|
.ed-insert-menu-btn {
|
|
3452
3515
|
min-width: 28px; height: 26px; padding: 0 8px;
|
|
3453
|
-
border: 1px solid
|
|
3454
|
-
background:
|
|
3516
|
+
border: 1px solid transparent; border-radius: 6px;
|
|
3517
|
+
background: transparent; color: inherit;
|
|
3455
3518
|
font: inherit; font-size: 12px; line-height: 1;
|
|
3456
3519
|
white-space: nowrap; cursor: pointer;
|
|
3457
3520
|
}
|
|
3458
|
-
.ed-insert-menu-btn:hover { background:
|
|
3521
|
+
.ed-insert-menu-btn:hover { background: var(--md-ed-hover); }
|
|
3459
3522
|
/* Task 5: hover-edge column/row insert bubbles — a SINGLETON pair of "+"
|
|
3460
3523
|
buttons (client runtime repositions them via getBoundingClientRect(),
|
|
3461
3524
|
never creates more than these two). Visual language deliberately
|
|
@@ -3468,11 +3531,11 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3468
3531
|
position: fixed; z-index: 8;
|
|
3469
3532
|
width: 18px; height: 18px; padding: 0; margin: 0;
|
|
3470
3533
|
display: flex; align-items: center; justify-content: center;
|
|
3471
|
-
border: 1px solid
|
|
3472
|
-
background:
|
|
3473
|
-
cursor: pointer; box-shadow: 0 1px
|
|
3534
|
+
border: 1px solid var(--md-accent); border-radius: 50%;
|
|
3535
|
+
background: var(--md-ed-surface); color: var(--md-accent); font-size: 13px; line-height: 1;
|
|
3536
|
+
cursor: pointer; box-shadow: 0 0 0 1px var(--md-ed-ring), 0 2px 6px var(--md-ed-shadow);
|
|
3474
3537
|
}
|
|
3475
|
-
.ed-tb-insert:hover { background:
|
|
3538
|
+
.ed-tb-insert:hover { background: var(--md-accent); color: var(--md-ed-surface); }
|
|
3476
3539
|
.ed-tb-insert[hidden] { display: none; }
|
|
3477
3540
|
/* Task 6: table edge-click menus (delete/align) + row drag-reorder.
|
|
3478
3541
|
'.ed-te-hl' marks the currently-selected column's or row's CELLS
|
|
@@ -3487,32 +3550,32 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3487
3550
|
relabeled/repositioned per click rather than rebuilt. '.ed-te-drop-
|
|
3488
3551
|
indicator' is the singleton line shown while dragging a row.
|
|
3489
3552
|
'.ed-te-row-dragging' dims the row actually being dragged. */
|
|
3490
|
-
.ed-te-hl { background:
|
|
3553
|
+
.ed-te-hl { background: var(--md-ed-sel) !important; }
|
|
3491
3554
|
/* Table cell-range selection: the painted rectangle, and the table that
|
|
3492
3555
|
holds one (its caret and native selection are hidden while it stands). */
|
|
3493
|
-
.ed-cell-range { background:
|
|
3556
|
+
.ed-cell-range { background: var(--md-ed-range) !important; }
|
|
3494
3557
|
.ed-cell-range-active { caret-color: transparent; }
|
|
3495
3558
|
.ed-cell-range-active ::selection { background: transparent; }
|
|
3496
3559
|
.ed-te-menu {
|
|
3497
3560
|
position: fixed; z-index: 12;
|
|
3498
3561
|
display: flex; align-items: center; gap: 4px;
|
|
3499
3562
|
padding: 4px 6px; border-radius: 8px;
|
|
3500
|
-
background:
|
|
3501
|
-
box-shadow: 0
|
|
3563
|
+
background: var(--md-ed-surface); color: var(--md-strong);
|
|
3564
|
+
box-shadow: 0 0 0 1px var(--md-ed-ring), 0 8px 24px var(--md-ed-shadow);
|
|
3502
3565
|
}
|
|
3503
3566
|
.ed-te-menu[hidden] { display: none; }
|
|
3504
3567
|
.ed-te-menu-btn {
|
|
3505
3568
|
min-width: 28px; height: 26px; padding: 0 8px;
|
|
3506
|
-
border: 1px solid
|
|
3507
|
-
background:
|
|
3569
|
+
border: 1px solid transparent; border-radius: 6px;
|
|
3570
|
+
background: transparent; color: inherit;
|
|
3508
3571
|
font: inherit; font-size: 12px; line-height: 1;
|
|
3509
3572
|
white-space: nowrap; cursor: pointer;
|
|
3510
3573
|
}
|
|
3511
|
-
.ed-te-menu-btn:hover { background:
|
|
3574
|
+
.ed-te-menu-btn:hover { background: var(--md-ed-hover); }
|
|
3512
3575
|
.ed-te-menu-btn[hidden] { display: none; }
|
|
3513
3576
|
.ed-te-drop-indicator {
|
|
3514
3577
|
position: fixed; z-index: 8; height: 3px; border-radius: 2px;
|
|
3515
|
-
background:
|
|
3578
|
+
background: var(--md-accent); pointer-events: none;
|
|
3516
3579
|
}
|
|
3517
3580
|
.ed-te-drop-indicator[hidden] { display: none; }
|
|
3518
3581
|
.ed-te-row-dragging { opacity: 0.4; }
|
|
@@ -3527,7 +3590,7 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3527
3590
|
the BLOCK line rather than table chrome that happened to be on screen. */
|
|
3528
3591
|
.ed-block-drop-indicator {
|
|
3529
3592
|
position: fixed; z-index: 8; height: 3px; border-radius: 2px;
|
|
3530
|
-
background:
|
|
3593
|
+
background: var(--md-accent); pointer-events: none;
|
|
3531
3594
|
}
|
|
3532
3595
|
.ed-block-drop-indicator[hidden] { display: none; }
|
|
3533
3596
|
/* S4 Task 2b (user request, 2026-09-01): the drag's feedback on the SOURCE
|
|
@@ -3579,9 +3642,9 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3579
3642
|
transition: background .12s ease;
|
|
3580
3643
|
}
|
|
3581
3644
|
.ed-te-grip[hidden] { display: none; }
|
|
3582
|
-
.ed-te-grip:hover { background:
|
|
3583
|
-
.ed-te-grip-dot { width: 3px; height: 3px; border-radius: 50%; background:
|
|
3584
|
-
.ed-te-grip:hover .ed-te-grip-dot { background:
|
|
3645
|
+
.ed-te-grip:hover { background: var(--md-ed-hover); }
|
|
3646
|
+
.ed-te-grip-dot { width: 3px; height: 3px; border-radius: 50%; background: var(--md-ed-glyph); }
|
|
3647
|
+
.ed-te-grip:hover .ed-te-grip-dot { background: var(--md-muted); }
|
|
3585
3648
|
/* spec §4.2 hit-test conflict 2: the row grip's width is a TOKEN because
|
|
3586
3649
|
lib/editor/client.js's updateTableEdgeGrips() reads it (via
|
|
3587
3650
|
gripRowWidthPx()) to CENTRE the grip on the table's left border —
|
|
@@ -3611,17 +3674,17 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3611
3674
|
position: fixed; z-index: 15;
|
|
3612
3675
|
display: flex; align-items: center; gap: 4px;
|
|
3613
3676
|
padding: 4px 6px; border-radius: 8px;
|
|
3614
|
-
background:
|
|
3615
|
-
box-shadow: 0
|
|
3677
|
+
background: var(--md-ed-surface); color: var(--md-strong);
|
|
3678
|
+
box-shadow: 0 0 0 1px var(--md-ed-ring), 0 8px 24px var(--md-ed-shadow);
|
|
3616
3679
|
}
|
|
3617
3680
|
.ed-seltb-btn {
|
|
3618
3681
|
min-width: 28px; height: 26px; padding: 0 8px;
|
|
3619
|
-
border: 1px solid
|
|
3620
|
-
background:
|
|
3682
|
+
border: 1px solid transparent; border-radius: 6px;
|
|
3683
|
+
background: transparent; color: inherit;
|
|
3621
3684
|
font: inherit; font-size: 13px; line-height: 1;
|
|
3622
3685
|
white-space: nowrap; cursor: pointer;
|
|
3623
3686
|
}
|
|
3624
|
-
.ed-seltb-btn:hover:not([aria-disabled="true"]) { background:
|
|
3687
|
+
.ed-seltb-btn:hover:not([aria-disabled="true"]) { background: var(--md-ed-hover); }
|
|
3625
3688
|
/* v3.3.0 (F2): the four states these buttons report about the selection.
|
|
3626
3689
|
'true' (the selection is entirely inside a mark of this type) is the
|
|
3627
3690
|
filled treatment the fixed toolbar already uses. 'mixed' (the selection
|
|
@@ -3631,17 +3694,18 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3631
3694
|
rule above. INERT is aria-disabled, never the disabled DOM property; see
|
|
3632
3695
|
paintSelToolbarMarks() in lib/editor/client.js for why. */
|
|
3633
3696
|
.ed-seltb-btn[aria-pressed="true"] {
|
|
3634
|
-
background:
|
|
3697
|
+
background: var(--md-active-bg); color: var(--md-active-fg); border-color: transparent;
|
|
3635
3698
|
}
|
|
3636
3699
|
.ed-seltb-btn[aria-pressed="mixed"] {
|
|
3637
|
-
background:
|
|
3638
|
-
border-style: dashed; border-color:
|
|
3700
|
+
background: transparent;
|
|
3701
|
+
border-style: dashed; border-color: var(--md-border);
|
|
3639
3702
|
}
|
|
3640
3703
|
.ed-seltb-btn[aria-disabled="true"] { opacity: 0.38; cursor: default; }
|
|
3641
|
-
.ed-seltb
|
|
3642
|
-
.ed-seltb-
|
|
3643
|
-
.ed-seltb-
|
|
3644
|
-
.ed-seltb-
|
|
3704
|
+
.ed-seltb { padding: 3px; gap: 2px; }
|
|
3705
|
+
.ed-seltb-btn { width: 30px; height: 30px; min-width: 0; padding: 0; display: inline-grid; place-items: center; color: var(--md-muted); }
|
|
3706
|
+
.ed-seltb-btn:hover:not([aria-disabled="true"]) { color: var(--md-strong); }
|
|
3707
|
+
.ed-seltb-sep { width: 1px; height: 18px; margin: 0 3px; background: var(--md-rule); align-self: center; }
|
|
3708
|
+
.ed-ico { display: block; flex: none; }
|
|
3645
3709
|
/* v3.1.0 §4: the always-visible editing toolbar. Its numeric language is
|
|
3646
3710
|
.lightbox-bar's (8px/12px padding, 6px gap, 13px type) over .ed-seltb's
|
|
3647
3711
|
dark pill, so the two floating surfaces read as one family.
|
|
@@ -3684,7 +3748,9 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3684
3748
|
save included, still reaches an empty unreachable list and an empty
|
|
3685
3749
|
neverClear list at all three — this change does not trade the T11-2
|
|
3686
3750
|
no-scroll guarantee for the F12 with-scroll one. */
|
|
3687
|
-
|
|
3751
|
+
/* v3.10.0 B 外觀: buttons grew to 32x32 (+~4px each) and separators to
|
|
3752
|
+
6px margins, so the gap went 3px -> 0 to keep outline (hamburger) inside 800px. */
|
|
3753
|
+
gap: 0; padding: 8px 12px;
|
|
3688
3754
|
/* F12, both halves measured on this build at 900px viewport height.
|
|
3689
3755
|
justify-content was center. Centering an overflowing flex row splits
|
|
3690
3756
|
the overflow across BOTH ends, and the leading end of a scroll
|
|
@@ -3704,9 +3770,13 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3704
3770
|
scrollLeft 0 after this change, [outline, preview] still overlap the
|
|
3705
3771
|
slot at a 900px viewport and [check, bold, italic, strike] do at 420px.
|
|
3706
3772
|
What makes that harmless is the slot's own pointer-events: none, in
|
|
3707
|
-
the rule further down — the load-bearing line, not this one.
|
|
3708
|
-
|
|
3709
|
-
|
|
3773
|
+
the rule further down — the load-bearing line, not this one.
|
|
3774
|
+
v3.10.0: 260px. The slot now carries the save state, and its longest
|
|
3775
|
+
text (the dirty one, "有未儲存的變更 · Ctrl+S 儲存" after a dot) is far
|
|
3776
|
+
wider than the old 7rem mode name. */
|
|
3777
|
+
padding-right: 260px;
|
|
3778
|
+
background: var(--md-ed-chrome); color: var(--md-muted);
|
|
3779
|
+
border-bottom: 1px solid var(--md-rule);
|
|
3710
3780
|
/* F12, second half: before this the bar scrolled but nothing on screen
|
|
3711
3781
|
said so, so a button parked outside the viewport looked absent rather
|
|
3712
3782
|
than off to one side. Two edge gradients, painted only on the side
|
|
@@ -3730,32 +3800,34 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3730
3800
|
than light — darkening the ground a translucent button sits on is what
|
|
3731
3801
|
reads as content passing under an edge, where a light wash behind the
|
|
3732
3802
|
same button would not. */
|
|
3733
|
-
--ed-tb-edge-l:
|
|
3734
|
-
--ed-tb-edge-r:
|
|
3803
|
+
--ed-tb-edge-l: transparent;
|
|
3804
|
+
--ed-tb-edge-r: transparent;
|
|
3735
3805
|
background-image:
|
|
3736
|
-
linear-gradient(to right, var(--ed-tb-edge-l),
|
|
3737
|
-
linear-gradient(to left, var(--ed-tb-edge-r),
|
|
3806
|
+
linear-gradient(to right, var(--ed-tb-edge-l), transparent),
|
|
3807
|
+
linear-gradient(to left, var(--ed-tb-edge-r), transparent);
|
|
3738
3808
|
background-repeat: no-repeat;
|
|
3739
3809
|
background-position: left center, right center;
|
|
3740
3810
|
background-size: 26px 100%, 26px 100%;
|
|
3741
3811
|
font-size: 13px;
|
|
3742
|
-
box-shadow:
|
|
3812
|
+
box-shadow: none;
|
|
3743
3813
|
}
|
|
3744
|
-
.ed-toolbar[data-ed-tb-overflow~="left"] { --ed-tb-edge-l:
|
|
3745
|
-
.ed-toolbar[data-ed-tb-overflow~="right"] { --ed-tb-edge-r:
|
|
3814
|
+
.ed-toolbar[data-ed-tb-overflow~="left"] { --ed-tb-edge-l: var(--md-ed-shadow); }
|
|
3815
|
+
.ed-toolbar[data-ed-tb-overflow~="right"] { --ed-tb-edge-r: var(--md-ed-shadow); }
|
|
3746
3816
|
.ed-toolbar-sep {
|
|
3747
|
-
flex: 0 0 auto; width: 1px; height:
|
|
3748
|
-
background:
|
|
3817
|
+
flex: 0 0 auto; width: 1px; height: 20px; margin: 0 6px;
|
|
3818
|
+
background: var(--md-rule);
|
|
3749
3819
|
}
|
|
3750
3820
|
.ed-toolbar-btn {
|
|
3751
3821
|
flex: 0 0 auto;
|
|
3752
|
-
min-width:
|
|
3753
|
-
|
|
3754
|
-
|
|
3822
|
+
min-width: 32px; height: 32px; padding: 0;
|
|
3823
|
+
display: inline-grid; place-items: center; color: var(--md-muted);
|
|
3824
|
+
border: 0 solid transparent; border-radius: 6px;
|
|
3825
|
+
background: transparent;
|
|
3755
3826
|
font: inherit; font-size: 13px; line-height: 1;
|
|
3756
3827
|
white-space: nowrap; cursor: pointer;
|
|
3757
3828
|
}
|
|
3758
|
-
.ed-toolbar-btn:hover:not(:disabled) { background:
|
|
3829
|
+
.ed-toolbar-btn:hover:not(:disabled) { background: var(--md-ed-hover); color: var(--md-strong); }
|
|
3830
|
+
.ed-toolbar-btn .ed-ico { width: 18px; height: 18px; }
|
|
3759
3831
|
/* F12: where the toolbar's keyboard cursor is. An outline rather than a
|
|
3760
3832
|
background so it stays legible on a button that is already pressed-in
|
|
3761
3833
|
(aria-pressed paints that one nearly white). Claim no more for it than a
|
|
@@ -3764,21 +3836,18 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3764
3836
|
follow, and what this cue does for a screen reader has not been measured
|
|
3765
3837
|
here. What it does do is let the row be walked without a mouse. */
|
|
3766
3838
|
.ed-toolbar-btn[data-ed-tb-cursor] {
|
|
3767
|
-
outline: 2px solid
|
|
3839
|
+
outline: 2px solid var(--md-accent); outline-offset: 1px;
|
|
3768
3840
|
}
|
|
3769
3841
|
.ed-toolbar-btn:disabled { opacity: 0.38; cursor: default; }
|
|
3770
3842
|
.ed-toolbar-btn[aria-pressed="true"] {
|
|
3771
|
-
background:
|
|
3843
|
+
background: var(--md-active-bg); color: var(--md-active-fg); border-color: transparent;
|
|
3772
3844
|
}
|
|
3773
3845
|
/* v3.3.0 (F2): the middle state, matching .ed-seltb-btn[aria-pressed="mixed"]
|
|
3774
3846
|
above so the two bars answer the same question the same way. */
|
|
3775
3847
|
.ed-toolbar-btn[aria-pressed="mixed"] {
|
|
3776
|
-
background:
|
|
3777
|
-
border-style: dashed; border-color:
|
|
3848
|
+
background: transparent;
|
|
3849
|
+
border-width: 1px; border-style: dashed; border-color: var(--md-border);
|
|
3778
3850
|
}
|
|
3779
|
-
.ed-toolbar-b { font-weight: bold; }
|
|
3780
|
-
.ed-toolbar-i { font-style: italic; }
|
|
3781
|
-
.ed-toolbar-s { text-decoration: line-through; }
|
|
3782
3851
|
/* H1 fix — and its reason has since moved, so both readings are kept here
|
|
3783
3852
|
rather than one silently standing in for the other. The brief's literal
|
|
3784
3853
|
margin-left: auto (a flex-flow item) was measured on v3.2.0 to break
|
|
@@ -3824,9 +3893,13 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3824
3893
|
regression, this time on content someone can actually see and try to
|
|
3825
3894
|
click. */
|
|
3826
3895
|
.ed-toolbar-status { position: fixed; top: 0; right: 12px;
|
|
3827
|
-
height: var(--ed-toolbar-h);
|
|
3828
|
-
min-width: 7rem;
|
|
3896
|
+
height: var(--ed-toolbar-h); display: flex; align-items: center; gap: 6px;
|
|
3897
|
+
min-width: 7rem; justify-content: flex-end; font-size: 13px; color: var(--md-muted);
|
|
3829
3898
|
pointer-events: none; }
|
|
3899
|
+
.ed-toolbar-status[data-state="clean"] .ed-ico { color: var(--md-ed-ok); }
|
|
3900
|
+
.ed-toolbar-status[data-state="failed"] { color: var(--md-ed-err); }
|
|
3901
|
+
.ed-status-dot { width: 8px; height: 8px; border-radius: 50%; background: var(--md-ed-dirty); display: inline-block; }
|
|
3902
|
+
.ed-toolbar-btn[data-ed-tb="save"][aria-pressed="true"] { color: var(--md-accent); background: var(--md-active-bg); }
|
|
3830
3903
|
/* The H▾ dropdown: same singleton-panel idiom as .ed-insert-menu, but
|
|
3831
3904
|
anchored to a fixed bar rather than moved into a block, so it is
|
|
3832
3905
|
positioned in viewport coordinates by the client runtime.
|
|
@@ -3839,8 +3912,8 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3839
3912
|
position: fixed; z-index: 102;
|
|
3840
3913
|
display: flex; flex-direction: column; gap: 2px;
|
|
3841
3914
|
padding: 4px; border-radius: 8px;
|
|
3842
|
-
background:
|
|
3843
|
-
box-shadow: 0
|
|
3915
|
+
background: var(--md-ed-surface); color: var(--md-strong);
|
|
3916
|
+
box-shadow: 0 0 0 1px var(--md-ed-ring), 0 8px 24px var(--md-ed-shadow);
|
|
3844
3917
|
max-height: calc(100vh - 8px); overflow-y: auto;
|
|
3845
3918
|
}
|
|
3846
3919
|
.ed-toolbar-menu[hidden] { display: none; }
|
|
@@ -3849,7 +3922,7 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3849
3922
|
border: none; border-radius: 4px; background: transparent; color: inherit;
|
|
3850
3923
|
font: inherit; font-size: 13px; line-height: 1.4; cursor: pointer;
|
|
3851
3924
|
}
|
|
3852
|
-
.ed-toolbar-menu-btn:hover { background:
|
|
3925
|
+
.ed-toolbar-menu-btn:hover { background: var(--md-ed-hover); }
|
|
3853
3926
|
/* backlog #7 (Task 9 review, M1): the panel's OWN keyboard cursor
|
|
3854
3927
|
(lib/editor/client.js's toolbarMenuIndex / data-ed-tb-menu-cursor) had
|
|
3855
3928
|
no matching rule at all — the fix made the six items operable by
|
|
@@ -3859,32 +3932,24 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3859
3932
|
over :hover's own background, and over nothing at all when neither
|
|
3860
3933
|
applies). */
|
|
3861
3934
|
.ed-toolbar-menu-btn[data-ed-tb-menu-cursor] {
|
|
3862
|
-
outline: 2px solid
|
|
3863
|
-
background:
|
|
3864
|
-
}
|
|
3865
|
-
/* 追加 4: the whole-document source escape hatch. Replaces the rendered
|
|
3866
|
-
content column for the duration of source mode; the document's own
|
|
3867
|
-
lines[] is untouched until the mode is left (see docsource.js). */
|
|
3868
|
-
.ed-source {
|
|
3869
|
-
display: block; width: 100%; box-sizing: border-box;
|
|
3870
|
-
min-height: 70vh; padding: 12px;
|
|
3871
|
-
font-family: monospace; font-size: 13px; line-height: 1.6;
|
|
3872
|
-
border: 1px solid #d0d7de; border-radius: 8px; resize: vertical;
|
|
3873
|
-
white-space: pre; overflow-wrap: normal;
|
|
3935
|
+
outline: 2px solid var(--md-accent); outline-offset: -2px;
|
|
3936
|
+
background: var(--md-ed-hover);
|
|
3874
3937
|
}
|
|
3875
3938
|
.ed-editing { position: relative; }
|
|
3876
3939
|
.ed-raw {
|
|
3877
|
-
display: block; width: 100%; font-family: monospace; font-size: 13px;
|
|
3940
|
+
display: block; width: 100%; font-family: "Cascadia Mono", Consolas, ui-monospace, monospace; font-size: 13px;
|
|
3878
3941
|
min-height: 3em; box-sizing: border-box; padding: 6px;
|
|
3879
|
-
border: 1px solid
|
|
3942
|
+
border: 1px solid var(--md-border); border-radius: 6px;
|
|
3943
|
+
background: var(--md-ed-field); color: var(--md-strong); resize: vertical;
|
|
3880
3944
|
}
|
|
3881
3945
|
.ed-controls { display: flex; gap: 6px; margin-top: 4px; }
|
|
3882
3946
|
.ed-controls button {
|
|
3883
3947
|
font-size: 13px; padding: 2px 10px; cursor: pointer;
|
|
3884
|
-
border: 1px solid
|
|
3948
|
+
border: 1px solid var(--md-border); border-radius: 6px;
|
|
3949
|
+
background: var(--md-ed-surface); color: var(--md-strong);
|
|
3885
3950
|
}
|
|
3886
|
-
.ed-commit { color:
|
|
3887
|
-
.ed-cancel { color:
|
|
3951
|
+
.ed-commit { color: var(--md-ed-ok); }
|
|
3952
|
+
.ed-cancel { color: var(--md-ed-err); }
|
|
3888
3953
|
/* backlog #8: 'top: 0' used to put this banner directly OVER .ed-toolbar
|
|
3889
3954
|
(same top-of-viewport band, and z-index 999 against the bar's 101 wins
|
|
3890
3955
|
the paint) — MEASURED (task-10-toolbar-probe.js): all 23 toolbar
|
|
@@ -3921,16 +3986,38 @@ ${usesDrawio ? ` /* v3.4.0 §4: a document with no drawio reference must not pa
|
|
|
3921
3986
|
land nearby as a side effect of their own trigger's position, not a
|
|
3922
3987
|
shared clamp — see showBanner()'s parallel comment in
|
|
3923
3988
|
lib/editor/client.js. Closed regardless, so a banner can never land on
|
|
3924
|
-
top of one of those instead.
|
|
3989
|
+
top of one of those instead.
|
|
3990
|
+
v3.10.0 (two message levels): only the ERROR card floors at the token
|
|
3991
|
+
now — its top is --ed-toolbar-h plus 10px, a centred card rather than a
|
|
3992
|
+
full-width band — and a NOTICE sits at the bottom of the viewport, so it
|
|
3993
|
+
never reaches the toolbar's band at all. */
|
|
3994
|
+
/* Centred with left/right + auto margins and a fit-content width, NOT
|
|
3995
|
+
left: 50% + translateX(-50%): a fixed box anchored at left: 50% may only
|
|
3996
|
+
grow into the right half of the viewport, so the 760px cap never applied
|
|
3997
|
+
and a long message wrapped into a card half the viewport wide and several
|
|
3998
|
+
times as tall (measured 800x600: 400px wide, y 54-284, covering the
|
|
3999
|
+
waveform editor's group buttons). */
|
|
3925
4000
|
.ed-conflict {
|
|
3926
|
-
position: fixed;
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
4001
|
+
position: fixed; left: 16px; right: 16px; margin: 0 auto; width: fit-content; z-index: 999;
|
|
4002
|
+
display: flex; align-items: center; gap: 10px;
|
|
4003
|
+
max-width: 760px; box-sizing: border-box;
|
|
4004
|
+
padding: 10px 10px 10px 14px; border-radius: 8px; font-size: 14px; line-height: 1.5;
|
|
4005
|
+
}
|
|
4006
|
+
.ed-conflict[data-level="error"] {
|
|
4007
|
+
top: calc(var(--ed-toolbar-h) + 10px);
|
|
4008
|
+
background: var(--md-ed-err-bg); color: var(--md-ed-err-ink);
|
|
4009
|
+
box-shadow: inset 3px 0 0 var(--md-ed-err), 0 0 0 1px var(--md-ed-ring), 0 8px 24px var(--md-ed-shadow);
|
|
4010
|
+
}
|
|
4011
|
+
.ed-conflict[data-level="notice"] {
|
|
4012
|
+
bottom: 28px; background: var(--md-ed-surface); color: var(--md-strong);
|
|
4013
|
+
box-shadow: 0 0 0 1px var(--md-ed-ring), 0 8px 24px var(--md-ed-shadow);
|
|
4014
|
+
}
|
|
4015
|
+
.ed-msg-ico { display: grid; color: var(--md-muted); }
|
|
4016
|
+
.ed-conflict[data-level="error"] .ed-msg-ico { color: var(--md-ed-err); }
|
|
4017
|
+
.ed-msg-text { flex: 1 1 auto; }
|
|
4018
|
+
.ed-conflict button { font: inherit; font-size: 13px; font-weight: 600; border: 0; border-radius: 6px;
|
|
4019
|
+
padding: 4px 12px; cursor: pointer; background: var(--md-ed-err); color: var(--md-ed-surface); }
|
|
4020
|
+
.ed-conflict button.ed-msg-x { background: transparent; color: inherit; padding: 4px; display: grid; }
|
|
3934
4021
|
${opts.editMode ? editModeLayoutCss : ''}
|
|
3935
4022
|
</style>
|
|
3936
4023
|
${usesMath ? buildKatexStyleTag() : ''}
|
|
@@ -5949,8 +6036,8 @@ ${usesDrawioMultiPage ? ` // v3.4.0 batch2 Task 6: wired through a NAMED, reusa
|
|
|
5949
6036
|
await drawioBrowser.closeIfOpen();
|
|
5950
6037
|
}
|
|
5951
6038
|
// v3.9.0 dark mode: a post-pass over the finished reader HTML (lib/theme/).
|
|
5952
|
-
//
|
|
5953
|
-
if (!opts.
|
|
6039
|
+
// v3.10.0: edit mode is themed too. noTheme is an internal switch for the light-lock test.
|
|
6040
|
+
if (!opts.noTheme) bakedHtml = applyReaderTheme(bakedHtml);
|
|
5954
6041
|
return {
|
|
5955
6042
|
html: bakedHtml, bodyHtml: bakedBody, parts, blocks,
|
|
5956
6043
|
// v3.4.0 batch2 Task 6: an added field, not a shape change to the four
|