@masmarino/gabarit 1.3.0 → 1.4.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/README.md CHANGED
@@ -135,6 +135,12 @@ but plain, without the layout the directive provides.
135
135
  | `MenuTrigger` | `[gbtMenuTrigger]` | `gbt-menu`: a custom trigger element instead of the default button. |
136
136
  | `StatTileLink` | `a[gbtStatTileLink]` | `gbt-stat-tile`: the router-agnostic link, its text is the label. |
137
137
 
138
+ ## Documentation reader
139
+
140
+ `@masmarino/gabarit/docs` is a reader for documentation written in Markdown and shipped with an app (navigation,
141
+ search, outline, neighbours), with `gbt-markdown-view` for Markdown anywhere else. It is a separate entry point
142
+ because it needs `@angular/router`, `marked` and `dompurify`; see [its README](docs/README.md).
143
+
138
144
  ## Primitives and pipes
139
145
 
140
146
  Pure functions exported from `@masmarino/gabarit`, usable in any TypeScript
package/docs/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # @masmarino/gabarit/docs
2
+
3
+ A reader for documentation written in Markdown and shipped with an app: a navigation with search on the left, the page
4
+ with its breadcrumb and neighbours, and its outline on a wide screen. It is its own entry point because it needs
5
+ `@angular/router`, [marked](https://marked.js.org) and [DOMPurify](https://github.com/cure53/DOMPurify), which the rest
6
+ of Gabarit does not; install them next to Gabarit:
7
+
8
+ ```sh
9
+ npm install marked dompurify
10
+ ```
11
+
12
+ ## The pages
13
+
14
+ The app serves the documentation as static files under a root (`/docs` by default), for instance from its `public/`
15
+ folder:
16
+
17
+ ```
18
+ public/docs/
19
+ index.json # the sections and their pages, in reading order
20
+ demarrer/presentation.md # one Markdown file per page: <section>/<page>.md
21
+ demarrer/prise-en-main.md
22
+ ```
23
+
24
+ ```json
25
+ {
26
+ "sections": [
27
+ {
28
+ "slug": "demarrer",
29
+ "title": "Démarrer",
30
+ "pages": [
31
+ { "slug": "presentation", "title": "Présentation", "description": "What the app does." }
32
+ ]
33
+ }
34
+ ]
35
+ }
36
+ ```
37
+
38
+ The index and each page are fetched once and kept. A page links to another with a root-relative link
39
+ (`[Configuration](/docs/installation/configuration#variables)`): the reader follows it through the router. A quote
40
+ whose first word is a bold callout key becomes a callout: `> **Note** …` (and `> **Warning** …` by default).
41
+
42
+ ## Wiring
43
+
44
+ ```ts
45
+ // app.routes.ts
46
+ import { docsRoutes } from '@masmarino/gabarit/docs'
47
+
48
+ export const routes: Routes = [
49
+ {
50
+ path: 'docs',
51
+ // The app's own page around the reader (its layout, its header), or DocsPage itself.
52
+ children: docsRoutes(() => import('./docs/docs-route').then((m) => m.DocsRoute)),
53
+ },
54
+ ]
55
+ ```
56
+
57
+ ```ts
58
+ // docs-route.ts: the reader inside the app's layout
59
+ @Component({
60
+ imports: [AppLayout, DocsPage],
61
+ providers: [
62
+ provideDocs({ callouts: { note: 'note', attention: 'warning' } }),
63
+ provideDocsLabels(FRENCH_DOCS_LABELS),
64
+ { provide: DOCS_TITLE, useFactory: () => (title: string) => inject(Title).setTitle(title) },
65
+ ],
66
+ template: `<app-layout><gbt-docs-page /></app-layout>`,
67
+ })
68
+ export class DocsRoute {}
69
+ ```
70
+
71
+ `docsRoutes()` sends the root to the first page, mounts `<section>/<page>`, and gives any other address the reader's
72
+ own "not found". `gbt-docs-page` reads the section and the page from the route.
73
+
74
+ ## Providers
75
+
76
+ | Token | Role |
77
+ | --------------------- | ------------------------------------------------------------------------------------------------------ |
78
+ | `provideDocs(config)` | `root` (`/docs`) and the `callouts` keys (`note`, `warning`). |
79
+ | `provideDocsLabels()` | The reader's strings, over the English defaults (`DEFAULT_DOCS_LABELS`). |
80
+ | `DOCS_TITLE` | A function given the shown page's title (or "not found", or the reader's name while loading). Optional. |
81
+
82
+ ## Pieces
83
+
84
+ | Piece | Role |
85
+ | ---------------------- | -------------------------------------------------------------------------------------------------------- |
86
+ | `gbt-docs-page` | The whole reader for the routed page: navigation, page, neighbours, outline, loading, failure, not found. |
87
+ | `gbt-docs-nav` | The sections and their pages, with the search; folds behind a toggle on a narrow layout. |
88
+ | `gbt-docs-search` | A search over every page, in the browser, loaded on first focus. |
89
+ | `gbt-markdown-view` | Markdown to sanitised HTML, with the reading styles; usable on its own (a README, release notes). |
90
+ | `gbt-markdown-outline` | The "On this page" panel for the headings a `gbt-markdown-view` emits. |
91
+
92
+ ## Security
93
+
94
+ The Markdown is sanitised with a dedicated DOMPurify instance, stricter than its defaults: no `<style>`, no `style`
95
+ attribute, no forms or buttons, no IDREFs or `tabindex`, ids and names prefixed with `user-content-`, only the
96
+ `language-*` classes of code blocks kept, task-list checkboxes disabled, remote images lazy and without a referrer.
97
+
98
+ ## Accessibility
99
+
100
+ Every heading gets a stable id; the outline and in-page links move the focus to the heading they reach. Code blocks
101
+ and tables that scroll sideways take the focus and are named. Task-list checkboxes are named by their item. A new page
102
+ moves the focus to its title, except on the first visit.