@grove-dev/astro 0.1.5 → 0.2.5

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.
Files changed (148) hide show
  1. package/LICENSE +21 -0
  2. package/dist/index.d.ts +4 -25
  3. package/dist/index.d.ts.map +1 -1
  4. package/dist/index.js +56 -22
  5. package/dist/index.js.map +1 -1
  6. package/dist/layouts/index.d.ts +25 -0
  7. package/dist/layouts/index.d.ts.map +1 -0
  8. package/dist/layouts/index.js +25 -0
  9. package/dist/layouts/index.js.map +1 -0
  10. package/dist/lib/display.d.ts +33 -0
  11. package/dist/lib/display.d.ts.map +1 -0
  12. package/dist/lib/display.js +104 -0
  13. package/dist/lib/display.js.map +1 -0
  14. package/dist/lib/format.d.ts +30 -0
  15. package/dist/lib/format.d.ts.map +1 -0
  16. package/dist/lib/format.js +73 -0
  17. package/dist/lib/format.js.map +1 -0
  18. package/dist/lib/index.d.ts +26 -0
  19. package/dist/lib/index.d.ts.map +1 -0
  20. package/dist/lib/index.js +26 -0
  21. package/dist/lib/index.js.map +1 -0
  22. package/dist/lib/lenses.d.ts +96 -0
  23. package/dist/lib/lenses.d.ts.map +1 -0
  24. package/dist/lib/lenses.js +181 -0
  25. package/dist/lib/lenses.js.map +1 -0
  26. package/dist/lib/repo.d.ts +30 -0
  27. package/dist/lib/repo.d.ts.map +1 -0
  28. package/dist/lib/repo.js +44 -0
  29. package/dist/lib/repo.js.map +1 -0
  30. package/dist/lib/scores.d.ts +38 -0
  31. package/dist/lib/scores.d.ts.map +1 -0
  32. package/dist/lib/scores.js +83 -0
  33. package/dist/lib/scores.js.map +1 -0
  34. package/dist/lib/search.d.ts +199 -0
  35. package/dist/lib/search.d.ts.map +1 -0
  36. package/dist/lib/search.js +357 -0
  37. package/dist/lib/search.js.map +1 -0
  38. package/dist/lib/taxonomy-counts.d.ts +25 -0
  39. package/dist/lib/taxonomy-counts.d.ts.map +1 -0
  40. package/dist/lib/taxonomy-counts.js +41 -0
  41. package/dist/lib/taxonomy-counts.js.map +1 -0
  42. package/package.json +7 -7
  43. package/src/components/AppsIndexRow.astro +204 -0
  44. package/src/components/AppsPagination.astro +126 -0
  45. package/src/components/CategoryGrid.astro +86 -17
  46. package/src/components/ContributorsGrid.astro +149 -0
  47. package/src/components/DecisionRow.astro +89 -0
  48. package/src/components/ExploreByCategory.astro +67 -0
  49. package/src/components/ExploreByStack.astro +72 -0
  50. package/src/components/Hero.astro +246 -0
  51. package/src/components/Icon.astro +223 -0
  52. package/src/components/ItemCard.astro +306 -30
  53. package/src/components/MinimalAbout.astro +82 -0
  54. package/src/components/OriginalCollection.astro +116 -0
  55. package/src/components/RecordSection.astro +88 -0
  56. package/src/components/RefinePanel.astro +197 -0
  57. package/src/components/ScoreBars.astro +92 -22
  58. package/src/components/SmartLensTabs.astro +71 -0
  59. package/src/components/StackGrid.astro +132 -0
  60. package/src/components/WhyThisExists.astro +116 -0
  61. package/src/index.ts +61 -14
  62. package/src/layouts/BaseLayout.astro +227 -15
  63. package/src/layouts/Container.astro +57 -0
  64. package/src/layouts/Footer.astro +235 -0
  65. package/src/layouts/Header.astro +159 -0
  66. package/src/layouts/SectionHeader.astro +58 -0
  67. package/{templates/default/src/components/layout → src/layouts}/Seo.astro +62 -38
  68. package/src/layouts/ThemeToggle.astro +110 -0
  69. package/src/layouts/astro-shim.d.ts +29 -0
  70. package/src/layouts/index.ts +24 -0
  71. package/src/lib/display.ts +118 -0
  72. package/src/lib/format.ts +65 -0
  73. package/src/lib/index.ts +26 -0
  74. package/src/lib/lenses.ts +241 -0
  75. package/src/lib/repo.ts +44 -0
  76. package/src/lib/scores.ts +94 -0
  77. package/src/lib/search.ts +481 -0
  78. package/src/lib/taxonomy-counts.ts +60 -0
  79. package/src/styles.css +366 -638
  80. package/templates/default/astro.config.mjs +8 -6
  81. package/templates/default/content/pages/about.md +66 -0
  82. package/templates/default/content/pages/methodology.md +103 -0
  83. package/templates/default/data/generated/records.full.json +8 -0
  84. package/templates/default/data/generated/records.index.json +7 -0
  85. package/templates/default/data/generated/records.json +8 -0
  86. package/templates/default/data/generated/site-config.json +31 -0
  87. package/templates/default/data/records/.gitkeep +0 -0
  88. package/templates/default/grove.config.ts +36 -0
  89. package/templates/default/package.json +6 -5
  90. package/templates/default/public/llms-full.txt +14 -0
  91. package/templates/default/public/llms.txt +11 -0
  92. package/templates/default/src/components/layout/BaseLayout.astro +10 -57
  93. package/templates/default/src/components/layout/Footer.astro +16 -134
  94. package/templates/default/src/components/layout/Header.astro +25 -126
  95. package/templates/default/src/data/records.ts +193 -0
  96. package/templates/default/src/lib/markdown.ts +171 -0
  97. package/templates/default/src/pages/about.astro +95 -429
  98. package/templates/default/src/pages/index.astro +263 -61
  99. package/templates/default/src/pages/projects/[slug].astro +480 -0
  100. package/templates/default/src/pages/projects/index.astro +193 -0
  101. package/templates/default/src/pages/sitemap.xml.ts +73 -61
  102. package/templates/default/src/pages/submit.astro +122 -411
  103. package/templates/default/src/styles/global.css +42 -68
  104. package/src/components/ActiveFilterChips.astro +0 -20
  105. package/src/components/DirectoryFilters.astro +0 -100
  106. package/src/components/DirectoryHero.astro +0 -32
  107. package/src/components/HealthBadge.astro +0 -12
  108. package/src/components/LensTabs.astro +0 -26
  109. package/src/components/MethodologyPanel.astro +0 -20
  110. package/src/components/Pagination.astro +0 -24
  111. package/src/components/ProjectDetail.astro +0 -166
  112. package/src/components/SubmitDraft.astro +0 -137
  113. package/templates/default/src/components/AppCard.astro +0 -248
  114. package/templates/default/src/components/AppSection.astro +0 -58
  115. package/templates/default/src/components/AppsIndexRow.astro +0 -230
  116. package/templates/default/src/components/AppsPagination.astro +0 -147
  117. package/templates/default/src/components/CategoryGrid.astro +0 -80
  118. package/templates/default/src/components/ContributorsGrid.astro +0 -105
  119. package/templates/default/src/components/DecisionRow.astro +0 -219
  120. package/templates/default/src/components/ExploreByCategory.astro +0 -74
  121. package/templates/default/src/components/ExploreByStack.astro +0 -102
  122. package/templates/default/src/components/Hero.astro +0 -176
  123. package/templates/default/src/components/MinimalAbout.astro +0 -57
  124. package/templates/default/src/components/OriginalCollection.astro +0 -144
  125. package/templates/default/src/components/RefinePanel.astro +0 -272
  126. package/templates/default/src/components/ScoreBars.astro +0 -72
  127. package/templates/default/src/components/SmartLensTabs.astro +0 -65
  128. package/templates/default/src/components/StackGrid.astro +0 -95
  129. package/templates/default/src/components/WhyThisExists.astro +0 -81
  130. package/templates/default/src/components/icons/Icon.astro +0 -148
  131. package/templates/default/src/components/layout/SectionHeader.astro +0 -42
  132. package/templates/default/src/components/layout/ThemeToggle.astro +0 -97
  133. package/templates/default/src/data/apps.ts +0 -149
  134. package/templates/default/src/data/categories.ts +0 -27
  135. package/templates/default/src/data/config.ts +0 -28
  136. package/templates/default/src/data/contributors.ts +0 -96
  137. package/templates/default/src/data/stacks.ts +0 -47
  138. package/templates/default/src/data/stats.ts +0 -65
  139. package/templates/default/src/data/types.ts +0 -248
  140. package/templates/default/src/lib/apps-search.ts +0 -228
  141. package/templates/default/src/lib/format.ts +0 -36
  142. package/templates/default/src/lib/lenses.ts +0 -98
  143. package/templates/default/src/lib/repo.ts +0 -12
  144. package/templates/default/src/lib/scores.ts +0 -51
  145. package/templates/default/src/lib/taxonomy-counts.ts +0 -31
  146. package/templates/default/src/pages/apps/[slug].astro +0 -709
  147. package/templates/default/src/pages/apps/index.astro +0 -669
  148. package/templates/default/src/pages/contributors.astro +0 -142
