@karimsa/mdxserve 0.2.0 → 0.4.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 (57) hide show
  1. package/README.md +60 -10
  2. package/client/CodeBlock.tsx +24 -0
  3. package/client/DocView.tsx +9 -2
  4. package/client/ListingView.tsx +14 -10
  5. package/client/MarkdownTable.tsx +190 -0
  6. package/client/MdSection.tsx +56 -21
  7. package/client/MdSectionEditor.tsx +149 -2
  8. package/client/Mermaid.tsx +33 -7
  9. package/client/Settings.css +17 -0
  10. package/client/Settings.tsx +132 -0
  11. package/client/Table.tsx +2 -14
  12. package/client/app.css +339 -1
  13. package/client/block-state/README.md +39 -0
  14. package/client/block-state/storage.ts +73 -0
  15. package/client/block-state/useBlockState.ts +120 -0
  16. package/client/builtins/DataTable.tsx +269 -0
  17. package/client/builtins/chart-data.ts +22 -10
  18. package/client/builtins/index.ts +10 -0
  19. package/client/data-table/ColumnMenu.tsx +168 -0
  20. package/client/data-table/ColumnOptions.tsx +141 -0
  21. package/client/data-table/TableCell.tsx +76 -0
  22. package/client/data-table/TableHeaderCell.tsx +94 -0
  23. package/client/data-table/model.ts +194 -0
  24. package/client/data-table/navigation.ts +34 -0
  25. package/client/data-table/table-state.ts +196 -0
  26. package/client/data-table/useColumnMenu.ts +84 -0
  27. package/client/data-table/useTableState.ts +36 -0
  28. package/client/design/base/prose.css +4 -0
  29. package/client/diagrams/Dialog.tsx +577 -0
  30. package/client/diagrams/EditDialog.tsx +67 -0
  31. package/client/diagrams/Preferences.tsx +213 -0
  32. package/client/diagrams/edit-block.ts +93 -0
  33. package/client/diagrams/edit-context.ts +4 -0
  34. package/client/diagrams/session-id.ts +8 -0
  35. package/client/diagrams/slash.ts +94 -0
  36. package/client/diagrams/source.ts +73 -0
  37. package/client/diagrams/style.css +599 -0
  38. package/client/entry.tsx +2 -0
  39. package/client/mdx-components-base.ts +2 -2
  40. package/client/router.ts +8 -1
  41. package/client/shell/AppShell.tsx +38 -15
  42. package/client/shell/Sidebar.tsx +20 -2
  43. package/client/shell/StandaloneShell.tsx +19 -6
  44. package/client/shell/TocRail.tsx +4 -3
  45. package/client/shell/TopBar.tsx +17 -5
  46. package/client/state.ts +14 -0
  47. package/client/ui/ConfirmDeleteDialog.tsx +48 -91
  48. package/client/ui/ExpandModal.tsx +63 -104
  49. package/client/ui/Modal.tsx +123 -0
  50. package/client/ui/ResizeHandle.tsx +1 -1
  51. package/client/ui/SearchDialog.tsx +81 -88
  52. package/client/ui/modal.css +42 -0
  53. package/dist/cli.js +2191 -778
  54. package/dist/diagram-worker.js +17 -0
  55. package/dist/registry.json +297 -0
  56. package/package.json +42 -2
  57. package/skills/mdxserve/SKILL.md +56 -1
