pict-section-inlinedocumentation 0.0.1

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 (51) hide show
  1. package/README.md +107 -0
  2. package/docs/.nojekyll +0 -0
  3. package/docs/README.md +83 -0
  4. package/docs/_cover.md +15 -0
  5. package/docs/_sidebar.md +24 -0
  6. package/docs/_topbar.md +8 -0
  7. package/docs/_version.json +7 -0
  8. package/docs/api-reference.md +185 -0
  9. package/docs/architecture.md +103 -0
  10. package/docs/css/docuserve.css +327 -0
  11. package/docs/embedding-level1-sidebar.md +92 -0
  12. package/docs/embedding-level2-routes.md +86 -0
  13. package/docs/embedding-level3-tooltips.md +97 -0
  14. package/docs/embedding-level4-autogen.md +126 -0
  15. package/docs/index.html +39 -0
  16. package/docs/overview.md +42 -0
  17. package/docs/quickstart.md +95 -0
  18. package/docs/reference.md +73 -0
  19. package/docs/retold-catalog.json +181 -0
  20. package/docs/retold-keyword-index.json +4374 -0
  21. package/example_applications/basic/docs/README.md +40 -0
  22. package/example_applications/basic/docs/_sidebar.md +4 -0
  23. package/example_applications/basic/docs/_topics.json +10 -0
  24. package/example_applications/basic/docs/advanced-topics.md +47 -0
  25. package/example_applications/basic/docs/getting-started.md +70 -0
  26. package/example_applications/basic/index.html +100 -0
  27. package/example_applications/bookshop/.quackage.json +10 -0
  28. package/example_applications/bookshop/Pict-Application-Bookshop-Configuration.json +15 -0
  29. package/example_applications/bookshop/Pict-Application-Bookshop.js +218 -0
  30. package/example_applications/bookshop/data/BookshopData.json +65 -0
  31. package/example_applications/bookshop/data/pict_documentation_topics.json +46 -0
  32. package/example_applications/bookshop/docs/_sidebar.md +6 -0
  33. package/example_applications/bookshop/docs/book-detail.md +21 -0
  34. package/example_applications/bookshop/docs/book-list.md +21 -0
  35. package/example_applications/bookshop/docs/search-filter.md +18 -0
  36. package/example_applications/bookshop/docs/store.md +29 -0
  37. package/example_applications/bookshop/docs/welcome.md +23 -0
  38. package/example_applications/bookshop/html/index.html +236 -0
  39. package/example_applications/bookshop/package.json +34 -0
  40. package/example_applications/bookshop/views/PictView-Bookshop-BookList.js +324 -0
  41. package/example_applications/bookshop/views/PictView-Bookshop-HelpToggle.js +44 -0
  42. package/example_applications/bookshop/views/PictView-Bookshop-Store.js +271 -0
  43. package/package.json +55 -0
  44. package/source/Pict-Section-InlineDocumentation.js +10 -0
  45. package/source/providers/Pict-Provider-InlineDocumentation.js +1995 -0
  46. package/source/views/Pict-View-InlineDocumentation-Content.js +542 -0
  47. package/source/views/Pict-View-InlineDocumentation-Layout.js +206 -0
  48. package/source/views/Pict-View-InlineDocumentation-Nav.js +475 -0
  49. package/source/views/Pict-View-InlineDocumentation-TopicManager.js +1623 -0
  50. package/test/Browser_Integration_tests.js +1449 -0
  51. package/test/Pict-Section-InlineDocumentation_test.js +1285 -0
