@grimoire-rs/indexer 0.5.1 → 0.5.3

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 CHANGED
@@ -21,6 +21,130 @@ props `{ pkg }` → `{ pkg, compact }`.
21
21
 
22
22
  ## [Unreleased]
23
23
 
24
+ ## [0.5.3] - 2026-09-01
25
+
26
+ ### Added
27
+
28
+ - **Search is fuzzy, and reaches every field an index publishes.** It was a
29
+ case-insensitive substring test over the seven fields the island is handed, so
30
+ a typo matched nothing and a package could not be found by its licence,
31
+ vendor, repository, authors or documentation. A query now splits on spaces
32
+ into terms that are AND-combined and order-independent, and each may land on a
33
+ different key — `astro grimoire` finds a package whose keywords carry one word
34
+ and whose vendor carries the other. The full record set comes from
35
+ `/all.json`, already published and already a frozen public URL, so it costs
36
+ the island no payload: it and the matcher load on the first keystroke and not
37
+ before, as an 8.5 KB gzipped chunk nothing preloads. Until they land, and if
38
+ the fetch fails, the substring pass stands — the field is never dead.
39
+ - **`relevance`, a sort mode**, and the reason the fuzzy pass is worth having:
40
+ it orders by match score. It is offered, stored and server-rendered like every
41
+ other mode, and with no query to rank it answers alphabetically — the order
42
+ the catalog opens on anyway — so a reader can leave it set and have every
43
+ later search come back ranked.
44
+ - **A clear button in the search field.** Chromium and Safari draw one of their
45
+ own, in the UA's styling, in the same corner the `/` hint occupies, and it
46
+ cannot be restyled beyond hiding. So it is hidden and the control is rendered:
47
+ the hint's exact box, carrying an X instead of the key. The two never coexist,
48
+ and clicking it returns focus to the field.
49
+ - **`sitemap.xml`, and a `robots.txt` naming it.** Written by `buildSite` from
50
+ the package list it already holds: every package page stated once, with no
51
+ crawler obliged to render an island or scroll it. This site emitted neither
52
+ before, so the landing page was the only path to a detail page — and the
53
+ windowed catalog below would have made that path a thin one.
54
+ - **A `<noscript>` catalog on the landing page**, listing every package. Without
55
+ JavaScript the island never hydrates, so the reader would otherwise get one
56
+ slice of cards under a toolbar that does nothing.
57
+
58
+ ### Changed
59
+
60
+ - **The catalog builds a viewport of the index, not all of it.** At 500
61
+ packages it took 1.9s to appear for a reader whose stored view is the list and
62
+ 1.5s to switch views; both are now under 50ms, and the landing page goes from
63
+ 3.42MB to 795KB. The island builds one viewport's worth and *grows* the slice
64
+ as a sentinel below the list comes into view — a growing slice rather than
65
+ true virtualization, so an item that has been built stays built and find-in-page
66
+ keeps working over everything reached. The keyword rail's two geometry-reading
67
+ layout effects are gated on a signature of the visible chips rather than
68
+ running on every commit, and the filter, sort and rail chain is memoized.
69
+ - **The island is shipped only the fields a card renders**, through a new
70
+ `CardPackage` type and `cardPackage()` projection exported from
71
+ `lib/catalog.ts`. Astro serializes island props into an attribute on
72
+ `<astro-island>`, so every field handed to `<Catalog>` was paid for twice on
73
+ the landing page: at 250 packages the attribute was 323,044 bytes, 17.5% of
74
+ the page, most of it fields no card or row reads. It is 201,554 now (-37.6%).
75
+ Three Unstable-tier components take the narrower type — `PackageCard`,
76
+ `PackageRow` and `CardLogo`, props `{ pkg: CatalogPackage }` →
77
+ `{ pkg: CardPackage }`. An override reading `license`, `authors`, `vendor`,
78
+ `documentation`, `compatibility`, `revision`, `support`, `repository`,
79
+ `title`, `owner`, `schema`, `tags` or an unknown enrichment key off `pkg` now
80
+ fails to compile rather than rendering `undefined` in the browser; the detail
81
+ pages are untouched, and read the full record as before.
82
+ - **The list view's columns are sized for the description.** The two marks are
83
+ `min-content` rather than `auto` and the name is `fit-content(14rem)` rather
84
+ than `minmax(8rem, 14rem)` — that 8rem floor made a list of short names pay a
85
+ fixed 8rem, so the description started after a column of empty space. The
86
+ row's gutter drops a step with them.
87
+
88
+ ### Fixed
89
+
90
+ - **The list view's rows lost their subgrid columns.** `content-visibility:
91
+ auto`, added as a paint bound, applies size containment — and a size-contained
92
+ element cannot be a subgrid, so `grid-template-columns: subgrid` degraded to
93
+ `none` in silence and every row computed its own equal-sixths grid. Every cell
94
+ lined up perfectly and the alignment was fake. The bound comes off; what it
95
+ was aimed at is held by `loading="lazy"` on the logo and by the window above.
96
+ - **The agent badge cleared WCAG AA.** `--grim-color-kind-agent` was `#b0641a`,
97
+ 4.484:1 against the white card and so under AA's 4.5 for the 11.5px badge it
98
+ tints; it is `#a05c17` now, 5.20:1. Its four siblings were audited at the same
99
+ time and clear it unaided, so they are unchanged, and so is the dark palette.
100
+ - **A stored `table` view no longer flips after the first paint.** The pre-paint
101
+ gate listed the sort, dir and deprecated preferences only, so a reader whose
102
+ stored view is the list got the server's cards painted first and the island's
103
+ table a moment later. `?kw=` had the same gap on the other half of the
104
+ condition — the parameter a keyword chip on a package page links to was never
105
+ checked. Both lists are pinned by a test now.
106
+ - **The sort control's focus ring stays off a mouse click.** Chromium matches
107
+ `:focus-visible` on a `<select>` after a plain click, so the accent ring lit on
108
+ click and stayed lit beside the thin neutral chips until the reader clicked
109
+ elsewhere. No selector distinguishes focus that arrived from a pointer, so the
110
+ element marks itself on `pointerdown` and a keypress or a blur clears it. The
111
+ keyboard path keeps both the ring and its focus.
112
+
113
+ ## [0.5.2] - 2026-08-31
114
+
115
+ ### Fixed
116
+
117
+ - **The sort control drew two borders when clicked.** Hover tints a control's
118
+ border to the accent and focus drew a 2px accent outline standing 1px clear
119
+ of it, so anyone who reached the control with a mouse had both at once — one
120
+ state reading as two lines with a gap between them. The ring merges onto the
121
+ border now, the way the card's focus state already did, and the offset comes
122
+ off every bordered control in the toolbar together rather than off the one
123
+ that showed it: the search field, the keyword overflow menu's search, both
124
+ sort halves and both view picks. Keyword chips gain the same ring, having
125
+ taken the browser's default until now.
126
+ - **A long address no longer wraps the card's head onto a second line.** A
127
+ namespace breaks at its own slashes and dots, so a wide one took two rows and
128
+ left the card taller than its neighbours with the tail of the address against
129
+ the padding edge. It stays on one line and the overflow is trimmed from the
130
+ *front* — the registry host is on every address in an index and the
131
+ repository at the tail is what tells two apart — with the whole of it in the
132
+ element's `title`.
133
+ - **Keyword chips could stutter, or stop part-way through the rail's slide.**
134
+ The rail's FLIP pass inverted each chip with an inline `transition: none` and
135
+ a `translate`, then dropped both on the next animation frame; any commit
136
+ landing inside that window left the chip carrying the offset with its
137
+ transition disabled, and nothing else took those off. It also measured seats
138
+ with `getBoundingClientRect`, which reports where a chip is *drawn*, so a
139
+ chip caught mid-slide recorded its animated box and the next inversion
140
+ compounded the error instead of correcting it. Neither window was rare: the
141
+ rail's own fit measurement re-commits whenever a rescore changes how many
142
+ chips fit. Seats now come from `offsetLeft`/`offsetTop`, which ignore
143
+ transforms and scroll, and the slide is a Web Animation — it starts without a
144
+ frame, writes nothing to `style`, and clears itself when it finishes or is
145
+ cancelled. `prefers-reduced-motion` is honoured by the effect rather than by
146
+ the stylesheet, and `--grim-duration-slow` is still its length.
147
+
24
148
  ## [0.5.1] - 2026-08-31
