pict-section-inlinedocumentation 1.0.0 → 1.0.2

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 (41) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +11 -13
  3. package/diagrams/four-levels-of-embeddedness.excalidraw +717 -0
  4. package/diagrams/four-levels-of-embeddedness.mmd +4 -0
  5. package/diagrams/four-levels-of-embeddedness.svg +2 -0
  6. package/docs/README.md +10 -19
  7. package/docs/_brand.json +18 -0
  8. package/docs/_cover.md +6 -0
  9. package/docs/_sidebar.md +8 -4
  10. package/docs/_version.json +3 -3
  11. package/docs/architecture.md +2 -44
  12. package/docs/diagrams/component-diagram.excalidraw +3546 -0
  13. package/docs/diagrams/component-diagram.mmd +42 -0
  14. package/docs/diagrams/component-diagram.svg +2 -0
  15. package/docs/diagrams/four-levels-of-embeddedness.excalidraw +717 -0
  16. package/docs/diagrams/four-levels-of-embeddedness.mmd +9 -0
  17. package/docs/diagrams/four-levels-of-embeddedness.svg +2 -0
  18. package/docs/diagrams/project-layout.excalidraw +6082 -0
  19. package/docs/diagrams/project-layout.mmd +25 -0
  20. package/docs/diagrams/project-layout.svg +2 -0
  21. package/docs/embedding-level2-routes.md +1 -1
  22. package/docs/embedding-level4-autogen.md +1 -1
  23. package/docs/examples/README.md +9 -0
  24. package/docs/examples/bookshop/README.md +582 -0
  25. package/docs/examples/bookshop/bookshop_example.js +4519 -0
  26. package/docs/examples/bookshop/index.html +236 -0
  27. package/docs/index.html +6 -7
  28. package/docs/overview.md +4 -4
  29. package/docs/reference.md +2 -27
  30. package/docs/retold-catalog.json +77 -178
  31. package/docs/retold-keyword-index.json +14134 -1917
  32. package/example_applications/basic/docs/_brand.json +18 -0
  33. package/example_applications/bookshop/docs/_brand.json +18 -0
  34. package/example_applications/bookshop/package.json +9 -1
  35. package/package.json +9 -9
  36. package/source/providers/Pict-Provider-InlineDocumentation.js +27 -3
  37. package/source/views/Pict-View-InlineDocumentation-Content.js +19 -15
  38. package/source/views/Pict-View-InlineDocumentation-Layout.js +115 -3
  39. package/source/views/Pict-View-InlineDocumentation-Nav.js +98 -17
  40. package/source/views/Pict-View-InlineDocumentation-TopicManager.js +18 -18
  41. package/docs/css/docuserve.css +0 -327
