diff --git a/.gitignore b/.gitignore index 80c163f..c166fee 100644 --- a/.gitignore +++ b/.gitignore @@ -17,3 +17,8 @@ ###< phpunit/phpunit ### .DS_Store + +###> symfony/asset-mapper ### +/public/assets/ +/assets/vendor/ +###< symfony/asset-mapper ### diff --git a/.junie/guidelines.md b/.junie/guidelines.md new file mode 100644 index 0000000..9e6e07c --- /dev/null +++ b/.junie/guidelines.md @@ -0,0 +1,156 @@ +# Development Guidelines + +This document provides guidelines and instructions for developing and maintaining the Futtern project. + +## Build/Configuration Instructions + +### Environment Setup + +1. **PHP Requirements**: The project requires PHP 8.4 or higher with the following extensions: + - ctype + - iconv + +2. **Composer**: Install dependencies using Composer: + ```bash + composer install + ``` + +3. **Environment Configuration**: Copy `.env` to `.env.local` and adjust the settings as needed for your local environment. + +### Development Server + +Start the Symfony development server: +```bash +symfony server:start +``` + +### Building Assets + +The project uses Tailwind CSS via the symfonycasts/tailwind-bundle: +```bash +# Install importmap assets +symfony console importmap:install +``` + +## Deployment + +The project includes several deployment scripts: + +1. **Prepare for Deployment**: + ```bash + ./deploy/prepare-deploy.sh + ``` + This script creates a clean copy of the application with only production dependencies. + +2. **Local Deployment**: + ```bash + ./deploy/local-deploy.sh + ``` + This script deploys the application to a remote server, backing up the database and restarting the service. + +3. **Update After Deployment**: + ```bash + ./deploy/update.sh + ``` + This script is run on the remote server to clear cache, warm up cache, and run database migrations. + +## Testing Information + +### Testing Framework + +The project uses Pest PHP, a testing framework built on top of PHPUnit, for testing. Tests are organized into: +- **Feature Tests**: For testing controllers and API endpoints +- **Unit Tests**: For testing individual components + +### Running Tests + +Run all tests: +```bash +composer test +# or +./vendor/bin/pest +``` + +Run specific tests: +```bash +./vendor/bin/pest tests/Unit/ExampleTest.php +``` + +Run tests in parallel: +```bash +./vendor/bin/pest --parallel +``` + +### Creating Tests + +1. **Unit Tests**: Create files in the `tests/Unit` directory. +2. **Feature Tests**: + - Controller tests: Create files in `tests/Feature/Controller` + - API tests: Create files in `tests/Feature/Api` + +### Example Test + +Here's a simple example of a Pest PHP test: + +```php +toBeTrue(); + expect(1 + 1)->toBe(2); + expect('hello world')->toContain('world'); +}); + +test('array operations', function (): void { + $array = [1, 2, 3]; + + expect($array)->toHaveCount(3); + expect($array)->toContain(2); + expect($array[0])->toBe(1); +}); +``` + +### Test Base Classes + +- `DbWebTest`: Base class for controller tests +- `DbApiTestCase`: Base class for API tests + +## Code Quality and Style + +### Code Style + +The project uses Easy Coding Standard (ECS) for code style checking: +```bash +composer lint +# or +./vendor/bin/ecs --fix +``` + +The code style is defined in `ecs.php` and includes: +- Custom rules from `Lubiana\CodeQuality\LubiSetList::ECS` +- All classes should be declared as final + +### Code Refactoring + +The project uses Rector for automated code refactoring: +```bash +./vendor/bin/rector +``` + +The refactoring rules are defined in `rector.php` and include: +- Custom rules from `Lubiana\CodeQuality\LubiSetList::RECTOR` +- StaticClosureRector is skipped in the tests directory + +### Development Workflow + +1. Make changes to the code +2. Run tests to ensure functionality: `composer test` +3. Fix code style issues: `composer lint` +4. Commit and push changes +5. Deploy using the deployment scripts + +## Debugging + +- Use the Symfony Web Profiler in development mode +- Check logs in `var/log/` +- For API debugging, use the API Platform documentation at `/api` \ No newline at end of file diff --git a/.symfony.local.yaml b/.symfony.local.yaml new file mode 100644 index 0000000..1198458 --- /dev/null +++ b/.symfony.local.yaml @@ -0,0 +1,3 @@ +workers: + tailwind: + cmd: ['symfony', 'console', 'tailwind:build', '--watch'] \ No newline at end of file diff --git a/assets/app.js b/assets/app.js new file mode 100644 index 0000000..05ff425 --- /dev/null +++ b/assets/app.js @@ -0,0 +1,8 @@ +/* + * Welcome to your app's main JavaScript file! + * + * This file will be included onto the page via the importmap() Twig function, + * which should already be in your base.html.twig. + */ +import './styles/app.css'; + diff --git a/assets/styles/app.css b/assets/styles/app.css new file mode 100644 index 0000000..f52a8ac --- /dev/null +++ b/assets/styles/app.css @@ -0,0 +1,7 @@ +@tailwind base; +@tailwind components; +@tailwind utilities; + +body { + background-color: skyblue; +} diff --git a/composer.json b/composer.json index 2360741..a69fb84 100644 --- a/composer.json +++ b/composer.json @@ -33,7 +33,8 @@ "symfony/twig-bundle": "7.1.*", "symfony/uid": "7.1.*", "symfony/validator": "7.1.*", - "symfony/yaml": "7.1.*" + "symfony/yaml": "7.1.*", + "symfonycasts/tailwind-bundle": "^0.10.0" }, "require-dev": { "doctrine/doctrine-fixtures-bundle": "^4.0", @@ -85,7 +86,8 @@ "scripts": { "auto-scripts": { "cache:clear": "symfony-cmd", - "assets:install %PUBLIC_DIR%": "symfony-cmd" + "assets:install %PUBLIC_DIR%": "symfony-cmd", + "importmap:install": "symfony-cmd" }, "post-install-cmd": [ "@auto-scripts" diff --git a/composer.lock b/composer.lock index 472b98c..e06da3f 100644 --- a/composer.lock +++ b/composer.lock @@ -4,7 +4,7 @@ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "This file is @generated automatically" ], - "content-hash": "d7745d305c728e9812365f75052d1031", + "content-hash": "1c86a4bdee669d314840de214b23cf19", "packages": [ { "name": "api-platform/doctrine-common", @@ -1112,6 +1112,87 @@ }, "time": "2025-04-11T09:32:56+00:00" }, + { + "name": "composer/semver", + "version": "3.4.3", + "source": { + "type": "git", + "url": "https://github.com/composer/semver.git", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/composer/semver/zipball/4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "reference": "4313d26ada5e0c4edfbd1dc481a92ff7bff91f12", + "shasum": "" + }, + "require": { + "php": "^5.3.2 || ^7.0 || ^8.0" + }, + "require-dev": { + "phpstan/phpstan": "^1.11", + "symfony/phpunit-bridge": "^3 || ^7" + }, + "type": "library", + "extra": { + "branch-alias": { + "dev-main": "3.x-dev" + } + }, + "autoload": { + "psr-4": { + "Composer\\Semver\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Nils Adermann", + "email": "naderman@naderman.de", + "homepage": "http://www.naderman.de" + }, + { + "name": "Jordi Boggiano", + "email": "j.boggiano@seld.be", + "homepage": "http://seld.be" + }, + { + "name": "Rob Bast", + "email": "rob.bast@gmail.com", + "homepage": "http://robbast.nl" + } + ], + "description": "Semver library that offers utilities, version constraint parsing and validation.", + "keywords": [ + "semantic", + "semver", + "validation", + "versioning" + ], + "support": { + "irc": "ircs://irc.libera.chat:6697/composer", + "issues": "https://github.com/composer/semver/issues", + "source": "https://github.com/composer/semver/tree/3.4.3" + }, + "funding": [ + { + "url": "https://packagist.com", + "type": "custom" + }, + { + "url": "https://github.com/composer", + "type": "github" + }, + { + "url": "https://tidelift.com/funding/github/packagist/composer/composer", + "type": "tidelift" + } + ], + "time": "2024-09-19T14:15:21+00:00" + }, { "name": "doctrine/collections", "version": "2.3.0", @@ -2983,6 +3064,85 @@ ], "time": "2024-10-25T15:15:23+00:00" }, + { + "name": "symfony/asset-mapper", + "version": "v7.2.5", + "source": { + "type": "git", + "url": "https://github.com/symfony/asset-mapper.git", + "reference": "6428e4b6d8cff9c5fe6f40ddbee4c9f6bfdaa0b8" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/asset-mapper/zipball/6428e4b6d8cff9c5fe6f40ddbee4c9f6bfdaa0b8", + "reference": "6428e4b6d8cff9c5fe6f40ddbee4c9f6bfdaa0b8", + "shasum": "" + }, + "require": { + "composer/semver": "^3.0", + "php": ">=8.2", + "symfony/deprecation-contracts": "^2.1|^3", + "symfony/filesystem": "^7.1", + "symfony/http-client": "^6.4|^7.0" + }, + "conflict": { + "symfony/framework-bundle": "<6.4" + }, + "require-dev": { + "symfony/asset": "^6.4|^7.0", + "symfony/browser-kit": "^6.4|^7.0", + "symfony/console": "^6.4|^7.0", + "symfony/event-dispatcher-contracts": "^3.0", + "symfony/finder": "^6.4|^7.0", + "symfony/framework-bundle": "^6.4|^7.0", + "symfony/http-foundation": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/web-link": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\AssetMapper\\": "" + }, + "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 directories of assets & makes them available in a public directory with versioned filenames.", + "homepage": "https://symfony.com", + "support": { + "source": "https://github.com/symfony/asset-mapper/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-26T11:29:07+00:00" + }, { "name": "symfony/cache", "version": "v7.2.5", @@ -4467,6 +4627,179 @@ ], "time": "2025-01-29T07:13:42+00:00" }, + { + "name": "symfony/http-client", + "version": "v7.2.4", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client.git", + "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client/zipball/78981a2ffef6437ed92d4d7e2a86a82f256c6dc6", + "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6", + "shasum": "" + }, + "require": { + "php": ">=8.2", + "psr/log": "^1|^2|^3", + "symfony/deprecation-contracts": "^2.5|^3", + "symfony/http-client-contracts": "~3.4.4|^3.5.2", + "symfony/service-contracts": "^2.5|^3" + }, + "conflict": { + "amphp/amp": "<2.5", + "php-http/discovery": "<1.15", + "symfony/http-foundation": "<6.4" + }, + "provide": { + "php-http/async-client-implementation": "*", + "php-http/client-implementation": "*", + "psr/http-client-implementation": "1.0", + "symfony/http-client-implementation": "3.0" + }, + "require-dev": { + "amphp/http-client": "^4.2.1|^5.0", + "amphp/http-tunnel": "^1.0|^2.0", + "amphp/socket": "^1.1", + "guzzlehttp/promises": "^1.4|^2.0", + "nyholm/psr7": "^1.0", + "php-http/httplug": "^1.0|^2.0", + "psr/http-client": "^1.0", + "symfony/amphp-http-client-meta": "^1.0|^2.0", + "symfony/dependency-injection": "^6.4|^7.0", + "symfony/http-kernel": "^6.4|^7.0", + "symfony/messenger": "^6.4|^7.0", + "symfony/process": "^6.4|^7.0", + "symfony/rate-limiter": "^6.4|^7.0", + "symfony/stopwatch": "^6.4|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfony\\Component\\HttpClient\\": "" + }, + "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 powerful methods to fetch HTTP resources synchronously or asynchronously", + "homepage": "https://symfony.com", + "keywords": [ + "http" + ], + "support": { + "source": "https://github.com/symfony/http-client/tree/v7.2.4" + }, + "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-02-13T10:27:23+00:00" + }, + { + "name": "symfony/http-client-contracts", + "version": "v3.5.2", + "source": { + "type": "git", + "url": "https://github.com/symfony/http-client-contracts.git", + "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645", + "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645", + "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\\HttpClient\\": "" + }, + "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 HTTP clients", + "homepage": "https://symfony.com", + "keywords": [ + "abstractions", + "contracts", + "decoupling", + "interfaces", + "interoperability", + "standards" + ], + "support": { + "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.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-07T08:49:48+00:00" + }, { "name": "symfony/http-foundation", "version": "v7.2.5", @@ -5276,6 +5609,67 @@ ], "time": "2024-09-09T11:45:10+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" + }, { "name": "symfony/property-access", "version": "v7.2.3", @@ -7107,6 +7501,62 @@ ], "time": "2025-01-07T12:50:05+00:00" }, + { + "name": "symfonycasts/tailwind-bundle", + "version": "v0.10.0", + "source": { + "type": "git", + "url": "https://github.com/SymfonyCasts/tailwind-bundle.git", + "reference": "380502c39bf403f772d050ff9904932040de8cf1" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/SymfonyCasts/tailwind-bundle/zipball/380502c39bf403f772d050ff9904932040de8cf1", + "reference": "380502c39bf403f772d050ff9904932040de8cf1", + "shasum": "" + }, + "require": { + "php": ">=8.1", + "symfony/asset-mapper": "^6.3|^7.0", + "symfony/cache": "^6.3|^7.0", + "symfony/console": "^5.4|^6.3|^7.0", + "symfony/deprecation-contracts": "^2.2|^3.0", + "symfony/http-client": "^5.4|^6.3|^7.0", + "symfony/process": "^5.4|^6.3|^7.0" + }, + "require-dev": { + "phpunit/phpunit": "^9.6", + "symfony/filesystem": "^6.3|^7.0", + "symfony/framework-bundle": "^6.3|^7.0", + "symfony/phpunit-bridge": "^6.3.9|^7.0" + }, + "type": "library", + "autoload": { + "psr-4": { + "Symfonycasts\\TailwindBundle\\": "src" + } + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Ryan Weaver", + "homepage": "https://symfonycasts.com" + } + ], + "description": "Delightful Tailwind Support for Symfony + AssetMapper", + "keywords": [ + "asset-mapper", + "tailwind" + ], + "support": { + "issues": "https://github.com/SymfonyCasts/tailwind-bundle/issues", + "source": "https://github.com/SymfonyCasts/tailwind-bundle/tree/v0.10.0" + }, + "time": "2025-04-09T15:18:46+00:00" + }, { "name": "twig/twig", "version": "v3.20.0", @@ -10627,179 +11077,6 @@ ], "time": "2025-02-17T15:53:07+00:00" }, - { - "name": "symfony/http-client", - "version": "v7.2.4", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-client.git", - "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client/zipball/78981a2ffef6437ed92d4d7e2a86a82f256c6dc6", - "reference": "78981a2ffef6437ed92d4d7e2a86a82f256c6dc6", - "shasum": "" - }, - "require": { - "php": ">=8.2", - "psr/log": "^1|^2|^3", - "symfony/deprecation-contracts": "^2.5|^3", - "symfony/http-client-contracts": "~3.4.4|^3.5.2", - "symfony/service-contracts": "^2.5|^3" - }, - "conflict": { - "amphp/amp": "<2.5", - "php-http/discovery": "<1.15", - "symfony/http-foundation": "<6.4" - }, - "provide": { - "php-http/async-client-implementation": "*", - "php-http/client-implementation": "*", - "psr/http-client-implementation": "1.0", - "symfony/http-client-implementation": "3.0" - }, - "require-dev": { - "amphp/http-client": "^4.2.1|^5.0", - "amphp/http-tunnel": "^1.0|^2.0", - "amphp/socket": "^1.1", - "guzzlehttp/promises": "^1.4|^2.0", - "nyholm/psr7": "^1.0", - "php-http/httplug": "^1.0|^2.0", - "psr/http-client": "^1.0", - "symfony/amphp-http-client-meta": "^1.0|^2.0", - "symfony/dependency-injection": "^6.4|^7.0", - "symfony/http-kernel": "^6.4|^7.0", - "symfony/messenger": "^6.4|^7.0", - "symfony/process": "^6.4|^7.0", - "symfony/rate-limiter": "^6.4|^7.0", - "symfony/stopwatch": "^6.4|^7.0" - }, - "type": "library", - "autoload": { - "psr-4": { - "Symfony\\Component\\HttpClient\\": "" - }, - "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 powerful methods to fetch HTTP resources synchronously or asynchronously", - "homepage": "https://symfony.com", - "keywords": [ - "http" - ], - "support": { - "source": "https://github.com/symfony/http-client/tree/v7.2.4" - }, - "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-02-13T10:27:23+00:00" - }, - { - "name": "symfony/http-client-contracts", - "version": "v3.5.2", - "source": { - "type": "git", - "url": "https://github.com/symfony/http-client-contracts.git", - "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/symfony/http-client-contracts/zipball/ee8d807ab20fcb51267fdace50fbe3494c31e645", - "reference": "ee8d807ab20fcb51267fdace50fbe3494c31e645", - "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\\HttpClient\\": "" - }, - "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 HTTP clients", - "homepage": "https://symfony.com", - "keywords": [ - "abstractions", - "contracts", - "decoupling", - "interfaces", - "interoperability", - "standards" - ], - "support": { - "source": "https://github.com/symfony/http-client-contracts/tree/v3.5.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-07T08:49:48+00:00" - }, { "name": "symfony/maker-bundle", "version": "v1.62.1", @@ -10892,67 +11169,6 @@ ], "time": "2025-01-15T00:21:40+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" - }, { "name": "symfony/web-profiler-bundle", "version": "v7.2.4", diff --git a/config/bundles.php b/config/bundles.php index 1aed8f6..6a662f2 100644 --- a/config/bundles.php +++ b/config/bundles.php @@ -11,6 +11,7 @@ use Symfony\Bundle\MakerBundle\MakerBundle; use Symfony\Bundle\SecurityBundle\SecurityBundle; use Symfony\Bundle\TwigBundle\TwigBundle; use Symfony\Bundle\WebProfilerBundle\WebProfilerBundle; +use Symfonycasts\TailwindBundle\SymfonycastsTailwindBundle; return [ FrameworkBundle::class => [ @@ -49,4 +50,7 @@ return [ 'dev' => true, 'test' => true, ], + SymfonycastsTailwindBundle::class => [ + 'all' => true, + ], ]; diff --git a/config/packages/asset_mapper.php b/config/packages/asset_mapper.php new file mode 100644 index 0000000..3a3cc5f --- /dev/null +++ b/config/packages/asset_mapper.php @@ -0,0 +1,21 @@ +extension('framework', [ + 'asset_mapper' => [ + 'paths' => [ + 'assets/', + ], + 'missing_import_mode' => 'strict', + ], + ]); + if ($containerConfigurator->env() === 'prod') { + $containerConfigurator->extension('framework', [ + 'asset_mapper' => [ + 'missing_import_mode' => 'warn', + ], + ]); + } +}; diff --git a/config/packages/symfonycasts_tailwind.php b/config/packages/symfonycasts_tailwind.php new file mode 100644 index 0000000..6c1a097 --- /dev/null +++ b/config/packages/symfonycasts_tailwind.php @@ -0,0 +1,9 @@ +extension('symfonycasts_tailwind', [ + 'binary_version' => 'v3.4.17', + ]); +}; diff --git a/importmap.php b/importmap.php new file mode 100644 index 0000000..c5b734e --- /dev/null +++ b/importmap.php @@ -0,0 +1,19 @@ + [ + 'path' => './assets/app.js', + 'entrypoint' => true, + ], +]; diff --git a/symfony.lock b/symfony.lock index 17beb57..63de157 100644 --- a/symfony.lock +++ b/symfony.lock @@ -99,6 +99,21 @@ "ref": "1019e5c08d4821cb9b77f4891f8e9c31ff20ac6f" } }, + "symfony/asset-mapper": { + "version": "7.2", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "6.4", + "ref": "5ad1308aa756d58f999ffbe1540d1189f5d7d14a" + }, + "files": [ + "assets/app.js", + "assets/styles/app.css", + "config/packages/asset_mapper.yaml", + "importmap.php" + ] + }, "symfony/console": { "version": "7.1", "recipe": { @@ -223,5 +238,17 @@ "config/packages/web_profiler.yaml", "config/routes/web_profiler.yaml" ] + }, + "symfonycasts/tailwind-bundle": { + "version": "0.10", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "0.8", + "ref": "4ea7c9488fdce8943520daf3fdc31e93e5b59c64" + }, + "files": [ + "config/packages/symfonycasts_tailwind.yaml" + ] } } diff --git a/tailwind.config.js b/tailwind.config.js new file mode 100644 index 0000000..531385f --- /dev/null +++ b/tailwind.config.js @@ -0,0 +1,12 @@ +/** @type {import('tailwindcss').Config} */ +module.exports = { + content: [ + "./assets/**/*.js", + "./templates/**/*.html.twig", + ], + darkMode: 'media', // Use 'media' to respect the user's system preference + theme: { + extend: {}, + }, + plugins: [], +} diff --git a/templates/_form.html.twig b/templates/_form.html.twig index bf20b98..6fe4982 100644 --- a/templates/_form.html.twig +++ b/templates/_form.html.twig @@ -1,4 +1,24 @@ -{{ form_start(form) }} - {{ form_widget(form) }} - +{{ form_start(form, {'attr': {'class': 'space-y-6'}}) }} + {% for field in form %} + {% if field.vars.name != '_token' %} +
{{ field.vars.help }}
+ {% endif %} +Hello {{ app.request.cookies.get('username', 'nobody') }} - change name
-