living-ai-documentation 1.11.0 → 2.1.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 (45) hide show
  1. package/dist/src/frontend/boot.js +1 -0
  2. package/dist/src/frontend/config.js +3 -2
  3. package/dist/src/frontend/context.html +1 -1
  4. package/dist/src/frontend/documents.js +46 -0
  5. package/dist/src/frontend/i18n/en.json +35 -0
  6. package/dist/src/frontend/i18n/fr.json +35 -0
  7. package/dist/src/frontend/index.html +256 -44
  8. package/dist/src/frontend/sidebar-helpers.js +33 -0
  9. package/dist/src/frontend/sidebar.js +28 -0
  10. package/dist/src/frontend/{inline-snippet-edit.js → snippets/inline-snippet-edit.js} +112 -32
  11. package/dist/src/frontend/snippets/snippet-builders.js +138 -0
  12. package/dist/src/frontend/{snippet-detect.js → snippets/snippet-detect.js} +3 -3
  13. package/dist/src/frontend/snippets/snippet-list-markdown.js +92 -0
  14. package/dist/src/frontend/snippets/snippet-parsers.js +156 -0
  15. package/dist/src/frontend/snippets/snippet-table-attributes.js +126 -0
  16. package/dist/src/frontend/{snippet-table.js → snippets/snippet-table.js} +6 -0
  17. package/dist/src/frontend/{snippets.js → snippets/snippets.js} +300 -341
  18. package/dist/src/frontend/state.js +11 -0
  19. package/dist/src/frontend/workspace/README.md +65 -0
  20. package/dist/src/frontend/workspace/app.js +1499 -0
  21. package/dist/src/frontend/workspace/app.js.map +1 -0
  22. package/dist/src/frontend/workspace/app.ts +1964 -0
  23. package/dist/src/frontend/workspace/index.html +318 -0
  24. package/dist/src/frontend/workspace/persistence.js +98 -0
  25. package/dist/src/frontend/workspace/persistence.js.map +1 -0
  26. package/dist/src/frontend/workspace/persistence.ts +159 -0
  27. package/dist/src/frontend/workspace/styles.css +787 -0
  28. package/dist/src/frontend/workspace/tsconfig.json +12 -0
  29. package/dist/src/routes/documents.d.ts.map +1 -1
  30. package/dist/src/routes/documents.js +23 -0
  31. package/dist/src/routes/documents.js.map +1 -1
  32. package/dist/src/routes/workspace.d.ts +3 -0
  33. package/dist/src/routes/workspace.d.ts.map +1 -0
  34. package/dist/src/routes/workspace.js +525 -0
  35. package/dist/src/routes/workspace.js.map +1 -0
  36. package/dist/src/server.d.ts.map +1 -1
  37. package/dist/src/server.js +3 -0
  38. package/dist/src/server.js.map +1 -1
  39. package/package.json +4 -3
  40. /package/dist/src/frontend/{confirm-modal.js → modals/confirm-modal.js} +0 -0
  41. /package/dist/src/frontend/{diagram-link-modal.js → modals/diagram-link-modal.js} +0 -0
  42. /package/dist/src/frontend/{files-modal.js → modals/files-modal.js} +0 -0
  43. /package/dist/src/frontend/{new-doc-modal.js → modals/new-doc-modal.js} +0 -0
  44. /package/dist/src/frontend/{new-folder-modal.js → modals/new-folder-modal.js} +0 -0
  45. /package/dist/src/frontend/{snippet-tree.js → snippets/snippet-tree.js} +0 -0
