@grimoire-rs/indexer 0.1.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/LICENSE +201 -0
- package/README.md +48 -0
- package/dist/cli/build.d.ts +6 -0
- package/dist/cli/build.d.ts.map +1 -0
- package/dist/cli/build.js +29 -0
- package/dist/cli/build.js.map +1 -0
- package/dist/cli/exit.d.ts +28 -0
- package/dist/cli/exit.d.ts.map +1 -0
- package/dist/cli/exit.js +33 -0
- package/dist/cli/exit.js.map +1 -0
- package/dist/cli/index.d.ts +3 -0
- package/dist/cli/index.d.ts.map +1 -0
- package/dist/cli/index.js +8 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/cli/init.d.ts +40 -0
- package/dist/cli/init.d.ts.map +1 -0
- package/dist/cli/init.js +317 -0
- package/dist/cli/init.js.map +1 -0
- package/dist/cli/main.d.ts +2 -0
- package/dist/cli/main.d.ts.map +1 -0
- package/dist/cli/main.js +112 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/validate.d.ts +18 -0
- package/dist/cli/validate.d.ts.map +1 -0
- package/dist/cli/validate.js +139 -0
- package/dist/cli/validate.js.map +1 -0
- package/dist/config.d.ts +76 -0
- package/dist/config.d.ts.map +1 -0
- package/dist/config.js +134 -0
- package/dist/config.js.map +1 -0
- package/dist/data/index.d.ts +40 -0
- package/dist/data/index.d.ts.map +1 -0
- package/dist/data/index.js +103 -0
- package/dist/data/index.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -0
- package/dist/integration.d.ts +2 -0
- package/dist/integration.d.ts.map +1 -0
- package/dist/integration.js +4 -0
- package/dist/integration.js.map +1 -0
- package/dist/renderer/astro/components/Catalog.d.ts +6 -0
- package/dist/renderer/astro/components/Catalog.d.ts.map +1 -0
- package/dist/renderer/astro/components/Catalog.js +73 -0
- package/dist/renderer/astro/components/Catalog.js.map +1 -0
- package/dist/renderer/astro/components/Catalog.tsx +256 -0
- package/dist/renderer/astro/components/CopyButton.astro +24 -0
- package/dist/renderer/astro/components/VersionMenu.astro +105 -0
- package/dist/renderer/astro/content.config.ts +30 -0
- package/dist/renderer/astro/layouts/Base.astro +623 -0
- package/dist/renderer/astro/lib/catalog.d.ts +7 -0
- package/dist/renderer/astro/lib/catalog.d.ts.map +1 -0
- package/dist/renderer/astro/lib/catalog.js +61 -0
- package/dist/renderer/astro/lib/catalog.js.map +1 -0
- package/dist/renderer/astro/lib/catalog.ts +69 -0
- package/dist/renderer/astro/lib/data.d.ts +3 -0
- package/dist/renderer/astro/lib/data.d.ts.map +1 -0
- package/dist/renderer/astro/lib/data.js +4 -0
- package/dist/renderer/astro/lib/data.js.map +1 -0
- package/dist/renderer/astro/lib/data.ts +12 -0
- package/dist/renderer/astro/pages/index.astro +69 -0
- package/dist/renderer/astro/pages/p/[...slug].astro +367 -0
- package/dist/renderer/index.d.ts +20 -0
- package/dist/renderer/index.d.ts.map +1 -0
- package/dist/renderer/index.js +192 -0
- package/dist/renderer/index.js.map +1 -0
- package/dist/renderer/public/favicon.svg +4 -0
- package/dist/renderer/types.d.ts +34 -0
- package/dist/renderer/types.d.ts.map +1 -0
- package/dist/renderer/types.js +4 -0
- package/dist/renderer/types.js.map +1 -0
- package/dist/validate/adapters/files.d.ts +17 -0
- package/dist/validate/adapters/files.d.ts.map +1 -0
- package/dist/validate/adapters/files.js +50 -0
- package/dist/validate/adapters/files.js.map +1 -0
- package/dist/validate/adapters/forge.d.ts +25 -0
- package/dist/validate/adapters/forge.d.ts.map +1 -0
- package/dist/validate/adapters/forge.js +100 -0
- package/dist/validate/adapters/forge.js.map +1 -0
- package/dist/validate/adapters/http.d.ts +24 -0
- package/dist/validate/adapters/http.d.ts.map +1 -0
- package/dist/validate/adapters/http.js +75 -0
- package/dist/validate/adapters/http.js.map +1 -0
- package/dist/validate/adapters/registry.d.ts +16 -0
- package/dist/validate/adapters/registry.d.ts.map +1 -0
- package/dist/validate/adapters/registry.js +91 -0
- package/dist/validate/adapters/registry.js.map +1 -0
- package/dist/validate/core/metadata.d.ts +67 -0
- package/dist/validate/core/metadata.d.ts.map +1 -0
- package/dist/validate/core/metadata.js +149 -0
- package/dist/validate/core/metadata.js.map +1 -0
- package/dist/validate/core/ownership.d.ts +43 -0
- package/dist/validate/core/ownership.d.ts.map +1 -0
- package/dist/validate/core/ownership.js +33 -0
- package/dist/validate/core/ownership.js.map +1 -0
- package/dist/validate/core/paths.d.ts +21 -0
- package/dist/validate/core/paths.d.ts.map +1 -0
- package/dist/validate/core/paths.js +34 -0
- package/dist/validate/core/paths.js.map +1 -0
- package/dist/validate/index.d.ts +40 -0
- package/dist/validate/index.d.ts.map +1 -0
- package/dist/validate/index.js +206 -0
- package/dist/validate/index.js.map +1 -0
- package/package.json +50 -0
- package/templates/README.md +48 -0
- package/templates/github-pages.yml +24 -0
- package/templates/github-validate.yml +36 -0
- package/templates/gitignore +9 -0
- package/templates/gitlab-ci.yml +13 -0
- package/templates/publish.toml +17 -0
- package/templates/reusable/gitlab-index-ci.yml +61 -0
- package/templates/reusable/index-pages.yml +80 -0
- package/templates/reusable/index-validate.yml +88 -0
|
@@ -0,0 +1,623 @@
|
|
|
1
|
+
---
|
|
2
|
+
// Shell for every page: head, header, footer, and the whole default style
|
|
3
|
+
// sheet. Everything in the global block sits in `@layer grimoire`, so a
|
|
4
|
+
// user CSS file (unlayered) wins over any of it regardless of specificity
|
|
5
|
+
// or injection order — that layer is the entire theming contract.
|
|
6
|
+
import { data } from "../lib/data";
|
|
7
|
+
|
|
8
|
+
interface Props {
|
|
9
|
+
title: string;
|
|
10
|
+
description: string;
|
|
11
|
+
image?: string;
|
|
12
|
+
}
|
|
13
|
+
const { config, css } = data;
|
|
14
|
+
const { title, description, image = config.favicon } = Astro.props;
|
|
15
|
+
// The mark is styled separately, so it only applies when it really is the
|
|
16
|
+
// leading run of the brand — otherwise the header renders the plain text.
|
|
17
|
+
const brandRest =
|
|
18
|
+
config.brandMark && config.brand.startsWith(config.brandMark)
|
|
19
|
+
? config.brand.slice(config.brandMark.length)
|
|
20
|
+
: null;
|
|
21
|
+
---
|
|
22
|
+
|
|
23
|
+
<html lang="en">
|
|
24
|
+
<head>
|
|
25
|
+
<meta charset="utf-8" />
|
|
26
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
27
|
+
<meta name="description" content={description} />
|
|
28
|
+
<link rel="icon" href={config.favicon} type="image/svg+xml" />
|
|
29
|
+
<title>{title}</title>
|
|
30
|
+
<meta property="og:title" content={title} />
|
|
31
|
+
<meta property="og:description" content={description} />
|
|
32
|
+
<meta property="og:image" content={image} />
|
|
33
|
+
<meta name="twitter:card" content="summary" />
|
|
34
|
+
<script is:inline>
|
|
35
|
+
// Before first paint: stored preference wins, else system scheme.
|
|
36
|
+
document.documentElement.dataset.theme =
|
|
37
|
+
localStorage.getItem("theme") ??
|
|
38
|
+
(matchMedia("(prefers-color-scheme: dark)").matches
|
|
39
|
+
? "dark"
|
|
40
|
+
: "light");
|
|
41
|
+
</script>
|
|
42
|
+
</head>
|
|
43
|
+
<body>
|
|
44
|
+
<header>
|
|
45
|
+
<div class="shell header-row">
|
|
46
|
+
<a class="brand" href="/">
|
|
47
|
+
{
|
|
48
|
+
brandRest === null ? (
|
|
49
|
+
config.brand
|
|
50
|
+
) : (
|
|
51
|
+
<Fragment>
|
|
52
|
+
<span class="brand-mark">{config.brandMark}</span>
|
|
53
|
+
{brandRest}
|
|
54
|
+
</Fragment>
|
|
55
|
+
)
|
|
56
|
+
}
|
|
57
|
+
</a>
|
|
58
|
+
<nav>
|
|
59
|
+
{config.docsUrl && <a href={config.docsUrl}>docs</a>}
|
|
60
|
+
{
|
|
61
|
+
config.repoUrl && (
|
|
62
|
+
<a href={config.repoUrl} target="_blank" rel="noopener noreferrer">
|
|
63
|
+
GitHub
|
|
64
|
+
</a>
|
|
65
|
+
)
|
|
66
|
+
}
|
|
67
|
+
<button id="theme-toggle" type="button" aria-label="Toggle theme">
|
|
68
|
+
<span class="when-light" aria-hidden="true">🌙</span>
|
|
69
|
+
<span class="when-dark" aria-hidden="true">☀️</span>
|
|
70
|
+
</button>
|
|
71
|
+
</nav>
|
|
72
|
+
</div>
|
|
73
|
+
</header>
|
|
74
|
+
|
|
75
|
+
<main class="shell">
|
|
76
|
+
<slot />
|
|
77
|
+
</main>
|
|
78
|
+
|
|
79
|
+
<footer>
|
|
80
|
+
<div class="shell">
|
|
81
|
+
<p>
|
|
82
|
+
Raw data: <a href="/all.json"><code>/all.json</code></a>{
|
|
83
|
+
config.footerNote ? ` · ${config.footerNote}` : ""
|
|
84
|
+
}
|
|
85
|
+
</p>
|
|
86
|
+
</div>
|
|
87
|
+
</footer>
|
|
88
|
+
|
|
89
|
+
<script is:inline>
|
|
90
|
+
document.getElementById("theme-toggle").addEventListener("click", () => {
|
|
91
|
+
const root = document.documentElement;
|
|
92
|
+
const next = root.dataset.theme === "dark" ? "light" : "dark";
|
|
93
|
+
root.dataset.theme = next;
|
|
94
|
+
localStorage.setItem("theme", next);
|
|
95
|
+
});
|
|
96
|
+
|
|
97
|
+
for (const btn of document.querySelectorAll("[data-copy]")) {
|
|
98
|
+
// Read the label up front: re-reading it inside the handler snapshots
|
|
99
|
+
// "copied" when the button is clicked twice inside the 1500ms window.
|
|
100
|
+
const label = btn.querySelector("span");
|
|
101
|
+
const original = label?.textContent ?? "copy";
|
|
102
|
+
btn.addEventListener("click", () => {
|
|
103
|
+
navigator.clipboard.writeText(btn.dataset.copy ?? "").then(() => {
|
|
104
|
+
btn.classList.add("copied");
|
|
105
|
+
if (label) label.textContent = "copied";
|
|
106
|
+
setTimeout(() => {
|
|
107
|
+
btn.classList.remove("copied");
|
|
108
|
+
if (label) label.textContent = original;
|
|
109
|
+
}, 1500);
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
}
|
|
113
|
+
</script>
|
|
114
|
+
|
|
115
|
+
<style is:global>
|
|
116
|
+
/* THE THEMING CONTRACT — these custom properties are the whole
|
|
117
|
+
customization surface. There is no component-override API.
|
|
118
|
+
|
|
119
|
+
Everything the renderer ships is layered. Unlayered CSS — i.e. any
|
|
120
|
+
user override file — beats a layered declaration outright, so a
|
|
121
|
+
single `:root { --accent: … }` wins in light AND dark without
|
|
122
|
+
!important and without knowing where Astro injects its bundle.
|
|
123
|
+
Redeclare under `[data-theme="dark"]` to differ per scheme.
|
|
124
|
+
|
|
125
|
+
surface --bg --fg --card --border --muted --chip-bg
|
|
126
|
+
accent --accent --accent-soft --on-accent
|
|
127
|
+
kinds --kind-skill --kind-rule --kind-agent --kind-mcp
|
|
128
|
+
--kind-bundle
|
|
129
|
+
states --deprecated --banner-bg --banner-fg --banner-border
|
|
130
|
+
|
|
131
|
+
Every one is declared in both schemes below; `color-scheme` rides
|
|
132
|
+
along so form controls and scrollbars follow. Adding a token is
|
|
133
|
+
additive, removing or renaming one is a breaking change. */
|
|
134
|
+
@layer grimoire {
|
|
135
|
+
:root {
|
|
136
|
+
--bg: #f7f6f3;
|
|
137
|
+
--fg: #1d1c1a;
|
|
138
|
+
--muted: #6d6a63;
|
|
139
|
+
--card: #ffffff;
|
|
140
|
+
--border: #dedbd3;
|
|
141
|
+
--accent: #6d4fc4;
|
|
142
|
+
--accent-soft: #efeafd;
|
|
143
|
+
--chip-bg: #edebe5;
|
|
144
|
+
--on-accent: #ffffff;
|
|
145
|
+
--kind-skill: #6d4fc4;
|
|
146
|
+
--kind-rule: #1a7f6b;
|
|
147
|
+
--kind-agent: #b0641a;
|
|
148
|
+
--kind-mcp: #2565c7;
|
|
149
|
+
--kind-bundle: #a63d68;
|
|
150
|
+
/* ~5.7:1 on --card (white) */
|
|
151
|
+
--deprecated: #9c5400;
|
|
152
|
+
--banner-bg: #fff3cd;
|
|
153
|
+
--banner-fg: #6b4c00;
|
|
154
|
+
--banner-border: #e0b84c;
|
|
155
|
+
color-scheme: light;
|
|
156
|
+
}
|
|
157
|
+
[data-theme="dark"] {
|
|
158
|
+
--bg: #16151a;
|
|
159
|
+
--fg: #e8e6e1;
|
|
160
|
+
--muted: #98948b;
|
|
161
|
+
--card: #201f26;
|
|
162
|
+
--border: #35333d;
|
|
163
|
+
--accent: #a58cf0;
|
|
164
|
+
--accent-soft: #2c2540;
|
|
165
|
+
--chip-bg: #2a2931;
|
|
166
|
+
--on-accent: #ffffff;
|
|
167
|
+
--kind-skill: #a58cf0;
|
|
168
|
+
--kind-rule: #4cc2a9;
|
|
169
|
+
--kind-agent: #e0a35c;
|
|
170
|
+
--kind-mcp: #6fa8f5;
|
|
171
|
+
--kind-bundle: #e07ba6;
|
|
172
|
+
/* ~7.6:1 on --card (#201f26) */
|
|
173
|
+
--deprecated: #e3a640;
|
|
174
|
+
--banner-bg: #4a3b0a;
|
|
175
|
+
--banner-fg: #f0d78c;
|
|
176
|
+
--banner-border: #8a6d1a;
|
|
177
|
+
color-scheme: dark;
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
* {
|
|
181
|
+
box-sizing: border-box;
|
|
182
|
+
}
|
|
183
|
+
body {
|
|
184
|
+
margin: 0;
|
|
185
|
+
min-height: 100vh;
|
|
186
|
+
display: flex;
|
|
187
|
+
flex-direction: column;
|
|
188
|
+
background: var(--bg);
|
|
189
|
+
color: var(--fg);
|
|
190
|
+
font-family:
|
|
191
|
+
system-ui,
|
|
192
|
+
-apple-system,
|
|
193
|
+
"Segoe UI",
|
|
194
|
+
sans-serif;
|
|
195
|
+
line-height: 1.55;
|
|
196
|
+
}
|
|
197
|
+
.shell {
|
|
198
|
+
width: min(72rem, 100% - 2.5rem);
|
|
199
|
+
margin-inline: auto;
|
|
200
|
+
}
|
|
201
|
+
main.shell {
|
|
202
|
+
flex: 1;
|
|
203
|
+
padding-block: 1.5rem 3rem;
|
|
204
|
+
}
|
|
205
|
+
a {
|
|
206
|
+
color: var(--accent);
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
header {
|
|
210
|
+
border-bottom: 1px solid var(--border);
|
|
211
|
+
background: var(--card);
|
|
212
|
+
}
|
|
213
|
+
.header-row {
|
|
214
|
+
display: flex;
|
|
215
|
+
align-items: center;
|
|
216
|
+
justify-content: space-between;
|
|
217
|
+
padding-block: 0.8rem;
|
|
218
|
+
gap: 1rem;
|
|
219
|
+
}
|
|
220
|
+
.brand {
|
|
221
|
+
color: var(--fg);
|
|
222
|
+
text-decoration: none;
|
|
223
|
+
font-weight: 600;
|
|
224
|
+
font-size: 1.05rem;
|
|
225
|
+
}
|
|
226
|
+
.brand-mark {
|
|
227
|
+
color: var(--accent);
|
|
228
|
+
font-family: ui-monospace, "SFMono-Regular", monospace;
|
|
229
|
+
}
|
|
230
|
+
nav {
|
|
231
|
+
display: flex;
|
|
232
|
+
align-items: center;
|
|
233
|
+
gap: 1rem;
|
|
234
|
+
}
|
|
235
|
+
nav a {
|
|
236
|
+
color: var(--muted);
|
|
237
|
+
text-decoration: none;
|
|
238
|
+
}
|
|
239
|
+
nav a:hover {
|
|
240
|
+
color: var(--fg);
|
|
241
|
+
}
|
|
242
|
+
#theme-toggle {
|
|
243
|
+
border: 1px solid var(--border);
|
|
244
|
+
background: transparent;
|
|
245
|
+
border-radius: 999px;
|
|
246
|
+
padding: 0.25rem 0.5rem;
|
|
247
|
+
cursor: pointer;
|
|
248
|
+
font-size: 0.9rem;
|
|
249
|
+
line-height: 1;
|
|
250
|
+
}
|
|
251
|
+
[data-theme="dark"] .when-light,
|
|
252
|
+
[data-theme="light"] .when-dark {
|
|
253
|
+
display: none;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
.hero {
|
|
257
|
+
display: grid;
|
|
258
|
+
/* fit-content: install column takes what its rows need, but can
|
|
259
|
+
shrink below content width (commands scroll) before squeezing
|
|
260
|
+
the text column out. h1 spans the full row; paragraph and
|
|
261
|
+
install strip share the second row, top-aligned. */
|
|
262
|
+
grid-template-columns: 1fr fit-content(44rem);
|
|
263
|
+
align-items: start;
|
|
264
|
+
gap: 0.75rem 2rem;
|
|
265
|
+
margin-block: 1rem 1.5rem;
|
|
266
|
+
}
|
|
267
|
+
.hero h1 {
|
|
268
|
+
grid-column: 1 / -1;
|
|
269
|
+
margin: 0;
|
|
270
|
+
font-size: 1.6rem;
|
|
271
|
+
}
|
|
272
|
+
.hero p {
|
|
273
|
+
margin: 0;
|
|
274
|
+
color: var(--muted);
|
|
275
|
+
max-width: 46rem;
|
|
276
|
+
}
|
|
277
|
+
@media (max-width: 64rem) {
|
|
278
|
+
.hero {
|
|
279
|
+
grid-template-columns: 1fr;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
.hero code {
|
|
283
|
+
background: var(--chip-bg);
|
|
284
|
+
border-radius: 4px;
|
|
285
|
+
padding: 0.1rem 0.35rem;
|
|
286
|
+
font-size: 0.9em;
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
.install {
|
|
290
|
+
display: grid;
|
|
291
|
+
/* One track set for all rows so the commands start at the same x
|
|
292
|
+
regardless of OS-label width; rows pick it up via subgrid. */
|
|
293
|
+
grid-template-columns: auto 1fr auto;
|
|
294
|
+
gap: 0.5rem;
|
|
295
|
+
min-width: 0;
|
|
296
|
+
}
|
|
297
|
+
.install-row {
|
|
298
|
+
grid-column: 1 / -1;
|
|
299
|
+
display: grid;
|
|
300
|
+
grid-template-columns: subgrid;
|
|
301
|
+
align-items: center;
|
|
302
|
+
column-gap: 0.6rem;
|
|
303
|
+
background: var(--card);
|
|
304
|
+
border: 1px solid var(--border);
|
|
305
|
+
border-radius: 8px;
|
|
306
|
+
padding: 0.45rem 0.7rem;
|
|
307
|
+
}
|
|
308
|
+
.install-row .os {
|
|
309
|
+
color: var(--muted);
|
|
310
|
+
font-size: 0.78rem;
|
|
311
|
+
font-weight: 600;
|
|
312
|
+
text-transform: uppercase;
|
|
313
|
+
letter-spacing: 0.04em;
|
|
314
|
+
white-space: nowrap;
|
|
315
|
+
}
|
|
316
|
+
.install-row code {
|
|
317
|
+
background: none;
|
|
318
|
+
padding: 0;
|
|
319
|
+
font-size: 0.85rem;
|
|
320
|
+
overflow-x: auto;
|
|
321
|
+
white-space: nowrap;
|
|
322
|
+
/* still scrollable, no visible bar */
|
|
323
|
+
scrollbar-width: none;
|
|
324
|
+
}
|
|
325
|
+
.install-row code::-webkit-scrollbar {
|
|
326
|
+
display: none;
|
|
327
|
+
}
|
|
328
|
+
/* The `[[registries]]` snippet is the one multi-line command: let it
|
|
329
|
+
wrap inside its cell instead of scrolling a three-line block. */
|
|
330
|
+
.install-row code.block {
|
|
331
|
+
white-space: pre;
|
|
332
|
+
line-height: 1.35;
|
|
333
|
+
}
|
|
334
|
+
@media (max-width: 40rem) {
|
|
335
|
+
.install {
|
|
336
|
+
grid-template-columns: 1fr auto;
|
|
337
|
+
}
|
|
338
|
+
.install-row .os {
|
|
339
|
+
grid-column: 1 / -1;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
.controls {
|
|
344
|
+
display: flex;
|
|
345
|
+
flex-wrap: wrap;
|
|
346
|
+
align-items: center;
|
|
347
|
+
gap: 0.75rem;
|
|
348
|
+
margin-bottom: 1.25rem;
|
|
349
|
+
}
|
|
350
|
+
.controls input[type="search"] {
|
|
351
|
+
flex: 1 1 16rem;
|
|
352
|
+
padding: 0.55rem 0.8rem;
|
|
353
|
+
border: 1px solid var(--border);
|
|
354
|
+
border-radius: 8px;
|
|
355
|
+
background: var(--card);
|
|
356
|
+
color: var(--fg);
|
|
357
|
+
font-size: 0.95rem;
|
|
358
|
+
}
|
|
359
|
+
.controls input[type="search"]:focus-visible {
|
|
360
|
+
outline: 2px solid var(--accent);
|
|
361
|
+
outline-offset: 1px;
|
|
362
|
+
}
|
|
363
|
+
.chips {
|
|
364
|
+
display: flex;
|
|
365
|
+
flex-wrap: wrap;
|
|
366
|
+
gap: 0.4rem;
|
|
367
|
+
}
|
|
368
|
+
.chip {
|
|
369
|
+
border: 1px solid var(--border);
|
|
370
|
+
background: var(--chip-bg);
|
|
371
|
+
color: var(--fg);
|
|
372
|
+
border-radius: 999px;
|
|
373
|
+
padding: 0.25rem 0.7rem;
|
|
374
|
+
font-size: 0.85rem;
|
|
375
|
+
transition: border-color 150ms ease;
|
|
376
|
+
cursor: pointer;
|
|
377
|
+
}
|
|
378
|
+
.chip small {
|
|
379
|
+
color: var(--muted);
|
|
380
|
+
}
|
|
381
|
+
/* button-only: the "+N" overflow chip is a span and stays inert */
|
|
382
|
+
button.chip:hover {
|
|
383
|
+
border-color: var(--accent);
|
|
384
|
+
}
|
|
385
|
+
.chip.active {
|
|
386
|
+
border-color: var(--accent);
|
|
387
|
+
background: var(--accent-soft);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
.grid {
|
|
391
|
+
list-style: none;
|
|
392
|
+
margin: 0;
|
|
393
|
+
padding: 0;
|
|
394
|
+
display: grid;
|
|
395
|
+
grid-template-columns: repeat(auto-fill, minmax(19rem, 1fr));
|
|
396
|
+
gap: 1rem;
|
|
397
|
+
}
|
|
398
|
+
.card {
|
|
399
|
+
display: flex;
|
|
400
|
+
flex-direction: column;
|
|
401
|
+
gap: 0.35rem;
|
|
402
|
+
background: var(--card);
|
|
403
|
+
border: 1px solid var(--border);
|
|
404
|
+
border-radius: 10px;
|
|
405
|
+
padding: 1rem 1.1rem;
|
|
406
|
+
/* Whole card navigates to the detail page via the stretched title
|
|
407
|
+
link below; real controls inside re-stack above the overlay. */
|
|
408
|
+
position: relative;
|
|
409
|
+
cursor: pointer;
|
|
410
|
+
transition: border-color 150ms ease;
|
|
411
|
+
}
|
|
412
|
+
/* Card highlight yields while an inner control is hovered, so its
|
|
413
|
+
own hover state reads as the click target instead. */
|
|
414
|
+
.card:hover:not(
|
|
415
|
+
:has(.keywords :hover, .copy-group :hover, .source:hover)
|
|
416
|
+
) {
|
|
417
|
+
border-color: var(--accent);
|
|
418
|
+
}
|
|
419
|
+
.card h2 a::after {
|
|
420
|
+
content: "";
|
|
421
|
+
position: absolute;
|
|
422
|
+
inset: 0;
|
|
423
|
+
}
|
|
424
|
+
.card .keywords,
|
|
425
|
+
.card .copy-group,
|
|
426
|
+
.card .source {
|
|
427
|
+
position: relative;
|
|
428
|
+
}
|
|
429
|
+
.card-head {
|
|
430
|
+
display: flex;
|
|
431
|
+
align-items: center;
|
|
432
|
+
gap: 0.6rem;
|
|
433
|
+
}
|
|
434
|
+
.card h2 {
|
|
435
|
+
flex: 1;
|
|
436
|
+
min-width: 0;
|
|
437
|
+
margin: 0;
|
|
438
|
+
font-size: 1.05rem;
|
|
439
|
+
font-family: ui-monospace, "SFMono-Regular", monospace;
|
|
440
|
+
word-break: break-word;
|
|
441
|
+
}
|
|
442
|
+
.card h2 a {
|
|
443
|
+
color: inherit;
|
|
444
|
+
text-decoration: none;
|
|
445
|
+
}
|
|
446
|
+
.card-logo {
|
|
447
|
+
flex-shrink: 0;
|
|
448
|
+
width: 28px;
|
|
449
|
+
height: 28px;
|
|
450
|
+
border-radius: 6px;
|
|
451
|
+
}
|
|
452
|
+
img.card-logo {
|
|
453
|
+
object-fit: contain;
|
|
454
|
+
background: var(--chip-bg);
|
|
455
|
+
}
|
|
456
|
+
.card-logo-fallback {
|
|
457
|
+
display: flex;
|
|
458
|
+
align-items: center;
|
|
459
|
+
justify-content: center;
|
|
460
|
+
color: var(--on-accent);
|
|
461
|
+
font-weight: 700;
|
|
462
|
+
font-size: 0.85rem;
|
|
463
|
+
font-family: ui-monospace, "SFMono-Regular", monospace;
|
|
464
|
+
}
|
|
465
|
+
.badge {
|
|
466
|
+
flex-shrink: 0;
|
|
467
|
+
font-size: 0.72rem;
|
|
468
|
+
font-weight: 600;
|
|
469
|
+
text-transform: uppercase;
|
|
470
|
+
letter-spacing: 0.04em;
|
|
471
|
+
border: 1px solid currentColor;
|
|
472
|
+
border-radius: 999px;
|
|
473
|
+
padding: 0.05rem 0.5rem;
|
|
474
|
+
color: var(--muted);
|
|
475
|
+
}
|
|
476
|
+
.kind-skill {
|
|
477
|
+
color: var(--kind-skill);
|
|
478
|
+
}
|
|
479
|
+
.kind-rule {
|
|
480
|
+
color: var(--kind-rule);
|
|
481
|
+
}
|
|
482
|
+
.kind-agent {
|
|
483
|
+
color: var(--kind-agent);
|
|
484
|
+
}
|
|
485
|
+
.kind-mcp {
|
|
486
|
+
color: var(--kind-mcp);
|
|
487
|
+
}
|
|
488
|
+
.kind-bundle {
|
|
489
|
+
color: var(--kind-bundle);
|
|
490
|
+
}
|
|
491
|
+
.badge.deprecated {
|
|
492
|
+
color: var(--deprecated);
|
|
493
|
+
}
|
|
494
|
+
.chip[class*="kind-"] {
|
|
495
|
+
color: var(--fg);
|
|
496
|
+
}
|
|
497
|
+
.namespace {
|
|
498
|
+
margin: 0;
|
|
499
|
+
color: var(--muted);
|
|
500
|
+
font-size: 0.82rem;
|
|
501
|
+
font-family: ui-monospace, "SFMono-Regular", monospace;
|
|
502
|
+
}
|
|
503
|
+
.meta-row {
|
|
504
|
+
display: flex;
|
|
505
|
+
flex-wrap: wrap;
|
|
506
|
+
align-items: center;
|
|
507
|
+
gap: 0.4rem;
|
|
508
|
+
}
|
|
509
|
+
.pill {
|
|
510
|
+
font-size: 0.78rem;
|
|
511
|
+
color: var(--muted);
|
|
512
|
+
border: 1px solid var(--border);
|
|
513
|
+
border-radius: 999px;
|
|
514
|
+
padding: 0.03rem 0.5rem;
|
|
515
|
+
}
|
|
516
|
+
.pill.version {
|
|
517
|
+
font-family: ui-monospace, "SFMono-Regular", monospace;
|
|
518
|
+
}
|
|
519
|
+
.updated {
|
|
520
|
+
font-size: 0.78rem;
|
|
521
|
+
color: var(--muted);
|
|
522
|
+
}
|
|
523
|
+
.deprecated-strip {
|
|
524
|
+
margin: 0;
|
|
525
|
+
font-size: 0.82rem;
|
|
526
|
+
color: var(--deprecated);
|
|
527
|
+
}
|
|
528
|
+
/* Long descriptions would stretch their whole grid row; clamp to 3
|
|
529
|
+
lines so cards stay uniform. Full text lives on the detail page. */
|
|
530
|
+
.description {
|
|
531
|
+
margin: 0;
|
|
532
|
+
font-size: 0.92rem;
|
|
533
|
+
/* `auto` basis, not `0`: overflow:hidden drops the min-height:auto
|
|
534
|
+
floor, so a 0-basis item can collapse in an auto-height column. */
|
|
535
|
+
flex: 1 1 auto;
|
|
536
|
+
display: -webkit-box;
|
|
537
|
+
-webkit-box-orient: vertical;
|
|
538
|
+
-webkit-line-clamp: 3;
|
|
539
|
+
line-clamp: 3;
|
|
540
|
+
overflow: hidden;
|
|
541
|
+
}
|
|
542
|
+
.keywords {
|
|
543
|
+
display: flex;
|
|
544
|
+
flex-wrap: wrap;
|
|
545
|
+
gap: 0.3rem;
|
|
546
|
+
}
|
|
547
|
+
.chip.keyword {
|
|
548
|
+
font-size: 0.72rem;
|
|
549
|
+
padding: 0.1rem 0.5rem;
|
|
550
|
+
color: var(--muted);
|
|
551
|
+
}
|
|
552
|
+
.chip.keyword.overflow {
|
|
553
|
+
cursor: default;
|
|
554
|
+
}
|
|
555
|
+
.card-foot {
|
|
556
|
+
display: flex;
|
|
557
|
+
align-items: center;
|
|
558
|
+
justify-content: space-between;
|
|
559
|
+
gap: 0.6rem;
|
|
560
|
+
margin-top: 0.5rem;
|
|
561
|
+
}
|
|
562
|
+
.copy-group {
|
|
563
|
+
display: flex;
|
|
564
|
+
gap: 0.4rem;
|
|
565
|
+
flex-wrap: wrap;
|
|
566
|
+
}
|
|
567
|
+
.copy {
|
|
568
|
+
display: inline-flex;
|
|
569
|
+
align-items: center;
|
|
570
|
+
gap: 0.32rem;
|
|
571
|
+
transition: border-color 150ms ease;
|
|
572
|
+
border: 1px solid var(--border);
|
|
573
|
+
background: var(--chip-bg);
|
|
574
|
+
color: var(--fg);
|
|
575
|
+
border-radius: 6px;
|
|
576
|
+
padding: 0.28rem 0.55rem;
|
|
577
|
+
font-size: 0.8rem;
|
|
578
|
+
font-family: ui-monospace, "SFMono-Regular", monospace;
|
|
579
|
+
cursor: pointer;
|
|
580
|
+
}
|
|
581
|
+
.copy:hover {
|
|
582
|
+
border-color: var(--accent);
|
|
583
|
+
}
|
|
584
|
+
.copy.copied {
|
|
585
|
+
color: var(--kind-rule);
|
|
586
|
+
border-color: var(--kind-rule);
|
|
587
|
+
}
|
|
588
|
+
/* card actions: icon-only square buttons. Scoped to .copy-group so the
|
|
589
|
+
hero install buttons (also .copy, elsewhere) keep their text label. */
|
|
590
|
+
.copy-group .copy {
|
|
591
|
+
justify-content: center;
|
|
592
|
+
width: 2rem;
|
|
593
|
+
height: 2rem;
|
|
594
|
+
padding: 0;
|
|
595
|
+
gap: 0;
|
|
596
|
+
text-decoration: none;
|
|
597
|
+
}
|
|
598
|
+
.source {
|
|
599
|
+
font-size: 0.85rem;
|
|
600
|
+
white-space: nowrap;
|
|
601
|
+
}
|
|
602
|
+
.empty {
|
|
603
|
+
color: var(--muted);
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
footer {
|
|
607
|
+
border-top: 1px solid var(--border);
|
|
608
|
+
color: var(--muted);
|
|
609
|
+
font-size: 0.85rem;
|
|
610
|
+
}
|
|
611
|
+
footer p {
|
|
612
|
+
margin: 0.8rem 0;
|
|
613
|
+
}
|
|
614
|
+
footer a {
|
|
615
|
+
color: inherit;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
</style>
|
|
619
|
+
|
|
620
|
+
{/* Unlayered, and last in the document: the user's file wins twice over. */}
|
|
621
|
+
{css && <style is:inline set:html={css} />}
|
|
622
|
+
</body>
|
|
623
|
+
</html>
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export type { CatalogPackage } from "../../types.js";
|
|
2
|
+
export declare function versionCascade(version: string | undefined, tags: string[]): string[];
|
|
3
|
+
export declare function compareVersions(a: string, b: string): number;
|
|
4
|
+
export declare function timeAgo(iso: string): string;
|
|
5
|
+
/** `vscode://<publisher.extension>/open?repo=<ref>`, or null when disabled. */
|
|
6
|
+
export declare function vscodeUrl(extension: string | null, ref: string): string | null;
|
|
7
|
+
//# sourceMappingURL=catalog.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../../../../src/renderer/astro/lib/catalog.ts"],"names":[],"mappings":"AAOA,YAAY,EAAE,cAAc,EAAE,MAAM,gBAAgB,CAAC;AAKrD,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,GAAG,SAAS,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,MAAM,EAAE,CAWpF;AAID,wBAAgB,eAAe,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,EAAE,MAAM,GAAG,MAAM,CAa5D;AAcD,wBAAgB,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAS3C;AAED,+EAA+E;AAC/E,wBAAgB,SAAS,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAE9E"}
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
// SPDX-License-Identifier: Apache-2.0
|
|
2
|
+
// Copyright 2026 The Grimoire Authors
|
|
3
|
+
// Publishing 0.10.0 also moves the rolling tags 0.10, 0 and latest, so the
|
|
4
|
+
// full tag list is mostly history. Return just the current release's chain
|
|
5
|
+
// (latest | 0 | 0.10 | 0.10.0). `tags` must already be sorted newest-first.
|
|
6
|
+
export function versionCascade(version, tags) {
|
|
7
|
+
const pinned = version ?? tags.find((t) => /^v?\d/.test(t));
|
|
8
|
+
// Split the raw string so a "v" prefix rides along into the rolling tags
|
|
9
|
+
// it was published under ("v1.2.3" -> "v1", "v1.2"), same as unprefixed.
|
|
10
|
+
const [major, minor] = (pinned ?? "").split(".");
|
|
11
|
+
const chain = [...new Set(["latest", major, `${major}.${minor}`, pinned])].filter((t) => !!t && tags.includes(t));
|
|
12
|
+
// Tags nothing recognises as a version (["stable", "beta"]) yield no chain
|
|
13
|
+
// — front the newest few rather than an empty strip.
|
|
14
|
+
return chain.length > 0 ? chain : tags.slice(0, 4);
|
|
15
|
+
}
|
|
16
|
+
// Tags are published version strings (e.g. "v1.2.0"); sort latest first,
|
|
17
|
+
// numeric-aware so "1.10.0" outranks "1.9.0".
|
|
18
|
+
export function compareVersions(a, b) {
|
|
19
|
+
const parts = (s) => s.replace(/^v/i, "").split(/[.-]/);
|
|
20
|
+
const pa = parts(a);
|
|
21
|
+
const pb = parts(b);
|
|
22
|
+
for (let i = 0; i < Math.max(pa.length, pb.length); i++) {
|
|
23
|
+
const [na, nb] = [Number(pa[i]), Number(pb[i])];
|
|
24
|
+
if (!Number.isNaN(na) && !Number.isNaN(nb)) {
|
|
25
|
+
if (na !== nb)
|
|
26
|
+
return nb - na;
|
|
27
|
+
}
|
|
28
|
+
else if (pa[i] !== pb[i]) {
|
|
29
|
+
return (pb[i] ?? "").localeCompare(pa[i] ?? "");
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return 0;
|
|
33
|
+
}
|
|
34
|
+
// MDN-standard Intl.RelativeTimeFormat rollup (no date library).
|
|
35
|
+
const RTF = new Intl.RelativeTimeFormat("en", { numeric: "auto" });
|
|
36
|
+
const TIME_DIVISIONS = [
|
|
37
|
+
[60, "seconds"],
|
|
38
|
+
[60, "minutes"],
|
|
39
|
+
[24, "hours"],
|
|
40
|
+
[7, "days"],
|
|
41
|
+
[4.34524, "weeks"],
|
|
42
|
+
[12, "months"],
|
|
43
|
+
[Infinity, "years"],
|
|
44
|
+
];
|
|
45
|
+
export function timeAgo(iso) {
|
|
46
|
+
const ms = new Date(iso).getTime();
|
|
47
|
+
if (!Number.isFinite(ms))
|
|
48
|
+
return ""; // unparseable: caller hides the element
|
|
49
|
+
let duration = (ms - Date.now()) / 1000;
|
|
50
|
+
for (const [amount, unit] of TIME_DIVISIONS) {
|
|
51
|
+
if (Math.abs(duration) < amount)
|
|
52
|
+
return RTF.format(Math.round(duration), unit);
|
|
53
|
+
duration /= amount;
|
|
54
|
+
}
|
|
55
|
+
return RTF.format(Math.round(duration), "years");
|
|
56
|
+
}
|
|
57
|
+
/** `vscode://<publisher.extension>/open?repo=<ref>`, or null when disabled. */
|
|
58
|
+
export function vscodeUrl(extension, ref) {
|
|
59
|
+
return extension ? `vscode://${extension}/open?repo=${encodeURIComponent(ref)}` : null;
|
|
60
|
+
}
|
|
61
|
+
//# sourceMappingURL=catalog.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.js","sourceRoot":"","sources":["../../../../src/renderer/astro/lib/catalog.ts"],"names":[],"mappings":"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"}
|