diff --git a/.cursor/rules/instructions.mdc b/.cursor/rules/instructions.mdc deleted file mode 100644 index 1df5f17..0000000 --- a/.cursor/rules/instructions.mdc +++ /dev/null @@ -1,22 +0,0 @@ ---- -description: -globs: -alwaysApply: true ---- -# Description - -This a fullstack nextjs project, all written in mordern and state of the art typescript. -The Project follows the latest coding standards for next js projects - -# Modules - -This Project will use as less modules and node packages as possible. This leads to the following rules: -- No Tailwind -- No SCSS / SASS - -# Code Style - -This project follows clean code rules: -- SOLID Principles -- No else statements -- readable name \ No newline at end of file diff --git a/.cursor/rules/project.mdc b/.cursor/rules/project.mdc deleted file mode 100644 index b356ec6..0000000 --- a/.cursor/rules/project.mdc +++ /dev/null @@ -1,14 +0,0 @@ ---- -description: -globs: -alwaysApply: true ---- -# EWIKI - -The EWIKI is a eletric vehicle database, that allows the user to search and compare any information about eletric vehicles. - -# Structure - -## Start page - -The start page looks like a modern web search engine. There are no fancy input and filter options, just a regular search bar \ No newline at end of file diff --git a/.gitignore b/.gitignore index 5ef6a52..cb38ff4 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,13 @@ yarn-error.log* # typescript *.tsbuildinfo next-env.d.ts + +###> symfony/framework-bundle ### +/.env.local +/.env.local.php +/.env.*.local +/config/secrets/prod/prod.decrypt.private.php +/public/bundles/ +/var/ +/vendor/ +###< symfony/framework-bundle ### diff --git a/Dockerfile.dev b/Dockerfile.dev index 388e53a..8558cbf 100644 --- a/Dockerfile.dev +++ b/Dockerfile.dev @@ -1,12 +1,37 @@ -FROM node:18-alpine +FROM php:8.4-fpm-alpine WORKDIR /app -# Copy package files -COPY package.json package-lock.json ./ +# Install system dependencies including zsh +RUN apk add --no-cache \ + git \ + curl \ + libpng-dev \ + libxml2-dev \ + zip \ + unzip \ + openssl-dev \ + autoconf \ + g++ \ + make \ + zsh \ + wget -# Install dependencies -RUN npm install +# Install PHP extensions +RUN docker-php-ext-install pdo pdo_mysql + +# Install MongoDB PHP extension +RUN pecl install mongodb \ + && docker-php-ext-enable mongodb + +# Install Composer +COPY --from=composer:latest /usr/bin/composer /usr/bin/composer + +# Install Oh My Zsh +RUN sh -c "$(wget -O- https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)" "" --unattended + +# Set zsh as default shell +RUN chsh -s $(which zsh) # CMD will be executed when container starts -CMD ["npm", "run", "dev"] \ No newline at end of file +CMD ["php", "-S", "0.0.0.0:3000", "-t", "public"] \ No newline at end of file diff --git a/README.md b/README.md index e215bc4..1835e7f 100644 --- a/README.md +++ b/README.md @@ -1,36 +1,170 @@ -This is a [Next.js](https://nextjs.org) project bootstrapped with [`create-next-app`](https://nextjs.org/docs/app/api-reference/cli/create-next-app). +# E-WIKI - Electric Vehicle Database -## Getting Started +A modern Symfony application for browsing and searching electric vehicle information. This application provides a clean, search-engine-like interface for exploring electric vehicle brands, models, and specifications. -First, run the development server: +## Features -```bash -npm run dev -# or -yarn dev -# or -pnpm dev -# or -bun dev +- **Modern Search Interface**: Google-like search experience for electric vehicles +- **Brand Directory**: Browse popular electric vehicle manufacturers +- **Vehicle Database**: Comprehensive information about electric car models and revisions +- **RESTful API**: JSON API endpoints for integration +- **MongoDB Integration**: NoSQL database for flexible data storage +- **Responsive Design**: Mobile-friendly interface without external CSS frameworks + +## Technology Stack + +- **Backend**: Symfony 7.2 (PHP 8.2+) +- **Database**: MongoDB with Doctrine ODM +- **Frontend**: Vanilla JavaScript with modern CSS +- **Architecture**: Clean Architecture with SOLID principles + +## Requirements + +- PHP 8.2 or higher +- MongoDB 4.4 or higher +- Composer +- MongoDB PHP Extension + +## Installation + +1. **Clone the repository** + ```bash + git clone + cd evwiki + ``` + +2. **Install dependencies** + ```bash + composer install + ``` + +3. **Configure environment** + ```bash + cp .env.local.example .env.local + ``` + + Edit `.env.local` and set your MongoDB connection: + ``` + APP_ENV=dev + APP_SECRET=your-secret-key-here + MONGODB_URI=mongodb://localhost:27017 + ``` + +4. **Start MongoDB** + Make sure MongoDB is running on your system. + +5. **Seed the database** + ```bash + php bin/console app:seed-data + ``` + +6. **Start the development server** + ```bash + symfony server:start + ``` + + Or use PHP's built-in server: + ```bash + php -S localhost:8000 -t public/ + ``` + +## Project Structure + +``` +src/ +├── Command/ # Console commands +├── Controller/ # HTTP controllers +├── Document/ # MongoDB document models +├── Repository/ # Data access layer +├── Service/ # Business logic layer +└── Kernel.php # Application kernel + +templates/ +├── base.html.twig # Base template +└── home/ # Home page templates + +config/ +├── bundles.php # Bundle configuration +├── packages/ # Package configurations +├── routes.yaml # Route definitions +└── services.yaml # Service container ``` -Open [http://localhost:3000](http://localhost:3000) with your browser to see the result. +## API Endpoints -You can start editing the page by modifying `app/page.tsx`. The page auto-updates as you edit the file. +### Search +- `GET /api/search?query={term}` - Search for vehicles, brands, or models -This project uses [`next/font`](https://nextjs.org/docs/app/building-your-application/optimizing/fonts) to automatically optimize and load [Geist](https://vercel.com/font), a new font family for Vercel. +### Brands +- `GET /api/brands` - Get all brands +- `GET /api/brands/{brandId}/models` - Get models for a specific brand -## Learn More +### Models +- `GET /api/models/category/{category}` - Get models by category -To learn more about Next.js, take a look at the following resources: +## Architecture -- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API. -- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial. +This application follows clean architecture principles: -You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js) - your feedback and contributions are welcome! +### Domain Layer +- **Documents**: MongoDB document models (`Brand`, `CarModel`, `CarRevision`) +- **Repositories**: Data access interfaces -## Deploy on Vercel +### Application Layer +- **Services**: Business logic (`CarSearchService`) +- **Commands**: Console commands for data management -The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js. +### Infrastructure Layer +- **Controllers**: HTTP request handlers +- **Templates**: Twig templates for rendering -Check out our [Next.js deployment documentation](https://nextjs.org/docs/app/building-your-application/deploying) for more details. +### Key Design Principles + +1. **SOLID Principles**: Each class has a single responsibility +2. **Dependency Injection**: All dependencies are injected via constructor +3. **No Else Statements**: Code uses early returns for better readability +4. **Readable Names**: Self-documenting code with descriptive names + +## Development + +### Adding New Data + +Use the seed command to populate the database: +```bash +php bin/console app:seed-data +``` + +### Console Commands + +List all available commands: +```bash +php bin/console list +``` + +### Database Operations + +The application uses MongoDB with Doctrine ODM. All database operations are handled through repositories following the Repository pattern. + +## Styling Guidelines + +- **No External CSS Frameworks**: Pure CSS following modern standards +- **Responsive Design**: Mobile-first approach +- **Modern UI**: Clean, minimalist design inspired by search engines +- **Accessibility**: Semantic HTML and proper contrast ratios + +## Contributing + +1. Follow PSR-12 coding standards +2. Write clean, self-documenting code +3. Use dependency injection +4. Follow SOLID principles +5. Avoid else statements +6. Use meaningful variable and method names + +## License + +This project is licensed under the MIT License. + +## Support + +For support and questions, please open an issue in the repository. diff --git a/bin/console b/bin/console new file mode 100755 index 0000000..c437288 --- /dev/null +++ b/bin/console @@ -0,0 +1,21 @@ +#!/usr/bin/env php +=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Cache\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for caching libraries", + "keywords": [ + "cache", + "psr", + "psr-6" + ], + "support": { + "source": "https://github.com/php-fig/cache/tree/3.0.0" + }, + "time": "2021-02-03T23:26:27+00:00" + }, + { + "name": "psr/container", + "version": "2.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/container.git", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/container/zipball/c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "reference": "c71ecc56dfe541dbd90c5360474fbc405f8d5963", + "shasum": "" + }, + "require": { + "php": ">=7.4.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "2.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Container\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common Container Interface (PHP FIG PSR-11)", + "homepage": "https://github.com/php-fig/container", + "keywords": [ + "PSR-11", + "container", + "container-interface", + "container-interop", + "psr" + ], + "support": { + "issues": "https://github.com/php-fig/container/issues", + "source": "https://github.com/php-fig/container/tree/2.0.2" + }, + "time": "2021-11-05T16:47:00+00:00" + }, + { + "name": "psr/event-dispatcher", + "version": "1.0.0", + "source": { + "type": "git", + "url": "https://github.com/php-fig/event-dispatcher.git", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/event-dispatcher/zipball/dbefd12671e8a14ec7f180cab83036ed26714bb0", + "reference": "dbefd12671e8a14ec7f180cab83036ed26714bb0", + "shasum": "" + }, + "require": { + "php": ">=7.2.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\EventDispatcher\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "http://www.php-fig.org/" + } + ], + "description": "Standard interfaces for event handling.", + "keywords": [ + "events", + "psr", + "psr-14" + ], + "support": { + "issues": "https://github.com/php-fig/event-dispatcher/issues", + "source": "https://github.com/php-fig/event-dispatcher/tree/1.0.0" + }, + "time": "2019-01-08T18:20:26+00:00" + }, + { + "name": "psr/log", + "version": "3.0.2", + "source": { + "type": "git", + "url": "https://github.com/php-fig/log.git", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/php-fig/log/zipball/f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "reference": "f16e1d5863e37f8d8c2a01719f5b34baa2b714d3", + "shasum": "" + }, + "require": { + "php": ">=8.0.0" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Psr\\Log\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "PHP-FIG", + "homepage": "https://www.php-fig.org/" + } + ], + "description": "Common interface for logging libraries", + "homepage": "https://github.com/php-fig/log", + "keywords": [ + "log", + "psr", + "psr-3" + ], + "support": { + "source": "https://github.com/php-fig/log/tree/3.0.2" + }, + "time": "2024-09-11T13:17:53+00:00" + }, + { + "name": "symfony/cache", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache.git", + "reference": "8b49dde3f5a5e9867595a3a269977f78418d75ee" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache/zipball/8b49dde3f5a5e9867595a3a269977f78418d75ee", + "reference": "8b49dde3f5a5e9867595a3a269977f78418d75ee", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/cache": "^2.0|^3.0", + "psr/log": "^1.1|^2|^3", + "symfony/cache-contracts": "^2.5|^3", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/var-exporter": "^6.4|^7.0" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/dependency-injection": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/var-dumper": "<6.4" + }, + "provide": { + "psr/cache-implementation": "2.0|3.0", + "psr/simple-cache-implementation": "1.0|2.0|3.0", + "symfony/cache-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "cache/integration-tests": "dev-master", + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "psr/simple-cache": "^1.0|^2.0|^3.0", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Cache\\": "" + }, + "classmap": [ + "Traits/ValueWrapper.php" + ], + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides extended PSR-6, PSR-16 (and tags) implementations", + "homepage": "https://symfony.com", + "keywords": [ + "caching", + "psr6" + ], + "support": { + "source": "https://github.com/symfony/cache/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-08T09:06:23+00:00" + }, + { + "name": "symfony/cache-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/cache-contracts.git", + "reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/cache-contracts/zipball/15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b", + "reference": "15a4f8e5cd3bce9aeafc882b1acab39ec8de2c1b", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/cache": "^3.0" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Cache\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to caching", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/cache-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/config", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/config.git", + "reference": "e0b050b83ba999aa77a3736cb6d5b206d65b9d0d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/config/zipball/e0b050b83ba999aa77a3736cb6d5b206d65b9d0d", + "reference": "e0b050b83ba999aa77a3736cb6d5b206d65b9d0d", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/filesystem": "^7.1", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "symfony/finder": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "require-dev": { + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Config\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Helps you find, load, combine, autofill and validate configuration values of any kind", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/config/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-03T21:14:15+00:00" + }, + { + "name": "symfony/console", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/console.git", + "reference": "0e2e3f38c192e93e622e41ec37f4ca70cfedf218" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/console/zipball/0e2e3f38c192e93e622e41ec37f4ca70cfedf218", + "reference": "0e2e3f38c192e93e622e41ec37f4ca70cfedf218", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/string": "^6.4|^7.0" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/event-dispatcher": "<6.4", + "symfony/lock": "<6.4", + "symfony/process": "<6.4" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Console\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Eases the creation of beautiful and testable command line interfaces", + "homepage": "https://symfony.com", + "keywords": [ + "cli", + "command-line", + "console", + "terminal" + ], + "support": { + "source": "https://github.com/symfony/console/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-07T19:09:28+00:00" + }, + { + "name": "symfony/dependency-injection", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/dependency-injection.git", + "reference": "2ca85496cde37f825bd14f7e3548e2793ca90712" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dependency-injection/zipball/2ca85496cde37f825bd14f7e3548e2793ca90712", + "reference": "2ca85496cde37f825bd14f7e3548e2793ca90712", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/service-contracts": "^3.5", + "symfony/var-exporter": "^6.4.20|^7.2.5" + }, + "conflict": { + "ext-psr": "<1.1|>=2", + "symfony/config": "<6.4", + "symfony/finder": "<6.4", + "symfony/yaml": "<6.4" + }, + "provide": { + "psr/container-implementation": "1.1|2.0", + "symfony/service-implementation": "1.1|2.0|3.0" + }, + "require-dev": { + "symfony/config": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\DependencyInjection\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows you to standardize and centralize the way objects are constructed in your application", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/dependency-injection/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-27T13:37:55+00:00" + }, + { + "name": "symfony/deprecation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/deprecation-contracts.git", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "reference": "74c71c939a79f7d5bf3c1ce9f5ea37ba0114c6f6", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "files": [ + "function.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "A generic function and convention to trigger deprecation notices", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/deprecation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/dotenv", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/dotenv.git", + "reference": "28347a897771d0c28e99b75166dd2689099f3045" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/dotenv/zipball/28347a897771d0c28e99b75166dd2689099f3045", + "reference": "28347a897771d0c28e99b75166dd2689099f3045", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "conflict": { + "symfony/console": "<6.4", + "symfony/process": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Dotenv\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Registers environment variables from a .env file", + "homepage": "https://symfony.com", + "keywords": [ + "dotenv", + "env", + "environment" + ], + "support": { + "source": "https://github.com/symfony/dotenv/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-11-27T11:18:42+00:00" + }, + { + "name": "symfony/error-handler", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/error-handler.git", + "reference": "102be5e6a8e4f4f3eb3149bcbfa33a80d1ee374b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/error-handler/zipball/102be5e6a8e4f4f3eb3149bcbfa33a80d1ee374b", + "reference": "102be5e6a8e4f4f3eb3149bcbfa33a80d1ee374b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/var-dumper": "^6.4|^7.0" + }, + "conflict": { + "symfony/deprecation-contracts": "<2.5", + "symfony/http-kernel": "<6.4" + }, + "require-dev": { + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/patch-type-declarations" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\ErrorHandler\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to manage errors and ease debugging PHP code", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/error-handler/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-03T07:12:39+00:00" + }, + { + "name": "symfony/event-dispatcher", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher.git", + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher/zipball/910c5db85a5356d0fea57680defec4e99eb9c8c1", + "reference": "910c5db85a5356d0fea57680defec4e99eb9c8c1", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/event-dispatcher-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/dependency-injection": "<6.4", + "symfony/service-contracts": "<2.5" + }, + "provide": { + "psr/event-dispatcher-implementation": "1.0", + "symfony/event-dispatcher-implementation": "2.0|3.0" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/error-handler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/service-contracts": "^2.5|^3", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\EventDispatcher\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools that allow your application components to communicate with each other by dispatching events and listening to them", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/event-dispatcher/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/event-dispatcher-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/event-dispatcher-contracts.git", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/event-dispatcher-contracts/zipball/7642f5e970b672283b7823222ae8ef8bbc160b9f", + "reference": "7642f5e970b672283b7823222ae8ef8bbc160b9f", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/event-dispatcher": "^1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\EventDispatcher\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to dispatching event", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/event-dispatcher-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/filesystem", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/filesystem.git", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/filesystem/zipball/b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "reference": "b8dce482de9d7c9fe2891155035a7248ab5c7fdb", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.8" + }, + "require-dev": { + "symfony/process": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Filesystem\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides basic utilities for the filesystem", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/filesystem/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-10-25T15:15:23+00:00" + }, + { + "name": "symfony/finder", + "version": "v7.2.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/finder.git", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/finder/zipball/87a71856f2f56e4100373e92529eed3171695cfb", + "reference": "87a71856f2f56e4100373e92529eed3171695cfb", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/filesystem": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Finder\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Finds files and directories via an intuitive fluent interface", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/finder/tree/v7.2.2" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-30T19:00:17+00:00" + }, + { + "name": "symfony/flex", + "version": "v2.7.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/flex.git", + "reference": "5d743b3b78fabe9f3146586d77b0a1f9292851fc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/flex/zipball/5d743b3b78fabe9f3146586d77b0a1f9292851fc", + "reference": "5d743b3b78fabe9f3146586d77b0a1f9292851fc", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^2.1", + "php": ">=8.0" + }, + "conflict": { + "composer/semver": "<1.7.2" + }, + "require-dev": { + "composer/composer": "^2.1", + "symfony/dotenv": "^5.4|^6.0", + "symfony/filesystem": "^5.4|^6.0", + "symfony/phpunit-bridge": "^5.4|^6.0", + "symfony/process": "^5.4|^6.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Flex\\Flex" + }, + "autoload": { + "psr-4": { + "Symfony\\Flex\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien.potencier@gmail.com" + } + ], + "description": "Composer plugin for Symfony", + "support": { + "issues": "https://github.com/symfony/flex/issues", + "source": "https://github.com/symfony/flex/tree/v2.7.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-23T11:41:40+00:00" + }, + { + "name": "symfony/framework-bundle", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/framework-bundle.git", + "reference": "c1c6ee8946491b698b067df2258e07918c25da02" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/framework-bundle/zipball/c1c6ee8946491b698b067df2258e07918c25da02", + "reference": "c1c6ee8946491b698b067df2258e07918c25da02", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "ext-xml": "*", + "php": ">=8.2", + "symfony/cache": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^7.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/filesystem": "^7.1", + "symfony/finder": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^7.2", + "symfony/polyfill-mbstring": "~1.0", + "symfony/routing": "^6.4|^7.0" + }, + "conflict": { + "doctrine/persistence": "<1.3", + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/asset": "<6.4", + "symfony/asset-mapper": "<6.4", + "symfony/clock": "<6.4", + "symfony/console": "<6.4", + "symfony/dom-crawler": "<6.4", + "symfony/dotenv": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/lock": "<6.4", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/mime": "<6.4", + "symfony/property-access": "<6.4", + "symfony/property-info": "<6.4", + "symfony/runtime": "<6.4.13|>=7.0,<7.1.6", + "symfony/scheduler": "<6.4.4|>=7.0.0,<7.0.4", + "symfony/security-core": "<6.4", + "symfony/security-csrf": "<7.2", + "symfony/serializer": "<7.2.5", + "symfony/stopwatch": "<6.4", + "symfony/translation": "<6.4", + "symfony/twig-bridge": "<6.4", + "symfony/twig-bundle": "<6.4", + "symfony/validator": "<6.4", + "symfony/web-profiler-bundle": "<6.4", + "symfony/webhook": "<7.2", + "symfony/workflow": "<6.4" + }, + "require-dev": { + "doctrine/persistence": "^1.3|^2|^3", + "dragonmantank/cron-expression": "^3.1", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "seld/jsonlint": "^1.10", + "symfony/asset": "^6.4|^7.0", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/dotenv": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/html-sanitizer": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/lock": "^6.4|^7.0", + "symfony/mailer": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/notifier": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/process": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/scheduler": "^6.4.4|^7.0.4", + "symfony/security-bundle": "^6.4|^7.0", + "symfony/semaphore": "^6.4|^7.0", + "symfony/serializer": "^7.2.5", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/string": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/twig-bundle": "^6.4|^7.0", + "symfony/type-info": "^7.1", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0", + "symfony/webhook": "^7.2", + "symfony/workflow": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\FrameworkBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration between Symfony components and the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/framework-bundle/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-24T12:37:32+00:00" + }, + { + "name": "symfony/http-foundation", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-foundation.git", + "reference": "6023ec7607254c87c5e69fb3558255aca440d72b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-foundation/zipball/6023ec7607254c87c5e69fb3558255aca440d72b", + "reference": "6023ec7607254c87c5e69fb3558255aca440d72b", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-mbstring": "~1.1", + "symfony/polyfill-php83": "^1.27" + }, + "conflict": { + "doctrine/dbal": "<3.6", + "symfony/cache": "<6.4.12|>=7.0,<7.1.5" + }, + "require-dev": { + "doctrine/dbal": "^3.6|^4", + "predis/predis": "^1.1|^2.0", + "symfony/cache": "^6.4.12|^7.1.5", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpFoundation\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Defines an object-oriented layer for the HTTP specification", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-foundation/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-09T08:14:01+00:00" + }, + { + "name": "symfony/http-kernel", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-kernel.git", + "reference": "f9dec01e6094a063e738f8945ef69c0cfcf792ec" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-kernel/zipball/f9dec01e6094a063e738f8945ef69c0cfcf792ec", + "reference": "f9dec01e6094a063e738f8945ef69c0cfcf792ec", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/error-handler": "^6.4|^7.0", + "symfony/event-dispatcher": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/browser-kit": "<6.4", + "symfony/cache": "<6.4", + "symfony/config": "<6.4", + "symfony/console": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<6.4", + "symfony/form": "<6.4", + "symfony/http-client": "<6.4", + "symfony/http-client-contracts": "<2.5", + "symfony/mailer": "<6.4", + "symfony/messenger": "<6.4", + "symfony/translation": "<6.4", + "symfony/translation-contracts": "<2.5", + "symfony/twig-bridge": "<6.4", + "symfony/validator": "<6.4", + "symfony/var-dumper": "<6.4", + "twig/twig": "<3.12" + }, + "provide": { + "psr/log-implementation": "1.0|2.0|3.0" + }, + "require-dev": { + "psr/cache": "^1.0|^2.0|^3.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/clock": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/css-selector": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/dom-crawler": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client-contracts": "^2.5|^3", + "symfony/process": "^6.4|^7.0", + "symfony/property-access": "^7.1", + "symfony/routing": "^6.4|^7.0", + "symfony/serializer": "^7.1", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symfony/var-exporter": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpKernel\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a structured process for converting a Request into a Response", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/http-kernel/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-02T09:04:03+00:00" + }, + { + "name": "symfony/polyfill-ctype", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-ctype.git", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-ctype/zipball/a3cc8b044a6ea513310cbd48ef7333b384945638", + "reference": "a3cc8b044a6ea513310cbd48ef7333b384945638", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "provide": { + "ext-ctype": "*" + }, + "suggest": { + "ext-ctype": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Ctype\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Gert de Pagter", + "email": "BackEndTea@gmail.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for ctype functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "ctype", + "polyfill", + "portable" + ], + "support": { + "source": "https://github.com/symfony/polyfill-ctype/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-grapheme", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-grapheme.git", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-grapheme/zipball/b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "reference": "b9123926e3b7bc2f98c02ad54f6a4b02b91a8abe", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Grapheme\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's grapheme_* functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "grapheme", + "intl", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-intl-normalizer", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-intl-normalizer.git", + "reference": "3833d7255cc303546435cb650316bff708a1c75c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-intl-normalizer/zipball/3833d7255cc303546435cb650316bff708a1c75c", + "reference": "3833d7255cc303546435cb650316bff708a1c75c", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "suggest": { + "ext-intl": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Intl\\Normalizer\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for intl's Normalizer class and related functions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "intl", + "normalizer", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-mbstring", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-mbstring.git", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/6d857f4d76bd4b343eac26d6b539585d2bc56493", + "reference": "6d857f4d76bd4b343eac26d6b539585d2bc56493", + "shasum": "" + }, + "require": { + "ext-iconv": "*", + "php": ">=7.2" + }, + "provide": { + "ext-mbstring": "*" + }, + "suggest": { + "ext-mbstring": "For best performance" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Mbstring\\": "" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill for the Mbstring extension", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "mbstring", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-mbstring/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-23T08:48:59+00:00" + }, + { + "name": "symfony/polyfill-php83", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php83.git", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php83/zipball/2fb86d65e2d424369ad2905e83b236a8805ba491", + "reference": "2fb86d65e2d424369ad2905e83b236a8805ba491", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php83\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.3+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php83/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-09T11:45:10+00:00" + }, + { + "name": "symfony/polyfill-php85", + "version": "v1.32.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/polyfill-php85.git", + "reference": "6fedf31ce4e3648f4ff5ca58bfd53127d38f05fd" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/polyfill-php85/zipball/6fedf31ce4e3648f4ff5ca58bfd53127d38f05fd", + "reference": "6fedf31ce4e3648f4ff5ca58bfd53127d38f05fd", + "shasum": "" + }, + "require": { + "php": ">=7.2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/polyfill", + "name": "symfony/polyfill" + } + }, + "autoload": { + "files": [ + "bootstrap.php" + ], + "psr-4": { + "Symfony\\Polyfill\\Php85\\": "" + }, + "classmap": [ + "Resources/stubs" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony polyfill backporting some PHP 8.5+ features to lower PHP versions", + "homepage": "https://symfony.com", + "keywords": [ + "compatibility", + "polyfill", + "portable", + "shim" + ], + "support": { + "source": "https://github.com/symfony/polyfill-php85/tree/v1.32.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-02T08:40:52+00:00" + }, + { + "name": "symfony/routing", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/routing.git", + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/routing/zipball/ee9a67edc6baa33e5fae662f94f91fd262930996", + "reference": "ee9a67edc6baa33e5fae662f94f91fd262930996", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "psr/log": "^1|^2|^3", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Routing\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Maps an HTTP request to a set of configuration variables", + "homepage": "https://symfony.com", + "keywords": [ + "router", + "routing", + "uri", + "url" + ], + "support": { + "source": "https://github.com/symfony/routing/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-01-17T10:56:55+00:00" + }, + { + "name": "symfony/runtime", + "version": "v7.2.3", + "source": { + "type": "git", + "url": "https://github.com/symfony/runtime.git", + "reference": "8e8d09bd69b7f6c0260dd3d58f37bd4fbdeab5ad" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/runtime/zipball/8e8d09bd69b7f6c0260dd3d58f37bd4fbdeab5ad", + "reference": "8e8d09bd69b7f6c0260dd3d58f37bd4fbdeab5ad", + "shasum": "" + }, + "require": { + "composer-plugin-api": "^1.0|^2.0", + "php": ">=8.2" + }, + "conflict": { + "symfony/dotenv": "<6.4" + }, + "require-dev": { + "composer/composer": "^2.6", + "symfony/console": "^6.4|^7.0", + "symfony/dotenv": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0" + }, + "type": "composer-plugin", + "extra": { + "class": "Symfony\\Component\\Runtime\\Internal\\ComposerPlugin" + }, + "autoload": { + "psr-4": { + "Symfony\\Component\\Runtime\\": "", + "Symfony\\Runtime\\Symfony\\Component\\": "Internal/" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Enables decoupling PHP applications from global state", + "homepage": "https://symfony.com", + "keywords": [ + "runtime" + ], + "support": { + "source": "https://github.com/symfony/runtime/tree/v7.2.3" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-12-29T21:39:47+00:00" + }, + { + "name": "symfony/serializer", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/serializer.git", + "reference": "be549655b034edc1a16ed23d8164aa04318c5ec1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/serializer/zipball/be549655b034edc1a16ed23d8164aa04318c5ec1", + "reference": "be549655b034edc1a16ed23d8164aa04318c5ec1", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/dependency-injection": "<6.4", + "symfony/property-access": "<6.4", + "symfony/property-info": "<6.4", + "symfony/uid": "<6.4", + "symfony/validator": "<6.4", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "phpdocumentor/reflection-docblock": "^3.2|^4.0|^5.0", + "phpstan/phpdoc-parser": "^1.0|^2.0", + "seld/jsonlint": "^1.10", + "symfony/cache": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^7.2", + "symfony/error-handler": "^6.4|^7.0", + "symfony/filesystem": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3", + "symfony/type-info": "^7.1", + "symfony/uid": "^6.4|^7.0", + "symfony/validator": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0", + "symfony/var-exporter": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Serializer\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Handles serializing and deserializing data structures, including object graphs, into array structures or other formats like XML and JSON.", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/serializer/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-27T13:34:41+00:00" + }, + { + "name": "symfony/service-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/service-contracts.git", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/service-contracts/zipball/e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "reference": "e53260aabf78fb3d63f8d79d69ece59f80d5eda0", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "psr/container": "^1.1|^2.0", + "symfony/deprecation-contracts": "^2.5|^3" + }, + "conflict": { + "ext-psr": "<1.1|>=2" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Service\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to writing services", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/service-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/string", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/string.git", + "reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/string/zipball/a214fe7d62bd4df2a76447c67c6b26e1d5e74931", + "reference": "a214fe7d62bd4df2a76447c67c6b26e1d5e74931", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-intl-grapheme": "~1.0", + "symfony/polyfill-intl-normalizer": "~1.0", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/translation-contracts": "<2.5" + }, + "require-dev": { + "symfony/emoji": "^7.1", + "symfony/error-handler": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/translation-contracts": "^2.5|^3.0", + "symfony/var-exporter": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "Resources/functions.php" + ], + "psr-4": { + "Symfony\\Component\\String\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides an object-oriented API to strings and deals with bytes, UTF-8 code points and grapheme clusters in a unified way", + "homepage": "https://symfony.com", + "keywords": [ + "grapheme", + "i18n", + "string", + "unicode", + "utf-8", + "utf8" + ], + "support": { + "source": "https://github.com/symfony/string/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-20T20:18:16+00:00" + }, + { + "name": "symfony/translation-contracts", + "version": "v3.5.1", + "source": { + "type": "git", + "url": "https://github.com/symfony/translation-contracts.git", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/translation-contracts/zipball/4667ff3bd513750603a09c8dedbea942487fb07c", + "reference": "4667ff3bd513750603a09c8dedbea942487fb07c", + "shasum": "" + }, + "require": { + "php": ">=8.1" + }, + "type": "library", + "extra": { + "thanks": { + "url": "https://github.com/symfony/contracts", + "name": "symfony/contracts" + }, + "branch-alias": { + "dev-main": "3.5-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Contracts\\Translation\\": "" + }, + "exclude-from-classmap": [ + "/Test/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Generic abstractions related to translation", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/translation-contracts/tree/v3.5.1" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:20:29+00:00" + }, + { + "name": "symfony/twig-bridge", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/twig-bridge.git", + "reference": "b1942d5515b7f0a18e16fd668a04ea952db2b0f2" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/twig-bridge/zipball/b1942d5515b7f0a18e16fd668a04ea952db2b0f2", + "reference": "b1942d5515b7f0a18e16fd668a04ea952db2b0f2", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/translation-contracts": "^2.5|^3", + "twig/twig": "^3.12" + }, + "conflict": { + "phpdocumentor/reflection-docblock": "<3.2.2", + "phpdocumentor/type-resolver": "<1.4.0", + "symfony/console": "<6.4", + "symfony/form": "<6.4", + "symfony/http-foundation": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/mime": "<6.4", + "symfony/serializer": "<6.4", + "symfony/translation": "<6.4", + "symfony/workflow": "<6.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3|^4", + "league/html-to-markdown": "^5.0", + "phpdocumentor/reflection-docblock": "^3.0|^4.0|^5.0", + "symfony/asset": "^6.4|^7.0", + "symfony/asset-mapper": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/emoji": "^7.1", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/form": "^6.4.20|^7.2.5", + "symfony/html-sanitizer": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/polyfill-intl-icu": "~1.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0", + "symfony/security-acl": "^2.8|^3.0", + "symfony/security-core": "^6.4|^7.0", + "symfony/security-csrf": "^6.4|^7.0", + "symfony/security-http": "^6.4|^7.0", + "symfony/serializer": "^6.4.3|^7.0.3", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0", + "symfony/workflow": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0", + "twig/cssinliner-extra": "^2.12|^3", + "twig/inky-extra": "^2.12|^3", + "twig/markdown-extra": "^2.12|^3" + }, + "type": "symfony-bridge", + "autoload": { + "psr-4": { + "Symfony\\Bridge\\Twig\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides integration for Twig with various Symfony components", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/twig-bridge/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-28T13:15:09+00:00" + }, + { + "name": "symfony/twig-bundle", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/twig-bundle.git", + "reference": "cd2be4563afaef5285bb6e0a06c5445e644a5c01" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/twig-bundle/zipball/cd2be4563afaef5285bb6e0a06c5445e644a5c01", + "reference": "cd2be4563afaef5285bb6e0a06c5445e644a5c01", + "shasum": "" + }, + "require": { + "composer-runtime-api": ">=2.1", + "php": ">=8.2", + "symfony/config": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/twig-bridge": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "conflict": { + "symfony/framework-bundle": "<6.4", + "symfony/translation": "<6.4" + }, + "require-dev": { + "symfony/asset": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/form": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/routing": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0", + "symfony/translation": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\TwigBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of Twig into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/twig-bundle/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-10-23T08:11:15+00:00" + }, + { + "name": "symfony/validator", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/validator.git", + "reference": "f7c32e309885a97fc9572335e22c2c2d31f328c4" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/validator/zipball/f7c32e309885a97fc9572335e22c2c2d31f328c4", + "reference": "f7c32e309885a97fc9572335e22c2c2d31f328c4", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "~1.8", + "symfony/polyfill-mbstring": "~1.0", + "symfony/polyfill-php83": "^1.27", + "symfony/translation-contracts": "^2.5|^3" + }, + "conflict": { + "doctrine/lexer": "<1.1", + "symfony/dependency-injection": "<6.4", + "symfony/doctrine-bridge": "<7.0", + "symfony/expression-language": "<6.4", + "symfony/http-kernel": "<6.4", + "symfony/intl": "<6.4", + "symfony/property-info": "<6.4", + "symfony/translation": "<6.4.3|>=7.0,<7.0.3", + "symfony/yaml": "<6.4" + }, + "require-dev": { + "egulias/email-validator": "^2.1.10|^3|^4", + "symfony/cache": "^6.4|^7.0", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/expression-language": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/http-client": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/intl": "^6.4|^7.0", + "symfony/mime": "^6.4|^7.0", + "symfony/property-access": "^6.4|^7.0", + "symfony/property-info": "^6.4|^7.0", + "symfony/translation": "^6.4.3|^7.0.3", + "symfony/type-info": "^7.1", + "symfony/yaml": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Validator\\": "" + }, + "exclude-from-classmap": [ + "/Tests/", + "/Resources/bin/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides tools to validate values", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/validator/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-02T08:36:00+00:00" + }, + { + "name": "symfony/var-dumper", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-dumper.git", + "reference": "9c46038cd4ed68952166cf7001b54eb539184ccb" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-dumper/zipball/9c46038cd4ed68952166cf7001b54eb539184ccb", + "reference": "9c46038cd4ed68952166cf7001b54eb539184ccb", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/polyfill-mbstring": "~1.0" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "ext-iconv": "*", + "symfony/console": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/uid": "^6.4|^7.0", + "twig/twig": "^3.12" + }, + "bin": [ + "Resources/bin/var-dump-server" + ], + "type": "library", + "autoload": { + "files": [ + "Resources/functions/dump.php" + ], + "psr-4": { + "Symfony\\Component\\VarDumper\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides mechanisms for walking through any arbitrary PHP variable", + "homepage": "https://symfony.com", + "keywords": [ + "debug", + "dump" + ], + "support": { + "source": "https://github.com/symfony/var-dumper/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-09T08:14:01+00:00" + }, + { + "name": "symfony/var-exporter", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/var-exporter.git", + "reference": "422b8de94c738830a1e071f59ad14d67417d7007" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/422b8de94c738830a1e071f59ad14d67417d7007", + "reference": "422b8de94c738830a1e071f59ad14d67417d7007", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "require-dev": { + "symfony/property-access": "^6.4|^7.0", + "symfony/serializer": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\VarExporter\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nicolas Grekas", + "email": "p@tchwork.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Allows exporting any serializable PHP data structure to plain PHP code", + "homepage": "https://symfony.com", + "keywords": [ + "clone", + "construct", + "export", + "hydrate", + "instantiate", + "lazy-loading", + "proxy", + "serialize" + ], + "support": { + "source": "https://github.com/symfony/var-exporter/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-05-02T08:36:00+00:00" + }, + { + "name": "symfony/yaml", + "version": "v7.2.6", + "source": { + "type": "git", + "url": "https://github.com/symfony/yaml.git", + "reference": "0feafffb843860624ddfd13478f481f4c3cd8b23" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/yaml/zipball/0feafffb843860624ddfd13478f481f4c3cd8b23", + "reference": "0feafffb843860624ddfd13478f481f4c3cd8b23", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.5|^3.0", + "symfony/polyfill-ctype": "^1.8" + }, + "conflict": { + "symfony/console": "<6.4" + }, + "require-dev": { + "symfony/console": "^6.4|^7.0" + }, + "bin": [ + "Resources/bin/yaml-lint" + ], + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Yaml\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Loads and dumps YAML files", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/yaml/tree/v7.2.6" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-04T10:10:11+00:00" + }, + { + "name": "twig/twig", + "version": "v3.21.1", + "source": { + "type": "git", + "url": "https://github.com/twigphp/Twig.git", + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/twigphp/Twig/zipball/285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "reference": "285123877d4dd97dd7c11842ac5fb7e86e60d81d", + "shasum": "" + }, + "require": { + "php": ">=8.1.0", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/polyfill-ctype": "^1.8", + "symfony/polyfill-mbstring": "^1.3" + }, + "require-dev": { + "phpstan/phpstan": "^2.0", + "psr/container": "^1.0|^2.0", + "symfony/phpunit-bridge": "^5.4.9|^6.4|^7.0" + }, + "type": "library", + "autoload": { + "files": [ + "src/Resources/core.php", + "src/Resources/debug.php", + "src/Resources/escaper.php", + "src/Resources/string_loader.php" + ], + "psr-4": { + "Twig\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com", + "homepage": "http://fabien.potencier.org", + "role": "Lead Developer" + }, + { + "name": "Twig Team", + "role": "Contributors" + }, + { + "name": "Armin Ronacher", + "email": "armin.ronacher@active-4.com", + "role": "Project Founder" + } + ], + "description": "Twig, the flexible, fast, and secure template language for PHP", + "homepage": "https://twig.symfony.com", + "keywords": [ + "templating" + ], + "support": { + "issues": "https://github.com/twigphp/Twig/issues", + "source": "https://github.com/twigphp/Twig/tree/v3.21.1" + }, + "funding": [ + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/twig/twig", + "type": "tidelift" + } + ], + "time": "2025-05-03T07:21:55+00:00" + } + ], + "packages-dev": [ + { + "name": "doctrine/inflector", + "version": "2.0.10", + "source": { + "type": "git", + "url": "https://github.com/doctrine/inflector.git", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/doctrine/inflector/zipball/5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "reference": "5817d0659c5b50c9b950feb9af7b9668e2c436bc", + "shasum": "" + }, + "require": { + "php": "^7.2 || ^8.0" + }, + "require-dev": { + "doctrine/coding-standard": "^11.0", + "phpstan/phpstan": "^1.8", + "phpstan/phpstan-phpunit": "^1.1", + "phpstan/phpstan-strict-rules": "^1.3", + "phpunit/phpunit": "^8.5 || ^9.5", + "vimeo/psalm": "^4.25 || ^5.4" + }, + "type": "library", + "autoload": { + "psr-4": { + "Doctrine\\Inflector\\": "lib/Doctrine/Inflector" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Guilherme Blanco", + "email": "guilhermeblanco@gmail.com" + }, + { + "name": "Roman Borschel", + "email": "roman@code-factory.org" + }, + { + "name": "Benjamin Eberlei", + "email": "kontakt@beberlei.de" + }, + { + "name": "Jonathan Wage", + "email": "jonwage@gmail.com" + }, + { + "name": "Johannes Schmitt", + "email": "schmittjoh@gmail.com" + } + ], + "description": "PHP Doctrine Inflector is a small library that can perform string manipulations with regard to upper/lowercase and singular/plural forms of words.", + "homepage": "https://www.doctrine-project.org/projects/inflector.html", + "keywords": [ + "inflection", + "inflector", + "lowercase", + "manipulation", + "php", + "plural", + "singular", + "strings", + "uppercase", + "words" + ], + "support": { + "issues": "https://github.com/doctrine/inflector/issues", + "source": "https://github.com/doctrine/inflector/tree/2.0.10" + }, + "funding": [ + { + "url": "https://www.doctrine-project.org/sponsorship.html", + "type": "custom" + }, + { + "url": "https://www.patreon.com/phpdoctrine", + "type": "patreon" + }, + { + "url": "https://tidelift.com/funding/github/packagist/doctrine%2Finflector", + "type": "tidelift" + } + ], + "time": "2024-02-18T20:23:39+00:00" + }, + { + "name": "nikic/php-parser", + "version": "v5.4.0", + "source": { + "type": "git", + "url": "https://github.com/nikic/PHP-Parser.git", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/nikic/PHP-Parser/zipball/447a020a1f875a434d62f2a401f53b82a396e494", + "reference": "447a020a1f875a434d62f2a401f53b82a396e494", + "shasum": "" + }, + "require": { + "ext-ctype": "*", + "ext-json": "*", + "ext-tokenizer": "*", + "php": ">=7.4" + }, + "require-dev": { + "ircmaxell/php-yacc": "^0.0.7", + "phpunit/phpunit": "^9.0" + }, + "bin": [ + "bin/php-parse" + ], + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "5.0-dev" + } + }, + "autoload": { + "psr-4": { + "PhpParser\\": "lib/PhpParser" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "BSD-3-Clause" + ], + "authors": [ + { + "name": "Nikita Popov" + } + ], + "description": "A PHP parser written in PHP", + "keywords": [ + "parser", + "php" + ], + "support": { + "issues": "https://github.com/nikic/PHP-Parser/issues", + "source": "https://github.com/nikic/PHP-Parser/tree/v5.4.0" + }, + "time": "2024-12-30T11:07:19+00:00" + }, + { + "name": "symfony/debug-bundle", + "version": "v7.2.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/debug-bundle.git", + "reference": "2dade0d1415c08b627379b5ec214ec8424cb2e32" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/debug-bundle/zipball/2dade0d1415c08b627379b5ec214ec8424cb2e32", + "reference": "2dade0d1415c08b627379b5ec214ec8424cb2e32", + "shasum": "" + }, + "require": { + "ext-xml": "*", + "php": ">=8.2", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/twig-bridge": "^6.4|^7.0", + "symfony/var-dumper": "^6.4|^7.0" + }, + "conflict": { + "symfony/config": "<6.4", + "symfony/dependency-injection": "<6.4" + }, + "require-dev": { + "symfony/config": "^6.4|^7.0", + "symfony/web-profiler-bundle": "^6.4|^7.0" + }, + "type": "symfony-bundle", + "autoload": { + "psr-4": { + "Symfony\\Bundle\\DebugBundle\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Provides a tight integration of the Symfony VarDumper component and the ServerLogCommand from MonologBridge into the Symfony full-stack framework", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/debug-bundle/tree/v7.2.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2024-09-25T14:21:43+00:00" + }, + { + "name": "symfony/maker-bundle", + "version": "v1.63.0", + "source": { + "type": "git", + "url": "https://github.com/symfony/maker-bundle.git", + "reference": "69478ab39bc303abfbe3293006a78b09a8512425" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/maker-bundle/zipball/69478ab39bc303abfbe3293006a78b09a8512425", + "reference": "69478ab39bc303abfbe3293006a78b09a8512425", + "shasum": "" + }, + "require": { + "doctrine/inflector": "^2.0", + "nikic/php-parser": "^5.0", + "php": ">=8.1", + "symfony/config": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/deprecation-contracts": "^2.2|^3", + "symfony/filesystem": "^6.4|^7.0", + "symfony/finder": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0" + }, + "conflict": { + "doctrine/doctrine-bundle": "<2.10", + "doctrine/orm": "<2.15" + }, + "require-dev": { + "composer/semver": "^3.0", + "doctrine/doctrine-bundle": "^2.5.0", + "doctrine/orm": "^2.15|^3", + "symfony/http-client": "^6.4|^7.0", + "symfony/phpunit-bridge": "^6.4.1|^7.0", + "symfony/security-core": "^6.4|^7.0", + "symfony/yaml": "^6.4|^7.0", + "twig/twig": "^3.0|^4.x-dev" + }, + "type": "symfony-bundle", + "extra": { + "branch-alias": { + "dev-main": "1.x-dev" + } + }, + "autoload": { + "psr-4": { + "Symfony\\Bundle\\MakerBundle\\": "src/" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Symfony Maker helps you create empty commands, controllers, form classes, tests and more so you can forget about writing boilerplate code.", + "homepage": "https://symfony.com/doc/current/bundles/SymfonyMakerBundle/index.html", + "keywords": [ + "code generator", + "dev", + "generator", + "scaffold", + "scaffolding" + ], + "support": { + "issues": "https://github.com/symfony/maker-bundle/issues", + "source": "https://github.com/symfony/maker-bundle/tree/v1.63.0" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-04-26T01:41:37+00:00" + }, + { + "name": "symfony/process", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/process.git", + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/process/zipball/87b7c93e57df9d8e39a093d32587702380ff045d", + "reference": "87b7c93e57df9d8e39a093d32587702380ff045d", + "shasum": "" + }, + "require": { + "php": ">=8.2" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\Process\\": "" + }, + "exclude-from-classmap": [ + "/Tests/" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Fabien Potencier", + "email": "fabien@symfony.com" + }, + { + "name": "Symfony Community", + "homepage": "https://symfony.com/contributors" + } + ], + "description": "Executes commands in sub-processes", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/process/tree/v7.2.5" + }, + "funding": [ + { + "url": "https://symfony.com/sponsor", + "type": "custom" + }, + { + "url": "https://github.com/fabpot", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/symfony/symfony", + "type": "tidelift" + } + ], + "time": "2025-03-13T12:21:46+00:00" + } + ], + "aliases": [], + "minimum-stability": "stable", + "stability-flags": {}, + "prefer-stable": true, + "prefer-lowest": false, + "platform": { + "php": "^8.3", + "ext-ctype": "*", + "ext-iconv": "*" + }, + "platform-dev": {}, + "plugin-api-version": "2.6.0" +} diff --git a/config/bundles.php b/config/bundles.php new file mode 100644 index 0000000..44fcc95 --- /dev/null +++ b/config/bundles.php @@ -0,0 +1,8 @@ + ['all' => true], + Symfony\Bundle\TwigBundle\TwigBundle::class => ['all' => true], + Symfony\Bundle\DebugBundle\DebugBundle::class => ['dev' => true], + Symfony\Bundle\MakerBundle\MakerBundle::class => ['dev' => true], +]; diff --git a/config/packages/cache.yaml b/config/packages/cache.yaml new file mode 100644 index 0000000..6899b72 --- /dev/null +++ b/config/packages/cache.yaml @@ -0,0 +1,19 @@ +framework: + cache: + # Unique name of your app: used to compute stable namespaces for cache keys. + #prefix_seed: your_vendor_name/app_name + + # The "app" cache stores to the filesystem by default. + # The data in this cache should persist between deploys. + # Other options include: + + # Redis + #app: cache.adapter.redis + #default_redis_provider: redis://localhost + + # APCu (not recommended with heavy random-write workloads as memory fragmentation can cause perf issues) + #app: cache.adapter.apcu + + # Namespaced pools use the above "app" backend by default + #pools: + #my.dedicated.cache: null diff --git a/config/packages/debug.yaml b/config/packages/debug.yaml new file mode 100644 index 0000000..ad874af --- /dev/null +++ b/config/packages/debug.yaml @@ -0,0 +1,5 @@ +when@dev: + debug: + # Forwards VarDumper Data clones to a centralized server allowing to inspect dumps on CLI or in your browser. + # See the "server:dump" command to start a new server. + dump_destination: "tcp://%env(VAR_DUMPER_SERVER)%" diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml new file mode 100644 index 0000000..00b3f0c --- /dev/null +++ b/config/packages/framework.yaml @@ -0,0 +1,10 @@ +framework: + secret: '%env(APP_SECRET)%' + serializer: + enabled: true + validation: + enabled: true + http_method_override: false + handle_all_throwables: true + php_errors: + log: true \ No newline at end of file diff --git a/config/packages/routing.yaml b/config/packages/routing.yaml new file mode 100644 index 0000000..8166181 --- /dev/null +++ b/config/packages/routing.yaml @@ -0,0 +1,10 @@ +framework: + router: + # Configure how to generate URLs in non-HTTP contexts, such as CLI commands. + # See https://symfony.com/doc/current/routing.html#generating-urls-in-commands + #default_uri: http://localhost + +when@prod: + framework: + router: + strict_requirements: null diff --git a/config/packages/twig.yaml b/config/packages/twig.yaml new file mode 100644 index 0000000..7e6cf68 --- /dev/null +++ b/config/packages/twig.yaml @@ -0,0 +1,2 @@ +twig: + default_path: '%kernel.project_dir%/templates' \ No newline at end of file diff --git a/config/packages/validator.yaml b/config/packages/validator.yaml new file mode 100644 index 0000000..dd47a6a --- /dev/null +++ b/config/packages/validator.yaml @@ -0,0 +1,11 @@ +framework: + validation: + # Enables validator auto-mapping support. + # For instance, basic validation constraints will be inferred from Doctrine's metadata. + #auto_mapping: + # App\Entity\: [] + +when@test: + framework: + validation: + not_compromised_password: false diff --git a/config/preload.php b/config/preload.php new file mode 100644 index 0000000..5ebcdb2 --- /dev/null +++ b/config/preload.php @@ -0,0 +1,5 @@ +=12" + } + }, + "node_modules/@dotenvx/dotenvx": { + "version": "1.44.1", + "resolved": "https://registry.npmjs.org/@dotenvx/dotenvx/-/dotenvx-1.44.1.tgz", + "integrity": "sha512-j1QImCqf/XJmhIjC1OPpgiZV9g370HG9MNT9s/CDwCKsoYzNCPEKK+GfsidahJx7yIlBbm+4dPLlGec+bKn7oA==", + "license": "BSD-3-Clause", + "dependencies": { + "commander": "^11.1.0", + "dotenv": "^16.4.5", + "eciesjs": "^0.4.10", + "execa": "^5.1.1", + "fdir": "^6.2.0", + "ignore": "^5.3.0", + "object-treeify": "1.1.33", + "picomatch": "^4.0.2", + "which": "^4.0.0" + }, + "bin": { + "dotenvx": "src/cli/dotenvx.js", + "git-dotenvx": "src/cli/dotenvx.js" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/fdir": { + "version": "6.4.4", + "resolved": "https://registry.npmjs.org/fdir/-/fdir-6.4.4.tgz", + "integrity": "sha512-1NZP+GK4GfuAv3PqKvxQRDMjdSRZjnkq7KfhlNrCNNlZ0ygQFpebfrnfnq/W7fpUnAv9aGWmY1zKx7FYL3gwhg==", + "license": "MIT", + "peerDependencies": { + "picomatch": "^3 || ^4" + }, + "peerDependenciesMeta": { + "picomatch": { + "optional": true + } + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "license": "ISC", + "engines": { + "node": ">=16" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/picomatch": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.2.tgz", + "integrity": "sha512-M7BAV6Rlcy5u+m6oPhAPFgJTzAioX/6B0DxyvDlo9l8+T3nLKbrczg2WLUyzd45L8RqfUMyGPzekbMvX2Ldkwg==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@dotenvx/dotenvx/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "license": "ISC", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@ecies/ciphers": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@ecies/ciphers/-/ciphers-0.2.3.tgz", + "integrity": "sha512-tapn6XhOueMwht3E2UzY0ZZjYokdaw9XtL9kEyjhQ/Fb9vL9xTFbOaI+fV0AWvTpYu4BNloC6getKW6NtSg4mA==", + "license": "MIT", + "engines": { + "bun": ">=1", + "deno": ">=2", + "node": ">=16" + }, + "peerDependencies": { + "@noble/ciphers": "^1.0.0" + } + }, "node_modules/@emnapi/core": { "version": "1.4.3", "resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.4.3.tgz", @@ -650,6 +756,34 @@ "url": "https://opencollective.com/libvips" } }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz", + "integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==", + "dev": true, + "license": "MIT" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, "node_modules/@mongodb-js/saslprep": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.2.2.tgz", @@ -816,6 +950,45 @@ "node": ">= 10" } }, + "node_modules/@noble/ciphers": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/ciphers/-/ciphers-1.3.0.tgz", + "integrity": "sha512-2I0gnIVPtfnMw9ee9h1dJG7tp81+8Ob3OJb3Mv37rx5L40/b0i7djjCVvGOVqc9AEIQyvyu1i6ypKdFw8R8gQw==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/curves": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/@noble/curves/-/curves-1.9.1.tgz", + "integrity": "sha512-k11yZxZg+t+gWvBbIswW0yoJlu8cHOC7dhunwOzoWH/mXGBiYyR4YY6hAEK/3EUs4UpB8la1RfdRpeGsFHkWsA==", + "license": "MIT", + "dependencies": { + "@noble/hashes": "1.8.0" + }, + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, + "node_modules/@noble/hashes": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.8.0.tgz", + "integrity": "sha512-jCs9ldd7NwzpgXDIf6P3+NrHh9/sD6CQdxHyjQI+h/6rDNo88ypBxxz45UDuZHz9r3tNz7N/VInSVoVdtXEI4A==", + "license": "MIT", + "engines": { + "node": "^14.21.3 || >=16" + }, + "funding": { + "url": "https://paulmillr.com/funding/" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -893,6 +1066,34 @@ "tslib": "^2.8.0" } }, + "node_modules/@tsconfig/node10": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz", + "integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true, + "license": "MIT" + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz", + "integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==", + "dev": true, + "license": "MIT" + }, "node_modules/@tybys/wasm-util": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.9.0.tgz", @@ -929,12 +1130,21 @@ "version": "20.17.48", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.17.48.tgz", "integrity": "sha512-KpSfKOHPsiSC4IkZeu2LsusFwExAIVGkhG1KkbaBMLwau0uMhj0fCrvyg9ddM2sAvd+gtiBJLir4LAw1MNMIaw==", - "dev": true, "license": "MIT", "dependencies": { "undici-types": "~6.19.2" } }, + "node_modules/@types/node-fetch": { + "version": "2.6.12", + "resolved": "https://registry.npmjs.org/@types/node-fetch/-/node-fetch-2.6.12.tgz", + "integrity": "sha512-8nneRWKCg3rMtF69nLQJnOYUcbafYeFSjqkw3jCRLsqkWFlHaoQrr5mXmofFGOx3DKn7UfmBMyov8ySvLRVldA==", + "license": "MIT", + "dependencies": { + "@types/node": "*", + "form-data": "^4.0.0" + } + }, "node_modules/@types/react": { "version": "19.1.4", "resolved": "https://registry.npmjs.org/@types/react/-/react-19.1.4.tgz", @@ -1457,6 +1667,18 @@ "win32" ] }, + "node_modules/abort-controller": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz", + "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==", + "license": "MIT", + "dependencies": { + "event-target-shim": "^5.0.0" + }, + "engines": { + "node": ">=6.5" + } + }, "node_modules/acorn": { "version": "8.14.1", "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.1.tgz", @@ -1480,6 +1702,31 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-walk": { + "version": "8.3.4", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz", + "integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==", + "dev": true, + "license": "MIT", + "dependencies": { + "acorn": "^8.11.0" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agentkeepalive": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/agentkeepalive/-/agentkeepalive-4.6.0.tgz", + "integrity": "sha512-kja8j7PjmncONqaTsB8fQ+wE2mSU2DJ9D4XKoJ5PFWIdRMa6SLSN1ff4mOr4jCbfRSsxR4keIiySJU0N9T5hIQ==", + "license": "MIT", + "dependencies": { + "humanize-ms": "^1.2.1" + }, + "engines": { + "node": ">= 8.0.0" + } + }, "node_modules/ajv": { "version": "6.12.6", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", @@ -1513,6 +1760,13 @@ "url": "https://github.com/chalk/ansi-styles?sponsor=1" } }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true, + "license": "MIT" + }, "node_modules/argparse": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", @@ -1705,6 +1959,12 @@ "node": ">= 0.4" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "license": "MIT" + }, "node_modules/available-typed-arrays": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz", @@ -1815,7 +2075,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/call-bind-apply-helpers/-/call-bind-apply-helpers-1.0.2.tgz", "integrity": "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -1940,6 +2199,27 @@ "simple-swizzle": "^0.2.2" } }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "license": "MIT", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-11.1.0.tgz", + "integrity": "sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ==", + "license": "MIT", + "engines": { + "node": ">=16" + } + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -1947,11 +2227,17 @@ "dev": true, "license": "MIT" }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true, + "license": "MIT" + }, "node_modules/cross-spawn": { "version": "7.0.6", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", - "dev": true, "license": "MIT", "dependencies": { "path-key": "^3.1.0", @@ -2091,6 +2377,15 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "license": "MIT", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/detect-libc": { "version": "2.0.4", "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-2.0.4.tgz", @@ -2101,6 +2396,16 @@ "node": ">=8" } }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "license": "BSD-3-Clause", + "engines": { + "node": ">=0.3.1" + } + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -2114,11 +2419,22 @@ "node": ">=0.10.0" } }, + "node_modules/dotenv": { + "version": "16.5.0", + "resolved": "https://registry.npmjs.org/dotenv/-/dotenv-16.5.0.tgz", + "integrity": "sha512-m/C+AwOAr9/W1UOIZUo232ejMNnJAJtYQjUbHoNTBNTJSvqzzDh7vnrei3o3r3m9blf6ZoDkvcw0VmozNRFJxg==", + "license": "BSD-2-Clause", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://dotenvx.com" + } + }, "node_modules/dunder-proto": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/dunder-proto/-/dunder-proto-1.0.1.tgz", "integrity": "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.1", @@ -2129,6 +2445,23 @@ "node": ">= 0.4" } }, + "node_modules/eciesjs": { + "version": "0.4.14", + "resolved": "https://registry.npmjs.org/eciesjs/-/eciesjs-0.4.14.tgz", + "integrity": "sha512-eJAgf9pdv214Hn98FlUzclRMYWF7WfoLlkS9nWMTm1qcCwn6Ad4EGD9lr9HXMBfSrZhYQujRE+p0adPRkctC6A==", + "license": "MIT", + "dependencies": { + "@ecies/ciphers": "^0.2.2", + "@noble/ciphers": "^1.0.0", + "@noble/curves": "^1.6.0", + "@noble/hashes": "^1.5.0" + }, + "engines": { + "bun": ">=1", + "deno": ">=2", + "node": ">=16" + } + }, "node_modules/emoji-regex": { "version": "9.2.2", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", @@ -2206,7 +2539,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.1.tgz", "integrity": "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2216,7 +2548,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -2254,7 +2585,6 @@ "version": "1.1.1", "resolved": "https://registry.npmjs.org/es-object-atoms/-/es-object-atoms-1.1.1.tgz", "integrity": "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0" @@ -2267,7 +2597,6 @@ "version": "2.1.0", "resolved": "https://registry.npmjs.org/es-set-tostringtag/-/es-set-tostringtag-2.1.0.tgz", "integrity": "sha512-j6vWzfrGVfyXxge+O0x5sh6cvxAog0a/4Rdd2K36zCMV5eJ+/+tOAngRO8cODMNWbVRdVlmGZQL2YS3yR8bIUA==", - "dev": true, "license": "MIT", "dependencies": { "es-errors": "^1.3.0", @@ -2541,6 +2870,19 @@ "ms": "^2.1.1" } }, + "node_modules/eslint-plugin-import/node_modules/json5": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", + "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "dev": true, + "license": "MIT", + "dependencies": { + "minimist": "^1.2.0" + }, + "bin": { + "json5": "lib/cli.js" + } + }, "node_modules/eslint-plugin-import/node_modules/semver": { "version": "6.3.1", "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", @@ -2551,6 +2893,19 @@ "semver": "bin/semver.js" } }, + "node_modules/eslint-plugin-import/node_modules/tsconfig-paths": { + "version": "3.15.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", + "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@types/json5": "^0.0.29", + "json5": "^1.0.2", + "minimist": "^1.2.6", + "strip-bom": "^3.0.0" + } + }, "node_modules/eslint-plugin-jsx-a11y": { "version": "6.10.2", "resolved": "https://registry.npmjs.org/eslint-plugin-jsx-a11y/-/eslint-plugin-jsx-a11y-6.10.2.tgz", @@ -2749,6 +3104,38 @@ "node": ">=0.10.0" } }, + "node_modules/event-target-shim": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz", + "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "license": "MIT", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, "node_modules/fast-deep-equal": { "version": "3.1.3", "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", @@ -2890,11 +3277,44 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/form-data": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.2.tgz", + "integrity": "sha512-hGfm/slu0ZabnNt4oaRZ6uREyfCj6P4fT/n6A1rGV+Z0VdGXjfOhVUpkn6qVQONHGIFwmveGXyDs75+nr6FM8w==", + "license": "MIT", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "es-set-tostringtag": "^2.1.0", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/form-data-encoder": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/form-data-encoder/-/form-data-encoder-1.7.2.tgz", + "integrity": "sha512-qfqtYan3rxrnCk1VYaA4H+Ms9xdpPqvLZa6xmMgFvhO32x7/3J/ExcTd6qpxM0vH2GdMI+poehyBZvqfMTto8A==", + "license": "MIT" + }, + "node_modules/formdata-node": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/formdata-node/-/formdata-node-4.4.1.tgz", + "integrity": "sha512-0iirZp3uVDjVGt9p49aTaqjk84TrglENEDuqfdlZQ1roC9CWlPk6Avf8EEnZNcAqPonwkG35x4n3ww/1THYAeQ==", + "license": "MIT", + "dependencies": { + "node-domexception": "1.0.0", + "web-streams-polyfill": "4.0.0-beta.3" + }, + "engines": { + "node": ">= 12.20" + } + }, "node_modules/function-bind": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", - "dev": true, "license": "MIT", "funding": { "url": "https://github.com/sponsors/ljharb" @@ -2935,7 +3355,6 @@ "version": "1.3.0", "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.3.0.tgz", "integrity": "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ==", - "dev": true, "license": "MIT", "dependencies": { "call-bind-apply-helpers": "^1.0.2", @@ -2960,7 +3379,6 @@ "version": "1.0.1", "resolved": "https://registry.npmjs.org/get-proto/-/get-proto-1.0.1.tgz", "integrity": "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g==", - "dev": true, "license": "MIT", "dependencies": { "dunder-proto": "^1.0.1", @@ -2970,6 +3388,18 @@ "node": ">= 0.4" } }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "license": "MIT", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/get-symbol-description": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/get-symbol-description/-/get-symbol-description-1.1.0.tgz", @@ -3048,7 +3478,6 @@ "version": "1.2.0", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.2.0.tgz", "integrity": "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3120,7 +3549,6 @@ "version": "1.1.0", "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.1.0.tgz", "integrity": "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3133,7 +3561,6 @@ "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz", "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==", - "dev": true, "license": "MIT", "dependencies": { "has-symbols": "^1.0.3" @@ -3149,7 +3576,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", - "dev": true, "license": "MIT", "dependencies": { "function-bind": "^1.1.2" @@ -3158,11 +3584,28 @@ "node": ">= 0.4" } }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "license": "Apache-2.0", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/humanize-ms": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/humanize-ms/-/humanize-ms-1.2.1.tgz", + "integrity": "sha512-Fl70vYtsAFb/C06PTS9dZBo7ihau+Tu/DNCk/OyHhea07S+aeMWpFFkUaXRa8fI+ScZbEI8dfSxwY7gxZ9SAVQ==", + "license": "MIT", + "dependencies": { + "ms": "^2.0.0" + } + }, "node_modules/ignore": { "version": "5.3.2", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.2.tgz", "integrity": "sha512-hsBTNUqQTDwkWtcdYI2i06Y/nUBEsNEDJKjWdigLvegy8kDuJAS8uRlpkkcQpyEXL0Z/pjDy5HBmMjRCJ2gq+g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 4" @@ -3508,6 +3951,18 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-string": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.1.1.tgz", @@ -3616,7 +4071,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true, "license": "ISC" }, "node_modules/iterator.prototype": { @@ -3679,16 +4133,16 @@ "license": "MIT" }, "node_modules/json5": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.2.tgz", - "integrity": "sha512-g1MWMLBiz8FKi1e4w0UyVL3w+iJceWAFBAaBnnGKOpNa5f8TLktkbre1+s6oICydWAm+HRUGTmI+//xv2hvXYA==", + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", "dev": true, "license": "MIT", - "dependencies": { - "minimist": "^1.2.0" - }, "bin": { "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" } }, "node_modules/jsx-ast-utils": { @@ -3787,11 +4241,17 @@ "loose-envify": "cli.js" } }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true, + "license": "ISC" + }, "node_modules/math-intrinsics": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "integrity": "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==", - "dev": true, "license": "MIT", "engines": { "node": ">= 0.4" @@ -3803,6 +4263,12 @@ "integrity": "sha512-ZS4Bp4r/Zoeq6+NLJpP+0Zzm0pR8whtGPf1XExKLJBAczGMnSi3It14OiNCStjQjM6NU1okjQGSxgEZN8eBYKg==", "license": "MIT" }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "license": "MIT" + }, "node_modules/merge2": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", @@ -3827,6 +4293,36 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "license": "MIT", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "license": "MIT", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3910,7 +4406,6 @@ "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", - "dev": true, "license": "MIT" }, "node_modules/nanoid": { @@ -4008,6 +4503,80 @@ } } }, + "node_modules/node-domexception": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/node-domexception/-/node-domexception-1.0.0.tgz", + "integrity": "sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==", + "deprecated": "Use your platform's native DOMException instead", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/jimmywarting" + }, + { + "type": "github", + "url": "https://paypal.me/jimmywarting" + } + ], + "license": "MIT", + "engines": { + "node": ">=10.5.0" + } + }, + "node_modules/node-fetch": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.7.0.tgz", + "integrity": "sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A==", + "license": "MIT", + "dependencies": { + "whatwg-url": "^5.0.0" + }, + "engines": { + "node": "4.x || >=6.0.0" + }, + "peerDependencies": { + "encoding": "^0.1.0" + }, + "peerDependenciesMeta": { + "encoding": { + "optional": true + } + } + }, + "node_modules/node-fetch/node_modules/tr46": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz", + "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==", + "license": "MIT" + }, + "node_modules/node-fetch/node_modules/webidl-conversions": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz", + "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==", + "license": "BSD-2-Clause" + }, + "node_modules/node-fetch/node_modules/whatwg-url": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz", + "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==", + "license": "MIT", + "dependencies": { + "tr46": "~0.0.3", + "webidl-conversions": "^3.0.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "license": "MIT", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/object-assign": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", @@ -4041,6 +4610,15 @@ "node": ">= 0.4" } }, + "node_modules/object-treeify": { + "version": "1.1.33", + "resolved": "https://registry.npmjs.org/object-treeify/-/object-treeify-1.1.33.tgz", + "integrity": "sha512-EFVjAYfzWqWsBMRHPMAXLCDIJnpMhdWAqR7xG6M6a2cs6PMFpl/+Z20w9zDW4vkxOFfddegBKq9Rehd0bxWE7A==", + "license": "MIT", + "engines": { + "node": ">= 10" + } + }, "node_modules/object.assign": { "version": "4.1.7", "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.7.tgz", @@ -4131,6 +4709,66 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "license": "MIT", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/openai": { + "version": "4.100.0", + "resolved": "https://registry.npmjs.org/openai/-/openai-4.100.0.tgz", + "integrity": "sha512-9soq/wukv3utxcuD7TWFqKdKp0INWdeyhUCvxwrne5KwnxaCp4eHL4GdT/tMFhYolxgNhxFzg5GFwM331Z5CZg==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + }, + "bin": { + "openai": "bin/cli" + }, + "peerDependencies": { + "ws": "^8.18.0", + "zod": "^3.23.8" + }, + "peerDependenciesMeta": { + "ws": { + "optional": true + }, + "zod": { + "optional": true + } + } + }, + "node_modules/openai/node_modules/@types/node": { + "version": "18.19.101", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.101.tgz", + "integrity": "sha512-Ykg7fcE3+cOQlLUv2Ds3zil6DVjriGQaSN/kEpl5HQ3DIGM6W0F2n9+GkWV4bRt7KjLymgzNdTnSKCbFUUJ7Kw==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, + "node_modules/openai/node_modules/undici-types": { + "version": "5.26.5", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", + "license": "MIT" + }, "node_modules/optionator": { "version": "0.9.4", "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.4.tgz", @@ -4226,7 +4864,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4664,7 +5301,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "license": "MIT", "dependencies": { "shebang-regex": "^3.0.0" @@ -4677,7 +5313,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "license": "MIT", "engines": { "node": ">=8" @@ -4759,6 +5394,12 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "license": "ISC" + }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", @@ -4925,6 +5566,15 @@ "node": ">=4" } }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/strip-json-comments": { "version": "3.1.1", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", @@ -5070,17 +5720,63 @@ "typescript": ">=4.8.4" } }, - "node_modules/tsconfig-paths": { - "version": "3.15.0", - "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-3.15.0.tgz", - "integrity": "sha512-2Ac2RgzDe/cn48GvOe3M+o82pEFewD3UPbyoUHHdKasHwJKjds4fLXWf/Ux5kATBKN20oaFGu+jbElp1pos0mg==", + "node_modules/ts-node": { + "version": "10.9.2", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz", + "integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==", "dev": true, "license": "MIT", "dependencies": { - "@types/json5": "^0.0.29", - "json5": "^1.0.2", + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tsconfig-paths": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz", + "integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==", + "dev": true, + "license": "MIT", + "dependencies": { + "json5": "^2.2.2", "minimist": "^1.2.6", "strip-bom": "^3.0.0" + }, + "engines": { + "node": ">=6" } }, "node_modules/tslib": { @@ -5217,7 +5913,6 @@ "version": "6.19.8", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz", "integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw==", - "dev": true, "license": "MIT" }, "node_modules/unrs-resolver": { @@ -5263,6 +5958,22 @@ "punycode": "^2.1.0" } }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true, + "license": "MIT" + }, + "node_modules/web-streams-polyfill": { + "version": "4.0.0-beta.3", + "resolved": "https://registry.npmjs.org/web-streams-polyfill/-/web-streams-polyfill-4.0.0-beta.3.tgz", + "integrity": "sha512-QW95TCTaHmsYfHDybGMwO5IJIM93I/6vTRk+daHTWFPhwh+C8Cg7j7XyKrwrj8Ib6vYXe0ocYNrmzY4xAAN6ug==", + "license": "MIT", + "engines": { + "node": ">= 14" + } + }, "node_modules/webidl-conversions": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-7.0.0.tgz", @@ -5289,7 +6000,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "license": "ISC", "dependencies": { "isexe": "^2.0.0" @@ -5400,6 +6110,16 @@ "node": ">=0.10.0" } }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/yocto-queue": { "version": "0.1.0", "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", diff --git a/package.json b/package.json index 16f06e6..29fd24c 100644 --- a/package.json +++ b/package.json @@ -9,9 +9,12 @@ "lint": "next lint" }, "dependencies": { + "@dotenvx/dotenvx": "^1.44.1", "@heroicons/react": "^2.2.0", + "dotenv": "^16.5.0", "mongodb": "^6.16.0", "next": "15.3.2", + "openai": "^4.100.0", "react": "^19.0.0", "react-dom": "^19.0.0" }, @@ -22,6 +25,8 @@ "@types/react-dom": "^19", "eslint": "^9", "eslint-config-next": "15.3.2", + "ts-node": "^10.9.2", + "tsconfig-paths": "^4.2.0", "typescript": "^5" } } diff --git a/public/file.svg b/public/file.svg deleted file mode 100644 index 004145c..0000000 --- a/public/file.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/globe.svg b/public/globe.svg deleted file mode 100644 index 567f17b..0000000 --- a/public/globe.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/index.php b/public/index.php new file mode 100644 index 0000000..f98ffae --- /dev/null +++ b/public/index.php @@ -0,0 +1,9 @@ + \ No newline at end of file diff --git a/public/vercel.svg b/public/vercel.svg deleted file mode 100644 index 7705396..0000000 --- a/public/vercel.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/public/window.svg b/public/window.svg deleted file mode 100644 index b2b2a44..0000000 --- a/public/window.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src/Application/Controller/HomeController.php b/src/Application/Controller/HomeController.php new file mode 100644 index 0000000..1d1ad15 --- /dev/null +++ b/src/Application/Controller/HomeController.php @@ -0,0 +1,24 @@ +render('home/index.html.twig', [ + 'brands' => $this->brandRepository->findAll()->array(), + ]); + } +} \ No newline at end of file diff --git a/src/Application/Controller/SearchController.php b/src/Application/Controller/SearchController.php new file mode 100644 index 0000000..25b294f --- /dev/null +++ b/src/Application/Controller/SearchController.php @@ -0,0 +1,27 @@ +render('result/index.html.twig', [ + 'tiles' => $this->engine->search($decodedQuery)->array(), + 'query' => $decodedQuery, + ]); + } +} \ No newline at end of file diff --git a/src/Application/Twig/InstanceOfTwigExtension.php b/src/Application/Twig/InstanceOfTwigExtension.php new file mode 100644 index 0000000..78b9271 --- /dev/null +++ b/src/Application/Twig/InstanceOfTwigExtension.php @@ -0,0 +1,23 @@ +getShortName(); + } +} \ No newline at end of file diff --git a/src/Domain/Model/Brand.php b/src/Domain/Model/Brand.php new file mode 100644 index 0000000..783b0f8 --- /dev/null +++ b/src/Domain/Model/Brand.php @@ -0,0 +1,17 @@ +brands; + } +} \ No newline at end of file diff --git a/src/Domain/Model/CarModel.php b/src/Domain/Model/CarModel.php new file mode 100644 index 0000000..4580301 --- /dev/null +++ b/src/Domain/Model/CarModel.php @@ -0,0 +1,24 @@ +getUnitOfWork(), $dm->getClassMetadata(CarModel::class)); + } + + public function findAllCarModels(): array + { + return $this->createQueryBuilder() + ->sort('name', 'asc') + ->getQuery() + ->execute() + ->toArray(); + } + + public function findCarModelById(string $id): ?CarModel + { + return $this->find($id); + } + + public function findCarModelsByBrandId(string $brandId): array + { + return $this->createQueryBuilder() + ->field('brand.$id')->equals(new \MongoDB\BSON\ObjectId($brandId)) + ->sort('name', 'asc') + ->getQuery() + ->execute() + ->toArray(); + } + + public function findCarModelsByName(string $name): array + { + return $this->createQueryBuilder() + ->field('name')->equals(new \MongoDB\BSON\Regex($name, 'i')) + ->sort('name', 'asc') + ->getQuery() + ->execute() + ->toArray(); + } + + public function findCarModelsByCategory(string $category): array + { + return $this->createQueryBuilder() + ->field('category')->equals($category) + ->sort('name', 'asc') + ->getQuery() + ->execute() + ->toArray(); + } + + public function findCarModelsByYearRange(int $startYear, int $endYear): array + { + return $this->createQueryBuilder() + ->field('productionStartYear')->gte($startYear) + ->field('productionStartYear')->lte($endYear) + ->sort('productionStartYear', 'asc') + ->getQuery() + ->execute() + ->toArray(); + } + + public function searchCarModels(string $query): array + { + $regex = new \MongoDB\BSON\Regex($query, 'i'); + + return $this->createQueryBuilder() + ->addOr( + $this->createQueryBuilder()->field('name')->equals($regex)->getQueryArray(), + $this->createQueryBuilder()->field('description')->equals($regex)->getQueryArray(), + $this->createQueryBuilder()->field('category')->equals($regex)->getQueryArray() + ) + ->sort('name', 'asc') + ->getQuery() + ->execute() + ->toArray(); + } + + public function saveCarModel(CarModel $carModel): void + { + $this->getDocumentManager()->persist($carModel); + $this->getDocumentManager()->flush(); + } + + public function deleteCarModel(CarModel $carModel): void + { + $this->getDocumentManager()->remove($carModel); + $this->getDocumentManager()->flush(); + } +} \ No newline at end of file diff --git a/src/Domain/Search/Engine.php b/src/Domain/Search/Engine.php new file mode 100644 index 0000000..95b8524 --- /dev/null +++ b/src/Domain/Search/Engine.php @@ -0,0 +1,18 @@ +tiles; + } +} \ No newline at end of file diff --git a/src/Domain/Search/Tiles/Brand.php b/src/Domain/Search/Tiles/Brand.php new file mode 100644 index 0000000..008773d --- /dev/null +++ b/src/Domain/Search/Tiles/Brand.php @@ -0,0 +1,11 @@ + $this->client->selectDatabase($this->databaseName); + } + + public function __construct( + private readonly string $dsl, + private readonly string $databaseName, + ) { + $this->client = new Client($this->dsl); + } +} \ No newline at end of file diff --git a/src/Infrastructure/MongoDB/Repository/BrandRepository/ModelMapper.php b/src/Infrastructure/MongoDB/Repository/BrandRepository/ModelMapper.php new file mode 100644 index 0000000..bc6db55 --- /dev/null +++ b/src/Infrastructure/MongoDB/Repository/BrandRepository/ModelMapper.php @@ -0,0 +1,27 @@ +client->database->selectCollection('brands')->find(); + $brands = []; + + $mapper = new ModelMapper(); + + /** @var \MongoDB\Model\BSONDocument $brand */ + foreach ($result as $brand) { + $brands[] = $mapper->map($brand->getArrayCopy()); + } + + return new BrandCollection($brands); + } +} \ No newline at end of file diff --git a/src/Kernel.php b/src/Kernel.php new file mode 100644 index 0000000..1843435 --- /dev/null +++ b/src/Kernel.php @@ -0,0 +1,11 @@ + -
-

