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.
- package/README.md +107 -0
- package/docs/.nojekyll +0 -0
- package/docs/README.md +83 -0
- package/docs/_cover.md +15 -0
- package/docs/_sidebar.md +24 -0
- package/docs/_topbar.md +8 -0
- package/docs/_version.json +7 -0
- package/docs/api-reference.md +185 -0
- package/docs/architecture.md +103 -0
- package/docs/css/docuserve.css +327 -0
- package/docs/embedding-level1-sidebar.md +92 -0
- package/docs/embedding-level2-routes.md +86 -0
- package/docs/embedding-level3-tooltips.md +97 -0
- package/docs/embedding-level4-autogen.md +126 -0
- package/docs/index.html +39 -0
- package/docs/overview.md +42 -0
- package/docs/quickstart.md +95 -0
- package/docs/reference.md +73 -0
- package/docs/retold-catalog.json +181 -0
- package/docs/retold-keyword-index.json +4374 -0
- package/example_applications/basic/docs/README.md +40 -0
- package/example_applications/basic/docs/_sidebar.md +4 -0
- package/example_applications/basic/docs/_topics.json +10 -0
- package/example_applications/basic/docs/advanced-topics.md +47 -0
- package/example_applications/basic/docs/getting-started.md +70 -0
- package/example_applications/basic/index.html +100 -0
- package/example_applications/bookshop/.quackage.json +10 -0
- package/example_applications/bookshop/Pict-Application-Bookshop-Configuration.json +15 -0
- package/example_applications/bookshop/Pict-Application-Bookshop.js +218 -0
- package/example_applications/bookshop/data/BookshopData.json +65 -0
- package/example_applications/bookshop/data/pict_documentation_topics.json +46 -0
- package/example_applications/bookshop/docs/_sidebar.md +6 -0
- package/example_applications/bookshop/docs/book-detail.md +21 -0
- package/example_applications/bookshop/docs/book-list.md +21 -0
- package/example_applications/bookshop/docs/search-filter.md +18 -0
- package/example_applications/bookshop/docs/store.md +29 -0
- package/example_applications/bookshop/docs/welcome.md +23 -0
- package/example_applications/bookshop/html/index.html +236 -0
- package/example_applications/bookshop/package.json +34 -0
- package/example_applications/bookshop/views/PictView-Bookshop-BookList.js +324 -0
- package/example_applications/bookshop/views/PictView-Bookshop-HelpToggle.js +44 -0
- package/example_applications/bookshop/views/PictView-Bookshop-Store.js +271 -0
- package/package.json +55 -0
- package/source/Pict-Section-InlineDocumentation.js +10 -0
- package/source/providers/Pict-Provider-InlineDocumentation.js +1995 -0
- package/source/views/Pict-View-InlineDocumentation-Content.js +542 -0
- package/source/views/Pict-View-InlineDocumentation-Layout.js +206 -0
- package/source/views/Pict-View-InlineDocumentation-Nav.js +475 -0
- package/source/views/Pict-View-InlineDocumentation-TopicManager.js +1623 -0
- package/test/Browser_Integration_tests.js +1449 -0
- package/test/Pict-Section-InlineDocumentation_test.js +1285 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
# Level 4 -- Auto-Generated Tooltips for Every Editable Control
|
|
2
|
+
|
|
3
|
+
The deepest integration. Every control in your application that is managed by a [Manyfest](/utility/manyfest/) descriptor gets a tooltip automatically, with zero `data-help` markup. Missing topics are materialized as stubs on the fly. When a privileged user enters **edit mode**, they can click any tooltip to open an inline editor and write the copy right there in the running app -- no repo checkouts, no deploys.
|
|
4
|
+
|
|
5
|
+
Good for: mature products with a content-owning team that isn't going to wait for engineering to merge every typo fix.
|
|
6
|
+
|
|
7
|
+
## Prerequisites
|
|
8
|
+
|
|
9
|
+
- Levels 1-3 are in place (you don't need to have used them, but the API is shared).
|
|
10
|
+
- Your form is built from a Manyfest descriptor. Anything produced by `pict-form` or `meadow-endpoints`' schema exporter qualifies.
|
|
11
|
+
- You have an identity provider with a role that identifies "content editors".
|
|
12
|
+
- An HTTP endpoint that accepts edited topic payloads (typically `retold-content-system` or similar).
|
|
13
|
+
|
|
14
|
+
## One-Line Bootstrap
|
|
15
|
+
|
|
16
|
+
```js
|
|
17
|
+
await _Pict.views.InlineDocumentation.autoGenerateTooltipsAsync(
|
|
18
|
+
{
|
|
19
|
+
Manyfest: _Pict.providers.CustomerManyfest,
|
|
20
|
+
Scope: '#CustomerForm',
|
|
21
|
+
TopicPrefix: 'customers/',
|
|
22
|
+
EditMode: _Pict.providers.Auth.userHasRole('docs-editor'),
|
|
23
|
+
EditEndpoint: '/api/docs/topics'
|
|
24
|
+
});
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Here's what happens under the hood:
|
|
28
|
+
|
|
29
|
+
1. The generator walks every hash in `CustomerManyfest`.
|
|
30
|
+
2. For each hash `customer.email`, it computes a topic key: `customers/customer.email`.
|
|
31
|
+
3. It asks the `TopicStore` for that topic. If it exists, it binds it to the matching element (located by the Manyfest's `DataElementAddress` resolver).
|
|
32
|
+
4. If the topic does not exist, a stub is created with the hash's `Description` as the body. The stub is flagged so the UI can render it differently (e.g. dimmed or marked "needs writing").
|
|
33
|
+
5. When `EditMode` is true, every tooltip grows a tiny pencil icon. Clicking it opens an in-place editor (a textarea with a Markdown preview). Saving POSTs the content to `EditEndpoint` and updates the live corpus.
|
|
34
|
+
|
|
35
|
+
## Manyfest Descriptor Example
|
|
36
|
+
|
|
37
|
+
```js
|
|
38
|
+
{
|
|
39
|
+
Scope: 'customer',
|
|
40
|
+
Descriptors:
|
|
41
|
+
{
|
|
42
|
+
'customer.email':
|
|
43
|
+
{
|
|
44
|
+
Hash: 'customer.email',
|
|
45
|
+
DataElementAddress: 'input[name="email"]',
|
|
46
|
+
Name: 'Customer Email',
|
|
47
|
+
Description: 'Primary correspondence address',
|
|
48
|
+
DataType: 'String'
|
|
49
|
+
},
|
|
50
|
+
'customer.taxId':
|
|
51
|
+
{
|
|
52
|
+
Hash: 'customer.taxId',
|
|
53
|
+
DataElementAddress: 'input[name="taxId"]',
|
|
54
|
+
Name: 'Tax ID',
|
|
55
|
+
Description: 'Jurisdiction-specific tax identifier',
|
|
56
|
+
DataType: 'String'
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Running the generator against this produces `customers/customer.email` and `customers/customer.taxId` topics, each bound to the correct `<input>`.
|
|
63
|
+
|
|
64
|
+
## Edit Mode UX
|
|
65
|
+
|
|
66
|
+
In edit mode, the tooltip's footer shows three affordances:
|
|
67
|
+
|
|
68
|
+
- **Edit** -- opens the in-place editor
|
|
69
|
+
- **Open in docs** -- opens the topic in the sidebar for full-length editing
|
|
70
|
+
- **Revert** -- drops the in-memory edit and reloads the original
|
|
71
|
+
|
|
72
|
+
The editor renders a side-by-side Markdown preview using the same `TopicRenderer` as the reading pane, so what the editor sees is exactly what end-users will see.
|
|
73
|
+
|
|
74
|
+
## Persistence
|
|
75
|
+
|
|
76
|
+
`autoGenerateTooltipsAsync` only creates stubs *in memory*. To persist:
|
|
77
|
+
|
|
78
|
+
- The built-in editor POSTs to `EditEndpoint` with `{ TopicKey, Markdown, Frontmatter }`.
|
|
79
|
+
- Or call `exportEditedTopicsAsync()` to pull the full set of session edits and persist them in a batch.
|
|
80
|
+
|
|
81
|
+
```js
|
|
82
|
+
document.getElementById('PublishDocsButton').addEventListener('click', async () =>
|
|
83
|
+
{
|
|
84
|
+
const tmpEdits = await _Pict.views.InlineDocumentation.exportEditedTopicsAsync();
|
|
85
|
+
await fetch('/api/docs/batch',
|
|
86
|
+
{
|
|
87
|
+
method: 'POST',
|
|
88
|
+
headers: { 'content-type': 'application/json' },
|
|
89
|
+
body: JSON.stringify(tmpEdits)
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
## Multiple Scopes
|
|
95
|
+
|
|
96
|
+
A single call handles one Manyfest. Large apps call it once per form:
|
|
97
|
+
|
|
98
|
+
```js
|
|
99
|
+
await _Pict.views.InlineDocumentation.autoGenerateTooltipsAsync({ Manyfest: _Pict.providers.CustomerManyfest, Scope: '#CustomerForm', TopicPrefix: 'customers/', EditMode });
|
|
100
|
+
await _Pict.views.InlineDocumentation.autoGenerateTooltipsAsync({ Manyfest: _Pict.providers.InvoiceManyfest, Scope: '#InvoiceForm', TopicPrefix: 'invoices/', EditMode });
|
|
101
|
+
await _Pict.views.InlineDocumentation.autoGenerateTooltipsAsync({ Manyfest: _Pict.providers.ProductManyfest, Scope: '#ProductForm', TopicPrefix: 'products/', EditMode });
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
## Audit Trail
|
|
105
|
+
|
|
106
|
+
Every save emits a `topic-edited` event with the editor's identity (pulled from your auth provider) and the diff. Wire it to whatever audit store you already have:
|
|
107
|
+
|
|
108
|
+
```js
|
|
109
|
+
_Pict.views.InlineDocumentation.on('topic-edited', (pEvent) =>
|
|
110
|
+
{
|
|
111
|
+
_Pict.providers.Audit.record('docs:edit',
|
|
112
|
+
{
|
|
113
|
+
topic: pEvent.TopicKey,
|
|
114
|
+
author: pEvent.Author,
|
|
115
|
+
before: pEvent.Previous,
|
|
116
|
+
after: pEvent.Topic.Markdown
|
|
117
|
+
});
|
|
118
|
+
});
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
## Guard Rails
|
|
122
|
+
|
|
123
|
+
- Stubs are never silently promoted to "real" topics -- they must be explicitly saved.
|
|
124
|
+
- Edit mode is opt-in per page; `EditMode: false` renders regular tooltips with no editing affordances at all.
|
|
125
|
+
- `EditEndpoint` is required for persistence; omitting it means stubs stay in memory for the session only (useful for demos).
|
|
126
|
+
- All edited Markdown runs through the same safe renderer as imported content; script tags and `javascript:` URLs are stripped before display.
|
package/docs/index.html
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<html lang="en">
|
|
3
|
+
<head>
|
|
4
|
+
<meta charset="utf-8">
|
|
5
|
+
<meta http-equiv="X-UA-Compatible" content="IE=edge">
|
|
6
|
+
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
|
|
7
|
+
<meta name="description" content="pict-section-inlinedocumentation v0.0.1 Documentation — Pict embeddable inline documentation browser with topic support">
|
|
8
|
+
|
|
9
|
+
<title>pict-section-inlinedocumentation v0.0.1 Documentation</title>
|
|
10
|
+
|
|
11
|
+
<!-- Application Stylesheet -->
|
|
12
|
+
<link href="css/docuserve.css" rel="stylesheet">
|
|
13
|
+
<!-- KaTeX stylesheet for LaTeX equation rendering -->
|
|
14
|
+
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.css">
|
|
15
|
+
<!-- PICT Dynamic View CSS Container -->
|
|
16
|
+
<style id="PICT-CSS"></style>
|
|
17
|
+
|
|
18
|
+
<!-- Load the PICT library from jsDelivr CDN -->
|
|
19
|
+
<script src="https://cdn.jsdelivr.net/npm/pict@1/dist/pict.min.js" type="text/javascript"></script>
|
|
20
|
+
<!-- Bootstrap the Application -->
|
|
21
|
+
<script type="text/javascript">
|
|
22
|
+
//<![CDATA[
|
|
23
|
+
Pict.safeOnDocumentReady(() => { Pict.safeLoadPictApplication(PictDocuserve, 2)});
|
|
24
|
+
//]]>
|
|
25
|
+
</script>
|
|
26
|
+
</head>
|
|
27
|
+
<body>
|
|
28
|
+
<!-- The root container for the Pict application -->
|
|
29
|
+
<div id="Docuserve-Application-Container"></div>
|
|
30
|
+
|
|
31
|
+
<!-- Mermaid diagram rendering -->
|
|
32
|
+
<script src="https://cdn.jsdelivr.net/npm/mermaid@11/dist/mermaid.min.js"></script>
|
|
33
|
+
<script>mermaid.initialize({ startOnLoad: false, theme: 'default' });</script>
|
|
34
|
+
<!-- KaTeX for LaTeX equation rendering -->
|
|
35
|
+
<script defer src="https://cdn.jsdelivr.net/npm/katex@0.16.21/dist/katex.min.js"></script>
|
|
36
|
+
<!-- Load the Docuserve PICT Application Bundle from jsDelivr CDN -->
|
|
37
|
+
<script src="https://cdn.jsdelivr.net/npm/pict-docuserve@0/dist/pict-docuserve.min.js" type="text/javascript"></script>
|
|
38
|
+
</body>
|
|
39
|
+
</html>
|
package/docs/overview.md
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
# Overview
|
|
2
|
+
|
|
3
|
+
`pict-section-inlinedocumentation` is a Pict section -- a composable, self-contained view module -- that turns a folder of Markdown files into live, context-aware documentation inside any Pict application. It lets you go from "no help at all" to "every field has a tooltip and every screen has a help pane" without rewriting your app.
|
|
4
|
+
|
|
5
|
+
## What It Does
|
|
6
|
+
|
|
7
|
+
- Loads a corpus of Markdown topics from a URL, a static bundle, or a `pict-docuserve` catalog.
|
|
8
|
+
- Renders a sidebar with a table of contents plus a main reading pane.
|
|
9
|
+
- Maps help topics to application routes so the content updates as the user navigates.
|
|
10
|
+
- Serves tooltip content to any control that asks for it by topic key.
|
|
11
|
+
- In edit mode, generates tooltip topics dynamically for every control exposed by a Manyfest-backed content model.
|
|
12
|
+
|
|
13
|
+
## Why It Exists
|
|
14
|
+
|
|
15
|
+
Most applications bolt documentation on the side -- a separate site, a separate deploy, stale the day it ships. `pict-section-inlinedocumentation` treats docs as a runtime dependency of the UI: the same content loaded by `pict-docuserve` for your public docs site can be embedded directly in the running app, and individual topics can be addressed by fragment to power inline tooltips.
|
|
16
|
+
|
|
17
|
+
## Four Levels of Embeddedness
|
|
18
|
+
|
|
19
|
+
The module exposes four progressively deeper integration modes. You pick the level that matches how much investment you want to make.
|
|
20
|
+
|
|
21
|
+
| Level | What You Get | Effort |
|
|
22
|
+
|---|---|---|
|
|
23
|
+
| **1. Sidebar + ToC** | A collapsible pane showing all docs with a table of contents | A few lines of config |
|
|
24
|
+
| **2. Route-Mapped Content** | Help pane auto-switches to the topic for the current route | Add a route map |
|
|
25
|
+
| **3. Hand-Authored Tooltips** | Specific fields/buttons show tooltips sourced from named topics | A `data-help` attribute per control |
|
|
26
|
+
| **4. Auto-Generated Tooltips** | Every Manyfest-managed control gets a tooltip automatically, and content editors can edit them live | Wire once, author forever |
|
|
27
|
+
|
|
28
|
+
Each level is a strict superset of the one before it. You can start at level 1 and upgrade later without rewriting anything.
|
|
29
|
+
|
|
30
|
+
## What You Need
|
|
31
|
+
|
|
32
|
+
- A Pict application (`pict@^1`)
|
|
33
|
+
- A folder of Markdown files, either served statically or bundled
|
|
34
|
+
- Optionally, a `retold-catalog.json` if you want cross-module search and navigation
|
|
35
|
+
- Optionally, a Manyfest descriptor if you want level-4 auto-generation
|
|
36
|
+
|
|
37
|
+
## Relationship to Other Modules
|
|
38
|
+
|
|
39
|
+
- Uses [`pict-view`](/pict/pict-view/) as its base class.
|
|
40
|
+
- Optionally consumes catalogs produced by [`pict-docuserve`](/pict/pict-docuserve/).
|
|
41
|
+
- Uses [`manyfest`](/utility/manyfest/) descriptors to enumerate controls at level 4.
|
|
42
|
+
- Uses [`pict-template-markdown`](/pict/pict-template-markdown/) or an equivalent renderer to turn Markdown into HTML at runtime.
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
# Quickstart
|
|
2
|
+
|
|
3
|
+
Get a sidebar of documentation rendering inside your Pict application in under five minutes.
|
|
4
|
+
|
|
5
|
+
## 1. Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install pict-section-inlinedocumentation
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 2. Register the Section
|
|
12
|
+
|
|
13
|
+
In your Pict application bootstrap:
|
|
14
|
+
|
|
15
|
+
```js
|
|
16
|
+
const libPict = require('pict');
|
|
17
|
+
const libInlineDocs = require('pict-section-inlinedocumentation');
|
|
18
|
+
|
|
19
|
+
const _Pict = new libPict(
|
|
20
|
+
{
|
|
21
|
+
Product: 'My Awesome App',
|
|
22
|
+
Version: '1.0.0'
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
_Pict.addSection('InlineDocumentation', libInlineDocs,
|
|
26
|
+
{
|
|
27
|
+
DocumentationRoot: '/docs/',
|
|
28
|
+
CatalogURL: '/docs/retold-catalog.json',
|
|
29
|
+
DefaultTopic: 'overview',
|
|
30
|
+
SidebarContainer: '#AppHelpSidebar'
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
_Pict.onAfterInitializeAsync = async () =>
|
|
34
|
+
{
|
|
35
|
+
await _Pict.views.InlineDocumentation.renderAsync();
|
|
36
|
+
};
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 3. Add a Container to Your HTML
|
|
40
|
+
|
|
41
|
+
```html
|
|
42
|
+
<aside id="AppHelpSidebar"></aside>
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
Reload. You should see the topic list populated from your docs folder, with the default topic rendered on click.
|
|
46
|
+
|
|
47
|
+
## 4. (Optional) Map Content to Routes
|
|
48
|
+
|
|
49
|
+
```js
|
|
50
|
+
_Pict.addSection('InlineDocumentation', libInlineDocs,
|
|
51
|
+
{
|
|
52
|
+
DocumentationRoot: '/docs/',
|
|
53
|
+
RouteMap:
|
|
54
|
+
[
|
|
55
|
+
{ Pattern: '/records/:entity', Topic: 'records/browsing' },
|
|
56
|
+
{ Pattern: '/records/:entity/:id/edit', Topic: 'records/editing' },
|
|
57
|
+
{ Pattern: '/settings/*', Topic: 'settings' }
|
|
58
|
+
]
|
|
59
|
+
});
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
Now when the user navigates, the help pane tracks them automatically.
|
|
63
|
+
|
|
64
|
+
## 5. (Optional) Mark Up a Tooltip
|
|
65
|
+
|
|
66
|
+
```html
|
|
67
|
+
<input id="CustomerEmail" data-help="customers/email-field" />
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
```js
|
|
71
|
+
_Pict.views.InlineDocumentation.bindTooltipsAsync('#CustomerForm');
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Every element with a `data-help` attribute in the scope will get a tooltip driven by the matching topic.
|
|
75
|
+
|
|
76
|
+
## 6. (Optional) Turn On Auto-Generation
|
|
77
|
+
|
|
78
|
+
If your form is built from a Manyfest descriptor:
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
_Pict.views.InlineDocumentation.autoGenerateTooltipsAsync(
|
|
82
|
+
{
|
|
83
|
+
Manyfest: _Pict.providers.CustomerManyfest,
|
|
84
|
+
Scope: '#CustomerForm',
|
|
85
|
+
EditMode: _Pict.providers.Auth.userHasRole('docs-editor')
|
|
86
|
+
});
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
Every hash in the manifest becomes a topic key. Missing topics are created as stubs that editors can fill in from the running app.
|
|
90
|
+
|
|
91
|
+
## Next Steps
|
|
92
|
+
|
|
93
|
+
- [Architecture](#/page/architecture.md) -- how the pieces fit together
|
|
94
|
+
- [API Reference](#/page/api-reference.md) -- every exposed function with code snippets
|
|
95
|
+
- [Embedding Level 1: Sidebar](#/page/embedding-level1-sidebar.md) through [Level 4: Auto-Gen](#/page/embedding-level4-autogen.md)
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# Implementation Reference
|
|
2
|
+
|
|
3
|
+
A tour of the source tree for contributors.
|
|
4
|
+
|
|
5
|
+
## Project Layout
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
pict-section-inlinedocumentation/
|
|
9
|
+
├── package.json
|
|
10
|
+
├── source/
|
|
11
|
+
│ ├── Pict-Section-InlineDocumentation.js // Main section class
|
|
12
|
+
│ ├── services/
|
|
13
|
+
│ │ ├── TopicStore.js
|
|
14
|
+
│ │ ├── TopicRenderer.js
|
|
15
|
+
│ │ ├── TooltipBinder.js
|
|
16
|
+
│ │ └── AutoTooltipGenerator.js
|
|
17
|
+
│ ├── views/
|
|
18
|
+
│ │ ├── SidebarView.js
|
|
19
|
+
│ │ ├── ReadingPaneView.js
|
|
20
|
+
│ │ └── TooltipView.js
|
|
21
|
+
│ ├── templates/
|
|
22
|
+
│ │ ├── sidebar.tpl
|
|
23
|
+
│ │ ├── reading-pane.tpl
|
|
24
|
+
│ │ └── tooltip.tpl
|
|
25
|
+
│ └── util/
|
|
26
|
+
│ ├── routeMatch.js
|
|
27
|
+
│ └── topicKey.js
|
|
28
|
+
└── test/
|
|
29
|
+
├── TopicStore.tests.js
|
|
30
|
+
├── TooltipBinder.tests.js
|
|
31
|
+
├── AutoTooltipGenerator.tests.js
|
|
32
|
+
└── Section.tests.js
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
## Class Summary
|
|
36
|
+
|
|
37
|
+
- **`PictSectionInlineDocumentation`** extends `libPictViewClass`. Holds config, instantiates services, exposes the public API.
|
|
38
|
+
- **`TopicStore`** -- loader, cache, search.
|
|
39
|
+
- **`TopicRenderer`** -- Markdown to HTML with Pict template integration.
|
|
40
|
+
- **`TooltipBinder`** -- DOM event + observer wiring.
|
|
41
|
+
- **`AutoTooltipGenerator`** -- Manyfest walker.
|
|
42
|
+
- **`SidebarView`**, **`ReadingPaneView`**, **`TooltipView`** -- `pict-view` subclasses, one per rendered surface.
|
|
43
|
+
|
|
44
|
+
## Configuration Schema
|
|
45
|
+
|
|
46
|
+
```js
|
|
47
|
+
{
|
|
48
|
+
DocumentationRoot: String, // URL or path to markdown folder
|
|
49
|
+
CatalogURL: String, // Optional, else walk the folder
|
|
50
|
+
KeywordIndexURL: String, // Optional
|
|
51
|
+
DefaultTopic: String, // Key rendered when nothing else is selected
|
|
52
|
+
SidebarContainer: String, // CSS selector
|
|
53
|
+
ReadingPaneContainer: String, // CSS selector (optional)
|
|
54
|
+
RouteMap: Array, // Level 2
|
|
55
|
+
EditMode: Boolean, // Enables level-4 edit affordances
|
|
56
|
+
EditEndpoint: String, // POST target for edited topics
|
|
57
|
+
TooltipDelayMs: Number, // Default 400
|
|
58
|
+
TooltipPlacement: String, // 'auto' | 'top' | 'bottom' | 'left' | 'right'
|
|
59
|
+
MaxCachedTopics: Number // Default 128
|
|
60
|
+
}
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
## Testing
|
|
64
|
+
|
|
65
|
+
- Unit tests run under Mocha TDD. `TopicStore` is tested against an in-memory fetch stub; `TooltipBinder` is tested against a JSDOM environment; `AutoTooltipGenerator` uses a fixture Manyfest.
|
|
66
|
+
- Run `npm test` for the full suite, `npx mocha -u tdd test/TopicStore.tests.js` for a single file.
|
|
67
|
+
- Coverage via `npm run coverage`.
|
|
68
|
+
|
|
69
|
+
## Extending
|
|
70
|
+
|
|
71
|
+
- **Custom renderers** -- subclass `TopicRenderer` and set `RendererClass` in config.
|
|
72
|
+
- **Custom tooltip UI** -- subclass `TooltipView`; set `TooltipViewClass` in config.
|
|
73
|
+
- **Alternate storage** -- implement the `TopicStore` interface (`loadCatalogAsync`, `loadTopicAsync`, `searchAsync`) and pass it as `TopicStoreInstance`.
|
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
{
|
|
2
|
+
"Generated": "2026-04-10T17:25:27.303Z",
|
|
3
|
+
"GitHubOrg": "stevenvelozo",
|
|
4
|
+
"DefaultBranch": "master",
|
|
5
|
+
"Groups": [
|
|
6
|
+
{
|
|
7
|
+
"Name": "Dist",
|
|
8
|
+
"Key": "dist",
|
|
9
|
+
"Description": "",
|
|
10
|
+
"Modules": [
|
|
11
|
+
{
|
|
12
|
+
"Name": "indoctrinate_content_staging",
|
|
13
|
+
"Repo": "indoctrinate_content_staging",
|
|
14
|
+
"Group": "dist",
|
|
15
|
+
"Branch": "master",
|
|
16
|
+
"HasDocs": false,
|
|
17
|
+
"HasCover": false,
|
|
18
|
+
"Sidebar": [],
|
|
19
|
+
"DocFiles": []
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"Name": "test-artifacts",
|
|
23
|
+
"Repo": "test-artifacts",
|
|
24
|
+
"Group": "dist",
|
|
25
|
+
"Branch": "master",
|
|
26
|
+
"HasDocs": false,
|
|
27
|
+
"HasCover": false,
|
|
28
|
+
"Sidebar": [],
|
|
29
|
+
"DocFiles": []
|
|
30
|
+
}
|
|
31
|
+
]
|
|
32
|
+
},
|
|
33
|
+
{
|
|
34
|
+
"Name": "Docs",
|
|
35
|
+
"Key": "docs",
|
|
36
|
+
"Description": "",
|
|
37
|
+
"Modules": [
|
|
38
|
+
{
|
|
39
|
+
"Name": "css",
|
|
40
|
+
"Repo": "css",
|
|
41
|
+
"Group": "docs",
|
|
42
|
+
"Branch": "master",
|
|
43
|
+
"HasDocs": true,
|
|
44
|
+
"HasCover": false,
|
|
45
|
+
"Sidebar": [],
|
|
46
|
+
"DocFiles": [
|
|
47
|
+
"css/docuserve.css"
|
|
48
|
+
]
|
|
49
|
+
}
|
|
50
|
+
]
|
|
51
|
+
},
|
|
52
|
+
{
|
|
53
|
+
"Name": "Example_applications",
|
|
54
|
+
"Key": "example_applications",
|
|
55
|
+
"Description": "",
|
|
56
|
+
"Modules": [
|
|
57
|
+
{
|
|
58
|
+
"Name": ".data",
|
|
59
|
+
"Repo": ".data",
|
|
60
|
+
"Group": "example_applications",
|
|
61
|
+
"Branch": "master",
|
|
62
|
+
"HasDocs": false,
|
|
63
|
+
"HasCover": false,
|
|
64
|
+
"Sidebar": [],
|
|
65
|
+
"DocFiles": []
|
|
66
|
+
},
|
|
67
|
+
{
|
|
68
|
+
"Name": "basic",
|
|
69
|
+
"Repo": "basic",
|
|
70
|
+
"Group": "example_applications",
|
|
71
|
+
"Branch": "master",
|
|
72
|
+
"HasDocs": true,
|
|
73
|
+
"HasCover": false,
|
|
74
|
+
"Sidebar": [
|
|
75
|
+
{
|
|
76
|
+
"Title": "Home",
|
|
77
|
+
"Path": "README.md"
|
|
78
|
+
},
|
|
79
|
+
{
|
|
80
|
+
"Title": "Guide",
|
|
81
|
+
"Children": [
|
|
82
|
+
{
|
|
83
|
+
"Title": "Getting Started",
|
|
84
|
+
"Path": "getting-started.md"
|
|
85
|
+
},
|
|
86
|
+
{
|
|
87
|
+
"Title": "Advanced Topics",
|
|
88
|
+
"Path": "advanced-topics.md"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
}
|
|
92
|
+
],
|
|
93
|
+
"DocFiles": [
|
|
94
|
+
"README.md",
|
|
95
|
+
"_sidebar.md",
|
|
96
|
+
"_topics.json",
|
|
97
|
+
"advanced-topics.md",
|
|
98
|
+
"getting-started.md"
|
|
99
|
+
]
|
|
100
|
+
},
|
|
101
|
+
{
|
|
102
|
+
"Name": "bookshop",
|
|
103
|
+
"Repo": "bookshop",
|
|
104
|
+
"Group": "example_applications",
|
|
105
|
+
"Branch": "master",
|
|
106
|
+
"HasDocs": true,
|
|
107
|
+
"HasCover": false,
|
|
108
|
+
"Sidebar": [
|
|
109
|
+
{
|
|
110
|
+
"Title": "Welcome",
|
|
111
|
+
"Path": "welcome.md"
|
|
112
|
+
},
|
|
113
|
+
{
|
|
114
|
+
"Title": "Using the Bookshop",
|
|
115
|
+
"Children": [
|
|
116
|
+
{
|
|
117
|
+
"Title": "Book Catalog",
|
|
118
|
+
"Path": "book-list.md"
|
|
119
|
+
},
|
|
120
|
+
{
|
|
121
|
+
"Title": "Book Details",
|
|
122
|
+
"Path": "book-detail.md"
|
|
123
|
+
},
|
|
124
|
+
{
|
|
125
|
+
"Title": "Store Page",
|
|
126
|
+
"Path": "store.md"
|
|
127
|
+
},
|
|
128
|
+
{
|
|
129
|
+
"Title": "Search & Filter",
|
|
130
|
+
"Path": "search-filter.md"
|
|
131
|
+
}
|
|
132
|
+
]
|
|
133
|
+
}
|
|
134
|
+
],
|
|
135
|
+
"DocFiles": [
|
|
136
|
+
"_sidebar.md",
|
|
137
|
+
"book-detail.md",
|
|
138
|
+
"book-list.md",
|
|
139
|
+
"pict_documentation_topics.json",
|
|
140
|
+
"search-filter.md",
|
|
141
|
+
"store.md",
|
|
142
|
+
"welcome.md",
|
|
143
|
+
"_sidebar.md",
|
|
144
|
+
"book-detail.md",
|
|
145
|
+
"book-list.md",
|
|
146
|
+
"search-filter.md",
|
|
147
|
+
"store.md",
|
|
148
|
+
"welcome.md"
|
|
149
|
+
]
|
|
150
|
+
}
|
|
151
|
+
]
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
"Name": "Source",
|
|
155
|
+
"Key": "source",
|
|
156
|
+
"Description": "",
|
|
157
|
+
"Modules": [
|
|
158
|
+
{
|
|
159
|
+
"Name": "providers",
|
|
160
|
+
"Repo": "providers",
|
|
161
|
+
"Group": "source",
|
|
162
|
+
"Branch": "master",
|
|
163
|
+
"HasDocs": false,
|
|
164
|
+
"HasCover": false,
|
|
165
|
+
"Sidebar": [],
|
|
166
|
+
"DocFiles": []
|
|
167
|
+
},
|
|
168
|
+
{
|
|
169
|
+
"Name": "views",
|
|
170
|
+
"Repo": "views",
|
|
171
|
+
"Group": "source",
|
|
172
|
+
"Branch": "master",
|
|
173
|
+
"HasDocs": false,
|
|
174
|
+
"HasCover": false,
|
|
175
|
+
"Sidebar": [],
|
|
176
|
+
"DocFiles": []
|
|
177
|
+
}
|
|
178
|
+
]
|
|
179
|
+
}
|
|
180
|
+
]
|
|
181
|
+
}
|