@grove-dev/astro 0.2.10 → 0.2.13

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 (235) hide show
  1. package/dist/lib/display.d.ts +11 -17
  2. package/dist/lib/display.d.ts.map +1 -1
  3. package/dist/lib/display.js +43 -43
  4. package/dist/lib/display.js.map +1 -1
  5. package/dist/lib/format.d.ts +6 -7
  6. package/dist/lib/format.d.ts.map +1 -1
  7. package/dist/lib/format.js +11 -12
  8. package/dist/lib/format.js.map +1 -1
  9. package/dist/lib/lenses.d.ts +35 -73
  10. package/dist/lib/lenses.d.ts.map +1 -1
  11. package/dist/lib/lenses.js +144 -126
  12. package/dist/lib/lenses.js.map +1 -1
  13. package/dist/lib/repo.d.ts +11 -22
  14. package/dist/lib/repo.d.ts.map +1 -1
  15. package/dist/lib/repo.js +12 -25
  16. package/dist/lib/repo.js.map +1 -1
  17. package/dist/lib/scores.d.ts +15 -16
  18. package/dist/lib/scores.d.ts.map +1 -1
  19. package/dist/lib/scores.js +4 -11
  20. package/dist/lib/scores.js.map +1 -1
  21. package/dist/lib/search.d.ts +47 -129
  22. package/dist/lib/search.d.ts.map +1 -1
  23. package/dist/lib/search.js +195 -180
  24. package/dist/lib/search.js.map +1 -1
  25. package/dist/lib/taxonomy-counts.d.ts +7 -21
  26. package/dist/lib/taxonomy-counts.d.ts.map +1 -1
  27. package/dist/lib/taxonomy-counts.js +12 -31
  28. package/dist/lib/taxonomy-counts.js.map +1 -1
  29. package/package.json +4 -4
  30. package/src/components/AppsIndexRow.astro +55 -184
  31. package/src/components/AppsPagination.astro +45 -108
  32. package/src/components/CategoryGrid.astro +43 -31
  33. package/src/components/ContributorsGrid.astro +3 -3
  34. package/src/components/CurationGrid.astro +41 -0
  35. package/src/components/ExploreByStack.astro +6 -0
  36. package/src/components/FilterGroupMenu.astro +49 -0
  37. package/src/components/FilterOptions.astro +44 -0
  38. package/src/components/Hero.astro +198 -147
  39. package/src/components/Icon.astro +10 -3
  40. package/src/components/ItemCard.astro +266 -248
  41. package/src/components/RecordSection.astro +68 -33
  42. package/src/components/RefinePanel.astro +115 -141
  43. package/src/components/StackGrid.astro +32 -24
  44. package/src/components/WhyThisExists.astro +32 -32
  45. package/src/layouts/BaseLayout.astro +104 -49
  46. package/src/layouts/Container.astro +5 -44
  47. package/src/layouts/Footer.astro +31 -20
  48. package/src/layouts/Header.astro +40 -19
  49. package/src/layouts/SectionHeader.astro +27 -43
  50. package/src/layouts/Seo.astro +38 -56
  51. package/src/layouts/ThemeToggle.astro +35 -48
  52. package/src/lib/display.ts +46 -53
  53. package/src/lib/format.ts +11 -12
  54. package/src/lib/lenses.ts +151 -172
  55. package/src/lib/repo.ts +16 -28
  56. package/src/lib/scores.ts +15 -19
  57. package/src/lib/search.ts +222 -290
  58. package/src/lib/taxonomy-counts.ts +12 -46
  59. package/src/styles.css +207 -1
  60. package/templates/default/.github/ISSUE_TEMPLATE/bug_report.md +33 -0
  61. package/templates/default/.github/ISSUE_TEMPLATE/feature_request.md +20 -0
  62. package/templates/default/.github/ISSUE_TEMPLATE/record_submission.md +48 -0
  63. package/templates/default/.github/pull_request_template.md +27 -0
  64. package/templates/default/.github/workflows/build.yml +55 -0
  65. package/templates/default/.github/workflows/cleanup-stale-records.yml +48 -0
  66. package/templates/default/.github/workflows/daily-refresh.yml +53 -0
  67. package/templates/default/.github/workflows/sync-contributors.yml +53 -0
  68. package/templates/default/.github/workflows/sync-github-metadata.yml +58 -0
  69. package/templates/default/.github/workflows/validate-data.yml +35 -0
  70. package/templates/default/data/records/coolify.yml +46 -0
  71. package/templates/default/data/records/gitea.yml +46 -0
  72. package/templates/default/data/records/hoppscotch.yml +47 -0
  73. package/templates/default/data/records/inventree.yml +47 -0
  74. package/templates/default/data/records/label-studio.yml +46 -0
  75. package/templates/default/data/records/logseq.yml +48 -0
  76. package/templates/default/data/records/private-gpt.yml +47 -0
  77. package/templates/default/data/records/wakapi.yml +44 -0
  78. package/templates/default/data/taxonomy/categories.yml +47 -0
  79. package/templates/default/data/taxonomy/distribution-channels.yml +43 -0
  80. package/templates/default/data/taxonomy/platforms.yml +27 -0
  81. package/templates/default/data/taxonomy/stacks.yml +41 -0
  82. package/templates/default/grove.config.ts +1 -1
  83. package/templates/default/package.json +5 -4
  84. package/templates/default/public/icons/stacks/bun.svg +1 -0
  85. package/templates/default/public/icons/stacks/clojure.svg +1 -0
  86. package/templates/default/public/icons/stacks/clojurescript.svg +1 -0
  87. package/templates/default/public/icons/stacks/deno.svg +1 -0
  88. package/templates/default/public/icons/stacks/django.svg +1 -0
  89. package/templates/default/public/icons/stacks/docker.svg +1 -0
  90. package/templates/default/public/icons/stacks/go.svg +1 -0
  91. package/templates/default/public/icons/stacks/llm.svg +1 -0
  92. package/templates/default/public/icons/stacks/node.js.svg +1 -0
  93. package/templates/default/public/icons/stacks/sveltekit.svg +1 -0
  94. package/templates/default/public/icons/stacks/vue.svg +1 -0
  95. package/templates/default/public/llms-full.txt +197 -5
  96. package/templates/default/public/llms.txt +107 -6
  97. package/templates/default/public/sitemap.xml +63 -0
  98. package/templates/default/scripts/build-llms.mjs +123 -0
  99. package/templates/default/scripts/build-records-json.mjs +27 -0
  100. package/templates/default/scripts/build-sitemap.mjs +20 -0
  101. package/templates/default/scripts/cleanup-stale-records.mjs +20 -0
  102. package/templates/default/scripts/enrich-github-metadata.mjs +99 -0
  103. package/templates/default/scripts/fetch-icons.mjs +137 -0
  104. package/templates/default/scripts/migrate-legacy-to-schema-v1.mjs +86 -0
  105. package/templates/default/scripts/parse-legacy-readme.mjs +59 -0
  106. package/templates/default/scripts/refresh-records-activity.mjs +24 -0
  107. package/templates/default/scripts/repair-license-format.mjs +72 -0
  108. package/templates/default/scripts/report-cleanup-candidates.mjs +21 -0
  109. package/templates/default/scripts/seed-from-github.mjs +62 -0
  110. package/templates/default/scripts/sync-contributors.mjs +145 -0
  111. package/templates/default/scripts/sync-github-metadata.mjs +28 -0
  112. package/templates/default/scripts/validate-records.mjs +27 -0
  113. package/templates/default/src/data/records.ts +134 -51
  114. package/templates/default/src/pages/404.astro +64 -0
  115. package/templates/default/src/pages/{projects/[slug].astro → [slug]/[itemSlug].astro} +236 -66
  116. package/templates/default/src/pages/[slug]/index.astro +476 -0
  117. package/templates/default/src/pages/about.astro +165 -82
  118. package/templates/default/src/pages/apps/[itemSlug].astro +301 -0
  119. package/templates/default/src/pages/apps/index.astro +146 -0
  120. package/templates/default/src/pages/contributors.astro +184 -0
  121. package/templates/default/src/pages/index.astro +119 -162
  122. package/templates/default/src/pages/submit.astro +276 -114
  123. package/templates/default/wrangler.jsonc +28 -0
  124. package/LICENSE +0 -21
  125. package/templates/default/.astro/content.d.ts +0 -155
  126. package/templates/default/.astro/settings.json +0 -5
  127. package/templates/default/.astro/types.d.ts +0 -1
  128. package/templates/default/data/generated/apps.json +0 -1
  129. package/templates/default/data/generated/records.full.json +0 -8
  130. package/templates/default/data/generated/records.index.json +0 -7
  131. package/templates/default/data/generated/records.json +0 -8
  132. package/templates/default/data/generated/repo-stats.json +0 -1
  133. package/templates/default/data/generated/site-config.json +0 -31
  134. package/templates/default/dist/_astro/BaseLayout.Dz_HR-68.css +0 -1
  135. package/templates/default/dist/about/index.html +0 -165
  136. package/templates/default/dist/icons/platforms/android.svg +0 -1
  137. package/templates/default/dist/icons/platforms/apple-dark.svg +0 -1
  138. package/templates/default/dist/icons/platforms/apple-light.svg +0 -1
  139. package/templates/default/dist/icons/platforms/chrome.svg +0 -1
  140. package/templates/default/dist/icons/platforms/chromeos.svg +0 -5
  141. package/templates/default/dist/icons/platforms/desktop.svg +0 -4
  142. package/templates/default/dist/icons/platforms/embedded.svg +0 -5
  143. package/templates/default/dist/icons/platforms/ios.svg +0 -1
  144. package/templates/default/dist/icons/platforms/linux.svg +0 -1
  145. package/templates/default/dist/icons/platforms/macos.svg +0 -1
  146. package/templates/default/dist/icons/platforms/ubuntu.svg +0 -1
  147. package/templates/default/dist/icons/platforms/web.svg +0 -5
  148. package/templates/default/dist/icons/platforms/windows.svg +0 -6
  149. package/templates/default/dist/icons/stacks/android.svg +0 -1
  150. package/templates/default/dist/icons/stacks/apple-dark.svg +0 -1
  151. package/templates/default/dist/icons/stacks/apple-light.svg +0 -1
  152. package/templates/default/dist/icons/stacks/capacitor.svg +0 -14
  153. package/templates/default/dist/icons/stacks/dart.svg +0 -1
  154. package/templates/default/dist/icons/stacks/firebase.svg +0 -1
  155. package/templates/default/dist/icons/stacks/flutter.svg +0 -1
  156. package/templates/default/dist/icons/stacks/graphql.svg +0 -1
  157. package/templates/default/dist/icons/stacks/ionic.svg +0 -4
  158. package/templates/default/dist/icons/stacks/java.svg +0 -1
  159. package/templates/default/dist/icons/stacks/javascript.svg +0 -1
  160. package/templates/default/dist/icons/stacks/kotlin.svg +0 -1
  161. package/templates/default/dist/icons/stacks/mongodb.svg +0 -1
  162. package/templates/default/dist/icons/stacks/nodejs.svg +0 -1
  163. package/templates/default/dist/icons/stacks/python.svg +0 -1
  164. package/templates/default/dist/icons/stacks/react-native.svg +0 -1
  165. package/templates/default/dist/icons/stacks/react.svg +0 -1
  166. package/templates/default/dist/icons/stacks/rust.svg +0 -1
  167. package/templates/default/dist/icons/stacks/solidity.svg +0 -1
  168. package/templates/default/dist/icons/stacks/swift.svg +0 -1
  169. package/templates/default/dist/icons/stacks/tensorflow.svg +0 -1
  170. package/templates/default/dist/icons/stacks/typescript.svg +0 -1
  171. package/templates/default/dist/index.html +0 -55
  172. package/templates/default/dist/llms-full.txt +0 -14
  173. package/templates/default/dist/llms.txt +0 -11
  174. package/templates/default/dist/og-image.svg +0 -48
  175. package/templates/default/dist/projects/index.html +0 -61
  176. package/templates/default/dist/robots.txt +0 -53
  177. package/templates/default/dist/sitemap.xml +0 -21
  178. package/templates/default/dist/submit/index.html +0 -69
  179. package/templates/default/node_modules/.bin/astro +0 -21
  180. package/templates/default/node_modules/.bin/astro-check +0 -21
  181. package/templates/default/node_modules/.bin/grove +0 -21
  182. package/templates/default/node_modules/.bin/jiti +0 -21
  183. package/templates/default/node_modules/.bin/prettier +0 -21
  184. package/templates/default/node_modules/.bin/rollup +0 -21
  185. package/templates/default/node_modules/.bin/tsc +0 -21
  186. package/templates/default/node_modules/.bin/tsserver +0 -21
  187. package/templates/default/node_modules/.bin/tsx +0 -21
  188. package/templates/default/node_modules/.bin/vite +0 -21
  189. package/templates/default/node_modules/.bin/yaml +0 -21
  190. package/templates/default/node_modules/.vite/deps/_metadata.json +0 -79
  191. package/templates/default/node_modules/.vite/deps/astro-KRVZHBC5.js +0 -433
  192. package/templates/default/node_modules/.vite/deps/astro-KRVZHBC5.js.map +0 -7
  193. package/templates/default/node_modules/.vite/deps/astro___aria-query.js +0 -5
  194. package/templates/default/node_modules/.vite/deps/astro___aria-query.js.map +0 -7
  195. package/templates/default/node_modules/.vite/deps/astro___axobject-query.js +0 -5
  196. package/templates/default/node_modules/.vite/deps/astro___axobject-query.js.map +0 -7
  197. package/templates/default/node_modules/.vite/deps/astro___html-escaper.js +0 -9
  198. package/templates/default/node_modules/.vite/deps/astro___html-escaper.js.map +0 -7
  199. package/templates/default/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js +0 -241
  200. package/templates/default/node_modules/.vite/deps/astro_runtime_client_dev-toolbar_entrypoint__js.js.map +0 -7
  201. package/templates/default/node_modules/.vite/deps/audit-GYHQ3ITH.js +0 -1592
  202. package/templates/default/node_modules/.vite/deps/audit-GYHQ3ITH.js.map +0 -7
  203. package/templates/default/node_modules/.vite/deps/chunk-5WRI5ZAA.js +0 -30
  204. package/templates/default/node_modules/.vite/deps/chunk-5WRI5ZAA.js.map +0 -7
  205. package/templates/default/node_modules/.vite/deps/chunk-7P4KIK53.js +0 -186
  206. package/templates/default/node_modules/.vite/deps/chunk-7P4KIK53.js.map +0 -7
  207. package/templates/default/node_modules/.vite/deps/chunk-BQGHFQJH.js +0 -48
  208. package/templates/default/node_modules/.vite/deps/chunk-BQGHFQJH.js.map +0 -7
  209. package/templates/default/node_modules/.vite/deps/chunk-CJCDKWP2.js +0 -6779
  210. package/templates/default/node_modules/.vite/deps/chunk-CJCDKWP2.js.map +0 -7
  211. package/templates/default/node_modules/.vite/deps/chunk-FHJ3XBDE.js +0 -33
  212. package/templates/default/node_modules/.vite/deps/chunk-FHJ3XBDE.js.map +0 -7
  213. package/templates/default/node_modules/.vite/deps/chunk-FQEMNIUQ.js +0 -88
  214. package/templates/default/node_modules/.vite/deps/chunk-FQEMNIUQ.js.map +0 -7
  215. package/templates/default/node_modules/.vite/deps/chunk-HBSVDAQD.js +0 -72
  216. package/templates/default/node_modules/.vite/deps/chunk-HBSVDAQD.js.map +0 -7
  217. package/templates/default/node_modules/.vite/deps/chunk-HDOQ2U3U.js +0 -3757
  218. package/templates/default/node_modules/.vite/deps/chunk-HDOQ2U3U.js.map +0 -7
  219. package/templates/default/node_modules/.vite/deps/chunk-XEBKRCNE.js +0 -54
  220. package/templates/default/node_modules/.vite/deps/chunk-XEBKRCNE.js.map +0 -7
  221. package/templates/default/node_modules/.vite/deps/package.json +0 -3
  222. package/templates/default/node_modules/.vite/deps/settings-C5H4VHXU.js +0 -213
  223. package/templates/default/node_modules/.vite/deps/settings-C5H4VHXU.js.map +0 -7
  224. package/templates/default/node_modules/.vite/deps/toolbar-H5DB6HVP.js +0 -525
  225. package/templates/default/node_modules/.vite/deps/toolbar-H5DB6HVP.js.map +0 -7
  226. package/templates/default/node_modules/.vite/deps/ui-library-JGHU6JE2.js +0 -1020
  227. package/templates/default/node_modules/.vite/deps/ui-library-JGHU6JE2.js.map +0 -7
  228. package/templates/default/node_modules/.vite/deps/xray-EFCQOW4E.js +0 -147
  229. package/templates/default/node_modules/.vite/deps/xray-EFCQOW4E.js.map +0 -7
  230. package/templates/default/src/components/layout/BaseLayout.astro +0 -47
  231. package/templates/default/src/components/layout/Container.astro +0 -18
  232. package/templates/default/src/components/layout/Footer.astro +0 -27
  233. package/templates/default/src/components/layout/Header.astro +0 -43
  234. package/templates/default/src/lib/markdown.ts +0 -171
  235. package/templates/default/src/pages/projects/index.astro +0 -193
