@grove-dev/astro 0.1.4 → 0.2.2
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/dist/index.d.ts +4 -25
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +56 -22
- package/dist/index.js.map +1 -1
- package/dist/layouts/index.d.ts +25 -0
- package/dist/layouts/index.d.ts.map +1 -0
- package/dist/layouts/index.js +25 -0
- package/dist/layouts/index.js.map +1 -0
- package/dist/lib/display.d.ts +33 -0
- package/dist/lib/display.d.ts.map +1 -0
- package/dist/lib/display.js +104 -0
- package/dist/lib/display.js.map +1 -0
- package/dist/lib/format.d.ts +30 -0
- package/dist/lib/format.d.ts.map +1 -0
- package/dist/lib/format.js +73 -0
- package/dist/lib/format.js.map +1 -0
- package/dist/lib/index.d.ts +26 -0
- package/dist/lib/index.d.ts.map +1 -0
- package/dist/lib/index.js +26 -0
- package/dist/lib/index.js.map +1 -0
- package/dist/lib/lenses.d.ts +96 -0
- package/dist/lib/lenses.d.ts.map +1 -0
- package/dist/lib/lenses.js +181 -0
- package/dist/lib/lenses.js.map +1 -0
- package/dist/lib/repo.d.ts +30 -0
- package/dist/lib/repo.d.ts.map +1 -0
- package/dist/lib/repo.js +44 -0
- package/dist/lib/repo.js.map +1 -0
- package/dist/lib/scores.d.ts +38 -0
- package/dist/lib/scores.d.ts.map +1 -0
- package/dist/lib/scores.js +83 -0
- package/dist/lib/scores.js.map +1 -0
- package/dist/lib/search.d.ts +199 -0
- package/dist/lib/search.d.ts.map +1 -0
- package/dist/lib/search.js +357 -0
- package/dist/lib/search.js.map +1 -0
- package/dist/lib/taxonomy-counts.d.ts +25 -0
- package/dist/lib/taxonomy-counts.d.ts.map +1 -0
- package/dist/lib/taxonomy-counts.js +41 -0
- package/dist/lib/taxonomy-counts.js.map +1 -0
- package/package.json +7 -7
- package/src/components/AppSection.astro +83 -0
- package/src/components/AppsIndexRow.astro +204 -0
- package/src/components/AppsPagination.astro +126 -0
- package/src/components/CategoryGrid.astro +86 -17
- package/src/components/ContributorsGrid.astro +149 -0
- package/src/components/DecisionRow.astro +89 -0
- package/src/components/ExploreByCategory.astro +67 -0
- package/src/components/ExploreByStack.astro +72 -0
- package/src/components/Hero.astro +246 -0
- package/src/components/Icon.astro +223 -0
- package/src/components/ItemCard.astro +289 -30
- package/src/components/MinimalAbout.astro +82 -0
- package/src/components/OriginalCollection.astro +116 -0
- package/src/components/RefinePanel.astro +197 -0
- package/src/components/ScoreBars.astro +92 -22
- package/src/components/SmartLensTabs.astro +71 -0
- package/src/components/StackGrid.astro +132 -0
- package/src/components/WhyThisExists.astro +116 -0
- package/src/index.ts +61 -14
- package/src/layouts/BaseLayout.astro +227 -15
- package/src/layouts/Container.astro +57 -0
- package/src/layouts/Footer.astro +235 -0
- package/src/layouts/Header.astro +159 -0
- package/src/layouts/SectionHeader.astro +58 -0
- package/{templates/default/src/components/layout → src/layouts}/Seo.astro +62 -38
- package/src/layouts/ThemeToggle.astro +110 -0
- package/src/layouts/astro-shim.d.ts +29 -0
- package/src/layouts/index.ts +24 -0
- package/src/lib/display.ts +118 -0
- package/src/lib/format.ts +65 -0
- package/src/lib/index.ts +26 -0
- package/src/lib/lenses.ts +241 -0
- package/src/lib/repo.ts +44 -0
- package/src/lib/scores.ts +94 -0
- package/src/lib/search.ts +481 -0
- package/src/lib/taxonomy-counts.ts +60 -0
- package/src/styles.css +366 -638
- package/templates/default/.astro/content.d.ts +155 -0
- package/templates/default/.astro/settings.json +5 -0
- package/templates/default/.astro/types.d.ts +2 -0
- package/templates/default/astro.config.mjs +8 -6
- package/templates/default/content/pages/about.md +66 -0
- package/templates/default/content/pages/methodology.md +103 -0
- package/templates/default/data/generated/records.full.json +8 -0
- package/templates/default/data/generated/records.index.json +7 -0
- package/templates/default/data/generated/records.json +8 -0
- package/templates/default/data/generated/site-config.json +31 -0
- package/templates/default/data/records/.gitkeep +0 -0
- package/templates/default/dist/_astro/BaseLayout.DfpwR3jc.css +1 -0
- package/templates/default/dist/about/index.html +165 -0
- package/templates/default/dist/icons/platforms/android.svg +1 -0
- package/templates/default/dist/icons/platforms/apple-dark.svg +1 -0
- package/templates/default/dist/icons/platforms/apple-light.svg +1 -0
- package/templates/default/dist/icons/platforms/chrome.svg +1 -0
- package/templates/default/dist/icons/platforms/chromeos.svg +5 -0
- package/templates/default/dist/icons/platforms/desktop.svg +4 -0
- package/templates/default/dist/icons/platforms/embedded.svg +5 -0
- package/templates/default/dist/icons/platforms/ios.svg +1 -0
- package/templates/default/dist/icons/platforms/linux.svg +1 -0
- package/templates/default/dist/icons/platforms/macos.svg +1 -0
- package/templates/default/dist/icons/platforms/ubuntu.svg +1 -0
- package/templates/default/dist/icons/platforms/web.svg +5 -0
- package/templates/default/dist/icons/platforms/windows.svg +6 -0
- package/templates/default/dist/icons/stacks/android.svg +1 -0
- package/templates/default/dist/icons/stacks/apple-dark.svg +1 -0
- package/templates/default/dist/icons/stacks/apple-light.svg +1 -0
- package/templates/default/dist/icons/stacks/capacitor.svg +14 -0
- package/templates/default/dist/icons/stacks/dart.svg +1 -0
- package/templates/default/dist/icons/stacks/firebase.svg +1 -0
- package/templates/default/dist/icons/stacks/flutter.svg +1 -0
- package/templates/default/dist/icons/stacks/graphql.svg +1 -0
- package/templates/default/dist/icons/stacks/ionic.svg +4 -0
- package/templates/default/dist/icons/stacks/java.svg +1 -0
- package/templates/default/dist/icons/stacks/javascript.svg +1 -0
- package/templates/default/dist/icons/stacks/kotlin.svg +1 -0
- package/templates/default/dist/icons/stacks/mongodb.svg +1 -0
- package/templates/default/dist/icons/stacks/nodejs.svg +1 -0
- package/templates/default/dist/icons/stacks/python.svg +1 -0
- package/templates/default/dist/icons/stacks/react-native.svg +1 -0
- package/templates/default/dist/icons/stacks/react.svg +1 -0
- package/templates/default/dist/icons/stacks/rust.svg +1 -0
- package/templates/default/dist/icons/stacks/solidity.svg +1 -0
- package/templates/default/dist/icons/stacks/swift.svg +1 -0
- package/templates/default/dist/icons/stacks/tensorflow.svg +1 -0
- package/templates/default/dist/icons/stacks/typescript.svg +1 -0
- package/templates/default/dist/index.html +55 -0
- package/templates/default/dist/llms-full.txt +14 -0
- package/templates/default/dist/llms.txt +11 -0
- package/templates/default/dist/og-image.svg +48 -0
- package/templates/default/dist/projects/index.html +61 -0
- package/templates/default/dist/robots.txt +53 -0
- package/templates/default/dist/sitemap.xml +21 -0
- package/templates/default/dist/submit/index.html +69 -0
- package/templates/default/grove.config.ts +36 -0
- package/templates/default/node_modules/.bin/astro +21 -0
- package/templates/default/node_modules/.bin/astro-check +21 -0
- package/templates/default/node_modules/.bin/grove +21 -0
- package/templates/default/node_modules/.bin/jiti +21 -0
- package/templates/default/node_modules/.bin/prettier +21 -0
- package/templates/default/node_modules/.bin/rollup +21 -0
- package/templates/default/node_modules/.bin/tsc +21 -0
- package/templates/default/node_modules/.bin/tsserver +21 -0
- package/templates/default/node_modules/.bin/tsx +21 -0
- package/templates/default/node_modules/.bin/vite +21 -0
- package/templates/default/node_modules/.bin/yaml +21 -0
- package/templates/default/node_modules/.vite/deps/_metadata.json +79 -0
- package/templates/default/node_modules/.vite/deps/astro-KRVZHBC5.js +433 -0
- package/templates/default/node_modules/.vite/deps/astro-KRVZHBC5.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/astro___aria-query.js +5 -0
- package/templates/default/node_modules/.vite/deps/astro___aria-query.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/astro___axobject-query.js +5 -0
- package/templates/default/node_modules/.vite/deps/astro___axobject-query.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/astro___html-escaper.js +9 -0
- package/templates/default/node_modules/.vite/deps/astro___html-escaper.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +241 -0
- package/templates/default/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/audit-GYHQ3ITH.js +1592 -0
- package/templates/default/node_modules/.vite/deps/audit-GYHQ3ITH.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/chunk-5WRI5ZAA.js +30 -0
- package/templates/default/node_modules/.vite/deps/chunk-5WRI5ZAA.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/chunk-7P4KIK53.js +186 -0
- package/templates/default/node_modules/.vite/deps/chunk-7P4KIK53.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/chunk-BQGHFQJH.js +48 -0
- package/templates/default/node_modules/.vite/deps/chunk-BQGHFQJH.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/chunk-CJCDKWP2.js +6779 -0
- package/templates/default/node_modules/.vite/deps/chunk-CJCDKWP2.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/chunk-FHJ3XBDE.js +33 -0
- package/templates/default/node_modules/.vite/deps/chunk-FHJ3XBDE.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/chunk-FQEMNIUQ.js +88 -0
- package/templates/default/node_modules/.vite/deps/chunk-FQEMNIUQ.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/chunk-HBSVDAQD.js +72 -0
- package/templates/default/node_modules/.vite/deps/chunk-HBSVDAQD.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/chunk-HDOQ2U3U.js +3757 -0
- package/templates/default/node_modules/.vite/deps/chunk-HDOQ2U3U.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/chunk-XEBKRCNE.js +54 -0
- package/templates/default/node_modules/.vite/deps/chunk-XEBKRCNE.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/package.json +3 -0
- package/templates/default/node_modules/.vite/deps/settings-C5H4VHXU.js +213 -0
- package/templates/default/node_modules/.vite/deps/settings-C5H4VHXU.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/toolbar-H5DB6HVP.js +525 -0
- package/templates/default/node_modules/.vite/deps/toolbar-H5DB6HVP.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/ui-library-JGHU6JE2.js +1020 -0
- package/templates/default/node_modules/.vite/deps/ui-library-JGHU6JE2.js.map +7 -0
- package/templates/default/node_modules/.vite/deps/xray-EFCQOW4E.js +147 -0
- package/templates/default/node_modules/.vite/deps/xray-EFCQOW4E.js.map +7 -0
- package/templates/default/package.json +6 -5
- package/templates/default/public/llms-full.txt +14 -0
- package/templates/default/public/llms.txt +11 -0
- package/templates/default/src/components/layout/BaseLayout.astro +10 -57
- package/templates/default/src/components/layout/Footer.astro +16 -134
- package/templates/default/src/components/layout/Header.astro +25 -126
- package/templates/default/src/data/records.ts +161 -0
- package/templates/default/src/lib/markdown.ts +171 -0
- package/templates/default/src/pages/about.astro +95 -429
- package/templates/default/src/pages/index.astro +258 -61
- package/templates/default/src/pages/projects/[slug].astro +480 -0
- package/templates/default/src/pages/projects/index.astro +193 -0
- package/templates/default/src/pages/sitemap.xml.ts +73 -61
- package/templates/default/src/pages/submit.astro +122 -411
- package/templates/default/src/styles/global.css +42 -68
- package/src/components/ActiveFilterChips.astro +0 -20
- package/src/components/DirectoryFilters.astro +0 -100
- package/src/components/DirectoryHero.astro +0 -32
- package/src/components/HealthBadge.astro +0 -12
- package/src/components/LensTabs.astro +0 -26
- package/src/components/MethodologyPanel.astro +0 -20
- package/src/components/Pagination.astro +0 -24
- package/src/components/ProjectDetail.astro +0 -166
- package/src/components/SubmitDraft.astro +0 -137
- package/templates/default/src/components/AppCard.astro +0 -248
- package/templates/default/src/components/AppSection.astro +0 -58
- package/templates/default/src/components/AppsIndexRow.astro +0 -230
- package/templates/default/src/components/AppsPagination.astro +0 -147
- package/templates/default/src/components/CategoryGrid.astro +0 -80
- package/templates/default/src/components/ContributorsGrid.astro +0 -105
- package/templates/default/src/components/DecisionRow.astro +0 -219
- package/templates/default/src/components/ExploreByCategory.astro +0 -74
- package/templates/default/src/components/ExploreByStack.astro +0 -102
- package/templates/default/src/components/Hero.astro +0 -176
- package/templates/default/src/components/MinimalAbout.astro +0 -57
- package/templates/default/src/components/OriginalCollection.astro +0 -144
- package/templates/default/src/components/RefinePanel.astro +0 -272
- package/templates/default/src/components/ScoreBars.astro +0 -72
- package/templates/default/src/components/SmartLensTabs.astro +0 -65
- package/templates/default/src/components/StackGrid.astro +0 -95
- package/templates/default/src/components/WhyThisExists.astro +0 -81
- package/templates/default/src/components/icons/Icon.astro +0 -148
- package/templates/default/src/components/layout/SectionHeader.astro +0 -42
- package/templates/default/src/components/layout/ThemeToggle.astro +0 -97
- package/templates/default/src/data/apps.ts +0 -149
- package/templates/default/src/data/categories.ts +0 -27
- package/templates/default/src/data/config.ts +0 -28
- package/templates/default/src/data/contributors.ts +0 -96
- package/templates/default/src/data/stacks.ts +0 -47
- package/templates/default/src/data/stats.ts +0 -65
- package/templates/default/src/data/types.ts +0 -248
- package/templates/default/src/lib/apps-search.ts +0 -228
- package/templates/default/src/lib/format.ts +0 -36
- package/templates/default/src/lib/lenses.ts +0 -98
- package/templates/default/src/lib/repo.ts +0 -12
- package/templates/default/src/lib/scores.ts +0 -51
- package/templates/default/src/lib/taxonomy-counts.ts +0 -31
- package/templates/default/src/pages/apps/[slug].astro +0 -709
- package/templates/default/src/pages/apps/index.astro +0 -669
- package/templates/default/src/pages/contributors.astro +0 -142
|
@@ -1,66 +1,263 @@
|
|
|
1
1
|
---
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
2
|
+
/**
|
|
3
|
+
* Home page — the showcase's front door.
|
|
4
|
+
*
|
|
5
|
+
* Sections (in order):
|
|
6
|
+
* 1. Hero — brand + search + stats row
|
|
7
|
+
* 2. WhyThisExists — 3 short value-prop points
|
|
8
|
+
* 3. AppSection "Trending" — hot lens (stars >= 1000 OR pushed <= 30d)
|
|
9
|
+
* 4. AppSection "Recently added"— new lens (pushed <= 7d OR curated "new")
|
|
10
|
+
* 5. AppSection "Established" — mature lens (tier=curated, pushed > 365d)
|
|
11
|
+
* 6. StackGrid — browse by stack
|
|
12
|
+
* 7. CategoryGrid — browse by category
|
|
13
|
+
* 8. ContributorsGrid — top contributors (when available)
|
|
14
|
+
* 9. OriginalCollection — origin-card link to the source repo
|
|
15
|
+
*
|
|
16
|
+
* Every section is defensive: with 0 records (fresh scaffold) it
|
|
17
|
+
* renders a graceful empty state instead of throwing.
|
|
18
|
+
*/
|
|
19
|
+
import siteConfig from "../../data/generated/site-config.json";
|
|
20
|
+
import { records, fullRecords, projects, indexSlug, itemLabel } from "../data/records";
|
|
21
|
+
import BaseLayout from "@grove-dev/astro/layouts/BaseLayout.astro";
|
|
22
|
+
import Hero from "@grove-dev/astro/components/Hero.astro";
|
|
23
|
+
import WhyThisExists from "@grove-dev/astro/components/WhyThisExists.astro";
|
|
24
|
+
import AppSection from "@grove-dev/astro/components/AppSection.astro";
|
|
25
|
+
import StackGrid from "@grove-dev/astro/components/StackGrid.astro";
|
|
26
|
+
import CategoryGrid from "@grove-dev/astro/components/CategoryGrid.astro";
|
|
27
|
+
import ContributorsGrid from "@grove-dev/astro/components/ContributorsGrid.astro";
|
|
28
|
+
import OriginalCollection from "@grove-dev/astro/components/OriginalCollection.astro";
|
|
29
|
+
import { countByCategory, countByStack } from "@grove-dev/astro";
|
|
30
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
31
|
+
import { fileURLToPath } from "node:url";
|
|
32
|
+
import { dirname, resolve } from "node:path";
|
|
33
|
+
import type { ProjectRecord } from "@grove-dev/core";
|
|
34
|
+
|
|
35
|
+
const slug = indexSlug();
|
|
36
|
+
const projectKind = projects;
|
|
37
|
+
|
|
38
|
+
// ── Hero stats ──────────────────────────────────────────────────
|
|
39
|
+
const totalApps = fullRecords.filter((r) => r.kind === "project").length;
|
|
40
|
+
const totalCategories = new Set(projectKind.map((r) => r.category).filter(Boolean))
|
|
41
|
+
.size;
|
|
42
|
+
const totalStacks = new Set(
|
|
43
|
+
projectKind.flatMap((r) => [r.stack, ...(r.stacks ?? [])]).filter(Boolean),
|
|
44
|
+
).size;
|
|
45
|
+
const totalContributors = new Set(
|
|
46
|
+
projectKind
|
|
47
|
+
.map((r) => {
|
|
48
|
+
const url = r.repoUrl ?? (r.links as { github?: string } | undefined)?.github ?? "";
|
|
49
|
+
const m = /github\.com\/([^/]+)\//.exec(url);
|
|
50
|
+
return m?.[1];
|
|
51
|
+
})
|
|
52
|
+
.filter(Boolean),
|
|
53
|
+
).size;
|
|
54
|
+
const totalStars = projectKind.reduce(
|
|
55
|
+
(acc, r) => acc + ((r as ProjectRecord).github?.stars ?? 0),
|
|
56
|
+
0,
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
// ── Lens sectioning (Hot / New / Mature) ────────────────────────
|
|
60
|
+
const DAY_MS = 86_400_000;
|
|
61
|
+
function daysSince(iso: string | null | undefined): number {
|
|
62
|
+
if (!iso) return Infinity;
|
|
63
|
+
const d = new Date(iso);
|
|
64
|
+
if (Number.isNaN(d.valueOf())) return Infinity;
|
|
65
|
+
return (Date.now() - d.valueOf()) / DAY_MS;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
const hot = projectKind
|
|
69
|
+
.filter((r) => {
|
|
70
|
+
const stars = (r as ProjectRecord).github?.stars ?? 0;
|
|
71
|
+
const pushedAt = (r as ProjectRecord).github?.pushedAt ?? null;
|
|
72
|
+
const pushed = daysSince(pushedAt);
|
|
73
|
+
const labelledHot = r.curation?.labels?.includes("hot") ?? false;
|
|
74
|
+
return labelledHot || stars >= 1000 || pushed <= 30;
|
|
75
|
+
})
|
|
76
|
+
.slice(0, 6);
|
|
77
|
+
|
|
78
|
+
const newItems = projectKind
|
|
79
|
+
.filter((r) => {
|
|
80
|
+
const pushedAt = (r as ProjectRecord).github?.pushedAt ?? null;
|
|
81
|
+
const pushed = daysSince(pushedAt);
|
|
82
|
+
const labelledNew = r.curation?.labels?.includes("new") ?? false;
|
|
83
|
+
return pushed <= 7 || labelledNew;
|
|
84
|
+
})
|
|
85
|
+
.slice(0, 6);
|
|
86
|
+
|
|
87
|
+
const mature = projectKind
|
|
88
|
+
.filter((r) => {
|
|
89
|
+
const tier = r.health?.tier;
|
|
90
|
+
const pushedAt = (r as ProjectRecord).github?.pushedAt ?? null;
|
|
91
|
+
const pushed = daysSince(pushedAt);
|
|
92
|
+
return tier === "curated" && pushed > 365;
|
|
93
|
+
})
|
|
94
|
+
.slice(0, 6);
|
|
95
|
+
|
|
96
|
+
// ── Stack / category aggregates ─────────────────────────────────
|
|
97
|
+
const stackCounts = countByStack(projectKind);
|
|
98
|
+
const stacks = [...stackCounts.entries()]
|
|
99
|
+
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
|
100
|
+
.slice(0, 12)
|
|
101
|
+
.map(([name, count]) => ({ name, slug: name, count }));
|
|
102
|
+
|
|
103
|
+
const categoryCounts = countByCategory(projectKind);
|
|
104
|
+
const categories = [...categoryCounts.entries()]
|
|
105
|
+
.sort((a, b) => b[1] - a[1] || a[0].localeCompare(b[0]))
|
|
106
|
+
.map(([name, count]) => ({ name, slug: name, count }));
|
|
107
|
+
|
|
108
|
+
// ── Contributors (best-effort, from records) ────────────────────
|
|
109
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
110
|
+
const contributorsPath = [
|
|
111
|
+
resolve(here, "..", "..", "data", "generated", "contributors.json"),
|
|
112
|
+
resolve(process.cwd(), "data", "generated", "contributors.json"),
|
|
113
|
+
].find((p) => existsSync(p));
|
|
114
|
+
|
|
115
|
+
interface ContributorsFile {
|
|
116
|
+
contributors?: Array<{
|
|
117
|
+
username: string;
|
|
118
|
+
name?: string;
|
|
119
|
+
avatarUrl?: string;
|
|
120
|
+
profileUrl?: string;
|
|
121
|
+
contributions?: number;
|
|
122
|
+
}>;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
let contributors: ContributorsFile["contributors"] = [];
|
|
126
|
+
if (contributorsPath) {
|
|
127
|
+
try {
|
|
128
|
+
const parsed = JSON.parse(readFileSync(contributorsPath, "utf8")) as ContributorsFile;
|
|
129
|
+
contributors = parsed.contributors ?? [];
|
|
130
|
+
} catch {
|
|
131
|
+
contributors = [];
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
const hasContributors = contributors && contributors.length > 0;
|
|
135
|
+
|
|
136
|
+
// ── OriginalCollection (repo-stats.json if present) ─────────────
|
|
137
|
+
interface RepoStats {
|
|
138
|
+
originalRepo?: string;
|
|
139
|
+
stars?: number;
|
|
140
|
+
forks?: number;
|
|
141
|
+
contributors?: number;
|
|
142
|
+
description?: string;
|
|
143
|
+
}
|
|
144
|
+
let repoStats: RepoStats = {};
|
|
145
|
+
const repoStatsPath = [
|
|
146
|
+
resolve(here, "..", "..", "data", "generated", "repo-stats.json"),
|
|
147
|
+
resolve(process.cwd(), "data", "generated", "repo-stats.json"),
|
|
148
|
+
].find((p) => existsSync(p));
|
|
149
|
+
if (repoStatsPath) {
|
|
150
|
+
try {
|
|
151
|
+
repoStats = JSON.parse(readFileSync(repoStatsPath, "utf8")) as RepoStats;
|
|
152
|
+
} catch {
|
|
153
|
+
repoStats = {};
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const title = `${siteConfig.name} — ${siteConfig.tagline}`;
|
|
23
158
|
const description =
|
|
24
|
-
|
|
159
|
+
siteConfig.description ?? `A growing community knowledge site powered by Grove.`;
|
|
160
|
+
|
|
161
|
+
// ── Render-time helpers ─────────────────────────────────────────
|
|
162
|
+
function detailHrefFor(r: (typeof records)[number]): string {
|
|
163
|
+
return `/${slug}/${r.slug}`;
|
|
164
|
+
}
|
|
25
165
|
---
|
|
26
166
|
|
|
27
|
-
<BaseLayout
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
167
|
+
<BaseLayout
|
|
168
|
+
title={title}
|
|
169
|
+
description={description}
|
|
170
|
+
site={siteConfig}
|
|
171
|
+
submitHref="/submit"
|
|
172
|
+
submitLabel={`Submit ${itemLabel()}`}
|
|
173
|
+
>
|
|
174
|
+
<Hero
|
|
175
|
+
name={siteConfig.name}
|
|
176
|
+
tagline={siteConfig.tagline}
|
|
177
|
+
description={description}
|
|
178
|
+
eyebrow="Curated directory"
|
|
179
|
+
searchPlaceholder={`Search ${slug}...`}
|
|
180
|
+
searchHref={`/${slug}`}
|
|
181
|
+
stats={{
|
|
182
|
+
apps: totalApps,
|
|
183
|
+
categories: totalCategories,
|
|
184
|
+
stacks: totalStacks,
|
|
185
|
+
contributors: totalContributors || undefined,
|
|
186
|
+
stars: totalStars || undefined,
|
|
187
|
+
}}
|
|
188
|
+
ctas={[
|
|
189
|
+
{ label: `Browse ${slug}`, href: `/${slug}`, variant: "primary" },
|
|
190
|
+
{ label: "About", href: "/about", variant: "outline" },
|
|
191
|
+
]}
|
|
192
|
+
/>
|
|
193
|
+
|
|
194
|
+
<WhyThisExists />
|
|
195
|
+
|
|
196
|
+
<AppSection
|
|
197
|
+
id="hot"
|
|
198
|
+
title="Trending"
|
|
199
|
+
description="The projects getting attention right now — high-star repos and recently active codebases."
|
|
200
|
+
items={hot}
|
|
201
|
+
hrefFor={detailHrefFor}
|
|
202
|
+
viewAllHref={`/${slug}?lens=hot`}
|
|
203
|
+
eyebrow="Hot"
|
|
204
|
+
emptyLabel="No trending projects yet."
|
|
205
|
+
/>
|
|
206
|
+
|
|
207
|
+
<AppSection
|
|
208
|
+
id="new"
|
|
209
|
+
title="Recently added"
|
|
210
|
+
description="Fresh entries — pushed within the last week or carrying the curated 'new' label."
|
|
211
|
+
items={newItems}
|
|
212
|
+
hrefFor={detailHrefFor}
|
|
213
|
+
viewAllHref={`/${slug}?lens=new`}
|
|
214
|
+
eyebrow="New"
|
|
215
|
+
emptyLabel="No new projects yet."
|
|
216
|
+
/>
|
|
217
|
+
|
|
218
|
+
<AppSection
|
|
219
|
+
id="mature"
|
|
220
|
+
title="Established"
|
|
221
|
+
description="Long-running curated projects with deep history and stable architecture."
|
|
222
|
+
items={mature}
|
|
223
|
+
hrefFor={detailHrefFor}
|
|
224
|
+
viewAllHref={`/${slug}?lens=mature`}
|
|
225
|
+
eyebrow="Mature"
|
|
226
|
+
emptyLabel="No established projects yet."
|
|
227
|
+
/>
|
|
228
|
+
|
|
229
|
+
{stacks.length > 0 && (
|
|
230
|
+
<StackGrid
|
|
231
|
+
stacks={stacks}
|
|
232
|
+
pathPrefix={`/${slug}`}
|
|
233
|
+
/>
|
|
234
|
+
)}
|
|
235
|
+
|
|
236
|
+
{categories.length > 0 && (
|
|
237
|
+
<CategoryGrid
|
|
238
|
+
categories={categories}
|
|
239
|
+
pathPrefix={`/${slug}`}
|
|
240
|
+
/>
|
|
241
|
+
)}
|
|
242
|
+
|
|
243
|
+
{hasContributors && (
|
|
244
|
+
<ContributorsGrid
|
|
245
|
+
contributors={contributors!}
|
|
246
|
+
total={contributors!.length}
|
|
247
|
+
viewAllHref={siteConfig.repoUrl || undefined}
|
|
248
|
+
viewAllLabel="View on GitHub"
|
|
249
|
+
/>
|
|
250
|
+
)}
|
|
251
|
+
|
|
252
|
+
{repoStats.originalRepo && (
|
|
253
|
+
<OriginalCollection
|
|
254
|
+
repoUrl={repoStats.originalRepo}
|
|
255
|
+
stats={{
|
|
256
|
+
stars: repoStats.stars,
|
|
257
|
+
forks: repoStats.forks,
|
|
258
|
+
contributors: repoStats.contributors,
|
|
259
|
+
description: repoStats.description,
|
|
260
|
+
}}
|
|
261
|
+
/>
|
|
262
|
+
)}
|
|
66
263
|
</BaseLayout>
|