living-ai-documentation 1.8.0 → 1.9.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/dist/src/frontend/i18n/en.json +12 -0
- package/dist/src/frontend/i18n/fr.json +12 -0
- package/dist/src/frontend/index.html +40 -0
- package/dist/src/frontend/inline-snippet-edit.js +27 -1
- package/dist/src/frontend/snippet-detect.js +2 -0
- package/dist/src/frontend/snippets.js +57 -6
- package/package.json +1 -1
|
@@ -269,6 +269,18 @@
|
|
|
269
269
|
"snippet.collapsible_summary_label": "Summary title",
|
|
270
270
|
"snippet.collapsible_details_placeholder": "Details",
|
|
271
271
|
"snippet.collapsible_summary_value": "Details",
|
|
272
|
+
"snippet.collapsible_body_label": "Body Markdown",
|
|
273
|
+
"snippet.collapsible_body_placeholder": "## Title\n\nText",
|
|
274
|
+
"snippet.heading_1": "🇭1 Heading level 1",
|
|
275
|
+
"snippet.heading_2": "🇭2 Heading level 2",
|
|
276
|
+
"snippet.heading_3": "🇭3 Heading level 3",
|
|
277
|
+
"snippet.heading_4": "🇭4 Heading level 4",
|
|
278
|
+
"snippet.heading_text_label": "Heading text",
|
|
279
|
+
"snippet.heading_text_placeholder": "My heading",
|
|
280
|
+
"snippet.inline_edit_btn_heading_1": "Edit heading level 1",
|
|
281
|
+
"snippet.inline_edit_btn_heading_2": "Edit heading level 2",
|
|
282
|
+
"snippet.inline_edit_btn_heading_3": "Edit heading level 3",
|
|
283
|
+
"snippet.inline_edit_btn_heading_4": "Edit heading level 4",
|
|
272
284
|
"snippet.link_text_label": "Link text",
|
|
273
285
|
"snippet.link_text_placeholder": "My link",
|
|
274
286
|
"snippet.link_url_label": "URL",
|
|
@@ -269,6 +269,18 @@
|
|
|
269
269
|
"snippet.collapsible_summary_label": "Titre du résumé",
|
|
270
270
|
"snippet.collapsible_details_placeholder": "Détails",
|
|
271
271
|
"snippet.collapsible_summary_value": "Détails",
|
|
272
|
+
"snippet.collapsible_body_label": "Contenu du bloc (Markdown)",
|
|
273
|
+
"snippet.collapsible_body_placeholder": "## Titre\n\nTexte",
|
|
274
|
+
"snippet.heading_1": "🇭1 Titre niveau 1",
|
|
275
|
+
"snippet.heading_2": "🇭2 Titre niveau 2",
|
|
276
|
+
"snippet.heading_3": "🇭3 Titre niveau 3",
|
|
277
|
+
"snippet.heading_4": "🇭4 Titre niveau 4",
|
|
278
|
+
"snippet.heading_text_label": "Texte du titre",
|
|
279
|
+
"snippet.heading_text_placeholder": "Mon titre",
|
|
280
|
+
"snippet.inline_edit_btn_heading_1": "Éditer le titre niveau 1",
|
|
281
|
+
"snippet.inline_edit_btn_heading_2": "Éditer le titre niveau 2",
|
|
282
|
+
"snippet.inline_edit_btn_heading_3": "Éditer le titre niveau 3",
|
|
283
|
+
"snippet.inline_edit_btn_heading_4": "Éditer le titre niveau 4",
|
|
272
284
|
"snippet.link_text_label": "Texte du lien",
|
|
273
285
|
"snippet.link_text_placeholder": "Mon lien",
|
|
274
286
|
"snippet.link_url_label": "URL",
|
|
@@ -1453,6 +1453,10 @@
|
|
|
1453
1453
|
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1454
1454
|
>
|
|
1455
1455
|
<option data-i18n="snippet.diagram" value="diagram" selected>Diagram</option>
|
|
1456
|
+
<option data-i18n="snippet.heading_1" value="heading-1">Title level 1</option>
|
|
1457
|
+
<option data-i18n="snippet.heading_2" value="heading-2">Title level 2</option>
|
|
1458
|
+
<option data-i18n="snippet.heading_3" value="heading-3">Title level 3</option>
|
|
1459
|
+
<option data-i18n="snippet.heading_4" value="heading-4">Title level 4</option>
|
|
1456
1460
|
<option data-i18n="snippet.collapsible" value="collapsible">Collapsible block (details)</option>
|
|
1457
1461
|
<option data-i18n="snippet.link" value="link">Link</option>
|
|
1458
1462
|
<option data-i18n="snippet.link_doc" value="doc-link">Link to document</option>
|
|
@@ -1476,6 +1480,26 @@
|
|
|
1476
1480
|
</select>
|
|
1477
1481
|
</div>
|
|
1478
1482
|
|
|
1483
|
+
<!-- Panel: heading (shared by heading-1..heading-4) -->
|
|
1484
|
+
<div id="snip-panel-heading" class="hidden space-y-3">
|
|
1485
|
+
<div class="space-y-1.5">
|
|
1486
|
+
<label
|
|
1487
|
+
data-i18n="snippet.heading_text_label"
|
|
1488
|
+
for="snip-heading-content"
|
|
1489
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1490
|
+
>Title text</label
|
|
1491
|
+
>
|
|
1492
|
+
<input
|
|
1493
|
+
id="snip-heading-content"
|
|
1494
|
+
type="text"
|
|
1495
|
+
oninput="snippetUpdatePreview()"
|
|
1496
|
+
data-i18n-placeholder="snippet.heading_text_placeholder"
|
|
1497
|
+
placeholder="My title"
|
|
1498
|
+
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1499
|
+
/>
|
|
1500
|
+
</div>
|
|
1501
|
+
</div>
|
|
1502
|
+
|
|
1479
1503
|
<!-- Panel: collapsible -->
|
|
1480
1504
|
<div id="snip-panel-collapsible" class="space-y-3">
|
|
1481
1505
|
<div class="space-y-1.5">
|
|
@@ -1492,6 +1516,22 @@
|
|
|
1492
1516
|
class="w-full px-3 py-2 text-sm rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1493
1517
|
/>
|
|
1494
1518
|
</div>
|
|
1519
|
+
<div class="space-y-1.5">
|
|
1520
|
+
<label
|
|
1521
|
+
data-i18n="snippet.collapsible_body_label"
|
|
1522
|
+
for="snip-collapsible-body"
|
|
1523
|
+
class="block text-xs font-medium text-gray-500 dark:text-gray-400"
|
|
1524
|
+
>Body Markdown</label
|
|
1525
|
+
>
|
|
1526
|
+
<textarea
|
|
1527
|
+
id="snip-collapsible-body"
|
|
1528
|
+
rows="6"
|
|
1529
|
+
oninput="snippetUpdatePreview()"
|
|
1530
|
+
data-i18n-placeholder="snippet.collapsible_body_placeholder"
|
|
1531
|
+
placeholder="## Titre Texte"
|
|
1532
|
+
class="w-full px-3 py-2 text-sm font-mono rounded-lg border border-gray-300 dark:border-gray-600 bg-gray-50 dark:bg-gray-800 text-gray-900 dark:text-gray-100 focus:outline-none focus:ring-2 focus:ring-blue-500"
|
|
1533
|
+
></textarea>
|
|
1534
|
+
</div>
|
|
1495
1535
|
</div>
|
|
1496
1536
|
|
|
1497
1537
|
<!-- Panel: link -->
|
|
@@ -19,6 +19,10 @@ const _INLINE_SNIPPET_TYPES = new Set([
|
|
|
19
19
|
"separator",
|
|
20
20
|
"ordered-list",
|
|
21
21
|
"unordered-list",
|
|
22
|
+
"heading-1",
|
|
23
|
+
"heading-2",
|
|
24
|
+
"heading-3",
|
|
25
|
+
"heading-4",
|
|
22
26
|
]);
|
|
23
27
|
|
|
24
28
|
const _INLINE_EDIT_AFFORDANCE_BY_TYPE = {
|
|
@@ -37,6 +41,10 @@ const _INLINE_EDIT_AFFORDANCE_BY_TYPE = {
|
|
|
37
41
|
"anchor-doc-link": { labelKey: "snippet.inline_edit_btn_anchor_doc_link", iconClass: "fa-solid fa-anchor" },
|
|
38
42
|
image: { labelKey: "snippet.inline_edit_btn_image", iconClass: "fa-solid fa-image" },
|
|
39
43
|
separator: { labelKey: "snippet.inline_edit_btn_separator", iconClass: "fa-solid fa-minus" },
|
|
44
|
+
"heading-1": { labelKey: "snippet.inline_edit_btn_heading_1", iconClass: "fa-solid fa-heading" },
|
|
45
|
+
"heading-2": { labelKey: "snippet.inline_edit_btn_heading_2", iconClass: "fa-solid fa-heading" },
|
|
46
|
+
"heading-3": { labelKey: "snippet.inline_edit_btn_heading_3", iconClass: "fa-solid fa-heading" },
|
|
47
|
+
"heading-4": { labelKey: "snippet.inline_edit_btn_heading_4", iconClass: "fa-solid fa-heading" },
|
|
40
48
|
};
|
|
41
49
|
|
|
42
50
|
function _inlineEditAffordance(type) {
|
|
@@ -55,6 +63,10 @@ const _INLINE_TYPE_SELECTORS = [
|
|
|
55
63
|
{ types: ["separator"], selector: "hr" },
|
|
56
64
|
{ types: ["ordered-list"], selector: "ol" },
|
|
57
65
|
{ types: ["unordered-list"], selector: "ul" },
|
|
66
|
+
{ types: ["heading-1"], selector: "h1" },
|
|
67
|
+
{ types: ["heading-2"], selector: "h2" },
|
|
68
|
+
{ types: ["heading-3"], selector: "h3" },
|
|
69
|
+
{ types: ["heading-4"], selector: "h4" },
|
|
58
70
|
{ types: ["image"], selector: "img" },
|
|
59
71
|
{
|
|
60
72
|
types: ["anchor-doc-link", "doc-link", "anchor-link", "link"],
|
|
@@ -65,6 +77,12 @@ const _INLINE_TYPE_SELECTORS = [
|
|
|
65
77
|
let _inlineSnippetPopup = null;
|
|
66
78
|
|
|
67
79
|
function _inlineRangesOverlap(a, b) {
|
|
80
|
+
// Reject only same-position duplicates (different regex matched the same span)
|
|
81
|
+
// and partial overlaps. Allow strict nesting so a container can coexist with
|
|
82
|
+
// its inner snippets (the deepest-mapped DOM ancestor wins at click time).
|
|
83
|
+
if (a.start === b.start && a.end === b.end) return true;
|
|
84
|
+
if (a.start >= b.start && a.end <= b.end) return false;
|
|
85
|
+
if (b.start >= a.start && b.end <= a.end) return false;
|
|
68
86
|
return a.start < b.end && b.start < a.end;
|
|
69
87
|
}
|
|
70
88
|
|
|
@@ -123,13 +141,21 @@ function _inlineAddCodeBlockRanges(ranges, content) {
|
|
|
123
141
|
function _inlineCollectSnippetRanges(content) {
|
|
124
142
|
const ranges = [];
|
|
125
143
|
|
|
126
|
-
|
|
144
|
+
// Container ranges first so inner snippets (code, lists, links…) that overlap
|
|
145
|
+
// with a container get skipped — the user edits the container as a whole.
|
|
127
146
|
_inlineAddRegexRanges(ranges, content, /<details[\s\S]*?<\/details>/gi);
|
|
128
147
|
_inlineAddRegexRanges(
|
|
129
148
|
ranges,
|
|
130
149
|
content,
|
|
131
150
|
/<div\b[^>]*border-left[^>]*>[\s\S]*?<\/div>/gi,
|
|
132
151
|
);
|
|
152
|
+
_inlineAddCodeBlockRanges(ranges, content);
|
|
153
|
+
_inlineAddRegexRanges(
|
|
154
|
+
ranges,
|
|
155
|
+
content,
|
|
156
|
+
/(?:^|\n\n)(#{1,4} [^\n]+)/g,
|
|
157
|
+
1,
|
|
158
|
+
);
|
|
133
159
|
_inlineAddRegexRanges(
|
|
134
160
|
ranges,
|
|
135
161
|
content,
|
|
@@ -18,6 +18,8 @@ function detectSnippetType(text) {
|
|
|
18
18
|
if (/^```/.test(t)) return "code-block";
|
|
19
19
|
if (/^(\| *.*? *\|)+\n(\| *-+.*\|)+/.test(t)) return "table";
|
|
20
20
|
if (/^> /.test(t)) return "blockquote";
|
|
21
|
+
const headingMatch = /^(#{1,4}) [^\n]+$/.exec(t);
|
|
22
|
+
if (headingMatch) return `heading-${headingMatch[1].length}`;
|
|
21
23
|
if (/^(---|\n---\n)$/.test(t)) return "separator";
|
|
22
24
|
if (/^1\. /.test(t)) return "ordered-list";
|
|
23
25
|
if (/^- /.test(t)) return "unordered-list";
|
|
@@ -10,6 +10,7 @@ let _snippetInlineEdit = false;
|
|
|
10
10
|
let _snippetInlineInsert = false;
|
|
11
11
|
let _snippetInlineIndent = "";
|
|
12
12
|
const _SNIPPET_PANELS = [
|
|
13
|
+
"heading",
|
|
13
14
|
"collapsible",
|
|
14
15
|
"link",
|
|
15
16
|
"doc-link",
|
|
@@ -29,6 +30,17 @@ const _SNIPPET_PANELS = [
|
|
|
29
30
|
"attachment",
|
|
30
31
|
];
|
|
31
32
|
|
|
33
|
+
const _SNIPPET_TYPE_TO_PANEL = {
|
|
34
|
+
"heading-1": "heading",
|
|
35
|
+
"heading-2": "heading",
|
|
36
|
+
"heading-3": "heading",
|
|
37
|
+
"heading-4": "heading",
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
function _snippetPanelForType(type) {
|
|
41
|
+
return _SNIPPET_TYPE_TO_PANEL[type] || type;
|
|
42
|
+
}
|
|
43
|
+
|
|
32
44
|
// Each emoji has search tags (bilingual FR/EN, space-separated, lowercase).
|
|
33
45
|
// Filter matches a 2+ char query against any tag prefix or substring.
|
|
34
46
|
const _EMOJI_CATEGORIES = [
|
|
@@ -700,6 +712,10 @@ function _openSnippetsModalForText(selectedText, detectedOverride = null) {
|
|
|
700
712
|
image: window.t('snippet.image'),
|
|
701
713
|
table: window.t('snippet.table'),
|
|
702
714
|
tree: window.t('snippet.tree'),
|
|
715
|
+
"heading-1": window.t('snippet.heading_1'),
|
|
716
|
+
"heading-2": window.t('snippet.heading_2'),
|
|
717
|
+
"heading-3": window.t('snippet.heading_3'),
|
|
718
|
+
"heading-4": window.t('snippet.heading_4'),
|
|
703
719
|
"colored-section": window.t('snippet.colored_section'),
|
|
704
720
|
"colored-text": window.t('snippet.colored_text'),
|
|
705
721
|
};
|
|
@@ -760,9 +776,10 @@ function closeSnippetsModal() {
|
|
|
760
776
|
|
|
761
777
|
function snippetTypeChanged() {
|
|
762
778
|
const type = document.getElementById("snippet-type").value;
|
|
779
|
+
const activePanel = _snippetPanelForType(type);
|
|
763
780
|
_SNIPPET_PANELS.forEach((p) => {
|
|
764
781
|
const panel = document.getElementById("snip-panel-" + p);
|
|
765
|
-
if (panel) panel.classList.toggle("hidden", p !==
|
|
782
|
+
if (panel) panel.classList.toggle("hidden", p !== activePanel);
|
|
766
783
|
});
|
|
767
784
|
const previewWrap = document.getElementById("snippet-preview-wrap");
|
|
768
785
|
if (previewWrap) {
|
|
@@ -776,7 +793,9 @@ function snippetTypeChanged() {
|
|
|
776
793
|
type === "unordered-list" ||
|
|
777
794
|
type === "colored-section" ||
|
|
778
795
|
type === "colored-text" ||
|
|
779
|
-
type === "tree"
|
|
796
|
+
type === "tree" ||
|
|
797
|
+
type === "collapsible" ||
|
|
798
|
+
type.startsWith("heading-"),
|
|
780
799
|
);
|
|
781
800
|
}
|
|
782
801
|
|
|
@@ -861,7 +880,11 @@ function buildSnippetMarkdown() {
|
|
|
861
880
|
const summary =
|
|
862
881
|
document.getElementById("snip-collapsible-summary").value ||
|
|
863
882
|
window.t('snippet.collapsible_summary_value');
|
|
864
|
-
|
|
883
|
+
const bodyEl = document.getElementById("snip-collapsible-body");
|
|
884
|
+
const body = bodyEl && bodyEl.value.trim() !== ""
|
|
885
|
+
? bodyEl.value
|
|
886
|
+
: "## Titre\n\nTexte";
|
|
887
|
+
return `<details>\n<summary>${summary}</summary>\n\n${body}\n\n</details>`;
|
|
865
888
|
}
|
|
866
889
|
case "link": {
|
|
867
890
|
const text =
|
|
@@ -973,6 +996,17 @@ function buildSnippetMarkdown() {
|
|
|
973
996
|
}
|
|
974
997
|
case "separator":
|
|
975
998
|
return `\n---\n`;
|
|
999
|
+
case "heading-1":
|
|
1000
|
+
case "heading-2":
|
|
1001
|
+
case "heading-3":
|
|
1002
|
+
case "heading-4": {
|
|
1003
|
+
const level = Number(type.slice(-1));
|
|
1004
|
+
const text =
|
|
1005
|
+
document.getElementById("snip-heading-content").value.trim() ||
|
|
1006
|
+
(window.t && window.t("snippet.heading_text_placeholder")) ||
|
|
1007
|
+
"Titre";
|
|
1008
|
+
return `${"#".repeat(level)} ${text}`;
|
|
1009
|
+
}
|
|
976
1010
|
case "image": {
|
|
977
1011
|
const alt =
|
|
978
1012
|
document.getElementById("snip-image-alt").value || "image";
|
|
@@ -1198,10 +1232,16 @@ function parseAndFillSnippet(text, type) {
|
|
|
1198
1232
|
const t = text.trim();
|
|
1199
1233
|
switch (type) {
|
|
1200
1234
|
case "collapsible": {
|
|
1201
|
-
const
|
|
1202
|
-
if (
|
|
1235
|
+
const summaryMatch = t.match(/<summary>([\s\S]*?)<\/summary>/i);
|
|
1236
|
+
if (summaryMatch) {
|
|
1203
1237
|
document.getElementById("snip-collapsible-summary").value =
|
|
1204
|
-
|
|
1238
|
+
summaryMatch[1].trim();
|
|
1239
|
+
}
|
|
1240
|
+
const bodyMatch = t.match(
|
|
1241
|
+
/<details\b[^>]*>[\s\S]*?<\/summary>\s*\n?([\s\S]*?)\s*<\/details>\s*$/i,
|
|
1242
|
+
);
|
|
1243
|
+
const bodyEl = document.getElementById("snip-collapsible-body");
|
|
1244
|
+
if (bodyEl) bodyEl.value = bodyMatch ? bodyMatch[1].trim() : "";
|
|
1205
1245
|
break;
|
|
1206
1246
|
}
|
|
1207
1247
|
case "link": {
|
|
@@ -1326,6 +1366,17 @@ function parseAndFillSnippet(text, type) {
|
|
|
1326
1366
|
}
|
|
1327
1367
|
break;
|
|
1328
1368
|
}
|
|
1369
|
+
case "heading-1":
|
|
1370
|
+
case "heading-2":
|
|
1371
|
+
case "heading-3":
|
|
1372
|
+
case "heading-4": {
|
|
1373
|
+
const level = Number(type.slice(-1));
|
|
1374
|
+
const re = new RegExp(`^#{${level}}\\s+(.+)$`);
|
|
1375
|
+
const m = t.match(re);
|
|
1376
|
+
const headingEl = document.getElementById("snip-heading-content");
|
|
1377
|
+
if (headingEl) headingEl.value = m ? m[1].trim() : "";
|
|
1378
|
+
break;
|
|
1379
|
+
}
|
|
1329
1380
|
case "table": {
|
|
1330
1381
|
const allLines = t
|
|
1331
1382
|
.split("\n")
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "living-ai-documentation",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.9.0",
|
|
4
4
|
"description": "Local Markdown documentation hub with a built-in MCP server — coding agents create ADRs, draw diagrams and detect drift while you code.",
|
|
5
5
|
"main": "dist/src/server.js",
|
|
6
6
|
"bin": {
|