@grove-dev/astro 0.1.5 → 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,20 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { DirectoryFilters } from "@grove-dev/ui";
|
|
3
|
-
import { activeFilterChips } from "@grove-dev/ui";
|
|
4
|
-
|
|
5
|
-
interface Props {
|
|
6
|
-
filters: DirectoryFilters;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const { filters } = Astro.props;
|
|
10
|
-
const chips = activeFilterChips(filters);
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
{chips.length > 0 && (
|
|
14
|
-
<div class="oc-active-chips" aria-label="Active filters">
|
|
15
|
-
{chips.map((chip) => (
|
|
16
|
-
<span data-filter-chip={chip.key}>{chip.label}</span>
|
|
17
|
-
))}
|
|
18
|
-
<a href="/projects">Clear all</a>
|
|
19
|
-
</div>
|
|
20
|
-
)}
|
|
@@ -1,100 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { HealthStatus } from "@grove-dev/core";
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
q?: string;
|
|
6
|
-
category?: string;
|
|
7
|
-
tag?: string;
|
|
8
|
-
language?: string;
|
|
9
|
-
license?: string;
|
|
10
|
-
health?: string;
|
|
11
|
-
maintained?: boolean;
|
|
12
|
-
hideArchived?: boolean;
|
|
13
|
-
hasRecentRelease?: boolean;
|
|
14
|
-
categories: string[];
|
|
15
|
-
tags: string[];
|
|
16
|
-
languages: string[];
|
|
17
|
-
licenses: string[];
|
|
18
|
-
action?: string;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
const {
|
|
22
|
-
q = "",
|
|
23
|
-
category = "",
|
|
24
|
-
tag = "",
|
|
25
|
-
language = "",
|
|
26
|
-
license = "",
|
|
27
|
-
health = "all",
|
|
28
|
-
maintained = false,
|
|
29
|
-
hideArchived = false,
|
|
30
|
-
hasRecentRelease = false,
|
|
31
|
-
categories,
|
|
32
|
-
tags,
|
|
33
|
-
languages,
|
|
34
|
-
licenses,
|
|
35
|
-
action = "/projects",
|
|
36
|
-
} = Astro.props;
|
|
37
|
-
|
|
38
|
-
const healthOptions: Array<HealthStatus | "all"> = [
|
|
39
|
-
"all",
|
|
40
|
-
"mature",
|
|
41
|
-
"active",
|
|
42
|
-
"stale",
|
|
43
|
-
"needs_review",
|
|
44
|
-
"inactive",
|
|
45
|
-
"archived",
|
|
46
|
-
"unknown",
|
|
47
|
-
];
|
|
48
|
-
---
|
|
49
|
-
|
|
50
|
-
<form class="oc-filters" action={action} method="get" role="search">
|
|
51
|
-
<label class="oc-filter-search">
|
|
52
|
-
<span>Search</span>
|
|
53
|
-
<input type="search" name="q" value={q} placeholder="Name, description, tag, license..." />
|
|
54
|
-
</label>
|
|
55
|
-
<label>
|
|
56
|
-
<span>Category</span>
|
|
57
|
-
<select name="category">
|
|
58
|
-
<option value="">All categories</option>
|
|
59
|
-
{categories.map((value) => <option value={value} selected={value === category}>{value}</option>)}
|
|
60
|
-
</select>
|
|
61
|
-
</label>
|
|
62
|
-
<label>
|
|
63
|
-
<span>Health</span>
|
|
64
|
-
<select name="health">
|
|
65
|
-
{healthOptions.map((value) => (
|
|
66
|
-
<option value={value} selected={value === health}>{value.replace(/_/g, " ")}</option>
|
|
67
|
-
))}
|
|
68
|
-
</select>
|
|
69
|
-
</label>
|
|
70
|
-
<label>
|
|
71
|
-
<span>Tag</span>
|
|
72
|
-
<select name="tag">
|
|
73
|
-
<option value="">All tags</option>
|
|
74
|
-
{tags.map((value) => <option value={value} selected={value === tag}>{value}</option>)}
|
|
75
|
-
</select>
|
|
76
|
-
</label>
|
|
77
|
-
<label>
|
|
78
|
-
<span>Language</span>
|
|
79
|
-
<select name="language">
|
|
80
|
-
<option value="">All languages</option>
|
|
81
|
-
{languages.map((value) => <option value={value} selected={value === language}>{value}</option>)}
|
|
82
|
-
</select>
|
|
83
|
-
</label>
|
|
84
|
-
<label>
|
|
85
|
-
<span>License</span>
|
|
86
|
-
<select name="license">
|
|
87
|
-
<option value="">All licenses</option>
|
|
88
|
-
{licenses.map((value) => <option value={value} selected={value === license}>{value}</option>)}
|
|
89
|
-
</select>
|
|
90
|
-
</label>
|
|
91
|
-
<div class="oc-filter-toggles">
|
|
92
|
-
<label><input type="checkbox" name="maintained" value="1" checked={maintained} /> Maintained only</label>
|
|
93
|
-
<label><input type="checkbox" name="hideArchived" value="1" checked={hideArchived} /> Hide archived</label>
|
|
94
|
-
<label><input type="checkbox" name="hasRecentRelease" value="1" checked={hasRecentRelease} /> Recent release</label>
|
|
95
|
-
</div>
|
|
96
|
-
<div class="oc-filter-actions">
|
|
97
|
-
<button type="submit">Apply</button>
|
|
98
|
-
<a href={action}>Reset</a>
|
|
99
|
-
</div>
|
|
100
|
-
</form>
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { DirectoryStats } from "@grove-dev/ui";
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
name: string;
|
|
6
|
-
tagline: string;
|
|
7
|
-
stats: DirectoryStats;
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
const { name, tagline, stats } = Astro.props;
|
|
11
|
-
---
|
|
12
|
-
|
|
13
|
-
<section class="oc-hero">
|
|
14
|
-
<div>
|
|
15
|
-
<p class="oc-eyebrow">Grove</p>
|
|
16
|
-
<h1>{name}</h1>
|
|
17
|
-
<p class="oc-lede">{tagline}</p>
|
|
18
|
-
</div>
|
|
19
|
-
<form class="oc-hero-search" action="/projects" role="search">
|
|
20
|
-
<label>
|
|
21
|
-
<span class="oc-sr-only">Search projects</span>
|
|
22
|
-
<input type="search" name="q" placeholder="Search projects, tags, licenses..." />
|
|
23
|
-
</label>
|
|
24
|
-
<button type="submit">Search</button>
|
|
25
|
-
</form>
|
|
26
|
-
<dl class="oc-stats">
|
|
27
|
-
<div><dt>Projects</dt><dd>{stats.total}</dd></div>
|
|
28
|
-
<div><dt>Active</dt><dd>{stats.active}</dd></div>
|
|
29
|
-
<div><dt>Mature</dt><dd>{stats.mature}</dd></div>
|
|
30
|
-
<div><dt>Needs review</dt><dd>{stats.needsReview}</dd></div>
|
|
31
|
-
</dl>
|
|
32
|
-
</section>
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { HealthStatus } from "@grove-dev/core";
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
status?: HealthStatus;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const { status = "unknown" } = Astro.props;
|
|
9
|
-
const label = status.replace(/_/g, " ");
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
<span class={`oc-health oc-health-${status}`}>{label}</span>
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import { LENSES } from "@grove-dev/ui";
|
|
3
|
-
|
|
4
|
-
interface Props {
|
|
5
|
-
current?: string;
|
|
6
|
-
action?: string;
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
const { current = "all", action = "/projects" } = Astro.props;
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
<nav class="oc-lenses" aria-label="Curated lenses">
|
|
13
|
-
{LENSES.map((lens) => {
|
|
14
|
-
const params = new URLSearchParams();
|
|
15
|
-
for (const [key, value] of Object.entries(lens.params)) {
|
|
16
|
-
params.set(key, String(value));
|
|
17
|
-
}
|
|
18
|
-
const href = lens.id === "all" ? action : `${action}?${params.toString()}`;
|
|
19
|
-
const active = current === lens.id || (current === "all" && lens.id === "all");
|
|
20
|
-
return (
|
|
21
|
-
<a href={href} data-lens-id={lens.id} aria-current={active ? "page" : undefined} title={lens.description}>
|
|
22
|
-
{lens.label}
|
|
23
|
-
</a>
|
|
24
|
-
);
|
|
25
|
-
})}
|
|
26
|
-
</nav>
|
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
---
|
|
3
|
-
|
|
4
|
-
<section class="oc-methodology">
|
|
5
|
-
<div>
|
|
6
|
-
<p class="oc-eyebrow">Methodology</p>
|
|
7
|
-
<h2>Health is a signal, not an automatic deletion rule.</h2>
|
|
8
|
-
<p>
|
|
9
|
-
Grove checks repository activity, archived state, releases, license,
|
|
10
|
-
adoption, and metadata freshness. Projects can still be kept, highlighted,
|
|
11
|
-
hidden, or preserved as historical through human curation decisions.
|
|
12
|
-
</p>
|
|
13
|
-
</div>
|
|
14
|
-
<ul>
|
|
15
|
-
<li>Archived repositories are flagged clearly.</li>
|
|
16
|
-
<li>Recent commits and releases increase confidence.</li>
|
|
17
|
-
<li>Missing metadata becomes unknown or needs review.</li>
|
|
18
|
-
<li>Humans control final visibility in decisions.yml.</li>
|
|
19
|
-
</ul>
|
|
20
|
-
</section>
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface Props {
|
|
3
|
-
page: number;
|
|
4
|
-
pages: number;
|
|
5
|
-
base?: string;
|
|
6
|
-
}
|
|
7
|
-
|
|
8
|
-
const { page, pages, base = "/projects" } = Astro.props;
|
|
9
|
-
|
|
10
|
-
function href(target: number) {
|
|
11
|
-
const current = new URL(Astro.url);
|
|
12
|
-
current.searchParams.set("page", String(target));
|
|
13
|
-
const query = current.searchParams.toString();
|
|
14
|
-
return `${base}${query ? `?${query}` : ""}`;
|
|
15
|
-
}
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
{pages > 1 && (
|
|
19
|
-
<nav class="oc-pagination" aria-label="Pagination">
|
|
20
|
-
<a href={href(Math.max(1, page - 1))} aria-disabled={page <= 1 ? "true" : undefined}>Previous</a>
|
|
21
|
-
<span>Page {page} of {pages}</span>
|
|
22
|
-
<a href={href(Math.min(pages, page + 1))} aria-disabled={page >= pages ? "true" : undefined}>Next</a>
|
|
23
|
-
</nav>
|
|
24
|
-
)}
|
|
@@ -1,166 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
import type { CuratedItem, HealthEntry, Decision } from "@grove-dev/core";
|
|
3
|
-
import HealthBadge from "./HealthBadge.astro";
|
|
4
|
-
import ScoreBars from "./ScoreBars.astro";
|
|
5
|
-
import { SCORE_LABELS, SCORE_REASONING } from "@grove-dev/ui";
|
|
6
|
-
|
|
7
|
-
interface Props {
|
|
8
|
-
item: CuratedItem;
|
|
9
|
-
health?: HealthEntry;
|
|
10
|
-
decision?: Decision;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const { item, health, decision } = Astro.props;
|
|
14
|
-
const links = Object.entries(item.links).filter(([, href]) => Boolean(href));
|
|
15
|
-
const channels = item.distribution.channels ?? [];
|
|
16
|
-
const languages = health?.github?.languages
|
|
17
|
-
? Object.entries(health.github.languages).sort((a, b) => b[1] - a[1]).slice(0, 5)
|
|
18
|
-
: [];
|
|
19
|
-
const totalLanguageBytes = Math.max(1, languages.reduce((sum, [, bytes]) => sum + bytes, 0));
|
|
20
|
-
const files = health?.github?.files ?? {};
|
|
21
|
-
const fileSignals = [
|
|
22
|
-
["README", files.readme],
|
|
23
|
-
["Contributing", files.contributing],
|
|
24
|
-
["Security", files.security],
|
|
25
|
-
["Issue templates", files.issueTemplates],
|
|
26
|
-
["PR template", files.pullRequestTemplate],
|
|
27
|
-
].filter(([, ok]) => ok !== undefined);
|
|
28
|
-
const monthly = health?.github?.monthlyCommits ?? [];
|
|
29
|
-
const maxCommits = Math.max(1, ...monthly.map((entry) => entry.commits));
|
|
30
|
-
---
|
|
31
|
-
|
|
32
|
-
<article class="oc-detail">
|
|
33
|
-
<header class="oc-detail-header">
|
|
34
|
-
<div>
|
|
35
|
-
<p class="oc-eyebrow">{item.taxonomy.category}</p>
|
|
36
|
-
<h1>{item.name}</h1>
|
|
37
|
-
<p class="oc-lede">{item.description}</p>
|
|
38
|
-
</div>
|
|
39
|
-
<HealthBadge status={health?.health.status} />
|
|
40
|
-
</header>
|
|
41
|
-
|
|
42
|
-
<div class="oc-detail-grid">
|
|
43
|
-
<section class="oc-detail-wide">
|
|
44
|
-
<h2>Curation Scores</h2>
|
|
45
|
-
<ScoreBars scores={item.curation.scores} />
|
|
46
|
-
<dl class="oc-score-reasons">
|
|
47
|
-
{(Object.keys(SCORE_LABELS) as Array<keyof typeof SCORE_LABELS>).map((key) => (
|
|
48
|
-
<div>
|
|
49
|
-
<dt>{SCORE_LABELS[key]}</dt>
|
|
50
|
-
<dd>{SCORE_REASONING[key]}</dd>
|
|
51
|
-
</div>
|
|
52
|
-
))}
|
|
53
|
-
</dl>
|
|
54
|
-
</section>
|
|
55
|
-
<section>
|
|
56
|
-
<h2>Links</h2>
|
|
57
|
-
<ul class="oc-link-list">
|
|
58
|
-
{links.map(([label, href]) => <li><a href={href}>{label}</a></li>)}
|
|
59
|
-
</ul>
|
|
60
|
-
{channels.length > 0 && (
|
|
61
|
-
<>
|
|
62
|
-
<h3>Distribution</h3>
|
|
63
|
-
<ul class="oc-link-list">
|
|
64
|
-
{channels.map((channel) => (
|
|
65
|
-
<li><a href={channel.url}>{channel.label ?? channel.type}</a>{channel.platform ? ` · ${channel.platform}` : ""}</li>
|
|
66
|
-
))}
|
|
67
|
-
</ul>
|
|
68
|
-
</>
|
|
69
|
-
)}
|
|
70
|
-
</section>
|
|
71
|
-
<section>
|
|
72
|
-
<h2>Metadata</h2>
|
|
73
|
-
<dl class="oc-fact-list">
|
|
74
|
-
<div><dt>Stars</dt><dd>{health?.github?.stars?.toLocaleString() ?? "Unknown"}</dd></div>
|
|
75
|
-
<div><dt>Forks</dt><dd>{health?.github?.forks?.toLocaleString() ?? "Unknown"}</dd></div>
|
|
76
|
-
<div><dt>License</dt><dd>{health?.github?.license ?? "Unknown"}</dd></div>
|
|
77
|
-
<div><dt>Language</dt><dd>{item.taxonomy.language ?? health?.github?.language ?? "Unknown"}</dd></div>
|
|
78
|
-
<div><dt>Last activity</dt><dd>{health?.github?.pushedAt?.slice(0, 10) ?? "Unknown"}</dd></div>
|
|
79
|
-
<div><dt>Latest release</dt><dd>{health?.github?.latestReleaseAt?.slice(0, 10) ?? "Unknown"}</dd></div>
|
|
80
|
-
<div><dt>Contributors</dt><dd>{health?.github?.contributorsKnown?.toLocaleString() ?? "Unknown"}</dd></div>
|
|
81
|
-
<div><dt>Open PRs</dt><dd>{health?.github?.openPullRequests?.toLocaleString() ?? "Unknown"}</dd></div>
|
|
82
|
-
</dl>
|
|
83
|
-
</section>
|
|
84
|
-
<section>
|
|
85
|
-
<h2>Health Signals</h2>
|
|
86
|
-
<ul class="oc-signal-list">
|
|
87
|
-
{(health?.health.reasons ?? ["No health metadata available"]).map((reason) => <li>{reason}</li>)}
|
|
88
|
-
</ul>
|
|
89
|
-
</section>
|
|
90
|
-
<section>
|
|
91
|
-
<h2>Curation</h2>
|
|
92
|
-
{decision ? (
|
|
93
|
-
<p><strong>{decision.decision.visibility.replace(/_/g, " ")}</strong>: {decision.decision.reason}</p>
|
|
94
|
-
) : (
|
|
95
|
-
<p>No manual curation decision has been recorded yet.</p>
|
|
96
|
-
)}
|
|
97
|
-
{item.curation.reviewed !== undefined && (
|
|
98
|
-
<p>{item.curation.reviewed ? "Curator reviewed" : "Generated curation pending review"}{item.curation.reviewedBy ? ` by ${item.curation.reviewedBy}` : ""}.</p>
|
|
99
|
-
)}
|
|
100
|
-
{item.source.file && <p class="oc-source">Source: {item.source.file}{item.source.line ? `:${item.source.line}` : ""}</p>}
|
|
101
|
-
</section>
|
|
102
|
-
{(item.curation.bestFor.length > 0 || item.curation.whyListed.length > 0 || item.curation.caveats.length > 0) && (
|
|
103
|
-
<section class="oc-detail-wide">
|
|
104
|
-
<h2>Why Included</h2>
|
|
105
|
-
<div class="oc-curation-columns">
|
|
106
|
-
{item.curation.bestFor.length > 0 && (
|
|
107
|
-
<div>
|
|
108
|
-
<h3>Best for</h3>
|
|
109
|
-
<ul class="oc-signal-list">{item.curation.bestFor.map((value) => <li>{value}</li>)}</ul>
|
|
110
|
-
</div>
|
|
111
|
-
)}
|
|
112
|
-
{item.curation.whyListed.length > 0 && (
|
|
113
|
-
<div>
|
|
114
|
-
<h3>Why listed</h3>
|
|
115
|
-
<ul class="oc-signal-list">{item.curation.whyListed.map((value) => <li>{value}</li>)}</ul>
|
|
116
|
-
</div>
|
|
117
|
-
)}
|
|
118
|
-
{item.curation.caveats.length > 0 && (
|
|
119
|
-
<div>
|
|
120
|
-
<h3>Caveats</h3>
|
|
121
|
-
<ul class="oc-signal-list">{item.curation.caveats.map((value) => <li>{value}</li>)}</ul>
|
|
122
|
-
</div>
|
|
123
|
-
)}
|
|
124
|
-
</div>
|
|
125
|
-
</section>
|
|
126
|
-
)}
|
|
127
|
-
{(languages.length > 0 || fileSignals.length > 0 || monthly.length > 0) && (
|
|
128
|
-
<section class="oc-detail-wide">
|
|
129
|
-
<h2>Repository Signals</h2>
|
|
130
|
-
<div class="oc-repo-signals">
|
|
131
|
-
{languages.length > 0 && (
|
|
132
|
-
<div>
|
|
133
|
-
<h3>Languages</h3>
|
|
134
|
-
<dl class="oc-language-bars">
|
|
135
|
-
{languages.map(([language, bytes]) => (
|
|
136
|
-
<div>
|
|
137
|
-
<dt>{language}</dt>
|
|
138
|
-
<dd><span style={`width: ${(bytes / totalLanguageBytes) * 100}%`}></span></dd>
|
|
139
|
-
</div>
|
|
140
|
-
))}
|
|
141
|
-
</dl>
|
|
142
|
-
</div>
|
|
143
|
-
)}
|
|
144
|
-
{fileSignals.length > 0 && (
|
|
145
|
-
<div>
|
|
146
|
-
<h3>Contribution files</h3>
|
|
147
|
-
<ul class="oc-signal-list">
|
|
148
|
-
{fileSignals.map(([label, ok]) => <li>{ok ? "Found" : "Missing"}: {label}</li>)}
|
|
149
|
-
</ul>
|
|
150
|
-
</div>
|
|
151
|
-
)}
|
|
152
|
-
{monthly.length > 0 && (
|
|
153
|
-
<div>
|
|
154
|
-
<h3>Monthly activity</h3>
|
|
155
|
-
<div class="oc-activity-bars">
|
|
156
|
-
{monthly.map((entry) => (
|
|
157
|
-
<span title={`${entry.month}: ${entry.commits} commits`} style={`height: ${Math.max(8, (entry.commits / maxCommits) * 48)}px`}></span>
|
|
158
|
-
))}
|
|
159
|
-
</div>
|
|
160
|
-
</div>
|
|
161
|
-
)}
|
|
162
|
-
</div>
|
|
163
|
-
</section>
|
|
164
|
-
)}
|
|
165
|
-
</div>
|
|
166
|
-
</article>
|
|
@@ -1,137 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
interface Props {
|
|
3
|
-
repoUrl?: string;
|
|
4
|
-
}
|
|
5
|
-
|
|
6
|
-
const { repoUrl = "" } = Astro.props;
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
<section class="oc-submit-grid">
|
|
10
|
-
<form class="oc-submit-form" id="submit-form">
|
|
11
|
-
<label>
|
|
12
|
-
<span>GitHub URL</span>
|
|
13
|
-
<input id="repo-url" type="url" required placeholder="https://github.com/owner/repo" value={repoUrl} />
|
|
14
|
-
</label>
|
|
15
|
-
<div class="oc-two-col">
|
|
16
|
-
<label><span>Name</span><input id="project-name" type="text" /></label>
|
|
17
|
-
<label><span>Slug</span><input id="project-slug" type="text" /></label>
|
|
18
|
-
</div>
|
|
19
|
-
<label><span>Description</span><textarea id="project-description" rows="3"></textarea></label>
|
|
20
|
-
<div class="oc-two-col">
|
|
21
|
-
<label><span>Category</span><input id="project-category" type="text" placeholder="Developer Tools" /></label>
|
|
22
|
-
<label><span>Language</span><input id="project-language" type="text" placeholder="TypeScript" /></label>
|
|
23
|
-
</div>
|
|
24
|
-
<label><span>Tags</span><input id="project-tags" type="text" placeholder="cli, static-site, search" /></label>
|
|
25
|
-
<label><span>Best for</span><textarea id="project-best-for" rows="3" placeholder="One line per use case"></textarea></label>
|
|
26
|
-
</form>
|
|
27
|
-
<aside class="oc-submit-preview">
|
|
28
|
-
<div class="oc-section-header">
|
|
29
|
-
<h2>YAML draft</h2>
|
|
30
|
-
<button type="button" id="copy-yaml">Copy</button>
|
|
31
|
-
</div>
|
|
32
|
-
<pre><code id="yaml-preview">Paste a GitHub URL to generate a draft.</code></pre>
|
|
33
|
-
<p id="submit-status" aria-live="polite"></p>
|
|
34
|
-
</aside>
|
|
35
|
-
</section>
|
|
36
|
-
|
|
37
|
-
<script>
|
|
38
|
-
type FormField = HTMLInputElement | HTMLTextAreaElement | HTMLElement | null;
|
|
39
|
-
|
|
40
|
-
const fields: Record<string, FormField> = {
|
|
41
|
-
repoUrl: document.querySelector("#repo-url"),
|
|
42
|
-
name: document.querySelector("#project-name"),
|
|
43
|
-
slug: document.querySelector("#project-slug"),
|
|
44
|
-
description: document.querySelector("#project-description"),
|
|
45
|
-
category: document.querySelector("#project-category"),
|
|
46
|
-
language: document.querySelector("#project-language"),
|
|
47
|
-
tags: document.querySelector("#project-tags"),
|
|
48
|
-
bestFor: document.querySelector("#project-best-for"),
|
|
49
|
-
preview: document.querySelector("#yaml-preview"),
|
|
50
|
-
status: document.querySelector("#submit-status"),
|
|
51
|
-
copy: document.querySelector("#copy-yaml"),
|
|
52
|
-
};
|
|
53
|
-
|
|
54
|
-
function valueOf(name: string): string {
|
|
55
|
-
const el = fields[name];
|
|
56
|
-
if (el instanceof HTMLInputElement || el instanceof HTMLTextAreaElement) return el.value;
|
|
57
|
-
return "";
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function setText(name: string, text: string): void {
|
|
61
|
-
const el = fields[name];
|
|
62
|
-
if (el) el.textContent = text;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function slugify(value: string): string {
|
|
66
|
-
return String(value || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
function parseRepo(value: string): { owner: string; repo: string } | null {
|
|
70
|
-
const match = String(value).match(/github\.com\/([^/]+)\/([^/?#]+)/);
|
|
71
|
-
if (!match) return null;
|
|
72
|
-
return { owner: match[1], repo: match[2].replace(/\.git$/, "") };
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function list(values: string[], indent: number): string {
|
|
76
|
-
return values.length
|
|
77
|
-
? values.map((v) => `${" ".repeat(indent)}- ${v}`).join("\n")
|
|
78
|
-
: `${" ".repeat(indent)}[]`;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
function quote(value: string): string {
|
|
82
|
-
return `"${String(value ?? "").replace(/"/g, '\\"')}"`;
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
function generate(): void {
|
|
86
|
-
const repo = parseRepo(valueOf("repoUrl"));
|
|
87
|
-
if (!repo) {
|
|
88
|
-
setText("preview", "Paste a valid GitHub repository URL.");
|
|
89
|
-
return;
|
|
90
|
-
}
|
|
91
|
-
const name = valueOf("name") || repo.repo;
|
|
92
|
-
const slug = valueOf("slug") || slugify(name);
|
|
93
|
-
const tags = valueOf("tags")
|
|
94
|
-
.split(",")
|
|
95
|
-
.map((t) => t.trim())
|
|
96
|
-
.filter(Boolean);
|
|
97
|
-
const bestFor = valueOf("bestFor")
|
|
98
|
-
.split("\n")
|
|
99
|
-
.map((l) => l.trim())
|
|
100
|
-
.filter(Boolean);
|
|
101
|
-
const yaml = [
|
|
102
|
-
`id: ${slug}`,
|
|
103
|
-
`name: ${quote(name)}`,
|
|
104
|
-
`description: ${quote(valueOf("description") || name)}`,
|
|
105
|
-
"links:",
|
|
106
|
-
` github: https://github.com/${repo.owner}/${repo.repo}`,
|
|
107
|
-
"source:",
|
|
108
|
-
" type: manual",
|
|
109
|
-
"taxonomy:",
|
|
110
|
-
` category: ${quote(valueOf("category") || "uncategorized")}`,
|
|
111
|
-
" tags:",
|
|
112
|
-
list(tags, 4),
|
|
113
|
-
...(valueOf("language") ? [` language: ${quote(valueOf("language"))}`] : []),
|
|
114
|
-
"curation:",
|
|
115
|
-
" bestFor:",
|
|
116
|
-
list(bestFor, 4),
|
|
117
|
-
" whyListed: []",
|
|
118
|
-
" caveats: []",
|
|
119
|
-
].join("\n");
|
|
120
|
-
setText("preview", yaml);
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
for (const input of Object.values(fields)) {
|
|
124
|
-
if (input instanceof HTMLInputElement || input instanceof HTMLTextAreaElement) {
|
|
125
|
-
input.addEventListener("input", generate);
|
|
126
|
-
}
|
|
127
|
-
}
|
|
128
|
-
const copyBtn = fields.copy;
|
|
129
|
-
if (copyBtn) {
|
|
130
|
-
copyBtn.addEventListener("click", async () => {
|
|
131
|
-
const previewEl = fields.preview;
|
|
132
|
-
await navigator.clipboard.writeText(previewEl?.textContent ?? "");
|
|
133
|
-
setText("status", "Copied YAML draft.");
|
|
134
|
-
});
|
|
135
|
-
}
|
|
136
|
-
generate();
|
|
137
|
-
</script>
|