mrmd-editor 0.7.1 → 0.8.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.
Files changed (58) hide show
  1. package/package.json +3 -1
  2. package/src/commands.js +112 -4
  3. package/src/comment-syntax.js +364 -39
  4. package/src/config/handlers.js +1 -2
  5. package/src/config/schema.js +46 -4
  6. package/src/document-template.js +2236 -0
  7. package/src/frontmatter-updater.js +204 -74
  8. package/src/grammar.js +758 -0
  9. package/src/index.js +1074 -55
  10. package/src/keymap.js +11 -2
  11. package/src/markdown/block-decorations.js +108 -5
  12. package/src/markdown/facets.js +37 -0
  13. package/src/markdown/html-inline.js +9 -5
  14. package/src/markdown/index.js +13 -3
  15. package/src/markdown/inline-commands.js +256 -0
  16. package/src/markdown/inline-model.js +578 -0
  17. package/src/markdown/inline-state.js +103 -0
  18. package/src/markdown/renderer.js +219 -12
  19. package/src/markdown/styles.js +290 -3
  20. package/src/markdown/widgets/alert-title.js +10 -8
  21. package/src/markdown/widgets/frontmatter.js +0 -6
  22. package/src/markdown/widgets/index.js +1 -0
  23. package/src/markdown/widgets/list-marker.js +29 -0
  24. package/src/markdown/wysiwyg.js +1158 -0
  25. package/src/mrp-types.js +2 -0
  26. package/src/output-widget.js +532 -18
  27. package/src/page-view-pagination.js +127 -0
  28. package/src/runtime-lsp.js +1757 -150
  29. package/src/section-controls/commands.js +617 -0
  30. package/src/section-controls/index.js +63 -0
  31. package/src/section-controls/plugin.js +165 -0
  32. package/src/section-controls/widgets.js +936 -0
  33. package/src/shell/ai-menu.js +11 -0
  34. package/src/shell/components/context-panel.js +572 -0
  35. package/src/shell/components/status-bar.js +10 -2
  36. package/src/shell/layouts/studio.js +206 -14
  37. package/src/shell/orchestrator-client.js +69 -0
  38. package/src/spellcheck.js +166 -0
  39. package/src/tables/README.md +97 -0
  40. package/src/tables/commands/insert-linked-table.js +122 -0
  41. package/src/tables/commands/open-table-workspace.js +43 -0
  42. package/src/tables/index.js +24 -0
  43. package/src/tables/jobs/client.js +158 -0
  44. package/src/tables/parsing/anchors.js +82 -0
  45. package/src/tables/parsing/linked-table-blocks.js +61 -0
  46. package/src/tables/state/linked-table-state.js +68 -0
  47. package/src/tables/widgets/linked-table-source-banner.js +77 -0
  48. package/src/tables/widgets/linked-table-widget.js +256 -0
  49. package/src/tables/workspace/controller.js +616 -0
  50. package/src/term-pty-client.js +51 -2
  51. package/src/term-widget.js +43 -3
  52. package/src/widgets/theme-utils.js +24 -16
  53. package/src/widgets/theme.js +1015 -1
  54. package/src/runtime-codelens/detector.js +0 -279
  55. package/src/runtime-codelens/index.js +0 -76
  56. package/src/runtime-codelens/plugin.js +0 -142
  57. package/src/runtime-codelens/styles.js +0 -184
  58. package/src/runtime-codelens/widgets.js +0 -216
@@ -15,6 +15,7 @@
15
15
  import { ViewPlugin, Decoration, WidgetType } from '@codemirror/view';
16
16
  import { Facet } from '@codemirror/state';
17
17
  import { syntaxTree } from '@codemirror/language';
18
+ import { sourceModeFacet, wysiwygModeFacet } from './facets.js';
18
19
 
19
20
  // =============================================================================
20
21
  // Asset Resolver Facet