@@ -2,18 +2,20 @@
2
2
  // SPDX-License-Identifier: MIT
3
3
  import { defineConfig } from 'astro/config';
4
4
  import tailwindcss from '@tailwindcss/vite';
5
+ import groveAstro from '@grove-dev/astro';
5
6
 
6
7
  // `site` is the canonical URL the build uses for absolute links
7
- // (sitemap, OpenGraph, canonical tags, JSON-LD). Set curated.config.ts
8
- // `siteUrl` and run `grove build` this file is read by
9
- // Astro directly.
8
+ // (sitemap, OpenGraph, canonical tags, JSON-LD). The CLI injects
9
+ // `grove.config.ts` `site.url` at scaffold time, but it can also
10
+ // be overridden per-build via the `SITE_URL` env var.
10
11
  //
11
- // The sitemap itself is generated by a custom Astro endpoint at
12
- // `src/pages/sitemap.xml.ts` rather than `@astrojs/sitemap`, so the
13
- // public URL is exactly `/sitemap.xml` (no `-index.xml` suffix).
12
+ // The sitemap is generated by the CLI's `grove sitemap` command
13
+ // into `public/sitemap.xml`; the public URL is exactly `/sitemap.xml`
14
+ // (no `-index.xml` suffix).
14
15
  export default defineConfig({
15
16
  site: process.env.SITE_URL || 'https://example.com',
16
17
  trailingSlash: 'ignore',
18
+ integrations: [groveAstro()],
17
19
  vite: {
18
20
  plugins: [tailwindcss()],
19
21
  },
@@ -0,0 +1,66 @@
1
+ ---
2
+ title: "About"
3
+ description: "What this directory is, who it's for, and how it works."
4
+ ---
5
+
6
+ # About this directory
7
+
8
+ This site is a small, hand-curated index of useful open-source work
9
+ relevant to a specific community. The framing is deliberately
10
+ narrow: we list *one* project per record, with a hand-written
11
+ "why listed" note for each, and we surface the things that matter
12
+ in practice (recent activity, install friction, license, etc.)
13
+ rather than the things that look impressive on a GitHub profile.
14
+
15
+ ## How it works
16
+
17
+ Records live as YAML files in `data/records/`. Each record carries:
18
+
19
+ - A `kind` (`project`, `resource`, or `entity` — picked by the
20
+ blueprint in `grove.config.ts`).
21
+ - A `slug` (URL-safe identifier; becomes the path on
22
+ `/<kind>/<slug>`).
23
+ - A `name` and a one-line `description`.
24
+ - Cross-links (`links.github`, `links.website`, etc.) and free-form
25
+ tags.
26
+ - An optional `curation` block with `labels`, `reviewedAt`,
27
+ `bestFor`, `whyListed`, `caveats`, and `scores`.
28
+ - An optional `github` block with the live repository signals
29
+ (stars, forks, latest release, languages, pushed-at).
30
+
31
+ At build time:
32
+
33
+ 1. `grove validate` checks every record against the JSON schema.
34
+ 2. `grove generate` writes `data/generated/records.{full,index}.json`
35
+ and `data/generated/site-config.json`.
36
+ 3. `grove sitemap` writes `public/sitemap.xml`.
37
+ 4. `grove llms` writes `public/llms.txt` and `llms-full.txt`.
38
+ 5. `astro build` produces the static output.
39
+
40
+ The whole pipeline is reproducible. The records are the source of
41
+ truth; everything else is derived.
42
+
43
+ ## Why a static site
44
+
45
+ The directory is a *reference*, not an *app*. Static HTML is the
46
+ right tool:
47
+
48
+ - Every page is a single round-trip. No client-side data layer.
49
+ - The output is auditable: open the deployed HTML and you can see
50
+ the full markup, no hidden hydration.
51
+ - Hosting is cheap (or free, on GitHub Pages / Cloudflare Pages).
52
+ - AI crawlers can read the full content. The `llms.txt` /
53
+ `llms-full.txt` files give them a single fetch to land on.
54
+
55
+ ## Contributing
56
+
57
+ To add a record, open a submission issue. The maintainer will
58
+ review and, if accepted, open a PR that adds the new YAML file.
59
+ See `/submit` for the issue form and a minimal record template.
60
+
61
+ ## License
62
+
63
+ The site's source code is MIT. The records are released under CC-BY
64
+ 4.0 unless a record's `license` field says otherwise. A record's
65
+ `license` field is the license of the *project it describes*, not
66
+ the license of the directory entry.
@@ -0,0 +1,103 @@
1
+ ---
2
+ title: "Methodology"
3
+ description: "How records are picked, scored, and surfaced in this directory."
4
+ ---
5
+
6
+ # Methodology
7
+
8
+ This page describes how entries in the directory are chosen, how the
9
+ curation signals are computed, and what we do (and don't) promise about
10
+ the data. The intent is to make the directory's logic auditable — every
11
+ number on a detail page is reproducible from the record's YAML.
12
+
13
+ ## Selection
14
+
15
+ A record is included if it is:
16
+
17
+ 1. **Open source.** Source is public under an OSI-approved license
18
+ (or public-domain dedication).
19
+ 2. **Actively maintained.** A pushed commit within the last 18 months
20
+ OR a declared maintenance status of `maintained` / `passive`.
21
+ 3. **Useful to a curious developer.** A working build, a real user
22
+ base (or a credible path to one), and a clear description of what
23
+ the project does.
24
+
25
+ We exclude: abandoned experiments, vapourware, projects whose entire
26
+ purpose is to sell a hosted plan, and any record that has not been
27
+ hand-checked by a maintainer.
28
+
29
+ ## Curation labels
30
+
31
+ The `curation.labels` field is a small, hand-set list. The supported
32
+ labels are:
33
+
34
+ - `hot` — high recent activity or attention (≥ 1 000 stars or a
35
+ commit within the last 30 days).
36
+ - `new` — added to the directory in the last 7 days.
37
+ - `mature` — long-running curated project, pushed > 365 days ago,
38
+ but still maintained.
39
+ - `featured` — editor's pick for the front page.
40
+ - `needs-review` — open submission awaiting a second maintainer
41
+ look.
42
+
43
+ These labels are mutually additive, not exclusive. A `new` record
44
+ can also be `hot`; a `mature` record can also be `featured`.
45
+
46
+ ## Scoring
47
+
48
+ The detail page surfaces a five-dimension score block. The five
49
+ dimensions are:
50
+
51
+ - **Documentation** — is the README / docs site enough to onboard
52
+ without reading the source?
53
+ - **Onboarding** — install in < 5 min, first useful result in < 1 h.
54
+ - **Maintenance** — recent commits, issue close rate, release cadence.
55
+ - **Community** — issues answered, discussions active, contributors
56
+ per release.
57
+ - **Production-readiness** — CI, tests, security policy, releases
58
+ with semver.
59
+
60
+ Each dimension is scored 0-5. The overall score on the detail page
61
+ is the mean. Scores are stored on the record, not computed at build
62
+ time, so we can deliberately disagree with the raw signals (a 1-line
63
+ toy that happens to be wildly popular can still score low on
64
+ documentation).
65
+
66
+ ## Health signals
67
+
68
+ The `health` block on each record tracks four state machines:
69
+
70
+ - `status` — `healthy` / `slowing` / `stale` / `archived`.
71
+ - `tier` — `curated` / `community` / `experimental`.
72
+ - `issue_close_rate` — moving 90-day average.
73
+ - `last_release` — most recent semver tag.
74
+
75
+ A record's `status` transitions are time-boxed: a project with no
76
+ commits in 365 days flips from `slowing` to `stale`; 730 days flips
77
+ to `archived`. The transition is mechanical; the recovery is
78
+ manual (a maintainer sets `tier` back to `community` after review).
79
+
80
+ ## Lenses
81
+
82
+ The directory's home page surfaces three curated lenses:
83
+
84
+ - **Hot** — `curation.labels` includes `hot`, OR `github.stars` ≥
85
+ 1 000, OR `pushedAt` within 30 days.
86
+ - **New** — `pushedAt` within 7 days, OR `curation.labels` includes
87
+ `new`.
88
+ - **Mature** — `health.tier === "curated"` AND `pushedAt` > 365 days
89
+ ago.
90
+
91
+ Each lens caps at 6 items on the home page; the full filtered list
92
+ is reachable via the lens tab on `/projects`.
93
+
94
+ ## What we don't promise
95
+
96
+ - **Real-time data.** The site is rebuilt on a schedule, not on
97
+ every push. Counts and dates can lag by up to one build cycle.
98
+ - **Verdict-free scores.** A high overall score means "useful to a
99
+ curious developer", not "best in class" — judgement calls are
100
+ documented per record, not baked into the score.
101
+ - **Causal claims.** The "best for" / "why listed" / "caveats"
102
+ blocks are editorial notes, not derived signals. They reflect
103
+ what a maintainer thought at review time.
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "blueprint": "project-directory",
4
+ "generatedAt": "2026-06-10T15:03:23.841Z",
5
+ "totalRecords": 0,
6
+ "visibleRecords": 0,
7
+ "records": []
8
+ }
@@ -0,0 +1,7 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "blueprint": "project-directory",
4
+ "generatedAt": "2026-06-10T15:03:23.841Z",
5
+ "totalRecords": 0,
6
+ "records": []
7
+ }
@@ -0,0 +1,8 @@
1
+ {
2
+ "schemaVersion": 1,
3
+ "blueprint": "project-directory",
4
+ "generatedAt": "2026-06-10T15:03:23.841Z",
5
+ "totalRecords": 0,
6
+ "visibleRecords": 0,
7
+ "records": []
8
+ }
@@ -0,0 +1,31 @@
1
+ {
2
+ "blueprint": "project-directory",
3
+ "name": "Grove Directory",
4
+ "tagline": "A curated, health-aware developer directory.",
5
+ "description": "A curated, health-aware developer directory powered by Grove.",
6
+ "siteUrl": "https://example.com",
7
+ "repoUrl": "https://github.com/tortuvshin/grove",
8
+ "nav": [
9
+ {
10
+ "label": "Home",
11
+ "href": "/"
12
+ },
13
+ {
14
+ "label": "Browse",
15
+ "href": "/projects"
16
+ },
17
+ {
18
+ "label": "About",
19
+ "href": "/about"
20
+ }
21
+ ],
22
+ "theme": {
23
+ "primaryColor": "#16a34a",
24
+ "radius": "soft",
25
+ "density": "comfortable",
26
+ "containerWidth": "72rem"
27
+ },
28
+ "integrations": {
29
+ "github": false
30
+ }
31
+ }
File without changes
@@ -0,0 +1,36 @@
1
+ import { defineConfig } from "@grove-dev/core";
2
+
3
+ /**
4
+ * Default template config — the smallest viable project-directory
5
+ * showcase. Consumers (created via `grove new`) override this
6
+ * with their own branding, taxonomy, and integrations.
7
+ */
8
+ export default defineConfig({
9
+ blueprint: "project-directory",
10
+
11
+ site: {
12
+ name: "Grove Directory",
13
+ tagline: "A curated, health-aware developer directory.",
14
+ description:
15
+ "A curated, health-aware developer directory powered by Grove.",
16
+ url: "https://example.com",
17
+ repoUrl: "https://github.com/tortuvshin/grove",
18
+ },
19
+
20
+ nav: [
21
+ { label: "Home", href: "/" },
22
+ { label: "Browse", href: "/projects" },
23
+ { label: "About", href: "/about" },
24
+ ],
25
+
26
+ facets: ["category", "stacks", "platforms", "tags"],
27
+
28
+ integrations: {},
29
+
30
+ theme: {
31
+ primaryColor: "#16a34a",
32
+ radius: "soft",
33
+ density: "comfortable",
34
+ containerWidth: "72rem",
35
+ },
36
+ });
@@ -11,16 +11,17 @@
11
11
  },
