From cb67f8174775c40f11dba1b316bf06fa250610f0 Mon Sep 17 00:00:00 2001 From: RONAK Date: Fri, 26 Jun 2026 10:02:58 +0530 Subject: [PATCH 1/5] feat: add interactive contributor wall to onboarding and settings --- app/settings.tsx | 17 +++- assets/contributors.json | 26 ++++++ components/ContributorsList.tsx | 115 ++++++++++++++++++++++++++ components/flows/onboarding-steps.tsx | 11 +++ manual-contributors.json | 9 ++ package.json | 2 + scripts/generate-contributors.js | 57 +++++++++++++ 7 files changed, 236 insertions(+), 1 deletion(-) create mode 100644 assets/contributors.json create mode 100644 components/ContributorsList.tsx create mode 100644 manual-contributors.json create mode 100644 scripts/generate-contributors.js diff --git a/app/settings.tsx b/app/settings.tsx index 9057531..2951769 100644 --- a/app/settings.tsx +++ b/app/settings.tsx @@ -6,6 +6,7 @@ import { ModeToggle } from "@/components/ui/mode-toggle"; import { Separator } from "@/components/ui/separator"; import { Text } from "@/components/ui/text"; import { View } from "@/components/ui/view"; +import { ContributorsList } from "@/components/ContributorsList"; import { type ExportFormat, exportAllChats, @@ -811,7 +812,21 @@ export default function Settings() { Open Source Credits - + {/* Contributors Section */} + + + CONTRIBUTORS + + + {/* Footer */} diff --git a/assets/contributors.json b/assets/contributors.json new file mode 100644 index 0000000..2ac52a6 --- /dev/null +++ b/assets/contributors.json @@ -0,0 +1,26 @@ +[ + { + "id": "manual-1", + "login": "marketing-guru", + "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4", + "html_url": "https://github.com/marketing-guru" + }, + { + "id": 30320791, + "login": "mrspence", + "avatar_url": "https://avatars.githubusercontent.com/u/30320791?v=4", + "html_url": "https://github.com/mrspence" + }, + { + "id": 89926355, + "login": "will-lamerton", + "avatar_url": "https://avatars.githubusercontent.com/u/89926355?v=4", + "html_url": "https://github.com/will-lamerton" + }, + { + "id": 49699333, + "login": "dependabot[bot]", + "avatar_url": "https://avatars.githubusercontent.com/in/29110?v=4", + "html_url": "https://github.com/apps/dependabot" + } +] \ No newline at end of file diff --git a/components/ContributorsList.tsx b/components/ContributorsList.tsx new file mode 100644 index 0000000..299b4db --- /dev/null +++ b/components/ContributorsList.tsx @@ -0,0 +1,115 @@ +import type React from "react"; +import { + FlatList, + Image, + Linking, + StyleSheet, + Text, + TouchableOpacity, + View, +} from "react-native"; + +import contributorsData from "../assets/contributors.json"; + +interface ContributorsListProps { + variant: "onboarding" | "settings"; +} + + const openProfile = (url: string) => { + if (url) { + // biome-ignore lint/suspicious/noConsole: Needed for openURL catch logging + Linking.openURL(url).catch((err) => console.error("Couldn't load page", err)); + } + }; + + if (variant === "onboarding") { + return ( + item.login} + numColumns={4} + contentContainerStyle={styles.gridContainer} + renderItem={({ item }) => ( + openProfile(item.html_url)} + > + + + )} + /> + ); + } + + return ( + item.login} + contentContainerStyle={styles.listContainer} + renderItem={({ item }) => ( + openProfile(item.html_url)} + > + + @{item.login} + {item.contributions && ( + + {item.contributions} + + )} + + )} + /> + ); +}; + +const styles = StyleSheet.create({ + gridContainer: { + padding: 16, + alignItems: "center", + }, + avatarWrapper: { + margin: 8, + }, + gridAvatar: { + width: 60, + height: 60, + borderRadius: 30, + backgroundColor: "#333", + }, + listContainer: { + paddingVertical: 8, + }, + rowContainer: { + flexDirection: "row", + alignItems: "center", + paddingVertical: 12, + paddingHorizontal: 16, + borderBottomWidth: 0.5, + borderBottomColor: "#333", + }, + listAvatar: { + width: 40, + height: 40, + borderRadius: 20, + backgroundColor: "#333", + marginRight: 16, + }, + username: { + flex: 1, + fontSize: 16, + fontWeight: "500", + color: "#fff", + }, + badge: { + backgroundColor: "#222", + paddingHorizontal: 8, + paddingVertical: 3, + borderRadius: 10, + }, + badgeText: { + fontSize: 12, + color: "#888", + }, +}); \ No newline at end of file diff --git a/components/flows/onboarding-steps.tsx b/components/flows/onboarding-steps.tsx index dd23461..9a23630 100644 --- a/components/flows/onboarding-steps.tsx +++ b/components/flows/onboarding-steps.tsx @@ -4,6 +4,7 @@ import { Colors } from "@/theme/colors"; import { Bird, ShieldCheck } from "lucide-react-native"; import { Logo } from "../logo"; import { LocalAuthStepContent } from "./local-auth-step"; +import { ContributorsList } from "@/components/ContributorsList"; export const onboardingSteps: OnboardingStep[] = [ { @@ -45,4 +46,14 @@ export const onboardingSteps: OnboardingStep[] = [ ), customContent: , }, + { + id: "4", + title: "Meet the Contributors", + description: + "Whisper is built by a community of privacy advocates and open-source enthusiasts.", + icon: null, + customContent: , + }, + + ]; diff --git a/manual-contributors.json b/manual-contributors.json new file mode 100644 index 0000000..1351dbc --- /dev/null +++ b/manual-contributors.json @@ -0,0 +1,9 @@ +[ + { + "id": "manual-1", + "login": "marketing-guru", + "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4", + "html_url": "https://github.com/marketing-guru", + "type": "Marketing" + } +] \ No newline at end of file diff --git a/package.json b/package.json index a076791..d239f26 100644 --- a/package.json +++ b/package.json @@ -5,6 +5,8 @@ "scripts": { "start": "expo start", "reset-project": "node ./scripts/reset-project.js", + "prestart": "node scripts/generate-contributors.js", + "generate-contributors": "node scripts/generate-contributors.js", "android": "expo run:android", "ios": "expo run:ios", "web": "expo start --web", diff --git a/scripts/generate-contributors.js b/scripts/generate-contributors.js new file mode 100644 index 0000000..983e9fb --- /dev/null +++ b/scripts/generate-contributors.js @@ -0,0 +1,57 @@ +// scripts/generate-contributors.js +const fs = require('fs'); +const path = require('path'); + +const GITHUB_API_URL = 'https://api.github.com/repos/Whisper-AI-App/app/contributors'; +const MANUAL_FILE_PATH = path.join(__dirname, '../manual-contributors.json'); +const OUTPUT_FILE_PATH = path.join(__dirname, '../assets/contributors.json'); + +async function generateContributors() { + try { + console.log('Fetching GitHub contributors...'); + + // 1. Fetch code contributors (Requires Node 18+ for native fetch) + const response = await fetch(GITHUB_API_URL, { + headers: { + 'User-Agent': 'Whisper-AI-App-Build-Script' + } + }); + + if (!response.ok) throw new Error(`GitHub API responded with ${response.status}`); + const codeContributors = await response.json(); + + // 2. Read manual contributors + let manualContributors = []; + if (fs.existsSync(MANUAL_FILE_PATH)) { + const manualData = fs.readFileSync(MANUAL_FILE_PATH, 'utf-8'); + manualContributors = JSON.parse(manualData); + } + + // 3. Merge and deduplicate (prioritizing manual entries if there's a login clash) + const allContributors = [...manualContributors, ...codeContributors]; + + const uniqueMap = new Map(); + allContributors.forEach(contributor => { + if (!uniqueMap.has(contributor.login)) { + uniqueMap.set(contributor.login, { + id: contributor.id, + login: contributor.login, + avatar_url: contributor.avatar_url, + html_url: contributor.html_url, + }); + } + }); + + const finalContributorsList = Array.from(uniqueMap.values()); + + // 4. Save to assets folder + fs.writeFileSync(OUTPUT_FILE_PATH, JSON.stringify(finalContributorsList, null, 2)); + console.log(`Successfully generated ${finalContributorsList.length} contributors to assets/contributors.json`); + + } catch (error) { + console.error('Failed to generate contributors:', error.message); + process.exit(1); + } +} + +generateContributors(); \ No newline at end of file From 4e7afbe1d04a195efe7322f57e327cf85c1f4e9a Mon Sep 17 00:00:00 2001 From: RONAK Date: Fri, 26 Jun 2026 16:34:39 +0530 Subject: [PATCH 2/5] fix: remove prestart script per reviewer request --- components/ContributorsList.tsx | 1 + package.json | 1 - 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/components/ContributorsList.tsx b/components/ContributorsList.tsx index 299b4db..fdc6b3b 100644 --- a/components/ContributorsList.tsx +++ b/components/ContributorsList.tsx @@ -15,6 +15,7 @@ interface ContributorsListProps { variant: "onboarding" | "settings"; } +export const ContributorsList: React.FC = ({ variant }) => { const openProfile = (url: string) => { if (url) { // biome-ignore lint/suspicious/noConsole: Needed for openURL catch logging diff --git a/package.json b/package.json index d239f26..a0bbb6b 100644 --- a/package.json +++ b/package.json @@ -5,7 +5,6 @@ "scripts": { "start": "expo start", "reset-project": "node ./scripts/reset-project.js", - "prestart": "node scripts/generate-contributors.js", "generate-contributors": "node scripts/generate-contributors.js", "android": "expo run:android", "ios": "expo run:ios", From 19eb6f4ac7d092f60eadb6305d536763ed961920 Mon Sep 17 00:00:00 2001 From: RONAK Date: Tue, 30 Jun 2026 21:22:03 +0530 Subject: [PATCH 3/5] feat: add contributor and padding etc --- components/ContributorsList.tsx | 1 + manual-contributors.json | 8 ++++++++ 2 files changed, 9 insertions(+) diff --git a/components/ContributorsList.tsx b/components/ContributorsList.tsx index fdc6b3b..ff7dbb8 100644 --- a/components/ContributorsList.tsx +++ b/components/ContributorsList.tsx @@ -68,6 +68,7 @@ export const ContributorsList: React.FC = ({ variant }) = const styles = StyleSheet.create({ gridContainer: { padding: 16, + marginTop: 40, alignItems: "center", }, avatarWrapper: { diff --git a/manual-contributors.json b/manual-contributors.json index 1351dbc..dd0864f 100644 --- a/manual-contributors.json +++ b/manual-contributors.json @@ -5,5 +5,13 @@ "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4", "html_url": "https://github.com/marketing-guru", "type": "Marketing" + }, + { + "id": "ronak-1", + "login": "RONAK-AI647", + "avatar_url": "https://github.com/RONAK-AI647.png", + "html_url": "https://github.com/RONAK-AI647", + "type": "Developer" } + ] \ No newline at end of file From 8bc8dd676a89e6e88ffcb3b27dc44150d94535f6 Mon Sep 17 00:00:00 2001 From: RONAK Date: Wed, 1 Jul 2026 03:28:00 +0530 Subject: [PATCH 4/5] feat: manual and code contributors' order --- assets/contributors.json | 20 ++++++++++++++------ manual-contributors.json | 2 +- scripts/generate-contributors.js | 17 +++++++++++++---- 3 files changed, 28 insertions(+), 11 deletions(-) diff --git a/assets/contributors.json b/assets/contributors.json index 2ac52a6..4de5e4d 100644 --- a/assets/contributors.json +++ b/assets/contributors.json @@ -1,10 +1,4 @@ [ - { - "id": "manual-1", - "login": "marketing-guru", - "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4", - "html_url": "https://github.com/marketing-guru" - }, { "id": 30320791, "login": "mrspence", @@ -22,5 +16,19 @@ "login": "dependabot[bot]", "avatar_url": "https://avatars.githubusercontent.com/in/29110?v=4", "html_url": "https://github.com/apps/dependabot" + }, + { + "id": "manual-1", + "login": "marketing-guru", + "avatar_url": "https://avatars.githubusercontent.com/u/583231?v=4", + "html_url": "https://github.com/marketing-guru", + "type": "Marketing" + }, + { + "id": "ronak-1", + "login": "RONAK-AI647", + "avatar_url": "https://avatars.githubusercontent.com/RONAK-AI647", + "html_url": "https://github.com/RONAK-AI647", + "type": "Developer" } ] \ No newline at end of file diff --git a/manual-contributors.json b/manual-contributors.json index dd0864f..ca343b2 100644 --- a/manual-contributors.json +++ b/manual-contributors.json @@ -9,7 +9,7 @@ { "id": "ronak-1", "login": "RONAK-AI647", - "avatar_url": "https://github.com/RONAK-AI647.png", + "avatar_url": "https://avatars.githubusercontent.com/RONAK-AI647", "html_url": "https://github.com/RONAK-AI647", "type": "Developer" } diff --git a/scripts/generate-contributors.js b/scripts/generate-contributors.js index 983e9fb..9ba9c34 100644 --- a/scripts/generate-contributors.js +++ b/scripts/generate-contributors.js @@ -27,17 +27,26 @@ async function generateContributors() { manualContributors = JSON.parse(manualData); } - // 3. Merge and deduplicate (prioritizing manual entries if there's a login clash) - const allContributors = [...manualContributors, ...codeContributors]; - + // 3. GitHub contributors first (by commit count), manual appended after const uniqueMap = new Map(); - allContributors.forEach(contributor => { + + codeContributors.forEach(contributor => { + uniqueMap.set(contributor.login, { + id: contributor.id, + login: contributor.login, + avatar_url: contributor.avatar_url, + html_url: contributor.html_url, + }); + }); + + manualContributors.forEach(contributor => { if (!uniqueMap.has(contributor.login)) { uniqueMap.set(contributor.login, { id: contributor.id, login: contributor.login, avatar_url: contributor.avatar_url, html_url: contributor.html_url, + type: contributor.type, }); } }); From 33cf9cf4b9afeed237f65b9756da2d9a8ce5e1ce Mon Sep 17 00:00:00 2001 From: RONAK Date: Wed, 1 Jul 2026 03:44:27 +0530 Subject: [PATCH 5/5] fix: lint check --- scripts/generate-contributors.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/generate-contributors.js b/scripts/generate-contributors.js index 9ba9c34..0c943b7 100644 --- a/scripts/generate-contributors.js +++ b/scripts/generate-contributors.js @@ -1,6 +1,6 @@ // scripts/generate-contributors.js -const fs = require('fs'); -const path = require('path'); +const fs = require('node:fs'); +const path = require('node:path'); const GITHUB_API_URL = 'https://api.github.com/repos/Whisper-AI-App/app/contributors'; const MANUAL_FILE_PATH = path.join(__dirname, '../manual-contributors.json');