@iyulab/canopy-page 0.10.0 → 0.11.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/CHANGELOG.md +26 -0
- package/README.md +14 -2
- package/dist/assets/mobile-nav.js +81 -0
- package/dist/assets-bundle.js +3 -2
- package/dist/settings.d.ts +2 -0
- package/dist/settings.js +1 -0
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,32 @@ Notable changes to canopy-page. The format follows
|
|
|
7
7
|
The `settings.json` contract is what consuming projects plan their upgrades around, so changes
|
|
8
8
|
to it — its fields, its validation, and what the checks reject — are what this file is about.
|
|
9
9
|
|
|
10
|
+
## [0.11.0] — 2026-08-17
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- **`strings.breadcrumb`**, overriding the accessible label of the topbar's new ancestor-trail
|
|
15
|
+
nav (canopy 0.11.0). Rides the same validated `strings` object every other reader-chrome
|
|
16
|
+
override already does.
|
|
17
|
+
|
|
18
|
+
### Changed
|
|
19
|
+
|
|
20
|
+
- **Upgraded to canopy 0.11.0** — collapsible sidebar groups and the breadcrumb trail (above),
|
|
21
|
+
a stronger sidebar current-page tint, a placeholder and icon on the search input, styled
|
|
22
|
+
topbar links, and the on-page outline now following the article instead of preceding it. See
|
|
23
|
+
[canopy's own changelog](https://github.com/iyulab/canopy/blob/main/CHANGELOG.md#0110--2026-08-17)
|
|
24
|
+
for the full list.
|
|
25
|
+
|
|
26
|
+
### Fixed
|
|
27
|
+
|
|
28
|
+
- **The mobile nav no longer opens on every page load.** canopy's shell ships the site
|
|
29
|
+
navigation as `<details open>` unconditionally — the one default that works with no script at
|
|
30
|
+
all — but on a narrow viewport, that meant a reader landed on a full navigation (rendered as a
|
|
31
|
+
full-screen overlay by canopy's own mobile styling) in front of the article they followed a
|
|
32
|
+
link to read, every single page. canopy-page's script now closes it by default on a narrow
|
|
33
|
+
viewport and remembers a reader's own choice to leave it open for the rest of that browser
|
|
34
|
+
session. A wide viewport, and a build with no script attached, are unaffected.
|
|
35
|
+
|
|
10
36
|
## [0.10.0] — 2026-08-11
|
|
11
37
|
|
|
12
38
|
### Added
|
package/README.md
CHANGED
|
@@ -40,7 +40,12 @@ go away.
|
|
|
40
40
|
system setting
|
|
41
41
|
- **Prev/next cards** linking to a page's neighbors in the sidebar's own order, and **backlinks**
|
|
42
42
|
listing every page that points to it
|
|
43
|
-
- **
|
|
43
|
+
- **Sidebar groups collapse**, open exactly along the path to the page you're on and closed
|
|
44
|
+
everywhere else
|
|
45
|
+
- **A breadcrumb trail** in the topbar, when there's a title, a logo, `home`, or search for it to
|
|
46
|
+
sit beside
|
|
47
|
+
- **A full-screen menu on narrow screens** that starts closed instead of opening on every page,
|
|
48
|
+
remembering a reader's own choice to leave it open for the rest of that visit
|
|
44
49
|
- **Sitemap and `robots.txt`**, once `siteUrl` is set
|
|
45
50
|
|
|
46
51
|
See it live at <https://iyulab.github.io/canopy-page>, or read
|
|
@@ -112,7 +117,7 @@ unpublished.
|
|
|
112
117
|
| `title` | Site name. Defaults to the folder's name |
|
|
113
118
|
| `description` | Fills `<meta name="description">`, which is what link previews show |
|
|
114
119
|
| `lang` | BCP 47 tag for `<html lang>`. Worth setting for any non-English site: assistive technology reads pronunciation from it |
|
|
115
|
-
| `strings` | Overrides for the reader chrome's own text — `search`, `toggleTheme`, `siteNav`, `pageNav`, `onThisPage`, `indexTitle` (the auto-generated contents page's title/heading), `backlinks` (a page's "linked references" heading), `searchFailed` (the client search's failure message). `lang` only changes what `<html lang>` declares; this text is canopy's own UI or canopy-page's own search script, not vault content, so it stays English otherwise. No built-in translation table — the same reasoning `home.label` already follows: link text has to be written in the site's own language. Keys left out keep their English default |
|
|
120
|
+
| `strings` | Overrides for the reader chrome's own text — `search`, `toggleTheme`, `siteNav`, `pageNav`, `onThisPage`, `indexTitle` (the auto-generated contents page's title/heading), `backlinks` (a page's "linked references" heading), `breadcrumb` (the topbar's ancestor-trail nav's label), `searchFailed` (the client search's failure message). `lang` only changes what `<html lang>` declares; this text is canopy's own UI or canopy-page's own search script, not vault content, so it stays English otherwise. No built-in translation table — the same reasoning `home.label` already follows: link text has to be written in the site's own language. Keys left out keep their English default |
|
|
116
121
|
| `icon` | Favicon, relative to the settings file. Must be a published file |
|
|
117
122
|
| `tokens` | CSS of design-token overrides, relative to the settings file. Appended *after* canopy's own tokens, so a file naming one value keeps the rest. It is configuration rather than content, so — unlike `icon` and `logo` — it is excluded from the published site automatically. Absent: canopy's default palette |
|
|
118
123
|
| `logo` | Image shown beside the site title, relative to the settings file. Must be a published file — the opposite direction from `tokens`, because this one is content. Rendered with an empty `alt`, deliberately: the site title beside it already names the site, so there is no separate text to give it. Absent: the sidebar header shows the title text alone |
|
|
@@ -145,6 +150,13 @@ specificity over a bare selector — so a bare `:root` appended after that block
|
|
|
145
150
|
schemes. A one-block file naming only a light-mode colour would ship that colour onto a dark
|
|
146
151
|
sidebar too.
|
|
147
152
|
|
|
153
|
+
Unlike `settings.json` (below), `tokens` gets no such validation — it's a plain CSS file appended
|
|
154
|
+
to canopy's own, and CSS silently ignores a custom property nothing reads. A file carried over
|
|
155
|
+
from a previous documentation tool's own token names (or a `.dark`/`.light` class toggle instead
|
|
156
|
+
of canopy's `[data-theme]` attribute) parses fine, builds fine, and changes nothing: the site
|
|
157
|
+
keeps canopy's default colours with no error anywhere. If a `tokens` override doesn't show up on
|
|
158
|
+
the built site, that silent mismatch — not a build failure — is the first thing to check.
|
|
159
|
+
|
|
148
160
|
The settings file itself is never published, and neither is anything `exclude` names. A file
|
|
149
161
|
named `settings.json` deeper in the site is content, and ships.
|
|
150
162
|
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* canopy-page's mobile nav default — vanilla JS, no dependencies. Wires the
|
|
3
|
+
* `<details class="canopy-nav" open>` disclosure canopy's shell always ships
|
|
4
|
+
* open: canopy itself writes no JavaScript (see canopy's docs/SCOPE.md), so
|
|
5
|
+
* a static page has no way to default that state per breakpoint on its own,
|
|
6
|
+
* and `open` has to pick one default for every viewport. It picks the safe
|
|
7
|
+
* one — a script-free reader on any screen still gets a working, fully
|
|
8
|
+
* visible navigation — but on a narrow viewport that leaves every fresh page
|
|
9
|
+
* load showing the full site navigation (canopy's shell renders an open
|
|
10
|
+
* `.canopy-nav` there as a full-screen overlay) in front of the article a
|
|
11
|
+
* reader actually followed a link to see.
|
|
12
|
+
*
|
|
13
|
+
* This script narrows that default, never widens it: a wide viewport is left
|
|
14
|
+
* exactly as canopy's shell already renders it (open, no toggle needed). On
|
|
15
|
+
* a narrow one it starts closed, unless the reader already chose to leave it
|
|
16
|
+
* open earlier in the same session — sessionStorage rather than
|
|
17
|
+
* localStorage, since a stale "open" choice from a different visit days ago
|
|
18
|
+
* would be more surprising than useful.
|
|
19
|
+
*
|
|
20
|
+
* `shouldOpenOnLoad` is exposed for tests: it is the one piece of this file
|
|
21
|
+
* with real logic, and it needs no DOM to run.
|
|
22
|
+
*/
|
|
23
|
+
var CanopyMobileNav = (function () {
|
|
24
|
+
"use strict";
|
|
25
|
+
|
|
26
|
+
var STORAGE_KEY = "canopy-nav-open";
|
|
27
|
+
var NARROW_QUERY = "(max-width: 40rem)";
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Whether the nav should start open, given the viewport it's rendering at
|
|
31
|
+
* and the reader's last explicit choice this session (undefined if they
|
|
32
|
+
* never toggled it). A wide viewport always opens — matching the shell's
|
|
33
|
+
* own always-there design there, which this script only ever narrows for
|
|
34
|
+
* a narrow viewport, never overrides for a wide one. A narrow viewport
|
|
35
|
+
* starts closed unless the reader explicitly left it open last time.
|
|
36
|
+
*/
|
|
37
|
+
function shouldOpenOnLoad(isNarrowViewport, storedChoice) {
|
|
38
|
+
if (!isNarrowViewport) return true;
|
|
39
|
+
return storedChoice === "open";
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
function readStoredChoice() {
|
|
43
|
+
try {
|
|
44
|
+
return sessionStorage.getItem(STORAGE_KEY) || undefined;
|
|
45
|
+
} catch (e) {
|
|
46
|
+
// Storage access can throw (private browsing with storage disabled) —
|
|
47
|
+
// a reader who hits that just gets the narrow-viewport default every
|
|
48
|
+
// load, not a broken page.
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
function storeChoice(open) {
|
|
54
|
+
try {
|
|
55
|
+
sessionStorage.setItem(STORAGE_KEY, open ? "open" : "closed");
|
|
56
|
+
} catch (e) {
|
|
57
|
+
// Same as above: a reader who can't write storage just loses the
|
|
58
|
+
// memory across pages, not the toggle itself.
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
function main() {
|
|
63
|
+
var nav = document.querySelector(".canopy-nav");
|
|
64
|
+
if (!nav || typeof matchMedia !== "function") return;
|
|
65
|
+
|
|
66
|
+
var isNarrow = matchMedia(NARROW_QUERY).matches;
|
|
67
|
+
nav.open = shouldOpenOnLoad(isNarrow, readStoredChoice());
|
|
68
|
+
|
|
69
|
+
// A reader's own click (native <details> toggling, no JS involved in the
|
|
70
|
+
// click itself) still fires this — the same event a script-driven
|
|
71
|
+
// assignment above fires too, so the very first automatic close is
|
|
72
|
+
// recorded as "closed" for free rather than needing a separate write.
|
|
73
|
+
nav.addEventListener("toggle", function () {
|
|
74
|
+
storeChoice(nav.open);
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
if (typeof document !== "undefined") main();
|
|
79
|
+
|
|
80
|
+
return { shouldOpenOnLoad: shouldOpenOnLoad };
|
|
81
|
+
})();
|
package/dist/assets-bundle.js
CHANGED
|
@@ -34,10 +34,11 @@ const SEARCH_FAILED_DEFAULT = "Search failed to load.";
|
|
|
34
34
|
* asset stays valid, readable JavaScript on its own.
|
|
35
35
|
*/
|
|
36
36
|
export async function assembleScript(searchFailed) {
|
|
37
|
-
const [search, scrollspy, themeToggle] = await Promise.all([
|
|
37
|
+
const [search, scrollspy, themeToggle, mobileNav] = await Promise.all([
|
|
38
38
|
readAsset("search.js"),
|
|
39
39
|
readAsset("scrollspy.js"),
|
|
40
40
|
readAsset("theme-toggle.js"),
|
|
41
|
+
readAsset("mobile-nav.js"),
|
|
41
42
|
]);
|
|
42
43
|
// A function replacer, not a replacement string: String.replace treats
|
|
43
44
|
// "$&"/"$'"/"$$" etc. in a replacement string as patterns, and a site
|
|
@@ -45,7 +46,7 @@ export async function assembleScript(searchFailed) {
|
|
|
45
46
|
const searchWithStrings = searchFailed === undefined
|
|
46
47
|
? search
|
|
47
48
|
: search.replace(JSON.stringify(SEARCH_FAILED_DEFAULT), () => JSON.stringify(searchFailed));
|
|
48
|
-
return `${searchWithStrings}\n${scrollspy}\n${themeToggle}`;
|
|
49
|
+
return `${searchWithStrings}\n${scrollspy}\n${themeToggle}\n${mobileNav}`;
|
|
49
50
|
}
|
|
50
51
|
/**
|
|
51
52
|
* CSS canopy-page contributes on top of a site's own tokens, carried via
|
package/dist/settings.d.ts
CHANGED
|
@@ -131,6 +131,8 @@ export interface Settings {
|
|
|
131
131
|
indexTitle?: string;
|
|
132
132
|
/** Heading over a page's list of pages that link to it. */
|
|
133
133
|
backlinks?: string;
|
|
134
|
+
/** Accessible label for the topbar's ancestor-trail nav. */
|
|
135
|
+
breadcrumb?: string;
|
|
134
136
|
/**
|
|
135
137
|
* Message shown in place of results when the client search index fails to
|
|
136
138
|
* load. This key rides the same JSON `--strings` flag as every other one
|
package/dist/settings.js
CHANGED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@iyulab/canopy-page",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.11.0",
|
|
4
4
|
"description": "Authoring pipeline for documentation sites: one settings file, integrity checks, and a build.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -53,7 +53,7 @@
|
|
|
53
53
|
"vitest": "^4.1.9"
|
|
54
54
|
},
|
|
55
55
|
"dependencies": {
|
|
56
|
-
"@iyulab/canopy": "^0.
|
|
56
|
+
"@iyulab/canopy": "^0.11.0",
|
|
57
57
|
"chokidar": "^5.0.0"
|
|
58
58
|
}
|
|
59
59
|
}
|