@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,149 +0,0 @@
1
- import generatedJson from "../../data/generated/apps.json";
2
- import type { OpenSourceApp, AppLabel } from "./types";
3
-
4
- // ──────────────────────────────────────────────────────────────────────
5
- // Source of truth: data/generated/apps.json, produced at build time
6
- // from data/apps/*.yml by scripts/build-apps-json.mjs. The yml files
7
- // are the human-edited source; this file is just a typed re-export
8
- // that fills in safe defaults so consumers don't have to guard every
9
- // optional field.
10
- //
11
- // When adding a new app: write a yml in data/apps/, run
12
- // `pnpm run build:data`, and it will appear here.
13
- // ──────────────────────────────────────────────────────────────────────
14
-
15
- const generated = generatedJson as { apps: unknown[] };
16
-
17
- type GeneratedApp = Partial<OpenSourceApp> & {
18
- slug: string;
19
- name: string;
20
- repoUrl: string;
21
- description?: string;
22
- stack: string;
23
- platforms: string[];
24
- category: string;
25
- activity?: {
26
- stars?: number;
27
- forks?: number;
28
- lastCommitAt?: string | null;
29
- contributors?: number;
30
- updatedAt?: string;
31
- };
32
- };
33
-
34
- /**
35
- * Auto-compute labels for an app from its activity block. Used as a
36
- * fallback when a curator hasn't hand-set `labels:` in the yml. Drives
37
- * the homepage "new / hot / mature" sections.
38
- *
39
- * mature — stars ≥ 500, OR very high stars (popular, established)
40
- * hot — last commit within the last 6 months (currently active)
41
- * new — emerging: not mature, not in the last commit window, or
42
- * no commit signal at all
43
- *
44
- * Multiple labels can apply (a popular active project is both mature
45
- * and hot).
46
- */
47
- function computeLabels(g: GeneratedApp): AppLabel[] {
48
- const labels: AppLabel[] = [];
49
- // After the schemaVersion 1 migration, stars + lastCommitAt live at
50
- // the top level of the generated record (the v1 normalizer in
51
- // `app-schema.mjs` flattens `github.repository.stargazers_count`
52
- // and `github.repository.pushed_at` to top-level). The old
53
- // `g.activity.stars` shape still works for legacy records, so we
54
- // fall back to it for mixed input.
55
- const stars =
56
- typeof g.stars === "number"
57
- ? g.stars
58
- : typeof g.activity?.stars === "number"
59
- ? g.activity.stars
60
- : 0;
61
- const lastCommit = g.lastCommitAt ?? g.activity?.lastCommitAt;
62
-
63
- if (stars >= 500) labels.push("mature");
64
- if (stars >= 100 && stars < 500) labels.push("hot");
65
- if (stars < 100) labels.push("new");
66
-
67
- // Hot: recent commit and not already tagged as such
68
- if (lastCommit) {
69
- const sixMonthsAgo = new Date();
70
- sixMonthsAgo.setMonth(sixMonthsAgo.getMonth() - 6);
71
- if (new Date(lastCommit) >= sixMonthsAgo && !labels.includes("hot")) {
72
- labels.push("hot");
73
- }
74
- }
75
- return labels;
76
- }
77
-
78
- /**
79
- * Map a generated yml-shaped record to the OpenSourceApp shape that
80
- * pages expect. Fills defaults, flattens `activity.stars` → `stars`,
81
- * and tolerates missing curation fields.
82
- */
83
- function normalize(g: GeneratedApp): OpenSourceApp {
84
- const a = g.activity ?? {};
85
- return {
86
- slug: g.slug,
87
- name: g.name,
88
- description: g.description ?? "",
89
- repoUrl: g.repoUrl,
90
- homepageUrl: g.homepageUrl,
91
- stack: g.stack,
92
- stacks: g.stacks,
93
- platforms: g.platforms ?? [],
94
- distribution: g.distribution,
95
- category: g.category,
96
- tags: g.tags,
97
- logoUrl: g.logoUrl,
98
- stars: typeof a.stars === "number" ? a.stars : g.stars,
99
- license: g.license,
100
- status: g.status,
101
- addedAt: g.addedAt,
102
- lastCommitAt: a.lastCommitAt ?? g.lastCommitAt,
103
- labels: g.labels && g.labels.length > 0 ? g.labels : computeLabels(g),
104
- // Curation (optional)
105
- projectType: g.projectType,
106
- stateManagement: g.stateManagement,
107
- backend: g.backend,
108
- architecture: g.architecture,
109
- difficulty: g.difficulty,
110
- codebaseSize: g.codebaseSize,
111
- bestFor: g.bestFor,
112
- whyListed: g.whyListed,
113
- caveats: g.caveats,
114
- goodFirstIssues: g.goodFirstIssues,
115
- contributionGuide: g.contributionGuide,
116
- launchedBy: g.launchedBy,
117
- launchAsk: g.launchAsk,
118
- lenses: g.lenses,
119
- scores: g.scores,
120
- curation: g.curation,
121
- github: g.github,
122
- health: g.health,
123
- tier: g.tier,
124
- };
125
- }
126
-
127
- const generatedApps = generated.apps as GeneratedApp[];
128
-
129
- export const apps: OpenSourceApp[] = generatedApps.map(normalize);
130
-
131
- // ── Convenience filters ──────────────────────────────────────────────
132
-
133
- export function newApps(): OpenSourceApp[] {
134
- return apps.filter((a) => a.labels?.includes("new"));
135
- }
136
- export function hotApps(): OpenSourceApp[] {
137
- return apps.filter((a) => a.labels?.includes("hot"));
138
- }
139
- export function matureApps(): OpenSourceApp[] {
140
- return apps.filter((a) => a.labels?.includes("mature"));
141
- }
142
-
143
- // ── Lookups ──────────────────────────────────────────────────────────
144
-
145
- const bySlug = new Map(apps.map((a) => [a.slug, a]));
146
-
147
- export function appBySlug(slug: string): OpenSourceApp | undefined {
148
- return bySlug.get(slug);
149
- }
@@ -1,27 +0,0 @@
1
- export type Category = {
2
- slug: string;
3
- name: string;
4
- blurb: string;
5
- };
6
-
7
- // Static taxonomy. Counts are NOT stored here — they are computed at
8
- // build time from data/generated/apps.json via src/lib/category-counts.ts
9
- // so the numbers always match what's actually rendered.
10
- export const categories: Category[] = [
11
- { slug: "productivity", name: "Productivity", blurb: "Tasks, notes, calendars, knowledge bases." },
12
- { slug: "finance", name: "Finance", blurb: "Budgeting, wallets, expense tracking." },
13
- { slug: "education", name: "Education", blurb: "Flashcards, learning, reference apps." },
14
- { slug: "tools", name: "Tools", blurb: "Browsers, utilities, dev helpers, file tools." },
15
- { slug: "communication", name: "Communication", blurb: "Chat, messaging, social, team tools." },
16
- { slug: "health-and-fitness", name: "Health and Fitness", blurb: "Workouts, nutrition, wellness tracking." },
17
- { slug: "business", name: "Business", blurb: "Invoicing, jobs, marketplace, ops tools." },
18
- { slug: "games", name: "Games", blurb: "Open-source games and engines." },
19
- { slug: "media", name: "Media", blurb: "Music, movies, photos, audio and video." },
20
- { slug: "entertainment", name: "Entertainment", blurb: "TV, movies, books, anime, ebooks." },
21
- { slug: "social-network", name: "Social Network", blurb: "Decentralized social clients and readers." },
22
- { slug: "shopping", name: "Shopping", blurb: "E-commerce, delivery, food, retail." },
23
- { slug: "news", name: "News and Magazine", blurb: "Hacker News clients, RSS, magazines." },
24
- { slug: "travel", name: "Travel", blurb: "Flights, tourism, cab sharing, guides." },
25
- { slug: "lifestyle", name: "Lifestyle", blurb: "Habits, journaling, daily life tools." },
26
- { slug: "personalization", name: "Personalization", blurb: "Launchers, themes, customization." },
27
- ];
@@ -1,28 +0,0 @@
1
- /**
2
- * Site config exposed to Astro pages.
3
- *
4
- * This file is the typed view of `curated.config.ts`. The CLI builds it
5
- * from the project-root config at `grove build-data` time. Astro
6
- * pages and components import it directly for branding strings.
7
- *
8
- * Do not edit by hand. Re-run `grove build-data` after changing
9
- * `curated.config.ts`.
10
- */
11
-
12
- export type SiteConfig = {
13
- name: string;
14
- tagline: string;
15
- description: string;
16
- siteUrl: string;
17
- repoUrl: string;
18
- itemLabel: string;
19
- };
20
-
21
- export const siteConfig: SiteConfig = {
22
- name: "Grove",
23
- tagline: "A living, health-aware developer directory.",
24
- description: "A searchable directory of open-source projects — organized by stack, category, platform, license, activity, and maturity.",
25
- siteUrl: "https://example.com",
26
- repoUrl: "https://github.com/tortuvshin/grove",
27
- itemLabel: "project",
28
- };
@@ -1,96 +0,0 @@
1
- export type Contributor = {
2
- username: string;
3
- name?: string;
4
- avatarUrl: string;
5
- profileUrl: string;
6
- contributions?: number;
7
- };
8
-
9
- // AUTO-GENERATED by scripts/sync-contributors.mjs — do not edit by hand.
10
- // Re-run the script (or wait for the weekly workflow) to refresh from GitHub.
11
- // Source: GET /repos/tortuvshin/open-apps/contributors (82 named contributors).
12
- // Anonymous contributors are excluded — the homepage grid renders <a> avatars with no anonymous target.
13
- export const contributors: Contributor[] = [
14
- { username: "tortuvshin", avatarUrl: "https://avatars.githubusercontent.com/u/9257227?v=4", profileUrl: "https://github.com/tortuvshin", contributions: 140 },
15
- { username: "j-j-gajjar", avatarUrl: "https://avatars.githubusercontent.com/u/57590688?v=4", profileUrl: "https://github.com/j-j-gajjar", contributions: 5 },
16
- { username: "ArizArmeidi", avatarUrl: "https://avatars.githubusercontent.com/u/60814961?v=4", profileUrl: "https://github.com/ArizArmeidi", contributions: 3 },
17
- { username: "vellt", avatarUrl: "https://avatars.githubusercontent.com/u/61885011?v=4", profileUrl: "https://github.com/vellt", contributions: 3 },
18
- { username: "tejasbadone", avatarUrl: "https://avatars.githubusercontent.com/u/81501235?v=4", profileUrl: "https://github.com/tejasbadone", contributions: 3 },
19
- { username: "ErfanRht", avatarUrl: "https://avatars.githubusercontent.com/u/68302442?v=4", profileUrl: "https://github.com/ErfanRht", contributions: 2 },
20
- { username: "monolidth", avatarUrl: "https://avatars.githubusercontent.com/u/71930307?v=4", profileUrl: "https://github.com/monolidth", contributions: 2 },
21
- { username: "proninyaroslav", avatarUrl: "https://avatars.githubusercontent.com/u/7840559?v=4", profileUrl: "https://github.com/proninyaroslav", contributions: 2 },
22
- { username: "Tarikul711", avatarUrl: "https://avatars.githubusercontent.com/u/9304805?v=4", profileUrl: "https://github.com/Tarikul711", contributions: 2 },
23
- { username: "lucalves", avatarUrl: "https://avatars.githubusercontent.com/u/17712401?v=4", profileUrl: "https://github.com/lucalves", contributions: 2 },
24
- { username: "1hanzla100", avatarUrl: "https://avatars.githubusercontent.com/u/59178380?v=4", profileUrl: "https://github.com/1hanzla100", contributions: 2 },
25
- { username: "jerichoi224", avatarUrl: "https://avatars.githubusercontent.com/u/4184001?v=4", profileUrl: "https://github.com/jerichoi224", contributions: 2 },
26
- { username: "tsvillain", avatarUrl: "https://avatars.githubusercontent.com/u/42140007?v=4", profileUrl: "https://github.com/tsvillain", contributions: 1 },
27
- { username: "TNT-Likely", avatarUrl: "https://avatars.githubusercontent.com/u/9278923?v=4", profileUrl: "https://github.com/TNT-Likely", contributions: 1 },
28
- { username: "sumittiware", avatarUrl: "https://avatars.githubusercontent.com/u/64718675?v=4", profileUrl: "https://github.com/sumittiware", contributions: 1 },
29
- { username: "simonbengtsson", avatarUrl: "https://avatars.githubusercontent.com/u/3586691?v=4", profileUrl: "https://github.com/simonbengtsson", contributions: 1 },
30
- { username: "shaxxx", avatarUrl: "https://avatars.githubusercontent.com/u/1778875?v=4", profileUrl: "https://github.com/shaxxx", contributions: 1 },
31
- { username: "88srzh", avatarUrl: "https://avatars.githubusercontent.com/u/61797666?v=4", profileUrl: "https://github.com/88srzh", contributions: 1 },
32
- { username: "SatyamX64", avatarUrl: "https://avatars.githubusercontent.com/u/62766656?v=4", profileUrl: "https://github.com/SatyamX64", contributions: 1 },
33
- { username: "sarvesh4396", avatarUrl: "https://avatars.githubusercontent.com/u/68162479?v=4", profileUrl: "https://github.com/sarvesh4396", contributions: 1 },
34
- { username: "illussna", avatarUrl: "https://avatars.githubusercontent.com/u/20238269?v=4", profileUrl: "https://github.com/illussna", contributions: 1 },
35
- { username: "SAHILDUDHAL21", avatarUrl: "https://avatars.githubusercontent.com/u/129080375?v=4", profileUrl: "https://github.com/SAHILDUDHAL21", contributions: 1 },
36
- { username: "SaadAAkash", avatarUrl: "https://avatars.githubusercontent.com/u/16515550?v=4", profileUrl: "https://github.com/SaadAAkash", contributions: 1 },
37
- { username: "Rohithgilla12", avatarUrl: "https://avatars.githubusercontent.com/u/19389850?v=4", profileUrl: "https://github.com/Rohithgilla12", contributions: 1 },
38
- { username: "teolemon", avatarUrl: "https://avatars.githubusercontent.com/u/1689815?v=4", profileUrl: "https://github.com/teolemon", contributions: 1 },
39
- { username: "Re4ch-Jay", avatarUrl: "https://avatars.githubusercontent.com/u/111555521?v=4", profileUrl: "https://github.com/Re4ch-Jay", contributions: 1 },
40
- { username: "pauek", avatarUrl: "https://avatars.githubusercontent.com/u/4069?v=4", profileUrl: "https://github.com/pauek", contributions: 1 },
41
- { username: "DaNnyKg07", avatarUrl: "https://avatars.githubusercontent.com/u/78636435?v=4", profileUrl: "https://github.com/DaNnyKg07", contributions: 1 },
42
- { username: "omar-h-omar", avatarUrl: "https://avatars.githubusercontent.com/u/58376513?v=4", profileUrl: "https://github.com/omar-h-omar", contributions: 1 },
43
- { username: "FatoomRe", avatarUrl: "https://avatars.githubusercontent.com/u/112693194?v=4", profileUrl: "https://github.com/FatoomRe", contributions: 1 },
44
- { username: "yon30c", avatarUrl: "https://avatars.githubusercontent.com/u/83658386?v=4", profileUrl: "https://github.com/yon30c", contributions: 1 },
45
- { username: "y-pakorn", avatarUrl: "https://avatars.githubusercontent.com/u/48324733?v=4", profileUrl: "https://github.com/y-pakorn", contributions: 1 },
46
- { username: "virlow-voice", avatarUrl: "https://avatars.githubusercontent.com/u/102702984?v=4", profileUrl: "https://github.com/virlow-voice", contributions: 1 },
47
- { username: "trizin", avatarUrl: "https://avatars.githubusercontent.com/u/25263018?v=4", profileUrl: "https://github.com/trizin", contributions: 1 },
48
- { username: "sparkleMing", avatarUrl: "https://avatars.githubusercontent.com/u/38350996?v=4", profileUrl: "https://github.com/sparkleMing", contributions: 1 },
49
- { username: "softjapan", avatarUrl: "https://avatars.githubusercontent.com/u/11269856?v=4", profileUrl: "https://github.com/softjapan", contributions: 1 },
50
- { username: "moda20", avatarUrl: "https://avatars.githubusercontent.com/u/23613485?v=4", profileUrl: "https://github.com/moda20", contributions: 1 },
51
- { username: "mihalycsaba", avatarUrl: "https://avatars.githubusercontent.com/u/50019470?v=4", profileUrl: "https://github.com/mihalycsaba", contributions: 1 },
52
- { username: "ivirtex", avatarUrl: "https://avatars.githubusercontent.com/u/57679865?v=4", profileUrl: "https://github.com/ivirtex", contributions: 1 },
53
- { username: "comerc", avatarUrl: "https://avatars.githubusercontent.com/u/1025241?v=4", profileUrl: "https://github.com/comerc", contributions: 1 },
54
- { username: "albemala", avatarUrl: "https://avatars.githubusercontent.com/u/2332860?v=4", profileUrl: "https://github.com/albemala", contributions: 1 },
55
- { username: "xal", avatarUrl: "https://avatars.githubusercontent.com/u/1388084?v=4", profileUrl: "https://github.com/xal", contributions: 1 },
56
- { username: "yash1200", avatarUrl: "https://avatars.githubusercontent.com/u/38391570?v=4", profileUrl: "https://github.com/yash1200", contributions: 1 },
57
- { username: "wad3g", avatarUrl: "https://avatars.githubusercontent.com/u/2086896?v=4", profileUrl: "https://github.com/wad3g", contributions: 1 },
58
- { username: "VarunS2002", avatarUrl: "https://avatars.githubusercontent.com/u/30069380?v=4", profileUrl: "https://github.com/VarunS2002", contributions: 1 },
59
- { username: "friebetill", avatarUrl: "https://avatars.githubusercontent.com/u/10923085?v=4", profileUrl: "https://github.com/friebetill", contributions: 1 },
60
- { username: "theachoem", avatarUrl: "https://avatars.githubusercontent.com/u/29684683?v=4", profileUrl: "https://github.com/theachoem", contributions: 1 },
61
- { username: "Enhancifire", avatarUrl: "https://avatars.githubusercontent.com/u/81345756?v=4", profileUrl: "https://github.com/Enhancifire", contributions: 1 },
62
- { username: "Ehtiram-Ullah", avatarUrl: "https://avatars.githubusercontent.com/u/157794767?v=4", profileUrl: "https://github.com/Ehtiram-Ullah", contributions: 1 },
63
- { username: "Deepanshu-Rohilla", avatarUrl: "https://avatars.githubusercontent.com/u/52520071?v=4", profileUrl: "https://github.com/Deepanshu-Rohilla", contributions: 1 },
64
- { username: "DattatreyaReddy", avatarUrl: "https://avatars.githubusercontent.com/u/58727124?v=4", profileUrl: "https://github.com/DattatreyaReddy", contributions: 1 },
65
- { username: "shurygindv", avatarUrl: "https://avatars.githubusercontent.com/u/38868386?v=4", profileUrl: "https://github.com/shurygindv", contributions: 1 },
66
- { username: "csuka1219", avatarUrl: "https://avatars.githubusercontent.com/u/70962953?v=4", profileUrl: "https://github.com/csuka1219", contributions: 1 },
67
- { username: "ChangJoo-Park", avatarUrl: "https://avatars.githubusercontent.com/u/1451365?v=4", profileUrl: "https://github.com/ChangJoo-Park", contributions: 1 },
68
- { username: "KyleKun", avatarUrl: "https://avatars.githubusercontent.com/u/36611739?v=4", profileUrl: "https://github.com/KyleKun", contributions: 1 },
69
- { username: "bipinct", avatarUrl: "https://avatars.githubusercontent.com/u/1249142?v=4", profileUrl: "https://github.com/bipinct", contributions: 1 },
70
- { username: "Spyy004", avatarUrl: "https://avatars.githubusercontent.com/u/54628130?v=4", profileUrl: "https://github.com/Spyy004", contributions: 1 },
71
- { username: "AyanDas-99", avatarUrl: "https://avatars.githubusercontent.com/u/86493736?v=4", profileUrl: "https://github.com/AyanDas-99", contributions: 1 },
72
- { username: "aryamangodara", avatarUrl: "https://avatars.githubusercontent.com/u/77824849?v=4", profileUrl: "https://github.com/aryamangodara", contributions: 1 },
73
- { username: "agordn52", avatarUrl: "https://avatars.githubusercontent.com/u/17294994?v=4", profileUrl: "https://github.com/agordn52", contributions: 1 },
74
- { username: "akmadan", avatarUrl: "https://avatars.githubusercontent.com/u/56507451?v=4", profileUrl: "https://github.com/akmadan", contributions: 1 },
75
- { username: "akashlilhare", avatarUrl: "https://avatars.githubusercontent.com/u/39927872?v=4", profileUrl: "https://github.com/akashlilhare", contributions: 1 },
76
- { username: "aditya-njr", avatarUrl: "https://avatars.githubusercontent.com/u/169588760?v=4", profileUrl: "https://github.com/aditya-njr", contributions: 1 },
77
- { username: "abhith", avatarUrl: "https://avatars.githubusercontent.com/u/7039457?v=4", profileUrl: "https://github.com/abhith", contributions: 1 },
78
- { username: "NaserElziadna", avatarUrl: "https://avatars.githubusercontent.com/u/24838963?v=4", profileUrl: "https://github.com/NaserElziadna", contributions: 1 },
79
- { username: "brownboycodes", avatarUrl: "https://avatars.githubusercontent.com/u/64550304?v=4", profileUrl: "https://github.com/brownboycodes", contributions: 1 },
80
- { username: "mzsdev1", avatarUrl: "https://avatars.githubusercontent.com/u/34914546?v=4", profileUrl: "https://github.com/mzsdev1", contributions: 1 },
81
- { username: "mllrr96", avatarUrl: "https://avatars.githubusercontent.com/u/28247455?v=4", profileUrl: "https://github.com/mllrr96", contributions: 1 },
82
- { username: "hadiuzzaman524", avatarUrl: "https://avatars.githubusercontent.com/u/52348628?v=4", profileUrl: "https://github.com/hadiuzzaman524", contributions: 1 },
83
- { username: "deandreamatias", avatarUrl: "https://avatars.githubusercontent.com/u/21011641?v=4", profileUrl: "https://github.com/deandreamatias", contributions: 1 },
84
- { username: "mateusz-bak", avatarUrl: "https://avatars.githubusercontent.com/u/32651935?v=4", profileUrl: "https://github.com/mateusz-bak", contributions: 1 },
85
- { username: "maksymilian-majer", avatarUrl: "https://avatars.githubusercontent.com/u/1215868?v=4", profileUrl: "https://github.com/maksymilian-majer", contributions: 1 },
86
- { username: "musfique113", avatarUrl: "https://avatars.githubusercontent.com/u/53111065?v=4", profileUrl: "https://github.com/musfique113", contributions: 1 },
87
- { username: "Mufaddal5253110", avatarUrl: "https://avatars.githubusercontent.com/u/60619133?v=4", profileUrl: "https://github.com/Mufaddal5253110", contributions: 1 },
88
- { username: "Kessir", avatarUrl: "https://avatars.githubusercontent.com/u/2332730?v=4", profileUrl: "https://github.com/Kessir", contributions: 1 },
89
- { username: "kaiwalyakoparkar", avatarUrl: "https://avatars.githubusercontent.com/u/53310847?v=4", profileUrl: "https://github.com/kaiwalyakoparkar", contributions: 1 },
90
- { username: "Livinglist", avatarUrl: "https://avatars.githubusercontent.com/u/7277662?v=4", profileUrl: "https://github.com/Livinglist", contributions: 1 },
91
- { username: "jerald-jacob", avatarUrl: "https://avatars.githubusercontent.com/u/25875900?v=4", profileUrl: "https://github.com/jerald-jacob", contributions: 1 },
92
- { username: "jaysavsani07", avatarUrl: "https://avatars.githubusercontent.com/u/43170852?v=4", profileUrl: "https://github.com/jaysavsani07", contributions: 1 },
93
- { username: "javipacheco", avatarUrl: "https://avatars.githubusercontent.com/u/456025?v=4", profileUrl: "https://github.com/javipacheco", contributions: 1 },
94
- { username: "7flash", avatarUrl: "https://avatars.githubusercontent.com/u/4569866?v=4", profileUrl: "https://github.com/7flash", contributions: 1 },
95
- { username: "floranguyen0", avatarUrl: "https://avatars.githubusercontent.com/u/72301141?v=4", profileUrl: "https://github.com/floranguyen0", contributions: 1 },
96
- ];
@@ -1,47 +0,0 @@
1
- export type Stack = {
2
- slug: string;
3
- name: string;
4
- blurb: string;
5
- status: "live" | "expanding" | "planned";
6
- };
7
-
8
- // Static taxonomy. Counts are NOT stored here — they are computed at
9
- // build time from data/generated/apps.json. See src/lib/stack-counts.ts.
10
- export const stacks: Stack[] = [
11
- {
12
- slug: "flutter",
13
- name: "Flutter",
14
- blurb: "Dart-based, cross-platform mobile apps.",
15
- status: "live",
16
- },
17
- {
18
- slug: "react-native",
19
- name: "React Native",
20
- blurb: "JavaScript / TypeScript mobile apps using React.",
21
- status: "expanding",
22
- },
23
- {
24
- slug: "ios",
25
- name: "iOS",
26
- blurb: "Native Swift apps from the App Store and the open-source community.",
27
- status: "expanding",
28
- },
29
- {
30
- slug: "android",
31
- name: "Android",
32
- blurb: "Native Kotlin / Java apps with a long, mature history.",
33
- status: "expanding",
34
- },
35
- {
36
- slug: "kmp",
37
- name: "Kotlin Multiplatform",
38
- blurb: "Shared Kotlin codebases targeting iOS and Android.",
39
- status: "planned",
40
- },
41
- {
42
- slug: "capacitor",
43
- name: "Capacitor",
44
- blurb: "Hybrid mobile apps built on web standards.",
45
- status: "planned",
46
- },
47
- ];
@@ -1,65 +0,0 @@
1
- // Site stats, derived from generated JSON files at build time.
2
- //
3
- // This file imports the same JSON the rest of the app uses, so the numbers
4
- // here always match what's actually rendered. No hand-tuned magic numbers.
5
- //
6
- // Numbers in the rendered UI (hero, header, OriginalCollection) come from
7
- // this module. If a number looks wrong, refresh the source data:
8
- // - pnpm run sync:repo-stats → data/generated/repo-stats.json (open-apps repo)
9
- // - pnpm run sync:contributors → src/data/contributors.ts
10
- // - pnpm run refresh:activity → data/apps/*.yml (per-app activity, then build:data)
11
- import generatedJson from "../../data/generated/apps.json";
12
- import repoStats from "../../data/generated/repo-stats.json";
13
- import { categories } from "./categories";
14
- import { contributors } from "./contributors";
15
-
16
- type GeneratedApp = {
17
- stack?: string;
18
- platforms?: string[];
19
- };
20
-
21
- type RepoStats = {
22
- stars: number;
23
- forks: number;
24
- watchers?: number;
25
- openIssues?: number;
26
- defaultBranch?: string;
27
- pushedAt?: string;
28
- syncedAt?: string;
29
- };
30
-
31
- const raw = generatedJson as { apps?: GeneratedApp[] };
32
- const apps: GeneratedApp[] = raw.apps ?? [];
33
- const repo = repoStats as RepoStats;
34
-
35
- const platforms = new Set<string>();
36
- for (const a of apps) {
37
- for (const p of a.platforms ?? []) platforms.add(p);
38
- }
39
-
40
- export type SiteStats = {
41
- apps: number;
42
- contributors: number;
43
- stars: number;
44
- forks: number;
45
- categories: number;
46
- stacks: number;
47
- platforms: number;
48
- originalRepo: string;
49
- };
50
-
51
- export const stats: SiteStats = {
52
- apps: apps.length,
53
- contributors: contributors.length,
54
- // Stars/forks are the open-apps repo's own — sourced from
55
- // data/generated/repo-stats.json, refreshed weekly by the
56
- // sync-repo-stats workflow. Previously these were summed across
57
- // every app in the directory, which produced 6-figure numbers
58
- // for a 4k-star repo.
59
- stars: repo.stars,
60
- forks: repo.forks,
61
- categories: categories.length,
62
- stacks: new Set(apps.map((a) => a.stack).filter(Boolean)).size,
63
- platforms: platforms.size,
64
- originalRepo: "https://github.com/tortuvshin/open-apps",
65
- };