@@ -0,0 +1,599 @@
1
+ .diagram-dialog {
2
+ font-family: var(--font-core);
3
+ }
4
+ .diagram-workspace[open] {
5
+ display: flex;
6
+ flex-direction: column;
7
+ width: min(1480px, 96vw);
8
+ height: 90dvh;
9
+ max-height: 960px;
10
+ overflow: hidden;
11
+ }
12
+ .diagram-dialog button,
13
+ .diagram-dialog select {
14
+ font: inherit;
15
+ font-size: 12px;
16
+ color: inherit;
17
+ cursor: pointer;
18
+ }
19
+ .diagram-dialog button {
20
+ display: inline-flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ gap: 7px;
24
+ border-radius: 5px;
25
+ padding: 7px 11px;
26
+ }
27
+ .diagram-dialog button:hover:not(:disabled) {
28
+ background: var(--surface-hover);
29
+ }
30
+ .diagram-dialog button:disabled {
31
+ opacity: 0.35;
32
+ cursor: default;
33
+ }
34
+ .diagram-dialog :focus-visible {
35
+ outline: 2px solid var(--border-accent);
36
+ outline-offset: -2px;
37
+ }
38
+ .diagram-navbar {
39
+ height: 57px;
40
+ min-height: 57px;
41
+ padding: 0 17px;
42
+ display: flex;
43
+ align-items: center;
44
+ justify-content: space-between;
45
+ border-bottom: 1px solid var(--border-default);
46
+ background: var(--surface-raised);
47
+ }
48
+ .diagram-title,
49
+ .diagram-actions {
50
+ display: flex;
51
+ align-items: center;
52
+ gap: 12px;
53
+ }
54
+ .diagram-title > svg {
55
+ color: var(--text-accent);
56
+ }
57
+ .diagram-title h2 {
58
+ font-size: 14px;
59
+ font-weight: 650;
60
+ margin: 0;
61
+ letter-spacing: -0.2px;
62
+ }
63
+ .diagram-command {
64
+ font: 11px var(--font-mono);
65
+ color: var(--text-subtle);
66
+ border-left: 1px solid var(--border-default);
67
+ padding-left: 12px;
68
+ }
69
+ .diagram-dialog .diagram-icon-button {
70
+ width: 30px;
71
+ height: 30px;
72
+ padding: 0;
73
+ color: var(--text-muted);
74
+ flex-shrink: 0;
75
+ }
76
+ .diagram-dialog .diagram-primary {
77
+ background: var(--surface-accent);
78
+ color: white;
79
+ padding: 8px 14px;
80
+ font-weight: 600;
81
+ }
82
+ .diagram-dialog .diagram-primary:hover:not(:disabled) {
83
+ background: var(--surface-accent);
84
+ filter: brightness(1.1);
85
+ }
86
+ .diagram-workbench {
87
+ display: grid;
88
+ grid-template-columns: minmax(0, 1fr) minmax(0, 1fr);
89
+ flex: 1;
90
+ min-height: 0;
91
+ }
92
+ .diagram-editor-pane,
93
+ .diagram-preview-pane {
94
+ display: flex;
95
+ flex-direction: column;
96
+ min-width: 0;
97
+ min-height: 0;
98
+ overflow: hidden;
99
+ }
100
+ .diagram-editor-pane {
101
+ background: var(--surface-card);
102
+ border-right: 1px solid var(--border-strong);
103
+ }
104
+ .diagram-pane-toolbar {
105
+ height: 43px;
106
+ min-height: 43px;
107
+ display: flex;
108
+ align-items: center;
109
+ justify-content: space-between;
110
+ padding: 0 13px;
111
+ border-bottom: 1px solid var(--border-default);
112
+ background: var(--surface-card);
113
+ }
114
+ .diagram-tabs {
115
+ display: flex;
116
+ align-self: stretch;
117
+ gap: 16px;
118
+ }
119
+ .diagram-dialog .diagram-tabs button {
120
+ border-radius: 0;
121
+ padding: 0 3px;
122
+ border-bottom: 2px solid transparent;
123
+ color: var(--text-subtle);
124
+ }
125
+ .diagram-dialog .diagram-tabs button[aria-selected="true"] {
126
+ color: var(--text-accent);
127
+ border-bottom-color: var(--text-accent);
128
+ }
129
+ .diagram-pane-toolbar .diagram-actions {
130
+ gap: 7px;
131
+ }
132
+ .diagram-dialog .diagram-run {
133
+ color: var(--text-accent);
134
+ background: var(--surface-accent-soft);
135
+ padding: 5px 9px;
136
+ }
137
+ .diagram-code-editor {
138
+ flex: 1;
139
+ min-height: 120px;
140
+ display: flex;
141
+ overflow: hidden;
142
+ padding-top: 19px;
143
+ }
144
+ .diagram-gutter {
145
+ width: 51px;
146
+ flex-shrink: 0;
147
+ overflow: hidden;
148
+ padding-right: 15px;
149
+ text-align: right;
150
+ font: 12px/25px var(--font-mono);
151
+ color: var(--text-subtle);
152
+ user-select: none;
153
+ opacity: 0.65;
154
+ }
155
+ .diagram-code-editor textarea {
156
+ width: 100%;
157
+ height: 100%;
158
+ min-width: 0;
159
+ border: 0;
160
+ border-radius: 0;
161
+ margin: 0;
162
+ padding: 0 20px 24px 0;
163
+ background: transparent;
164
+ color: var(--text-body);
165
+ font: 13px/25px var(--font-mono);
166
+ resize: none;
167
+ tab-size: 2;
168
+ outline: none;
169
+ }
170
+ .diagram-workspace .diagram-code-editor textarea:focus {
171
+ outline: none;
172
+ box-shadow: none;
173
+ }
174
+ .diagram-code-editor textarea::placeholder {
175
+ color: var(--text-subtle);
176
+ opacity: 0.7;
177
+ }
178
+ .diagram-code-editor:focus-within {
179
+ box-shadow: inset 2px 0 var(--border-accent);
180
+ }
181
+ .diagram-pane-label {
182
+ display: flex;
183
+ align-items: center;
184
+ gap: 8px;
185
+ font-size: 12px;
186
+ color: var(--text-muted);
187
+ }
188
+ .diagram-preview-state {
189
+ font-size: 11px;
190
+ color: var(--text-subtle);
191
+ }
192
+ .diagram-canvas {
193
+ flex: 1;
194
+ min-height: 0;
195
+ overflow: hidden;
196
+ position: relative;
197
+ background-color: var(--diagram-bg);
198
+ background-image: radial-gradient(var(--border-default) 0.7px, transparent 0.7px);
199
+ background-size: 20px 20px;
200
+ }
201
+ .diagram-canvas > p {
202
+ padding: 24px;
203
+ font-size: 13px;
204
+ }
205
+ .diagram-canvas .mermaid-viewport {
206
+ background: transparent;
207
+ }
208
+ .diagram-stale {
209
+ opacity: 0.5;
210
+ }
211
+ .diagram-empty {
212
+ height: 100%;
213
+ display: flex;
214
+ flex-direction: column;
215
+ align-items: center;
216
+ justify-content: center;
217
+ gap: 12px;
218
+ text-align: center;
219
+ color: var(--text-subtle);
220
+ padding: 24px;
221
+ }
222
+ .diagram-empty > svg {
223
+ opacity: 0.5;
224
+ margin-bottom: 7px;
225
+ }
226
+ .diagram-empty strong {
227
+ font-size: 14px;
228
+ font-weight: 500;
229
+ color: var(--text-muted);
230
+ }
231
+ .diagram-empty span {
232
+ font-size: 12px;
233
+ }
234
+ .diagram-pane-footer {
235
+ display: flex;
236
+ align-items: center;
237
+ justify-content: space-between;
238
+ gap: 8px;
239
+ min-height: 30px;
240
+ padding: 0 14px;
241
+ border-top: 1px solid var(--border-subtle);
242
+ background: var(--surface-card);
243
+ font-size: 10px;
244
+ color: var(--text-subtle);
245
+ }
246
+ .diagram-statusbar {
247
+ min-height: 31px;
248
+ display: flex;
249
+ align-items: center;
250
+ justify-content: space-between;
251
+ gap: 20px;
252
+ padding: 7px 17px;
253
+ border-top: 1px solid var(--border-default);
254
+ background: var(--surface-raised);
255
+ font-size: 11px;
256
+ color: var(--text-muted);
257
+ }
258
+ .diagram-statusbar > :last-child {
259
+ white-space: nowrap;
260
+ color: var(--text-subtle);
261
+ }
262
+ .diagram-attachment,
263
+ .diagram-review {
264
+ border-top: 1px solid var(--border-default);
265
+ background: var(--surface-card);
266
+ font-size: 11px;
267
+ flex-shrink: 0;
268
+ }
269
+ .diagram-attachment summary,
270
+ .diagram-review summary {
271
+ cursor: pointer;
272
+ padding: 10px 14px;
273
+ color: var(--text-muted);
274
+ }
275
+ .diagram-attachment summary svg {
276
+ display: inline;
277
+ margin: 0 7px 0 3px;
278
+ vertical-align: middle;
279
+ }
280
+ .diagram-attachment > div {
281
+ padding: 0 14px 12px;
282
+ display: flex;
283
+ align-items: flex-start;
284
+ gap: 12px;
285
+ }
286
+ .diagram-attachment img {
287
+ max-height: 105px;
288
+ max-width: calc(100% - 45px);
289
+ object-fit: contain;
290
+ border-radius: 3px;
291
+ }
292
+ .diagram-review > div {
293
+ max-height: 160px;
294
+ overflow: auto;
295
+ padding: 0 18px 12px;
296
+ font-size: 12px;
297
+ line-height: 1.65;
298
+ }
299
+ .diagram-review summary {
300
+ color: var(--status-warn-fg);
301
+ }
302
+ .diagram-review ul {
303
+ list-style: disc;
304
+ padding-left: 17px;
305
+ }
306
+ .diagram-sr-only {
307
+ position: absolute;
308
+ width: 1px;
309
+ height: 1px;
310
+ padding: 0;
311
+ overflow: hidden;
312
+ clip: rect(0, 0, 0, 0);
313
+ white-space: nowrap;
314
+ }
315
+ .diagram-settings {
316
+ width: min(780px, 94vw);
317
+ max-height: 90dvh;
318
+ overflow: auto;
319
+ }
320
+ .diagram-settings-body {
321
+ display: grid;
322
+ grid-template-columns: 160px minmax(0, 1fr);
323
+ min-height: 360px;
324
+ }
325
+ .diagram-settings-body aside {
326
+ display: flex;
327
+ flex-direction: column;
328
+ gap: 4px;
329
+ padding: 20px 12px;
330
+ border-right: 1px solid var(--border-default);
331
+ background: var(--surface-sunken);
332
+ }
333
+ .diagram-dialog .diagram-settings-category {
334
+ justify-content: flex-start;
335
+ width: 100%;
336
+ border: 0;
337
+ text-align: left;
338
+ cursor: pointer;
339
+ display: flex;
340
+ align-items: center;
341
+ gap: 9px;
342
+ padding: 9px 10px;
343
+ border-radius: 5px;
344
+ color: var(--text-muted);
345
+ background: transparent;
346
+ font-size: 12px;
347
+ }
348
+ .diagram-dialog .diagram-settings-category[aria-pressed="true"],
349
+ .diagram-dialog .diagram-settings-category[aria-pressed="true"]:hover:not(:disabled) {
350
+ color: var(--text-accent);
351
+ background: var(--surface-accent-soft);
352
+ }
353
+ .diagram-settings-category:focus-visible {
354
+ outline: 2px solid var(--text-accent);
355
+ outline-offset: 2px;
356
+ }
357
+ .diagram-settings-body section {
358
+ padding: 26px;
359
+ }
360
+ .diagram-settings-body h3 {
361
+ font-size: 16px;
362
+ font-weight: 600;
363
+ margin: 0 0 7px;
364
+ }
365
+ .diagram-settings-body p {
366
+ font-size: 12px;
367
+ line-height: 1.65;
368
+ color: var(--text-muted);
369
+ }
370
+ .diagram-setting-row {
371
+ display: flex;
372
+ align-items: center;
373
+ justify-content: space-between;
374
+ gap: 18px;
375
+ margin-top: 25px;
376
+ }
377
+ .diagram-setting-row strong {
378
+ display: block;
379
+ font-size: 13px;
380
+ font-weight: 550;
381
+ }
382
+ .diagram-setting-row small {
383
+ display: block;
384
+ font-size: 11px;
385
+ color: var(--text-subtle);
386
+ margin-top: 5px;
387
+ }
388
+ .diagram-setting-row select {
389
+ width: 150px;
390
+ padding: 8px 10px;
391
+ border: 1px solid var(--border-default);
392
+ border-radius: 5px;
393
+ background: var(--surface-sunken);
394
+ }
395
+ .diagram-settings-body .diagram-setting-note {
396
+ font-size: 11px;
397
+ color: var(--text-subtle);
398
+ margin-top: 10px;
399
+ }
400
+ .diagram-agent-status {
401
+ border-top: 1px solid var(--border-default);
402
+ margin-top: 24px;
403
+ padding-top: 17px;
404
+ display: flex;
405
+ align-items: center;
406
+ justify-content: space-between;
407
+ gap: 12px;
408
+ font-size: 11px;
409
+ color: var(--text-muted);
410
+ }
411
+ .diagram-agent-status button {
412
+ border: 1px solid var(--border-default);
413
+ white-space: nowrap;
414
+ }
415
+ .diagram-settings-body .diagram-settings-disclosure {
416
+ margin-top: 22px;
417
+ font-size: 11px;
418
+ color: var(--text-subtle);
419
+ }
420
+ .diagram-settings-footer {
421
+ display: flex;
422
+ align-items: center;
423
+ justify-content: space-between;
424
+ gap: 16px;
425
+ border-top: 1px solid var(--border-default);
426
+ padding: 14px 20px;
427
+ font-size: 11px;
428
+ color: var(--text-subtle);
429
+ }
430
+ .diagram-error {
431
+ color: var(--status-danger-fg);
432
+ }
433
+ @media (max-width: 700px) {
434
+ .diagram-workspace[open] {
435
+ width: 100vw;
436
+ height: 100dvh;
437
+ max-height: none;
438
+ max-width: none;
439
+ border: 0;
440
+ border-radius: 0;
441
+ }
442
+ .diagram-workbench {
443
+ grid-template-columns: 1fr;
444
+ grid-template-rows: minmax(0, 1fr) minmax(0, 1fr);
445
+ }
446
+ .diagram-editor-pane {
447
+ border-right: 0;
448
+ border-bottom: 1px solid var(--border-strong);
449
+ }
450
+ .diagram-command,
451
+ .diagram-pane-footer > :last-child {
452
+ display: none;
453
+ }
454
+ .diagram-title,
455
+ .diagram-actions {
456
+ gap: 8px;
457
+ }
458
+ .diagram-navbar {
459
+ padding: 0 10px;
460
+ }
461
+ .diagram-settings-body {
462
+ grid-template-columns: 1fr;
463
+ }
464
+ .diagram-settings-body aside {
465
+ display: flex;
466
+ flex-direction: row;
467
+ gap: 8px;
468
+ padding: 12px;
469
+ border-right: 0;
470
+ border-bottom: 1px solid var(--border-default);
471
+ }
472
+ .diagram-dialog .diagram-settings-category {
473
+ width: auto;
474
+ }
475
+ .diagram-settings-footer {
476
+ flex-wrap: wrap;
477
+ }
478
+ }
479
+ .diagram-slash-menu {
480
+ position: fixed;
481
+ z-index: 100;
482
+ background: var(--surface-raised);
483
+ border: 1px solid var(--border-default);
484
+ padding: 6px;
485
+ box-shadow: 0 6px 20px #0002;
486
+ border-radius: 8px;
487
+ width: 250px;
488
+ }
489
+ .diagram-slash-menu button {
490
+ padding: 12px;
491
+ text-align: left;
492
+ width: 100%;
493
+ background: var(--surface-accent-soft);
494
+ color: var(--text-accent);
495
+ border-radius: 5px;
496
+ }
497
+
498
+ .diagram-statusbar[data-error="true"] > :first-child {
499
+ color: var(--status-danger-fg);
500
+ }
501
+
502
+ .diagram-agent-select {
503
+ position: relative;
504
+ display: inline-flex;
505
+ flex-shrink: 0;
506
+ }
507
+ .diagram-dialog .diagram-agent-select select {
508
+ appearance: none;
509
+ background-image: none;
510
+ padding-right: 34px;
511
+ }
512
+ .diagram-agent-select > svg {
513
+ position: absolute;
514
+ right: 10px;
515
+ top: 50%;
516
+ transform: translateY(-50%);
517
+ pointer-events: none;
518
+ }
519
+ .diagram-setting-row input[type="text"] {
520
+ width: 180px;
521
+ min-width: 0;
522
+ padding: 8px 10px;
523
+ border: 1px solid var(--border-default);
524
+ border-radius: 6px;
525
+ background: var(--surface-sunken);
526
+ color: inherit;
527
+ font: inherit;
528
+ }
529
+
530
+ .diagram-dialog .diagram-model-select select {
531
+ width: 220px;
532
+ max-width: 100%;
533
+ }
534
+ .diagram-model-status {
535
+ display: flex;
536
+ align-items: center;
537
+ justify-content: space-between;
538
+ gap: 12px;
539
+ color: var(--text-subtle);
540
+ margin-top: 8px;
541
+ }
542
+ .diagram-model-status button {
543
+ white-space: nowrap;
544
+ font-size: 11px;
545
+ border: 1px solid var(--border-default);
546
+ }
547
+
548
+ .diagram-edit-block {
549
+ display: block;
550
+ margin-left: auto;
551
+ padding: 6px 10px;
552
+ border: 1px solid var(--border-default);
553
+ border-radius: 6px;
554
+ color: var(--text-accent);
555
+ background: var(--surface-raised);
556
+ font-size: 12px;
557
+ cursor: pointer;
558
+ }
559
+
560
+ /* Alternate names restart the nudge on repeated outside clicks. */
561
+ .diagram-workspace[data-shake="left"] {
562
+ animation: diagram-nudge-left 280ms ease-out;
563
+ }
564
+ .diagram-workspace[data-shake="right"] {
565
+ animation: diagram-nudge-right 280ms ease-out;
566
+ }
567
+ @keyframes diagram-nudge-left {
568
+ 0%,
569
+ 100% {
570
+ transform: translateX(0);
571
+ }
572
+ 25%,
573
+ 65% {
574
+ transform: translateX(-5px);
575
+ }
576
+ 45%,
577
+ 85% {
578
+ transform: translateX(5px);
579
+ }
580
+ }
581
+ @keyframes diagram-nudge-right {
582
+ 0%,
583
+ 100% {
584
+ transform: translateX(0);
585
+ }
586
+ 25%,
587
+ 65% {
588
+ transform: translateX(5px);
589
+ }
590
+ 45%,
591
+ 85% {
592
+ transform: translateX(-5px);
593
+ }
594
+ }
595
+ @media (prefers-reduced-motion: reduce) {
596
+ .diagram-workspace[data-shake] {
597
+ animation: none;
598
+ }
599
+ }
package/client/entry.tsx CHANGED
@@ -14,7 +14,9 @@ function parseInitialRoute(): Route {
14
14
  if (!el?.textContent) return fallback;
15
15
  const rootCount = Number.parseInt(el.dataset.rootCount ?? "", 10);
16
16
  if (Number.isFinite(rootCount)) shellInfo.rootCount = rootCount;
17
+ shellInfo.immutableSite = el.dataset.immutableSite === "1";
17
18
  shellInfo.sameMachine = el.dataset.sameMachine === "1";
19
+ shellInfo.permissions = el.dataset.permissions === "restricted" ? "restricted" : "full";
18
20
  try {
19
21
  return JSON.parse(el.textContent) as Route;
20
22
  } catch {
@@ -11,7 +11,7 @@ import type { ComponentType } from "react";
11
11
  import { TaskCheckbox } from "./TaskCheckbox";
12
12
  import { Figure, Pre } from "./CodeBlock";
13
13
  import { H2, H3, H4 } from "./Heading";
14
- import { Table } from "./Table";
14
+ import { MarkdownTable } from "./MarkdownTable";
15
15
  import { builtinComponents } from "./builtins/index";
16
16
 
17
17
  /**
@@ -28,5 +28,5 @@ export const mdxComponentsBase: Record<string, ComponentType<any>> = {
28
28
  h3: H3,
29
29
  h4: H4,
30
30
  input: TaskCheckbox,
31
- table: Table,
31
+ table: MarkdownTable,
32
32
  };
package/client/router.ts CHANGED
@@ -75,9 +75,16 @@ function ensureDocModule(path: string): Promise<void> {
75
75
  * entry.tsx before React mounts so multi-root navigation (home crumb, `..`
76
76
  * row) doesn't flash in or out while the tree query is still loading.
77
77
  */
78
- export const shellInfo: { rootCount: number | null; sameMachine: boolean } = {
78
+ export const shellInfo: {
79
+ rootCount: number | null;
80
+ immutableSite: boolean;
81
+ sameMachine: boolean;
82
+ permissions: "full" | "restricted";
83
+ } = {
79
84
  rootCount: null,
85
+ immutableSite: false,
80
86
  sameMachine: false,
87
+ permissions: "full",
81
88
  };
82
89
 
83
90
  function mapRoots(data: DocTreeOutput): RootTree[] {