diff --git a/composer.lock b/composer.lock index c50f566..e61e046 100644 --- a/composer.lock +++ b/composer.lock @@ -3125,16 +3125,16 @@ }, { "name": "symfony/flex", - "version": "v2.7.0", + "version": "v2.7.1", "source": { "type": "git", "url": "https://github.com/symfony/flex.git", - "reference": "5d743b3b78fabe9f3146586d77b0a1f9292851fc" + "reference": "4ae50d368415a06820739e54d38a4a29d6df9155" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/flex/zipball/5d743b3b78fabe9f3146586d77b0a1f9292851fc", - "reference": "5d743b3b78fabe9f3146586d77b0a1f9292851fc", + "url": "https://api.github.com/repos/symfony/flex/zipball/4ae50d368415a06820739e54d38a4a29d6df9155", + "reference": "4ae50d368415a06820739e54d38a4a29d6df9155", "shasum": "" }, "require": { @@ -3173,7 +3173,7 @@ "description": "Composer plugin for Symfony", "support": { "issues": "https://github.com/symfony/flex/issues", - "source": "https://github.com/symfony/flex/tree/v2.7.0" + "source": "https://github.com/symfony/flex/tree/v2.7.1" }, "funding": [ { @@ -3189,7 +3189,7 @@ "type": "tidelift" } ], - "time": "2025-05-23T11:41:40+00:00" + "time": "2025-05-28T14:22:54+00:00" }, { "name": "symfony/form", @@ -6623,16 +6623,16 @@ }, { "name": "symfony/var-exporter", - "version": "v6.4.21", + "version": "v6.4.22", "source": { "type": "git", "url": "https://github.com/symfony/var-exporter.git", - "reference": "717e7544aa99752c54ecba5c0e17459c48317472" + "reference": "f28cf841f5654955c9f88ceaf4b9dc29571988a9" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/var-exporter/zipball/717e7544aa99752c54ecba5c0e17459c48317472", - "reference": "717e7544aa99752c54ecba5c0e17459c48317472", + "url": "https://api.github.com/repos/symfony/var-exporter/zipball/f28cf841f5654955c9f88ceaf4b9dc29571988a9", + "reference": "f28cf841f5654955c9f88ceaf4b9dc29571988a9", "shasum": "" }, "require": { @@ -6680,7 +6680,7 @@ "serialize" ], "support": { - "source": "https://github.com/symfony/var-exporter/tree/v6.4.21" + "source": "https://github.com/symfony/var-exporter/tree/v6.4.22" }, "funding": [ { @@ -6696,7 +6696,7 @@ "type": "tidelift" } ], - "time": "2025-04-27T21:06:26+00:00" + "time": "2025-05-14T13:00:13+00:00" }, { "name": "symfony/web-link", @@ -9145,16 +9145,16 @@ }, { "name": "symfony/phpunit-bridge", - "version": "v7.2.6", + "version": "v7.3.0", "source": { "type": "git", "url": "https://github.com/symfony/phpunit-bridge.git", - "reference": "6106ae85a0e3ed509d339b7f924788c9cc4e7cfb" + "reference": "2eabda563921f21cbce1d1e3247b3c36568905e6" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/6106ae85a0e3ed509d339b7f924788c9cc4e7cfb", - "reference": "6106ae85a0e3ed509d339b7f924788c9cc4e7cfb", + "url": "https://api.github.com/repos/symfony/phpunit-bridge/zipball/2eabda563921f21cbce1d1e3247b3c36568905e6", + "reference": "2eabda563921f21cbce1d1e3247b3c36568905e6", "shasum": "" }, "require": { @@ -9207,7 +9207,7 @@ "description": "Provides utilities for PHPUnit, especially user deprecation notices management", "homepage": "https://symfony.com", "support": { - "source": "https://github.com/symfony/phpunit-bridge/tree/v7.2.6" + "source": "https://github.com/symfony/phpunit-bridge/tree/v7.3.0" }, "funding": [ { @@ -9223,7 +9223,7 @@ "type": "tidelift" } ], - "time": "2025-04-09T08:35:42+00:00" + "time": "2025-05-23T07:26:30+00:00" }, { "name": "symfony/web-profiler-bundle", @@ -9356,7 +9356,7 @@ ], "aliases": [], "minimum-stability": "stable", - "stability-flags": {}, + "stability-flags": [], "prefer-stable": true, "prefer-lowest": false, "platform": { @@ -9364,6 +9364,6 @@ "ext-ctype": "*", "ext-iconv": "*" }, - "platform-dev": {}, + "platform-dev": [], "plugin-api-version": "2.6.0" } diff --git a/config/packages/framework.yaml b/config/packages/framework.yaml index 7853e9e..3ef8da6 100644 --- a/config/packages/framework.yaml +++ b/config/packages/framework.yaml @@ -1,24 +1,24 @@ # see https://symfony.com/doc/current/reference/configuration/framework.html framework: - secret: '%env(APP_SECRET)%' - #csrf_protection: true - http_method_override: false + secret: "%env(APP_SECRET)%" + #csrf_protection: true + http_method_override: false - # Enables session support. Note that the session will ONLY be started if you read or write from it. - # Remove or comment this section to explicitly disable session support. - session: - handler_id: null - cookie_secure: auto - cookie_samesite: lax - storage_factory_id: session.storage.factory.native + # Enables session support. Note that the session will ONLY be started if you read or write from it. + # Remove or comment this section to explicitly disable session support. + session: + handler_id: null + cookie_secure: auto + cookie_samesite: lax + storage_factory_id: session.storage.factory.native - #esi: true - #fragments: true - php_errors: - log: true + #esi: true + #fragments: true + php_errors: + log: true when@test: - framework: - test: true - session: - storage_factory_id: session.storage.factory.mock_file + framework: + test: true + session: + storage_factory_id: session.storage.factory.mock_file diff --git a/config/packages/routing.yaml b/config/packages/routing.yaml index 4b766ce..c0f1474 100644 --- a/config/packages/routing.yaml +++ b/config/packages/routing.yaml @@ -1,12 +1,12 @@ framework: - router: - utf8: true + router: + utf8: true - # 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 + # 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 + framework: + router: + strict_requirements: null diff --git a/public/media/boxing_ring.jpg b/public/media/boxing_ring.jpg new file mode 100644 index 0000000..79e8d58 Binary files /dev/null and b/public/media/boxing_ring.jpg differ diff --git a/public/script/combat.js b/public/script/combat.js new file mode 100644 index 0000000..d057f4a --- /dev/null +++ b/public/script/combat.js @@ -0,0 +1,38 @@ +document.addEventListener('DOMContentLoaded', () => { + const left = document.querySelector('.left-emoji'); + const right = document.querySelector('.right-emoji'); + const winnerText = document.getElementById('winner-text'); + + // These variables will be injected by Twig in the template as data attributes or global variables + const winnerSide = window.winnerSide; + const loserSide = window.loserSide; + + left.classList.add('slide-in-left'); + right.classList.add('slide-in-right'); + + setTimeout(() => { + left.style.left = '100px'; + right.style.left = '300px'; + + left.classList.add('fight-animation'); + right.classList.add('fight-animation'); + + setTimeout(() => { + left.classList.remove('fight-animation'); + right.classList.remove('fight-animation'); + + const loser = loserSide === 'left' ? left : right; + loser.classList.add('loser-fly-up'); + const wing = document.createElement('div'); + wing.classList.add('wing'); + wing.textContent = '🪽'; + loser.appendChild(wing); + + const winner = winnerSide === 'left' ? left : right; + winner.classList.add('winner-center', 'winner-crown'); + + winnerText.textContent = `${winner.textContent.trim()} a gagné ! 🎉`; + winnerText.style.display = 'block'; + }, 1500); + }, 3000); +}); diff --git a/public/style/combat.css b/public/style/combat.css new file mode 100644 index 0000000..dbf0025 --- /dev/null +++ b/public/style/combat.css @@ -0,0 +1,133 @@ +body { + margin: 0; + height: 100vh; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + background-image: url("../media/boxing_ring.jpg"); + background-position: center; + background-repeat: no-repeat; + background-size: cover; + overflow: hidden; + font-family: Arial, sans-serif; +} + +.arena { + position: relative; + width: 400px; + height: 150px; +} + +.emoji { + position: absolute; + top: 50%; + font-size: 5rem; + transform: translate(-50%, -50%); +} + +.left-emoji { + left: -100px; +} + +.right-emoji { + left: 500px; +} + +@keyframes slideInLeft { + to { + left: 100px; + } +} + +@keyframes slideInRight { + to { + left: 300px; + } +} + +.slide-in-left { + animation: slideInLeft 3s forwards; +} + +.slide-in-right { + animation: slideInRight 3s forwards; +} + +@keyframes fightShake { + 0%, + 100% { + transform: translate(-50%, -50%) translateX(0); + } + 20%, + 60% { + transform: translate(-50%, -50%) translateX(-15px); + } + 40%, + 80% { + transform: translate(-50%, -50%) translateX(15px); + } +} + +.fight-animation { + animation: fightShake 0.5s 3; +} + +@keyframes flyUpFade { + to { + opacity: 0; + transform: translate(-50%, calc(-150px - 50%)); + } +} + +.loser-fly-up { + animation: flyUpFade 3s forwards; + position: absolute; +} + +.wing { + font-size: 2rem; + margin-top: -1.5rem; + animation: wingFlap 3s infinite; +} + +@keyframes wingFlap { + 0%, + 100% { + transform: rotate(0deg); + } + 50% { + transform: rotate(15deg); + } +} + +@keyframes moveToCenter { + to { + left: 50%; + transform: translate(-50%, -50%); + } +} + +.winner-center { + animation: moveToCenter 1s forwards; + position: absolute !important; + top: 50% !important; + font-size: 6rem; + z-index: 10; +} + +.winner-crown::after { + content: "👑"; + position: absolute; + top: -1.5rem; + left: 50%; + transform: translateX(-50%); + font-size: 2rem; +} + +#winner-text { + margin-top: 1rem; + font-size: 2rem; + text-align: center; + display: none; +} diff --git a/src/Controller/CombatController.php b/src/Controller/CombatController.php new file mode 100644 index 0000000..d1e1556 --- /dev/null +++ b/src/Controller/CombatController.php @@ -0,0 +1,42 @@ +render('combat/index.html.twig', [ + 'left_emoji' => $leftEmoji, + 'right_emoji' => $rightEmoji, + 'winner' => $winner, + 'loser' => $loser, + ]); + } + + #[Route('/combat-{leftEmoji}-{rightEmoji}-{winner}', name: 'app_combat_with_params', requirements: ['leftEmoji' => '.+', 'rightEmoji' => '.+'])] + public function combatWithParams(string $leftEmoji, string $rightEmoji, string $winner): Response + // Example : /combat-🐱-🐶-left + { + $loser = ($winner === 'left') ? 'right' : 'left'; + + return $this->render('combat/index.html.twig', [ + 'left_emoji' => $leftEmoji, + 'right_emoji' => $rightEmoji, + 'winner' => $winner, + 'loser' => $loser, + ]); + } +} diff --git a/src/Controller/EmojiController.php b/src/Controller/EmojiController.php index c8a6b83..bc4359d 100644 --- a/src/Controller/EmojiController.php +++ b/src/Controller/EmojiController.php @@ -8,7 +8,7 @@ use Symfony\Component\Routing\Annotation\Route; class EmojiController extends AbstractController { - #[Route('/emoji', name: 'app_emoji')] + #[Route('/emoji', name: 'app_emoji')] public function index(): Response { return $this->render('emoji/index.html.twig', [ diff --git a/symfony.lock b/symfony.lock index 6eda14c..4a0d895 100644 --- a/symfony.lock +++ b/symfony.lock @@ -1,4 +1,13 @@ { + "doctrine/deprecations": { + "version": "1.1", + "recipe": { + "repo": "github.com/symfony/recipes", + "branch": "main", + "version": "1.0", + "ref": "87424683adc81d7dc305eefec1fced883084aab9" + } + }, "doctrine/doctrine-bundle": { "version": "2.13", "recipe": { diff --git a/templates/combat/index.html.twig b/templates/combat/index.html.twig new file mode 100644 index 0000000..e988d2b --- /dev/null +++ b/templates/combat/index.html.twig @@ -0,0 +1,25 @@ + + +
+ + +