🔥 Sync 2026-11-04 02:13:23

This commit is contained in:
github-actions[bot] committed 2026-11-04 02:13:23 +08:00
1 parent e281fb4f73
commit bfc1ef0244
65 files changed
+1112 -468

No files matched your search

+5
View File
@@ -13,6 +13,11 @@
`htdocs/` is generated output checked into git. Rebuild it with `pnpm build`, or trigger the manual `frontend-assets-build.yml` workflow, which builds and commits `htdocs/**`.
Install from `.dev/` using the pnpm version pinned in `package.json` and
`pnpm install --frozen-lockfile`, as the asset workflow does. The shared router
comes from the published `@eamonxg/luci-theme-devkit@0.3.2` package.
See [navigation-loading.md](navigation-loading.md) for the integration details.
## Terser options that are load-bearing
`.dev/src/resource/*.js` goes through terser (compress + local-scope mangle, no bundling); each file stays a standalone LuCI `L.require()`-able module. Two options must not be dropped:
@@ -0,0 +1,75 @@
# Navigation loading — 0.6.2 (2026-11-04)
The footer starts the menu and router modules in parallel. The router still
waits for the menu instance and `ui.menu.load()` before registering navigation
handlers. LuCI caches the pending promise for both its module loader and menu
request, so this removes the menu → router download dependency without adding
an `/admin/menu` request.
The header retains LuCI's standard translation script before `cbi.js`.
The optional catalog-directory probe was removed to keep template logic small
and avoid maintaining a separate decision about whether translations exist.
The pre-paint menu snapshot is scoped to language, user, session and theme
asset version. It is not reused after `ui.menu.flushCache()` invalidates the
LuCI session's menu. Logging out or returning to login clears the snapshot.
## Shared runtime integration
The theme pins `@eamonxg/luci-theme-devkit` to the published npm version
`0.3.2`. The lockfile records its registry integrity; no local dependency
patch or sibling checkout is required.
From the theme repository's `.dev/` directory, use the pnpm version pinned
by `package.json`:
```sh
pnpm install --frozen-lockfile
pnpm build
pnpm test
```
Shared runtime changes belong in the devkit repository. Publish the updated
npm package first, then update the theme dependency and lockfile before
rebuilding production assets.
The bounded dependency prewarmer brings the generated router from 15,771 B
to 17,806 B raw, or from 5,840 B to 6,618 B with Node gzip defaults. The router budget is now
18 KiB. Independent CSS, menu, sidebar and font budgets are unchanged.
The increase is 2,035 B raw and 778 B with Node gzip defaults.
The prewarmer fetches source without evaluating it, limits parallel requests,
honors reduced-data connections and retries failed fetches. Pointer hover
immediately fetches only the root view source; a 65 ms hover dwell then permits
dependency expansion. Keyboard `:focus-visible` may start deep warming directly.
Template shell prefetch always waits for that dwell. Pointer-down cancels the
pending timer without starting another fetch, and mouse focus starts no warmup.
A warmup generation counter lets the next intent retry after failures or a
navigation clears queued requests.
Template routes
with query parameters or wildcard arguments retain full document navigation;
template shells are cached by both template name and pathname. See the shared
devkit's maintained router documentation for the exact behavior.
## Validation
- Tests execute the footer with a never-resolving menu promise to verify the
router download starts immediately, and remains disabled without the
Navigation API.
- Cache tests cover identity/version mismatches and LuCI menu invalidation.
- Ordinary production builds use the published npm package. Both theme routers are
17,806 B, SHA-256 `c18a6f9b3a2f9b551ac7d7ee55560fdaec16901bfca9da3c9ff0dfc42a35973b`.
- Device timing and template checks are recorded in the devkit performance
report for this coordinated change; local unit timings are not device load
timings.
Shadcn renders its sidebar chrome and enables delegated controls while the
menu tree is still loading. Only navigation items wait for the authoritative
menu. The replay cache schema is version 2 (`{v, stamp, html, scroll}`).
The combined admin budget increases only by the router allowance delta:
217,500 + (18,432 − 16,000) = 219,932 B. A delayed-menu test verifies chrome
and the ready event are available before the response arrives.
The shadcn suite passed all 26 tests after the frozen install and ordinary rebuild;
color/contrast build checks also pass. Combined admin assets are 219,373 B
(budget 219,932 B). The menu asset is 17,007 B, two bytes smaller than before.
+1 -1
View File
@@ -9,7 +9,7 @@
How the theme turns a menu click into an in-document view swap instead of a
full page load, where it deliberately does not, and the invariants a router
inside LuCI has to keep. Source: `.dev/src/resource/router-shadcn.js`,
loaded from `footer.ut` after `menu-shadcn.js`. **No changes to luci-base
requested from `footer.ut` in parallel with `menu-shadcn.js`; the router waits for the menu instance and shared menu tree before installing navigation handlers. **No changes to luci-base
or to any view** — the router is additive theme JS plus small template hooks
(a patch manifest, `data-shadcn-*` markers on the stylesheets header.ut
itself renders, the asset version, a focusable `#maincontent`).
+2 -2
View File
@@ -2,11 +2,11 @@
- `header.ut`: near-minimal shell — empty `#sidebar` plus a parser-blocking inline script right after it that replays the sidebar cache (below) before first paint; sidebar chrome + nav are otherwise built client-side in `menu-shadcn.js`.
- `sidebar-shadcn.js`: state machine for theme (light/dark/device), sidebar collapse/expand, accordion, and mobile drawer — exposed as `window.ShadcnSidebar` after the `shadcn-sidebar-ready` event fires.
- `menu-shadcn.js`: resolves the `admin` branch of `ui.menu.load()`, then renders a two-level sidebar; `ICON_MAP` maps a LuCI menu node's `name` to `/shadcn/icons/*.svg`; deeper levels render as `#tabmenu`. `syncRoute()` re-marks the active sidebar item (same longest-link-prefix rule as the header.ut replay), breadcrumb and tabs from `L.env` after a [router](router.md) swap without rebuilding the sidebar; `closeSurfaces()` closes palette/drawer/popover.
- `menu-shadcn.js`: builds the sidebar chrome and emits `shadcn-sidebar-ready` before waiting for the menu request, so the branding, theme toggle and drawer/collapse controls are immediately available. Its navigation listeners are delegated. It resolves the `admin` branch of `ui.menu.load()`, then renders a two-level sidebar; `ICON_MAP` maps a LuCI menu node's `name` to `/shadcn/icons/*.svg`; deeper levels render as `#tabmenu`. `syncRoute()` re-marks the active sidebar item (same longest-link-prefix rule as the header.ut replay), breadcrumb and tabs from `L.env` after a [router](router.md) swap without rebuilding the sidebar; `closeSurfaces()` closes palette/drawer/popover.
## Sidebar cache (anti-flash)
`menu-shadcn.js` snapshots `#sidebar.innerHTML` + scroll position into `sessionStorage['shadcn.sidebar.cache']` (`{v, lang, html, scroll}`) after render and on `pagehide`. The `header.ut` inline script replays it pre-paint on the next navigation, recomputes the active highlight for the current URL (longest link-path prefix — keep in sync with menu-shadcn's dispatchpath matching), restores accordion/scroll state, and sets `data-shadcn-built` / `data-shadcn-restored` on `#sidebar`.
`menu-shadcn.js` snapshots `#sidebar.innerHTML` + scroll position into `sessionStorage['shadcn.sidebar.cache']` (`{v: 2, stamp, html, scroll}`) after render and on `pagehide`. The stamp binds the language, user, session and asset version. The `header.ut` inline script only replays while LuCI's session store still contains its menu, so `ui.menu.flushCache()` also invalidates the snapshot; the login page clears it. It replays pre-paint on the next navigation, recomputes the active highlight for the current URL (longest link-path prefix — keep in sync with menu-shadcn's dispatchpath matching), restores accordion/scroll state, and sets `data-shadcn-built` / `data-shadcn-restored` on `#sidebar`.
When restored, `renderSidebarChrome` only re-syncs the hostname, and `renderSidebarNav` preserves accordion/scroll across its authoritative rebuild.