@@ -0,0 +1,18 @@
1
+ {
2
+ "Hash": "pict-section-inlinedocumentation/basic",
3
+ "Name": "basic",
4
+ "Tagline": "",
5
+ "Palette": "carnival",
6
+ "Icon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-pict-section-inlinedocumentation_basic-filled-light\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tA 46 46 0 1 0 94 48\n\t\t\tA 46 46 0 1 0 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tA 46 46 0 1 0 94 48\n\t\t\tA 46 46 0 1 0 2 48 Z\" fill=\"#e4a926\"/>\n\t\t<g clip-path=\"url(#frame-pict-section-inlinedocumentation_basic-filled-light)\"><circle cx=\"48\" cy=\"48\" r=\"36\" fill=\"none\" stroke=\"#66efae\" stroke-width=\"2\" opacity=\"0.45\"/>\n\t\t\t\t\t<circle cx=\"48\" cy=\"48\" r=\"22\" fill=\"rgba(255,255,255,0.18)\"/>\n\t\t\t\t\t<circle cx=\"13.69\" cy=\"37.09\" r=\"9\" fill=\"#66efae\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"28\" font-weight=\"600\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">PSI</text>\n\t</svg>",
7
+ "IconType": "svg",
8
+ "Favicon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-pict-section-inlinedocumentation_basic-light\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tA 46 46 0 1 0 94 48\n\t\t\tA 46 46 0 1 0 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tA 46 46 0 1 0 94 48\n\t\t\tA 46 46 0 1 0 2 48 Z\" fill=\"#e4a926\"/>\n\t\t<g clip-path=\"url(#fav-pict-section-inlinedocumentation_basic-light)\"><circle cx=\"48\" cy=\"48\" r=\"28\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">P</text>\n\t</svg>",
9
+ "FaviconDark": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-pict-section-inlinedocumentation_basic-dark\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tA 46 46 0 1 0 94 48\n\t\t\tA 46 46 0 1 0 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tA 46 46 0 1 0 94 48\n\t\t\tA 46 46 0 1 0 2 48 Z\" fill=\"#eac87c\"/>\n\t\t<g clip-path=\"url(#fav-pict-section-inlinedocumentation_basic-dark)\"><circle cx=\"48\" cy=\"48\" r=\"28\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">P</text>\n\t</svg>",
10
+ "Colors": {
11
+ "Primary": "#e4a926",
12
+ "Secondary": "#66efae",
13
+ "PrimaryLight": "#e4a926",
14
+ "PrimaryDark": "#eac87c",
15
+ "SecondaryLight": "#66efae",
16
+ "SecondaryDark": "#a6f2ce"
17
+ }
18
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "Hash": "pict-section-inlinedocumentation/bookshop",
3
+ "Name": "bookshop",
4
+ "Tagline": "Bookshop example demonstrating inline contextual documentation with pict-section-inlinedocumentation",
5
+ "Palette": "carnival",
6
+ "Icon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-pict-section-inlinedocumentation_bookshop-filled-light\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#f3a513\"/>\n\t\t<g clip-path=\"url(#frame-pict-section-inlinedocumentation_bookshop-filled-light)\"><circle cx=\"48\" cy=\"48\" r=\"38\" fill=\"rgba(255,255,255,0.18)\"/>\n\t\t\t\t\t<circle cx=\"48\" cy=\"48\" r=\"21\" fill=\"#38ec8f\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"28\" font-weight=\"700\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">PSI</text>\n\t</svg>",
7
+ "IconType": "svg",
8
+ "Favicon": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-pict-section-inlinedocumentation_bookshop-light\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#f3a513\"/>\n\t\t<g clip-path=\"url(#fav-pict-section-inlinedocumentation_bookshop-light)\"><circle cx=\"48\" cy=\"48\" r=\"42\" fill=\"rgba(255,255,255,0.22)\"/>\n\t\t\t\t\t<circle cx=\"48\" cy=\"48\" r=\"21\" fill=\"#38ec8f\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">P</text>\n\t</svg>",
9
+ "FaviconDark": "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-pict-section-inlinedocumentation_bookshop-dark\">\n\t\t\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 24 2\n\t\tH 72\n\t\tQ 94 2 94 24\n\t\tV 72\n\t\tQ 94 94 72 94\n\t\tH 24\n\t\tQ 2 94 2 72\n\t\tV 24\n\t\tQ 2 2 24 2 Z\" fill=\"#f3c56f\"/>\n\t\t<g clip-path=\"url(#fav-pict-section-inlinedocumentation_bookshop-dark)\"><circle cx=\"48\" cy=\"48\" r=\"42\" fill=\"rgba(255,255,255,0.22)\"/>\n\t\t\t\t\t<circle cx=\"48\" cy=\"48\" r=\"21\" fill=\"#8ff0be\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">P</text>\n\t</svg>",
10
+ "Colors": {
11
+ "Primary": "#f3a513",
12
+ "Secondary": "#38ec8f",
13
+ "PrimaryLight": "#f3a513",
14
+ "PrimaryDark": "#f3c56f",
15
+ "SecondaryLight": "#38ec8f",
16
+ "SecondaryDark": "#8ff0be"
17
+ }
18
+ }
@@ -30,5 +30,13 @@
30
30
  "from": "./data/pict_documentation_topics.json",
31
31
  "to": "./dist/docs/"
32
32
  }
33
- ]
33
+ ],
34
+ "retold": {
35
+ "ExampleApplication": {
36
+ "Stage": true,
37
+ "Title": "Bookshop",
38
+ "Summary": "E-commerce demo with route-mapped help, data-attribute tooltips, and F1 toggling for pict-section-inlinedocumentation.",
39
+ "Complexity": "Intermediate"
40
+ }
41
+ }
34
42
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pict-section-inlinedocumentation",
3
- "version": "1.0.0",
3
+ "version": "1.0.2",
4
4
  "description": "Pict embeddable inline documentation browser with topic support",
5
5
  "main": "source/Pict-Section-InlineDocumentation.js",
6
6
  "scripts": {
@@ -13,27 +13,27 @@
13
13
  },
14
14
  "repository": {
15
15
  "type": "git",
16
- "url": "git+https://github.com/stevenvelozo/pict-section-inlinedocumentation.git"
16
+ "url": "git+https://github.com/fable-retold/pict-section-inlinedocumentation.git"
17
17
  },
18
18
  "author": "steven velozo <steven@velozo.com>",
19
19
  "license": "MIT",
20
20
  "bugs": {
21
- "url": "https://github.com/stevenvelozo/pict-section-inlinedocumentation/issues"
21
+ "url": "https://github.com/fable-retold/pict-section-inlinedocumentation/issues"
22
22
  },
