From dcb58bcd2b4a4c853d3df974cb7101b2910c9110 Mon Sep 17 00:00:00 2001
From: ZorroGuardaPavos <4ndres.or@gmail.com>
Date: Thu, 1 May 2025 01:30:01 +0200
Subject: [PATCH] feat: add contributors page
---
README.md | 45 -----------
frontend/public/locales/en/translation.json | 7 +-
frontend/public/locales/es/translation.json | 7 +-
frontend/public/locales/nl/translation.json | 7 +-
frontend/src/assets/contributors.json | 50 ++++++++++++
frontend/src/components/commonUI/Footer.tsx | 65 ++++++++-------
frontend/src/routeTree.gen.ts | 27 +++++++
frontend/src/routes/_publicLayout/thanks.tsx | 84 ++++++++++++++++++++
8 files changed, 215 insertions(+), 77 deletions(-)
create mode 100644 frontend/src/assets/contributors.json
create mode 100644 frontend/src/routes/_publicLayout/thanks.tsx
diff --git a/README.md b/README.md
index e0733be..ff45ce8 100644
--- a/README.md
+++ b/README.md
@@ -31,51 +31,6 @@
Explore the API documentation at [http://127.0.0.1:8000/docs](http://127.0.0.1:8000/docs).
-## Frontend (`/frontend`)
-
-```plaintext
-frontend/
-├── public/ # Static assets and translations (i18n)
-├── src/
-│ ├── assets/ # Images, SVGs, and static media
-│ ├── client/ # Generated API client (OpenAPI)
-│ ├── components/ # Reusable UI components (cards, collections, stats, etc.)
-│ ├── db/ # IndexedDB (Dexie.js) setup for offline/guest mode
-│ ├── data/localDB/ # Local DB logic for guest/offline mode (CRUD, stats, etc.)
-│ ├── hooks/ # Custom React hooks (auth, data fetching, etc.)
-│ ├── repositories/ # Data access layer (API/local switch for cards, collections, stats)
-│ ├── routes/ # Application routes (pages, layouts)
-│ ├── services/ # Business logic for cards, collections, practice, stats
-│ ├── utils/ # Utility functions (auth, stats, etc.)
-│ └── main.tsx # App entry point
-├── package.json # Frontend dependencies and scripts
-├── pnpm-lock.yaml # Lockfile for reproducible installs
-├── tsconfig*.json # TypeScript configuration
-├── vite.config.ts # Vite build configuration
-└── index.html # Main HTML template
-```
-
-## Backend (`/backend`)
-
-```plaintext
-backend/
-├── src/
-│ ├── api/ # FastAPI route definitions
-│ ├── core/ # Core logic (auth, config, security)
-│ ├── db/ # Database models and access (SQLAlchemy)
-│ ├── schemas/ # Pydantic models (request/response)
-│ ├── services/ # Business logic (users, flashcards, etc.)
-│ └── main.py # FastAPI app entry point
-├── tests/ # Backend tests (pytest)
-├── pyproject.toml # Python dependencies and project config
-├── uv.lock # Poetry/uv lockfile for reproducible installs
-├── Dockerfile # Production Docker build
-├── Dockerfile.pip # Alternative Docker build (pip)
-├── entrypoint.sh # Docker entrypoint script
-├── prestart.sh # Pre-start script (migrations, etc.)
-└── alembic.ini # Alembic DB migration config
-```
-
## Setup Instructions
### Backend Setup
diff --git a/frontend/public/locales/en/translation.json b/frontend/public/locales/en/translation.json
index dd13088..48956a0 100644
--- a/frontend/public/locales/en/translation.json
+++ b/frontend/public/locales/en/translation.json
@@ -168,7 +168,7 @@
"publicLayout": {
"index": {
"title": "Learn Better with FlashNotes",
- "description": "A simple flashcard app that helps you learn. Create cards,practice regularly, and remember what matters.",
+ "description": "Capture your ideas, turn them into flashcards, and practice often so you can remember more!",
"offlineMode": "Offline Mode",
"offlineModeDescription": "Use FlashNotes anywhere, even without an internet connection. Guest mode and all your data work fully offline!",
"aiGeneration": "AI Generation",
@@ -181,6 +181,11 @@
},
"signUp": {
"alreadyHaveAccount": "Already have an account?"
+ },
+ "thanks": {
+ "title": "Thank You to All Contributors!",
+ "description": "This project would not be possible without the amazing work and support of our contributors.",
+ "link": "Thanks to all contributors"
}
}
}
diff --git a/frontend/public/locales/es/translation.json b/frontend/public/locales/es/translation.json
index 103ad7c..4aeb840 100644
--- a/frontend/public/locales/es/translation.json
+++ b/frontend/public/locales/es/translation.json
@@ -168,7 +168,7 @@
"publicLayout": {
"index": {
"title": "Aprende Mejor con FlashNotes",
- "description": "Una aplicación de tarjetas de memoria simple que te ayuda a aprender. Crea tarjetas, practica regularmente y recuerda lo que importa.",
+ "description": "Captura tus ideas, conviértelas en tarjetas de memoria y practica a menudo para recordar más!",
"offlineMode": "Modo sin conexión",
"offlineModeDescription": "Usa FlashNotes en cualquier lugar, incluso sin conexión a internet. ¡El modo invitado y todos tus datos funcionan completamente sin conexión!",
"aiGeneration": "Generación con IA",
@@ -181,6 +181,11 @@
},
"signUp": {
"alreadyHaveAccount": "¿Ya tienes una cuenta?"
+ },
+ "thanks": {
+ "title": "¡Gracias a todos los colaboradores!",
+ "description": "Este proyecto no sería posible sin el increíble trabajo y apoyo de nuestros colaboradores.",
+ "link": "Gracias a todos los colaboradores"
}
}
}
diff --git a/frontend/public/locales/nl/translation.json b/frontend/public/locales/nl/translation.json
index 1686022..f530d7a 100644
--- a/frontend/public/locales/nl/translation.json
+++ b/frontend/public/locales/nl/translation.json
@@ -168,7 +168,7 @@
"publicLayout": {
"index": {
"title": "Beter Leren met FlashNotes",
- "description": "Een eenvoudige flashcard-app die je helpt te leren. Maak kaarten, oefen regelmatig en onthoud wat belangrijk is.",
+ "description": "Leg je ideeën vast, maak er flashcards van en oefen vaak zodat je meer onthoudt!",
"offlineMode": "Offline Modus",
"offlineModeDescription": "Gebruik FlashNotes overal, zelfs zonder internetverbinding. Gastmodus en al je gegevens werken volledig offline!",
"aiGeneration": "AI Generatie",
@@ -181,6 +181,11 @@
},
"signUp": {
"alreadyHaveAccount": "Heb je al een account?"
+ },
+ "thanks": {
+ "title": "Dank aan alle bijdragers!",
+ "description": "Dit project zou niet mogelijk zijn zonder het geweldige werk en de steun van onze bijdragers.",
+ "link": "Dank aan alle bijdragers"
}
}
}
diff --git a/frontend/src/assets/contributors.json b/frontend/src/assets/contributors.json
new file mode 100644
index 0000000..4c91659
--- /dev/null
+++ b/frontend/src/assets/contributors.json
@@ -0,0 +1,50 @@
+[
+ {
+ "login": "jose-fernandez",
+ "name": "Jose Fernandez",
+ "avatar_url": "https://avatars.githubusercontent.com/u/22930011?v=4",
+ "profile": "https://github.com/jose-fernandez"
+ },
+ {
+ "login": "ryanli",
+ "name": "Ryan Li",
+ "avatar_url": "https://avatars.githubusercontent.com/u/148289?v=4",
+ "profile": "https://github.com/ryanli"
+ },
+ {
+ "login": "VictoriaTskhondia",
+ "name": "VictoriaTskhondia",
+ "avatar_url": "https://avatars.githubusercontent.com/u/48713882?v=4",
+ "profile": "https://github.com/VictoriaTskhondia"
+ },
+ {
+ "login": "sebampuero",
+ "name": "Sebastian",
+ "avatar_url": "https://avatars.githubusercontent.com/u/20564582?v=4",
+ "profile": "https://sebampuerom.de/"
+ },
+ {
+ "login": "mohsenkhosroanjam",
+ "name": "Mohsen Khosroanjam",
+ "avatar_url": "https://avatars.githubusercontent.com/u/60619215?v=4",
+ "profile": "https://github.com/mohsenkhosroanjam"
+ },
+ {
+ "login": "muhammedsirajudeen",
+ "name": "MuhammedSirajudeen ",
+ "avatar_url": "https://avatars.githubusercontent.com/u/43089951?v=4",
+ "profile": "https://github.com/muhammedsirajudeen"
+ },
+ {
+ "login": "sonegs",
+ "name": "Miguel Cobo",
+ "avatar_url": "https://avatars.githubusercontent.com/u/47485321?v=4",
+ "profile": "https://github.com/sonegs"
+ },
+ {
+ "login": "jcmc0011",
+ "name": "jcmc0011",
+ "avatar_url": "https://avatars.githubusercontent.com/u/11525905?v=4",
+ "profile": "https://github.com/jcmc0011"
+ }
+]
diff --git a/frontend/src/components/commonUI/Footer.tsx b/frontend/src/components/commonUI/Footer.tsx
index 022526e..8fd59ca 100644
--- a/frontend/src/components/commonUI/Footer.tsx
+++ b/frontend/src/components/commonUI/Footer.tsx
@@ -1,4 +1,5 @@
import { Stack, Text } from '@chakra-ui/react'
+import { Link } from '@tanstack/react-router'
import { useTranslation } from 'react-i18next'
import { ImGithub } from 'react-icons/im'
@@ -15,36 +16,42 @@ export function Footer({
}: FooterProps) {
const { t } = useTranslation()
return (
-
-
+
-
-
-
- {t('general.words.github')}
-
-
- •
-
- {t('general.words.version')} {version}
-
- •
-
- © {copyrightYear} {t('general.words.flashNotes')}
+
+
+
+ {t('general.words.github')}
+
+
+ •
+
+ {t('general.words.version')} {version}
+
+ •
+
+ © {copyrightYear} {t('general.words.flashNotes')}
+
+
+
+
+ {t('routes.publicLayout.thanks.link', 'Thanks to all contributors')}
+
-
+ >
)
}
diff --git a/frontend/src/routeTree.gen.ts b/frontend/src/routeTree.gen.ts
index 924cc33..812ea65 100644
--- a/frontend/src/routeTree.gen.ts
+++ b/frontend/src/routeTree.gen.ts
@@ -14,6 +14,7 @@ import { Route as rootRoute } from './routes/__root'
import { Route as PublicLayoutImport } from './routes/_publicLayout'
import { Route as LayoutImport } from './routes/_layout'
import { Route as PublicLayoutIndexImport } from './routes/_publicLayout/index'
+import { Route as PublicLayoutThanksImport } from './routes/_publicLayout/thanks'
import { Route as PublicLayoutSignupImport } from './routes/_publicLayout/signup'
import { Route as PublicLayoutLoginImport } from './routes/_publicLayout/login'
import { Route as LayoutCollectionsIndexImport } from './routes/_layout/collections/index'
@@ -41,6 +42,12 @@ const PublicLayoutIndexRoute = PublicLayoutIndexImport.update({
getParentRoute: () => PublicLayoutRoute,
} as any)
+const PublicLayoutThanksRoute = PublicLayoutThanksImport.update({
+ id: '/thanks',
+ path: '/thanks',
+ getParentRoute: () => PublicLayoutRoute,
+} as any)
+
const PublicLayoutSignupRoute = PublicLayoutSignupImport.update({
id: '/signup',
path: '/signup',
@@ -126,6 +133,13 @@ declare module '@tanstack/react-router' {
preLoaderRoute: typeof PublicLayoutSignupImport
parentRoute: typeof PublicLayoutImport
}
+ '/_publicLayout/thanks': {
+ id: '/_publicLayout/thanks'
+ path: '/thanks'
+ fullPath: '/thanks'
+ preLoaderRoute: typeof PublicLayoutThanksImport
+ parentRoute: typeof PublicLayoutImport
+ }
'/_publicLayout/': {
id: '/_publicLayout/'
path: '/'
@@ -209,12 +223,14 @@ const LayoutRouteWithChildren =
interface PublicLayoutRouteChildren {
PublicLayoutLoginRoute: typeof PublicLayoutLoginRoute
PublicLayoutSignupRoute: typeof PublicLayoutSignupRoute
+ PublicLayoutThanksRoute: typeof PublicLayoutThanksRoute
PublicLayoutIndexRoute: typeof PublicLayoutIndexRoute
}
const PublicLayoutRouteChildren: PublicLayoutRouteChildren = {
PublicLayoutLoginRoute: PublicLayoutLoginRoute,
PublicLayoutSignupRoute: PublicLayoutSignupRoute,
+ PublicLayoutThanksRoute: PublicLayoutThanksRoute,
PublicLayoutIndexRoute: PublicLayoutIndexRoute,
}
@@ -226,6 +242,7 @@ export interface FileRoutesByFullPath {
'': typeof PublicLayoutRouteWithChildren
'/login': typeof PublicLayoutLoginRoute
'/signup': typeof PublicLayoutSignupRoute
+ '/thanks': typeof PublicLayoutThanksRoute
'/': typeof PublicLayoutIndexRoute
'/collections': typeof LayoutCollectionsIndexRoute
'/collections/$collectionId/practice': typeof LayoutCollectionsCollectionIdPracticeRoute
@@ -239,6 +256,7 @@ export interface FileRoutesByTo {
'': typeof LayoutRouteWithChildren
'/login': typeof PublicLayoutLoginRoute
'/signup': typeof PublicLayoutSignupRoute
+ '/thanks': typeof PublicLayoutThanksRoute
'/': typeof PublicLayoutIndexRoute
'/collections': typeof LayoutCollectionsIndexRoute
'/collections/$collectionId/practice': typeof LayoutCollectionsCollectionIdPracticeRoute
@@ -254,6 +272,7 @@ export interface FileRoutesById {
'/_publicLayout': typeof PublicLayoutRouteWithChildren
'/_publicLayout/login': typeof PublicLayoutLoginRoute
'/_publicLayout/signup': typeof PublicLayoutSignupRoute
+ '/_publicLayout/thanks': typeof PublicLayoutThanksRoute
'/_publicLayout/': typeof PublicLayoutIndexRoute
'/_layout/collections/': typeof LayoutCollectionsIndexRoute
'/_layout/collections/$collectionId/practice': typeof LayoutCollectionsCollectionIdPracticeRoute
@@ -269,6 +288,7 @@ export interface FileRouteTypes {
| ''
| '/login'
| '/signup'
+ | '/thanks'
| '/'
| '/collections'
| '/collections/$collectionId/practice'
@@ -281,6 +301,7 @@ export interface FileRouteTypes {
| ''
| '/login'
| '/signup'
+ | '/thanks'
| '/'
| '/collections'
| '/collections/$collectionId/practice'
@@ -294,6 +315,7 @@ export interface FileRouteTypes {
| '/_publicLayout'
| '/_publicLayout/login'
| '/_publicLayout/signup'
+ | '/_publicLayout/thanks'
| '/_publicLayout/'
| '/_layout/collections/'
| '/_layout/collections/$collectionId/practice'
@@ -344,6 +366,7 @@ export const routeTree = rootRoute
"children": [
"/_publicLayout/login",
"/_publicLayout/signup",
+ "/_publicLayout/thanks",
"/_publicLayout/"
]
},
@@ -355,6 +378,10 @@ export const routeTree = rootRoute
"filePath": "_publicLayout/signup.tsx",
"parent": "/_publicLayout"
},
+ "/_publicLayout/thanks": {
+ "filePath": "_publicLayout/thanks.tsx",
+ "parent": "/_publicLayout"
+ },
"/_publicLayout/": {
"filePath": "_publicLayout/index.tsx",
"parent": "/_publicLayout"
diff --git a/frontend/src/routes/_publicLayout/thanks.tsx b/frontend/src/routes/_publicLayout/thanks.tsx
new file mode 100644
index 0000000..f977451
--- /dev/null
+++ b/frontend/src/routes/_publicLayout/thanks.tsx
@@ -0,0 +1,84 @@
+import Logo from '@/assets/Logo.svg'
+import contributorsData from '@/assets/contributors.json'
+import { Footer } from '@/components/commonUI/Footer'
+import {
+ Box,
+ Link as ChakraLink,
+ Container,
+ Heading,
+ Image,
+ SimpleGrid,
+ Text,
+ VStack,
+} from '@chakra-ui/react'
+import { Link as RouterLink, createFileRoute } from '@tanstack/react-router'
+import { useTranslation } from 'react-i18next'
+
+interface Contributor {
+ login: string
+ name: string
+ avatar_url: string
+ profile: string
+ contributions: string[]
+}
+
+const contributors: Contributor[] = contributorsData as Contributor[]
+
+export const Route = createFileRoute('/_publicLayout/thanks')({
+ component: ThanksPage,
+})
+
+function ContributorCard({ contributor }: { contributor: Contributor }) {
+ return (
+
+
+
+
+
+
+ {contributor.name}
+
+
+
+ )
+}
+
+function ThanksPage() {
+ const { t } = useTranslation()
+ return (
+
+
+
+
+
+
+
+
+ {t('routes.publicLayout.thanks.title')}
+
+
+ {t('routes.publicLayout.thanks.description')}
+
+
+ {contributors.map((contributor) => (
+
+ ))}
+
+
+
+
+ )
+}
+
+export default ThanksPage