25
149
 
26
150
  ### Added
@@ -265,6 +389,8 @@ props `{ pkg }` → `{ pkg, compact }`.
265
389
  boot can leave a `.index-*` holding Vite's `deps_temp_<hash>`, which the
266
390
  dependency optimizer recreates after the removal has already returned.
267
391
 
268
- [Unreleased]: https://github.com/grimoire-rs/indexer/compare/v0.5.1...HEAD
392
+ [Unreleased]: https://github.com/grimoire-rs/indexer/compare/v0.5.3...HEAD
393
+ [0.5.3]: https://github.com/grimoire-rs/indexer/compare/v0.5.2...v0.5.3
394
+ [0.5.2]: https://github.com/grimoire-rs/indexer/compare/v0.5.1...v0.5.2
269
395
  [0.5.1]: https://github.com/grimoire-rs/indexer/compare/v0.5.0...v0.5.1
270
396
  [0.5.0]: https://github.com/grimoire-rs/indexer/compare/v0.4.4...v0.5.0
@@ -1,5 +1,5 @@
1
- import type { CatalogPackage } from "../lib/catalog.js";
1
+ import type { CardPackage } from "../lib/catalog.js";
2
2
  export declare function CardLogo({ pkg }: {
3
- pkg: CatalogPackage;
3
+ pkg: CardPackage;
4
4
  }): import("preact").JSX.Element;
