@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
@@ -1,74 +1,86 @@
1
- // SPDX-License-Identifier: MIT
2
- //
3
- // `/sitemap.xml` — single-file sitemap, served as `application/xml`.
4
- //
5
- // Replaces `@astrojs/sitemap` so the public URL is exactly
6
- // `/sitemap.xml` (the integration's default output is
7
- // `/sitemap-index.xml`, which doesn't match what `robots.txt` and
8
- // most crawler configs expect). For 79 apps + 4 static pages this
9
- // is well under any per-sitemap limit, so a single file is fine.
10
- //
11
- // Excludes `/submit` (noindex form wrapper) and any other pages
12
- // that opt out by setting `noindex` in their SEO props.
13
-
1
+ /**
2
+ * sitemap.xml.ts — Astro endpoint that serves the site map.
3
+ *
4
+ * The CLI's `grove sitemap` command also writes a sitemap into
5
+ * `public/sitemap.xml`. This endpoint is the consumer-facing
6
+ * version: it builds the sitemap from the live record set at
7
+ * request time, so a manual `astro build` (without running the
8
+ * CLI first) still gets a correct map.
9
+ *
10
+ * In practice the CLI's output is preferred for SEO (it's
11
+ * deterministic and includes the build timestamp); the consumer
12
+ * is expected to wire `public/sitemap.xml` and this endpoint to
13
+ * the same source. We keep the endpoint thin so it can serve as
14
+ * either a fallback or a live override.
15
+ */
14
16
  import type { APIRoute } from "astro";
15
- import generatedJson from "../../data/generated/apps.json";
17
+ import { fullRecords, indexSlug } from "../data/records";
18
+ import siteConfig from "../../data/generated/site-config.json";
16
19
 
17
- type GeneratedApp = {
18
- slug: string;
19
- name: string;
20
- lastCommitAt?: string;
21
- activity?: { lastCommitAt?: string };
22
- };
20
+ interface SitemapEntry {
21
+ loc: string;
22
+ lastmod?: string;
23
+ changefreq?: "daily" | "weekly" | "monthly" | "yearly";
24
+ priority?: number;
25
+ }
26
+
27
+ function absoluteUrl(siteUrl: string, path: string): string {
28
+ const base = siteUrl.replace(/\/$/, "");
29
+ const tail = path.startsWith("/") ? path : `/${path}`;
30
+ return `${base}${tail}`;
31
+ }
32
+
33
+ function buildEntries(siteUrl: string, blueprint: string | undefined): SitemapEntry[] {
34
+ const slug = indexSlug(blueprint);
35
+ const now = new Date().toISOString().slice(0, 10);
23
36
 
24
- const apps = (generatedJson as { apps?: GeneratedApp[] }).apps ?? [];
37
+ const top: SitemapEntry[] = [
38
+ { loc: absoluteUrl(siteUrl, "/"), lastmod: now, changefreq: "daily", priority: 1.0 },
39
+ { loc: absoluteUrl(siteUrl, "/about"), lastmod: now, changefreq: "monthly", priority: 0.5 },
40
+ { loc: absoluteUrl(siteUrl, "/submit"), lastmod: now, changefreq: "yearly", priority: 0.3 },
41
+ ];
25
42
 
26
- const STATIC_PAGES: { path: string; priority: string; changefreq: string }[] = [
27
- { path: "/", priority: "1.0", changefreq: "weekly" },
28
- { path: "/about", priority: "0.8", changefreq: "monthly" },
29
- { path: "/apps", priority: "0.9", changefreq: "daily" },
30
- ];
43
+ if (fullRecords.length > 0) {
44
+ top.push({
45
+ loc: absoluteUrl(siteUrl, `/${slug}`),
46
+ lastmod: now,
47
+ changefreq: "daily",
48
+ priority: 0.9,
49
+ });
50
+ }
51
+
52
+ const recordEntries: SitemapEntry[] = fullRecords
53
+ .filter((r) => r.kind === "project")
54
+ .map((r) => ({
55
+ loc: absoluteUrl(siteUrl, `/${slug}/${r.slug}`),
56
+ // detail pages don't carry a `pushedAt` in the typed union;
57
+ // we use the build date so crawlers see a recent timestamp.
58
+ lastmod: now,
59
+ changefreq: "weekly",
60
+ priority: 0.7,
61
+ }));
31
62
 
32
- function isoDate(iso?: string): string | null {
33
- if (!iso) return null;
34
- const d = new Date(iso);
35
- if (isNaN(d.getTime())) return null;
36
- return d.toISOString().slice(0, 10);
63
+ return [...top, ...recordEntries];
37
64
  }
38
65
 
39
- function urlEntry(loc: string, lastmod?: string, priority = "0.7", changefreq = "weekly"): string {
40
- const lm = isoDate(lastmod);
41
- return [
42
- " <url>",
43
- ` <loc>${loc}</loc>`,
44
- lm ? ` <lastmod>${lm}</lastmod>` : null,
45
- ` <changefreq>${changefreq}</changefreq>`,
46
- ` <priority>${priority}</priority>`,
47
- " </url>",
48
- ]
49
- .filter(Boolean)
66
+ function renderXml(entries: SitemapEntry[]): string {
67
+ const body = entries
68
+ .map((e) => {
69
+ const lines: string[] = [` <url>`, ` <loc>${e.loc}</loc>`];
70
+ if (e.lastmod) lines.push(` <lastmod>${e.lastmod}</lastmod>`);
71
+ if (e.changefreq) lines.push(` <changefreq>${e.changefreq}</changefreq>`);
72
+ if (e.priority !== undefined) lines.push(` <priority>${e.priority.toFixed(1)}</priority>`);
73
+ lines.push(` </url>`);
74
+ return lines.join("\n");
75
+ })
50
76
  .join("\n");
77
+ return `<?xml version="1.0" encoding="UTF-8"?>\n<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">\n${body}\n</urlset>\n`;
51
78
  }
52
79
 
53
- export const GET: APIRoute = ({ site }) => {
54
- const base = (site?.toString() ?? "https://open-apps.dev.mn").replace(/\/$/, "");
55
- const today = new Date().toISOString().slice(0, 10);
56
-
57
- const lines: string[] = [];
58
- lines.push('<?xml version="1.0" encoding="UTF-8"?>');
59
- lines.push('<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">');
60
- for (const p of STATIC_PAGES) {
61
- lines.push(urlEntry(`${base}${p.path}`, today, p.priority, p.changefreq));
62
- }
63
- for (const app of apps) {
64
- const lastmod = app.lastCommitAt ?? app.activity?.lastCommitAt ?? today;
65
- lines.push(urlEntry(`${base}/apps/${app.slug}`, lastmod));
66
- }
67
- lines.push("</urlset>");
68
- lines.push("");
69
-
70
- const body = lines.join("\n");
71
- return new Response(body, {
80
+ export const GET: APIRoute = () => {
81
+ const xml = renderXml(buildEntries(siteConfig.siteUrl ?? "", siteConfig.blueprint));
82
+ return new Response(xml, {
83
+ status: 200,
72
84
  headers: {
73
85
  "Content-Type": "application/xml; charset=utf-8",
74
86
  "Cache-Control": "public, max-age=3600",