@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
package/src/index.ts
CHANGED
|
@@ -1,17 +1,64 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* @grove-dev/astro — Astro
|
|
2
|
+
* @grove-dev/astro — Astro framework adapter for Grove.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
* Astro
|
|
6
|
-
*
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
*
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
15
|
-
*
|
|
4
|
+
* Provides:
|
|
5
|
+
* - `default` export: an Astro integration that wires the
|
|
6
|
+
* `@grove-dev/astro/components/*` and `@grove-dev/astro/layouts/*`
|
|
7
|
+
* subpath imports into Vite so consumer projects can write:
|
|
8
|
+
* import ItemCard from "@grove-dev/astro/components/ItemCard.astro";
|
|
9
|
+
* and have Vite resolve the source `.astro` file (the package's
|
|
10
|
+
* `dist/` only contains TypeScript helpers, not the components
|
|
11
|
+
* themselves).
|
|
12
|
+
* - Re-exports the framework-agnostic `Resource` types from
|
|
13
|
+
* `@grove-dev/core` so the component prop signatures stay
|
|
14
|
+
* type-safe without forcing a dependency on the core package
|
|
15
|
+
* in every consumer file.
|
|
16
|
+
* - Re-exports the generic `lib/` helpers (search, lenses, scores,
|
|
17
|
+
* repo, format, display, taxonomy-counts) under a single import
|
|
18
|
+
* path so consumers can `import { ... } from "@grove-dev/astro"`.
|
|
16
19
|
*/
|
|
17
|
-
|
|
20
|
+
import { fileURLToPath } from "node:url";
|
|
21
|
+
import { dirname, resolve } from "node:path";
|
|
22
|
+
import type { AstroIntegration } from "astro";
|
|
23
|
+
|
|
24
|
+
export * from "@grove-dev/core";
|
|
25
|
+
|
|
26
|
+
// Generic lib helpers — repo URL parsing, formatting, search /
|
|
27
|
+
// facet / sort / paginate, lens application, score tiers, taxonomy
|
|
28
|
+
// counts, and pretty-print display maps. All dependency-free and
|
|
29
|
+
// typed against `@grove-dev/core`.
|
|
30
|
+
export * from "./lib/index.js";
|
|
31
|
+
|
|
32
|
+
const here = dirname(fileURLToPath(import.meta.url));
|
|
33
|
+
// `here` is the compiled `dist/` directory. The components and
|
|
34
|
+
// layouts live in the source tree (the `dist/` is for the
|
|
35
|
+
// integration helper only). Walk up one level to reach `src/`
|
|
36
|
+
// before resolving the subpath roots.
|
|
37
|
+
const srcRoot = resolve(here, "..", "src");
|
|
38
|
+
const componentsDir = resolve(srcRoot, "components");
|
|
39
|
+
const layoutsDir = resolve(srcRoot, "layouts");
|
|
40
|
+
|
|
41
|
+
export default function groveAstro(): AstroIntegration {
|
|
42
|
+
return {
|
|
43
|
+
name: "@grove-dev/astro",
|
|
44
|
+
hooks: {
|
|
45
|
+
"astro:config:setup": ({ updateConfig }) => {
|
|
46
|
+
// Alias the components/layouts source directories so
|
|
47
|
+
// consumer builds can import from
|
|
48
|
+
// @grove-dev/astro/components/ItemCard.astro
|
|
49
|
+
// without us shipping a glob-shaped `exports` map that
|
|
50
|
+
// Vite/Rollup does not expand reliably.
|
|
51
|
+
updateConfig({
|
|
52
|
+
vite: {
|
|
53
|
+
resolve: {
|
|
54
|
+
alias: {
|
|
55
|
+
"@grove-dev/astro/components": componentsDir,
|
|
56
|
+
"@grove-dev/astro/layouts": layoutsDir,
|
|
57
|
+
},
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
});
|
|
61
|
+
},
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -1,32 +1,244 @@
|
|
|
1
1
|
---
|
|
2
|
+
/**
|
|
3
|
+
* BaseLayout — wraps every page. Owns the theme-detection inline
|
|
4
|
+
* script and the global shell (Header, Footer). Per-page SEO
|
|
5
|
+
* (title, description, OG, JSON-LD) is delegated to <Seo /> so each
|
|
6
|
+
* page can declare what it needs without polluting the layout.
|
|
7
|
+
*
|
|
8
|
+
* Generic: takes a `site` prop with brand + nav, no siteConfig import.
|
|
9
|
+
* The header / footer / SEO components are imported from sibling
|
|
10
|
+
* files; consumers can override the Header/Footer via Astro's slot
|
|
11
|
+
* mechanism (`<Header slot="header" />`) if they need custom branding.
|
|
12
|
+
*
|
|
13
|
+
* The THEME_INIT inline script persists user preference in
|
|
14
|
+
* `localStorage` under the key "grove-theme" — matching the key
|
|
15
|
+
* `ThemeToggle.astro` uses.
|
|
16
|
+
*/
|
|
17
|
+
|
|
2
18
|
import "../styles.css";
|
|
19
|
+
import Header from "./Header.astro";
|
|
20
|
+
import Footer from "./Footer.astro";
|
|
21
|
+
import Seo from "./Seo.astro";
|
|
22
|
+
|
|
23
|
+
interface NavItem {
|
|
24
|
+
label: string;
|
|
25
|
+
href: string;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
interface Site {
|
|
29
|
+
name: string;
|
|
30
|
+
tagline?: string;
|
|
31
|
+
description?: string;
|
|
32
|
+
nav: NavItem[];
|
|
33
|
+
repoUrl?: string;
|
|
34
|
+
url?: string;
|
|
35
|
+
}
|
|
3
36
|
|
|
4
37
|
interface Props {
|
|
5
38
|
title: string;
|
|
6
|
-
description
|
|
39
|
+
description: string;
|
|
40
|
+
site: Site;
|
|
41
|
+
type?: "website" | "article" | "profile";
|
|
42
|
+
noindex?: boolean;
|
|
43
|
+
jsonLd?: Record<string, unknown> | Record<string, unknown>[];
|
|
44
|
+
/** Optional Google Analytics 4 Measurement ID (e.g. "G-XXXXXX"). */
|
|
45
|
+
gaId?: string;
|
|
46
|
+
/** Path used for JSON-LD `SearchAction` target. Defaults to "/projects". */
|
|
47
|
+
searchPath?: string;
|
|
48
|
+
/** Submit button label rendered in the header. Omit to hide. */
|
|
49
|
+
submitLabel?: string;
|
|
50
|
+
/** Submit button href rendered in the header. */
|
|
51
|
+
submitHref?: string;
|
|
7
52
|
}
|
|
8
53
|
|
|
9
|
-
const {
|
|
54
|
+
const {
|
|
55
|
+
title,
|
|
56
|
+
description,
|
|
57
|
+
site,
|
|
58
|
+
type,
|
|
59
|
+
noindex,
|
|
60
|
+
jsonLd,
|
|
61
|
+
gaId,
|
|
62
|
+
searchPath,
|
|
63
|
+
submitLabel,
|
|
64
|
+
submitHref,
|
|
65
|
+
} = Astro.props;
|
|
66
|
+
|
|
67
|
+
const favicon =
|
|
68
|
+
"data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16'%3E%3Crect width='16' height='16' rx='3' fill='%2318181b'/%3E%3C/svg%3E";
|
|
10
69
|
---
|
|
11
70
|
|
|
12
71
|
<!doctype html>
|
|
13
72
|
<html lang="en">
|
|
14
73
|
<head>
|
|
15
|
-
<meta charset="
|
|
16
|
-
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
17
|
-
<meta name="
|
|
18
|
-
<
|
|
74
|
+
<meta charset="UTF-8" />
|
|
75
|
+
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
|
76
|
+
<meta name="generator" content={Astro.generator} />
|
|
77
|
+
<meta name="theme-color" content="#0a0a0c" media="(prefers-color-scheme: dark)" />
|
|
78
|
+
<meta name="theme-color" content="#fafafa" media="(prefers-color-scheme: light)" />
|
|
79
|
+
<link rel="icon" href={favicon} />
|
|
80
|
+
<link rel="sitemap" href="/sitemap.xml" />
|
|
81
|
+
<link
|
|
82
|
+
rel="alternate"
|
|
83
|
+
type="text/plain"
|
|
84
|
+
href="/llms.txt"
|
|
85
|
+
title="LLM usage guidance"
|
|
86
|
+
/>
|
|
87
|
+
|
|
88
|
+
{gaId && (
|
|
89
|
+
<>
|
|
90
|
+
{/* GA4 — gtag.js loader. We send the initial page_view with
|
|
91
|
+
the current path + query string so the dashboard
|
|
92
|
+
distinguishes /projects?stack=flutter from
|
|
93
|
+
/projects?stack=react (otherwise they'd all collapse to
|
|
94
|
+
/projects). */}
|
|
95
|
+
<script
|
|
96
|
+
is:inline
|
|
97
|
+
async
|
|
98
|
+
src={`https://www.googletagmanager.com/gtag/js?id=${gaId}`}
|
|
99
|
+
/>
|
|
100
|
+
<script is:inline define:vars={{ gaId }}>
|
|
101
|
+
window.dataLayer = window.dataLayer || [];
|
|
102
|
+
function gtag() {
|
|
103
|
+
dataLayer.push(arguments);
|
|
104
|
+
}
|
|
105
|
+
gtag("js", new Date());
|
|
106
|
+
gtag("config", gaId, {
|
|
107
|
+
page_path: window.location.pathname + window.location.search,
|
|
108
|
+
page_title: document.title,
|
|
109
|
+
});
|
|
110
|
+
</script>
|
|
111
|
+
</>
|
|
112
|
+
)}
|
|
113
|
+
|
|
114
|
+
<Seo
|
|
115
|
+
title={title}
|
|
116
|
+
description={description}
|
|
117
|
+
type={type}
|
|
118
|
+
noindex={noindex}
|
|
119
|
+
jsonLd={jsonLd}
|
|
120
|
+
site={site}
|
|
121
|
+
searchPath={searchPath}
|
|
122
|
+
/>
|
|
123
|
+
|
|
124
|
+
<slot name="head" />
|
|
125
|
+
|
|
126
|
+
<script is:inline>
|
|
127
|
+
// THEME_INIT — runs before paint so the user never sees a
|
|
128
|
+
// flash of the wrong theme. State is persisted in localStorage
|
|
129
|
+
// under the key "grove-theme" (matching ThemeToggle.astro).
|
|
130
|
+
(function () {
|
|
131
|
+
var STORAGE_KEY = "grove-theme";
|
|
132
|
+
function getMode() {
|
|
133
|
+
try {
|
|
134
|
+
var stored = localStorage.getItem(STORAGE_KEY);
|
|
135
|
+
if (stored === "light" || stored === "dark" || stored === "system")
|
|
136
|
+
return stored;
|
|
137
|
+
} catch (e) {
|
|
138
|
+
// localStorage may be blocked (private mode, etc.) —
|
|
139
|
+
// fall through to the system default.
|
|
140
|
+
}
|
|
141
|
+
return "system";
|
|
142
|
+
}
|
|
143
|
+
function apply(mode) {
|
|
144
|
+
var resolved =
|
|
145
|
+
mode === "system"
|
|
146
|
+
? (window.matchMedia("(prefers-color-scheme: dark)").matches
|
|
147
|
+
? "dark"
|
|
148
|
+
: "light")
|
|
149
|
+
: mode;
|
|
150
|
+
var root = document.documentElement;
|
|
151
|
+
if (resolved === "dark") root.classList.add("dark");
|
|
152
|
+
else root.classList.remove("dark");
|
|
153
|
+
root.dataset.theme = mode;
|
|
154
|
+
root.dataset.resolvedTheme = resolved;
|
|
155
|
+
}
|
|
156
|
+
apply(getMode());
|
|
157
|
+
window.addEventListener("theme:set", function (e) {
|
|
158
|
+
apply(e.detail);
|
|
159
|
+
});
|
|
160
|
+
var mq = window.matchMedia("(prefers-color-scheme: dark)");
|
|
161
|
+
mq.addEventListener("change", function () {
|
|
162
|
+
if (getMode() === "system") apply("system");
|
|
163
|
+
});
|
|
164
|
+
})();
|
|
165
|
+
</script>
|
|
19
166
|
</head>
|
|
20
|
-
<body>
|
|
21
|
-
<
|
|
22
|
-
<
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
</
|
|
28
|
-
|
|
167
|
+
<body class="min-h-screen bg-white text-ink-900 dark:bg-ink-950 dark:text-ink-100">
|
|
168
|
+
<slot name="header">
|
|
169
|
+
<Header
|
|
170
|
+
site={site}
|
|
171
|
+
submitLabel={submitLabel}
|
|
172
|
+
submitHref={submitHref}
|
|
173
|
+
/>
|
|
174
|
+
</slot>
|
|
175
|
+
|
|
176
|
+
<main>
|
|
29
177
|
<slot />
|
|
30
178
|
</main>
|
|
179
|
+
|
|
180
|
+
<slot name="footer">
|
|
181
|
+
<Footer site={site} />
|
|
182
|
+
</slot>
|
|
183
|
+
|
|
184
|
+
<slot name="body-end" />
|
|
185
|
+
|
|
186
|
+
{gaId && (
|
|
187
|
+
<script is:inline define:vars={{ gaId }}>
|
|
188
|
+
// Mirror in-page SPA navigation (history.pushState /
|
|
189
|
+
// replaceState) into GA4 page_view events so filter changes
|
|
190
|
+
// on /projects show up as separate page views in the
|
|
191
|
+
// dashboard instead of one inflated session.
|
|
192
|
+
(function () {
|
|
193
|
+
var last = location.pathname + location.search;
|
|
194
|
+
function report() {
|
|
195
|
+
var next = location.pathname + location.search;
|
|
196
|
+
if (next === last) return;
|
|
197
|
+
last = next;
|
|
198
|
+
window.gtag("event", "page_view", {
|
|
199
|
+
page_path: next,
|
|
200
|
+
page_title: document.title,
|
|
201
|
+
page_location: location.href,
|
|
202
|
+
});
|
|
203
|
+
}
|
|
204
|
+
window.addEventListener("popstate", report);
|
|
205
|
+
var origPush = history.pushState;
|
|
206
|
+
var origReplace = history.replaceState;
|
|
207
|
+
history.pushState = function () {
|
|
208
|
+
origPush.apply(this, arguments);
|
|
209
|
+
report();
|
|
210
|
+
};
|
|
211
|
+
history.replaceState = function () {
|
|
212
|
+
origReplace.apply(this, arguments);
|
|
213
|
+
report();
|
|
214
|
+
};
|
|
215
|
+
})();
|
|
216
|
+
</script>
|
|
217
|
+
)}
|
|
218
|
+
|
|
219
|
+
{gaId && (
|
|
220
|
+
<script is:inline>
|
|
221
|
+
// Delegated click handler for `data-event` elements. We do
|
|
222
|
+
// this in one place so individual components just emit data
|
|
223
|
+
// attributes and stay declarative.
|
|
224
|
+
(function () {
|
|
225
|
+
document.addEventListener("click", function (e) {
|
|
226
|
+
var el = e.target instanceof Element
|
|
227
|
+
? e.target.closest("[data-event]")
|
|
228
|
+
: null;
|
|
229
|
+
if (!el) return;
|
|
230
|
+
var name = el.getAttribute("data-event");
|
|
231
|
+
if (!name) return;
|
|
232
|
+
var params = {
|
|
233
|
+
source: el.getAttribute("data-event-source") || undefined,
|
|
234
|
+
app_slug: el.getAttribute("data-event-app") || undefined,
|
|
235
|
+
channel: el.getAttribute("data-event-channel") || undefined,
|
|
236
|
+
link_url: el.getAttribute("href") || undefined,
|
|
237
|
+
};
|
|
238
|
+
window.gtag("event", name, params);
|
|
239
|
+
});
|
|
240
|
+
})();
|
|
241
|
+
</script>
|
|
242
|
+
)}
|
|
31
243
|
</body>
|
|
32
244
|
</html>
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Container — page-width wrapper.
|
|
4
|
+
*
|
|
5
|
+
* Centralizes the three layout widths the showcase uses:
|
|
6
|
+
*
|
|
7
|
+
* - "default" → 1140px (the standard reading width)
|
|
8
|
+
* - "wide" → 1400px (home, full-bleed grid sections)
|
|
9
|
+
* - "narrow" → 720px (about, methodology, content-heavy pages)
|
|
10
|
+
*
|
|
11
|
+
* Pure layout, no styling dependencies beyond Tailwind's `max-w-*`
|
|
12
|
+
* tokens defined in `@grove-dev/astro/styles.css`.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
interface Props {
|
|
16
|
+
size?: "default" | "wide" | "narrow";
|
|
17
|
+
class?: string;
|
|
18
|
+
/** Padding preset. Defaults to a comfortable 1.25rem / 1.75rem. */
|
|
19
|
+
padding?: "default" | "none" | "tight";
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
const {
|
|
23
|
+
size = "default",
|
|
24
|
+
class: className = "",
|
|
25
|
+
padding = "default",
|
|
26
|
+
} = Astro.props;
|
|
27
|
+
|
|
28
|
+
const sizeClass =
|
|
29
|
+
size === "wide"
|
|
30
|
+
? "grove-container-wide"
|
|
31
|
+
: size === "narrow"
|
|
32
|
+
? "grove-container-narrow"
|
|
33
|
+
: "grove-container";
|
|
34
|
+
|
|
35
|
+
const paddingClass =
|
|
36
|
+
padding === "none"
|
|
37
|
+
? ""
|
|
38
|
+
: padding === "tight"
|
|
39
|
+
? "px-4 sm:px-5"
|
|
40
|
+
: "px-5 sm:px-7";
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
<div class:list={["mx-auto", sizeClass, paddingClass, className]}>
|
|
44
|
+
<slot />
|
|
45
|
+
</div>
|
|
46
|
+
|
|
47
|
+
<style>
|
|
48
|
+
.grove-container {
|
|
49
|
+
max-width: var(--container-container, 1140px);
|
|
50
|
+
}
|
|
51
|
+
.grove-container-wide {
|
|
52
|
+
max-width: var(--container-wide, 1400px);
|
|
53
|
+
}
|
|
54
|
+
.grove-container-narrow {
|
|
55
|
+
max-width: var(--container-narrow, 720px);
|
|
56
|
+
}
|
|
57
|
+
</style>
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
---
|
|
2
|
+
/**
|
|
3
|
+
* Footer — 4-column grid (brand + Discover + Contribute + Project) plus
|
|
4
|
+
* a thin bar at the bottom with copyright + repo link.
|
|
5
|
+
*
|
|
6
|
+
* Generic: takes a `site` prop with brand + repoUrl. No siteConfig
|
|
7
|
+
* import — consumers compose props from their own config.
|
|
8
|
+
*
|
|
9
|
+
* Each column's links are passed in as a `{ heading, items[] }` shape
|
|
10
|
+
* so consumers can customize the order and copy. Defaults are provided
|
|
11
|
+
* for the brand and bar so the footer still renders if no extra
|
|
12
|
+
* link data is supplied.
|
|
13
|
+
*/
|
|
14
|
+
|
|
15
|
+
interface NavItem {
|
|
16
|
+
label: string;
|
|
17
|
+
href: string;
|
|
18
|
+
/** When true, opens in a new tab (external). */
|
|
19
|
+
external?: boolean;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
interface FooterColumn {
|
|
23
|
+
heading: string;
|
|
24
|
+
items: NavItem[];
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface Site {
|
|
28
|
+
name: string;
|
|
29
|
+
tagline?: string;
|
|
30
|
+
description?: string;
|
|
31
|
+
repoUrl?: string;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface Props {
|
|
35
|
+
site: Site;
|
|
36
|
+
/** Discover links — first content column. */
|
|
37
|
+
discover?: FooterColumn;
|
|
38
|
+
/** Contribute links — second content column. */
|
|
39
|
+
contribute?: FooterColumn;
|
|
40
|
+
/** Project links — third content column. */
|
|
41
|
+
project?: FooterColumn;
|
|
42
|
+
/** Stats line under brand blurb (e.g. "79 apps · 12 categories"). */
|
|
43
|
+
stats?: { apps?: number; categories?: number; contributors?: number };
|
|
44
|
+
/** Copyright suffix. Defaults to site.name. */
|
|
45
|
+
copyrightHolder?: string;
|
|
46
|
+
/** License line under the bar (e.g. "Content under CC BY-SA 4.0."). */
|
|
47
|
+
licenseLine?: string;
|
|
48
|
+
/** Extra class for the outer footer element. */
|
|
49
|
+
class?: string;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const {
|
|
53
|
+
site,
|
|
54
|
+
discover = { heading: "Discover", items: [] },
|
|
55
|
+
contribute = { heading: "Contribute", items: [] },
|
|
56
|
+
project = { heading: "Project", items: [] },
|
|
57
|
+
stats,
|
|
58
|
+
copyrightHolder,
|
|
59
|
+
licenseLine,
|
|
60
|
+
class: className = "",
|
|
61
|
+
} = Astro.props;
|
|
62
|
+
|
|
63
|
+
const year = new Date().getFullYear();
|
|
64
|
+
const holder = copyrightHolder ?? site.name;
|
|
65
|
+
const gh = site.repoUrl;
|
|
66
|
+
|
|
67
|
+
const defaultDiscover: NavItem[] = gh
|
|
68
|
+
? [
|
|
69
|
+
{ label: "Source on GitHub", href: gh, external: true },
|
|
70
|
+
{ label: "Latest release", href: `${gh}/releases`, external: true },
|
|
71
|
+
]
|
|
72
|
+
: [];
|
|
73
|
+
const defaultContribute: NavItem[] = gh
|
|
74
|
+
? [
|
|
75
|
+
{ label: "Submit via GitHub", href: `${gh}/blob/main/CONTRIBUTING.md`, external: true },
|
|
76
|
+
{ label: "Report an issue", href: `${gh}/issues`, external: true },
|
|
77
|
+
{ label: "Contributing guide", href: `${gh}/blob/main/CONTRIBUTING.md`, external: true },
|
|
78
|
+
]
|
|
79
|
+
: [];
|
|
80
|
+
const defaultProject: NavItem[] = gh
|
|
81
|
+
? [
|
|
82
|
+
{ label: "README", href: `${gh}/blob/main/README.md`, external: true },
|
|
83
|
+
{ label: "Changelog", href: `${gh}/blob/main/CHANGELOG.md`, external: true },
|
|
84
|
+
]
|
|
85
|
+
: [];
|
|
86
|
+
|
|
87
|
+
const discoverItems = discover.items.length ? discover.items : defaultDiscover;
|
|
88
|
+
const contributeItems = contribute.items.length ? contribute.items : defaultContribute;
|
|
89
|
+
const projectItems = project.items.length ? project.items : defaultProject;
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
<footer
|
|
93
|
+
class:list={[
|
|
94
|
+
"mt-16 border-t border-ink-200 bg-white text-ink-500 dark:border-ink-800 dark:bg-ink-950 dark:text-ink-400",
|
|
95
|
+
className,
|
|
96
|
+
]}
|
|
97
|
+
>
|
|
98
|
+
<div
|
|
99
|
+
class="mx-auto grid max-w-wide grid-cols-2 gap-8 px-5 py-12 md:grid-cols-4 sm:px-7"
|
|
100
|
+
style="max-width: var(--container-wide, 1400px);"
|
|
101
|
+
>
|
|
102
|
+
<div class="col-span-2 md:col-span-1">
|
|
103
|
+
<div
|
|
104
|
+
class="mb-2 inline-flex items-center gap-2 text-[0.95rem] font-semibold text-ink-900 dark:text-ink-100"
|
|
105
|
+
>
|
|
106
|
+
<span
|
|
107
|
+
aria-hidden="true"
|
|
108
|
+
class="inline-block h-3.5 w-3.5 rounded bg-ink-900 dark:bg-ink-100"
|
|
109
|
+
></span>
|
|
110
|
+
<span>{site.name}</span>
|
|
111
|
+
</div>
|
|
112
|
+
{site.tagline && (
|
|
113
|
+
<p class="m-0 max-w-[36ch] text-[0.8125rem] leading-relaxed text-ink-500 dark:text-ink-400">
|
|
114
|
+
{site.tagline}
|
|
115
|
+
</p>
|
|
116
|
+
)}
|
|
117
|
+
{stats && (
|
|
118
|
+
<p class="mt-3 m-0 text-2xs text-ink-500 dark:text-ink-400">
|
|
119
|
+
{stats.apps !== undefined && (
|
|
120
|
+
<>
|
|
121
|
+
<span class="font-mono">{stats.apps}</span> apps
|
|
122
|
+
</>
|
|
123
|
+
)}
|
|
124
|
+
{stats.apps !== undefined && (stats.categories !== undefined || stats.contributors !== undefined) && (
|
|
125
|
+
<span class="mx-1 text-ink-300 dark:text-ink-700">·</span>
|
|
126
|
+
)}
|
|
127
|
+
{stats.categories !== undefined && (
|
|
128
|
+
<>
|
|
129
|
+
<span class="font-mono">{stats.categories}</span> categories
|
|
130
|
+
</>
|
|
131
|
+
)}
|
|
132
|
+
{stats.categories !== undefined && stats.contributors !== undefined && (
|
|
133
|
+
<span class="mx-1 text-ink-300 dark:text-ink-700">·</span>
|
|
134
|
+
)}
|
|
135
|
+
{stats.contributors !== undefined && (
|
|
136
|
+
<>
|
|
137
|
+
<span class="font-mono">{stats.contributors}</span> contributors
|
|
138
|
+
</>
|
|
139
|
+
)}
|
|
140
|
+
</p>
|
|
141
|
+
)}
|
|
142
|
+
</div>
|
|
143
|
+
|
|
144
|
+
{discoverItems.length > 0 && (
|
|
145
|
+
<div>
|
|
146
|
+
<h4 class="mb-3 text-2xs font-semibold uppercase tracking-wider text-ink-900 dark:text-ink-100">
|
|
147
|
+
{discover.heading}
|
|
148
|
+
</h4>
|
|
149
|
+
<ul class="m-0 flex list-none flex-col gap-2 p-0">
|
|
150
|
+
{discoverItems.map((item) => (
|
|
151
|
+
<li>
|
|
152
|
+
<a
|
|
153
|
+
href={item.href}
|
|
154
|
+
class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100"
|
|
155
|
+
{...(item.external
|
|
156
|
+
? { target: "_blank", rel: "noopener noreferrer" }
|
|
157
|
+
: {})}
|
|
158
|
+
>
|
|
159
|
+
{item.label}
|
|
160
|
+
</a>
|
|
161
|
+
</li>
|
|
162
|
+
))}
|
|
163
|
+
</ul>
|
|
164
|
+
</div>
|
|
165
|
+
)}
|
|
166
|
+
|
|
167
|
+
{contributeItems.length > 0 && (
|
|
168
|
+
<div>
|
|
169
|
+
<h4 class="mb-3 text-2xs font-semibold uppercase tracking-wider text-ink-900 dark:text-ink-100">
|
|
170
|
+
{contribute.heading}
|
|
171
|
+
</h4>
|
|
172
|
+
<ul class="m-0 flex list-none flex-col gap-2 p-0">
|
|
173
|
+
{contributeItems.map((item) => (
|
|
174
|
+
<li>
|
|
175
|
+
<a
|
|
176
|
+
href={item.href}
|
|
177
|
+
class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100"
|
|
178
|
+
{...(item.external
|
|
179
|
+
? { target: "_blank", rel: "noopener noreferrer" }
|
|
180
|
+
: {})}
|
|
181
|
+
>
|
|
182
|
+
{item.label}
|
|
183
|
+
</a>
|
|
184
|
+
</li>
|
|
185
|
+
))}
|
|
186
|
+
</ul>
|
|
187
|
+
</div>
|
|
188
|
+
)}
|
|
189
|
+
|
|
190
|
+
{projectItems.length > 0 && (
|
|
191
|
+
<div>
|
|
192
|
+
<h4 class="mb-3 text-2xs font-semibold uppercase tracking-wider text-ink-900 dark:text-ink-100">
|
|
193
|
+
{project.heading}
|
|
194
|
+
</h4>
|
|
195
|
+
<ul class="m-0 flex list-none flex-col gap-2 p-0">
|
|
196
|
+
{projectItems.map((item) => (
|
|
197
|
+
<li>
|
|
198
|
+
<a
|
|
199
|
+
href={item.href}
|
|
200
|
+
class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100"
|
|
201
|
+
{...(item.external
|
|
202
|
+
? { target: "_blank", rel: "noopener noreferrer" }
|
|
203
|
+
: {})}
|
|
204
|
+
>
|
|
205
|
+
{item.label}
|
|
206
|
+
</a>
|
|
207
|
+
</li>
|
|
208
|
+
))}
|
|
209
|
+
</ul>
|
|
210
|
+
</div>
|
|
211
|
+
)}
|
|
212
|
+
</div>
|
|
213
|
+
|
|
214
|
+
<div class="border-t border-ink-200 dark:border-ink-800">
|
|
215
|
+
<div
|
|
216
|
+
class="mx-auto flex max-w-wide flex-wrap items-center gap-3 px-5 py-4 text-2xs text-ink-500 sm:px-7 dark:text-ink-400"
|
|
217
|
+
style="max-width: var(--container-wide, 1400px);"
|
|
218
|
+
>
|
|
219
|
+
<span>© {year} {holder}.{licenseLine ? ` ${licenseLine}` : ""}</span>
|
|
220
|
+
{gh && (
|
|
221
|
+
<>
|
|
222
|
+
<span class="text-ink-300 dark:text-ink-700">·</span>
|
|
223
|
+
<a
|
|
224
|
+
href={gh}
|
|
225
|
+
target="_blank"
|
|
226
|
+
rel="noopener noreferrer"
|
|
227
|
+
class="transition-colors hover:text-ink-900 dark:hover:text-ink-100"
|
|
228
|
+
>
|
|
229
|
+
View source on GitHub
|
|
230
|
+
</a>
|
|
231
|
+
</>
|
|
232
|
+
)}
|
|
233
|
+
</div>
|
|
234
|
+
</div>
|
|
235
|
+
</footer>
|