@@ -1,127 +1,289 @@
1
1
  ---
2
- /**
3
- * Submit page — text-based instructions for contributing a new
4
- * record. No form: the openapps 19K form preview is overkill for
5
- * the default template, and a static "open a PR / open an issue"
6
- * workflow matches how the showcase actually accepts submissions.
7
- */
8
2
  import siteConfig from "../../data/generated/site-config.json";
9
- import { indexSlug, itemLabel } from "../data/records";
3
+ import { fullItems, itemLabel } from "../data/records";
10
4
  import BaseLayout from "@grove-dev/astro/layouts/BaseLayout.astro";
11
5
  import Container from "@grove-dev/astro/layouts/Container.astro";
12
6
 
13
- const title = `Submit a ${itemLabel()} — ${siteConfig.name}`;
14
- const description = `Submit a new ${itemLabel()} to ${siteConfig.name}.`;
15
- const noindex = true;
16
- const slug = indexSlug();
7
+ const singular = itemLabel();
8
+ const title = `Submit ${singular} - ${siteConfig.name}`;
9
+ const description = `Submit a new ${singular} to ${siteConfig.name}.`;
10
+ const repoUrl = siteConfig.repoUrl ?? "https://github.com/tortuvshin/grove";
17
11
 
18
- const repoPath = (siteConfig.repoUrl ?? "").replace(/^https?:\/\/github\.com\//, "");
19
- const issueUrl = repoPath
20
- ? `https://github.com/${repoPath}/issues/new?template=record_submission.md`
21
- : "https://github.com/tortuvshin/grove/issues/new";
12
+ const values = (key: "category" | "stack") =>
13
+ [...new Set(fullItems.map((item) => String(item[key] ?? "")).filter(Boolean))]
14
+ .sort((a, b) => a.localeCompare(b));
15
+ const categories = values("category");
16
+ const stacks = values("stack");
17
+ const existingSlugs = fullItems.map((item) => item.slug).filter(Boolean);
18
+ const existingFullNames = fullItems
19
+ .map((item) => {
20
+ const url = String(item.repoUrl ?? item.links?.github ?? "");
21
+ const match = url.match(/github\.com\/([^/]+)\/([^/?#]+)/i);
22
+ return match ? `${match[1]}/${match[2].replace(/\.git$/, "")}`.toLowerCase() : null;
23
+ })
24
+ .filter(Boolean);
25
+
26
+ const platformOptions = ["iOS", "Android", "Web", "macOS", "Windows", "Linux"];
27
+ const goodSubmissions = [
28
+ `A real, usable ${singular}, not a tutorial or one-screen demo`,
29
+ "A public repository with a clear open-source license",
30
+ "Enough documentation to understand, run, or contribute",
31
+ "Recent maintenance, releases, or meaningful project history",
32
+ ];
33
+ const pleaseAvoid = [
34
+ "Snippets, exercises, abandoned experiments, or duplicate entries",
35
+ "Private repositories or projects without source",
36
+ "Marketing pages with no usable project behind them",
37
+ "Records with no license or verifiable repository",
38
+ ];
22
39
  ---
23
40
 
24
- <BaseLayout
25
- title={title}
26
- description={description}
27
- site={siteConfig}
28
- noindex={noindex}
29
- >
41
+ <BaseLayout title={title} description={description} site={siteConfig} noindex>
30
42
  <Container>
31
- <article class="py-12 sm:py-16">
32
- <span class="text-2xs font-medium uppercase tracking-wider text-ink-500 dark:text-ink-400">
33
- Submit
34
- </span>
35
- <h1 class="mt-1 text-[1.75rem] sm:text-[2rem] font-semibold tracking-tight text-ink-900 dark:text-ink-100 m-0">
36
- Submit a {itemLabel()}
37
- </h1>
38
- <p class="mt-4 max-w-[62ch] text-sm text-ink-700 dark:text-ink-200 m-0">
39
- {siteConfig.name} is a community knowledge site. Adding a new{" "}
40
- {itemLabel()} is a two-step process open a submission issue,
41
- then open a pull request that adds a new YAML file under{" "}
42
- <code class="font-mono text-ink-900 dark:text-ink-100">data/records/</code>.
43
- </p>
44
-
45
- <div class="mt-6 flex flex-wrap gap-2">
46
- <a
47
- href={issueUrl}
48
- target="_blank"
49
- rel="noopener noreferrer"
50
- class="grove-btn grove-btn-primary"
51
- >
52
- Open a submission issue ↗
53
- </a>
54
- {repoPath && (
55
- <a
56
- href={`https://github.com/${repoPath}/blob/main/.github/ISSUE_TEMPLATE/record_submission.md`}
57
- target="_blank"
58
- rel="noopener noreferrer"
59
- class="grove-btn grove-btn-outline"
60
- >
61
- See the issue template
62
- </a>
63
- )}
43
+ <section class="py-10 sm:py-14">
44
+ <div class="max-w-3xl">
45
+ <p class="m-0 text-2xs font-semibold uppercase tracking-wider text-ink-500 dark:text-ink-400">
46
+ {singular} submission
47
+ </p>
48
+ <h1 class="mt-2 text-[2rem] font-semibold tracking-tight text-ink-900 dark:text-ink-100">
49
+ Add {singular === "app" ? "an" : "a"} {singular} to the directory
50
+ </h1>
51
+ <p class="m-0 mt-3 max-w-[60ch] text-[0.9375rem] leading-relaxed text-ink-500 dark:text-ink-400">
52
+ Paste a GitHub URL to pull in the basics, edit the generated draft,
53
+ then open a pull request. The data stays in this repository.
54
+ </p>
64
55
  </div>
65
56
 
66
- <section class="mt-12 max-w-[68ch">
67
- <h2 class="m-0 text-lg font-semibold tracking-tight text-ink-900 dark:text-ink-100">
68
- Manual record (alternative to the issue form)
69
- </h2>
70
- <p class="mt-2 text-sm text-ink-700 dark:text-ink-200 m-0">
71
- Prefer to write a record by hand? Here's the minimum shape for a{" "}
72
- <code class="font-mono">{siteConfig.blueprint}</code> record.
73
- The schema is validated automatically on every PR.
74
- </p>
75
- {siteConfig.blueprint === "project-directory" && (
76
- <pre class="mt-4 overflow-x-auto rounded-md border border-ink-200 bg-ink-50 p-4 text-xs leading-relaxed text-ink-800 dark:border-ink-800 dark:bg-ink-900/60 dark:text-ink-200"><code>{`kind: project
77
- slug: my-project
78
- name: My Project
79
- description: One-line description of what this project does
80
- category: tools
81
- tags:
82
- - open-source
83
- links:
84
- github: https://github.com/owner/repo
85
- website: https://example.com`}</code></pre>
86
- )}
87
- {siteConfig.blueprint === "resource-hub" && (
88
- <pre class="mt-4 overflow-x-auto rounded-md border border-ink-200 bg-ink-50 p-4 text-xs leading-relaxed text-ink-800 dark:border-ink-800 dark:bg-ink-900/60 dark:text-ink-200"><code>{`kind: resource
89
- slug: my-resource
90
- title: My Resource
91
- description: One-line description of what this resource is
92
- category: guides
93
- type: guide
94
- topic: coding-agents
95
- tags:
96
- - ai
97
- links:
98
- source: https://example.com`}</code></pre>
99
- )}
100
- {siteConfig.blueprint === "ecosystem-map" && (
101
- <pre class="mt-4 overflow-x-auto rounded-md border border-ink-200 bg-ink-50 p-4 text-xs leading-relaxed text-ink-800 dark:border-ink-800 dark:bg-ink-900/60 dark:text-ink-200"><code>{`kind: entity
102
- slug: my-entity
103
- name: My Organization
104
- description: One-line description of what this organization does
105
- category: education
106
- type: company
107
- tags:
108
- - technology
109
- links:
110
- website: https://example.com`}</code></pre>
111
- )}
112
- </section>
113
-
114
- <section class="mt-12 max-w-[68ch">
115
- <h2 class="m-0 text-lg font-semibold tracking-tight text-ink-900 dark:text-ink-100">
116
- What happens after you submit
117
- </h2>
118
- <ol class="mt-3 m-0 flex list-decimal flex-col gap-2 pl-5 text-sm text-ink-700 dark:text-ink-200">
119
- <li>A maintainer reviews the issue and tags it as <code class="font-mono">accepted</code> or <code class="font-mono">needs-info</code>.</li>
120
- <li>You open a PR with the new <code class="font-mono">data/records/&lt;slug&gt;.yml</code> file.</li>
121
- <li>CI runs <code class="font-mono">grove validate</code> and previews the site with your record.</li>
122
- <li>A maintainer merges. The next <code class="font-mono">grove build</code> deploys it.</li>
123
- </ol>
124
- </section>
125
- </article>
57
+ <ol class="mt-6 grid grid-cols-1 gap-2 text-2xs sm:grid-cols-3 sm:gap-3" aria-label="Submission steps">
58
+ {[
59
+ ["1", "Paste a GitHub URL", "We'll pull the metadata automatically."],
60
+ ["2", "Edit the draft", "Fix the category, stack, platforms, and notes."],
61
+ ["3", "Open a pull request", "Reviewers will validate and merge the record."],
62
+ ].map(([number, heading, copy]) => (
63
+ <li class="card flex items-start gap-2 p-3">
64
+ <span class="mt-0.5 inline-flex h-5 w-5 shrink-0 items-center justify-center rounded-full border border-ink-300 font-mono font-semibold text-ink-700 dark:border-ink-700 dark:text-ink-300">{number}</span>
65
+ <div>
66
+ <div class="font-medium text-ink-900 dark:text-ink-100">{heading}</div>
67
+ <div class="text-ink-500 dark:text-ink-400">{copy}</div>
68
+ </div>
69
+ </li>
70
+ ))}
71
+ </ol>
72
+
73
+ <div class="mt-8 grid grid-cols-1 gap-6 lg:grid-cols-[minmax(0,1fr)_minmax(360px,0.8fr)]">
74
+ <form id="submit-form" class="card p-5">
75
+ <div class="grid gap-5">
76
+ <label class="grid gap-1.5">
77
+ <span class="label">GitHub URL</span>
78
+ <div class="flex flex-col gap-2 sm:flex-row">
79
+ <input id="repo-url" type="url" required placeholder="https://github.com/owner/repo" class="field flex-1" />
80
+ <button id="fetch-repo" type="button" class="btn-primary min-h-10 justify-center">Generate draft</button>
81
+ </div>
82
+ <span class="help">The repository must be public. We never write to it.</span>
83
+ </label>
84
+
85
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
86
+ <label class="grid gap-1.5"><span class="label">Name</span><input id="item-name" type="text" class="field" /></label>
87
+ <label class="grid gap-1.5"><span class="label">Slug</span><input id="item-slug" type="text" class="field font-mono" /><span class="help">URL fragment, auto-filled from the repository name.</span></label>
88
+ </div>
89
+
90
+ <label class="grid gap-1.5">
91
+ <span class="label">Description</span>
92
+ <textarea id="item-description" rows="3" class="field resize-y"></textarea>
93
+ <span class="help">One or two sentences in plain language.</span>
94
+ </label>
95
+
96
+ <div class="grid grid-cols-1 gap-4 sm:grid-cols-2">
97
+ <label class="grid gap-1.5">
98
+ <span class="label">Category</span>
99
+ <input id="item-category" list="category-options" class="field" />
100
+ <datalist id="category-options">{categories.map((value) => <option value={value} />)}</datalist>
101
+ </label>
102
+ <label class="grid gap-1.5">
103
+ <span class="label">Primary stack</span>
104
+ <input id="primary-stack" list="stack-options" class="field" />
105
+ <datalist id="stack-options">{stacks.map((value) => <option value={value} />)}</datalist>
106
+ </label>
107
+ </div>
108
+
109
+ <fieldset class="grid gap-2">
110
+ <legend class="label">Platforms</legend>
111
+ <div class="grid grid-cols-2 gap-2 sm:grid-cols-3">
112
+ {platformOptions.map((platform) => (
113
+ <label class="flex min-h-9 items-center gap-2 rounded-md border border-ink-200 px-2 text-sm dark:border-ink-800">
114
+ <input type="checkbox" name="platform" value={platform.toLowerCase()} class="h-4 w-4" />
115
+ <span>{platform}</span>
116
+ </label>
117
+ ))}
118
+ </div>
119
+ </fieldset>
120
+
121
+ <label class="grid gap-1.5"><span class="label">Tags</span><input id="item-tags" type="text" placeholder="self-hosted, developer-tools, offline-first" class="field" /></label>
122
+ <label class="grid gap-1.5"><span class="label">Website</span><input id="item-website" type="url" placeholder="https://example.com" class="field" /></label>
123
+ <label class="grid gap-1.5"><span class="label">Best for</span><textarea id="best-for" rows="3" class="field resize-y" placeholder="One use case per line"></textarea></label>
124
+ </div>
125
+ </form>
126
+
127
+ <aside class="flex flex-col gap-4">
128
+ <div class="card p-5">
129
+ <h2 class="m-0 text-[0.9375rem] font-semibold text-ink-900 dark:text-ink-100">Submission criteria</h2>
130
+ <p class="m-0 mt-1 text-2xs text-ink-500 dark:text-ink-400">Use this checklist before opening the draft.</p>
131
+ <div class="mt-4 grid grid-cols-1 gap-4 text-2xs sm:grid-cols-2 lg:grid-cols-1 xl:grid-cols-2">
132
+ <div>
133
+ <div class="font-semibold uppercase tracking-wider text-emerald-700 dark:text-emerald-400">Good submissions</div>
134
+ <ul class="m-0 mt-2 list-none space-y-1 p-0 text-ink-700 dark:text-ink-200">{goodSubmissions.map((item) => <li class="flex gap-2"><span class="text-emerald-600">✓</span><span>{item}</span></li>)}</ul>
135
+ </div>
136
+ <div>
137
+ <div class="font-semibold uppercase tracking-wider text-amber-700 dark:text-amber-400">Please avoid</div>
138
+ <ul class="m-0 mt-2 list-none space-y-1 p-0 text-ink-700 dark:text-ink-200">{pleaseAvoid.map((item) => <li class="flex gap-2"><span class="text-amber-600">·</span><span>{item}</span></li>)}</ul>
139
+ </div>
140
+ </div>
141
+ </div>
142
+
143
+ <div class="card flex min-h-[420px] flex-col p-5">
144
+ <div class="flex flex-wrap items-center justify-between gap-3">
145
+ <h2 class="m-0 text-base font-semibold text-ink-900 dark:text-ink-100">YAML draft</h2>
146
+ <div class="flex items-center gap-2">
147
+ <button id="copy-yaml" type="button" class="btn-outline pointer-events-none opacity-50" disabled>Copy YAML</button>
148
+ <a id="open-pr-link" href="#" target="_blank" rel="noopener noreferrer" class="btn-outline pointer-events-none opacity-50">Open PR draft</a>
149
+ </div>
150
+ </div>
151
+ <pre class="mt-4 min-h-0 flex-1 overflow-auto rounded-md border border-ink-200 bg-ink-50 p-3 text-xs leading-relaxed text-ink-800 dark:border-ink-800 dark:bg-ink-900/60 dark:text-ink-200"><code id="yaml-preview">Paste a GitHub URL to generate a draft.</code></pre>
152
+ <p id="submit-status" class="mt-3 min-h-5 text-2xs text-ink-500 dark:text-ink-400" aria-live="polite"></p>
153
+ </div>
154
+ </aside>
155
+ </div>
156
+ </section>
126
157
  </Container>
158
+
159
+ <style>
160
+ .field { min-height: 2.5rem; border-radius: .375rem; border: 1px solid var(--color-ink-200); background: white; padding: .5rem .75rem; color: var(--color-ink-900); font-size: .875rem; outline: none; }
161
+ .field:focus { border-color: var(--color-ink-500); }
162
+ :global(.dark) .field { border-color: var(--color-ink-800); background: var(--color-ink-950); color: var(--color-ink-100); }
163
+ .label { font-size: var(--text-2xs); font-weight: 500; text-transform: uppercase; letter-spacing: .05em; color: var(--color-ink-500); }
164
+ .help { font-size: var(--text-2xs); color: var(--color-ink-500); }
165
+ </style>
166
+
167
+ <script is:inline define:vars={{ existingSlugs, existingFullNames, repoUrl }}>
168
+ // @ts-nocheck
169
+ const $ = (selector) => document.querySelector(selector);
170
+ const inputs = {
171
+ repo: $("#repo-url"), name: $("#item-name"), slug: $("#item-slug"),
172
+ description: $("#item-description"), category: $("#item-category"),
173
+ stack: $("#primary-stack"), tags: $("#item-tags"),
174
+ website: $("#item-website"), bestFor: $("#best-for"),
175
+ };
176
+ const fetchButton = $("#fetch-repo");
177
+ const preview = $("#yaml-preview");
178
+ const status = $("#submit-status");
179
+ const copyButton = $("#copy-yaml");
180
+ const openPrLink = $("#open-pr-link");
181
+ const slugSet = new Set(existingSlugs);
182
+ const repoSet = new Set(existingFullNames);
183
+ let repository = null;
184
+
185
+ const slugify = (value) => String(value || "").toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
186
+ const parseRepo = (value) => {
187
+ const match = String(value).match(/github\.com\/([^/]+)\/([^/?#]+)/);
188
+ return match ? { owner: match[1], repo: match[2].replace(/\.git$/, "") } : null;
189
+ };
190
+ const quote = (value) => `"${String(value ?? "").replace(/\\/g, "\\\\").replace(/"/g, '\\"')}"`;
191
+ const lines = (values, indent = 2) => values.map((value) => `${" ".repeat(indent)}- ${value}`).join("\n");
192
+ const selectedPlatforms = () => [...document.querySelectorAll("input[name=platform]:checked")].map((input) => input.value);
193
+ const setStatus = (text, tone = "muted") => {
194
+ status.textContent = text;
195
+ status.className = `mt-3 min-h-5 text-2xs ${tone === "error" ? "text-red-600 dark:text-red-400" : tone === "warn" ? "text-amber-700 dark:text-amber-400" : tone === "success" ? "text-emerald-700 dark:text-emerald-400" : "text-ink-500 dark:text-ink-400"}`;
196
+ };
197
+ const inferStack = (repo) => {
198
+ const language = String(repo.language || "").toLowerCase();
199
+ const topics = (repo.topics || []).map((topic) => String(topic).toLowerCase());
200
+ if (topics.includes("flutter") || language === "dart") return "Flutter";
201
+ if (topics.includes("react-native")) return "React Native";
202
+ if (language === "typescript" || language === "javascript") return "TypeScript";
203
+ return repo.language || "";
204
+ };
205
+ const generateYaml = () => {
206
+ if (!repository) return "";
207
+ const parsed = parseRepo(inputs.repo.value);
208
+ if (!parsed) return "";
209
+ const tags = inputs.tags.value.split(",").map((tag) => tag.trim()).filter(Boolean);
210
+ const platforms = selectedPlatforms();
211
+ const bestFor = inputs.bestFor.value.split("\n").map((item) => item.trim()).filter(Boolean);
212
+ return [
213
+ "kind: project",
214
+ `slug: ${slugify(inputs.slug.value || repository.name)}`,
215
+ `name: ${quote(inputs.name.value)}`,
216
+ `description: ${quote(inputs.description.value)}`,
217
+ `category: ${inputs.category.value || "other"}`,
218
+ "projectType: real-app",
219
+ `stack: ${quote(inputs.stack.value)}`,
220
+ "platforms:", platforms.length ? lines(platforms) : " []",
221
+ "tags:", tags.length ? lines(tags) : " []",
222
+ `repoUrl: ${repository.html_url}`,
223
+ "links:",
224
+ ` github: ${repository.html_url}`,
225
+ ...(inputs.website.value ? [` website: ${inputs.website.value}`] : []),
226
+ "bestFor:", bestFor.length ? lines(bestFor) : " []",
227
+ "source:",
228
+ " type: github",
229
+ ` owner: ${parsed.owner}`,
230
+ ` repo: ${parsed.repo}`,
231
+ "curation:",
232
+ " reviewed: false",
233
+ " labels: []",
234
+ " lenses: []",
235
+ "",
236
+ ].join("\n");
237
+ };
238
+ const refresh = () => {
239
+ const yaml = generateYaml();
240
+ preview.textContent = yaml || "Paste a GitHub URL to generate a draft.";
241
+ if (!yaml) return;
242
+ const params = new URLSearchParams({ filename: `data/records/${slugify(inputs.slug.value)}.yml`, value: yaml });
243
+ openPrLink.href = `${repoUrl}/new/main?${params}`;
244
+ openPrLink.classList.remove("pointer-events-none", "opacity-50");
245
+ copyButton.disabled = false;
246
+ copyButton.classList.remove("pointer-events-none", "opacity-50");
247
+ };
248
+
249
+ fetchButton.addEventListener("click", async () => {
250
+ const parsed = parseRepo(inputs.repo.value);
251
+ if (!parsed) return setStatus("Enter a valid GitHub repository URL.", "error");
252
+ const fullName = `${parsed.owner}/${parsed.repo}`.toLowerCase();
253
+ if (repoSet.has(fullName)) setStatus("This repository is already listed. The draft can update its record.", "warn");
254
+ fetchButton.disabled = true;
255
+ setStatus("Fetching GitHub metadata...");
256
+ try {
257
+ const response = await fetch(`https://api.github.com/repos/${parsed.owner}/${parsed.repo}`, { headers: { Accept: "application/vnd.github+json" } });
258
+ if (response.status === 404) throw new Error("Repository not found or not public.");
259
+ if (response.status === 403) throw new Error("GitHub rate limit reached. Try again shortly.");
260
+ if (!response.ok) throw new Error(`GitHub returned ${response.status}.`);
261
+ repository = await response.json();
262
+ if (repository.private) throw new Error("Private repositories cannot be submitted.");
263
+ inputs.name.value = repository.name || parsed.repo;
264
+ inputs.slug.value = slugify(repository.name || parsed.repo);
265
+ inputs.description.value = repository.description || "";
266
+ inputs.stack.value = inferStack(repository);
267
+ inputs.tags.value = (repository.topics || []).slice(0, 8).join(", ");
268
+ inputs.website.value = repository.homepage || "";
269
+ const duplicate = slugSet.has(inputs.slug.value);
270
+ setStatus(duplicate ? "That slug already exists. Choose another or update the existing record." : "Draft generated. Edit any field and the YAML will refresh.", duplicate ? "warn" : "success");
271
+ refresh();
272
+ } catch (error) {
273
+ repository = null;
274
+ setStatus(error.message || "Unable to fetch repository metadata.", "error");
275
+ } finally {
276
+ fetchButton.disabled = false;
277
+ }
278
+ });
279
+ $("#submit-form").addEventListener("input", refresh);
280
+ copyButton.addEventListener("click", async () => {
281
+ try {
282
+ await navigator.clipboard.writeText(preview.textContent || "");
283
+ setStatus("Copied YAML to clipboard.", "success");
284
+ } catch {
285
+ setStatus("Couldn't copy automatically. Select the YAML and copy it.", "error");
286
+ }
287
+ });
288
+ </script>
127
289
  </BaseLayout>
@@ -0,0 +1,28 @@
1
+ {
2
+ // SPDX-License-Identifier: MIT
3
+ //
4
+ // Cloudflare Pages configuration for the Grove Astro template.
5
+ //
6
+ // `name` is the Pages project name (`grove-site` by default —
7
+ // rename to match your Cloudflare account, or override via
8
+ // `wrangler pages deploy --project-name <name>`).
9
+ //
10
+ // `compatibility_date` pins the runtime API surface. Bump it
11
+ // when you want to opt into newer Pages features; older dates
12
+ // are fine for stable behavior.
13
+ //
14
+ // `pages_build_output_dir` is the directory that `astro build`
15
+ // writes to. Astro 6's default is `./dist`, which matches.
16
+ //
17
+ // The deploy workflow in `.github/workflows/build.yml` runs
18
+ // pnpm run build
19
+ // npx wrangler pages deploy dist --project-name <name>
20
+ // after this file is committed.
21
+ "$schema": "node_modules/wrangler/config-schema.json",
22
+ "name": "grove-site",
23
+ "compatibility_date": "2026-06-07",
24
+ "pages_build_output_dir": "./dist",
25
+ "observability": {
26
+ "enabled": true
27
+ }
28
+ }
package/LICENSE DELETED
@@ -1,21 +0,0 @@
1
- MIT License
2
-
3
- Copyright (c) 2026 Turtuvshin Byambaa
4
-
5
- Permission is hereby granted, free of charge, to any person obtaining a copy
6
- of this software and associated documentation files (the "Software"), to deal
7
- in the Software without restriction, including without limitation the rights
8
- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- copies of the Software, and to permit persons to whom the Software is
10
- furnished to do so, subject to the following conditions:
11
-
12
- The above copyright notice and this permission notice shall be included in all
13
- copies or substantial portions of the Software.
14
-
15
- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- SOFTWARE.
@@ -1,155 +0,0 @@
1
- declare module 'astro:content' {
2
- export interface RenderResult {
3
- Content: import('astro/runtime/server/index.js').AstroComponentFactory;
4
- headings: import('astro').MarkdownHeading[];
5
- remarkPluginFrontmatter: Record<string, any>;
6
- }
7
- interface Render {
8
- '.md': Promise<RenderResult>;
9
- }
10
-
11
- export interface RenderedContent {
12
- html: string;
13
- metadata?: {
14
- imagePaths: Array<string>;
15
- [key: string]: unknown;
16
- };
17
- }
18
-
19
- type Flatten<T> = T extends { [K: string]: infer U } ? U : never;
20
-
21
- export type CollectionKey = keyof DataEntryMap;
22
- export type CollectionEntry<C extends CollectionKey> = Flatten<DataEntryMap[C]>;
23
-
24
- type AllValuesOf<T> = T extends any ? T[keyof T] : never;
25
-
26
- export type ReferenceDataEntry<
27
- C extends CollectionKey,
28
- E extends keyof DataEntryMap[C] = string,
29
- > = {
30
- collection: C;
31
- id: E;
32
- };
33
-
34
- export type ReferenceLiveEntry<C extends keyof LiveContentConfig['collections']> = {
35
- collection: C;
36
- id: string;
37
- };
38
-
39
- export function getCollection<C extends keyof DataEntryMap, E extends CollectionEntry<C>>(
40
- collection: C,
41
- filter?: (entry: CollectionEntry<C>) => entry is E,
42
- ): Promise<E[]>;
43
- export function getCollection<C extends keyof DataEntryMap>(
44
- collection: C,
45
- filter?: (entry: CollectionEntry<C>) => unknown,
46
- ): Promise<CollectionEntry<C>[]>;
47
-
48
- export function getLiveCollection<C extends keyof LiveContentConfig['collections']>(
49
- collection: C,
50
- filter?: LiveLoaderCollectionFilterType<C>,
51
- ): Promise<
52
- import('astro').LiveDataCollectionResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>
53
- >;
54
-
55
- export function getEntry<
56
- C extends keyof DataEntryMap,
57
- E extends keyof DataEntryMap[C] | (string & {}),
58
- >(
59
- entry: ReferenceDataEntry<C, E>,
60
- ): E extends keyof DataEntryMap[C]
61
- ? Promise<DataEntryMap[C][E]>
62
- : Promise<CollectionEntry<C> | undefined>;
63
- export function getEntry<
64
- C extends keyof DataEntryMap,
65
- E extends keyof DataEntryMap[C] | (string & {}),
66
- >(
67
- collection: C,
68
- id: E,
69
- ): E extends keyof DataEntryMap[C]
70
- ? string extends keyof DataEntryMap[C]
71
- ? Promise<DataEntryMap[C][E]> | undefined
72
- : Promise<DataEntryMap[C][E]>
73
- : Promise<CollectionEntry<C> | undefined>;
74
- export function getLiveEntry<C extends keyof LiveContentConfig['collections']>(
75
- collection: C,
76
- filter: string | LiveLoaderEntryFilterType<C>,
77
- ): Promise<import('astro').LiveDataEntryResult<LiveLoaderDataType<C>, LiveLoaderErrorType<C>>>;
78
-
79
- /** Resolve an array of entry references from the same collection */
80
- export function getEntries<C extends keyof DataEntryMap>(
81
- entries: ReferenceDataEntry<C, keyof DataEntryMap[C]>[],
82
- ): Promise<CollectionEntry<C>[]>;
83
-
84
- export function render<C extends keyof DataEntryMap>(
85
- entry: DataEntryMap[C][string],
86
- ): Promise<RenderResult>;
87
-
88
- export function reference<
89
- C extends
90
- | keyof DataEntryMap
91
- // Allow generic `string` to avoid excessive type errors in the config
92
- // if `dev` is not running to update as you edit.
93
- // Invalid collection names will be caught at build time.
94
- | (string & {}),
95
- >(
96
- collection: C,
97
- ): import('astro/zod').ZodPipe<
98
- import('astro/zod').ZodString,
99
- import('astro/zod').ZodTransform<
100
- C extends keyof DataEntryMap
101
- ? {
102
- collection: C;
103
- id: string;
104
- }
105
- : never,
106
- string
107
- >
108
- >;
109
-
110
- type ReturnTypeOrOriginal<T> = T extends (...args: any[]) => infer R ? R : T;
111
- type InferEntrySchema<C extends keyof DataEntryMap> = import('astro/zod').infer<
112
- ReturnTypeOrOriginal<Required<ContentConfig['collections'][C]>['schema']>
113
- >;
114
- type ExtractLoaderConfig<T> = T extends { loader: infer L } ? L : never;
115
- type InferLoaderSchema<
116
- C extends keyof DataEntryMap,
117
- L = ExtractLoaderConfig<ContentConfig['collections'][C]>,
118
- > = L extends { schema: import('astro/zod').ZodSchema }
119
- ? import('astro/zod').infer<L['schema']>
120
- : any;
121
-
122
- type DataEntryMap = {
123
-
124
- };
125
-
126
- type ExtractLoaderTypes<T> = T extends import('astro/loaders').LiveLoader<
127
- infer TData,
128
- infer TEntryFilter,
129
- infer TCollectionFilter,
130
- infer TError
131
- >
132
- ? { data: TData; entryFilter: TEntryFilter; collectionFilter: TCollectionFilter; error: TError }
133
- : { data: never; entryFilter: never; collectionFilter: never; error: never };
134
- type ExtractEntryFilterType<T> = ExtractLoaderTypes<T>['entryFilter'];
135
- type ExtractCollectionFilterType<T> = ExtractLoaderTypes<T>['collectionFilter'];
136
- type ExtractErrorType<T> = ExtractLoaderTypes<T>['error'];
137
- type ExtractDataType<T> = ExtractLoaderTypes<T>['data'];
138
-
139
- type LiveLoaderDataType<C extends keyof LiveContentConfig['collections']> =
140
- LiveContentConfig['collections'][C]['schema'] extends undefined
141
- ? ExtractDataType<LiveContentConfig['collections'][C]['loader']>
142
- : import('astro/zod').infer<
143
- Exclude<LiveContentConfig['collections'][C]['schema'], undefined>
144
- >;
145
- type LiveLoaderEntryFilterType<C extends keyof LiveContentConfig['collections']> =
146
- ExtractEntryFilterType<LiveContentConfig['collections'][C]['loader']>;
147
- type LiveLoaderCollectionFilterType<C extends keyof LiveContentConfig['collections']> =
148
- ExtractCollectionFilterType<LiveContentConfig['collections'][C]['loader']>;
149
- type LiveLoaderErrorType<C extends keyof LiveContentConfig['collections']> = ExtractErrorType<
150
- LiveContentConfig['collections'][C]['loader']
151
- >;
152
-
153
- export type ContentConfig = never;
154
- export type LiveContentConfig = never;
155
- }
@@ -1,5 +0,0 @@
1
- {
2
- "_variables": {
3
- "lastUpdateCheck": 1781103180236
4
- }
5
- }
@@ -1 +0,0 @@
1
- /// <reference types="astro/client" />
@@ -1 +0,0 @@
1
- {"schemaVersion":1,"generatedAt":"2026-01-01T00:00:00Z","totalApps":0,"visibleApps":0,"apps":[]}
@@ -1,8 +0,0 @@
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
- }
@@ -1,7 +0,0 @@
1
- {
2
- "schemaVersion": 1,
3
- "blueprint": "project-directory",
4
- "generatedAt": "2026-06-10T15:03:23.841Z",
5
- "totalRecords": 0,
6
- "records": []
7
- }