12
12
  "scripts": {
13
13
  "validate:data": "grove validate",
14
- "build:data": "grove build-data",
15
- "build:llms-full": "grove build-llms-full",
16
- "build": "pnpm run build:data && pnpm run build:llms-full && astro build",
14
+ "build:data": "grove generate",
15
+ "build:sitemap": "grove sitemap",
16
+ "build:llms": "grove llms",
17
+ "build": "pnpm run build:data && pnpm run build:sitemap && pnpm run build:llms && astro build",
17
18
  "dev": "pnpm run build:data && astro dev",
18
19
  "start": "astro dev",
19
20
  "preview": "astro preview",
20
21
  "astro": "astro",
21
22
  "check": "astro check",
22
- "refresh:activity": "grove analyze",
23
- "enrich:github": "grove enrich"
23
+ "sync:github": "grove sync github",
24
+ "cleanup": "grove cleanup stale"
24
25
  },
25
26
  "dependencies": {
26
27
  "@astrojs/check": "^0.9.9",
@@ -0,0 +1,14 @@
1
+ # Grove Directory — full directory
2
+
3
+ > Generated 2026-06-10T15:03:23.841Z from 0 records.
4
+ > Source: https://example.com/projects · Regenerate with `grove generate`.
5
+
6
+ Each section below mirrors one record detail page.
7
+
8
+ ## Index
9
+
10
+
11
+
12
+
13
+
14
+
@@ -0,0 +1,11 @@
1
+ # Grove Directory
2
+
3
+ A curated, health-aware developer directory powered by Grove.
4
+
5
+ Directory: https://example.com/projects
6
+ Records indexed: 0
7
+ Categories: 0
8
+
9
+ ## Usage
10
+
11
+ Use /llms-full.txt for record-level details. Prefer detail pages for citations.
@@ -1,32 +1,16 @@
1
1
  ---
2
- // SPDX-License-Identifier: MIT
3
-
4
- /**
5
- * BaseLayout — wraps every page. Owns the theme-detection inline script
6
- * and the global shell (Header, Footer). Per-page SEO (title, description,
7
- * OG, JSON-LD) is delegated to <Seo /> so each page can declare what it
8
- * needs without polluting the layout file.
9
- */
10
2
  import "../../styles/global.css";
11
3
  import Header from "./Header.astro";
12
4
  import Footer from "./Footer.astro";
13
- import Seo from "./Seo.astro";
14
5
 
15
6
  interface Props {
16
7
  title: string;
17
8
  description: string;
18
- type?: "website" | "article" | "profile";
19
9
  noindex?: boolean;
20
10
  jsonLd?: Record<string, unknown> | Record<string, unknown>[];
21
11
  }
22
12
 
23
- const {
24
- title,
25
- description,
26
- type,
27
- noindex,
28
- jsonLd,
29
- } = Astro.props;
13
+ const { title, description, noindex, jsonLd } = Astro.props;
30
14
 
31
15
  const favicon =
32
16
  "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";
@@ -38,57 +22,26 @@ const favicon =
38
22
  <meta charset="UTF-8" />
39
23
  <meta name="viewport" content="width=device-width, initial-scale=1.0" />
40
24
  <meta name="generator" content={Astro.generator} />
25
+ <meta name="description" content={description} />
41
26
  <meta name="theme-color" content="#0a0a0c" media="(prefers-color-scheme: dark)" />
42
27
  <meta name="theme-color" content="#fafafa" media="(prefers-color-scheme: light)" />
43
28
  <link rel="icon" href={favicon} />
44
29
  <link rel="sitemap" href="/sitemap.xml" />
45
30
  <link rel="alternate" type="text/plain" href="/llms.txt" title="LLM usage guidance" />
46
-
47
- <Seo
48
- title={title}
49
- description={description}
50
- type={type}
51
- noindex={noindex}
52
- jsonLd={jsonLd}
53
- />
54
-
55
- <slot name="head" />
56
- <script is:inline>
57
- (function () {
58
- var STORAGE_KEY = "open-apps-theme";
59
- function getMode() {
60
- var stored = localStorage.getItem(STORAGE_KEY);
61
- if (stored === "light" || stored === "dark" || stored === "system") return stored;
62
- return "system";
63
- }
64
- function apply(mode) {
65
- var resolved =
66
- mode === "system"
67
- ? (window.matchMedia("(prefers-color-scheme: dark)").matches ? "dark" : "light")
68
- : mode;
69
- var root = document.documentElement;
70
- if (resolved === "dark") root.classList.add("dark");
71
- else root.classList.remove("dark");
72
- root.dataset.theme = mode;
73
- root.dataset.resolvedTheme = resolved;
74
- }
75
- apply(getMode());
76
- window.addEventListener("theme:set", function (e) { apply(e.detail); });
77
- var mq = window.matchMedia("(prefers-color-scheme: dark)");
78
- mq.addEventListener("change", function () {
79
- if (getMode() === "system") apply("system");
80
- });
81
- })();
82
- </script>
31
+ {noindex && <meta name="robots" content="noindex,nofollow" />}
32
+ <title>{title}</title>
33
+ {jsonLd && (
34
+ <script
35
+ type="application/ld+json"
36
+ set:html={JSON.stringify(jsonLd)}
37
+ />
38
+ )}
83
39
  </head>
84
40
  <body class="min-h-screen bg-white text-ink-900 dark:bg-ink-950 dark:text-ink-100">
85
41
  <Header />
86
-
87
42
  <main>
88
43
  <slot />
89
44
  </main>
90
-
91
45
  <Footer />
92
- <slot name="body-end" />
93
46
  </body>
94
47
  </html>
@@ -1,145 +1,27 @@
1
1
  ---
2
- import { siteConfig } from "../../data/config";
3
- import { stats } from "../../data/stats";
2
+ import siteConfig from "../../data/generated/site-config.json";
4
3
 
5
- const githubUrl = stats.originalRepo;
6
4
  const year = new Date().getFullYear();
7
-
8
- // One-line positioning. Should be the same on every page so the
9
- // project's identity is consistent.
10
- const positioning =
11
- "A searchable directory of real open-source applications — organized by stack, category, platform, license, activity, and maturity.";
12
5
  ---
13
6
 
14
7
  <footer class="mt-16 border-t border-ink-200 bg-white text-ink-500 dark:border-ink-800 dark:bg-ink-950 dark:text-ink-400">
15
- <div
16
- class="mx-auto grid max-w-wide grid-cols-2 gap-8 px-5 py-12 md:grid-cols-4 sm:px-7"
17
- >
18
- <div class="col-span-2 md:col-span-1">
19
- <div
20
- class="mb-2 inline-flex items-center gap-2 text-[0.95rem] font-semibold text-ink-900 dark:text-ink-100"
21
- >
22
- <span
23
- aria-hidden="true"
24
- class="inline-block h-3.5 w-3.5 rounded bg-ink-900 dark:bg-ink-100"
25
- ></span>
26
- <span>{siteConfig.name}</span>
27
- </div>
28
- <p class="m-0 max-w-[36ch] text-[0.8125rem] leading-relaxed text-ink-500 dark:text-ink-400">
29
- {positioning}
8
+ <div class="mx-auto max-w-6xl px-5 py-8 sm:px-7">
9
+ <div class="flex flex-col gap-3 sm:flex-row sm:items-center sm:justify-between">
10
+ <p class="m-0 text-sm">
11
+ © {year} {siteConfig.name}.
30
12
  </p>
31
- <p class="mt-3 m-0 text-2xs text-ink-500 dark:text-ink-400">
32
- <span class="font-mono">{stats.apps}</span> apps
33
- <span class="mx-1 text-ink-300 dark:text-ink-700">·</span>
34
- <span class="font-mono">{stats.categories}</span> categories
35
- <span class="mx-1 text-ink-300 dark:text-ink-700">·</span>
36
- <span class="font-mono">{stats.contributors}</span> contributors
13
+ <p class="m-0 text-2xs text-ink-500 dark:text-ink-400">
14
+ Built with{" "}
15
+ <a
16
+ href="https://github.com/tortuvshin/grove"
17
+ target="_blank"
18
+ rel="noopener noreferrer"
19
+ class="hover:text-ink-900 dark:hover:text-ink-100"
20
+ >
21
+ Grove
22
+ </a>
23
+ {" "}— an open-source framework for community knowledge sites.
37
24
  </p>
38
25
  </div>
39
-
40
- <div>
41
- <h4
42
- class="mb-3 text-2xs font-semibold uppercase tracking-wider text-ink-900 dark:text-ink-100"
43
- >
44
- Discover
45
- </h4>
46
- <ul class="m-0 flex list-none flex-col gap-2 p-0">
47
- <li><a href="#hot" class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100">Hot apps</a></li>
48
- <li><a href="#new" class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100">New apps</a></li>
49
- <li><a href="#mature" class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100">Mature apps</a></li>
50
- <li><a href="#stacks" class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100">By stack</a></li>
51
- <li><a href="#categories" class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100">By category</a></li>
52
- </ul>
53
- </div>
54
-
55
- <div>
56
- <h4
57
- class="mb-3 text-2xs font-semibold uppercase tracking-wider text-ink-900 dark:text-ink-100"
58
- >
59
- Contribute
60
- </h4>
61
- <ul class="m-0 flex list-none flex-col gap-2 p-0">
62
- <li>
63
- <a
64
- href={`${githubUrl}/blob/main/CONTRIBUTING.md`}
65
- target="_blank"
66
- rel="noopener noreferrer"
67
- class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100"
68
- >Submit via GitHub</a
69
- >
70
- </li>
71
- <li><a href="#contributors" class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100">Contributors</a></li>
72
- <li>
73
- <a
74
- href={`${githubUrl}/issues`}
75
- target="_blank"
76
- rel="noopener noreferrer"
77
- class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100"
78
- >Report an issue</a
79
- >
80
- </li>
81
- <li>
82
- <a
83
- href={`${githubUrl}/blob/main/CONTRIBUTING.md`}
84
- target="_blank"
85
- rel="noopener noreferrer"
86
- class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100"
87
- >Contributing guide</a
88
- >
89
- </li>
90
- </ul>
91
- </div>
92
-
93
- <div>
94
- <h4
95
- class="mb-3 text-2xs font-semibold uppercase tracking-wider text-ink-900 dark:text-ink-100"
96
- >
97
- Project
98
- </h4>
99
- <ul class="m-0 flex list-none flex-col gap-2 p-0">
100
- <li>
101
- <a
102
- href={githubUrl}
103
- target="_blank"
104
- rel="noopener noreferrer"
105
- class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100"
106
- >Source on GitHub</a
107
- >
108
- </li>
109
- <li><a href="#about" class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100">Why this exists</a></li>
110
- <li>
111
- <a
112
- href={`${githubUrl}/blob/main/README.md`}
113
- target="_blank"
114
- rel="noopener noreferrer"
115
- class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100"
116
- >README</a
117
- >
118
- </li>
119
- <li>
120
- <a
121
- href="/about"
122
- class="text-sm transition-colors hover:text-ink-900 dark:hover:text-ink-100"
123
- >About</a
124
- >
125
- </li>
126
- </ul>
127
- </div>
128
- </div>
129
-
130
- <div class="border-t border-ink-200 dark:border-ink-800">
131
- <div
132
- 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"
133
- >
134
- <span>© {year} {siteConfig.name}. Content under CC BY-SA 4.0.</span>
135
- <span class="text-ink-300 dark:text-ink-700">·</span>
136
- <a
137
- href={githubUrl}
138
- target="_blank"
139
- rel="noopener noreferrer"
140
- class="transition-colors hover:text-ink-900 dark:hover:text-ink-100"
141
- >View source on GitHub</a
142
- >
143
- </div>
144
26
  </div>
145
27
  </footer>