diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 00000000..1d9f8e51 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,245 @@ +# AGENTS.md + +Developer documentation for AI agents working on the Onward project. + +## Project Overview + +**Onward** is a professional development platform designed to empower teachers with flexible, personalized, and bite-sized learning resources. The platform delivers practical growth opportunities that fit seamlessly into busy teaching schedules. + +### Tech Stack + +- **Framework**: [SvelteKit](https://kit.svelte.dev/) (v2) with Svelte 5 +- **Language**: TypeScript +- **Styling**: Tailwind CSS v4 +- **Database**: PostgreSQL with [Prisma ORM](https://www.prisma.io/) +- **Caching**: Valkey (Redis-compatible) +- **Storage**: S3-compatible object storage (MinIO for local development) +- **Vector Database**: Weaviate for embeddings and semantic search +- **AI Integration**: OpenAI API +- **Authentication**: Google OAuth2 +- **Testing**: Vitest with Testing Library +- **Package Manager**: pnpm (workspace-based monorepo) + +### Project Structure + +``` +. +├── prisma/ # Database schema and migrations +├── src/ # SvelteKit application source code +├── patches/ # pnpm package patches +└── [config files] # Various configuration files for tools +``` + +## Build and Test Commands + +All commands should be run from the project root using `pnpm`: + +| Command | Description | +| :----------------- | :--------------------------------------------- | +| `pnpm install` | Install all project dependencies | +| `pnpm dev` | Start development server with hot reloading | +| `pnpm build` | Build the application for production | +| `pnpm preview` | Preview the production build locally | +| `pnpm test` | Run the test suite with Vitest | +| `pnpm check` | Run SvelteKit sync and svelte-check validation | +| `pnpm format` | Check code formatting with Prettier | +| `pnpm lint` | Lint code with ESLint | +| `pnpm db:generate` | Generate Prisma client from schema | +| `pnpm db:migrate` | Create and apply new database migrations | +| `pnpm db:deploy` | Apply pending database migrations (production) | +| `pnpm db:reset` | Reset database and reapply all migrations | +| `pnpm db:seed` | Seed the database with initial data | + +### Development Setup + +**Prerequisites:** + +- Node.js version 22 or 23 +- pnpm package manager +- Docker and Docker Compose (for local services) + +**Initial Setup:** + +1. Install dependencies: + + ```sh + pnpm install + ``` + +2. Start required local services (PostgreSQL, Valkey, MinIO, Weaviate): + + ```sh + docker compose up -d valkey postgres minio weaviate + ``` + +3. Configure MinIO: + - Access MinIO console at `http://localhost:9001` + - Create a bucket named `onward` + +4. Set up environment variables: + - Copy `.env.example` to `.env` + - Fill in the required values (database URLs, API keys, OAuth credentials) + +5. Run database migrations: + + ```sh + pnpm db:migrate + ``` + +6. Start the development server: + ```sh + pnpm dev + ``` + +## Code Style Guidelines + +### Formatting + +The project uses **Prettier** for consistent code formatting with the following configuration: + +- **Print Width**: 100 characters +- **Tab Width**: 2 spaces +- **Quotes**: Single quotes +- **Trailing Commas**: Always +- **Plugins**: prettier-plugin-svelte, prettier-plugin-tailwindcss + +### Linting + +The project uses **ESLint** with TypeScript and Svelte plugins. Key rules include: + +- **Import Sorting**: Imports must be sorted using `eslint-plugin-simple-import-sort` +- **Unused Variables**: Variables and args prefixed with `_` are ignored +- **Type Imports**: Use inline type imports (e.g., `import { type Foo } from '...'`) +- **TypeScript**: Follows recommended and stylistic TypeScript ESLint rules + +### Automated Checks + +The project uses **Husky** Git hooks to enforce code quality: + +- **Pre-commit**: Runs `lint-staged` which automatically formats and lints staged files +- **Pre-push**: Runs TypeScript type checking (`tsc`) and SvelteKit checks (`svelte-check`) + +### Manual Quality Checks + +Run these commands before committing if needed: + +```sh +# Format all code +pnpm format + +# Lint all code +pnpm lint + +# Run type checking +pnpm -r check +``` + +### Commit Messages + +Follow the [Conventional Commits](https://www.conventionalcommits.org/) specification: + +``` +feat: add user profile page +fix: correct typo in navigation +docs: update README with new setup steps +chore: update dependencies +``` + +## Testing Instructions + +### Test Framework + +The project uses **Vitest** with **Testing Library** for Svelte components. + +### Running Tests + +```sh +# Run all tests +pnpm test + +# Run tests in watch mode +pnpm test -- --watch + +# Run tests with coverage +pnpm test -- --coverage +``` + +### Test File Locations + +- Test files should be co-located with the source files they test +- Use the naming convention: `*.test.ts` or `*.spec.ts` + +### Writing Tests + +- Use Testing Library's Svelte utilities for component testing +- Follow the "Arrange-Act-Assert" pattern +- Write descriptive test names that explain the expected behavior +- Mock external dependencies (database, API calls) appropriately + +### Test Configuration + +- **Config File**: `vitest.config.ts` +- **Setup File**: `vitest.setup.ts` +- **Environment**: jsdom for DOM testing + +## Security Considerations + +### Environment Variables + +**CRITICAL**: Never commit sensitive credentials to version control. + +- Use `.env` for local development (git-ignored) +- Reference `.env.example` for required environment variables +- Production credentials should be managed through secure secrets management +- Required sensitive variables include: + - Database connection strings (`POSTGRES_URL`, `VALKEY_URL`) + - API keys (`OPENAI_API_KEY`, `WEAVIATE_API_KEY`) + - OAuth credentials (`GOOGLE_CLIENT_ID`, `GOOGLE_CLIENT_SECRET`) + - S3 storage credentials (`S3_ACCESS_KEY`, `S3_SECRET_KEY`) + +### Authentication + +- The application uses **Google OAuth2** for authentication +- Configure `GOOGLE_HOSTED_DOMAIN` to restrict access to specific domains if needed +- OAuth tokens and sessions should be handled securely + +### Data Storage + +- **Database**: PostgreSQL with Prisma ORM for type-safe queries +- **Caching**: Valkey for session and cache storage +- **File Storage**: S3-compatible storage for user uploads +- **Vector Data**: Weaviate for embeddings and semantic search + +### Dependencies + +- Keep dependencies up to date to patch security vulnerabilities +- Use `pnpm audit` to check for known vulnerabilities +- Review package patches in the `patches/` directory + +### Input Validation + +- All user inputs should be validated and sanitized +- Use Prisma's parameterized queries to prevent SQL injection +- Implement proper CORS policies +- Use Content Security Policy (CSP) headers + +### Docker Security + +- Local development uses Docker Compose for services +- Ensure Docker images are from trusted sources +- Keep Docker and Docker Compose updated +- Use strong credentials even in local development to maintain good practices + +### Best Practices + +- Follow principle of least privilege for database access +- Implement rate limiting for API endpoints +- Use HTTPS in production environments +- Regularly rotate API keys and credentials +- Sanitize data before rendering (prevent XSS attacks) +- Implement proper error handling without leaking sensitive information +- Use DOMPurify for sanitizing HTML content (already included as dependency) + +--- + +**Note for AI Agents**: When making changes to this project, always ensure code quality checks pass, tests are updated accordingly, and security best practices are followed. Refer to [CONTRIBUTING.md](./CONTRIBUTING.md) for detailed contribution guidelines. diff --git a/components.json b/components.json new file mode 100644 index 00000000..ccecb20a --- /dev/null +++ b/components.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://shadcn-svelte.com/schema.json", + "style": "new-york", + "tailwind": { + "config": "", + "css": "src/app.css", + "baseColor": "slate" + }, + "aliases": { + "components": "$lib/components", + "utils": "$lib/utils", + "ui": "$lib/components/ui", + "lib": "$lib", + "hooks": "$lib/hooks" + }, + "typescript": true +} diff --git a/package.json b/package.json index f8abe4c2..d5aad86f 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,8 @@ }, "devDependencies": { "@eslint/js": "^9.33.0", - "@lucide/svelte": "^0.511.0", + "@internationalized/date": "^3.10.1", + "@lucide/svelte": "^0.561.0", "@sveltejs/adapter-node": "^5.2.12", "@sveltejs/enhanced-img": "^0.8.1", "@sveltejs/kit": "^2.27.3", @@ -38,6 +39,8 @@ "@testing-library/jest-dom": "^6.9.1", "@testing-library/svelte": "^5.2.9", "@types/node": "^24.10.1", + "bits-ui": "^2.14.4", + "clsx": "^2.1.1", "date-fns": "^4.1.0", "dompurify": "^3.2.7", "dotenv": "^17.2.2", @@ -59,6 +62,8 @@ "prisma": "^7.0.1", "svelte": "^5.38.0", "svelte-check": "^4.3.0", + "tailwind-merge": "^3.4.0", + "tailwind-variants": "^3.2.2", "tailwindcss": "^4.1.11", "tsx": "^4.20.5", "typescript": "^5.9.2", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 0d9bc956..a783c315 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -35,9 +35,12 @@ importers: '@eslint/js': specifier: ^9.33.0 version: 9.33.0 + '@internationalized/date': + specifier: ^3.10.1 + version: 3.10.1 '@lucide/svelte': - specifier: ^0.511.0 - version: 0.511.0(svelte@5.38.0) + specifier: ^0.561.0 + version: 0.561.0(svelte@5.38.0) '@sveltejs/adapter-node': specifier: ^5.2.12 version: 5.2.12(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0))) @@ -65,6 +68,12 @@ importers: '@types/node': specifier: ^24.10.1 version: 24.10.1 + bits-ui: + specifier: ^2.14.4 + version: 2.14.4(@internationalized/date@3.10.1)(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0) + clsx: + specifier: ^2.1.1 + version: 2.1.1 date-fns: specifier: ^4.1.0 version: 4.1.0 @@ -128,6 +137,12 @@ importers: svelte-check: specifier: ^4.3.0 version: 4.3.0(picomatch@4.0.3)(svelte@5.38.0)(typescript@5.9.2) + tailwind-merge: + specifier: ^3.4.0 + version: 3.4.0 + tailwind-variants: + specifier: ^3.2.2 + version: 3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.11) tailwindcss: specifier: ^4.1.11 version: 4.1.11 @@ -747,6 +762,15 @@ packages: resolution: {integrity: sha512-Z5kJ+wU3oA7MMIqVR9tyZRtjYPr4OC004Q4Rw7pgOKUOKkJfZ3O24nz3WYfGRpMDNmcOi3TwQOmgm7B7Tpii0w==} engines: {node: ^18.18.0 || ^20.9.0 || >=21.1.0} + '@floating-ui/core@1.7.3': + resolution: {integrity: sha512-sGnvb5dmrJaKEZ+LDIpguvdX3bDlEllmv4/ClQ9awcmCZrlx5jQyyMWFM5kBI+EyNOCDDiKk8il0zeuX3Zlg/w==} + + '@floating-ui/dom@1.7.4': + resolution: {integrity: sha512-OOchDgh4F2CchOX94cRVqhvy7b3AFb+/rQXyswmzmGakRfkMgoWVjfnLWkRirfLEfuD4ysVW16eXzwt3jHIzKA==} + + '@floating-ui/utils@0.2.10': + resolution: {integrity: sha512-aGTxbpbg8/b5JfU1HXSrbH3wXZuLPJcNEcZQFMxLs3oSzgtVu6nFPkbbGGUvBcUjKV2YyB9Wxxabo+HEH9tcRQ==} + '@graphql-typed-document-node/core@3.2.0': resolution: {integrity: sha512-mB9oAsNCm9aM3/SOv4YtBMqZbYj10R7dkq8byBqxGY/ncFwhf2oQzMV+LCRlWoDSEBJ3COiR1yeDvMtsoOsuFQ==} peerDependencies: @@ -909,6 +933,9 @@ packages: cpu: [x64] os: [win32] + '@internationalized/date@3.10.1': + resolution: {integrity: sha512-oJrXtQiAXLvT9clCf1K4kxp3eKsQhIaZqxEyowkBcsvZDdZkbWrVmnGknxs5flTD0VGsxrxKgBCZty1EzoiMzA==} + '@isaacs/fs-minipass@4.0.1': resolution: {integrity: sha512-wgm9Ehl2jpeqP3zw/7mo3kRHFp5MEDhqAdwy1fTGkHAwnkGOVsgpvQhL8B5n1qlb01jV3n/bI0ZfZp5lWA1k4w==} engines: {node: '>=18.0.0'} @@ -932,8 +959,8 @@ packages: '@js-sdsl/ordered-map@4.4.2': resolution: {integrity: sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==} - '@lucide/svelte@0.511.0': - resolution: {integrity: sha512-aLCSPMUJmHlCuLXzXENXa4Z1NV2mN1iAZAFKk4bEbey+/MdsNlu+/DqwVkgW3Yvj6p8y8Vn5xZ2v9CLmPlA6Vw==} + '@lucide/svelte@0.561.0': + resolution: {integrity: sha512-vofKV2UFVrKE6I4ewKJ3dfCXSV6iP6nWVmiM83MLjsU91EeJcEg7LoWUABLp/aOTxj1HQNbJD1f3g3L0JQgH9A==} peerDependencies: svelte: ^5 @@ -1546,6 +1573,9 @@ packages: svelte: ^5.0.0 vite: ^6.3.0 || ^7.0.0 + '@swc/helpers@0.5.18': + resolution: {integrity: sha512-TXTnIcNJQEKwThMMqBXsZ4VGAza6bvN4pa41Rkqoio6QBKMvo+5lexeTMScGCIxtzgQJzElcvIltani+adC5PQ==} + '@tailwindcss/node@4.1.11': resolution: {integrity: sha512-yzhzuGRmv5QyU9qLNg4GTlYI6STedBWRE7NjxP45CsFYYq9taI0zJXZBMqIC/c8fViNLhmrbpSFS57EoxUmD6Q==} @@ -1899,6 +1929,13 @@ packages: bignumber.js@9.3.1: resolution: {integrity: sha512-Ko0uX15oIUS7wJ3Rb30Fs6SkVbLmPBAKdlm7q9+ak9bbIeFf0MwuBsQV6z7+X768/cHsfg+WlysDWJcmthjsjQ==} + bits-ui@2.14.4: + resolution: {integrity: sha512-W6kenhnbd/YVvur+DKkaVJ6GldE53eLewur5AhUCqslYQ0vjZr8eWlOfwZnMiPB+PF5HMVqf61vXBvmyrAmPWg==} + engines: {node: '>=20'} + peerDependencies: + '@internationalized/date': ^3.8.1 + svelte: ^5.33.0 + bowser@2.12.1: resolution: {integrity: sha512-z4rE2Gxh7tvshQ4hluIT7XcFrgLIQaw9X3A+kTTRdovCz5PMukm/0QC/BKSYPj3omF5Qfypn9O/c5kgpmvYUCw==} @@ -2491,6 +2528,9 @@ packages: resolution: {integrity: sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==} engines: {node: '>=8'} + inline-style-parser@0.2.7: + resolution: {integrity: sha512-Nb2ctOyNR8DqQoR0OwRG95uNWIC0C1lCgf5Naz5H6Ji72KZ8OcFZLz2P5sNgwlyoJ8Yif11oMuYs5pBQa86csA==} + is-arrayish@0.3.2: resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==} @@ -3230,6 +3270,15 @@ packages: run-parallel@1.2.0: resolution: {integrity: sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==} + runed@0.35.1: + resolution: {integrity: sha512-2F4Q/FZzbeJTFdIS/PuOoPRSm92sA2LhzTnv6FXhCoENb3huf5+fDuNOg1LNvGOouy3u/225qxmuJvcV3IZK5Q==} + peerDependencies: + '@sveltejs/kit': ^2.21.0 + svelte: ^5.7.0 + peerDependenciesMeta: + '@sveltejs/kit': + optional: true + sade@1.8.1: resolution: {integrity: sha512-xal3CZX1Xlo/k4ApwCFrHVACi9fBqJ7V+mwhBsuf/1IOKbBy098Fex+Wa/5QMubw09pSZ/u8EY8PWgevJsXp1A==} engines: {node: '>=6'} @@ -3361,6 +3410,9 @@ packages: strnum@2.1.1: resolution: {integrity: sha512-7ZvoFTiCnGxBtDqJ//Cu6fWtZtc7Y3x+QOirG15wztbdngGSkht27o2pyGWrVy0b4WAy3jbKmnoK6g5VlVNUUw==} + style-to-object@1.0.14: + resolution: {integrity: sha512-LIN7rULI0jBscWQYaSswptyderlarFkjQ+t79nzty8tcIAceVomEVlLzH5VP4Cmsv6MtKhs7qaAiwlcp+Mgaxw==} + supports-color@7.2.0: resolution: {integrity: sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==} engines: {node: '>=8'} @@ -3391,6 +3443,12 @@ packages: peerDependencies: svelte: ^3.0.0 || ^4.0.0 || ^5.0.0-next.1 + svelte-toolbelt@0.10.6: + resolution: {integrity: sha512-YWuX+RE+CnWYx09yseAe4ZVMM7e7GRFZM6OYWpBKOb++s+SQ8RBIMMe+Bs/CznBMc0QPLjr+vDBxTAkozXsFXQ==} + engines: {node: '>=18', pnpm: '>=8.7.0'} + peerDependencies: + svelte: ^5.30.2 + svelte@5.38.0: resolution: {integrity: sha512-cWF1Oc2IM/QbktdK89u5lt9MdKxRtQnRKnf2tq6KOhYuhLOd2hbMuTiJ+vWMzAeMDe81AzbCgLd4GVtOJ4fDRg==} engines: {node: '>=18'} @@ -3398,6 +3456,22 @@ packages: symbol-tree@3.2.4: resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==} + tabbable@6.3.0: + resolution: {integrity: sha512-EIHvdY5bPLuWForiR/AN2Bxngzpuwn1is4asboytXtpTgsArc+WmSJKVLlhdh71u7jFcryDqB2A8lQvj78MkyQ==} + + tailwind-merge@3.4.0: + resolution: {integrity: sha512-uSaO4gnW+b3Y2aWoWfFpX62vn2sR3skfhbjsEnaBI81WD1wBLlHZe5sWf0AqjksNdYTbGBEd0UasQMT3SNV15g==} + + tailwind-variants@3.2.2: + resolution: {integrity: sha512-Mi4kHeMTLvKlM98XPnK+7HoBPmf4gygdFmqQPaDivc3DpYS6aIY6KiG/PgThrGvii5YZJqRsPz0aPyhoFzmZgg==} + engines: {node: '>=16.x', pnpm: '>=7.x'} + peerDependencies: + tailwind-merge: '>=3.0.0' + tailwindcss: '*' + peerDependenciesMeta: + tailwind-merge: + optional: true + tailwindcss@4.1.11: resolution: {integrity: sha512-2E9TBm6MDD/xKYe+dvJZAmg3yxIEDNRc0jwlNyDg/4Fil2QcSLjFKGVff0lAf1jjeaArlG/M75Ey/EYr/OJtBA==} @@ -4530,6 +4604,17 @@ snapshots: '@eslint/core': 0.15.2 levn: 0.4.1 + '@floating-ui/core@1.7.3': + dependencies: + '@floating-ui/utils': 0.2.10 + + '@floating-ui/dom@1.7.4': + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/utils': 0.2.10 + + '@floating-ui/utils@0.2.10': {} + '@graphql-typed-document-node/core@3.2.0(graphql@16.11.0)': dependencies: graphql: 16.11.0 @@ -4649,6 +4734,10 @@ snapshots: '@img/sharp-win32-x64@0.34.3': optional: true + '@internationalized/date@3.10.1': + dependencies: + '@swc/helpers': 0.5.18 + '@isaacs/fs-minipass@4.0.1': dependencies: minipass: 7.1.2 @@ -4671,7 +4760,7 @@ snapshots: '@js-sdsl/ordered-map@4.4.2': {} - '@lucide/svelte@0.511.0(svelte@5.38.0)': + '@lucide/svelte@0.561.0(svelte@5.38.0)': dependencies: svelte: 5.38.0 @@ -5369,6 +5458,10 @@ snapshots: transitivePeerDependencies: - supports-color + '@swc/helpers@0.5.18': + dependencies: + tslib: 2.8.1 + '@tailwindcss/node@4.1.11': dependencies: '@ampproject/remapping': 2.3.0 @@ -5726,6 +5819,19 @@ snapshots: bignumber.js@9.3.1: {} + bits-ui@2.14.4(@internationalized/date@3.10.1)(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0): + dependencies: + '@floating-ui/core': 1.7.3 + '@floating-ui/dom': 1.7.4 + '@internationalized/date': 3.10.1 + esm-env: 1.2.2 + runed: 0.35.1(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0) + svelte: 5.38.0 + svelte-toolbelt: 0.10.6(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0) + tabbable: 6.3.0 + transitivePeerDependencies: + - '@sveltejs/kit' + bowser@2.12.1: {} brace-expansion@1.1.12: @@ -6352,6 +6458,8 @@ snapshots: indent-string@4.0.0: {} + inline-style-parser@0.2.7: {} + is-arrayish@0.3.2: {} is-core-module@2.16.1: @@ -7043,6 +7151,15 @@ snapshots: dependencies: queue-microtask: 1.2.3 + runed@0.35.1(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0): + dependencies: + dequal: 2.0.3 + esm-env: 1.2.2 + lz-string: 1.5.0 + svelte: 5.38.0 + optionalDependencies: + '@sveltejs/kit': 2.27.3(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)) + sade@1.8.1: dependencies: mri: 1.2.0 @@ -7176,6 +7293,10 @@ snapshots: strnum@2.1.1: {} + style-to-object@1.0.14: + dependencies: + inline-style-parser: 0.2.7 + supports-color@7.2.0: dependencies: has-flag: 4.0.0 @@ -7209,6 +7330,15 @@ snapshots: dependencies: svelte: 5.38.0 + svelte-toolbelt@0.10.6(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0): + dependencies: + clsx: 2.1.1 + runed: 0.35.1(@sveltejs/kit@2.27.3(@sveltejs/vite-plugin-svelte@6.2.1(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0)(vite@7.1.12(@types/node@24.10.1)(jiti@2.5.1)(lightningcss@1.30.1)(tsx@4.20.5)(yaml@2.8.0)))(svelte@5.38.0) + style-to-object: 1.0.14 + svelte: 5.38.0 + transitivePeerDependencies: + - '@sveltejs/kit' + svelte@5.38.0: dependencies: '@ampproject/remapping': 2.3.0 @@ -7228,6 +7358,16 @@ snapshots: symbol-tree@3.2.4: {} + tabbable@6.3.0: {} + + tailwind-merge@3.4.0: {} + + tailwind-variants@3.2.2(tailwind-merge@3.4.0)(tailwindcss@4.1.11): + dependencies: + tailwindcss: 4.1.11 + optionalDependencies: + tailwind-merge: 3.4.0 + tailwindcss@4.1.11: {} tapable@2.2.2: {} diff --git a/src/app.css b/src/app.css index 1b745eff..efc507cc 100644 --- a/src/app.css +++ b/src/app.css @@ -10,9 +10,80 @@ } } +/* Shadcn theme variables */ +@layer base { + :root { + --background: 0 0% 100%; + --foreground: 222.2 84% 4.9%; + --card: 0 0% 100%; + --card-foreground: 222.2 84% 4.9%; + --popover: 0 0% 100%; + --popover-foreground: 222.2 84% 4.9%; + --primary: 222.2 47.4% 11.2%; + --primary-foreground: 210 40% 98%; + --secondary: 210 40% 96.1%; + --secondary-foreground: 222.2 47.4% 11.2%; + --muted: 210 40% 96.1%; + --muted-foreground: 215.4 16.3% 46.9%; + --accent: 210 40% 96.1%; + --accent-foreground: 222.2 47.4% 11.2%; + --destructive: 0 84.2% 60.2%; + --destructive-foreground: 210 40% 98%; + --border: 214.3 31.8% 91.4%; + --input: 214.3 31.8% 91.4%; + --ring: 222.2 84% 4.9%; + --radius: 0.5rem; + --chart-1: 12 76% 61%; + --chart-2: 173 58% 39%; + --chart-3: 197 37% 24%; + --chart-4: 43 74% 66%; + --chart-5: 27 87% 67%; + } +} + +@layer base { + * { + @apply border-border; + } + body { + @apply bg-background text-foreground; + } +} + @theme { --font-geist: 'Geist', sans-serif; --font-logo: 'Inria Sans', sans-serif; + + --color-border: hsl(var(--border)); + --color-input: hsl(var(--input)); + --color-ring: hsl(var(--ring)); + --color-background: hsl(var(--background)); + --color-foreground: hsl(var(--foreground)); + + --color-primary: hsl(var(--primary)); + --color-primary-foreground: hsl(var(--primary-foreground)); + + --color-secondary: hsl(var(--secondary)); + --color-secondary-foreground: hsl(var(--secondary-foreground)); + + --color-destructive: hsl(var(--destructive)); + --color-destructive-foreground: hsl(var(--destructive-foreground)); + + --color-muted: hsl(var(--muted)); + --color-muted-foreground: hsl(var(--muted-foreground)); + + --color-accent: hsl(var(--accent)); + --color-accent-foreground: hsl(var(--accent-foreground)); + + --color-popover: hsl(var(--popover)); + --color-popover-foreground: hsl(var(--popover-foreground)); + + --color-card: hsl(var(--card)); + --color-card-foreground: hsl(var(--card-foreground)); + + --radius-lg: var(--radius); + --radius-md: calc(var(--radius) - 2px); + --radius-sm: calc(var(--radius) - 4px); } @utility prose-slate { diff --git a/src/lib/components/Badge/Badge.svelte b/src/lib/components/Badge/Badge.svelte deleted file mode 100644 index 16639ab9..00000000 --- a/src/lib/components/Badge/Badge.svelte +++ /dev/null @@ -1,55 +0,0 @@ - - -