23
- "homepage": "https://github.com/stevenvelozo/pict-section-inlinedocumentation#readme",
23
+ "homepage": "https://github.com/fable-retold/pict-section-inlinedocumentation#readme",
24
24
  "dependencies": {
25
25
  "lunr": "^2.3.9",
26
26
  "pict-provider": "^1.0.13",
27
- "pict-section-content": "^1.0.0",
27
+ "pict-section-content": "^1.0.7",
28
28
  "pict-section-markdowneditor": "^1.0.15",
29
- "pict-section-modal": "^1.0.1",
29
+ "pict-section-modal": "^1.1.4",
30
30
  "pict-view": "^1.0.68"
31
31
  },
32
32
  "devDependencies": {
33
- "pict": "^1.0.368",
34
- "pict-docuserve": "^1.0.0",
33
+ "pict": "^1.0.372",
34
+ "pict-docuserve": "^1.4.4",
35
35
  "puppeteer": "^24.40.0",
36
- "quackage": "^1.2.3"
36
+ "quackage": "^1.3.0"
37
37
  },
38
38
  "mocha": {
39
39
  "diff": true,
@@ -2213,24 +2213,48 @@ class InlineDocumentationProvider extends libPictProvider
2213
2213
  }
2214
2214
  else if (tmpCurrentGroup)
2215
2215
  {
2216
- // Indented item — document within the current group
2216
+ // Indented item — a document (link) or a sub-folder (no link)
2217
+ // within the current group. Capture the nesting Level from the
2218
+ // indentation so the nav can render real hierarchy.
2219
+ let tmpLevel = Math.max(0, Math.floor((tmpIndent - 2) / 2));
2217
2220
  if (tmpLinkMatch)
2218
2221
  {
2219
2222
  tmpCurrentGroup.Items.push({
2220
2223
  Name: tmpLinkMatch[1].trim(),
2221
- Path: this._normalizePath(tmpLinkMatch[2].trim())
2224
+ Path: this._normalizePath(tmpLinkMatch[2].trim()),
2225
+ Level: tmpLevel
2222
2226
  });
2223
2227
  }
2224
2228
  else
2225
2229
  {
2226
2230
  tmpCurrentGroup.Items.push({
2227
2231
  Name: tmpItemContent,
2228
- Path: ''
2232
+ Path: '',
2233
+ Level: tmpLevel,
2234
+ IsFolder: true
2229
2235
  });
2230
2236
  }
2231
2237
  }
2232
2238
  }
2233
2239
 
2240
+ // Make sub-folder nodes actionable: resolve each folder's first
2241
+ // descendant document (the items are in depth-first order, so scan
2242
+ // forward until we leave the folder's subtree) so clicking the folder
2243
+ // opens its first child.
2244
+ for (let g = 0; g < tmpGroups.length; g++)
2245
+ {
2246
+ let tmpItems = tmpGroups[g].Items || [];
2247
+ for (let a = 0; a < tmpItems.length; a++)
2248
+ {
2249
+ if (!tmpItems[a].IsFolder) { continue; }
2250
+ for (let b = a + 1; b < tmpItems.length; b++)
2251
+ {
2252
+ if ((tmpItems[b].Level || 0) <= (tmpItems[a].Level || 0)) { break; }
2253
+ if (tmpItems[b].Path) { tmpItems[a].FirstChildPath = tmpItems[b].Path; break; }
2254
+ }
2255
+ }
2256
+ }
2257
+
2234
2258
  return tmpGroups;
2235
2259
  }
2236
2260
 
@@ -60,9 +60,13 @@ const _ViewConfiguration =
60
60
  .pict-inline-doc-content a:hover {
61
61
  text-decoration: underline;
62
62
  }