Popular brands

-
- { - e.currentTarget.style.backgroundColor = '#edae49'; - e.currentTarget.style.color = '#2e4057'; - }} - onMouseOut={(e) => { - e.currentTarget.style.backgroundColor = 'white'; - e.currentTarget.style.color = '#083d77'; - }} - >Tesla - { - e.currentTarget.style.backgroundColor = '#edae49'; - e.currentTarget.style.color = '#2e4057'; - }} - onMouseOut={(e) => { - e.currentTarget.style.backgroundColor = 'white'; - e.currentTarget.style.color = '#083d77'; - }} - >BMW - { - e.currentTarget.style.backgroundColor = '#edae49'; - e.currentTarget.style.color = '#2e4057'; - }} - onMouseOut={(e) => { - e.currentTarget.style.backgroundColor = 'white'; - e.currentTarget.style.color = '#083d77'; - }} - >Toyota - { - e.currentTarget.style.backgroundColor = '#edae49'; - e.currentTarget.style.color = '#2e4057'; - }} - onMouseOut={(e) => { - e.currentTarget.style.backgroundColor = 'white'; - e.currentTarget.style.color = '#083d77'; - }} - >Audi - { - e.currentTarget.style.backgroundColor = '#edae49'; - e.currentTarget.style.color = '#2e4057'; - }} - onMouseOut={(e) => { - e.currentTarget.style.backgroundColor = 'white'; - e.currentTarget.style.color = '#083d77'; - }} - >Mercedes -
- - ); -} \ No newline at end of file diff --git a/src/app/components/SearchBar.tsx b/src/app/components/SearchBar.tsx deleted file mode 100644 index 972b3b6..0000000 --- a/src/app/components/SearchBar.tsx +++ /dev/null @@ -1,103 +0,0 @@ -'use client'; - -import { useState, FormEvent } from 'react'; -import { useRouter } from 'next/navigation'; - -type SearchBarProps = { - initialQuery?: string; -}; - -export default function SearchBar({ initialQuery = '' }: SearchBarProps) { - const [query, setQuery] = useState(initialQuery); - const router = useRouter(); - - const handleSubmit = (e: FormEvent) => { - e.preventDefault(); - - if (query.trim()) { - router.push(`/results?query=${encodeURIComponent(query)}`); - } - }; - - const styles = { - searchContainer: { - width: '100%', - maxWidth: '42rem', - margin: '0 auto 1.5rem' - }, - searchForm: { - display: 'flex', - width: '100%', - position: 'relative' - }, - searchInput: { - width: '100%', - padding: '1.2rem 1.5rem', - fontSize: '1.2rem', - border: '2px solid transparent', - borderRadius: '30px', - boxShadow: '0 4px 12px rgba(0, 0, 0, 0.1)', - outline: 'none', - transition: 'all 0.3s ease', - backgroundColor: 'white', - color: '#2e4057' - }, - searchButton: { - position: 'absolute', - right: '12px', - top: '50%', - transform: 'translateY(-50%)', - width: '45px', - height: '45px', - backgroundColor: 'transparent', - color: '#083d77', - border: 'none', - borderRadius: '50%', - cursor: 'pointer', - transition: 'all 0.2s ease', - display: 'flex', - alignItems: 'center', - justifyContent: 'center' - } - } as const; - - return ( -
-
- setQuery(e.target.value)} - placeholder="Search for electric vehicles..." - style={styles.searchInput} - aria-label="Search for electric vehicles" - onFocus={(e) => { - e.target.style.boxShadow = '0 6px 16px rgba(8, 61, 119, 0.2)'; - e.target.style.borderColor = '#083d77'; - }} - onBlur={(e) => { - e.target.style.boxShadow = '0 4px 12px rgba(0, 0, 0, 0.1)'; - e.target.style.borderColor = 'transparent'; - }} - /> - -
-
- ); -} \ No newline at end of file diff --git a/src/app/favicon.ico b/src/app/favicon.ico deleted file mode 100644 index 718d6fe..0000000 Binary files a/src/app/favicon.ico and /dev/null differ diff --git a/src/app/globals.css b/src/app/globals.css deleted file mode 100644 index d44bd94..0000000 --- a/src/app/globals.css +++ /dev/null @@ -1,50 +0,0 @@ -:root { - --color-sunset: #F6D8AE; - --color-charcoal: #2E4057; - --color-yale-blue: #083D77; - --color-cerise: #DA4167; - --color-naples-yellow: #F4D35E; - - /* Neutral background colors */ - --color-light-neutral: #F5F5F5; - --color-dark-neutral: #1F1F1F; - - --background: var(--color-light-neutral); - --foreground: var(--color-charcoal); -} - -html, -body { - max-width: 100vw; - overflow-x: hidden; -} - -body { - background: var(--background); - color: var(--foreground); - font-family: Arial, Helvetica, sans-serif; - -webkit-font-smoothing: antialiased; - -moz-osx-font-smoothing: grayscale; -} - -* { - box-sizing: border-box; - padding: 0; - margin: 0; -} - -a { - color: inherit; - text-decoration: none; -} - -@media (prefers-color-scheme: dark) { - html { - color-scheme: dark; - } -} - -.button-primary { - background: var(--color-yale-blue); - color: #fff; -} diff --git a/src/app/home.module.css b/src/app/home.module.css deleted file mode 100644 index 24eb7df..0000000 --- a/src/app/home.module.css +++ /dev/null @@ -1,180 +0,0 @@ -/* Home page specific styles */ -.container { - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 2rem; - background: linear-gradient(135deg, var(--background), rgba(8, 61, 119, 0.05)); -} - -.title { - font-size: 3.5rem; - font-weight: 800; - margin-bottom: 2.5rem; - text-align: center; - letter-spacing: -1px; - animation: fadeIn 0.8s ease-in-out; -} - -.gradientText { - background: linear-gradient(90deg, - var(--color-yale-blue) 0%, - var(--color-charcoal) 35%, - var(--color-cerise) 100%); - -webkit-background-clip: text; - background-clip: text; - -webkit-text-fill-color: transparent; - display: inline-block; -} - -@keyframes fadeIn { - from { opacity: 0; transform: translateY(-20px); } - to { opacity: 1; transform: translateY(0); } -} - -.searchContainer { - width: 100%; - max-width: 42rem; - margin-bottom: 2.5rem; - animation: scaleIn 0.5s ease-in-out; - animation-delay: 0.3s; - animation-fill-mode: both; -} - -@keyframes scaleIn { - from { opacity: 0; transform: scale(0.95); } - to { opacity: 1; transform: scale(1); } -} - -.searchForm { - display: flex; - width: 100%; - position: relative; -} - -.searchInput { - width: 100%; - padding: 1.2rem 1.5rem; - font-size: 1.2rem; - border: 2px solid transparent; - border-radius: 30px; - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); - outline: none; - transition: all 0.3s ease; - background-color: white; - color: var(--color-charcoal); -} - -.searchInput:focus { - box-shadow: 0 6px 16px rgba(8, 61, 119, 0.2); - border-color: var(--color-yale-blue); -} - -.searchInput::placeholder { - color: rgba(46, 64, 87, 0.5); -} - -.searchButton { - position: absolute; - right: 5px; - top: 5px; - bottom: 5px; - padding: 0 1.8rem; - background-color: var(--color-yale-blue); - color: white; - border: none; - border-radius: 25px; - font-size: 1.1rem; - font-weight: 600; - cursor: pointer; - transition: all 0.2s ease; - display: flex; - align-items: center; - justify-content: center; -} - -.searchButton:hover { - background-color: var(--color-charcoal); -} - -.card { - width: 100%; - max-width: 42rem; - background-color: white; - padding: 2rem; - border-radius: 0.5rem; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); -} - -.subtitle { - font-size: 1.5rem; - font-weight: 600; - margin-bottom: 1.5rem; - color: var(--foreground); -} - -.form { - display: flex; - flex-direction: column; - gap: 1rem; -} - -.yearGrid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 1rem; -} - -.brandSection { - margin-top: 2rem; - text-align: center; - color: var(--color-charcoal); - animation: fadeIn 0.5s ease-in-out; - animation-delay: 0.6s; - animation-fill-mode: both; - position: relative; -} - -.brandSection::before { - content: ''; - position: absolute; - top: -15px; - left: 50%; - transform: translateX(-50%); - width: 50px; - height: 3px; - background-color: var(--color-naples-yellow); - border-radius: 3px; -} - -.brandSection p { - font-weight: 600; - margin-bottom: 0.8rem; - font-size: 1.1rem; -} - -.brandList { - margin-top: 0.8rem; - display: flex; - justify-content: center; - flex-wrap: wrap; - gap: 1.2rem; -} - -.brandLink { - color: var(--color-yale-blue); - text-decoration: none; - font-weight: 500; - padding: 0.5rem 1rem; - border-radius: 20px; - transition: all 0.2s ease; - background-color: white; - border: 1px solid rgba(8, 61, 119, 0.1); -} - -.brandLink:hover { - background-color: var(--color-sunset); - color: var(--color-charcoal); -} \ No newline at end of file diff --git a/src/app/layout.tsx b/src/app/layout.tsx deleted file mode 100644 index adb04af..0000000 --- a/src/app/layout.tsx +++ /dev/null @@ -1,33 +0,0 @@ -import type { Metadata } from "next"; -import { Geist, Geist_Mono } from "next/font/google"; -import "./globals.css"; -import "./components.css"; - -const geistSans = Geist({ - variable: "--font-geist-sans", - subsets: ["latin"], -}); - -const geistMono = Geist_Mono({ - variable: "--font-geist-mono", - subsets: ["latin"], -}); - -export const metadata: Metadata = { - title: "EV WIKI", - description: "Modern search engine for electric vehicle information", -}; - -export default function RootLayout({ - children, -}: Readonly<{ - children: React.ReactNode; -}>) { - return ( - - - {children} - - - ); -} diff --git a/src/app/page.module.css b/src/app/page.module.css deleted file mode 100644 index 0670dbb..0000000 --- a/src/app/page.module.css +++ /dev/null @@ -1,471 +0,0 @@ -.page { - --gray-rgb: 0, 0, 0; - --gray-alpha-200: rgba(var(--gray-rgb), 0.08); - --gray-alpha-100: rgba(var(--gray-rgb), 0.05); - - --button-primary-hover: #383838; - --button-secondary-hover: #f2f2f2; - - display: grid; - grid-template-rows: 20px 1fr 20px; - align-items: center; - justify-items: center; - min-height: 100svh; - padding: 80px; - gap: 64px; - font-family: var(--font-geist-sans); -} - -@media (prefers-color-scheme: dark) { - .page { - --gray-rgb: 255, 255, 255; - --gray-alpha-200: rgba(var(--gray-rgb), 0.145); - --gray-alpha-100: rgba(var(--gray-rgb), 0.06); - - --button-primary-hover: #ccc; - --button-secondary-hover: #1a1a1a; - } -} - -.main { - display: flex; - flex-direction: column; - gap: 32px; - grid-row-start: 2; -} - -.main ol { - font-family: var(--font-geist-mono); - padding-left: 0; - margin: 0; - font-size: 14px; - line-height: 24px; - letter-spacing: -0.01em; - list-style-position: inside; -} - -.main li:not(:last-of-type) { - margin-bottom: 8px; -} - -.main code { - font-family: inherit; - background: var(--gray-alpha-100); - padding: 2px 4px; - border-radius: 4px; - font-weight: 600; -} - -.ctas { - display: flex; - gap: 16px; -} - -.ctas a { - appearance: none; - border-radius: 128px; - height: 48px; - padding: 0 20px; - border: none; - border: 1px solid transparent; - transition: - background 0.2s, - color 0.2s, - border-color 0.2s; - cursor: pointer; - display: flex; - align-items: center; - justify-content: center; - font-size: 16px; - line-height: 20px; - font-weight: 500; -} - -a.primary { - background: var(--foreground); - color: var(--background); - gap: 8px; -} - -a.secondary { - border-color: var(--gray-alpha-200); - min-width: 158px; -} - -.footer { - grid-row-start: 3; - display: flex; - gap: 24px; -} - -.footer a { - display: flex; - align-items: center; - gap: 8px; -} - -.footer img { - flex-shrink: 0; -} - -/* Enable hover only on non-touch devices */ -@media (hover: hover) and (pointer: fine) { - a.primary:hover { - background: var(--button-primary-hover); - border-color: transparent; - } - - a.secondary:hover { - background: var(--button-secondary-hover); - border-color: transparent; - } - - .footer a:hover { - text-decoration: underline; - text-underline-offset: 4px; - } -} - -@media (max-width: 600px) { - .page { - padding: 32px; - padding-bottom: 80px; - } - - .main { - align-items: center; - } - - .main ol { - text-align: center; - } - - .ctas { - flex-direction: column; - } - - .ctas a { - font-size: 14px; - height: 40px; - padding: 0 16px; - } - - a.secondary { - min-width: auto; - } - - .footer { - flex-wrap: wrap; - align-items: center; - justify-content: center; - } -} - -@media (prefers-color-scheme: dark) { - .logo { - filter: invert(); - } -} - -.searchPage { - display: flex; - flex-direction: column; - min-height: 100vh; - align-items: center; - justify-content: space-between; - font-family: var(--font-geist-sans); - background: var(--background); - color: var(--foreground); -} - -.searchMain { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - flex: 1; - width: 100%; - max-width: 800px; - padding: 0 24px; -} - -.logoContainer { - margin-bottom: 36px; - text-align: center; -} - -.logo { - font-size: 4rem; - font-weight: 700; - letter-spacing: -1px; - background: linear-gradient(to right, var(--color-yale-blue), var(--color-cerise)); - -webkit-background-clip: text; - background-clip: text; - color: transparent; - margin: 0; -} - -.searchContainer { - width: 100%; - max-width: 600px; - margin-bottom: 24px; -} - -.searchBox { - display: flex; - width: 100%; - position: relative; - border-radius: 24px; - background: #fff; - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.1); - overflow: hidden; - transition: box-shadow 0.3s ease; -} - -.searchBox:hover, .searchBox:focus-within { - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.15); -} - -.searchInput { - flex: 1; - height: 48px; - padding: 0 16px; - font-size: 16px; - border: none; - outline: none; - background: transparent; - color: #333; -} - -.searchButton { - display: flex; - align-items: center; - justify-content: center; - padding: 0 16px; - background: none; - border: none; - cursor: pointer; - color: var(--color-yale-blue); - transition: color 0.3s ease; -} - -.searchButton:hover { - color: var(--color-cerise); -} - -.searchIcon { - width: 24px; - height: 24px; -} - -.suggestionsContainer { - display: flex; - flex-wrap: wrap; - justify-content: center; - gap: 8px; - margin-top: 12px; -} - -.suggestionChip { - padding: 8px 16px; - background: rgba(8, 61, 119, 0.08); - border: 1px solid rgba(8, 61, 119, 0.15); - border-radius: 20px; - font-size: 14px; - font-weight: 500; - color: var(--foreground); - cursor: pointer; - transition: all 0.2s ease; -} - -.suggestionChip:hover { - background: var(--color-yale-blue); - color: white; - border-color: var(--color-yale-blue); -} - -.searchFooter { - width: 100%; - padding: 16px 0; - border-top: 1px solid rgba(var(--gray-rgb), 0.1); - font-size: 14px; -} - -.footerLinks { - display: flex; - justify-content: center; - gap: 24px; -} - -.footerLinks a { - color: var(--foreground); - opacity: 0.8; - transition: opacity 0.2s ease; -} - -.footerLinks a:hover { - opacity: 1; - text-decoration: underline; -} - -@media (max-width: 600px) { - .logo { - font-size: 3rem; - } - - .searchBox { - border-radius: 20px; - } - - .searchInput { - height: 44px; - } - - .suggestionsContainer { - flex-direction: column; - align-items: center; - } - - .suggestionChip { - width: 100%; - max-width: 280px; - text-align: center; - } - - .footerLinks { - flex-wrap: wrap; - gap: 16px; - justify-content: center; - } -} - -@media (prefers-color-scheme: dark) { - .searchBox { - background: rgba(255, 255, 255, 0.05); - box-shadow: 0 2px 5px rgba(0, 0, 0, 0.2); - } - - .searchBox:hover, .searchBox:focus-within { - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); - } - - .searchInput { - color: var(--foreground); - } - - .searchButton { - color: var(--color-yale-blue); - } - - .searchButton:hover { - color: var(--color-cerise); - } - - .suggestionChip { - background: rgba(255, 255, 255, 0.07); - border: 1px solid rgba(255, 255, 255, 0.15); - } -} - -.pageContainer { - min-height: 100vh; - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 2rem; - background-color: #f9fafb; -} - -.mainTitle { - font-size: 2.5rem; - font-weight: bold; - margin-bottom: 2rem; -} - -.searchCard { - width: 100%; - max-width: 40rem; - background-color: white; - padding: 2rem; - border-radius: 0.5rem; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); -} - -.cardTitle { - font-size: 1.5rem; - font-weight: 600; - margin-bottom: 1.5rem; -} - -.formGroup { - margin-bottom: 1rem; -} - -.label { - display: block; - font-size: 0.875rem; - font-weight: 500; - color: #4b5563; - margin-bottom: 0.25rem; -} - -.input, -.select { - width: 100%; - padding: 0.5rem 1rem; - border: 1px solid #d1d5db; - border-radius: 0.375rem; - font-size: 1rem; -} - -.input:focus, -.select:focus { - outline: none; - border-color: #3b82f6; - box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1); -} - -.yearGrid { - display: grid; - grid-template-columns: 1fr 1fr; - gap: 1rem; -} - -.button { - width: 100%; - background-color: #3b82f6; - color: white; - padding: 0.5rem 1rem; - border: none; - border-radius: 0.375rem; - font-size: 1rem; - font-weight: 500; - cursor: pointer; - transition: background-color 0.2s; -} - -.button:hover { - background-color: #2563eb; -} - -.brandSection { - margin-top: 1.5rem; - text-align: center; - color: #6b7280; -} - -.brandList { - margin-top: 0.5rem; - display: flex; - justify-content: center; - gap: 1rem; -} - -.brandLink { - color: #3b82f6; -} - -.brandLink:hover { - text-decoration: underline; -} diff --git a/src/app/page.tsx b/src/app/page.tsx deleted file mode 100644 index 12829d6..0000000 --- a/src/app/page.tsx +++ /dev/null @@ -1,38 +0,0 @@ -'use client'; - -import SearchBar from './components/SearchBar'; -import BrandList from './components/BrandList'; - -export default function Home() { - const styles = { - container: { - minHeight: '100vh', - display: 'flex', - flexDirection: 'column', - alignItems: 'center', - justifyContent: 'center', - padding: '2rem', - background: 'linear-gradient(135deg, #ffffff, rgba(8, 61, 119, 0.05))' - }, - title: { - fontSize: '3.5rem', - fontWeight: '800', - marginBottom: '2.5rem', - textAlign: 'center', - letterSpacing: '-1px', - background: 'linear-gradient(90deg, #083d77 0%, #2e4057 35%, #d1495b 100%)', - WebkitBackgroundClip: 'text', - backgroundClip: 'text', - WebkitTextFillColor: 'transparent', - display: 'inline-block' - } - } as const; - - return ( -
-

E-WIKI

- - -
- ); -} diff --git a/src/app/results/page.tsx b/src/app/results/page.tsx deleted file mode 100644 index 8236f64..0000000 --- a/src/app/results/page.tsx +++ /dev/null @@ -1,228 +0,0 @@ -'use client'; - -import { useEffect, useState } from 'react'; -import { useSearchParams } from 'next/navigation'; -import { CarService } from '../services/carService'; -import { CarModel, CarRevision, Brand } from '../../backend/models'; -import SearchBar from '../components/SearchBar'; -import styles from './results.module.css'; - -// Extended interfaces for the frontend display -interface DisplayCarModel extends CarModel { - brand?: { - name: string; - }; -} - -interface DisplayCarRevision extends CarRevision { - baseModel?: { - brand?: { - name: string; - }; - }; -} - -export default function Results() { - const searchParams = useSearchParams(); - const [loading, setLoading] = useState(true); - const [models, setModels] = useState([]); - const [revisions, setRevisions] = useState([]); - const [error, setError] = useState(null); - const query = searchParams.get('query') || ''; - - useEffect(() => { - const fetchResults = async () => { - try { - setLoading(true); - setError(null); - - const query = searchParams.get('query') || ''; - const category = searchParams.get('category') || ''; - const startYear = searchParams.get('startYear'); - const endYear = searchParams.get('endYear'); - const brandId = searchParams.get('brand'); - - let results; - - if (brandId) { - // Handle brand-specific search (if implemented in CarService) - const response = await fetch(`/api/cars/brand/${brandId}`); - if (!response.ok) throw new Error('Failed to fetch brand models'); - results = await response.json(); - } else if (category) { - results = await CarService.searchByCategory(category); - } else if (startYear && endYear) { - results = await CarService.searchByYearRange( - parseInt(startYear), - parseInt(endYear) - ); - } else { - results = await CarService.searchByQuery(query); - } - - setModels(results.models || []); - setRevisions(results.revisions || []); - } catch (err) { - console.error('Error fetching search results:', err); - setError('Failed to load search results. Please try again.'); - } finally { - setLoading(false); - } - }; - - fetchResults(); - }, [searchParams]); - - // Helper function to generate a unique key - const getModelKey = (model: DisplayCarModel) => { - return model._id?.toString() || model.id || `model-${model.name}-${model.productionStartYear}`; - }; - - const getRevisionKey = (revision: DisplayCarRevision) => { - return revision._id?.toString() || revision.id || `revision-${revision.name}-${revision.releaseYear}`; - }; - - return ( -
-
- - - {loading ? ( -
-
-
- ) : error ? ( -
- {error} -
- ) : models.length === 0 && revisions.length === 0 ? ( -
-

No results found

-

- Try adjusting your search criteria to find more cars. -

-
- ) : ( -
- {models.length > 0 && ( -
-

Car Models

-
- {models.map((model) => ( -
-
- {model.image ? ( - {model.name} - ) : ( -
- No image available -
- )} -
-
-
-

{model.name}

- - {model.brand?.name} - -
-

{model.description}

-
- - {model.category} - - - Since {model.productionStartYear} - {model.productionEndYear - ? ` - ${model.productionEndYear}` - : ''} - -
-
-
- ))} -
-
- )} - - {revisions.length > 0 && ( -
-

Car Revisions

-
- {revisions.map((revision) => ( -
-
- {revision.images && revision.images.length > 0 ? ( - {revision.name} - ) : ( -
- No image available -
- )} -
-
-
-

{revision.name}

- - {revision.baseModel?.brand?.name} - -
-
-
- Engine: - {revision.engineTypes?.join(', ')} -
-
- Power: - {revision.horsePower} HP -
-
- 0-100 km/h: - {revision.acceleration0To100}s -
-
- Top Speed: - {revision.topSpeed} km/h -
-
-
- {revision.features?.slice(0, 3).map((feature, index) => ( - - {feature} - - ))} - {revision.features && revision.features.length > 3 && ( - - +{revision.features.length - 3} more - - )} -
-
-
- ))} -
-
- )} -
- )} -
-
- ); -} \ No newline at end of file diff --git a/src/app/results/results.module.css b/src/app/results/results.module.css deleted file mode 100644 index b1b13a4..0000000 --- a/src/app/results/results.module.css +++ /dev/null @@ -1,238 +0,0 @@ -/* Results page specific styles */ -.container { - min-height: 100vh; - background: linear-gradient(135deg, var(--background), rgba(8, 61, 119, 0.05)); - padding: 2rem; -} - -.header { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 2rem; - max-width: 1200px; - margin: 0 auto 2rem; -} - -.title { - font-size: 2.5rem; - font-weight: 700; - color: var(--color-charcoal); -} - -.backButton { - background-color: var(--color-yale-blue); - color: white; - padding: 0.6rem 1.2rem; - border-radius: 25px; - text-decoration: none; - font-weight: 600; - transition: all 0.2s ease; - display: inline-flex; - align-items: center; -} - -.backButton:hover { - background-color: var(--color-charcoal); -} - -.content { - max-width: 1200px; - margin: 0 auto; -} - -.loader { - display: flex; - justify-content: center; - align-items: center; - padding: 3rem 0; -} - -.spinner { - width: 3rem; - height: 3rem; - border: 0.25rem solid rgba(8, 61, 119, 0.1); - border-top: 0.25rem solid var(--color-yale-blue); - border-radius: 50%; - animation: spin 1s linear infinite; -} - -@keyframes spin { - 0% { transform: rotate(0deg); } - 100% { transform: rotate(360deg); } -} - -.errorMessage { - background-color: #fde8e8; - border: 1px solid #f8b4b4; - color: #9b1c1c; - padding: 1rem; - border-radius: 0.5rem; - text-align: center; -} - -.noResults { - background-color: white; - padding: 2rem; - border-radius: 0.5rem; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); - text-align: center; -} - -.emptyResults { - text-align: center; - padding: 2rem 0; -} - -.noResultsTitle { - font-size: 1.5rem; - font-weight: 600; - margin-bottom: 1rem; - color: var(--color-charcoal); -} - -.noResultsText { - color: #4b5563; -} - -.sectionTitle { - font-size: 1.8rem; - font-weight: 600; - margin-bottom: 1.5rem; - color: var(--color-charcoal); -} - -.sectionContent { - margin-bottom: 2.5rem; -} - -.grid { - display: grid; - grid-template-columns: repeat(1, 1fr); - gap: 1.5rem; -} - -@media (min-width: 768px) { - .grid { - grid-template-columns: repeat(2, 1fr); - } -} - -@media (min-width: 1024px) { - .grid { - grid-template-columns: repeat(3, 1fr); - } -} - -.card { - background-color: white; - border-radius: 0.5rem; - box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1); - overflow: hidden; - transition: transform 0.2s ease, box-shadow 0.2s ease; -} - -.card:hover { - transform: translateY(-4px); - box-shadow: 0 10px 15px rgba(0, 0, 0, 0.1); -} - -.cardImage { - height: 12rem; - background-color: #f3f4f6; - position: relative; -} - -.image { - width: 100%; - height: 100%; - object-fit: cover; -} - -.noImage { - display: flex; - align-items: center; - justify-content: center; - height: 100%; - color: #6b7280; -} - -.cardContent { - padding: 1rem; -} - -.cardHeader { - display: flex; - align-items: center; - justify-content: space-between; - margin-bottom: 0.5rem; -} - -.cardTitle { - font-size: 1.25rem; - font-weight: 700; - color: var(--color-charcoal); -} - -.brandName { - font-size: 0.875rem; - font-weight: 500; - color: var(--color-yale-blue); -} - -.cardDescription { - color: #4b5563; - font-size: 0.875rem; - margin-bottom: 0.5rem; -} - -.cardFooter { - display: flex; - justify-content: space-between; - align-items: center; - font-size: 0.875rem; -} - -.category { - background-color: #f3f4f6; - padding: 0.25rem 0.5rem; - border-radius: 0.25rem; - color: #4b5563; -} - -.years { - color: #4b5563; -} - -.specGrid { - display: grid; - grid-template-columns: repeat(2, 1fr); - gap: 0.5rem; - margin-bottom: 0.5rem; - font-size: 0.875rem; -} - -.specLabel { - font-weight: 500; - color: var(--color-charcoal); -} - -.tagContainer { - display: flex; - flex-wrap: wrap; - gap: 0.25rem; - margin-top: 0.5rem; -} - -.tag { - background-color: #dbeafe; - color: #1e40af; - font-size: 0.75rem; - padding: 0.25rem 0.5rem; - border-radius: 0.25rem; -} - -.tagCount { - font-size: 0.75rem; - color: #6b7280; -} \ No newline at end of file diff --git a/src/app/services/carService.ts b/src/app/services/carService.ts deleted file mode 100644 index 49df3d3..0000000 --- a/src/app/services/carService.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { Brand, CarModel, CarRevision } from '../../backend/models'; - -interface SearchResults { - models: CarModel[]; - revisions: CarRevision[]; -} - -export class CarService { - /** - * Search cars by free-text query - */ - static async searchByQuery(query: string): Promise { - try { - const response = await fetch(`/api/cars/search?query=${encodeURIComponent(query)}`); - - if (!response.ok) { - throw new Error('Failed to search cars'); - } - - return await response.json(); - } catch (error) { - console.error('Error searching cars:', error); - return { models: [], revisions: [] }; - } - } - - /** - * Search cars by category - */ - static async searchByCategory(category: string): Promise { - try { - const response = await fetch(`/api/cars/search?category=${encodeURIComponent(category)}`); - - if (!response.ok) { - throw new Error('Failed to search cars by category'); - } - - return await response.json(); - } catch (error) { - console.error('Error searching cars by category:', error); - return { models: [], revisions: [] }; - } - } - - /** - * Search cars by year range - */ - static async searchByYearRange(startYear: number, endYear: number): Promise { - try { - const response = await fetch(`/api/cars/search?startYear=${startYear}&endYear=${endYear}`); - - if (!response.ok) { - throw new Error('Failed to search cars by year range'); - } - - return await response.json(); - } catch (error) { - console.error('Error searching cars by year range:', error); - return { models: [], revisions: [] }; - } - } - - /** - * Get all car brands - */ - static async getAllBrands(): Promise { - try { - const response = await fetch('/api/cars/brands'); - - if (!response.ok) { - throw new Error('Failed to fetch brands'); - } - - return await response.json(); - } catch (error) { - console.error('Error fetching brands:', error); - return []; - } - } -} \ No newline at end of file diff --git a/src/backend/models/Brand.ts b/src/backend/models/Brand.ts deleted file mode 100644 index ab80a9a..0000000 --- a/src/backend/models/Brand.ts +++ /dev/null @@ -1,14 +0,0 @@ -import { CarModel } from './CarModel'; -import { ObjectId } from 'mongodb'; - -export interface Brand { - _id?: ObjectId; - id?: string; - name: string; - logo: string; - description: string; - foundedYear: number; - headquarters: string; - website: string; - carModels?: CarModel[]; -} \ No newline at end of file diff --git a/src/backend/models/CarModel.ts b/src/backend/models/CarModel.ts deleted file mode 100644 index 533305c..0000000 --- a/src/backend/models/CarModel.ts +++ /dev/null @@ -1,16 +0,0 @@ -import { Brand } from './Brand'; -import { CarRevision } from './CarRevision'; -import { ObjectId } from 'mongodb'; - -export interface CarModel { - _id?: ObjectId; - id?: string; - name: string; - productionStartYear: number; - productionEndYear?: number; - category?: string; - description?: string; - image?: string; - revisions?: CarRevision[]; - brandId?: ObjectId; -} \ No newline at end of file diff --git a/src/backend/models/CarRevision.ts b/src/backend/models/CarRevision.ts deleted file mode 100644 index 1e9fdfa..0000000 --- a/src/backend/models/CarRevision.ts +++ /dev/null @@ -1,27 +0,0 @@ -import { CarModel } from './CarModel'; -import { ObjectId } from 'mongodb'; - -export interface Dimensions { - length: number; - width: number; - height: number; - wheelbase: number; -} - -export interface CarRevision { - _id?: ObjectId; - id?: string; - name: string; - releaseYear: number; - engineTypes: string[]; - horsePower: number; - torque: number; - topSpeed: number; - acceleration0To100: number; - fuelConsumption: number; - dimensions: Dimensions; - weight: number; - features: string[]; - images: string[]; - modelId?: ObjectId; -} \ No newline at end of file diff --git a/src/backend/models/index.ts b/src/backend/models/index.ts deleted file mode 100644 index 8fd7eec..0000000 --- a/src/backend/models/index.ts +++ /dev/null @@ -1,3 +0,0 @@ -export * from './Brand'; -export * from './CarModel'; -export * from './CarRevision'; \ No newline at end of file diff --git a/src/backend/repositories/CarRepository.ts b/src/backend/repositories/CarRepository.ts deleted file mode 100644 index 7d54dbc..0000000 --- a/src/backend/repositories/CarRepository.ts +++ /dev/null @@ -1,540 +0,0 @@ -import { Brand, CarModel, CarRevision } from '../models'; -import { MongoClient, Db, Collection, ObjectId } from 'mongodb'; - -export class CarRepository { - private client: MongoClient; - private db: Db | null = null; - private brandsCollection: Collection | null = null; - private carModelsCollection: Collection | null = null; - private carRevisionsCollection: Collection | null = null; - - constructor(private mongoUrl: string = process.env.MONGODB_URI || 'mongodb://localhost:27017/evwiki') { - this.client = new MongoClient(this.mongoUrl); - } - - /** - * Initialize the database connection - */ - async connect(): Promise { - if (!this.db) { - await this.client.connect(); - this.db = this.client.db(); - this.brandsCollection = this.db.collection('brands'); - this.carModelsCollection = this.db.collection('carModels'); - this.carRevisionsCollection = this.db.collection('carRevisions'); - - // Check if data exists, if not initialize with default data - const brandsCount = await this.brandsCollection.countDocuments(); - if (brandsCount === 0) { - await this.initializeDefaultData(); - } - } - } - - /** - * Close the database connection - */ - async disconnect(): Promise { - if (this.client) { - await this.client.close(); - this.db = null; - this.brandsCollection = null; - this.carModelsCollection = null; - this.carRevisionsCollection = null; - } - } - - /** - * Initialize the database with default data if empty - */ - private async initializeDefaultData(): Promise { - if (!this.db || !this.brandsCollection || !this.carModelsCollection || !this.carRevisionsCollection) { - throw new Error('Database not initialized'); - } - - // Insert default brands - await this.brandsCollection.insertMany([ - { - name: 'Tesla', - logo: 'https://example.com/tesla-logo.png', - description: 'American electric vehicle and clean energy company', - foundedYear: 2003, - headquarters: 'Palo Alto, California, United States', - website: 'https://www.tesla.com', - }, - { - name: 'BMW', - logo: 'https://example.com/bmw-logo.png', - description: 'German luxury automobile and motorcycle manufacturer', - foundedYear: 1916, - headquarters: 'Munich, Germany', - website: 'https://www.bmw.com', - }, - { - name: 'Toyota', - logo: 'https://example.com/toyota-logo.png', - description: 'Japanese multinational automotive manufacturer', - foundedYear: 1937, - headquarters: 'Toyota City, Japan', - website: 'https://www.toyota.com', - }, - { - name: 'Audi', - logo: 'https://example.com/audi-logo.png', - description: 'German luxury automobile manufacturer', - foundedYear: 1909, - headquarters: 'Ingolstadt, Germany', - website: 'https://www.audi.com', - }, - { - name: 'Mercedes-Benz', - logo: 'https://example.com/mercedes-logo.png', - description: 'German global automobile marque and a division of Daimler AG', - foundedYear: 1926, - headquarters: 'Stuttgart, Germany', - website: 'https://www.mercedes-benz.com', - }, - ]); - - // Get the inserted brands to connect them with models later - const brands = await this.brandsCollection.find().toArray(); - - // Insert default car models - await this.carModelsCollection.insertMany([ - { - name: 'Model S', - productionStartYear: 2012, - category: 'Sedan', - description: 'All-electric five-door liftback sedan', - image: 'https://example.com/tesla-model-s.jpg', - brandId: brands[0]._id, - }, - { - name: 'Model 3', - productionStartYear: 2017, - category: 'Sedan', - description: 'All-electric four-door sedan', - image: 'https://example.com/tesla-model-3.jpg', - brandId: brands[0]._id, - }, - { - name: '3 Series', - productionStartYear: 1975, - category: 'Sedan', - description: 'Compact executive car', - image: 'https://example.com/bmw-3-series.jpg', - brandId: brands[1]._id, - }, - { - name: 'X5', - productionStartYear: 1999, - category: 'SUV', - description: 'Mid-size luxury SUV', - image: 'https://example.com/bmw-x5.jpg', - brandId: brands[1]._id, - }, - { - name: 'Camry', - productionStartYear: 1982, - category: 'Sedan', - description: 'Mid-size car', - image: 'https://example.com/toyota-camry.jpg', - brandId: brands[2]._id, - }, - { - name: 'Prius', - productionStartYear: 1997, - category: 'Hatchback', - description: 'Hybrid electric mid-size car', - image: 'https://example.com/toyota-prius.jpg', - brandId: brands[2]._id, - }, - { - name: 'A4', - productionStartYear: 1994, - category: 'Sedan', - description: 'Compact executive car', - image: 'https://example.com/audi-a4.jpg', - brandId: brands[3]._id, - }, - { - name: 'Q7', - productionStartYear: 2005, - category: 'SUV', - description: 'Full-size luxury crossover SUV', - image: 'https://example.com/audi-q7.jpg', - brandId: brands[3]._id, - }, - { - name: 'C-Class', - productionStartYear: 1993, - category: 'Sedan', - description: 'Compact executive car', - image: 'https://example.com/mercedes-c-class.jpg', - brandId: brands[4]._id, - }, - { - name: 'GLE', - productionStartYear: 2015, - category: 'SUV', - description: 'Mid-size luxury crossover SUV', - image: 'https://example.com/mercedes-gle.jpg', - brandId: brands[4]._id, - }, - ]); - - // Get the inserted models to connect them with revisions - const models = await this.carModelsCollection.find().toArray(); - - // Find models by name for easy reference - const findModelByName = (name: string) => models.find(model => model.name === name); - - // Insert default car revisions - await this.carRevisionsCollection.insertMany([ - { - name: 'Model S Long Range Plus', - releaseYear: 2020, - engineTypes: ['Electric'], - horsePower: 670, - torque: 850, - topSpeed: 250, - acceleration0To100: 3.1, - fuelConsumption: 0, - dimensions: { - length: 4970, - width: 1964, - height: 1445, - wheelbase: 2960, - }, - weight: 2250, - features: ['Autopilot', 'Premium Interior', 'All-Wheel Drive'], - images: ['https://example.com/tesla-model-s-2020-1.jpg', 'https://example.com/tesla-model-s-2020-2.jpg'], - modelId: findModelByName('Model S')?._id, - }, - { - name: 'Model S Plaid', - releaseYear: 2021, - engineTypes: ['Electric'], - horsePower: 1020, - torque: 1050, - topSpeed: 322, - acceleration0To100: 2.1, - fuelConsumption: 0, - dimensions: { - length: 4970, - width: 1964, - height: 1445, - wheelbase: 2960, - }, - weight: 2300, - features: ['Enhanced Autopilot', 'Yoke Steering', 'All-Wheel Drive', 'New Interior Design'], - images: ['https://example.com/tesla-model-s-plaid-1.jpg', 'https://example.com/tesla-model-s-plaid-2.jpg'], - modelId: findModelByName('Model S')?._id, - }, - { - name: 'Model 3 Standard Range Plus', - releaseYear: 2021, - engineTypes: ['Electric'], - horsePower: 283, - torque: 450, - topSpeed: 225, - acceleration0To100: 5.6, - fuelConsumption: 0, - dimensions: { - length: 4694, - width: 1849, - height: 1443, - wheelbase: 2875, - }, - weight: 1750, - features: ['Basic Autopilot', 'Standard Interior', 'Rear-Wheel Drive'], - images: ['https://example.com/tesla-model-3-standard-1.jpg', 'https://example.com/tesla-model-3-standard-2.jpg'], - modelId: findModelByName('Model 3')?._id, - }, - { - name: '330i Sedan', - releaseYear: 2021, - engineTypes: ['Gasoline'], - horsePower: 255, - torque: 400, - topSpeed: 209, - acceleration0To100: 5.6, - fuelConsumption: 7.1, - dimensions: { - length: 4709, - width: 1827, - height: 1435, - wheelbase: 2851, - }, - weight: 1620, - features: ['LED Headlights', 'iDrive Infotainment System', 'Leather Seats'], - images: ['https://example.com/bmw-330i-1.jpg', 'https://example.com/bmw-330i-2.jpg'], - modelId: findModelByName('3 Series')?._id, - }, - { - name: 'M340i Sedan', - releaseYear: 2021, - engineTypes: ['Gasoline'], - horsePower: 382, - torque: 500, - topSpeed: 250, - acceleration0To100: 4.4, - fuelConsumption: 8.0, - dimensions: { - length: 4709, - width: 1827, - height: 1435, - wheelbase: 2851, - }, - weight: 1670, - features: ['M Sport Differential', 'M Sport Brakes', 'Adaptive M Suspension'], - images: ['https://example.com/bmw-m340i-1.jpg', 'https://example.com/bmw-m340i-2.jpg'], - modelId: findModelByName('3 Series')?._id, - }, - { - name: 'X5 xDrive40i', - releaseYear: 2021, - engineTypes: ['Gasoline'], - horsePower: 335, - torque: 450, - topSpeed: 243, - acceleration0To100: 5.5, - fuelConsumption: 9.2, - dimensions: { - length: 4922, - width: 2004, - height: 1745, - wheelbase: 2975, - }, - weight: 2260, - features: ['Panoramic Roof', 'Head-Up Display', 'Gesture Control'], - images: ['https://example.com/bmw-x5-xdrive40i-1.jpg', 'https://example.com/bmw-x5-xdrive40i-2.jpg'], - modelId: findModelByName('X5')?._id, - }, - { - name: 'Camry LE', - releaseYear: 2021, - engineTypes: ['Gasoline'], - horsePower: 203, - torque: 250, - topSpeed: 210, - acceleration0To100: 8.1, - fuelConsumption: 7.6, - dimensions: { - length: 4880, - width: 1840, - height: 1445, - wheelbase: 2825, - }, - weight: 1580, - features: ['Toyota Safety Sense', 'Apple CarPlay', 'Android Auto'], - images: ['https://example.com/toyota-camry-le-1.jpg', 'https://example.com/toyota-camry-le-2.jpg'], - modelId: findModelByName('Camry')?._id, - }, - { - name: 'Camry Hybrid', - releaseYear: 2021, - engineTypes: ['Hybrid'], - horsePower: 208, - torque: 220, - topSpeed: 180, - acceleration0To100: 7.8, - fuelConsumption: 4.2, - dimensions: { - length: 4880, - width: 1840, - height: 1445, - wheelbase: 2825, - }, - weight: 1680, - features: ['Regenerative Braking', 'EV Mode', 'Energy Monitor'], - images: ['https://example.com/toyota-camry-hybrid-1.jpg', 'https://example.com/toyota-camry-hybrid-2.jpg'], - modelId: findModelByName('Camry')?._id, - }, - { - name: 'Prius Prime', - releaseYear: 2021, - engineTypes: ['Plug-in Hybrid'], - horsePower: 121, - torque: 142, - topSpeed: 165, - acceleration0To100: 10.5, - fuelConsumption: 1.8, - dimensions: { - length: 4645, - width: 1760, - height: 1470, - wheelbase: 2700, - }, - weight: 1530, - features: ['Electric Range of 40 km', 'Touch-sensitive controls', 'Quad-LED projector headlights'], - images: ['https://example.com/toyota-prius-prime-1.jpg', 'https://example.com/toyota-prius-prime-2.jpg'], - modelId: findModelByName('Prius')?._id, - }, - { - name: 'A4 Prestige', - releaseYear: 2021, - engineTypes: ['Gasoline'], - horsePower: 261, - torque: 370, - topSpeed: 210, - acceleration0To100: 5.5, - fuelConsumption: 7.5, - dimensions: { - length: 4762, - width: 1847, - height: 1435, - wheelbase: 2820, - }, - weight: 1640, - features: ['Audi Virtual Cockpit', 'Bang & Olufsen Sound System', 'Adaptive Cruise Control'], - images: ['https://example.com/audi-a4-prestige-1.jpg', 'https://example.com/audi-a4-prestige-2.jpg'], - modelId: findModelByName('A4')?._id, - }, - ]); - } - - /** - * Get all brands - */ - async getAllBrands(): Promise { - await this.connect(); - if (!this.brandsCollection) throw new Error('Database not initialized'); - - return this.brandsCollection.find().toArray(); - } - - /** - * Get brand by ID - */ - async getBrandById(id: string): Promise { - await this.connect(); - if (!this.brandsCollection) throw new Error('Database not initialized'); - - return this.brandsCollection.findOne({ _id: new ObjectId(id) }); - } - - /** - * Get all car models - */ - async getAllCarModels(): Promise { - await this.connect(); - if (!this.carModelsCollection) throw new Error('Database not initialized'); - - return this.carModelsCollection.find().toArray(); - } - - /** - * Get car models by brand ID - */ - async getCarModelsByBrandId(brandId: string): Promise { - await this.connect(); - if (!this.carModelsCollection) throw new Error('Database not initialized'); - - return this.carModelsCollection.find({ brandId: new ObjectId(brandId) }).toArray(); - } - - /** - * Get car model by ID - */ - async getCarModelById(id: string): Promise { - await this.connect(); - if (!this.carModelsCollection) throw new Error('Database not initialized'); - - return this.carModelsCollection.findOne({ _id: new ObjectId(id) }); - } - - /** - * Get all car revisions - */ - async getAllCarRevisions(): Promise { - await this.connect(); - if (!this.carRevisionsCollection) throw new Error('Database not initialized'); - - return this.carRevisionsCollection.find().toArray(); - } - - /** - * Get car revisions by model ID - */ - async getCarRevisionsByModelId(modelId: string): Promise { - await this.connect(); - if (!this.carRevisionsCollection) throw new Error('Database not initialized'); - - return this.carRevisionsCollection.find({ modelId: new ObjectId(modelId) }).toArray(); - } - - /** - * Get car revision by ID - */ - async getCarRevisionById(id: string): Promise { - await this.connect(); - if (!this.carRevisionsCollection) throw new Error('Database not initialized'); - - return this.carRevisionsCollection.findOne({ _id: new ObjectId(id) }); - } - - /** - * Search cars by name (searches both models and revisions) - */ - async searchCarsByName(name: string): Promise<{ models: CarModel[], revisions: CarRevision[], brands: Brand[] }> { - await this.connect(); - if (!this.brandsCollection || !this.carModelsCollection || !this.carRevisionsCollection) { - throw new Error('Database not initialized'); - } - - const lowercaseName = name.toLowerCase(); - - const matchingModels = await this.carModelsCollection.find({ - name: { $regex: new RegExp(lowercaseName, 'i') } - }).toArray(); - - const matchingRevisions = await this.carRevisionsCollection.find({ - name: { $regex: new RegExp(lowercaseName, 'i') } - }).toArray(); - - const matchingBrands = await this.brandsCollection.find({ - name: { $regex: new RegExp(lowercaseName, 'i') } - }).toArray(); - - return { - models: matchingModels, - revisions: matchingRevisions, - brands: matchingBrands - }; - } - - /** - * Get cars by category - */ - async getCarsByCategory(category: string): Promise { - await this.connect(); - if (!this.carModelsCollection) throw new Error('Database not initialized'); - - return this.carModelsCollection.find({ - category: { $regex: new RegExp(`^${category}$`, 'i') } - }).toArray(); - } - - /** - * Get cars by year range - */ - async getCarsByYearRange(startYear: number, endYear: number): Promise { - await this.connect(); - if (!this.carModelsCollection) throw new Error('Database not initialized'); - - return this.carModelsCollection.find({ - $or: [ - { productionStartYear: { $lte: endYear, $gte: startYear } }, - { - productionStartYear: { $lte: endYear }, - productionEndYear: { $gte: startYear } - }, - { - productionStartYear: { $lte: endYear }, - productionEndYear: { $exists: false } - } - ] - }).toArray(); - } -} \ No newline at end of file diff --git a/src/backend/repositories/index.ts b/src/backend/repositories/index.ts deleted file mode 100644 index 9e4feb8..0000000 --- a/src/backend/repositories/index.ts +++ /dev/null @@ -1 +0,0 @@ -export * from './CarRepository'; \ No newline at end of file diff --git a/symfony.lock b/symfony.lock new file mode 100644 index 0000000..5c33e13 --- /dev/null +++ b/symfony.lock @@ -0,0 +1,105 @@ +{ + "symfony/console": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.3", + "ref": "1781ff40d8a17d87cf53f8d4cf0c8346ed2bb461" + }, + "files": [ + "bin/console" + ] + }, + "symfony/debug-bundle": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "5.3", + "ref": "5aa8aa48234c8eb6dbdd7b3cd5d791485d2cec4b" + }, + "files": [ + "config/packages/debug.yaml" + ] + }, + "symfony/flex": { + "version": "2.7", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "2.4", + "ref": "52e9754527a15e2b79d9a610f98185a1fe46622a" + }, + "files": [ + ".env", + ".env.dev" + ] + }, + "symfony/framework-bundle": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.2", + "ref": "87bcf6f7c55201f345d8895deda46d2adbdbaa89" + }, + "files": [ + "config/packages/cache.yaml", + "config/packages/framework.yaml", + "config/preload.php", + "config/routes/framework.yaml", + "config/services.yaml", + "public/index.php", + "src/Controller/.gitignore", + "src/Kernel.php" + ] + }, + "symfony/maker-bundle": { + "version": "1.63", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.0", + "ref": "fadbfe33303a76e25cb63401050439aa9b1a9c7f" + } + }, + "symfony/routing": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "21b72649d5622d8f7da329ffb5afb232a023619d" + }, + "files": [ + "config/packages/routing.yaml", + "config/routes.yaml" + ] + }, + "symfony/twig-bundle": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.4", + "ref": "cab5fd2a13a45c266d45a7d9337e28dee6272877" + }, + "files": [ + "config/packages/twig.yaml", + "templates/base.html.twig" + ] + }, + "symfony/validator": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "7.0", + "ref": "8c1c4e28d26a124b0bb273f537ca8ce443472bfd" + }, + "files": [ + "config/packages/validator.yaml" + ] + } +} diff --git a/templates/_components/search.html.twig b/templates/_components/search.html.twig new file mode 100644 index 0000000..5082f08 --- /dev/null +++ b/templates/_components/search.html.twig @@ -0,0 +1,45 @@ +
+ + +
+ + \ No newline at end of file diff --git a/templates/base.html.twig b/templates/base.html.twig new file mode 100644 index 0000000..5b50405 --- /dev/null +++ b/templates/base.html.twig @@ -0,0 +1,162 @@ + + + + + + {% block title %}E-WIKI - Electric Vehicle Database{% endblock %} + + {% block stylesheets %}{% endblock %} + + +
+ {% block body %}{% endblock %} +
+ + {% block javascripts %}{% endblock %} + + \ No newline at end of file diff --git a/templates/home/index.html.twig b/templates/home/index.html.twig new file mode 100644 index 0000000..ea75943 --- /dev/null +++ b/templates/home/index.html.twig @@ -0,0 +1,31 @@ +{% extends 'base.html.twig' %} + +{% block title %}E-WIKI - Electric Vehicle Database{% endblock %} + +{% block body %} +
+

E-WIKI

+ + {% include '_components/search.html.twig' %} +
+ +
+

Popular Electric Vehicle Brands

+
+ {% for brand in brands %} +
+
{{ brand.name }}
+ {% if brand.description %} +
{{ brand.description }}
+ {% endif %} +
Founded: {{ brand.foundedYear }}
+ {% if brand.headquarters %} +
{{ brand.headquarters }}
+ {% endif %} +
+ {% else %} +
No brands available
+ {% endfor %} +
+
+{% endblock %} \ No newline at end of file diff --git a/templates/result/index.html.twig b/templates/result/index.html.twig new file mode 100644 index 0000000..4093ee6 --- /dev/null +++ b/templates/result/index.html.twig @@ -0,0 +1,11 @@ +{% extends 'base.html.twig' %} + +{% block body %} +
+ E-WIKI + + {% include '_components/search.html.twig' with { query: query } %} +
+ + {% include 'result/tiles/collection.html.twig' with { tiles: tiles } %} +{% endblock %} \ No newline at end of file diff --git a/templates/result/tiles/brand.html.twig b/templates/result/tiles/brand.html.twig new file mode 100644 index 0000000..ce29dd0 --- /dev/null +++ b/templates/result/tiles/brand.html.twig @@ -0,0 +1,4 @@ +
+ +
{{ tile.name }}
+
diff --git a/templates/result/tiles/collection.html.twig b/templates/result/tiles/collection.html.twig new file mode 100644 index 0000000..9fd6cf5 --- /dev/null +++ b/templates/result/tiles/collection.html.twig @@ -0,0 +1,5 @@ +{% for tile in tiles %} +
+ {% include 'result/tiles/' ~ tile|twig_name ~ '.html.twig' with { tile: tile } %} +
+{% endfor %} \ No newline at end of file diff --git a/templates/result/tiles/section.html.twig b/templates/result/tiles/section.html.twig new file mode 100644 index 0000000..57febcf --- /dev/null +++ b/templates/result/tiles/section.html.twig @@ -0,0 +1,3 @@ +

{{ tile.title }}

+ +{% include 'result/tiles/collection.html.twig' with { tiles: tile.tiles } %} \ No newline at end of file