@@ -0,0 +1,542 @@
1
+ const libPictContentView = require('pict-section-content');
2
+
3
+ const _ViewConfiguration =
4
+ {
5
+ ViewIdentifier: "InlineDoc-Content",
6
+
7
+ DefaultRenderable: "InlineDoc-Content-Display",
8
+ DefaultDestinationAddress: "#InlineDoc-Content-Container",
9
+
10
+ AutoRender: false,
11
+
12
+ CSS: /*css*/`
13
+ .pict-inline-doc-content {
14
+ padding: 1em 1.25em;
15
+ max-width: 100%;
16
+ word-wrap: break-word;
17
+ overflow-wrap: break-word;
18
+ }
19
+ .pict-inline-doc-content-loading {
20
+ display: flex;
21
+ align-items: center;
22
+ justify-content: center;
23
+ min-height: 150px;
24
+ color: #8A7F72;
25
+ font-size: 0.95em;
26
+ }
27
+ .pict-inline-doc-content h1 {
28
+ font-size: 1.75em;
29
+ color: #3D3229;
30
+ border-bottom: 1px solid #DDD6CA;
31
+ padding-bottom: 0.3em;
32
+ margin-top: 0;
33
+ }
34
+ .pict-inline-doc-content h2 {
35
+ font-size: 1.35em;
36
+ color: #3D3229;
37
+ border-bottom: 1px solid #EAE3D8;
38
+ padding-bottom: 0.2em;
39
+ margin-top: 1.25em;
40
+ }
41
+ .pict-inline-doc-content h3 {
42
+ font-size: 1.15em;
43
+ color: #3D3229;
44
+ margin-top: 1em;
45
+ }
46
+ .pict-inline-doc-content h4, .pict-inline-doc-content h5, .pict-inline-doc-content h6 {
47
+ color: #5E5549;
48
+ margin-top: 0.8em;
49
+ }
50
+ .pict-inline-doc-content p {
51
+ line-height: 1.65;
52
+ color: #423D37;
53
+ margin: 0.6em 0;
54
+ }
55
+ .pict-inline-doc-content a {
56
+ color: #2E7D74;
57
+ text-decoration: none;
58
+ cursor: pointer;
59
+ }
60
+ .pict-inline-doc-content a:hover {
61
+ text-decoration: underline;
62
+ }
63
+ .pict-inline-doc-content pre {
64
+ background: #3D3229;
65
+ color: #E8E0D4;
66
+ padding: 1em;
67
+ border-radius: 5px;
68
+ overflow-x: auto;
69
+ line-height: 1.5;
70
+ font-size: 0.85em;
71
+ max-width: 100%;
72
+ }
73
+ .pict-inline-doc-content code {
74
+ background: #F0ECE4;
75
+ padding: 0.15em 0.35em;
76
+ border-radius: 3px;
77
+ font-size: 0.85em;
78
+ color: #9E6B47;
79
+ }
80
+ .pict-inline-doc-content pre code {
81
+ background: none;
82
+ padding: 0;
83
+ color: inherit;
84
+ font-size: inherit;
85
+ }
86
+ .pict-inline-doc-content blockquote {
87
+ border-left: 3px solid #2E7D74;
88
+ margin: 0.8em 0;
89
+ padding: 0.4em 0.8em;
90
+ background: #F7F5F0;
91
+ color: #5E5549;
92
+ }
93
+ .pict-inline-doc-content blockquote p {
94
+ margin: 0.2em 0;
95
+ }
96
+ .pict-inline-doc-content ul, .pict-inline-doc-content ol {
97
+ padding-left: 1.8em;
98
+ line-height: 1.7;
99
+ }
100
+ .pict-inline-doc-content li {
101
+ margin: 0.2em 0;
102
+ color: #423D37;
103
+ }
104
+ .pict-inline-doc-content hr {
105
+ border: none;
106
+ border-top: 1px solid #DDD6CA;
107
+ margin: 1.5em 0;
108
+ }
109
+ .pict-inline-doc-content table {
110
+ width: 100%;
111
+ border-collapse: collapse;
112
+ margin: 0.8em 0;
113
+ display: block;
114
+ overflow-x: auto;
115
+ }
116
+ .pict-inline-doc-content table th {
117
+ background: #F5F0E8;
118
+ border: 1px solid #DDD6CA;
119
+ padding: 0.5em 0.7em;
120
+ text-align: left;
121
+ font-weight: 600;
122
+ color: #3D3229;
123
+ }
124
+ .pict-inline-doc-content table td {
125
+ border: 1px solid #DDD6CA;
126
+ padding: 0.4em 0.7em;
127
+ color: #423D37;
128
+ }
129
+ .pict-inline-doc-content table tr:nth-child(even) {
130
+ background: #F7F5F0;
131
+ }
132
+ .pict-inline-doc-content img {
133
+ max-width: 100%;
134
+ height: auto;
135
+ }
136
+ .pict-inline-doc-not-found {
137
+ text-align: center;
138
+ padding: 2em 1em;
139
+ color: #5E5549;
140
+ }
141
+ .pict-inline-doc-not-found h2 {
142
+ color: #8A7F72;
143
+ font-size: 1.3em;
144
+ border-bottom: none;
145
+ }
146
+ .pict-inline-doc-not-found code {
147
+ background: #F0ECE4;
148
+ padding: 0.15em 0.35em;
149
+ border-radius: 3px;
150
+ font-size: 0.85em;
151
+ color: #9E6B47;
152
+ }
153
+ .pict-inline-doc-edit-toolbar {
154
+ display: none;
155
+ align-items: center;
156
+ gap: 0.4em;
157
+ padding: 0.4em 0.6em;
158
+ margin-bottom: 0.5em;
159
+ background: #F5F0E8;
160
+ border: 1px solid #E5DED4;
161
+ border-radius: 4px;
162
+ font-size: 0.8em;
163
+ }
164
+ .pict-inline-doc-edit-toolbar.visible {
165
+ display: flex;
166
+ }
167
+ .pict-inline-doc-edit-toolbar .edit-label {
168
+ color: #8A7F72;
169
+ margin-right: auto;
170
+ }
171
+ .pict-inline-doc-edit-btn {
172
+ display: inline-flex;
173
+ align-items: center;
174
+ justify-content: center;
175
+ padding: 0.25em 0.6em;
176
+ border: 1px solid #D4A373;
177
+ border-radius: 3px;
178
+ background: #fff;
179
+ color: #5E5549;
180
+ font-size: 0.9em;
181
+ cursor: pointer;
182
+ transition: background 0.1s;
183
+ }
184
+ .pict-inline-doc-edit-btn:hover {
185
+ background: #F0ECE4;
186
+ }
187
+ .pict-inline-doc-edit-btn.primary {
188
+ background: #2E7D74;
189
+ color: #fff;
190
+ border-color: #2E7D74;
191
+ }
192
+ .pict-inline-doc-edit-btn.primary:hover {
193
+ background: #266D65;
194
+ }
195
+ .pict-inline-doc-edit-btn .btn-icon {
196
+ margin-right: 0.3em;
197
+ }
198
+ #InlineDoc-Editor-Container {
199
+ min-height: 300px;
200
+ }
201
+ /* Tooltip placeholder: edit mode indicators */
202
+ [data-d-tooltip].pict-inline-doc-tooltip-edit-target {
203
+ outline: 1px dashed #2E7D74;
204
+ outline-offset: 2px;
205
+ cursor: pointer;
206
+ position: relative;
207
+ }
208
+ [data-d-tooltip].pict-inline-doc-tooltip-edit-target:not([data-d-tooltip-icon])::after {
209
+ content: '?';
210
+ position: absolute;
211
+ top: -6px;
212
+ right: -6px;
213
+ width: 14px;
214
+ height: 14px;
215
+ background: #2E7D74;
216
+ color: #fff;
217
+ border-radius: 50%;
218
+ font-size: 9px;
219
+ line-height: 14px;
220
+ text-align: center;
221
+ font-weight: 700;
222
+ pointer-events: none;
223
+ }
224
+ /* Tooltip placeholder: default icon */
225
+ .pict-inline-doc-tooltip-icon {
226
+ display: inline-flex;
227
+ align-items: center;
228
+ justify-content: center;
229
+ width: 16px;
230
+ height: 16px;
231
+ font-size: 12px;
232
+ color: #2E7D74;
233
+ cursor: pointer;
234
+ vertical-align: middle;
235
+ }
236
+ /* Empty icon tooltip in edit mode */
237
+ .pict-inline-doc-tooltip-empty .pict-inline-doc-tooltip-icon {
238
+ opacity: 0.4;
239
+ outline: 1px dashed #8A7F72;
240
+ outline-offset: 1px;
241
+ border-radius: 50%;
242
+ }
243
+ /* Tooltip editor textarea in modal */
244
+ .pict-inline-doc-tooltip-editor-textarea {
245
+ width: 100%;
246
+ min-height: 120px;
247
+ padding: 0.6em;
248
+ font-family: 'SFMono-Regular', 'SF Mono', 'Menlo', 'Consolas', monospace;
249
+ font-size: 0.85em;
250
+ line-height: 1.5;
251
+ color: #3D3229;
252
+ background: #FDFCFA;
253
+ border: 1px solid #DDD6CA;
254
+ border-radius: 4px;
255
+ resize: vertical;
256
+ box-sizing: border-box;
257
+ }
258
+ .pict-inline-doc-tooltip-editor-textarea:focus {
259
+ outline: none;
260
+ border-color: #2E7D74;
261
+ box-shadow: 0 0 0 2px rgba(46, 125, 116, 0.15);
262
+ }
263
+ .pict-inline-doc-tooltip-preview {
264
+ margin-top: 0.5em;
265
+ padding: 0.5em 0.7em;
266
+ background: #F5F0E8;
267
+ border: 1px solid #E5DED4;
268
+ border-radius: 4px;
269
+ font-size: 0.9em;
270
+ min-height: 2em;
271
+ color: #3D3229;
272
+ }
273
+ .pict-inline-doc-tooltip-preview-label {
274
+ font-size: 0.75em;
275
+ color: #8A7F72;
276
+ text-transform: uppercase;
277
+ letter-spacing: 0.03em;
278
+ margin-bottom: 0.3em;
279
+ }
280
+ `,
281
+
282
+ Templates:
283
+ [
284
+ {
285
+ Hash: "InlineDoc-Content-Template",
286
+ Template: /*html*/`
287
+ <div class="pict-inline-doc-edit-toolbar" id="InlineDoc-Edit-Toolbar">
288
+ <span class="edit-label" id="InlineDoc-Edit-Label">View mode</span>
289
+ <button class="pict-inline-doc-edit-btn" id="InlineDoc-Edit-Toggle" title="Edit this document"><span class="btn-icon">&#x270E;</span> Edit</button>
290
+ <button class="pict-inline-doc-edit-btn primary" id="InlineDoc-Edit-Save" style="display:none"><span class="btn-icon">&#x2713;</span> Save</button>
291
+ <button class="pict-inline-doc-edit-btn" id="InlineDoc-Edit-Cancel" style="display:none"><span class="btn-icon">&#x2717;</span> Cancel</button>
292
+ </div>
293
+ <div class="pict-inline-doc-content pict-content" id="InlineDoc-Content-Body">
294
+ <div class="pict-inline-doc-content-loading">Loading...</div>
295
+ </div>
296
+ `
297
+ }
298
+ ],
299
+
300
+ Renderables:
301
+ [
302
+ {
303
+ RenderableHash: "InlineDoc-Content-Display",
304
+ TemplateHash: "InlineDoc-Content-Template",
305
+ DestinationAddress: "#InlineDoc-Content-Container",
306
+ RenderMethod: "replace"
307
+ }
308
+ ]
309
+ };
310
+
311
+ class InlineDocumentationContentView extends libPictContentView
312
+ {
313
+ constructor(pFable, pOptions, pServiceHash)
314
+ {
315
+ super(pFable, pOptions, pServiceHash);
316
+ }
317
+
318
+ onAfterRender()
319
+ {
320
+ this.renderEditToolbar();
321
+ return super.onAfterRender();
322
+ }
323
+
324
+ /**
325
+ * Display parsed HTML content in the content area.
326
+ *
327
+ * @param {string} pHTMLContent - The HTML to display
328
+ */
329
+ displayContent(pHTMLContent)
330
+ {
331
+ super.displayContent(pHTMLContent, 'InlineDoc-Content-Body');
332
+
333
+ // Wire up click interception for internal doc links
334
+ this._wireInternalLinks();
335
+
336
+ // Update the edit toolbar state
337
+ this.renderEditToolbar();
338
+ }
339
+
340
+ /**
341
+ * Show a loading indicator.
342
+ */
343
+ showLoading()
344
+ {
345
+ super.showLoading('Loading...', 'InlineDoc-Content-Body');
346
+ }
347
+
348
+ /**
349
+ * Show or hide the edit toolbar based on EditEnabled state.
350
+ */
351
+ renderEditToolbar()
352
+ {
353
+ if (typeof document === 'undefined')
354
+ {
355
+ return;
356
+ }
357
+
358
+ let tmpToolbar = document.getElementById('InlineDoc-Edit-Toolbar');
359
+ if (!tmpToolbar)
360
+ {
361
+ return;
362
+ }
363
+
364
+ let tmpState = this.pict.AppData.InlineDocumentation;
365
+ if (!tmpState)
366
+ {
367
+ return;
368
+ }
369
+
370
+ if (tmpState.EditEnabled && tmpState.CurrentPath)
371
+ {
372
+ tmpToolbar.classList.add('visible');
373
+ }
374
+ else
375
+ {
376
+ tmpToolbar.classList.remove('visible');
377
+ }
378
+
379
+ // Update button visibility based on editing state
380
+ let tmpToggleBtn = document.getElementById('InlineDoc-Edit-Toggle');
381
+ let tmpSaveBtn = document.getElementById('InlineDoc-Edit-Save');
382
+ let tmpCancelBtn = document.getElementById('InlineDoc-Edit-Cancel');
383
+ let tmpLabel = document.getElementById('InlineDoc-Edit-Label');
384
+
385
+ if (tmpState.Editing)
386
+ {
387
+ if (tmpToggleBtn) { tmpToggleBtn.style.display = 'none'; }
388
+ if (tmpSaveBtn) { tmpSaveBtn.style.display = ''; }
389
+ if (tmpCancelBtn) { tmpCancelBtn.style.display = ''; }
390
+ if (tmpLabel) { tmpLabel.textContent = 'Editing: ' + (tmpState.EditingPath || ''); }
391
+ }
392
+ else
393
+ {
394
+ if (tmpToggleBtn) { tmpToggleBtn.style.display = ''; }
395
+ if (tmpSaveBtn) { tmpSaveBtn.style.display = 'none'; }
396
+ if (tmpCancelBtn) { tmpCancelBtn.style.display = 'none'; }
397
+ if (tmpLabel) { tmpLabel.textContent = tmpState.CurrentPath || 'View mode'; }
398
+ }
399
+
400
+ // Re-wire click handlers (DOM may have been recreated by render)
401
+ this._wireEditToolbar();
402
+ }
403
+
404
+ /**
405
+ * Show the markdown editor with the raw markdown content.
406
+ *
407
+ * @param {string} pMarkdown - The raw markdown to edit
408
+ */
409
+ showEditor(pMarkdown)
410
+ {
411
+ if (typeof document === 'undefined')
412
+ {
413
+ return;
414
+ }
415
+
416
+ let tmpContainer = document.getElementById('InlineDoc-Content-Body');
417
+ if (!tmpContainer)
418
+ {
419
+ return;
420
+ }
421
+
422
+ // Create a container for the markdown editor view to render into
423
+ tmpContainer.innerHTML = '<div id="InlineDoc-Editor-Container"></div>';
424
+
425
+ // Set up the editor segments data for the markdown editor
426
+ if (!this.pict.AppData.InlineDocumentation)
427
+ {
428
+ this.pict.AppData.InlineDocumentation = {};
429
+ }
430
+ this.pict.AppData.InlineDocumentation.EditorSegments = [{ Content: pMarkdown || '' }];
431
+
432
+ // Render the markdown editor view into the container
433
+ let tmpEditorView = this.pict.views['InlineDoc-MarkdownEditor'];
434
+ if (tmpEditorView)
435
+ {
436
+ tmpEditorView.render();
437
+ }
438
+
439
+ this.renderEditToolbar();
440
+ }
441
+
442
+ /**
443
+ * Hide the textarea editor.
444
+ */
445
+ hideEditor()
446
+ {
447
+ // The editor will be replaced by displayContent, but update toolbar state
448
+ this.renderEditToolbar();
449
+ }
450
+
451
+ /**
452
+ * Wire click handlers for the edit toolbar buttons.
453
+ */
454
+ _wireEditToolbar()
455
+ {
456
+ if (typeof document === 'undefined')
457
+ {
458
+ return;
459
+ }
460
+
461
+ let tmpProvider = this.pict.providers['Pict-InlineDocumentation'];
462
+
463
+ let tmpToggleBtn = document.getElementById('InlineDoc-Edit-Toggle');
464
+ if (tmpToggleBtn)
465
+ {
466
+ tmpToggleBtn.addEventListener('click', () =>
467
+ {
468
+ if (tmpProvider)
469
+ {
470
+ tmpProvider.beginEdit();
471
+ }
472
+ });
473
+ }
474
+
475
+ let tmpSaveBtn = document.getElementById('InlineDoc-Edit-Save');
476
+ if (tmpSaveBtn)
477
+ {
478
+ tmpSaveBtn.addEventListener('click', () =>
479
+ {
480
+ if (tmpProvider)
481
+ {
482
+ tmpProvider.saveEdit();
483
+ }
484
+ });
485
+ }
486
+
487
+ let tmpCancelBtn = document.getElementById('InlineDoc-Edit-Cancel');
488
+ if (tmpCancelBtn)
489
+ {
490
+ tmpCancelBtn.addEventListener('click', () =>
491
+ {
492
+ if (tmpProvider)
493
+ {
494
+ tmpProvider.cancelEdit();
495
+ }
496
+ });
497
+ }
498
+ }
499
+
500
+ /**
501
+ * Wire click handlers on internal documentation links.
502
+ *
503
+ * Links with rel="pict-inline-doc-link:path" are intercepted and
504
+ * routed through the provider's loadDocument() method.
505
+ */
506
+ _wireInternalLinks()
507
+ {
508
+ if (typeof document === 'undefined')
509
+ {
510
+ return;
511
+ }
512
+
513
+ let tmpContainer = document.getElementById('InlineDoc-Content-Body');
514
+ if (!tmpContainer)
515
+ {
516
+ return;
517
+ }
518
+
519
+ let tmpLinks = tmpContainer.querySelectorAll('a[rel^="pict-inline-doc-link:"]');
520
+ let tmpProvider = this.pict.providers['Pict-InlineDocumentation'];
521
+
522
+ for (let i = 0; i < tmpLinks.length; i++)
523
+ {
524
+ let tmpLink = tmpLinks[i];
525
+ let tmpRel = tmpLink.getAttribute('rel');
526
+ let tmpPath = tmpRel.replace('pict-inline-doc-link:', '');
527
+
528
+ tmpLink.addEventListener('click', (pEvent) =>
529
+ {
530
+ pEvent.preventDefault();
531
+ if (tmpProvider)
532
+ {
533
+ tmpProvider.loadDocument(tmpPath);
534
+ }
535
+ });
536
+ }
537
+ }
538
+ }
539
+
540
+ module.exports = InlineDocumentationContentView;
541
+
542
+ module.exports.default_configuration = _ViewConfiguration;