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} + + + + {contributor.name} + + + + ) +} + +function ThanksPage() { + const { t } = useTranslation() + return ( + + + + FlashNotes Logo + + + + + {t('routes.publicLayout.thanks.title')} + + + {t('routes.publicLayout.thanks.description')} + + + {contributors.map((contributor) => ( + + ))} + + +