63
+ /* Code blocks: bg + text both flow from background/text tokens
64
+ so they re-skin coherently across themes. (Previous version
65
+ paired background-tertiary with text-on-brand — both light
66
+ in most palettes, producing invisible text.) */
63
67
  .pict-inline-doc-content pre {
64
- background: var(--theme-color-text-primary, #3D3229);
65
- color: var(--theme-color-text-on-brand, #E8E0D4);
68
+ background: var(--theme-color-background-tertiary, #F0ECE4);
69
+ color: var(--theme-color-text-primary, #3D3229);
66
70
  padding: 1em;
67
71
  border-radius: 5px;
68
72
  overflow-x: auto;
@@ -84,7 +88,7 @@ const _ViewConfiguration =
84
88
  font-size: inherit;
85
89
  }
86
90
  .pict-inline-doc-content blockquote {
87
- border-left: 3px solid #2E7D74;
91
+ border-left: 3px solid var(--theme-color-brand-primary, #2E7D74);
88
92
  margin: 0.8em 0;
89
93
  padding: 0.4em 0.8em;
90
94
  background: var(--theme-color-background-secondary, #F7F5F0);
@@ -197,13 +201,13 @@ const _ViewConfiguration =
197
201
  stroke-linejoin: round;
198
202
  }
199
203
  .pict-content-code-action-btn:hover {
200
- background: #2E7D74;
201
- color: var(--theme-color-background-panel, #FFFFFF);
204
+ background: var(--theme-color-brand-primary, #2E7D74);
205
+ color: var(--theme-color-text-on-brand, #FFFFFF);
202
206
  border-color: var(--theme-color-brand-primary, #2E7D74);
203
207
  }
204
208
  .pict-content-code-action-btn.is-copied {
205
- background: #2E7D74;
206
- color: var(--theme-color-background-panel, #FFFFFF);
209
+ background: var(--theme-color-brand-primary, #2E7D74);
210
+ color: var(--theme-color-text-on-brand, #FFFFFF);
207
211
  border-color: var(--theme-color-brand-primary, #2E7D74);
208
212
  }
209
213
  .pict-inline-doc-edit-toolbar {
@@ -229,7 +233,7 @@ const _ViewConfiguration =
229
233
  align-items: center;
230
234
  justify-content: center;
231
235
  padding: 0.25em 0.6em;
232
- border: 1px solid #D4A373;
236
+ border: 1px solid var(--theme-color-border-default, #D4A373);
233
237
  border-radius: 3px;
234
238
  background: var(--theme-color-background-panel, #fff);
235
239
  color: var(--theme-color-text-secondary, #5E5549);
@@ -241,12 +245,12 @@ const _ViewConfiguration =
241
245
  background: var(--theme-color-background-tertiary, #F0ECE4);
242
246
  }
243
247
  .pict-inline-doc-edit-btn.primary {
244
- background: #2E7D74;
245
- color: var(--theme-color-background-panel, #fff);
248
+ background: var(--theme-color-brand-primary, #2E7D74);
249
+ color: var(--theme-color-text-on-brand, #fff);
246
250
  border-color: var(--theme-color-brand-primary, #2E7D74);
247
251
  }
248
252
  .pict-inline-doc-edit-btn.primary:hover {
249
- background: #266D65;
253
+ background: var(--theme-color-brand-primary-hover, #266D65);
250
254
  }
251
255
  .pict-inline-doc-edit-btn .btn-icon {
252
256
  margin-right: 0.3em;
@@ -256,7 +260,7 @@ const _ViewConfiguration =
256
260
  }
257
261
  /* Tooltip placeholder: edit mode indicators */
258
262
  [data-d-tooltip].pict-inline-doc-tooltip-edit-target {
259
- outline: 1px dashed #2E7D74;
263
+ outline: 1px dashed var(--theme-color-brand-primary, #2E7D74);
260
264
  outline-offset: 2px;
261
265
  cursor: pointer;
262
266
  position: relative;
@@ -268,8 +272,8 @@ const _ViewConfiguration =
268
272
  right: -6px;
269
273
  width: 14px;
270
274
  height: 14px;
271
- background: #2E7D74;
272
- color: var(--theme-color-background-panel, #fff);
275
+ background: var(--theme-color-brand-primary, #2E7D74);
276
+ color: var(--theme-color-text-on-brand, #fff);
273
277
  border-radius: 50%;
274
278
  font-size: 9px;
275
279
  line-height: 14px;
@@ -292,7 +296,7 @@ const _ViewConfiguration =
292
296
  /* Empty icon tooltip in edit mode */
293
297
  .pict-inline-doc-tooltip-empty .pict-inline-doc-tooltip-icon {
294
298
  opacity: 0.4;
295
- outline: 1px dashed #8A7F72;
299
+ outline: 1px dashed var(--theme-color-text-muted, #8A7F72);
296
300
  outline-offset: 1px;
297
301
  border-radius: 50%;
298
302
  }
@@ -25,14 +25,27 @@ const _ViewConfiguration =
25
25
  overflow: hidden;
26
26
  }
27
27
  .pict-inline-doc-nav-container {
28
- width: 240px;
29
- min-width: 200px;
30
- max-width: 300px;
28
+ width: var(--pict-inline-doc-nav-width, 240px);
29
+ min-width: 160px;
30
+ max-width: 640px;
31
31
  border-right: 1px solid var(--theme-color-border-default, #E5DED4);
32
32
  background: var(--theme-color-background-secondary, #F7F5F0);
33
33
  overflow-y: auto;
34
34
  flex-shrink: 0;
35
35
  }
36
+ .pict-inline-doc-resizer {
37
+ flex: 0 0 6px;
38
+ width: 6px;
39
+ margin: 0 -3px;
40
+ z-index: 2;
41
+ cursor: col-resize;
42
+ background: transparent;
43
+ transition: background 0.12s ease;
44
+ }
45
+ .pict-inline-doc-resizer:hover,
46
+ .pict-inline-doc-resizer.pict-inline-doc-resizing {
47
+ background: var(--theme-color-brand-primary, #2E7D74);
48
+ }
36
49
  .pict-inline-doc-content-container {
37
50
  flex: 1;
38
51
  overflow-y: auto;
@@ -55,6 +68,9 @@ const _ViewConfiguration =
55
68
  overflow-y: visible;
56
69
  flex-shrink: 0;
57
70
  }
71
+ .pict-inline-doc.pict-inline-doc-compact .pict-inline-doc-resizer {
72
+ display: none;
73
+ }
58
74
  `,
59
75
 
60
76
  Templates:
@@ -64,6 +80,7 @@ const _ViewConfiguration =
64
80
  Template: /*html*/`
65
81
  <div class="pict-inline-doc">
66
82
  <div class="pict-inline-doc-nav-container" id="InlineDoc-Nav-Container"></div>
83
+ <div class="pict-inline-doc-resizer" id="InlineDoc-Resizer" title="Drag to resize the navigation"></div>
67
84
  <div class="pict-inline-doc-content-container" id="InlineDoc-Content-Container"></div>
68
85
  </div>
69
86
  `
@@ -93,12 +110,107 @@ class InlineDocumentationLayoutView extends libPictView
93
110
  // Inject all view CSS into the PICT-CSS style element
94
111
  this.pict.CSSMap.injectCSS();
95
112
 
113
+ // Restore any saved nav width, then make the nav/content divider draggable
114
+ this._restoreNavWidth();
115
+ this._wireNavResizer();
116
+
96
117
  // Watch for size changes and toggle compact mode
97
118
  this._setupCompactModeObserver();
98
119
 
99
120
  return super.onAfterRender();
100
121
  }
101
122
 
123
+ /**
124
+ * Make the divider between the nav and the content draggable so the reader
125
+ * can widen or narrow the navigation. The width lives in a CSS custom
126
+ * property on the layout container and is persisted to localStorage.
127
+ */
128
+ _wireNavResizer()
129
+ {
130
+ if (typeof document === 'undefined')
131
+ {
132
+ return;
133
+ }
134
+
135
+ let tmpResizer = document.getElementById('InlineDoc-Resizer');
136
+ let tmpContainer = document.querySelector('.pict-inline-doc');
137
+ let tmpNav = document.getElementById('InlineDoc-Nav-Container');
138
+ if (!tmpResizer || !tmpContainer || !tmpNav)
139
+ {
140
+ return;
141
+ }
142
+
143
+ let tmpMin = 160;
144
+ let tmpMax = 640;
145
+ let tmpSelf = this;
146
+
147
+ tmpResizer.addEventListener('mousedown', (pDownEvent) =>
148
+ {
149
+ pDownEvent.preventDefault();
150
+ let tmpStartX = pDownEvent.clientX;
151
+ let tmpStartWidth = tmpNav.offsetWidth;
152
+
153
+ tmpResizer.classList.add('pict-inline-doc-resizing');
154
+ document.body.style.userSelect = 'none';
155
+ document.body.style.cursor = 'col-resize';
156
+
157
+ // A drag needs document-level move/up tracking; both listeners are
158
+ // removed on release, so nothing leaks across renders.
159
+ let fMove = (pMoveEvent) =>
160
+ {
161
+ let tmpWidth = tmpStartWidth + (pMoveEvent.clientX - tmpStartX);
162
+ tmpWidth = Math.max(tmpMin, Math.min(tmpMax, tmpWidth));
163
+ tmpContainer.style.setProperty('--pict-inline-doc-nav-width', tmpWidth + 'px');
164
+ };
165
+ let fUp = () =>
166
+ {
167
+ document.removeEventListener('mousemove', fMove);
168
+ document.removeEventListener('mouseup', fUp);
169
+ tmpResizer.classList.remove('pict-inline-doc-resizing');
170
+ document.body.style.userSelect = '';
171
+ document.body.style.cursor = '';
172
+ tmpSelf._persistNavWidth(tmpContainer.style.getPropertyValue('--pict-inline-doc-nav-width'));
173
+ };
174
+
175
+ document.addEventListener('mousemove', fMove);
176
+ document.addEventListener('mouseup', fUp);
177
+ });
178
+ }
179
+
180
+ _persistNavWidth(pWidth)
181
+ {
182
+ try
183
+ {
184
+ if (pWidth && typeof localStorage !== 'undefined')
185
+ {
186
+ localStorage.setItem('pict-inline-doc-nav-width', pWidth);
187
+ }
188
+ }
189
+ catch (pError) { /* storage unavailable — the width just won't persist */ }
190
+ }
191
+
192
+ _restoreNavWidth()
193
+ {
194
+ try
195
+ {
196
+ if (typeof localStorage === 'undefined')
197
+ {
198
+ return;
199
+ }
200
+ let tmpSaved = localStorage.getItem('pict-inline-doc-nav-width');
201
+ if (!tmpSaved)
202
+ {
203
+ return;
204
+ }
205
+ let tmpContainer = document.querySelector('.pict-inline-doc');
206
+ if (tmpContainer)
207
+ {
208
+ tmpContainer.style.setProperty('--pict-inline-doc-nav-width', tmpSaved);
209
+ }
210
+ }
211
+ catch (pError) { /* ignore */ }
212
+ }
213
+
102
214
  /**
103
215
  * Set up a ResizeObserver to toggle compact mode when the container
104
216
  * is too narrow for a side-by-side nav + content layout.
@@ -112,7 +112,7 @@ const _ViewConfiguration =
112
112
  }
113
113
  .pict-inline-doc-nav-item {
114
114
  display: block;
115
- padding: 0.25em 0.8em 0.25em 1.6em;
115
+ padding: 0.25em 0.8em 0.25em calc(1.6em + var(--doc-nav-level, 0) * 0.85em);
116
116
  color: var(--theme-color-text-secondary, #5E5549);
117
117
  text-decoration: none;
118
118
  font-size: 0.85em;
@@ -123,15 +123,34 @@ const _ViewConfiguration =
123
123
  .pict-inline-doc-nav-item:hover {
124
124
  background: var(--theme-color-background-tertiary, #EDE8DF);
125
125
  }
126
+ .pict-inline-doc-nav-folder {
127
+ font-weight: 600;
128
+ color: var(--theme-color-text-primary, #3D3229);
129
+ }
130
+ .pict-inline-doc-nav-folder-icon {
131
+ margin-right: 0.4em;
132
+ vertical-align: -0.12em;
133
+ opacity: 0.65;
134
+ }
135
+ .pict-inline-doc-nav-file-icon {
136
+ margin-right: 0.4em;
137
+ vertical-align: -0.12em;
138
+ opacity: 0.55;
139
+ }
140
+ .pict-inline-doc-nav-section-dot {
141
+ margin-right: 0.4em;
142
+ vertical-align: -0.12em;
143
+ opacity: 0.3;
144
+ }
126
145
  .pict-inline-doc-nav-item.active {
127
- background: #E8E3D8;
146
+ background: var(--theme-color-background-hover, #E8E3D8);
128
147
  color: var(--theme-color-brand-primary, #2E7D74);
129
148
  border-left-color: var(--theme-color-brand-primary, #2E7D74);
130
149
  font-weight: 500;
131
150
  }
132
151
  .pict-inline-doc-nav-heading {
133
152
  display: block;
134
- padding: 0.15em 0.8em 0.15em 2.4em;
153
+ padding: 0.15em 0.8em 0.15em calc(2.4em + var(--doc-nav-level, 0) * 0.85em);
135
154
  color: var(--theme-color-text-muted, #8A7F72);
136
155
  font-size: 0.78em;
137
156
  cursor: pointer;
@@ -143,7 +162,7 @@ const _ViewConfiguration =
143
162
  color: var(--theme-color-text-secondary, #5E5549);
144
163
  }
145
164
  .pict-inline-doc-nav-heading.h3 {
146
- padding-left: 3.2em;
165
+ padding-left: calc(3.2em + var(--doc-nav-level, 0) * 0.85em);
147
166
  font-size: 0.72em;
148
167
  }
149
168
  /* Search icon in collapsed header */
@@ -214,8 +233,8 @@ const _ViewConfiguration =
214
233
  display: inline-block;
215
234
  margin: 0.5em 1em;
216
235
  padding: 0.3em 0.7em;
217
- background: #2E7D74;
218
- color: var(--theme-color-background-panel, #fff);
236
+ background: var(--theme-color-brand-primary, #2E7D74);
237
+ color: var(--theme-color-text-on-brand, #fff);
219
238
  border-radius: 4px;
220
239
  font-size: 0.8em;
221
240
  font-weight: 500;
@@ -258,15 +277,15 @@ const _ViewConfiguration =
258
277
  color: var(--theme-color-brand-primary, #2E7D74);
259
278
  }
260
279
  .pict-inline-doc-nav-toolbar-btn.accent:hover {
261
- background: #F0F9F7;
280
+ background: var(--theme-color-background-hover, #F0F9F7);
262
281
  }
263
282
  .pict-inline-doc-nav-toolbar-btn.active {
264
- background: #2E7D74;
265
- color: var(--theme-color-background-panel, #fff);
283
+ background: var(--theme-color-brand-primary, #2E7D74);
284
+ color: var(--theme-color-text-on-brand, #fff);
266
285
  border-color: var(--theme-color-brand-primary, #2E7D74);
267
286
  }
268
287
  .pict-inline-doc-nav-toolbar-btn.active:hover {
269
- background: #266D65;
288
+ background: var(--theme-color-brand-primary-hover, #266D65);
270
289
  }
271
290
  .pict-inline-doc-nav-toolbar-spacer {
272
291
  flex: 1;
@@ -624,22 +643,44 @@ class InlineDocumentationNavView extends libPictView
624
643
  let tmpActive = (pCurrentPath === tmpGroup.Path) ? ' active' : '';
625
644
  tmpHTML += '<a class="pict-inline-doc-nav-item' + tmpActive
626
645
  + '" data-doc-path="' + this._escapeHTML(tmpGroup.Path) + '">'
646
+ + this._fileIconSVG()
627
647
  + this._escapeHTML(tmpGroup.Name)
628
648
  + '</a>';
629
649
 
630
650
  // If this is the active item, render heading sub-items
631
651
  if (pCurrentPath === tmpGroup.Path)
632
652
  {
633
- tmpHTML += this._renderHeadingSubItems(pHeadings, tmpFilterLower);
653
+ tmpHTML += this._renderHeadingSubItems(pHeadings, tmpFilterLower, 0);
634
654
  }
635
655
  }
636
656
 
637
657
  for (let j = 0; j < tmpGroupItems.length; j++)
638
658
  {
639
659
  let tmpItem = tmpGroupItems[j];
660
+ let tmpIndent = ' style="--doc-nav-level:' + (tmpItem.Level || 0) + '"';
661
+
662
+ // Sub-folder node (no document of its own). Indent it by its
663
+ // level and, when it has descendants, make it clickable so it
664
+ // opens its first child document; mark it with a folder glyph.
640
665
  if (!tmpItem.Path)
641
666
  {
642
- tmpHTML += '<span class="pict-inline-doc-nav-item">' + this._escapeHTML(tmpItem.Name) + '</span>';
667
+ if (tmpItem.FirstChildPath)
668
+ {
669
+ // Folders are navigational shortcuts to their first child; the
670
+ // child item carries the active highlight, so the folder doesn't.
671
+ tmpHTML += '<a class="pict-inline-doc-nav-item pict-inline-doc-nav-folder'
672
+ + '" data-doc-path="' + this._escapeHTML(tmpItem.FirstChildPath) + '"' + tmpIndent + '>'
673
+ + this._folderIconSVG()
674
+ + this._escapeHTML(tmpItem.Name)
675
+ + '</a>';
676
+ }
677
+ else
678
+ {
679
+ tmpHTML += '<span class="pict-inline-doc-nav-item pict-inline-doc-nav-folder"' + tmpIndent + '>'
680
+ + this._folderIconSVG()
681
+ + this._escapeHTML(tmpItem.Name)
682
+ + '</span>';
683
+ }
643
684
  continue;
644
685
  }
645
686
 
@@ -647,7 +688,8 @@ class InlineDocumentationNavView extends libPictView
647
688
  {
648
689
  // External link — opens in a new tab
649
690
  tmpHTML += '<a class="pict-inline-doc-nav-item pict-inline-doc-nav-item-external'
650
- + '" data-external-url="' + this._escapeHTML(tmpItem.ExternalURL) + '">'
691
+ + '" data-external-url="' + this._escapeHTML(tmpItem.ExternalURL) + '"' + tmpIndent + '>'
692
+ + this._fileIconSVG()
651
693
  + this._escapeHTML(tmpItem.Name)
652
694
  + '<svg class="pict-inline-doc-nav-external-icon" width="0.75em" height="0.75em" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M12 9v4a1 1 0 01-1 1H3a1 1 0 01-1-1V5a1 1 0 011-1h4"/><polyline points="8,2 14,2 14,8"/><line x1="14" y1="2" x2="7" y2="9"/></svg>'
653
695
  + '</a>';
@@ -656,14 +698,15 @@ class InlineDocumentationNavView extends libPictView
656
698
  {
657
699
  let tmpActive = (pCurrentPath === tmpItem.Path) ? ' active' : '';
658
700
  tmpHTML += '<a class="pict-inline-doc-nav-item' + tmpActive
659
- + '" data-doc-path="' + this._escapeHTML(tmpItem.Path) + '">'
701
+ + '" data-doc-path="' + this._escapeHTML(tmpItem.Path) + '"' + tmpIndent + '>'
702
+ + this._fileIconSVG()
660
703
  + this._escapeHTML(tmpItem.Name)
661
704
  + '</a>';
662
705
 
663
706
  // If this is the active item, render heading sub-items
664
707
  if (pCurrentPath === tmpItem.Path)
665
708
  {
666
- tmpHTML += this._renderHeadingSubItems(pHeadings, tmpFilterLower);
709
+ tmpHTML += this._renderHeadingSubItems(pHeadings, tmpFilterLower, tmpItem.Level || 0);
667
710
  }
668
711
  }
669
712
  }
@@ -675,6 +718,40 @@ class InlineDocumentationNavView extends libPictView
675
718
  return tmpHTML;
676
719
  }
677
720
 
721
+ /**
722
+ * A small folder glyph for sub-folder nav nodes. Uses currentColor so it
723
+ * follows the theme like the other inline nav icons.
724
+ *
725
+ * @returns {string} inline SVG HTML
726
+ */
727
+ _folderIconSVG()
728
+ {
729
+ return '<svg class="pict-inline-doc-nav-folder-icon" width="0.85em" height="0.85em" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M1.5 5a1 1 0 0 1 1-1h3.2l1.3 1.4h5.5a1 1 0 0 1 1 1V12a1 1 0 0 1-1 1h-11a1 1 0 0 1-1-1z"/></svg>';
730
+ }
731
+
732
+ /**
733
+ * A small document glyph (a page with a folded corner) for markdown file
734
+ * nodes. Same footprint as the folder glyph so files and folders line up at
735
+ * the same depth.
736
+ *
737
+ * @returns {string} inline SVG HTML
738
+ */
739
+ _fileIconSVG()
740
+ {
741
+ return '<svg class="pict-inline-doc-nav-file-icon" width="0.85em" height="0.85em" viewBox="0 0 16 16" fill="none" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"><path d="M4 2.5H9L12 5.5V13.5H4Z"/><polyline points="9 2.5 9 5.5 12 5.5"/></svg>';
742
+ }
743
+
744
+ /**
745
+ * A small filled dot marking an in-document section (a heading sub-item shown
746
+ * beneath the active document). currentColor + low opacity keeps it quiet.
747
+ *
748
+ * @returns {string} inline SVG HTML
749
+ */
750
+ _sectionDotSVG()
751
+ {
752
+ return '<svg class="pict-inline-doc-nav-section-dot" width="0.85em" height="0.85em" viewBox="0 0 16 16" aria-hidden="true"><circle cx="8" cy="8" r="2.3" fill="currentColor"/></svg>';
753
+ }
754
+
678
755
  /**
679
756
  * Render heading sub-items (h2 and h3) beneath the active nav item.
680
757
  *
@@ -682,13 +759,16 @@ class InlineDocumentationNavView extends libPictView
682
759
  * @param {string} pFilterText - Lowercase filter text
683
760
  * @returns {string} HTML string for heading sub-items
684
761
  */
685
- _renderHeadingSubItems(pHeadings, pFilterText)
762
+ _renderHeadingSubItems(pHeadings, pFilterText, pBaseLevel)
686
763
  {
687
764
  if (!pHeadings || pHeadings.length < 1)
688
765
  {
689
766
  return '';
690
767
  }
691
768
 
769
+ // Indent the headings relative to their (possibly nested) parent
770
+ // document item, so they line up one notch under it at any tree depth.
771
+ let tmpLevelStyle = ' style="--doc-nav-level:' + (pBaseLevel || 0) + '"';
692
772
  let tmpHTML = '';
693
773
 
694
774
  for (let i = 0; i < pHeadings.length; i++)
@@ -704,7 +784,8 @@ class InlineDocumentationNavView extends libPictView
704
784
 
705
785
  let tmpLevelClass = (tmpHeading.Level === 3) ? ' h3' : '';
706
786
  tmpHTML += '<a class="pict-inline-doc-nav-heading' + tmpLevelClass
707
- + '" data-heading-slug="' + this._escapeHTML(tmpHeading.Slug) + '">'
787
+ + '" data-heading-slug="' + this._escapeHTML(tmpHeading.Slug) + '"' + tmpLevelStyle + '>'
788
+ + this._sectionDotSVG()
708
789
  + this._escapeHTML(tmpText)
709
790
  + '</a>';
710
791
  }