@grimoire-rs/indexer 0.5.0 → 0.5.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/CHANGELOG.md +81 -1
- package/dist/cli/dev.d.ts +14 -0
- package/dist/cli/dev.d.ts.map +1 -1
- package/dist/cli/dev.js +22 -1
- package/dist/cli/dev.js.map +1 -1
- package/dist/cli/main.d.ts.map +1 -1
- package/dist/cli/main.js +5 -0
- package/dist/cli/main.js.map +1 -1
- package/dist/renderer/astro/components/Catalog.js +109 -3
- package/dist/renderer/astro/components/Catalog.tsx +156 -9
- package/dist/renderer/astro/components/CodeBlock.astro +74 -0
- package/dist/renderer/astro/layouts/Base.astro +143 -54
- package/dist/renderer/astro/lib/code.d.ts +2 -2
- package/dist/renderer/astro/lib/code.js +2 -2
- package/dist/renderer/astro/lib/code.ts +2 -2
- package/dist/renderer/astro/lib/commands.d.ts +9 -3
- package/dist/renderer/astro/lib/commands.js +10 -5
- package/dist/renderer/astro/lib/commands.ts +22 -6
- package/dist/renderer/astro/pages/p/[...slug].astro +23 -17
- package/dist/renderer/index.d.ts +19 -0
- package/dist/renderer/index.d.ts.map +1 -1
- package/dist/renderer/index.js +18 -2
- package/dist/renderer/index.js.map +1 -1
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -21,6 +21,85 @@ props `{ pkg }` → `{ pkg, compact }`.
|
|
|
21
21
|
|
|
22
22
|
## [Unreleased]
|
|
23
23
|
|
|
24
|
+
## [0.5.1] - 2026-08-31
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
|
|
28
|
+
- **`grim-indexer dev --host [addr]`.** Bare, it binds every interface; with a
|
|
29
|
+
value, that address. Without it the server binds loopback only — Astro's own
|
|
30
|
+
default — which is unreachable from a dev container, a VM or a WSL guest,
|
|
31
|
+
where the port forwards and the connection then hangs against a socket that
|
|
32
|
+
is not listening for it. `npm run dev -- --host` takes the same two forms.
|
|
33
|
+
Bare `--host` puts the preview on your network; the CLI reference says so.
|
|
34
|
+
- **`CodeBlock.astro`**, a reusable code block: the site's own frame, the same
|
|
35
|
+
Shiki theme pair every rendered README uses, the same copy button and toast,
|
|
36
|
+
and an optional VS Code button. Props
|
|
37
|
+
`{ code, lang?, name?, vscodeHref?, vscodeLabel? }`; `vscodeHref` is a plain
|
|
38
|
+
URL, so `vscodeUrl`, `vscodeVoteUrl`, `addRegistryUrl` and a hand-written
|
|
39
|
+
deep link all work. Worked example in
|
|
40
|
+
[Reuse shipped components](docs/how-to/reuse-components.md#code-blocks).
|
|
41
|
+
- **`data-slot="code-block"`**, for it. Contract tier, like every other slot.
|
|
42
|
+
- **A second argument on `registryAddCommand` and `registryScopeChoices`**,
|
|
43
|
+
the registry to build the command for — defaulting to the one in your config,
|
|
44
|
+
so nothing existing changes. It is what lets a setup page draw the "add
|
|
45
|
+
registry" bar for an index *other* than the site's own: a corporate index in
|
|
46
|
+
the hero and the public one further down.
|
|
47
|
+
- **A clear button on the keyword filters**, in the catalog toolbar. Rendered
|
|
48
|
+
only while a keyword is picked, and it lifts the keywords alone — Escape is
|
|
49
|
+
still what clears the search and the kinds with them.
|
|
50
|
+
|
|
51
|
+
### Fixed
|
|
52
|
+
|
|
53
|
+
- **The keyword overflow menu opened invisibly.** Its panel was an absolutely
|
|
54
|
+
positioned child of the toolbar's filter row, which is a scroll container, so
|
|
55
|
+
the panel was cropped to the row and stretched the row's scroll extent — a
|
|
56
|
+
menu nobody could see, with a stray horizontal and vertical scrollbar to show
|
|
57
|
+
for it. It is a popover now, which puts it in the top layer, outside every
|
|
58
|
+
ancestor's `overflow`, and brings Escape and light dismiss with it. The
|
|
59
|
+
trigger is a `<button>` rather than a `<summary>`, so the toolbar's arrow-key
|
|
60
|
+
navigation now reaches it.
|
|
61
|
+
- **The detail page's logo drifted down under a long description.** The header
|
|
62
|
+
centred the tile against the text beside it, so the same package's mark sat
|
|
63
|
+
at a different height on every page. It holds against the title now.
|
|
64
|
+
- **Dropped the tinted square behind a package logo**, on the cards, the list
|
|
65
|
+
rows and the detail header alike. A logo is a designed mark already sitting
|
|
66
|
+
on its own ground, so the slot framed it twice — most visibly for the many
|
|
67
|
+
logos that are themselves a rounded square, which then sat inside a slightly
|
|
68
|
+
larger one. The slot still reserves the same box, so nothing shifts. The
|
|
69
|
+
dashed frame the broken-logo state drew goes with it — it read as a fault in
|
|
70
|
+
the layout rather than in the image; the slashed glyph is what says the logo
|
|
71
|
+
failed, and `role="img"` with a label is what announces it. The
|
|
72
|
+
initial-letter tile a package with no logo gets is unchanged: there the
|
|
73
|
+
coloured ground is the mark.
|
|
74
|
+
- **The dev server's URL is a legal URL when the server binds an IPv6
|
|
75
|
+
address.** An unbracketed literal reads its own colons as a port, so
|
|
76
|
+
`http://::1:4321/` threw `ERR_INVALID_URL` at the first `new URL` against it
|
|
77
|
+
and took `dev:smoke` down with a message naming neither the address nor the
|
|
78
|
+
host. Wildcard binds still become `localhost`; anything carrying a colon is
|
|
79
|
+
bracketed.
|
|
80
|
+
- **The detail page's logo tile is a fixed square.** `aspect-ratio: 1` derived
|
|
81
|
+
its width from the height the box had *before* `align-self: stretch` grew it,
|
|
82
|
+
so it rendered 56x93 beside a logo and 56x70 beside a letter — portrait,
|
|
83
|
+
never square, and narrow enough to read as bounding the image rather than
|
|
84
|
+
framing it.
|
|
85
|
+
- **The list row's glyphs sit on the row's centre.** `vertical-align: middle`
|
|
86
|
+
aligns to half the parent's x-height, about 2px under the line's true middle
|
|
87
|
+
at this step, and the upvote arrow's optical nudge added a third pixel the
|
|
88
|
+
same way. The kind and rating cells are flex boxes now and centre their
|
|
89
|
+
contents as boxes.
|
|
90
|
+
- **Keyword chips could freeze part-way through the rail's slide.** The rail
|
|
91
|
+
animates a rescore by inverting each chip with an inline `translate` and
|
|
92
|
+
dropping it on the next animation frame. A rescore that also changes how many
|
|
93
|
+
chips fit commits a second time, and that commit cancelled the frame before
|
|
94
|
+
it ran — leaving every moved chip parked at its offset with transitions
|
|
95
|
+
disabled. Deselecting the last keyword hit it most often, because that
|
|
96
|
+
rescore is the largest. The offsets are now cleared before each measurement
|
|
97
|
+
and on cleanup, so an interrupted slide resolves instead of sticking.
|
|
98
|
+
- **Switching between the cards and list views repainted the whole catalog.**
|
|
99
|
+
Off-screen cards are skipped until they are scrolled to. The two views share
|
|
100
|
+
no element types, so a switch still rebuilds every item — past a few hundred
|
|
101
|
+
packages the answer is windowing the list, and this is not that.
|
|
102
|
+
|
|
24
103
|
## [0.5.0] - 2026-08-30
|
|
25
104
|
|
|
26
105
|
### Added
|
|
@@ -186,5 +265,6 @@ props `{ pkg }` → `{ pkg, compact }`.
|
|
|
186
265
|
boot can leave a `.index-*` holding Vite's `deps_temp_<hash>`, which the
|
|
187
266
|
dependency optimizer recreates after the removal has already returned.
|
|
188
267
|
|
|
189
|
-
[Unreleased]: https://github.com/grimoire-rs/indexer/compare/v0.5.
|
|
268
|
+
[Unreleased]: https://github.com/grimoire-rs/indexer/compare/v0.5.1...HEAD
|
|
269
|
+
[0.5.1]: https://github.com/grimoire-rs/indexer/compare/v0.5.0...v0.5.1
|
|
190
270
|
[0.5.0]: https://github.com/grimoire-rs/indexer/compare/v0.4.4...v0.5.0
|
package/dist/cli/dev.d.ts
CHANGED
|
@@ -2,6 +2,20 @@ import { type ExitCode } from "./exit.js";
|
|
|
2
2
|
export interface DevFlags {
|
|
3
3
|
outDir?: string;
|
|
4
4
|
port?: string;
|
|
5
|
+
/** `true` for a bare `--host` (every interface), or the address to bind. */
|
|
6
|
+
host?: string | boolean;
|
|
5
7
|
}
|
|
8
|
+
/**
|
|
9
|
+
* What `--host` binds to, in the shape Astro's `server.host` takes: `true` for
|
|
10
|
+
* every interface, a string for one address, `undefined` to leave the default
|
|
11
|
+
* loopback bind alone.
|
|
12
|
+
*
|
|
13
|
+
* Only the shapes that cannot be an address are rejected here — an empty value,
|
|
14
|
+
* and anything carrying whitespace or a `/`, which is what `--host
|
|
15
|
+
* http://0.0.0.0` and a pasted URL look like. Whether the address exists on
|
|
16
|
+
* this machine is the kernel's answer, not this function's, and it arrives as a
|
|
17
|
+
* bind error naming the address.
|
|
18
|
+
*/
|
|
19
|
+
export declare function resolveHost(host: string | boolean | undefined): string | boolean | undefined;
|
|
6
20
|
export declare function dev(root: string, flags: DevFlags): Promise<ExitCode>;
|
|
7
21
|
//# sourceMappingURL=dev.d.ts.map
|
package/dist/cli/dev.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"AASA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAG1D,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"dev.d.ts","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"AASA,OAAO,EAAkB,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAC;AAG1D,MAAM,WAAW,QAAQ;IACvB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,4EAA4E;IAC5E,IAAI,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;CACzB;AAgBD;;;;;;;;;;GAUG;AACH,wBAAgB,WAAW,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,GAAG,SAAS,GAAG,MAAM,GAAG,OAAO,GAAG,SAAS,CAU5F;AAED,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAqC1E"}
|
package/dist/cli/dev.js
CHANGED
|
@@ -21,10 +21,31 @@ function resolvePort(port) {
|
|
|
21
21
|
}
|
|
22
22
|
return value;
|
|
23
23
|
}
|
|
24
|
+
/**
|
|
25
|
+
* What `--host` binds to, in the shape Astro's `server.host` takes: `true` for
|
|
26
|
+
* every interface, a string for one address, `undefined` to leave the default
|
|
27
|
+
* loopback bind alone.
|
|
28
|
+
*
|
|
29
|
+
* Only the shapes that cannot be an address are rejected here — an empty value,
|
|
30
|
+
* and anything carrying whitespace or a `/`, which is what `--host
|
|
31
|
+
* http://0.0.0.0` and a pasted URL look like. Whether the address exists on
|
|
32
|
+
* this machine is the kernel's answer, not this function's, and it arrives as a
|
|
33
|
+
* bind error naming the address.
|
|
34
|
+
*/
|
|
35
|
+
export function resolveHost(host) {
|
|
36
|
+
if (host === undefined || typeof host === "boolean")
|
|
37
|
+
return host;
|
|
38
|
+
const value = host.trim();
|
|
39
|
+
if (value === "" || /[\s/]/.test(value)) {
|
|
40
|
+
throw new CliError(`--host ${JSON.stringify(host)}: must be a hostname or IP address, or bare for all interfaces`, EXIT.usage);
|
|
41
|
+
}
|
|
42
|
+
return value;
|
|
43
|
+
}
|
|
24
44
|
export async function dev(root, flags) {
|
|
25
45
|
const rootDir = path.resolve(root);
|
|
26
46
|
const outDir = resolveOutDir(rootDir, flags.outDir);
|
|
27
47
|
const port = resolvePort(flags.port);
|
|
48
|
+
const host = resolveHost(flags.host);
|
|
28
49
|
const [{ loadConfig }, { compileIndex }, { devSite }] = await Promise.all([
|
|
29
50
|
import("../config.js"),
|
|
30
51
|
import("../data/index.js"),
|
|
@@ -32,7 +53,7 @@ export async function dev(root, flags) {
|
|
|
32
53
|
]);
|
|
33
54
|
const config = await loadConfig(rootDir);
|
|
34
55
|
const { count, namespaces } = await compileIndex({ root: rootDir, outDir });
|
|
35
|
-
const server = await devSite({ root: rootDir, outDir, config, port });
|
|
56
|
+
const server = await devSite({ root: rootDir, outDir, config, port, host });
|
|
36
57
|
console.log(`\n ${server.url}\n`);
|
|
37
58
|
console.log(` ${count} package(s) across ${namespaces.length} namespace(s)`);
|
|
38
59
|
// `index.config.json` is read once, at boot, and baked into the bundle — the
|
package/dist/cli/dev.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"AAAA,sCAAsC;AACtC,sCAAsC;AAEtC,8EAA8E;AAC9E,+EAA+E;AAC/E,4EAA4E;AAC5E,uBAAuB;AACvB,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAiB,MAAM,WAAW,CAAC;AAC1D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;
|
|
1
|
+
{"version":3,"file":"dev.js","sourceRoot":"","sources":["../../src/cli/dev.ts"],"names":[],"mappings":"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"}
|
package/dist/cli/main.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AA+FA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"AA+FA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAyJzD"}
|
package/dist/cli/main.js
CHANGED
|
@@ -143,6 +143,11 @@ export async function run(argv) {
|
|
|
143
143
|
.description("serve this index locally with a live preview")
|
|
144
144
|
.option("--out-dir <dir>", "output directory", "dist")
|
|
145
145
|
.option("--port <n>", "port to listen on")
|
|
146
|
+
// `[addr]` and not `<addr>`: bare `--host` means every interface, the same
|
|
147
|
+
// thing it means to `astro dev`, whose own banner is what tells a reader
|
|
148
|
+
// stuck behind a dev container or a WSL port forward to reach for it.
|
|
149
|
+
// Commander hands back `true` for the bare form and the string otherwise.
|
|
150
|
+
.option("--host [addr]", "expose the server on a network address (bare: all interfaces)")
|
|
146
151
|
.action(async (root, opts) => {
|
|
147
152
|
code = await dev(root, opts);
|
|
148
153
|
});
|
package/dist/cli/main.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"main.js","sourceRoot":"","sources":["../../src/cli/main.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,7 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "preact/jsx-ru
|
|
|
2
2
|
import { useEffect, useLayoutEffect, useMemo, useRef, useState, } from "preact/hooks";
|
|
3
3
|
// Lucide (ISC) draws the toolbar. The brand marks and kind glyphs moved out
|
|
4
4
|
// with the card and the row that wear them.
|
|
5
|
-
import { ArrowDownWideNarrow, ArrowUpNarrowWide, LayoutGrid, List, } from "lucide-preact";
|
|
5
|
+
import { ArrowDownWideNarrow, ArrowUpNarrowWide, LayoutGrid, List, X, } from "lucide-preact";
|
|
6
6
|
import { PackageCard } from "./PackageCard.js";
|
|
7
7
|
import { PackageRow } from "./PackageRow.js";
|
|
8
8
|
import { keywordFrequency, selectRailKeywords } from "../lib/keywordRail.js";
|
|
@@ -22,6 +22,12 @@ function kindOrder(kind) {
|
|
|
22
22
|
* all of it is a wall of chips nobody reads.
|
|
23
23
|
*/
|
|
24
24
|
const KEYWORD_CHIP_LIMIT = 8;
|
|
25
|
+
/**
|
|
26
|
+
* `popovertarget` needs an id, and the catalog is a singleton on its page —
|
|
27
|
+
* one island, one toolbar, one overflow menu — so this is a constant rather
|
|
28
|
+
* than something generated per mount.
|
|
29
|
+
*/
|
|
30
|
+
const KEYWORD_MENU_ID = "grim-keyword-overflow";
|
|
25
31
|
/**
|
|
26
32
|
* The direction each field is *worth* reading first in — A→Z for a name,
|
|
27
33
|
* newest and best-liked first for the two ranked keys.
|
|
@@ -254,6 +260,56 @@ export default function Catalog({ packages, vscodeExtension, }) {
|
|
|
254
260
|
const railRefs = useRef(new Map());
|
|
255
261
|
const railRects = useRef(new Map());
|
|
256
262
|
const railRef = useRef(null);
|
|
263
|
+
const kwMenuRef = useRef(null);
|
|
264
|
+
const kwTriggerRef = useRef(null);
|
|
265
|
+
// Drives the trigger's own `aria-expanded` and its open styling. The panel's
|
|
266
|
+
// visibility is the popover's business, not this flag's.
|
|
267
|
+
const [kwMenuOpen, setKwMenuOpen] = useState(false);
|
|
268
|
+
/**
|
|
269
|
+
* Seat the overflow menu under its trigger.
|
|
270
|
+
*
|
|
271
|
+
* The panel is a popover, so it lives in the top layer and is positioned
|
|
272
|
+
* against the viewport rather than against any ancestor — which is the whole
|
|
273
|
+
* point (`.filter-row` is a scroll container and used to crop it). That
|
|
274
|
+
* leaves the seat to us.
|
|
275
|
+
*
|
|
276
|
+
* It always opens downward: the toolbar sits at the top of the page, and a
|
|
277
|
+
* flip would only ever fire on a viewport short enough that the panel has
|
|
278
|
+
* nowhere to go either way. What does not fit becomes `max-height` and
|
|
279
|
+
* scrolls inside the list.
|
|
280
|
+
*
|
|
281
|
+
* Called twice per open, from `beforetoggle` and again from `toggle`. The
|
|
282
|
+
* first runs while the panel is still `display: none`, so its measured width
|
|
283
|
+
* is 0 and the horizontal clamp is a no-op — but the vertical seat is right,
|
|
284
|
+
* which is what stops it appearing in the wrong place for a frame. The
|
|
285
|
+
* second has a real width and finishes the clamp.
|
|
286
|
+
*/
|
|
287
|
+
const placeKwMenu = () => {
|
|
288
|
+
const panel = kwMenuRef.current;
|
|
289
|
+
const trigger = kwTriggerRef.current;
|
|
290
|
+
if (!panel || !trigger)
|
|
291
|
+
return;
|
|
292
|
+
const seat = trigger.getBoundingClientRect();
|
|
293
|
+
const gap = 8;
|
|
294
|
+
const width = panel.getBoundingClientRect().width;
|
|
295
|
+
panel.style.left = `${Math.max(gap, Math.min(seat.left, window.innerWidth - width - gap))}px`;
|
|
296
|
+
panel.style.top = `${seat.bottom + gap}px`;
|
|
297
|
+
panel.style.maxHeight = `${Math.max(120, window.innerHeight - seat.bottom - gap * 3)}px`;
|
|
298
|
+
};
|
|
299
|
+
// A fixed panel does not travel with the trigger, so it is re-seated rather
|
|
300
|
+
// than left behind. Only while open — there is nothing to follow otherwise.
|
|
301
|
+
useEffect(() => {
|
|
302
|
+
if (!kwMenuOpen)
|
|
303
|
+
return;
|
|
304
|
+
const reseat = () => placeKwMenu();
|
|
305
|
+
// Capturing: the scroll may be any ancestor's, including `.filter-row`'s.
|
|
306
|
+
window.addEventListener("scroll", reseat, { capture: true, passive: true });
|
|
307
|
+
window.addEventListener("resize", reseat);
|
|
308
|
+
return () => {
|
|
309
|
+
window.removeEventListener("scroll", reseat, { capture: true });
|
|
310
|
+
window.removeEventListener("resize", reseat);
|
|
311
|
+
};
|
|
312
|
+
}, [kwMenuOpen]);
|
|
257
313
|
/**
|
|
258
314
|
* How many keyword chips actually fit on the row, measured.
|
|
259
315
|
*
|
|
@@ -325,9 +381,26 @@ export default function Catalog({ packages, vscodeExtension, }) {
|
|
|
325
381
|
* shape that makes a layout thrash, and this runs per keystroke.
|
|
326
382
|
*/
|
|
327
383
|
useLayoutEffect(() => {
|
|
384
|
+
// Undo whatever the last pass left on the chips before measuring
|
|
385
|
+
// anything. Two reasons, and both were visible: `getBoundingClientRect`
|
|
386
|
+
// reports the *translated* box, so a chip caught mid-slide would be
|
|
387
|
+
// measured where it is drawn rather than where it belongs and the next
|
|
388
|
+
// inversion would compound that error; and a chip whose play frame never
|
|
389
|
+
// ran is still carrying `transition: none` with an offset, which is a chip
|
|
390
|
+
// frozen off its seat. Clearing here is what unfreezes it.
|
|
391
|
+
//
|
|
392
|
+
// Mid-slide is not a rare case: the fit measurement above commits a second
|
|
393
|
+
// time whenever the rescore changes how many chips fit, and that commit
|
|
394
|
+
// lands between this one and its animation frame.
|
|
395
|
+
for (const el of railRefs.current.values()) {
|
|
396
|
+
el.style.transition = "";
|
|
397
|
+
el.style.translate = "";
|
|
398
|
+
}
|
|
328
399
|
const previous = railRects.current;
|
|
329
400
|
const current = new Map();
|
|
330
401
|
const moved = [];
|
|
402
|
+
// A second pass, deliberately: every write above is flushed before the
|
|
403
|
+
// first read below, rather than interleaving them per chip.
|
|
331
404
|
for (const [keyword, el] of railRefs.current) {
|
|
332
405
|
const rect = el.getBoundingClientRect();
|
|
333
406
|
current.set(keyword, rect);
|
|
@@ -352,7 +425,19 @@ export default function Catalog({ packages, vscodeExtension, }) {
|
|
|
352
425
|
el.style.translate = "";
|
|
353
426
|
}
|
|
354
427
|
});
|
|
355
|
-
return () =>
|
|
428
|
+
return () => {
|
|
429
|
+
cancelAnimationFrame(frame);
|
|
430
|
+
// Cancelling is not enough on its own. Nothing else takes these off, so
|
|
431
|
+
// a commit landing before the frame ran would leave every moved chip
|
|
432
|
+
// sitting at its inverted offset with transitions disabled — the rail
|
|
433
|
+
// stopping halfway and staying there. Deselecting the last keyword is
|
|
434
|
+
// the reliable way to see it: the rescore is at its largest, so the fit
|
|
435
|
+
// changes and the extra commit always lands.
|
|
436
|
+
for (const { el } of moved) {
|
|
437
|
+
el.style.transition = "";
|
|
438
|
+
el.style.translate = "";
|
|
439
|
+
}
|
|
440
|
+
};
|
|
356
441
|
});
|
|
357
442
|
/** Move focus `delta` cards along, clamping at both ends rather than wrapping. */
|
|
358
443
|
const focusCard = (from, delta) => {
|
|
@@ -768,7 +853,28 @@ export default function Catalog({ packages, vscodeExtension, }) {
|
|
|
768
853
|
]
|
|
769
854
|
.filter(Boolean)
|
|
770
855
|
.join(" "), "data-slot": "filter-chip", "aria-pressed": keywords.includes(keyword), "aria-hidden": clipped ? "true" : undefined, tabIndex: clipped ? -1 : undefined, onKeyDown: onChipKeyDown, onClick: () => toggleKeyword(keyword), children: keyword }, keyword));
|
|
771
|
-
}) })] })), menuKeywords.length > 0 && (_jsxs("
|
|
856
|
+
}) })] })), menuKeywords.length > 0 && (_jsxs("div", { class: "kw-menu", children: [_jsxs("button", { type: "button", class: "chip", "data-slot": "filter-chip", ref: kwTriggerRef, popovertarget: KEYWORD_MENU_ID, "aria-expanded": kwMenuOpen, children: ["+", menuKeywords.length, " more"] }), _jsxs("div", { class: "kw-menu-panel", id: KEYWORD_MENU_ID, popover: "auto", ref: kwMenuRef,
|
|
857
|
+
// Both, and in this order: `beforetoggle` runs synchronously
|
|
858
|
+
// inside the show steps, so the panel is seated before it is
|
|
859
|
+
// ever painted; `toggle` runs after, when its width can
|
|
860
|
+
// actually be measured for the clamp.
|
|
861
|
+
onBeforeToggle: (e) => {
|
|
862
|
+
setKwMenuOpen(e.newState === "open");
|
|
863
|
+
placeKwMenu();
|
|
864
|
+
}, onToggle: (e) => {
|
|
865
|
+
setKwMenuOpen(e.newState === "open");
|
|
866
|
+
placeKwMenu();
|
|
867
|
+
}, children: [_jsx("input", { type: "text", class: "kw-menu-search", placeholder: "Filter keywords\u2026", "aria-label": "Filter keywords", value: keywordFilter, onInput: (e) => setKeywordFilter(e.target.value) }), _jsxs("div", { class: "kw-menu-list", children: [menuShown.map(({ keyword, count }) => (_jsxs("button", { type: "button", class: "kw-menu-item", onClick: () => toggleKeyword(keyword), children: [_jsx("span", { children: keyword }), _jsx("small", { children: count })] }, keyword))), menuShown.length === 0 && (_jsx("p", { class: "kw-menu-empty", children: "No keyword matches." }))] })] })] })), keywords.length > 0 && (_jsxs("button", { type: "button", class: "chip kw-clear", "data-slot": "filter-chip", title: "Clear the keyword filters", onKeyDown: onChipKeyDown, onClick: (e) => {
|
|
868
|
+
setKeywords([]);
|
|
869
|
+
// This button is the last thing standing when it is pressed:
|
|
870
|
+
// clearing the facets unmounts it, and focus would land on
|
|
871
|
+
// `<body>`, sending a keyboard reader back to the top of the
|
|
872
|
+
// document. `detail === 0` is a click synthesized by Enter or
|
|
873
|
+
// Space, so a pointer user is left alone and a keyboard one
|
|
874
|
+
// gets the toolbar's own anchor instead of nothing.
|
|
875
|
+
if (e.detail === 0)
|
|
876
|
+
searchRef.current?.focus();
|
|
877
|
+
}, children: [_jsx(X, { size: 13, "aria-hidden": "true" }), "clear ", keywords.length] })), hasDeprecated && (_jsx("button", { type: "button", class: showDeprecated
|
|
772
878
|
? "chip deprecated-toggle active"
|
|
773
879
|
: "chip deprecated-toggle", "aria-pressed": showDeprecated, title: showDeprecated
|
|
774
880
|
? "Hide deprecated packages"
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
ArrowUpNarrowWide,
|
|
13
13
|
LayoutGrid,
|
|
14
14
|
List,
|
|
15
|
+
X,
|
|
15
16
|
} from "lucide-preact";
|
|
16
17
|
import { PackageCard } from "./PackageCard.js";
|
|
17
18
|
import { PackageRow } from "./PackageRow.js";
|
|
@@ -41,6 +42,13 @@ export type View = "cards" | "table";
|
|
|
41
42
|
*/
|
|
42
43
|
const KEYWORD_CHIP_LIMIT = 8;
|
|
43
44
|
|
|
45
|
+
/**
|
|
46
|
+
* `popovertarget` needs an id, and the catalog is a singleton on its page —
|
|
47
|
+
* one island, one toolbar, one overflow menu — so this is a constant rather
|
|
48
|
+
* than something generated per mount.
|
|
49
|
+
*/
|
|
50
|
+
const KEYWORD_MENU_ID = "grim-keyword-overflow";
|
|
51
|
+
|
|
44
52
|
/**
|
|
45
53
|
* The direction each field is *worth* reading first in — A→Z for a name,
|
|
46
54
|
* newest and best-liked first for the two ranked keys.
|
|
@@ -329,6 +337,57 @@ export default function Catalog({
|
|
|
329
337
|
const railRects = useRef(new Map<string, DOMRect>());
|
|
330
338
|
const railRef = useRef<HTMLDivElement>(null);
|
|
331
339
|
|
|
340
|
+
const kwMenuRef = useRef<HTMLDivElement>(null);
|
|
341
|
+
const kwTriggerRef = useRef<HTMLButtonElement>(null);
|
|
342
|
+
// Drives the trigger's own `aria-expanded` and its open styling. The panel's
|
|
343
|
+
// visibility is the popover's business, not this flag's.
|
|
344
|
+
const [kwMenuOpen, setKwMenuOpen] = useState(false);
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Seat the overflow menu under its trigger.
|
|
348
|
+
*
|
|
349
|
+
* The panel is a popover, so it lives in the top layer and is positioned
|
|
350
|
+
* against the viewport rather than against any ancestor — which is the whole
|
|
351
|
+
* point (`.filter-row` is a scroll container and used to crop it). That
|
|
352
|
+
* leaves the seat to us.
|
|
353
|
+
*
|
|
354
|
+
* It always opens downward: the toolbar sits at the top of the page, and a
|
|
355
|
+
* flip would only ever fire on a viewport short enough that the panel has
|
|
356
|
+
* nowhere to go either way. What does not fit becomes `max-height` and
|
|
357
|
+
* scrolls inside the list.
|
|
358
|
+
*
|
|
359
|
+
* Called twice per open, from `beforetoggle` and again from `toggle`. The
|
|
360
|
+
* first runs while the panel is still `display: none`, so its measured width
|
|
361
|
+
* is 0 and the horizontal clamp is a no-op — but the vertical seat is right,
|
|
362
|
+
* which is what stops it appearing in the wrong place for a frame. The
|
|
363
|
+
* second has a real width and finishes the clamp.
|
|
364
|
+
*/
|
|
365
|
+
const placeKwMenu = () => {
|
|
366
|
+
const panel = kwMenuRef.current;
|
|
367
|
+
const trigger = kwTriggerRef.current;
|
|
368
|
+
if (!panel || !trigger) return;
|
|
369
|
+
const seat = trigger.getBoundingClientRect();
|
|
370
|
+
const gap = 8;
|
|
371
|
+
const width = panel.getBoundingClientRect().width;
|
|
372
|
+
panel.style.left = `${Math.max(gap, Math.min(seat.left, window.innerWidth - width - gap))}px`;
|
|
373
|
+
panel.style.top = `${seat.bottom + gap}px`;
|
|
374
|
+
panel.style.maxHeight = `${Math.max(120, window.innerHeight - seat.bottom - gap * 3)}px`;
|
|
375
|
+
};
|
|
376
|
+
|
|
377
|
+
// A fixed panel does not travel with the trigger, so it is re-seated rather
|
|
378
|
+
// than left behind. Only while open — there is nothing to follow otherwise.
|
|
379
|
+
useEffect(() => {
|
|
380
|
+
if (!kwMenuOpen) return;
|
|
381
|
+
const reseat = () => placeKwMenu();
|
|
382
|
+
// Capturing: the scroll may be any ancestor's, including `.filter-row`'s.
|
|
383
|
+
window.addEventListener("scroll", reseat, { capture: true, passive: true });
|
|
384
|
+
window.addEventListener("resize", reseat);
|
|
385
|
+
return () => {
|
|
386
|
+
window.removeEventListener("scroll", reseat, { capture: true });
|
|
387
|
+
window.removeEventListener("resize", reseat);
|
|
388
|
+
};
|
|
389
|
+
}, [kwMenuOpen]);
|
|
390
|
+
|
|
332
391
|
/**
|
|
333
392
|
* How many keyword chips actually fit on the row, measured.
|
|
334
393
|
*
|
|
@@ -399,9 +458,26 @@ export default function Catalog({
|
|
|
399
458
|
* shape that makes a layout thrash, and this runs per keystroke.
|
|
400
459
|
*/
|
|
401
460
|
useLayoutEffect(() => {
|
|
461
|
+
// Undo whatever the last pass left on the chips before measuring
|
|
462
|
+
// anything. Two reasons, and both were visible: `getBoundingClientRect`
|
|
463
|
+
// reports the *translated* box, so a chip caught mid-slide would be
|
|
464
|
+
// measured where it is drawn rather than where it belongs and the next
|
|
465
|
+
// inversion would compound that error; and a chip whose play frame never
|
|
466
|
+
// ran is still carrying `transition: none` with an offset, which is a chip
|
|
467
|
+
// frozen off its seat. Clearing here is what unfreezes it.
|
|
468
|
+
//
|
|
469
|
+
// Mid-slide is not a rare case: the fit measurement above commits a second
|
|
470
|
+
// time whenever the rescore changes how many chips fit, and that commit
|
|
471
|
+
// lands between this one and its animation frame.
|
|
472
|
+
for (const el of railRefs.current.values()) {
|
|
473
|
+
el.style.transition = "";
|
|
474
|
+
el.style.translate = "";
|
|
475
|
+
}
|
|
402
476
|
const previous = railRects.current;
|
|
403
477
|
const current = new Map<string, DOMRect>();
|
|
404
478
|
const moved: { el: HTMLElement; dx: number; dy: number }[] = [];
|
|
479
|
+
// A second pass, deliberately: every write above is flushed before the
|
|
480
|
+
// first read below, rather than interleaving them per chip.
|
|
405
481
|
for (const [keyword, el] of railRefs.current) {
|
|
406
482
|
const rect = el.getBoundingClientRect();
|
|
407
483
|
current.set(keyword, rect);
|
|
@@ -423,7 +499,19 @@ export default function Catalog({
|
|
|
423
499
|
el.style.translate = "";
|
|
424
500
|
}
|
|
425
501
|
});
|
|
426
|
-
return () =>
|
|
502
|
+
return () => {
|
|
503
|
+
cancelAnimationFrame(frame);
|
|
504
|
+
// Cancelling is not enough on its own. Nothing else takes these off, so
|
|
505
|
+
// a commit landing before the frame ran would leave every moved chip
|
|
506
|
+
// sitting at its inverted offset with transitions disabled — the rail
|
|
507
|
+
// stopping halfway and staying there. Deselecting the last keyword is
|
|
508
|
+
// the reliable way to see it: the rescore is at its largest, so the fit
|
|
509
|
+
// changes and the extra commit always lands.
|
|
510
|
+
for (const { el } of moved) {
|
|
511
|
+
el.style.transition = "";
|
|
512
|
+
el.style.translate = "";
|
|
513
|
+
}
|
|
514
|
+
};
|
|
427
515
|
});
|
|
428
516
|
|
|
429
517
|
/** Move focus `delta` cards along, clamping at both ends rather than wrapping. */
|
|
@@ -961,14 +1049,42 @@ export default function Catalog({
|
|
|
961
1049
|
// catalog's keyword vocabulary is open-ended, and a few hundred
|
|
962
1050
|
// chips at once is a wall, not a control.
|
|
963
1051
|
//
|
|
964
|
-
// A
|
|
965
|
-
//
|
|
966
|
-
//
|
|
967
|
-
|
|
968
|
-
|
|
1052
|
+
// A popover, and not by preference: the panel used to be an
|
|
1053
|
+
// absolutely-positioned child of `.filter-row`, which is a scroll
|
|
1054
|
+
// container, so it was cropped to the row and stretched the row's
|
|
1055
|
+
// scroll extent — an invisible menu and two stray scrollbars. The
|
|
1056
|
+
// top layer is outside every ancestor's `overflow`. Escape and
|
|
1057
|
+
// light dismiss come with it; only the seat is ours to compute,
|
|
1058
|
+
// and that is `placeKwMenu` above.
|
|
1059
|
+
<div class="kw-menu">
|
|
1060
|
+
<button
|
|
1061
|
+
type="button"
|
|
1062
|
+
class="chip"
|
|
1063
|
+
data-slot="filter-chip"
|
|
1064
|
+
ref={kwTriggerRef}
|
|
1065
|
+
popovertarget={KEYWORD_MENU_ID}
|
|
1066
|
+
aria-expanded={kwMenuOpen}
|
|
1067
|
+
>
|
|
969
1068
|
+{menuKeywords.length} more
|
|
970
|
-
</
|
|
971
|
-
<div
|
|
1069
|
+
</button>
|
|
1070
|
+
<div
|
|
1071
|
+
class="kw-menu-panel"
|
|
1072
|
+
id={KEYWORD_MENU_ID}
|
|
1073
|
+
popover="auto"
|
|
1074
|
+
ref={kwMenuRef}
|
|
1075
|
+
// Both, and in this order: `beforetoggle` runs synchronously
|
|
1076
|
+
// inside the show steps, so the panel is seated before it is
|
|
1077
|
+
// ever painted; `toggle` runs after, when its width can
|
|
1078
|
+
// actually be measured for the clamp.
|
|
1079
|
+
onBeforeToggle={(e) => {
|
|
1080
|
+
setKwMenuOpen(e.newState === "open");
|
|
1081
|
+
placeKwMenu();
|
|
1082
|
+
}}
|
|
1083
|
+
onToggle={(e) => {
|
|
1084
|
+
setKwMenuOpen(e.newState === "open");
|
|
1085
|
+
placeKwMenu();
|
|
1086
|
+
}}
|
|
1087
|
+
>
|
|
972
1088
|
<input
|
|
973
1089
|
type="text"
|
|
974
1090
|
class="kw-menu-search"
|
|
@@ -996,7 +1112,38 @@ export default function Catalog({
|
|
|
996
1112
|
)}
|
|
997
1113
|
</div>
|
|
998
1114
|
</div>
|
|
999
|
-
</
|
|
1115
|
+
</div>
|
|
1116
|
+
)}
|
|
1117
|
+
{keywords.length > 0 && (
|
|
1118
|
+
// Lifts every keyword at once. Only rendered while there is
|
|
1119
|
+
// something to lift — a permanently visible control that does
|
|
1120
|
+
// nothing most of the time is a chip's width spent on nothing, and
|
|
1121
|
+
// this row is already the one that runs out of room first.
|
|
1122
|
+
//
|
|
1123
|
+
// Keywords only, deliberately. Escape clears the search and the
|
|
1124
|
+
// kinds along with them, and a button that quietly did the same
|
|
1125
|
+
// would undo a filter the reader did not ask about; the label
|
|
1126
|
+
// names exactly what it lifts.
|
|
1127
|
+
<button
|
|
1128
|
+
type="button"
|
|
1129
|
+
class="chip kw-clear"
|
|
1130
|
+
data-slot="filter-chip"
|
|
1131
|
+
title="Clear the keyword filters"
|
|
1132
|
+
onKeyDown={onChipKeyDown}
|
|
1133
|
+
onClick={(e) => {
|
|
1134
|
+
setKeywords([]);
|
|
1135
|
+
// This button is the last thing standing when it is pressed:
|
|
1136
|
+
// clearing the facets unmounts it, and focus would land on
|
|
1137
|
+
// `<body>`, sending a keyboard reader back to the top of the
|
|
1138
|
+
// document. `detail === 0` is a click synthesized by Enter or
|
|
1139
|
+
// Space, so a pointer user is left alone and a keyboard one
|
|
1140
|
+
// gets the toolbar's own anchor instead of nothing.
|
|
1141
|
+
if (e.detail === 0) searchRef.current?.focus();
|
|
1142
|
+
}}
|
|
1143
|
+
>
|
|
1144
|
+
<X size={13} aria-hidden="true" />
|
|
1145
|
+
clear {keywords.length}
|
|
1146
|
+
</button>
|
|
1000
1147
|
)}
|
|
1001
1148
|
{hasDeprecated && (
|
|
1002
1149
|
// A toggle, not a filter: `aria-pressed` rather than the `active`
|