@@ -49,6 +50,7 @@ import {
49
50
  // Tables handled by StateField (block-decorations.js) - multi-line replace not allowed in ViewPlugin
50
51
  import { TaskCheckboxWidget } from './widgets/checkbox.js';
51
52
  import { AlertTitleWidget } from './widgets/alert-title.js';
53
+ import { ListMarkerWidget } from './widgets/list-marker.js';
52
54
  import {
53
55
  InlineMathWidget,
54
56
  extractInlineMath,
@@ -239,6 +241,93 @@ class ImageSpacerWidget extends WidgetType {
239
241
  }
240
242
  }
241
243
 
244
+ const ALERT_TYPE_MAP = {
245
+ note: 'note',
246
+ tip: 'tip',
247
+ important: 'important',
248
+ warning: 'warning',
249
+ caution: 'caution',
250
+ info: 'note',
251
+ abstract: 'note',
252
+ success: 'tip',
253
+ question: 'important',
254
+ failure: 'caution',
255
+ danger: 'caution',
256
+ bug: 'caution',
257
+ };
258
+
259
+ function toTitleCase(text) {
260
+ if (!text) return '';
261
+ return text
262
+ .replace(/[-_]+/g, ' ')
263
+ .trim()
264
+ .split(/\s+/)
265
+ .map((w) => w.charAt(0).toUpperCase() + w.slice(1).toLowerCase())
266
+ .join(' ');
267
+ }
268
+
269
+ function normalizeAlertType(type) {
270
+ const lower = (type || '').toLowerCase();
271
+ return ALERT_TYPE_MAP[lower] || 'note';
272
+ }
273
+
274
+ /**
275
+ * Find MkDocs-style admonitions:
276
+ *
277
+ * !!! tip
278
+ * indented body
279
+ */
280
+ function findBangAdmonitions(doc) {
281
+ const ranges = [];
282
+
283
+ for (let i = 1; i <= doc.lines; i++) {
284
+ const startLine = doc.line(i);
285
+ const match = startLine.text.match(/^(\s*)!!!\s+([A-Za-z][\w-]*)(?:\s+"([^"]+)")?\s*$/);
286
+ if (!match) continue;
287
+
288
+ const baseIndent = match[1] || '';
289
+ const bodyIndentSpaces = `${baseIndent} `;
290
+ const bodyIndentTab = `${baseIndent}\t`;
291
+
292
+ let endLine = i;
293
+ let hasBody = false;
294
+
295
+ for (let j = i + 1; j <= doc.lines; j++) {
296
+ const lineText = doc.line(j).text;
297
+
298
+ if (lineText.trim() === '') {
299
+ if (hasBody) {
300
+ endLine = j;
301
+ continue;
302
+ }
303
+ break;
304
+ }
305
+
306
+ if (lineText.startsWith(bodyIndentSpaces) || lineText.startsWith(bodyIndentTab)) {
307
+ hasBody = true;
308
+ endLine = j;
309
+ continue;
310
+ }
311
+
312
+ break;
313
+ }
314
+
315
+ ranges.push({
316
+ startLine: i,
317
+ endLine,
318
+ headerIndent: baseIndent.length,
319
+ bodyIndentSpaces,
320
+ bodyIndentTab,
321
+ alertType: normalizeAlertType(match[2]),
322
+ title: match[3] || toTitleCase(match[2]),
323
+ });
324
+
325
+ i = endLine;
326
+ }
327
+
328
+ return ranges;
329
+ }
330
+
242
331
  /**
243
332
  * Build decorations for all markdown elements in the viewport.
244
333
  *
@@ -252,6 +341,10 @@ function buildDecorations(view) {
252
341
  const cursorLine = doc.lineAt(cursorPos).number;
253
342
  const frontmatterRange = findFrontmatterRange(doc);
254
343
 
344
+ // Mode flags
345
+ const isSourceMode = view.state.facet(sourceModeFacet);
346
+ const isWysiwygMode = view.state.facet(wysiwygModeFacet);
347
+
255
348
  // Get asset resolver from facet (may be null)
256
349
  const assetResolver = view.state.facet(assetResolverFacet);
257
350
 
@@ -292,7 +385,7 @@ function buildDecorations(view) {
292
385
  }
293
386
  }
294
387
 
295
- const isActiveLine = lineNum === cursorLine;
388
+ const isActiveLine = isSourceMode || (!isWysiwygMode && lineNum === cursorLine);
296
389
 
297
390
  // Marker class: hidden on blur, muted on focus
298
391
  const markerClass = isActiveLine ? 'cm-md-marker' : 'cm-md-hidden';
@@ -386,8 +479,9 @@ function buildDecorations(view) {
386
479
  // Code backticks (inline only, not fenced code)
387
480
  if (node.name === 'CodeMark') {
388
481
  const text = doc.sliceString(node.from, node.to);
389
- // Only hide single/double backticks, not fenced code markers (```)
390
- if (text.length < 3) {
482
+ // In normal rendered mode, only hide inline backticks.
483
+ // In WYSIWYG mode, also hide fenced code markers.
484
+ if (text.length < 3 || isWysiwygMode) {
391
485
  decorations.push(
392
486
  Decoration.mark({ class: markerClass }).range(node.from, node.to)
393
487
  );
@@ -429,7 +523,7 @@ function buildDecorations(view) {
429
523
  const linkUrl = linkMatch[2];
430
524
 
431
525
  const linkLine = doc.lineAt(node.from).number;
432
- const isLinkActive = linkLine === cursorLine;
526
+ const isLinkActive = isSourceMode || (!isWysiwygMode && linkLine === cursorLine);
433
527
 
434
528
  if (isLinkActive) {
435
529
  // Show raw markdown with styling on active line
@@ -517,7 +611,7 @@ function buildDecorations(view) {
517
611
  }
518
612
 
519
613
  // Replace the alert marker [!TYPE] with widget when not on that line
520
- if (alertType && startLine.number !== cursorLine) {
614
+ if (alertType && !isSourceMode && (isWysiwygMode || startLine.number !== cursorLine)) {
521
615
  const markerStart = startLine.from + firstLineText.indexOf('[!');
522
616
  const markerEnd = startLine.from + firstLineText.indexOf(']') + 1;
523
617
  if (markerStart >= startLine.from && markerEnd > markerStart) {
@@ -541,9 +635,30 @@ function buildDecorations(view) {
541
635
  // LISTS
542
636
  // =======================================================================
543
637
  if (node.name === 'ListMark') {
544
- decorations.push(
545
- Decoration.mark({ class: 'cm-md-list-marker' }).range(node.from, node.to)
546
- );
638
+ const line = doc.lineAt(node.from);
639
+ const listMarkText = doc.sliceString(node.from, node.to);
640
+ const isListActive = isSourceMode || (!isWysiwygMode && line.number === cursorLine);
641
+ const isUnordered = /^[-+*]$/.test(listMarkText);
642
+ const textAfterMarker = doc.sliceString(node.to, Math.min(node.to + 6, line.to));
643
+ const isTaskItem = /^\s+\[[ xX]\]/.test(textAfterMarker);
644
+
645
+ if (isListActive) {
646
+ decorations.push(
647
+ Decoration.mark({ class: 'cm-md-marker cm-md-list-marker' }).range(node.from, node.to)
648
+ );
649
+ } else if (isUnordered && !isTaskItem) {
650
+ decorations.push(
651
+ Decoration.replace({ widget: new ListMarkerWidget() }).range(node.from, node.to)
652
+ );
653
+ } else if (isTaskItem) {
654
+ decorations.push(
655
+ Decoration.mark({ class: 'cm-md-hidden' }).range(node.from, node.to)
656
+ );
657
+ } else {
658
+ decorations.push(
659
+ Decoration.mark({ class: 'cm-md-list-marker cm-md-list-number' }).range(node.from, node.to)
660
+ );
661
+ }
547
662
  }
548
663
 
549
664
  // Task list checkboxes: - [ ] or - [x]
@@ -559,7 +674,7 @@ function buildDecorations(view) {
559
674
 
560
675
  // Don't render widget if cursor is on this line
561
676
  const itemLine = doc.lineAt(node.from);
562
- if (itemLine.number !== cursorLine) {
677
+ if (!isSourceMode && (isWysiwygMode || itemLine.number !== cursorLine)) {
563
678
  // Replace [ ], [x], or [X] with checkbox widget
564
679
  decorations.push(
565
680
  Decoration.replace({
@@ -583,6 +698,27 @@ function buildDecorations(view) {
583
698
  );
584
699
  }
585
700
 
701
+ // =======================================================================
702
+ // PAGE BREAKS (\pagebreak, \newpage)
703
+ // Detected as single-line paragraphs containing only the command.
704
+ // In WYSIWYG mode, rendered as a visual break indicator.
705
+ // =======================================================================
706
+ if (node.name === 'Paragraph' || node.name === 'HTMLBlock') {
707
+ const nodeText = doc.sliceString(node.from, node.to).trim();
708
+ if (/^\\(pagebreak|newpage)$/.test(nodeText) ||
709
+ /^<div\s+style\s*=\s*["']page-break-after:\s*always;?["']\s*>\s*<\/div>$/i.test(nodeText)) {
710
+ const line = doc.lineAt(node.from);
711
+ decorations.push(
712
+ Decoration.line({ class: 'cm-pagebreak-line' }).range(line.from)
713
+ );
714
+ if (!isActiveLine) {
715
+ decorations.push(
716
+ Decoration.mark({ class: 'cm-md-hidden' }).range(node.from, node.to)
717
+ );
718
+ }
719
+ }
720
+ }
721
+
586
722
  // =======================================================================
587
723
  // IMAGES
588
724
  // =======================================================================
@@ -769,6 +905,72 @@ function buildDecorations(view) {
769
905
  }
770
906
  });
771
907
 
908
+ // ==========================================================================
909
+ // MKDOCS-STYLE ADMONITIONS: !!! tip / !!! warning / ...
910
+ // ==========================================================================
911
+ const bangAdmonitions = findBangAdmonitions(doc);
912
+ const viewportStartLine = doc.lineAt(view.viewport.from).number;
913
+ const viewportEndLine = doc.lineAt(view.viewport.to).number;
914
+
915
+ for (const admonition of bangAdmonitions) {
916
+ // Skip if out of viewport
917
+ if (admonition.endLine < viewportStartLine || admonition.startLine > viewportEndLine) {
918
+ continue;
919
+ }
920
+
921
+ // Skip if inside frontmatter or fenced code block
922
+ if (
923
+ (frontmatterRange &&
924
+ admonition.startLine >= frontmatterRange.startLine &&
925
+ admonition.startLine <= frontmatterRange.endLine) ||
926
+ codeBlockLines.has(admonition.startLine)
927
+ ) {
928
+ continue;
929
+ }
930
+
931
+ const cursorInAdmonition = isSourceMode || (!isWysiwygMode && cursorLine >= admonition.startLine && cursorLine <= admonition.endLine);
932
+ if (cursorInAdmonition) {
933
+ continue;
934
+ }
935
+
936
+ const visibleStart = Math.max(admonition.startLine, viewportStartLine);
937
+ const visibleEnd = Math.min(admonition.endLine, viewportEndLine);
938
+
939
+ for (let lineNum = visibleStart; lineNum <= visibleEnd; lineNum++) {
940
+ const line = doc.line(lineNum);
941
+ const classes = [
942
+ `cm-md-alert-${admonition.alertType}`,
943
+ 'cm-md-admonition-line',
944
+ ];
945
+
946
+ if (lineNum === admonition.startLine) classes.push('cm-md-admonition-start', 'cm-md-admonition-title-line');
947
+ if (lineNum === admonition.endLine) classes.push('cm-md-admonition-end');
948
+
949
+ decorations.push(
950
+ Decoration.line({ class: classes.join(' ') }).range(line.from)
951
+ );
952
+
953
+ if (lineNum === admonition.startLine) {
954
+ const from = line.from + admonition.headerIndent;
955
+ if (from < line.to) {
956
+ decorations.push(
957
+ Decoration.replace({
958
+ widget: new AlertTitleWidget(admonition.alertType, admonition.title),
959
+ }).range(from, line.to)
960
+ );
961
+ }
962
+ } else if (line.text.startsWith(admonition.bodyIndentSpaces)) {
963
+ decorations.push(
964
+ Decoration.mark({ class: 'cm-md-hidden' }).range(line.from, line.from + admonition.bodyIndentSpaces.length)
965
+ );
966
+ } else if (line.text.startsWith(admonition.bodyIndentTab)) {
967
+ decorations.push(
968
+ Decoration.mark({ class: 'cm-md-hidden' }).range(line.from, line.from + admonition.bodyIndentTab.length)
969
+ );
970
+ }
971
+ }
972
+ }
973
+
772
974
  // ==========================================================================
773
975
  // INLINE MATH: $...$ (single line only)
774
976
  // ==========================================================================
@@ -776,7 +978,7 @@ function buildDecorations(view) {
776
978
  // Process line by line in viewport
777
979
  for (let i = doc.lineAt(view.viewport.from).number; i <= doc.lineAt(view.viewport.to).number; i++) {
778
980
  const line = doc.line(i);
779
- const isActiveLine = i === cursorLine;
981
+ const isActiveLine = isSourceMode || (!isWysiwygMode && i === cursorLine);
780
982
 
781
983
  // Skip frontmatter lines
782
984
  if (frontmatterRange && i >= frontmatterRange.startLine && i <= frontmatterRange.endLine) continue;
@@ -814,7 +1016,7 @@ function buildDecorations(view) {
814
1016
  // ==========================================================================
815
1017
  for (let i = doc.lineAt(view.viewport.from).number; i <= doc.lineAt(view.viewport.to).number; i++) {
816
1018
  const line = doc.line(i);
817
- const isActiveLine = i === cursorLine;
1019
+ const isActiveLine = isSourceMode || (!isWysiwygMode && i === cursorLine);
818
1020
 
819
1021
  // Skip frontmatter lines
820
1022
  if (frontmatterRange && i >= frontmatterRange.startLine && i <= frontmatterRange.endLine) continue;
@@ -857,7 +1059,7 @@ function buildDecorations(view) {
857
1059
 
858
1060
  for (let i = doc.lineAt(view.viewport.from).number; i <= doc.lineAt(view.viewport.to).number; i++) {
859
1061
  const line = doc.line(i);
860
- const isActiveLine = i === cursorLine;
1062
+ const isActiveLine = isSourceMode || (!isWysiwygMode && i === cursorLine);
861
1063
 
862
1064
  // Skip frontmatter lines
863
1065
  if (frontmatterRange && i >= frontmatterRange.startLine && i <= frontmatterRange.endLine) continue;
@@ -868,6 +1070,11 @@ function buildDecorations(view) {
868
1070
  const htmlElements = extractHtmlElements(line.text);
869
1071
 
870
1072
  for (const el of htmlElements) {
1073
+ // Underline is handled by the shared inline formatting model so it can
1074
+ // participate in semantic toggling like bold/italic instead of being
1075
+ // rendered as an opaque HTML widget.
1076
+ if (el.tag === 'u') continue;
1077
+
871
1078
  const from = line.from + el.start;
872
1079
  const to = line.from + el.end;
873
1080
 
@@ -102,6 +102,12 @@ export const markdownStyles = `
102
102
  font-style: italic;
103
103
  }
104
104
 
105
+ .cm-md-underline {
106
+ text-decoration: underline;
107
+ text-decoration-thickness: 1px;
108
+ text-underline-offset: 2px;
109
+ }
110
+
105
111
  .cm-md-strikethrough {
106
112
  text-decoration: line-through;
107
113
  opacity: 0.7;
@@ -217,22 +223,58 @@ export const markdownStyles = `
217
223
 
218
224
  .cm-md-alert-note {
219
225
  border-left-color: var(--md-alert-note-color);
226
+ --md-alert-accent: var(--md-alert-note-color);
220
227
  }
221
228
 
222
229
  .cm-md-alert-tip {
223
230
  border-left-color: var(--md-alert-tip-color);
231
+ --md-alert-accent: var(--md-alert-tip-color);
224
232
  }
225
233
 
226
234
  .cm-md-alert-important {
227
235
  border-left-color: var(--md-alert-important-color);
236
+ --md-alert-accent: var(--md-alert-important-color);
228
237
  }
229
238
 
230
239
  .cm-md-alert-warning {
231
240
  border-left-color: var(--md-alert-warning-color);
241
+ --md-alert-accent: var(--md-alert-warning-color);
232
242
  }
233
243
 
234
244
  .cm-md-alert-caution {
235
245
  border-left-color: var(--md-alert-caution-color);
246
+ --md-alert-accent: var(--md-alert-caution-color);
247
+ }
248
+
249
+ /* MkDocs-style !!! admonitions (card style with title bar) */
250
+ .cm-md-admonition-line {
251
+ border-left: var(--md-admonition-border-width, 1px) solid var(--md-admonition-border-color, color-mix(in srgb, var(--md-alert-accent, var(--widget-border-accent)) 46%, var(--widget-border) 54%));
252
+ border-right: var(--md-admonition-border-width, 1px) solid var(--md-admonition-border-color, color-mix(in srgb, var(--md-alert-accent, var(--widget-border-accent)) 46%, var(--widget-border) 54%));
253
+ background: var(--md-admonition-body-background, var(--md-admonition-background, color-mix(in srgb, var(--md-alert-accent, var(--widget-border-accent)) 5%, var(--editor-background, transparent) 95%)));
254
+ color: var(--md-admonition-text-color, inherit);
255
+ padding-left: var(--md-admonition-padding-x, 0.9em);
256
+ padding-right: var(--md-admonition-padding-x, 0.9em);
257
+ }
258
+
259
+ .cm-md-admonition-start {
260
+ border-top: var(--md-admonition-border-width, 1px) solid var(--md-admonition-border-color, color-mix(in srgb, var(--md-alert-accent, var(--widget-border-accent)) 46%, var(--widget-border) 54%));
261
+ border-top-left-radius: var(--md-admonition-radius, 6px);
262
+ border-top-right-radius: var(--md-admonition-radius, 6px);
263
+ background: var(--md-admonition-title-background, color-mix(in srgb, var(--md-alert-accent, var(--widget-border-accent)) 14%, var(--editor-background, transparent) 86%));
264
+ padding-top: var(--md-admonition-padding-y, 0.35em);
265
+ padding-bottom: var(--md-admonition-padding-y, 0.35em);
266
+ border-bottom: 1px solid color-mix(in srgb, var(--md-admonition-border-color, var(--md-alert-accent, var(--widget-border-accent))) 55%, transparent);
267
+ }
268
+
269
+ .cm-md-admonition-end {
270
+ border-bottom: var(--md-admonition-border-width, 1px) solid var(--md-admonition-border-color, color-mix(in srgb, var(--md-alert-accent, var(--widget-border-accent)) 46%, var(--widget-border) 54%));
271
+ border-bottom-left-radius: var(--md-admonition-radius, 6px);
272
+ border-bottom-right-radius: var(--md-admonition-radius, 6px);
273
+ padding-bottom: calc(var(--md-admonition-padding-y, 0.35em) + 0.05em);
274
+ }
275
+
276
+ .cm-md-admonition-title-line {
277
+ color: var(--md-admonition-title-color, var(--md-alert-accent, var(--widget-text-accent)));
236
278
  }
237
279
 
238
280
  /* ==========================================================================
@@ -241,6 +283,19 @@ export const markdownStyles = `
241
283
 
242
284
  .cm-md-list-marker {
243
285
  color: var(--md-list-marker-color);
286
+ font-variant-numeric: tabular-nums;
287
+ }
288
+
289
+ .cm-md-list-number {
290
+ font-weight: var(--md-list-number-weight, 600);
291
+ }
292
+
293
+ .cm-md-list-bullet {
294
+ display: inline-block;
295
+ width: var(--md-list-bullet-width, 0.75em);
296
+ color: var(--md-list-marker-color);
297
+ font-weight: var(--md-list-bullet-weight, 700);
298
+ text-align: center;
244
299
  }
245
300
 
246
301
  /* ==========================================================================
@@ -322,6 +377,222 @@ export const markdownStyles = `
322
377
  padding: 0.5em 0;
323
378
  }
324
379
 
380
+ /* Linked-table wrapper (header chrome + table snapshot) */
381
+ .cm-linked-table-widget {
382
+ display: block;
383
+ margin: 0.35em 0;
384
+ padding: 0.45em 0.6em 0.55em;
385
+ border: 1px solid var(--widget-border, rgba(128, 128, 128, 0.2));
386
+ border-radius: var(--widget-border-radius, 8px);
387
+ background: color-mix(in srgb, var(--md-table-bg, var(--editor-background)) 92%, var(--widget-surface, transparent) 8%);
388
+ }
389
+
390
+ .cm-linked-table-widget .cm-table-widget {
391
+ padding: 0;
392
+ background: transparent;
393
+ }
394
+
395
+ .cm-linked-table-chrome {
396
+ display: flex;
397
+ align-items: center;
398
+ justify-content: space-between;
399
+ gap: 0.75em;
400
+ margin-bottom: 0.45em;
401
+ }
402
+
403
+ .cm-linked-table-chrome-left {
404
+ display: flex;
405
+ align-items: baseline;
406
+ gap: 0.55em;
407
+ min-width: 0;
408
+ flex-wrap: wrap;
409
+ }
410
+
411
+ .cm-linked-table-title {
412
+ font-size: 0.95em;
413
+ font-weight: 600;
414
+ color: var(--widget-text);
415
+ }
416
+
417
+ .cm-linked-table-badges {
418
+ display: inline-flex;
419
+ align-items: center;
420
+ gap: 0.35em;
421
+ flex-wrap: wrap;
422
+ }
423
+
424
+ .cm-linked-table-badge {
425
+ display: inline-flex;
426
+ align-items: center;
427
+ padding: 0.1em 0.45em;
428
+ border-radius: 999px;
429
+ background: var(--widget-surface, rgba(128, 128, 128, 0.12));
430
+ color: var(--widget-text-muted, inherit);
431
+ font-size: 0.75em;
432
+ line-height: 1.25;
433
+ }
434
+
435
+ .cm-linked-table-badge-linked {
436
+ color: var(--md-link-color, var(--widget-text));
437
+ }
438
+
439
+ .cm-linked-table-status-badge {
440
+ border: 1px solid transparent;
441
+ }
442
+
443
+ .cm-linked-table-status-pending,
444
+ .cm-linked-table-status-claimed,
445
+ .cm-linked-table-status-requested {
446
+ background: color-mix(in srgb, var(--widget-surface, rgba(128, 128, 128, 0.12)) 60%, var(--md-link-color, #64748b) 40%);
447
+ color: var(--widget-text);
448
+ }
449
+
450
+ .cm-linked-table-status-running,
451
+ .cm-linked-table-status-writing {
452
+ background: color-mix(in srgb, var(--widget-surface, rgba(128, 128, 128, 0.12)) 45%, var(--mrmd-accent, #2563eb) 55%);
453
+ color: white;
454
+ }
455
+
456
+ .cm-linked-table-status-stale {
457
+ background: color-mix(in srgb, var(--widget-surface, rgba(128, 128, 128, 0.12)) 35%, var(--mrmd-warning, #d97706) 65%);
458
+ color: white;
459
+ }
460
+
461
+ .cm-linked-table-status-error {
462
+ background: color-mix(in srgb, var(--widget-surface, rgba(128, 128, 128, 0.12)) 35%, var(--mrmd-error, #dc2626) 65%);
463
+ color: white;
464
+ }
465
+
466
+ .cm-linked-table-status-fresh {
467
+ border-color: var(--widget-border, rgba(128, 128, 128, 0.2));
468
+ }
469
+
470
+ .cm-linked-table-status-active {
471
+ position: relative;
472
+ }
473
+
474
+ .cm-linked-table-status-active::after {
475
+ content: '';
476
+ width: 0.45em;
477
+ height: 0.45em;
478
+ margin-left: 0.4em;
479
+ border-radius: 999px;
480
+ background: currentColor;
481
+ display: inline-block;
482
+ opacity: 0.75;
483
+ animation: cm-linked-table-pulse 1s ease-in-out infinite;
484
+ }
485
+
486
+ @keyframes cm-linked-table-pulse {
487
+ 0%, 100% { opacity: 0.35; transform: scale(0.85); }
488
+ 50% { opacity: 0.95; transform: scale(1); }
489
+ }
490
+
491
+ .cm-linked-table-widget[data-job-status="running"],
492
+ .cm-linked-table-widget[data-job-status="writing"],
493
+ .cm-linked-table-widget[data-job-status="requested"],
494
+ .cm-linked-table-widget[data-job-status="claimed"] {
495
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--mrmd-accent, #2563eb) 35%, transparent 65%);
496
+ }
497
+
498
+ .cm-linked-table-widget[data-job-status="stale"] {
499
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--mrmd-warning, #d97706) 35%, transparent 65%);
500
+ }
501
+
502
+ .cm-linked-table-widget[data-job-status="error"] {
503
+ box-shadow: 0 0 0 1px color-mix(in srgb, var(--mrmd-error, #dc2626) 35%, transparent 65%);
504
+ }
505
+
506
+ .cm-linked-table-widget[aria-busy="true"] .cm-linked-table-sortable {
507
+ opacity: 0.7;
508
+ }
509
+
510
+ .cm-linked-table-actions {
511
+ display: inline-flex;
512
+ align-items: center;
513
+ gap: 0.35em;
514
+ flex-wrap: wrap;
515
+ }
516
+
517
+ .cm-linked-table-action {
518
+ appearance: none;
519
+ border: 1px solid var(--widget-border, rgba(128, 128, 128, 0.2));
520
+ background: var(--widget-surface, transparent);
521
+ color: var(--widget-text);
522
+ border-radius: 6px;
523
+ padding: 0.18em 0.5em;
524
+ font: inherit;
525
+ font-size: 0.78em;
526
+ cursor: pointer;
527
+ }
528
+
529
+ .cm-linked-table-action:hover {
530
+ background: var(--widget-surface-hover, rgba(128, 128, 128, 0.08));
531
+ }
532
+
533
+ .cm-linked-table-caption {
534
+ font-size: 0.85em;
535
+ color: var(--widget-text-muted);
536
+ font-style: italic;
537
+ line-height: 1.35;
538
+ }
539
+
540
+ .cm-linked-table-caption-above {
541
+ margin: 0 0 0.35em;
542
+ }
543
+
544
+ .cm-linked-table-caption-below {
545
+ margin: 0.45em 0 0;
546
+ }
547
+
548
+ .cm-linked-table-sortable {
549
+ cursor: pointer;
550
+ user-select: none;
551
+ }
552
+
553
+ .cm-linked-table-sortable::after {
554
+ content: ' ↕';
555
+ opacity: 0.35;
556
+ font-size: 0.8em;
557
+ }
558
+
559
+ .cm-linked-table-sortable:hover::after {
560
+ opacity: 0.65;
561
+ }
562
+
563
+ .cm-linked-table-source-banner {
564
+ display: flex;
565
+ align-items: center;
566
+ justify-content: space-between;
567
+ gap: 0.75em;
568
+ margin: 0.25em 0 0.4em;
569
+ padding: 0.35em 0.5em;
570
+ border: 1px dashed var(--widget-border, rgba(128, 128, 128, 0.24));
571
+ border-radius: 8px;
572
+ background: color-mix(in srgb, var(--widget-surface, transparent) 30%, var(--editor-background, transparent) 70%);
573
+ }
574
+
575
+ .cm-linked-table-source-banner-text {
576
+ font-size: 0.82em;
577
+ color: var(--widget-text-muted, inherit);
578
+ }
579
+
580
+ .cm-linked-table-source-banner-action {
581
+ appearance: none;
582
+ border: 1px solid var(--widget-border, rgba(128, 128, 128, 0.24));
583
+ background: var(--widget-surface, transparent);
584
+ color: var(--widget-text, inherit);
585
+ border-radius: 6px;
586
+ padding: 0.16em 0.5em;
587
+ font: inherit;
588
+ font-size: 0.78em;
589
+ cursor: pointer;
590
+ }
591
+
592
+ .cm-linked-table-source-banner-action:hover {
593
+ background: var(--widget-surface-hover, rgba(128, 128, 128, 0.08));
594
+ }
595
+
325
596
  /* The table element */
326
597
  .cm-table {
327
598
  display: table;
@@ -854,11 +1125,16 @@ export const markdownStyles = `
854
1125
  .cm-alert-title {
855
1126
  display: inline-flex;
856
1127
  align-items: center;
857
- gap: 0.4em;
858
- font-weight: 600;
1128
+ gap: 0.45em;
1129
+ font-weight: 650;
859
1130
  margin-bottom: 0.25em;
860
1131
  }
861
1132
 
1133
+ .cm-md-admonition-title-line .cm-alert-title {
1134
+ margin-bottom: 0;
1135
+ color: var(--md-admonition-title-color, var(--md-alert-accent, var(--widget-text-accent)));
1136
+ }
1137
+
862
1138
  .cm-alert-title-note {
863
1139
  color: var(--md-alert-note-color);
864
1140
  }
@@ -881,7 +1157,18 @@ export const markdownStyles = `
881
1157
 
882
1158
  /* Alert icons */
883
1159
  .cm-alert-icon {
884
- font-size: 1.1em;
1160
+ width: 1.2em;
1161
+ height: 1.2em;
1162
+ border-radius: 999px;
1163
+ display: inline-flex;
1164
+ align-items: center;
1165
+ justify-content: center;
1166
+ font-size: 0.75em;
1167
+ font-weight: 700;
1168
+ line-height: 1;
1169
+ color: var(--md-admonition-title-color, currentColor);
1170
+ border: 1px solid color-mix(in srgb, currentColor 45%, transparent);
1171
+ background: color-mix(in srgb, currentColor 12%, transparent);
885
1172
  }
886
1173
 
887
1174
  /* ==========================================================================