@grove-dev/astro 0.2.10 → 0.2.14
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/README.md +26 -18
- package/dist/lib/display.d.ts +11 -17
- package/dist/lib/display.d.ts.map +1 -1
- package/dist/lib/display.js +43 -43
- package/dist/lib/display.js.map +1 -1
- package/dist/lib/format.d.ts +6 -7
- package/dist/lib/format.d.ts.map +1 -1
- package/dist/lib/format.js +11 -12
- package/dist/lib/format.js.map +1 -1
- package/dist/lib/lenses.d.ts +35 -73
- package/dist/lib/lenses.d.ts.map +1 -1
- package/dist/lib/lenses.js +144 -126
- package/dist/lib/lenses.js.map +1 -1
- package/dist/lib/repo.d.ts +12 -22
- package/dist/lib/repo.d.ts.map +1 -1
- package/dist/lib/repo.js +13 -25
- package/dist/lib/repo.js.map +1 -1
- package/dist/lib/scores.d.ts +15 -16
- package/dist/lib/scores.d.ts.map +1 -1
- package/dist/lib/scores.js +4 -11
- package/dist/lib/scores.js.map +1 -1
- package/dist/lib/search.d.ts +44 -129
- package/dist/lib/search.d.ts.map +1 -1
- package/dist/lib/search.js +192 -180
- package/dist/lib/search.js.map +1 -1
- package/dist/lib/taxonomy-counts.d.ts +7 -21
- package/dist/lib/taxonomy-counts.d.ts.map +1 -1
- package/dist/lib/taxonomy-counts.js +12 -31
- package/dist/lib/taxonomy-counts.js.map +1 -1
- package/package.json +4 -4
- package/src/components/CategoryGrid.astro +43 -31
- package/src/components/ContributorsGrid.astro +3 -3
- package/src/components/CurationGrid.astro +41 -0
- package/src/components/ExploreByStack.astro +6 -0
- package/src/components/FilterGroupMenu.astro +49 -0
- package/src/components/FilterOptions.astro +44 -0
- package/src/components/Hero.astro +198 -147
- package/src/components/Icon.astro +10 -3
- package/src/components/IndexRow.astro +75 -0
- package/src/components/ItemCard.astro +266 -248
- package/src/components/Pagination.astro +63 -0
- package/src/components/RecordSection.astro +70 -34
- package/src/components/RefinePanel.astro +115 -141
- package/src/components/StackGrid.astro +32 -24
- package/src/components/WhyThisExists.astro +32 -32
- package/src/layouts/BaseLayout.astro +104 -49
- package/src/layouts/Container.astro +5 -44
- package/src/layouts/Footer.astro +31 -20
- package/src/layouts/Header.astro +40 -19
- package/src/layouts/SectionHeader.astro +27 -43
- package/src/layouts/Seo.astro +38 -56
- package/src/layouts/ThemeToggle.astro +35 -48
- package/src/lib/display.ts +46 -53
- package/src/lib/format.ts +11 -12
- package/src/lib/lenses.ts +151 -172
- package/src/lib/repo.ts +17 -28
- package/src/lib/scores.ts +15 -19
- package/src/lib/search.ts +218 -291
- package/src/lib/taxonomy-counts.ts +12 -46
- package/src/styles.css +209 -1
- package/templates/default/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
- package/templates/default/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
- package/templates/default/.github/ISSUE_TEMPLATE/record_submission.md +48 -0
- package/templates/default/.github/pull_request_template.md +27 -0
- package/templates/default/.github/workflows/build.yml +55 -0
- package/templates/default/.github/workflows/cleanup-stale-records.yml +48 -0
- package/templates/default/.github/workflows/daily-refresh.yml +53 -0
- package/templates/default/.github/workflows/sync-contributors.yml +53 -0
- package/templates/default/.github/workflows/sync-github-metadata.yml +58 -0
- package/templates/default/.github/workflows/validate-data.yml +35 -0
- package/templates/default/data/records/coolify.yml +46 -0
- package/templates/default/data/records/gitea.yml +46 -0
- package/templates/default/data/records/hoppscotch.yml +47 -0
- package/templates/default/data/records/inventree.yml +47 -0
- package/templates/default/data/records/label-studio.yml +46 -0
- package/templates/default/data/records/logseq.yml +48 -0
- package/templates/default/data/records/private-gpt.yml +47 -0
- package/templates/default/data/records/wakapi.yml +44 -0
- package/templates/default/data/taxonomy/categories.yml +47 -0
- package/templates/default/data/taxonomy/distribution-channels.yml +43 -0
- package/templates/default/data/taxonomy/platforms.yml +27 -0
- package/templates/default/data/taxonomy/stacks.yml +41 -0
- package/templates/default/grove.config.ts +1 -1
- package/templates/default/package.json +5 -4
- package/templates/default/public/icons/stacks/bun.svg +1 -0
- package/templates/default/public/icons/stacks/clojure.svg +1 -0
- package/templates/default/public/icons/stacks/clojurescript.svg +1 -0
- package/templates/default/public/icons/stacks/deno.svg +1 -0
- package/templates/default/public/icons/stacks/django.svg +1 -0
- package/templates/default/public/icons/stacks/docker.svg +1 -0
- package/templates/default/public/icons/stacks/go.svg +1 -0
- package/templates/default/public/icons/stacks/llm.svg +1 -0
- package/templates/default/public/icons/stacks/node.js.svg +1 -0
- package/templates/default/public/icons/stacks/sveltekit.svg +1 -0
- package/templates/default/public/icons/stacks/vue.svg +1 -0
- package/templates/default/public/llms-full.txt +197 -5
- package/templates/default/public/llms.txt +107 -6
- package/templates/default/public/sitemap.xml +63 -0
- package/templates/default/scripts/build-llms.mjs +123 -0
- package/templates/default/scripts/build-records-json.mjs +27 -0
- package/templates/default/scripts/build-sitemap.mjs +20 -0
- package/templates/default/scripts/cleanup-stale-records.mjs +20 -0
- package/templates/default/scripts/enrich-github-metadata.mjs +99 -0
- package/templates/default/scripts/fetch-icons.mjs +137 -0
- package/templates/default/scripts/migrate-legacy-to-schema-v1.mjs +86 -0
- package/templates/default/scripts/parse-legacy-readme.mjs +59 -0
- package/templates/default/scripts/refresh-records-activity.mjs +24 -0
- package/templates/default/scripts/repair-license-format.mjs +72 -0
- package/templates/default/scripts/report-cleanup-candidates.mjs +21 -0
- package/templates/default/scripts/seed-from-github.mjs +62 -0
- package/templates/default/scripts/sync-contributors.mjs +145 -0
- package/templates/default/scripts/sync-github-metadata.mjs +28 -0
- package/templates/default/scripts/validate-records.mjs +27 -0
- package/templates/default/src/data/records.ts +138 -51
- package/templates/default/src/pages/404.astro +64 -0
- package/templates/default/src/pages/{projects/[slug].astro → [slug]/[recordSlug].astro} +236 -66
- package/templates/default/src/pages/[slug]/index.astro +477 -0
- package/templates/default/src/pages/about.astro +165 -82
- package/templates/default/src/pages/apps/[recordSlug].astro +33 -0
- package/templates/default/src/pages/contributors.astro +184 -0
- package/templates/default/src/pages/index.astro +119 -162
- package/templates/default/src/pages/submit.astro +276 -114
- package/templates/default/wrangler.jsonc +28 -0
- package/LICENSE +0 -21
- package/src/components/AppsIndexRow.astro +0 -204
- package/src/components/AppsPagination.astro +0 -126
- package/templates/default/.astro/content.d.ts +0 -155
- package/templates/default/.astro/settings.json +0 -5
- package/templates/default/.astro/types.d.ts +0 -1
- package/templates/default/data/generated/apps.json +0 -1
- package/templates/default/data/generated/records.full.json +0 -8
- package/templates/default/data/generated/records.index.json +0 -7
- package/templates/default/data/generated/records.json +0 -8
- package/templates/default/data/generated/repo-stats.json +0 -1
- package/templates/default/data/generated/site-config.json +0 -31
- package/templates/default/dist/_astro/BaseLayout.Dz_HR-68.css +0 -1
- package/templates/default/dist/about/index.html +0 -165
- package/templates/default/dist/icons/platforms/android.svg +0 -1
- package/templates/default/dist/icons/platforms/apple-dark.svg +0 -1
- package/templates/default/dist/icons/platforms/apple-light.svg +0 -1
- package/templates/default/dist/icons/platforms/chrome.svg +0 -1
- package/templates/default/dist/icons/platforms/chromeos.svg +0 -5
- package/templates/default/dist/icons/platforms/desktop.svg +0 -4
- package/templates/default/dist/icons/platforms/embedded.svg +0 -5
- package/templates/default/dist/icons/platforms/ios.svg +0 -1
- package/templates/default/dist/icons/platforms/linux.svg +0 -1
- package/templates/default/dist/icons/platforms/macos.svg +0 -1
- package/templates/default/dist/icons/platforms/ubuntu.svg +0 -1
- package/templates/default/dist/icons/platforms/web.svg +0 -5
- package/templates/default/dist/icons/platforms/windows.svg +0 -6
- package/templates/default/dist/icons/stacks/android.svg +0 -1
- package/templates/default/dist/icons/stacks/apple-dark.svg +0 -1
- package/templates/default/dist/icons/stacks/apple-light.svg +0 -1
- package/templates/default/dist/icons/stacks/capacitor.svg +0 -14
- package/templates/default/dist/icons/stacks/dart.svg +0 -1
- package/templates/default/dist/icons/stacks/firebase.svg +0 -1
- package/templates/default/dist/icons/stacks/flutter.svg +0 -1
- package/templates/default/dist/icons/stacks/graphql.svg +0 -1
- package/templates/default/dist/icons/stacks/ionic.svg +0 -4
- package/templates/default/dist/icons/stacks/java.svg +0 -1
- package/templates/default/dist/icons/stacks/javascript.svg +0 -1
- package/templates/default/dist/icons/stacks/kotlin.svg +0 -1
- package/templates/default/dist/icons/stacks/mongodb.svg +0 -1
- package/templates/default/dist/icons/stacks/nodejs.svg +0 -1
- package/templates/default/dist/icons/stacks/python.svg +0 -1
- package/templates/default/dist/icons/stacks/react-native.svg +0 -1
- package/templates/default/dist/icons/stacks/react.svg +0 -1
- package/templates/default/dist/icons/stacks/rust.svg +0 -1
- package/templates/default/dist/icons/stacks/solidity.svg +0 -1
- package/templates/default/dist/icons/stacks/swift.svg +0 -1
- package/templates/default/dist/icons/stacks/tensorflow.svg +0 -1
- package/templates/default/dist/icons/stacks/typescript.svg +0 -1
- package/templates/default/dist/index.html +0 -55
- package/templates/default/dist/llms-full.txt +0 -14
- package/templates/default/dist/llms.txt +0 -11
- package/templates/default/dist/og-image.svg +0 -48
- package/templates/default/dist/projects/index.html +0 -61
- package/templates/default/dist/robots.txt +0 -53
- package/templates/default/dist/sitemap.xml +0 -21
- package/templates/default/dist/submit/index.html +0 -69
- package/templates/default/node_modules/.bin/astro +0 -21
- package/templates/default/node_modules/.bin/astro-check +0 -21
- package/templates/default/node_modules/.bin/grove +0 -21
- package/templates/default/node_modules/.bin/jiti +0 -21
- package/templates/default/node_modules/.bin/prettier +0 -21
- package/templates/default/node_modules/.bin/rollup +0 -21
- package/templates/default/node_modules/.bin/tsc +0 -21
- package/templates/default/node_modules/.bin/tsserver +0 -21
- package/templates/default/node_modules/.bin/tsx +0 -21
- package/templates/default/node_modules/.bin/vite +0 -21
- package/templates/default/node_modules/.bin/yaml +0 -21
- package/templates/default/node_modules/.vite/deps/_metadata.json +0 -79
- package/templates/default/node_modules/.vite/deps/astro-KRVZHBC5.js +0 -433
- package/templates/default/node_modules/.vite/deps/astro-KRVZHBC5.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/astro___aria-query.js +0 -5
- package/templates/default/node_modules/.vite/deps/astro___aria-query.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/astro___axobject-query.js +0 -5
- package/templates/default/node_modules/.vite/deps/astro___axobject-query.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/astro___html-escaper.js +0 -9
- package/templates/default/node_modules/.vite/deps/astro___html-escaper.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -241
- package/templates/default/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/audit-GYHQ3ITH.js +0 -1592
- package/templates/default/node_modules/.vite/deps/audit-GYHQ3ITH.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/chunk-5WRI5ZAA.js +0 -30
- package/templates/default/node_modules/.vite/deps/chunk-5WRI5ZAA.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/chunk-7P4KIK53.js +0 -186
- package/templates/default/node_modules/.vite/deps/chunk-7P4KIK53.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/chunk-BQGHFQJH.js +0 -48
- package/templates/default/node_modules/.vite/deps/chunk-BQGHFQJH.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/chunk-CJCDKWP2.js +0 -6779
- package/templates/default/node_modules/.vite/deps/chunk-CJCDKWP2.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/chunk-FHJ3XBDE.js +0 -33
- package/templates/default/node_modules/.vite/deps/chunk-FHJ3XBDE.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/chunk-FQEMNIUQ.js +0 -88
- package/templates/default/node_modules/.vite/deps/chunk-FQEMNIUQ.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/chunk-HBSVDAQD.js +0 -72
- package/templates/default/node_modules/.vite/deps/chunk-HBSVDAQD.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/chunk-HDOQ2U3U.js +0 -3757
- package/templates/default/node_modules/.vite/deps/chunk-HDOQ2U3U.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/chunk-XEBKRCNE.js +0 -54
- package/templates/default/node_modules/.vite/deps/chunk-XEBKRCNE.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/package.json +0 -3
- package/templates/default/node_modules/.vite/deps/settings-C5H4VHXU.js +0 -213
- package/templates/default/node_modules/.vite/deps/settings-C5H4VHXU.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/toolbar-H5DB6HVP.js +0 -525
- package/templates/default/node_modules/.vite/deps/toolbar-H5DB6HVP.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/ui-library-JGHU6JE2.js +0 -1020
- package/templates/default/node_modules/.vite/deps/ui-library-JGHU6JE2.js.map +0 -7
- package/templates/default/node_modules/.vite/deps/xray-EFCQOW4E.js +0 -147
- package/templates/default/node_modules/.vite/deps/xray-EFCQOW4E.js.map +0 -7
- package/templates/default/src/components/layout/BaseLayout.astro +0 -47
- package/templates/default/src/components/layout/Container.astro +0 -18
- package/templates/default/src/components/layout/Footer.astro +0 -27
- package/templates/default/src/components/layout/Header.astro +0 -43
- package/templates/default/src/lib/markdown.ts +0 -171
- package/templates/default/src/pages/projects/index.astro +0 -193
|
@@ -1,60 +1,26 @@
|
|
|
1
|
-
|
|
2
|
-
* Build-time helpers that compute taxonomy counts from an array of
|
|
3
|
-
* records. Generic over any object that carries the index-payload
|
|
4
|
-
* fields the UI cares about (`category`, `stack` / `stacks`,
|
|
5
|
-
* `curation.labels`). No filesystem / data import — consumers pass
|
|
6
|
-
* the records explicitly so this stays testable.
|
|
7
|
-
*
|
|
8
|
-
* All functions are synchronous and cheap — they're called from
|
|
9
|
-
* Astro page frontmatter at build time, never on the client.
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
export interface Taxonomable {
|
|
1
|
+
type TaxonomyRecord = {
|
|
13
2
|
category?: string;
|
|
14
3
|
stack?: string;
|
|
15
4
|
stacks?: string[];
|
|
16
|
-
|
|
17
|
-
}
|
|
5
|
+
};
|
|
18
6
|
|
|
19
|
-
/** Number of
|
|
20
|
-
export function countByCategory<
|
|
21
|
-
records: T[],
|
|
22
|
-
): Map<string, number> {
|
|
7
|
+
/** Number of items in the directory, per category name. */
|
|
8
|
+
export function countByCategory(items: TaxonomyRecord[] = []): Map<string, number> {
|
|
23
9
|
const m = new Map<string, number>();
|
|
24
|
-
for (const
|
|
25
|
-
const k =
|
|
10
|
+
for (const a of items) {
|
|
11
|
+
const k = a.category || "Other";
|
|
26
12
|
m.set(k, (m.get(k) ?? 0) + 1);
|
|
27
13
|
}
|
|
28
14
|
return m;
|
|
29
15
|
}
|
|
30
16
|
|
|
31
|
-
/** Number of
|
|
32
|
-
export function countByStack<
|
|
33
|
-
records: T[],
|
|
34
|
-
): Map<string, number> {
|
|
35
|
-
const m = new Map<string, number>();
|
|
36
|
-
for (const r of records) {
|
|
37
|
-
const keys = new Set(
|
|
38
|
-
[r.stack, ...(r.stacks ?? [])].filter(
|
|
39
|
-
(s): s is string => Boolean(s),
|
|
40
|
-
),
|
|
41
|
-
);
|
|
42
|
-
for (const k of keys) {
|
|
43
|
-
m.set(k, (m.get(k) ?? 0) + 1);
|
|
44
|
-
}
|
|
45
|
-
}
|
|
46
|
-
return m;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
/** Number of records per curated label (curation.labels). */
|
|
50
|
-
export function countByLabel<T extends Taxonomable>(
|
|
51
|
-
records: T[],
|
|
52
|
-
): Map<string, number> {
|
|
17
|
+
/** Number of items in the directory, per primary stack. */
|
|
18
|
+
export function countByStack(items: TaxonomyRecord[] = []): Map<string, number> {
|
|
53
19
|
const m = new Map<string, number>();
|
|
54
|
-
for (const
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
20
|
+
for (const a of items) {
|
|
21
|
+
const stacks = new Set([a.stack, ...(a.stacks ?? [])].filter(Boolean) as string[]);
|
|
22
|
+
if (stacks.size === 0) stacks.add("Other");
|
|
23
|
+
for (const stack of stacks) m.set(stack, (m.get(stack) ?? 0) + 1);
|
|
58
24
|
}
|
|
59
25
|
return m;
|
|
60
26
|
}
|
package/src/styles.css
CHANGED
|
@@ -16,6 +16,9 @@
|
|
|
16
16
|
* removed) prefix. Only `grove-*` remains.
|
|
17
17
|
*/
|
|
18
18
|
|
|
19
|
+
@import "tailwindcss";
|
|
20
|
+
@source "./**/*.{astro,html,js,jsx,ts,tsx}";
|
|
21
|
+
|
|
19
22
|
@theme {
|
|
20
23
|
/* ── Neutral ink scale (V1 default) ───────────────────────────── */
|
|
21
24
|
--color-ink-50: #fafafa;
|
|
@@ -154,7 +157,7 @@
|
|
|
154
157
|
line-height: 1.55;
|
|
155
158
|
}
|
|
156
159
|
|
|
157
|
-
|
|
160
|
+
.dark body {
|
|
158
161
|
background: var(--color-ink-950);
|
|
159
162
|
color: var(--color-ink-100);
|
|
160
163
|
}
|
|
@@ -199,6 +202,84 @@
|
|
|
199
202
|
}
|
|
200
203
|
}
|
|
201
204
|
|
|
205
|
+
/* ──────────────────────────────────────────────────────────────────
|
|
206
|
+
* Rendered record Markdown
|
|
207
|
+
* ────────────────────────────────────────────────────────────────── */
|
|
208
|
+
.grove-prose {
|
|
209
|
+
max-width: 72ch;
|
|
210
|
+
color: var(--color-ink-700);
|
|
211
|
+
font-size: 0.9375rem;
|
|
212
|
+
line-height: 1.75;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
.dark .grove-prose {
|
|
216
|
+
color: var(--color-ink-200);
|
|
217
|
+
}
|
|
218
|
+
|
|
219
|
+
.grove-prose :where(h1, h2, h3, h4) {
|
|
220
|
+
margin: 1.75em 0 0.65em;
|
|
221
|
+
color: var(--color-ink-900);
|
|
222
|
+
font-weight: 650;
|
|
223
|
+
line-height: 1.25;
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
.dark .grove-prose :where(h1, h2, h3, h4) {
|
|
227
|
+
color: var(--color-ink-100);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
.grove-prose :where(p, ul, ol, pre, blockquote) {
|
|
231
|
+
margin: 1em 0;
|
|
232
|
+
}
|
|
233
|
+
|
|
234
|
+
.grove-prose :where(ul, ol) {
|
|
235
|
+
padding-left: 1.5rem;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
.grove-prose a {
|
|
239
|
+
color: var(--color-accent);
|
|
240
|
+
text-decoration: underline;
|
|
241
|
+
text-underline-offset: 0.18em;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
.grove-prose :where(code, pre) {
|
|
245
|
+
font-family: var(--font-mono);
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
.grove-prose code {
|
|
249
|
+
border-radius: 0.25rem;
|
|
250
|
+
background: var(--color-ink-100);
|
|
251
|
+
padding: 0.1em 0.3em;
|
|
252
|
+
font-size: 0.875em;
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
.dark .grove-prose code {
|
|
256
|
+
background: var(--color-ink-800);
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
.grove-prose pre {
|
|
260
|
+
overflow-x: auto;
|
|
261
|
+
border: 1px solid var(--color-ink-200);
|
|
262
|
+
border-radius: var(--radius-lg);
|
|
263
|
+
background: var(--color-ink-50);
|
|
264
|
+
padding: 1rem;
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
.dark .grove-prose pre {
|
|
268
|
+
border-color: var(--color-ink-800);
|
|
269
|
+
background: var(--color-ink-900);
|
|
270
|
+
}
|
|
271
|
+
|
|
272
|
+
.grove-prose pre code {
|
|
273
|
+
background: transparent;
|
|
274
|
+
padding: 0;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
.grove-prose blockquote {
|
|
278
|
+
border-left: 3px solid var(--color-ink-300);
|
|
279
|
+
padding-left: 1rem;
|
|
280
|
+
color: var(--color-ink-500);
|
|
281
|
+
}
|
|
282
|
+
|
|
202
283
|
/* ──────────────────────────────────────────────────────────────────
|
|
203
284
|
* Component classes — shared by the showcase component library.
|
|
204
285
|
* Use these directly; you can also use the equivalent Tailwind
|
|
@@ -206,6 +287,31 @@
|
|
|
206
287
|
* ────────────────────────────────────────────────────────────────── */
|
|
207
288
|
|
|
208
289
|
@layer components {
|
|
290
|
+
/*
|
|
291
|
+
* Stable container classes for consumers of the packaged stylesheet.
|
|
292
|
+
* Tailwind does not emit utilities referenced only inside a dependency,
|
|
293
|
+
* so relying on `max-w-container` alone can leave template content
|
|
294
|
+
* unconstrained.
|
|
295
|
+
*/
|
|
296
|
+
.grove-container,
|
|
297
|
+
.grove-container-wide,
|
|
298
|
+
.grove-container-narrow {
|
|
299
|
+
width: 100%;
|
|
300
|
+
margin-inline: auto;
|
|
301
|
+
}
|
|
302
|
+
|
|
303
|
+
.grove-container {
|
|
304
|
+
max-width: var(--container-container);
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
.grove-container-wide {
|
|
308
|
+
max-width: var(--container-wide);
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
.grove-container-narrow {
|
|
312
|
+
max-width: var(--container-narrow);
|
|
313
|
+
}
|
|
314
|
+
|
|
209
315
|
/* Section spacing — consistent vertical rhythm */
|
|
210
316
|
.grove-section {
|
|
211
317
|
padding-top: 3rem;
|
|
@@ -401,3 +507,105 @@
|
|
|
401
507
|
background: #ffffff;
|
|
402
508
|
}
|
|
403
509
|
}
|
|
510
|
+
|
|
511
|
+
/* ────────────────────────────────────────────────────────────────────
|
|
512
|
+
* Backwards-compat aliases — openapps used the unprefixed utility
|
|
513
|
+
* names (`card`, `btn-primary`, `btn-outline`, `btn-ghost`). New
|
|
514
|
+
* components should use the `grove-` prefix. These rules mirror
|
|
515
|
+
* the `grove-*` definitions above so the openapps-derived
|
|
516
|
+
* components (ItemCard, AppCard, etc. — kept as `ItemCard` for V1
|
|
517
|
+
* published API stability) work without per-component
|
|
518
|
+
* edits.
|
|
519
|
+
* ────────────────────────────────────────────────────────────────────*/
|
|
520
|
+
.card {
|
|
521
|
+
border: 1px solid var(--color-ink-200);
|
|
522
|
+
background: #ffffff;
|
|
523
|
+
border-radius: 0.5rem;
|
|
524
|
+
transition: border-color 150ms ease, background-color 150ms ease, box-shadow 150ms ease;
|
|
525
|
+
}
|
|
526
|
+
.dark .card {
|
|
527
|
+
border-color: var(--color-ink-800);
|
|
528
|
+
background: var(--color-ink-950);
|
|
529
|
+
}
|
|
530
|
+
.card-hover:hover {
|
|
531
|
+
border-color: var(--color-ink-300);
|
|
532
|
+
background: rgba(244, 244, 245, 0.6);
|
|
533
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04), 0 4px 12px -2px rgba(0, 0, 0, 0.06);
|
|
534
|
+
}
|
|
535
|
+
.dark .card-hover:hover {
|
|
536
|
+
border-color: var(--color-ink-700);
|
|
537
|
+
background: rgba(24, 24, 27, 0.4);
|
|
538
|
+
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.4), 0 4px 12px -2px rgba(0, 0, 0, 0.3);
|
|
539
|
+
}
|
|
540
|
+
|
|
541
|
+
/* Chip — small inline label used for platforms/stacks/etc. on
|
|
542
|
+
* ItemCard. Mirrors openapps' `.chip` from the ItemCard.astro
|
|
543
|
+
* (component name retained for V1 published API stability).
|
|
544
|
+
* `<style>` block so the @apply in the component still works. */
|
|
545
|
+
.chip {
|
|
546
|
+
display: inline-flex;
|
|
547
|
+
align-items: center;
|
|
548
|
+
gap: 0.25rem;
|
|
549
|
+
border-radius: 0.375rem;
|
|
550
|
+
border: 1px solid var(--color-ink-200);
|
|
551
|
+
background: #ffffff;
|
|
552
|
+
padding: 0.125rem 0.375rem;
|
|
553
|
+
font-size: 0.6875rem;
|
|
554
|
+
font-weight: 500;
|
|
555
|
+
color: var(--color-ink-700);
|
|
556
|
+
transition: color 150ms ease, background-color 150ms ease, border-color 150ms ease;
|
|
557
|
+
}
|
|
558
|
+
.dark .chip {
|
|
559
|
+
border-color: var(--color-ink-200);
|
|
560
|
+
background: var(--color-ink-950);
|
|
561
|
+
color: var(--color-ink-300);
|
|
562
|
+
}
|
|
563
|
+
.chip-stack {
|
|
564
|
+
background: var(--color-ink-50);
|
|
565
|
+
}
|
|
566
|
+
.dark .chip-stack {
|
|
567
|
+
background: rgba(24, 24, 27, 0.6);
|
|
568
|
+
}
|
|
569
|
+
.btn-primary,
|
|
570
|
+
.btn-outline,
|
|
571
|
+
.btn-ghost {
|
|
572
|
+
display: inline-flex;
|
|
573
|
+
align-items: center;
|
|
574
|
+
justify-content: center;
|
|
575
|
+
gap: 0.375rem;
|
|
576
|
+
border-radius: 0.5rem;
|
|
577
|
+
padding: 0.5rem 0.875rem;
|
|
578
|
+
font-size: 0.875rem;
|
|
579
|
+
font-weight: 500;
|
|
580
|
+
white-space: nowrap;
|
|
581
|
+
transition: color 0.15s, background-color 0.15s, border-color 0.15s;
|
|
582
|
+
cursor: pointer;
|
|
583
|
+
border: 1px solid transparent;
|
|
584
|
+
text-decoration: none;
|
|
585
|
+
}
|
|
586
|
+
.btn-primary {
|
|
587
|
+
border-color: var(--color-ink-900);
|
|
588
|
+
background: var(--color-ink-900);
|
|
589
|
+
color: var(--color-ink-50);
|
|
590
|
+
}
|
|
591
|
+
.btn-primary:hover {
|
|
592
|
+
background: var(--color-ink-700);
|
|
593
|
+
border-color: var(--color-ink-700);
|
|
594
|
+
}
|
|
595
|
+
.btn-outline {
|
|
596
|
+
border-color: var(--color-ink-200);
|
|
597
|
+
background: var(--color-ink-50);
|
|
598
|
+
color: var(--color-ink-700);
|
|
599
|
+
}
|
|
600
|
+
.btn-outline:hover {
|
|
601
|
+
border-color: var(--color-ink-300);
|
|
602
|
+
background: var(--color-ink-100);
|
|
603
|
+
}
|
|
604
|
+
.btn-ghost {
|
|
605
|
+
background: transparent;
|
|
606
|
+
color: var(--color-ink-500);
|
|
607
|
+
}
|
|
608
|
+
.btn-ghost:hover {
|
|
609
|
+
color: var(--color-ink-900);
|
|
610
|
+
background: var(--color-ink-100);
|
|
611
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Bug report
|
|
3
|
+
about: Something is broken on the site
|
|
4
|
+
title: "[bug] "
|
|
5
|
+
labels: ["bug"]
|
|
6
|
+
assignees: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## What happened
|
|
10
|
+
|
|
11
|
+
A clear, concise description of the bug.
|
|
12
|
+
|
|
13
|
+
## Steps to reproduce
|
|
14
|
+
|
|
15
|
+
1. Go to '…'
|
|
16
|
+
2. Click on '…'
|
|
17
|
+
3. Scroll down to '…'
|
|
18
|
+
4. See error
|
|
19
|
+
|
|
20
|
+
## What I expected
|
|
21
|
+
|
|
22
|
+
A clear, concise description of what you expected to happen.
|
|
23
|
+
|
|
24
|
+
## What I saw
|
|
25
|
+
|
|
26
|
+
Screenshots, error messages, console output — anything that helps.
|
|
27
|
+
|
|
28
|
+
## Environment
|
|
29
|
+
|
|
30
|
+
- Browser:
|
|
31
|
+
- OS:
|
|
32
|
+
- Page URL:
|
|
33
|
+
- Viewport size (rough):
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Feature request
|
|
3
|
+
about: Suggest an improvement to the site
|
|
4
|
+
title: "[feature] "
|
|
5
|
+
labels: ["enhancement"]
|
|
6
|
+
assignees: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## The problem
|
|
10
|
+
|
|
11
|
+
What's missing or awkward today?
|
|
12
|
+
|
|
13
|
+
## The proposed solution
|
|
14
|
+
|
|
15
|
+
What would you like to see? Mockups, links, references — anything
|
|
16
|
+
that helps us understand the shape of the change.
|
|
17
|
+
|
|
18
|
+
## Alternatives considered
|
|
19
|
+
|
|
20
|
+
Any other approaches you weighed, and why this one wins.
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: Submit a record
|
|
3
|
+
about: Suggest a new entry for the directory
|
|
4
|
+
title: "[submit] "
|
|
5
|
+
labels: ["submission"]
|
|
6
|
+
assignees: []
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
Thanks for taking the time to suggest a new entry! Please fill in the
|
|
10
|
+
template below — the more complete it is, the faster it lands.
|
|
11
|
+
|
|
12
|
+
**Important:** this issue tracker is for **suggestions**, not for the
|
|
13
|
+
actual data. Once approved, a maintainer will add the record to
|
|
14
|
+
`data/records/<slug>.yml` (or invite you to open a PR).
|
|
15
|
+
|
|
16
|
+
## 1. Basics
|
|
17
|
+
|
|
18
|
+
- **Name:**
|
|
19
|
+
- **One-line description:**
|
|
20
|
+
- **Category:** (e.g. Mobile, Web, DevOps, AI/ML)
|
|
21
|
+
- **Primary stack:** (e.g. Flutter, Vue, Go, Python)
|
|
22
|
+
- **Platforms:** (e.g. iOS, Android, Web, Linux, Self-host)
|
|
23
|
+
- **Project type:** (real-app, production, reference, library, tool,
|
|
24
|
+
demo, template, historical)
|
|
25
|
+
- **Difficulty:** (beginner, intermediate, advanced)
|
|
26
|
+
|
|
27
|
+
## 2. Links
|
|
28
|
+
|
|
29
|
+
- **Repository URL:** (the canonical `https://github.com/owner/repo`)
|
|
30
|
+
- **Website / homepage:**
|
|
31
|
+
- **Docs:**
|
|
32
|
+
|
|
33
|
+
## 3. Why it deserves a spot
|
|
34
|
+
|
|
35
|
+
A short paragraph — what makes it stand out, what it's good for, who
|
|
36
|
+
should look at it.
|
|
37
|
+
|
|
38
|
+
## 4. Caveats
|
|
39
|
+
|
|
40
|
+
Anything we should know about: license quirks, abandoned status,
|
|
41
|
+
paid-only features, etc.
|
|
42
|
+
|
|
43
|
+
## 5. Checkboxes
|
|
44
|
+
|
|
45
|
+
- [ ] The repo is **public** on GitHub / another public forge
|
|
46
|
+
- [ ] It's **open source** under an OSI-approved license
|
|
47
|
+
- [ ] It has been **maintained** in the last 12 months
|
|
48
|
+
- [ ] I am **not** the author (or I'm disclosing that I am)
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
## What this PR does
|
|
2
|
+
|
|
3
|
+
A short summary of the change. One or two sentences. If it closes an
|
|
4
|
+
issue, write "Closes #123" so it auto-links.
|
|
5
|
+
|
|
6
|
+
## Why
|
|
7
|
+
|
|
8
|
+
The motivation. Link to any relevant issues or discussions. If this
|
|
9
|
+
is a UI change, attach a before/after screenshot.
|
|
10
|
+
|
|
11
|
+
## How to verify
|
|
12
|
+
|
|
13
|
+
Steps for a reviewer to follow:
|
|
14
|
+
|
|
15
|
+
1. `pnpm install`
|
|
16
|
+
2. `pnpm exec grove validate`
|
|
17
|
+
3. `pnpm grove:dev` and open `…`
|
|
18
|
+
4. Confirm that `…`
|
|
19
|
+
|
|
20
|
+
## Checklist
|
|
21
|
+
|
|
22
|
+
- [ ] `pnpm exec grove validate` passes
|
|
23
|
+
- [ ] `pnpm run build` succeeds locally
|
|
24
|
+
- [ ] For record changes: the `slug` is unique and matches the
|
|
25
|
+
filename (`data/records/<slug>.yml`)
|
|
26
|
+
- [ ] For new categories / stacks / platforms: the field appears
|
|
27
|
+
sensibly in `Browse by category` and `Browse by stack`
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
name: Build
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
push:
|
|
5
|
+
branches: [main]
|
|
6
|
+
workflow_dispatch:
|
|
7
|
+
|
|
8
|
+
jobs:
|
|
9
|
+
build:
|
|
10
|
+
name: grove build
|
|
11
|
+
runs-on: ubuntu-latest
|
|
12
|
+
timeout-minutes: 15
|
|
13
|
+
permissions:
|
|
14
|
+
contents: read
|
|
15
|
+
pages: write
|
|
16
|
+
id-token: write
|
|
17
|
+
steps:
|
|
18
|
+
- uses: actions/checkout@v4
|
|
19
|
+
|
|
20
|
+
- uses: pnpm/action-setup@v4
|
|
21
|
+
with:
|
|
22
|
+
version: 10
|
|
23
|
+
|
|
24
|
+
- uses: actions/setup-node@v4
|
|
25
|
+
with:
|
|
26
|
+
node-version: 20
|
|
27
|
+
cache: pnpm
|
|
28
|
+
|
|
29
|
+
- name: Install dependencies
|
|
30
|
+
run: pnpm install --frozen-lockfile
|
|
31
|
+
|
|
32
|
+
# `build` chains build:data + build:sitemap + build:llms + astro build.
|
|
33
|
+
# Site URL is overridden so sitemap/OG/canonical links resolve to
|
|
34
|
+
# the deployed URL rather than the placeholder in grove.config.ts.
|
|
35
|
+
- name: Build site
|
|
36
|
+
env:
|
|
37
|
+
SITE_URL: ${{ vars.SITE_URL || github.pages.custom_domain || format('https://{0}.github.io/{1}', github.repository_owner, github.event.repository.name) }}
|
|
38
|
+
run: pnpm run build
|
|
39
|
+
|
|
40
|
+
- name: Setup Pages
|
|
41
|
+
uses: actions/configure-pages@v5
|
|
42
|
+
|
|
43
|
+
- name: Upload artifact
|
|
44
|
+
uses: actions/upload-pages-artifact@v3
|
|
45
|
+
with:
|
|
46
|
+
path: ./dist
|
|
47
|
+
|
|
48
|
+
- name: Deploy to GitHub Pages
|
|
49
|
+
id: deployment
|
|
50
|
+
uses: actions/deploy-pages@v4
|
|
51
|
+
|
|
52
|
+
- name: Summary
|
|
53
|
+
if: success()
|
|
54
|
+
run: |
|
|
55
|
+
echo "✅ Deployed to ${{ steps.deployment.outputs.page_url }}"
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
name: Cleanup stale records
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
# Monthly — first Monday 05:00 UTC. Cheap enough to run daily
|
|
6
|
+
# if you want, but most repos don't change status that often.
|
|
7
|
+
- cron: "0 5 1-7 * 1"
|
|
8
|
+
workflow_dispatch:
|
|
9
|
+
|
|
10
|
+
jobs:
|
|
11
|
+
cleanup:
|
|
12
|
+
name: grove cleanup stale
|
|
13
|
+
runs-on: ubuntu-latest
|
|
14
|
+
timeout-minutes: 10
|
|
15
|
+
permissions:
|
|
16
|
+
contents: read
|
|
17
|
+
issues: write
|
|
18
|
+
steps:
|
|
19
|
+
- uses: actions/checkout@v4
|
|
20
|
+
|
|
21
|
+
- uses: pnpm/action-setup@v4
|
|
22
|
+
with:
|
|
23
|
+
version: 10
|
|
24
|
+
|
|
25
|
+
- uses: actions/setup-node@v4
|
|
26
|
+
with:
|
|
27
|
+
node-version: 20
|
|
28
|
+
cache: pnpm
|
|
29
|
+
|
|
30
|
+
- name: Install dependencies
|
|
31
|
+
run: pnpm install --frozen-lockfile
|
|
32
|
+
|
|
33
|
+
# `grove cleanup stale` lists records whose health signals say
|
|
34
|
+
# they need human review (archived, no commits in 12+ months,
|
|
35
|
+
# unparseable repo, etc). The report is rendered as a Markdown
|
|
36
|
+
# summary in the workflow run.
|
|
37
|
+
- name: Run cleanup report
|
|
38
|
+
id: report
|
|
39
|
+
run: pnpm exec grove cleanup stale --report > cleanup-report.md
|
|
40
|
+
|
|
41
|
+
- name: Summarise
|
|
42
|
+
run: |
|
|
43
|
+
if [ -s cleanup-report.md ]; then
|
|
44
|
+
echo "## Cleanup candidates" >> $GITHUB_STEP_SUMMARY
|
|
45
|
+
cat cleanup-report.md >> $GITHUB_STEP_SUMMARY
|
|
46
|
+
else
|
|
47
|
+
echo "✅ No records need cleanup." >> $GITHUB_STEP_SUMMARY
|
|
48
|
+
fi
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Daily records refresh
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
# Daily — 06:00 UTC. Refreshes stars, forks, and the most
|
|
6
|
+
# recent commit date for every record so the home page and
|
|
7
|
+
# /apps filters stay accurate.
|
|
8
|
+
- cron: "0 6 * * *"
|
|
9
|
+
workflow_dispatch:
|
|
10
|
+
|
|
11
|
+
jobs:
|
|
12
|
+
refresh:
|
|
13
|
+
name: refresh activity
|
|
14
|
+
runs-on: ubuntu-latest
|
|
15
|
+
timeout-minutes: 15
|
|
16
|
+
permissions:
|
|
17
|
+
contents: write
|
|
18
|
+
pull-requests: write
|
|
19
|
+
steps:
|
|
20
|
+
- uses: actions/checkout@v4
|
|
21
|
+
|
|
22
|
+
- uses: pnpm/action-setup@v4
|
|
23
|
+
with:
|
|
24
|
+
version: 10
|
|
25
|
+
|
|
26
|
+
- uses: actions/setup-node@v4
|
|
27
|
+
with:
|
|
28
|
+
node-version: 20
|
|
29
|
+
cache: pnpm
|
|
30
|
+
|
|
31
|
+
- name: Install dependencies
|
|
32
|
+
run: pnpm install --frozen-lockfile
|
|
33
|
+
|
|
34
|
+
- name: Refresh activity
|
|
35
|
+
env:
|
|
36
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
37
|
+
# `grove sync github` walks every record, fetches the
|
|
38
|
+
# latest stars/forks/pushed_at, and writes back to the
|
|
39
|
+
# corresponding yml file. Idempotent — no change if the
|
|
40
|
+
# record is already up to date.
|
|
41
|
+
run: pnpm exec grove sync github
|
|
42
|
+
|
|
43
|
+
- name: Open PR if records changed
|
|
44
|
+
uses: peter-evans/create-pull-request@v6
|
|
45
|
+
with:
|
|
46
|
+
commit-message: "chore(data): daily records refresh"
|
|
47
|
+
title: "Daily records refresh"
|
|
48
|
+
body: |
|
|
49
|
+
Automated daily refresh of stars, forks, and last-commit
|
|
50
|
+
timestamps for every record. Generated by the
|
|
51
|
+
`daily-refresh` workflow.
|
|
52
|
+
branch: chore/daily-refresh
|
|
53
|
+
delete-branch: true
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
name: Sync contributors
|
|
2
|
+
|
|
3
|
+
on:
|
|
4
|
+
schedule:
|
|
5
|
+
# Weekly — Sunday 04:00 UTC (after the metadata sync).
|
|
6
|
+
- cron: "0 4 * * 0"
|
|
7
|
+
workflow_dispatch:
|
|
8
|
+
|
|
9
|
+
jobs:
|
|
10
|
+
sync:
|
|
11
|
+
name: sync contributors
|
|
12
|
+
runs-on: ubuntu-latest
|
|
13
|
+
timeout-minutes: 10
|
|
14
|
+
permissions:
|
|
15
|
+
contents: read
|
|
16
|
+
steps:
|
|
17
|
+
- uses: actions/checkout@v4
|
|
18
|
+
|
|
19
|
+
- uses: pnpm/action-setup@v4
|
|
20
|
+
with:
|
|
21
|
+
version: 10
|
|
22
|
+
|
|
23
|
+
- uses: actions/setup-node@v4
|
|
24
|
+
with:
|
|
25
|
+
node-version: 20
|
|
26
|
+
cache: pnpm
|
|
27
|
+
|
|
28
|
+
- name: Install dependencies
|
|
29
|
+
run: pnpm install --frozen-lockfile
|
|
30
|
+
|
|
31
|
+
# Walk the records' repoUrl fields, fetch each repo's
|
|
32
|
+
# /contributors endpoint, and write a single
|
|
33
|
+
# `data/generated/contributors.json` (consumed by the home
|
|
34
|
+
# page and /contributors page). The script lives at the root
|
|
35
|
+
# of the project — it's not a CLI command because contributor
|
|
36
|
+
# fan-in is tightly coupled to this directory's git history
|
|
37
|
+
# and doesn't generalise across forks.
|
|
38
|
+
- name: Sync contributors from GitHub
|
|
39
|
+
env:
|
|
40
|
+
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
|
41
|
+
run: node scripts/sync-contributors.mjs
|
|
42
|
+
|
|
43
|
+
- name: Commit contributors.json
|
|
44
|
+
run: |
|
|
45
|
+
git config user.name "github-actions[bot]"
|
|
46
|
+
git config user.email "41898282+github-actions[bot]@users.noreply.github.com"
|
|
47
|
+
if git diff --quiet data/generated/contributors.json; then
|
|
48
|
+
echo "No changes to contributors.json"
|
|
49
|
+
else
|
|
50
|
+
git add data/generated/contributors.json
|
|
51
|
+
git commit -m "chore(data): refresh contributors"
|
|
52
|
+
git push
|
|
53
|
+
fi
|