@@ -19,6 +19,7 @@ document.addEventListener("DOMContentLoaded", async () => {
19
19
  await loadDocuments();
20
20
  applyHideCategoriesButtonState();
21
21
  applyHideAttachmentsButtonState();
22
+ applyHighlightStatusButtonState();
22
23
 
23
24
  // Deep-link via ?doc=id, otherwise open first General doc
24
25
  const params = new URLSearchParams(location.search);
@@ -6,8 +6,9 @@ async function loadConfig() {
6
6
  await window.initI18n(cfg.language || 'en');
7
7
  window.applyI18n();
8
8
  if (cfg.title) document.title = cfg.title;
9
- document.getElementById("app-title").textContent =
10
- cfg.title || "Living Documentation";
9
+ document.getElementById("app-title").textContent = "Living AI Documentation";
10
+ const subtitle = document.getElementById("app-subtitle");
11
+ if (subtitle) subtitle.textContent = cfg.title || "";
11
12
  if (cfg.filenamePattern) {
12
13
  document.getElementById("welcome-pattern").textContent =
13
14
  cfg.filenamePattern + ".md";
@@ -5,7 +5,7 @@
5
5
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
6
6
  <title>AI Context</title>
7
7
  <script src="/i18n.js"></script>
8
- <script src="/confirm-modal.js"></script>
8
+ <script src="/modals/confirm-modal.js"></script>
9
9
  <script src="https://cdn.tailwindcss.com?plugins=typography"></script>
10
10
  <script>
11
11
  tailwind.config = { darkMode: "class", theme: { extend: {} } };
@@ -8,10 +8,43 @@
8
8
  let _lastDocHtml = null;
9
9
  let _lastDocIdRendered = null;
10
10
 
11
+ function _applyTableStyles(contentEl) {
12
+ const attrs = ldCollectTableAttributesFromSource(
13
+ typeof currentDocContent === "string" ? currentDocContent : "",
14
+ );
15
+ const tables = contentEl.querySelectorAll("table");
16
+ tables.forEach((table, i) => {
17
+ const a = attrs[i];
18
+ if (!a) return;
19
+ if (a.style) {
20
+ table.classList.add(`table-style-${a.style}`);
21
+ table.dataset.tableStyle = a.style;
22
+ }
23
+ if (a.border) {
24
+ table.classList.add(`table-border-${a.border}`);
25
+ table.dataset.tableBorder = a.border;
26
+ }
27
+ if (a.color) {
28
+ table.classList.add(`table-color-${a.color}`);
29
+ table.dataset.tableColor = a.color;
30
+ }
31
+ });
32
+ }
33
+
34
+ function _fillEmptyTableCells(contentEl) {
35
+ contentEl.querySelectorAll("table th, table td").forEach((cell) => {
36
+ if (cell.textContent.trim() === "") {
37
+ cell.textContent = "\u00A0";
38
+ }
39
+ });
40
+ }
41
+
11
42
  function _wireDocContent(html) {
12
43
  const contentEl = document.getElementById("doc-content");
13
44
  if (!contentEl) return;
14
45
  contentEl.innerHTML = html;
46
+ _applyTableStyles(contentEl);
47
+ _fillEmptyTableCells(contentEl);
15
48
 
16
49
  contentEl.querySelectorAll("h1, h2, h3, h4, h5, h6").forEach((h) => {
17
50
  if (!h.id) {
@@ -187,6 +220,7 @@ async function loadDocuments() {
187
220
  await Promise.all([
188
221
  refreshAnnotationCounts(),
189
222
  refreshFileAttachmentCounts(),
223
+ refreshDocStatuses(),
190
224
  ]);
191
225
  renderSidebar(allDocs);
192
226
  } catch {
@@ -222,6 +256,18 @@ async function refreshFileAttachmentCounts() {
222
256
  }
223
257
  }
224
258
 
259
+ async function refreshDocStatuses() {
260
+ try {
261
+ const raw = await fetch("/api/documents/statuses").then((r) => r.json());
262
+ docStatuses = {};
263
+ for (const [docId, status] of Object.entries(raw || {})) {
264
+ docStatuses[docId] = status;
265
+ }
266
+ } catch {
267
+ docStatuses = {};
268
+ }
269
+ }
270
+
225
271
  async function openDocument(id, skipHistory = false, fromLink = false, anchor = null) {
226
272
  // Track navigation history for breadcrumb trail
227
273
  // fromLink===true : forward navigation via in-doc link → push current to stack
@@ -19,10 +19,12 @@
19
19
  "nav.toggle_sidebar": "Toggle sidebar",
20
20
  "nav.search_placeholder": "Search docs…",
21
21
  "nav.search_mobile_placeholder": "Search…",
22
+ "nav.workspace": "Agentic Workspace",
22
23
  "nav.toggle_dark": "Toggle dark mode",
23
24
  "nav.export": "Export",
24
25
  "nav.toggle_categories": "Show/hide category grouping",
25
26
  "nav.toggle_attachments": "Show/hide attachments",
27
+ "nav.toggle_status_highlight": "Highlight document statuses (To be validated / SuperSeeded)",
26
28
  "nav.export_html": "Export folders as HTML ZIP",
27
29
  "nav.export_all_pdf": "Export all documents as PDF",
28
30
  "nav.new_folder": "New folder",
@@ -65,6 +67,8 @@
65
67
  "sidebar.annotated_docs_badge": "document with annotations",
66
68
  "sidebar.file_attachment_badge": "attachment",
67
69
  "sidebar.file_attached_docs_badge": "document with attachments",
70
+ "sidebar.status_to_validate": "To be validated",
71
+ "sidebar.status_superseeded": "SuperSeeded",
68
72
 
69
73
  "doc.validate_mode": "Validate document — flip frontmatter status from \"To be validated\" to \"Accepted\"",
70
74
  "doc.validate_btn": "Validate",
@@ -281,6 +285,37 @@
281
285
  "snippet.inline_edit_btn_heading_2": "Edit heading level 2",
282
286
  "snippet.inline_edit_btn_heading_3": "Edit heading level 3",
283
287
  "snippet.inline_edit_btn_heading_4": "Edit heading level 4",
288
+ "snippet.inline_delete_btn_table": "Delete table",
289
+ "snippet.inline_delete_btn_code_block": "Delete code block",
290
+ "snippet.inline_delete_btn_blockquote": "Delete blockquote",
291
+ "snippet.inline_delete_btn_ordered_list": "Delete numbered list",
292
+ "snippet.inline_delete_btn_unordered_list": "Delete bullet list",
293
+ "snippet.inline_delete_btn_tree": "Delete tree",
294
+ "snippet.inline_delete_btn_colored_section": "Delete colored section",
295
+ "snippet.inline_delete_btn_colored_text": "Delete colored text",
296
+ "snippet.inline_delete_btn_collapsible": "Delete collapsible block",
297
+ "snippet.inline_delete_btn_link": "Delete link",
298
+ "snippet.inline_delete_btn_doc_link": "Delete document link",
299
+ "snippet.inline_delete_btn_anchor_link": "Delete anchor link",
300
+ "snippet.inline_delete_btn_anchor_doc_link": "Delete document + anchor link",
301
+ "snippet.inline_delete_btn_image": "Delete image",
302
+ "snippet.inline_delete_btn_separator": "Delete separator",
303
+ "snippet.inline_delete_btn_heading_1": "Delete heading level 1",
304
+ "snippet.inline_delete_btn_heading_2": "Delete heading level 2",
305
+ "snippet.inline_delete_btn_heading_3": "Delete heading level 3",
306
+ "snippet.inline_delete_btn_heading_4": "Delete heading level 4",
307
+ "snippet.table_style_label": "Table style",
308
+ "snippet.table_style_default": "Default",
309
+ "snippet.table_style_compact": "Compact",
310
+ "snippet.table_style_striped": "Striped",
311
+ "snippet.table_border_label": "Borders",
312
+ "snippet.table_color_label": "Color",
313
+ "snippet.table_color_default": "None",
314
+ "snippet.table_color_info": "Info (blue)",
315
+ "snippet.table_color_success": "Success (green)",
316
+ "snippet.table_color_warning": "Warning (orange)",
317
+ "snippet.table_color_danger": "Danger (red)",
318
+ "snippet.table_color_note": "Note (violet)",
284
319
  "snippet.picker_search_placeholder": "Search a snippet…",
285
320
  "snippet.picker_back": "Back",
286
321
  "snippet.picker_no_results": "No matching snippet.",
@@ -19,10 +19,12 @@
19
19
  "nav.toggle_sidebar": "Afficher/masquer le panneau",
20
20
  "nav.search_placeholder": "Rechercher dans les docs…",
21
21
  "nav.search_mobile_placeholder": "Rechercher…",
22
+ "nav.workspace": "Workspace Agentique",
22
23
  "nav.toggle_dark": "Basculer le mode sombre",
23
24
  "nav.export": "Exporter",
24
25
  "nav.toggle_categories": "Afficher/masquer le regroupement par catégorie",
25
26
  "nav.toggle_attachments": "Afficher/masquer les pièces jointes",
27
+ "nav.toggle_status_highlight": "Mettre en évidence les statuts (À valider / Obsolète)",
26
28
  "nav.export_html": "Exporter les dossiers en HTML (ZIP)",
27
29
  "nav.export_all_pdf": "Exporter tous les documents en PDF",
28
30
  "nav.new_folder": "Nouveau dossier",
@@ -65,6 +67,8 @@
65
67
  "sidebar.annotated_docs_badge": "document contenant des annotations",
66
68
  "sidebar.file_attachment_badge": "pièce jointe",
67
69
  "sidebar.file_attached_docs_badge": "document contenant des pièces jointes",
70
+ "sidebar.status_to_validate": "À valider",
71
+ "sidebar.status_superseeded": "Obsolète",
68
72
 
69
73
  "doc.validate_mode": "Valider le document — passer le statut frontmatter de « To be validated » à « Accepted »",
70
74
  "doc.validate_btn": "Valider",
@@ -281,6 +285,37 @@
281
285
  "snippet.inline_edit_btn_heading_2": "Éditer le titre niveau 2",
282
286
  "snippet.inline_edit_btn_heading_3": "Éditer le titre niveau 3",
283
287
  "snippet.inline_edit_btn_heading_4": "Éditer le titre niveau 4",
288
+ "snippet.inline_delete_btn_table": "Supprimer le tableau",
289
+ "snippet.inline_delete_btn_code_block": "Supprimer le bloc de code",
290
+ "snippet.inline_delete_btn_blockquote": "Supprimer la citation",
291
+ "snippet.inline_delete_btn_ordered_list": "Supprimer la liste numérotée",
292
+ "snippet.inline_delete_btn_unordered_list": "Supprimer la liste à puces",
293
+ "snippet.inline_delete_btn_tree": "Supprimer l'arborescence",
294
+ "snippet.inline_delete_btn_colored_section": "Supprimer la section colorée",
295
+ "snippet.inline_delete_btn_colored_text": "Supprimer le texte coloré",
296
+ "snippet.inline_delete_btn_collapsible": "Supprimer le bloc repliable",
297
+ "snippet.inline_delete_btn_link": "Supprimer le lien",
298
+ "snippet.inline_delete_btn_doc_link": "Supprimer le lien vers un document",
299
+ "snippet.inline_delete_btn_anchor_link": "Supprimer le lien d'ancre",
300
+ "snippet.inline_delete_btn_anchor_doc_link": "Supprimer le lien document + ancre",
301
+ "snippet.inline_delete_btn_image": "Supprimer l'image",
302
+ "snippet.inline_delete_btn_separator": "Supprimer le séparateur",
303
+ "snippet.inline_delete_btn_heading_1": "Supprimer le titre niveau 1",
304
+ "snippet.inline_delete_btn_heading_2": "Supprimer le titre niveau 2",
305
+ "snippet.inline_delete_btn_heading_3": "Supprimer le titre niveau 3",
306
+ "snippet.inline_delete_btn_heading_4": "Supprimer le titre niveau 4",
307
+ "snippet.table_style_label": "Style du tableau",
308
+ "snippet.table_style_default": "Par défaut",
309
+ "snippet.table_style_compact": "Compact",
310
+ "snippet.table_style_striped": "Rayé",
311
+ "snippet.table_border_label": "Bordures",
312
+ "snippet.table_color_label": "Couleur",
313
+ "snippet.table_color_default": "Aucune",
314
+ "snippet.table_color_info": "Info (bleu)",
315
+ "snippet.table_color_success": "Succès (vert)",
316
+ "snippet.table_color_warning": "Avertissement (orange)",
317
+ "snippet.table_color_danger": "Danger (rouge)",
318
+ "snippet.table_color_note": "Note (violet)",
284
319
  "snippet.picker_search_placeholder": "Rechercher un snippet…",
285
320
  "snippet.picker_back": "Retour",
286
321
  "snippet.picker_no_results": "Aucun snippet ne correspond.",
@@ -34,9 +34,13 @@
34
34
  <script defer src="/utils.js"></script>
35
35
  <script defer src="/state.js"></script>
36
36
  <script defer src="/sidebar-helpers.js"></script>
37
- <script defer src="/snippet-detect.js"></script>
38
- <script defer src="/snippet-table.js"></script>
39
- <script defer src="/snippet-tree.js"></script>
37
+ <script defer src="/snippets/snippet-table-attributes.js"></script>
38
+ <script defer src="/snippets/snippet-list-markdown.js"></script>
39
+ <script defer src="/snippets/snippet-builders.js"></script>
40
+ <script defer src="/snippets/snippet-parsers.js"></script>
41
+ <script defer src="/snippets/snippet-detect.js"></script>
42
+ <script defer src="/snippets/snippet-table.js"></script>
43
+ <script defer src="/snippets/snippet-tree.js"></script>
40
44
  <script defer src="/dark-mode.js"></script>
41
45
  <script defer src="/config.js"></script>
42
46
  <script defer src="/sidebar.js"></script>
@@ -47,18 +51,18 @@
47
51
  <script defer src="/file-attach.js"></script>
48
52
  <script defer src="/documents.js"></script>
49
53
  <script defer src="/misc.js"></script>
50
- <script defer src="/snippets.js"></script>
51
- <script defer src="/inline-snippet-edit.js"></script>
54
+ <script defer src="/snippets/snippets.js"></script>
55
+ <script defer src="/snippets/inline-snippet-edit.js"></script>
52
56
  <script defer src="/annotations.js"></script>
53
57
  <script defer src="/metadata.js"></script>
54
58
  <script defer src="/accuracy-gauge.js"></script>
55
59
  <script defer src="/validate.js"></script>
56
60
  <script defer src="/export.js"></script>
57
- <script defer src="/diagram-link-modal.js"></script>
58
- <script defer src="/new-folder-modal.js"></script>
59
- <script defer src="/new-doc-modal.js"></script>
60
- <script defer src="/confirm-modal.js"></script>
61
- <script defer src="/files-modal.js"></script>
61
+ <script defer src="/modals/diagram-link-modal.js"></script>
62
+ <script defer src="/modals/new-folder-modal.js"></script>
63
+ <script defer src="/modals/new-doc-modal.js"></script>
64
+ <script defer src="/modals/confirm-modal.js"></script>
65
+ <script defer src="/modals/files-modal.js"></script>
62
66
  <script defer src="/boot.js"></script>
63
67
 
64
68
  <script>
@@ -128,6 +132,149 @@
128
132
  border-color: rgba(34, 197, 94, 0.4);
129
133
  }
130
134
 
135
+ /* Table presets — triggered by table-style/table-border/table-color comments. */
136
+
137
+ /* Color palette via CSS variables. Default (no color class) uses neutral fallbacks. */
138
+ table.table-color-info {
139
+ --tbl-accent: rgb(59 130 246);
140
+ --tbl-accent-soft: rgb(219 234 254);
141
+ --tbl-accent-stripe: rgb(239 246 255);
142
+ --tbl-accent-text: rgb(30 58 138);
143
+ }
144
+ table.table-color-success {
145
+ --tbl-accent: rgb(34 197 94);
146
+ --tbl-accent-soft: rgb(220 252 231);
147
+ --tbl-accent-stripe: rgb(240 253 244);
148
+ --tbl-accent-text: rgb(20 83 45);
149
+ }
150
+ table.table-color-warning {
151
+ --tbl-accent: rgb(245 158 11);
152
+ --tbl-accent-soft: rgb(254 243 199);
153
+ --tbl-accent-stripe: rgb(255 251 235);
154
+ --tbl-accent-text: rgb(120 53 15);
155
+ }
156
+ table.table-color-danger {
157
+ --tbl-accent: rgb(239 68 68);
158
+ --tbl-accent-soft: rgb(254 226 226);
159
+ --tbl-accent-stripe: rgb(254 242 242);
160
+ --tbl-accent-text: rgb(127 29 29);
161
+ }
162
+ table.table-color-note {
163
+ --tbl-accent: rgb(139 92 246);
164
+ --tbl-accent-soft: rgb(233 213 255);
165
+ --tbl-accent-stripe: rgb(245 243 255);
166
+ --tbl-accent-text: rgb(76 29 149);
167
+ }
168
+ .dark table.table-color-info {
169
+ --tbl-accent: rgb(96 165 250);
170
+ --tbl-accent-soft: rgb(30 58 138 / 0.55);
171
+ --tbl-accent-stripe: rgb(30 58 138 / 0.35);
172
+ --tbl-accent-text: rgb(191 219 254);
173
+ }
174
+ .dark table.table-color-success {
175
+ --tbl-accent: rgb(74 222 128);
176
+ --tbl-accent-soft: rgb(20 83 45 / 0.55);
177
+ --tbl-accent-stripe: rgb(20 83 45 / 0.35);
178
+ --tbl-accent-text: rgb(187 247 208);
179
+ }
180
+ .dark table.table-color-warning {
181
+ --tbl-accent: rgb(251 191 36);
182
+ --tbl-accent-soft: rgb(120 53 15 / 0.55);
183
+ --tbl-accent-stripe: rgb(120 53 15 / 0.35);
184
+ --tbl-accent-text: rgb(254 215 170);
185
+ }
186
+ .dark table.table-color-danger {
187
+ --tbl-accent: rgb(248 113 113);
188
+ --tbl-accent-soft: rgb(127 29 29 / 0.55);
189
+ --tbl-accent-stripe: rgb(127 29 29 / 0.35);
190
+ --tbl-accent-text: rgb(254 202 202);
191
+ }
192
+ .dark table.table-color-note {
193
+ --tbl-accent: rgb(167 139 250);
194
+ --tbl-accent-soft: rgb(76 29 149 / 0.55);
195
+ --tbl-accent-stripe: rgb(76 29 149 / 0.35);
196
+ --tbl-accent-text: rgb(221 214 254);
197
+ }
198
+ /* When a color is applied, tint the header with the accent palette. */
199
+ .prose table[class*="table-color-"] thead th {
200
+ background-color: var(--tbl-accent-soft);
201
+ color: var(--tbl-accent-text);
202
+ }
203
+
204
+ /* Default table type: generous padding with horizontal separators only. */
205
+ .prose table {
206
+ border-collapse: collapse;
207
+ border: none;
208
+ }
209
+ .prose table th,
210
+ .prose table td {
211
+ padding: 0.6rem 1rem;
212
+ border: none;
213
+ border-bottom: 1px solid rgb(229 231 235);
214
+ }
215
+ .prose table thead th {
216
+ border-bottom-color: rgb(209 213 219);
217
+ }
218
+ .dark .prose table th,
219
+ .dark .prose table td {
220
+ border-bottom-color: rgb(55 65 81);
221
+ }
222
+ .prose table[class*="table-color-"] th,
223
+ .prose table[class*="table-color-"] td {
224
+ border-bottom-color: var(--tbl-accent-soft);
225
+ }
226
+ .prose table[class*="table-color-"] thead th {
227
+ border-bottom-color: var(--tbl-accent);
228
+ }
229
+ .prose table thead,
230
+ .prose table tbody tr {
231
+ border: none;
232
+ }
233
+
234
+ /* Compact: small font + reduced padding (clearly denser than other variants). */
235
+ .prose table.table-style-compact {
236
+ font-size: 0.85em;
237
+ line-height: 1.35;
238
+ }
239
+ .prose table.table-style-compact th,
240
+ .prose table.table-style-compact td {
241
+ padding: 0.2rem 0.5rem;
242
+ }
243
+
244
+ /* Striped: zebra rows using the accent stripe (neutral fallback if no color). */
245
+ .prose table.table-style-striped {
246
+ border-collapse: collapse;
247
+ }
248
+ .prose table.table-style-striped tbody tr:nth-child(odd) {
249
+ background-color: var(--tbl-accent-stripe, rgb(243 244 246));
250
+ }
251
+ .dark .prose table.table-style-striped tbody tr:nth-child(odd) {
252
+ background-color: var(--tbl-accent-stripe, rgb(55 65 81));
253
+ }
254
+
255
+ /* Border checkbox: visible borders tinted with the accent (neutral fallback otherwise). */
256
+ .prose table.table-border-bordered {
257
+ border-collapse: collapse;
258
+ }
259
+ .prose table.table-border-bordered,
260
+ .prose table.table-border-bordered th,
261
+ .prose table.table-border-bordered td {
262
+ border: 1px solid var(--tbl-accent, rgb(209 213 219));
263
+ }
264
+ .dark .prose table.table-border-bordered,
265
+ .dark .prose table.table-border-bordered th,
266
+ .dark .prose table.table-border-bordered td {
267
+ border-color: var(--tbl-accent, rgb(75 85 99));
268
+ }
269
+
270
+ /* Explicit/legacy borderless: keep only horizontal separators. */
271
+ .prose table.table-border-borderless th,
272
+ .prose table.table-border-borderless td {
273
+ border-left: none !important;
274
+ border-right: none !important;
275
+ border-top: none !important;
276
+ }
277
+
131
278
  /* Collapsible code blocks (set via --ld-code-max-h from .living-doc.json) */
132
279
  pre.ld-collapsible {
133
280
  max-height: var(--ld-code-max-h, 400px);
@@ -384,52 +531,37 @@
384
531
  <!-- ── Header ── -->
385
532
  <header
386
533
  id="header"
387
- class="no-print flex items-center justify-between px-4 h-14 border-b border-gray-200 dark:border-gray-800 bg-white dark:bg-gray-900 shrink-0 z-10 shadow-sm"
534
+ class="no-print flex items-center justify-between px-6 h-[72px] border-b border-gray-200 dark:border-gray-800 bg-white/90 dark:bg-gray-900/90 backdrop-blur shrink-0 z-10 shadow-sm"
388
535
  >
389
536
  <div class="flex items-center gap-3">
390
537
  <span
391
538
  onclick="toggleSidebar()"
392
539
  data-i18n-title="nav.toggle_sidebar"
393
540
  title="Toggle sidebar"
394
- class="text-blue-600 dark:text-blue-400 text-xl select-none cursor-pointer hover:opacity-70 transition-opacity"
395
- >&#128218;</span
396
- >
397
- <span id="app-title" class="font-semibold text-base tracking-tight"
398
- >Living Documentation</span
541
+ class="select-none cursor-pointer hover:opacity-70 transition-opacity flex items-center justify-center w-[38px] h-[38px] rounded-[10px] bg-gray-900 dark:bg-gray-800 border border-gray-600 text-white text-xs font-black"
542
+ >LD</span
399
543
  >
544
+ <div>
545
+ <div id="app-title" class="font-[760] text-[15px] tracking-tight leading-tight">Living AI Documentation</div>
546
+ <div id="app-subtitle" class="text-[12px] text-gray-400 mt-[2px]"></div>
547
+ </div>
400
548
  </div>
401
549
 
402
550
  <div class="flex items-center gap-2">
403
- <!-- Search (desktop — mirrors sidebar search) -->
404
- <div class="relative hidden sm:block">
405
- <input
406
- id="header-search"
407
- type="search"
408
- data-i18n-placeholder="nav.search_placeholder"
409
- placeholder="Search docs…"
410
- class="w-56 pl-8 pr-3 py-1.5 text-sm rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
411
- />
412
- <span
413
- class="absolute left-2.5 top-2 text-gray-400 text-sm pointer-events-none"
414
- >&#128269;</span
415
- >
416
- </div>
417
-
418
- <!-- Dark mode toggle -->
419
- <button
420
- id="dark-toggle"
421
- data-i18n-title="nav.toggle_dark"
422
- title="Toggle dark mode"
423
- class="p-2 rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
551
+ <!-- Workspace -->
552
+ <a
553
+ href="/workspace"
554
+ data-i18n="nav.workspace"
555
+ class="h-[34px] px-3 rounded-[9px] border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 text-[13px] font-bold text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors inline-flex items-center no-underline"
424
556
  >
425
- <span id="dark-icon" class="text-lg leading-none">&#9790;</span>
426
- </button>
557
+ Workspace
558
+ </a>
427
559
 
428
560
  <!-- Word Cloud -->
429
561
  <button
430
562
  onclick="openWordCloud()"
431
563
  data-i18n="nav.word_cloud"
432
- class="text-sm px-3 py-1.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors font-medium"
564
+ class="h-[34px] px-3 rounded-[9px] border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 text-[13px] font-bold text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors inline-flex items-center"
433
565
  >
434
566
  &#9729; Word Cloud
435
567
  </button>
@@ -438,7 +570,7 @@
438
570
  <a
439
571
  href="/diagram"
440
572
  data-i18n="nav.diagram"
441
- class="text-sm px-3 py-1.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors font-medium"
573
+ class="h-[34px] px-3 rounded-[9px] border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 text-[13px] font-bold text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors inline-flex items-center no-underline"
442
574
  >
443
575
  &#9671; Diagram
444
576
  </a>
@@ -447,7 +579,7 @@
447
579
  <a
448
580
  href="/context"
449
581
  data-i18n="nav.ai_context"
450
- class="text-sm px-3 py-1.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors font-medium"
582
+ class="h-[34px] px-3 rounded-[9px] border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 text-[13px] font-bold text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors inline-flex items-center no-underline"
451
583
  >
452
584
  AI Context
453
585
  </a>
@@ -456,7 +588,7 @@
456
588
  <button
457
589
  onclick="openFilesModal()"
458
590
  data-i18n="nav.files"
459
- class="text-sm px-3 py-1.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors font-medium"
591
+ class="h-[34px] px-3 rounded-[9px] border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 text-[13px] font-bold text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors inline-flex items-center"
460
592
  >
461
593
  &#128193; Files
462
594
  </button>
@@ -465,10 +597,35 @@
465
597
  <a
466
598
  href="/admin"
467
599
  data-i18n="nav.admin"
468
- class="text-sm px-3 py-1.5 rounded-lg text-gray-600 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors font-medium"
600
+ class="h-[34px] px-3 rounded-[9px] border border-gray-200 dark:border-gray-700 bg-white dark:bg-gray-900 text-[13px] font-bold text-gray-700 dark:text-gray-300 hover:bg-gray-50 dark:hover:bg-gray-800 transition-colors inline-flex items-center no-underline"
469
601
  >
470
602
  &#9881; Admin
471
603
  </a>
604
+
605
+ <!-- Dark mode toggle -->
606
+ <button
607
+ id="dark-toggle"
608
+ data-i18n-title="nav.toggle_dark"
609
+ title="Toggle dark mode"
610
+ class="p-2 rounded-lg text-gray-500 dark:text-gray-400 hover:bg-gray-100 dark:hover:bg-gray-800 transition-colors"
611
+ >
612
+ <span id="dark-icon" class="text-lg leading-none">&#9790;</span>
613
+ </button>
614
+
615
+ <!-- Search (desktop — mirrors sidebar search) -->
616
+ <div class="relative hidden sm:block">
617
+ <input
618
+ id="header-search"
619
+ type="search"
620
+ data-i18n-placeholder="nav.search_placeholder"
621
+ placeholder="Search docs…"
622
+ class="w-56 pl-8 pr-3 py-1.5 text-sm rounded-lg border border-gray-200 dark:border-gray-700 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 placeholder:text-gray-400 focus:outline-none focus:ring-2 focus:ring-blue-500"
623
+ />
624
+ <span
625
+ class="absolute left-2.5 top-2 text-gray-400 text-sm pointer-events-none"
626
+ >&#128269;</span
627
+ >
628
+ </div>
472
629
  </div>
473
630
  </header>
474
631
 
@@ -502,6 +659,15 @@
502
659
  class="text-xs text-gray-400 dark:text-gray-500"
503
660
  ></p>
504
661
  <div class="flex items-center gap-2">
662
+ <button
663
+ id="toggle-status-highlight-btn"
664
+ onclick="cycleHighlightStatus()"
665
+ data-i18n-title="nav.toggle_status_highlight"
666
+ title="Highlight document statuses"
667
+ class="text-gray-400 hover:opacity-80 dark:text-gray-500 transition-colors leading-none"
668
+ >
669
+ <i class="fa-solid fa-certificate"></i>
670
+ </button>
505
671
  <button
506
672
  id="toggle-attachments-btn"
507
673
  onclick="toggleHideAttachments()"
@@ -1837,6 +2003,52 @@
1837
2003
  <!-- Panel: table -->
1838
2004
  <div id="snip-panel-table" class="hidden space-y-3">
1839
2005
  <div class="flex items-center gap-5">
2006
+ <div class="flex items-center gap-2">
2007
+ <label
2008
+ for="snip-table-style"
2009
+ data-i18n="snippet.table_style_label"
2010
+ class="text-xs text-gray-500 dark:text-gray-400"
2011
+ >Table style</label
2012
+ >
2013
+ <select
2014
+ id="snip-table-style"
2015
+ onchange="snippetUpdatePreview()"
2016
+ class="text-xs rounded border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 px-2 py-1"
2017
+ >
2018
+ <option data-i18n="snippet.table_style_default" value="">Default</option>
2019
+ <option data-i18n="snippet.table_style_compact" value="compact">Compact</option>
2020
+ <option data-i18n="snippet.table_style_striped" value="striped">Striped</option>
2021
+ </select>
2022
+ </div>
2023
+ <label class="flex items-center gap-2 text-xs text-gray-500 dark:text-gray-400">
2024
+ <input
2025
+ id="snip-table-bordered"
2026
+ type="checkbox"
2027
+ onchange="snippetUpdatePreview()"
2028
+ class="rounded border-gray-300 dark:border-gray-600 text-blue-600 focus:ring-blue-500"
2029
+ />
2030
+ <span data-i18n="snippet.table_border_label">Borders</span>
2031
+ </label>
2032
+ <div class="flex items-center gap-2">
2033
+ <label
2034
+ for="snip-table-color"
2035
+ data-i18n="snippet.table_color_label"
2036
+ class="text-xs text-gray-500 dark:text-gray-400"
2037
+ >Color</label
2038
+ >
2039
+ <select
2040
+ id="snip-table-color"
2041
+ onchange="snippetUpdatePreview()"
2042
+ class="text-xs rounded border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 px-2 py-1"
2043
+ >
2044
+ <option data-i18n="snippet.table_color_default" value="">None</option>
2045
+ <option data-i18n="snippet.table_color_info" value="info">Info (blue)</option>
2046
+ <option data-i18n="snippet.table_color_success" value="success">Success (green)</option>
2047
+ <option data-i18n="snippet.table_color_warning" value="warning">Warning (orange)</option>
2048
+ <option data-i18n="snippet.table_color_danger" value="danger">Danger (red)</option>
2049
+ <option data-i18n="snippet.table_color_note" value="note">Note (violet)</option>
2050
+ </select>
2051
+ </div>
1840
2052
  <div class="flex items-center gap-2">
1841
2053
  <span data-i18n="snippet.table_rows_label" class="text-xs text-gray-500 dark:text-gray-400"
1842
2054
  >Rows</span
@@ -82,6 +82,39 @@ function fileAttachmentBadge(count) {
82
82
  border border-sky-500 shadow-sm">${count}</span>`;
83
83
  }
84
84
 
85
+ // Lifecycle pill driven by the tri-state status-highlight toggle. A document
86
+ // carries a single frontmatter `status`, so it shows at most one pill: a green
87
+ // "V" for "To be validated" (states 1 and 2) or an orange "S" for "SuperSeeded"
88
+ // (state 2 only). Status matching is case-insensitive.
89
+ function statusPill(doc) {
90
+ if (typeof highlightStatusState === "undefined" || !highlightStatusState)
91
+ return "";
92
+ const status = String(docStatuses[doc.id] || "")
93
+ .trim()
94
+ .toLowerCase();
95
+ if (status === "to be validated") {
96
+ const label = window.t
97
+ ? window.t("sidebar.status_to_validate")
98
+ : "To be validated";
99
+ return `<span title="${esc(label)}"
100
+ class="inline-flex items-center justify-center w-5 h-5
101
+ rounded-full bg-green-500 dark:bg-green-500
102
+ text-[10px] font-bold text-white
103
+ border border-green-600 shadow-sm">V</span>`;
104
+ }
105
+ if (highlightStatusState === 2 && status === "superseeded") {
106
+ const label = window.t
107
+ ? window.t("sidebar.status_superseeded")
108
+ : "SuperSeeded";
109
+ return `<span title="${esc(label)}"
110
+ class="inline-flex items-center justify-center w-5 h-5
111
+ rounded-full bg-orange-500 dark:bg-orange-500
112
+ text-[10px] font-bold text-white
113
+ border border-orange-600 shadow-sm">S</span>`;
114
+ }
115
+ return "";
116
+ }
117
+
85
118
  function fileAttachedDocsBadge(count) {
86
119
  if (!count) return "";
87
120
  if (typeof hideAttachments !== "undefined" && hideAttachments) return "";