5
5
  //# sourceMappingURL=CardLogo.d.ts.map
@@ -7,7 +7,7 @@
7
7
  import { useEffect, useRef, useState } from "preact/hooks";
8
8
  import { Image, ImageOff } from "lucide-preact";
9
9
  import { withBase } from "../lib/base.js";
10
- import type { CatalogPackage } from "../lib/catalog.js";
10
+ import type { CardPackage } from "../lib/catalog.js";
11
11
 
12
12
  export /**
13
13
  * The card's 28px logo slot, in its three states.
@@ -24,7 +24,7 @@ export /**
24
24
  * so it opts into the global handler in `Base.astro` instead — keep the two
25
25
  * placeholders looking alike.
26
26
  */
27
- function CardLogo({ pkg }: { pkg: CatalogPackage }) {
27
+ function CardLogo({ pkg }: { pkg: CardPackage }) {
28
28
  const [state, setState] = useState<"loading" | "ready" | "broken">("loading");
29
29
  const imgRef = useRef<HTMLImageElement>(null);
30
30
 
@@ -1,5 +1,13 @@
1
- import { type CatalogPackage } from "../lib/catalog.js";
2
- export type Sort = "name" | "updated" | "rating";
1
+ import { type CardPackage } from "../lib/catalog.js";
2
+ /**
3
+ * `relevance` orders by how well each package answered the query on screen,
4
+ * where the other three order by something every package carries. It is
5
+ * offered and stored like any of them even so: with no query it has nothing
6
+ * to rank, and `CHAINS.relevance` answers that with alphabetical — the order
7
+ * the catalog opens on anyway — so a reader can leave the catalog set to it
8
+ * and have every later search come back ranked without touching the control.
9
+ */
10
+ export type Sort = "name" | "updated" | "rating" | "relevance";
3
11
  export type Dir = "asc" | "desc";
4
12
  /** Roomy cards, or the same packages as a scannable list. */
5
13
  export type View = "cards" | "table";
@@ -13,9 +21,9 @@ export type View = "cards" | "table";
13
21
  * order actually is rather than which way a flag is set.
14
22
  */
15
23
  export declare const NATURAL: Record<Sort, Dir>;
16
- export declare function compare(a: CatalogPackage, b: CatalogPackage, sort: Sort, dir?: Dir): number;
24
+ export declare function compare(a: CardPackage, b: CardPackage, sort: Sort, dir?: Dir): number;
17
25
  export default function Catalog({ packages, vscodeExtension, }: {
18
- packages: CatalogPackage[];
26
+ packages: CardPackage[];
19
27
  vscodeExtension: string | null;
20
28
  }): import("preact").JSX.Element;
21
29
  //# sourceMappingURL=Catalog.d.ts.map