diff --git a/ux.symfony.com/assets/images/ux_packages/stimulus-1200x675.png b/ux.symfony.com/assets/images/ux_packages/stimulus-1200x675.png new file mode 100644 index 00000000000..4d7f5a688b4 Binary files /dev/null and b/ux.symfony.com/assets/images/ux_packages/stimulus-1200x675.png differ diff --git a/ux.symfony.com/assets/images/ux_packages/stimulus.svg b/ux.symfony.com/assets/images/ux_packages/stimulus.svg new file mode 100644 index 00000000000..b951c16f759 --- /dev/null +++ b/ux.symfony.com/assets/images/ux_packages/stimulus.svg @@ -0,0 +1,5 @@ + + + + + diff --git a/ux.symfony.com/assets/styles/app.scss b/ux.symfony.com/assets/styles/app.scss index c38c96d208d..0b17c833edf 100644 --- a/ux.symfony.com/assets/styles/app.scss +++ b/ux.symfony.com/assets/styles/app.scss @@ -132,6 +132,7 @@ $utilities: map-remove( @import "components/DemoContainer"; @import "components/DemoCard"; @import "components/DocsLink"; +@import "components/FeatureBox"; @import "components/FileTree"; @import "components/Icon"; @import "components/IconGrid"; diff --git a/ux.symfony.com/assets/styles/components/_FeatureBox.scss b/ux.symfony.com/assets/styles/components/_FeatureBox.scss new file mode 100644 index 00000000000..82cf3b632aa --- /dev/null +++ b/ux.symfony.com/assets/styles/components/_FeatureBox.scss @@ -0,0 +1,49 @@ +.FeatureBox { + + --bg-color: var(--bs-body-bg); + [data-bs-theme="dark"] { + --bg-color: #1b1e21; + } + + background: var(--bg-color); + border: 1px solid var(--bs-secondary-bg-subtle); + border-radius: var(--border-radius); + display: grid; + padding: 1rem; + place-content: center; + gap: .75rem; +} + +.FeatureBox_icon { + height: 2.4rem; + display: grid; + place-content: center; + svg { + height: 100%; + width: 100%; + } + path, circle { + fill: var(--bs-body-bg); + fill-opacity: .1; + stroke: currentColor; + stroke-width: 1; + transition: 400ms; + } +} +.FeatureBox:hover { + path, circle { + fill-opacity: .15; + stroke-width: 1.25; + } +} + +.FeatureBox_title { + opacity: .85; + font-weight: 400; + font-size: 1rem; + font-family: var(--font-family-text); + color: var(--bs-body-color); + text-decoration: none; + line-height: 1; + text-align: center; +} diff --git a/ux.symfony.com/assets/styles/sections/_hero.scss b/ux.symfony.com/assets/styles/sections/_hero.scss index fbf30e7a289..30434b17bc8 100644 --- a/ux.symfony.com/assets/styles/sections/_hero.scss +++ b/ux.symfony.com/assets/styles/sections/_hero.scss @@ -7,9 +7,16 @@ } .hero-sub-text { - width: 40%; + width: 50%; text-wrap: balance; } +.hero-sub-text a { + border-bottom: 1.5px solid #ffff; + text-decoration: none; +} +.hero-sub-text a:hover { + color: inherit; +} @media (max-width: 1114px) { .hero-sub-text { diff --git a/ux.symfony.com/config/packages/ux_icons.yaml b/ux.symfony.com/config/packages/ux_icons.yaml index 61326164e87..43ecf5c476d 100644 --- a/ux.symfony.com/config/packages/ux_icons.yaml +++ b/ux.symfony.com/config/packages/ux_icons.yaml @@ -1,3 +1,10 @@ ux_icons: default_icon_attributes: class: 'Icon' + + icon_sets: + + # FeatureBox icons + feature: + alias: 'lucide' + # icon_attributes: diff --git a/ux.symfony.com/src/Controller/UxPackage/StimulusController.php b/ux.symfony.com/src/Controller/UxPackage/StimulusController.php new file mode 100644 index 00000000000..6719020f49c --- /dev/null +++ b/ux.symfony.com/src/Controller/UxPackage/StimulusController.php @@ -0,0 +1,35 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + */ + +namespace App\Controller\UxPackage; + +use App\Service\UxPackageRepository; +use Symfony\Bundle\FrameworkBundle\Controller\AbstractController; +use Symfony\Component\HttpFoundation\Response; +use Symfony\Component\Routing\Attribute\Route; + +class StimulusController extends AbstractController +{ + public function __construct( + private readonly UxPackageRepository $packageRepository, + ) { + } + + #[Route('/stimulus', name: 'app_stimulus')] + public function __invoke(): Response + { + $package = $this->packageRepository->find('stimulus'); + + return $this->render('ux_packages/stimulus.html.twig', [ + 'package' => $package, + ]); + } +} diff --git a/ux.symfony.com/src/Model/UxPackage.php b/ux.symfony.com/src/Model/UxPackage.php index 824983b45bd..bba81f52e5c 100644 --- a/ux.symfony.com/src/Model/UxPackage.php +++ b/ux.symfony.com/src/Model/UxPackage.php @@ -26,8 +26,9 @@ public function __construct( private string $gradient, private string $tagLine, private string $description, - private string $createString, + private ?string $createString = null, private ?string $imageFileName = null, + private ?string $composerName = null, ) { } @@ -73,7 +74,7 @@ public function getDescription(): string public function getComposerName(): string { - return 'symfony/ux-'.$this->getName(); + return $this->composerName ?? 'symfony/ux-'.$this->getName(); } public function getComposerRequireCommand(): string @@ -117,12 +118,21 @@ public function getScreencastLinkText(): ?string return $this->screencastLinkText; } + public function setOfficialDocsUrl(string $officialDocsUrl): self + { + $this->officialDocsUrl = $officialDocsUrl; + + return $this; + } + + private string $officialDocsUrl; + public function getOfficialDocsUrl(): string { - return \sprintf('https://symfony.com/bundles/ux-%s/current/index.html', $this->name); + return $this->officialDocsUrl ??= \sprintf('https://symfony.com/bundles/ux-%s/current/index.html', $this->name); } - public function getCreateString(): string + public function getCreateString(): ?string { return $this->createString; } diff --git a/ux.symfony.com/src/Service/UxPackageRepository.php b/ux.symfony.com/src/Service/UxPackageRepository.php index a0a2eb251a9..0810e0e8def 100644 --- a/ux.symfony.com/src/Service/UxPackageRepository.php +++ b/ux.symfony.com/src/Service/UxPackageRepository.php @@ -80,6 +80,21 @@ public function findAll(?string $query = null): array ->setDocsLink('https://turbo.hotwired.dev/handbook/introduction', 'Documentation specifically for the Turbo JavaScript library.') ->setScreencastLink('https://symfonycasts.com/screencast/turbo', 'Go deep into all 3 parts of Turbo.'), + (new UxPackage( + 'stimulus', + 'Stimulus', + 'app_stimulus', + '#2EB17B', + 'linear-gradient(to bottom right, #3D9A89 5%, #2EB17B 80%)', + 'Central Bridge of Symfony UX', + 'Integration with Stimulus for HTML-powered controllers', + null, + 'stimulus.svg', + 'symfony/stimulus-bundle', + )) + ->setOfficialDocsUrl('https://symfony.com/bundles/StimulusBundle') + ->setScreencastLink('https://symfonycasts.com/screencast/stimulus', 'More than 40 videos to master Stimulus.'), + new UxPackage( 'autocomplete', 'Autocomplete', @@ -100,7 +115,7 @@ public function findAll(?string $query = null): array 'Symfony Translations in JavaScript', "Use Symfony's translations in JavaScript", 'I need to translate strings in JavaScript', - 'translator.svg' + 'translator.svg', ), (new UxPackage( @@ -135,7 +150,7 @@ public function findAll(?string $query = null): array 'linear-gradient(95deg, #35B67C -5%, #8CE3BC 105%)', 'Render Vue components from Twig', 'Quickly render `` components & pass them props.', - 'I need to render Vue.js components from Twig' + null, )) ->setDocsLink('https://vuejs.org/', 'Go deeper with the Vue.js docs.'), @@ -147,7 +162,7 @@ public function findAll(?string $query = null): array 'linear-gradient(115deg, #BE3030, #FF3E00)', 'Render Svelte components from Twig', 'Quickly render `` components & pass them props.', - 'I need to render Svelte components from Twig', + null, 'svelte.svg', )) ->setDocsLink('https://svelte.dev/', 'Go deeper with the Svelte docs.'), @@ -160,7 +175,7 @@ public function findAll(?string $query = null): array 'linear-gradient(136deg, #1E8FA8 -7%, #3FC0DC 105%)', 'Form Tools for cropping images', 'Form Type and tools for cropping images', - 'I need to add a JavaScript image cropper' + null, )) ->setDocsLink('https://github.com/fengyuanchen/cropperjs', 'Cropper.js documentation.'), @@ -172,7 +187,6 @@ public function findAll(?string $query = null): array 'linear-gradient(136deg, #AC2777 -8%, #F246AD 105%)', 'Delay Loading with Blurhash', 'Optimize Image Loading with BlurHash', - 'I need to delay large image loading' ), new UxPackage( @@ -194,7 +208,6 @@ public function findAll(?string $query = null): array 'linear-gradient(95deg, #D87036 -5%, #EA9633 105%)', 'Stylized Page Transitions', 'Integration with the page transition library Swup', - 'I need stylized page transitions' )) ->setDocsLink('https://swup.js.org/', 'Swup documentation'), @@ -206,7 +219,6 @@ public function findAll(?string $query = null): array 'linear-gradient(95deg, #204CA0 -6%, #3D82EA 105%)', 'Native Browser Notifications', 'Trigger native browser notifications from inside PHP', - 'I need to send browser notifications', ), new UxPackage( @@ -217,7 +229,6 @@ public function findAll(?string $query = null): array 'linear-gradient(142deg, #FD963C -15%, #BE0404 95%)', 'Password Visibility Switch', 'Switch the visibility of a password field', - 'I need to toggle the visibility of a password field', ), (new UxPackage( @@ -228,7 +239,6 @@ public function findAll(?string $query = null): array 'linear-gradient(95deg, #20A091 -5%, #4EC9B3 105%)', 'Animated Typing with Typed.js', 'Animated typing with Typed.js', - 'I need to type onto the screen... like this' )) ->setDocsLink('https://github.com/mattboldt/typed.js/', 'Typed.js documentation'), ]; diff --git a/ux.symfony.com/src/Twig/HomepageTerminalSwapper.php b/ux.symfony.com/src/Twig/HomepageTerminalSwapper.php index c3eb925d2f6..dca67b402af 100644 --- a/ux.symfony.com/src/Twig/HomepageTerminalSwapper.php +++ b/ux.symfony.com/src/Twig/HomepageTerminalSwapper.php @@ -11,6 +11,7 @@ namespace App\Twig; +use App\Model\UxPackage; use App\Service\UxPackageRepository; use App\Util\SourceCleaner; use Symfony\UX\TwigComponent\Attribute\AsTwigComponent; @@ -27,7 +28,8 @@ public function __construct(private UxPackageRepository $packageRepository) public function getTypedStrings(): array { $strings = []; - $packages = $this->packageRepository->findAll(); + $packages = array_filter($this->packageRepository->findAll(), fn (UxPackage $p): bool => null !== $p->getCreateString()); + shuffle($packages); foreach ($packages as $package) { diff --git a/ux.symfony.com/templates/components/FeatureBox.html.twig b/ux.symfony.com/templates/components/FeatureBox.html.twig new file mode 100644 index 00000000000..946b6c6eded --- /dev/null +++ b/ux.symfony.com/templates/components/FeatureBox.html.twig @@ -0,0 +1,6 @@ +
+
+ +
+

{{ title }}

+
diff --git a/ux.symfony.com/templates/components/Package/PackageHeader.html.twig b/ux.symfony.com/templates/components/Package/PackageHeader.html.twig index 73d3f0eac5a..d3cf28ec734 100644 --- a/ux.symfony.com/templates/components/Package/PackageHeader.html.twig +++ b/ux.symfony.com/templates/components/Package/PackageHeader.html.twig @@ -1,22 +1,26 @@ -
+
-

{{ eyebrowText|raw }}

+

{{ eyebrowText|raw }}

-

{% block title_header %}{% endblock %}

+

{% block title_header %}{{ title|default }}{% endblock %}

- {% block sub_content %}{% endblock %} + {% block sub_content %}{{ subtitle|default }}{% endblock %}

-
- -
+ {% if command is not defined or command %} +
+ +
+ {% endif %} +
diff --git a/ux.symfony.com/templates/ux_packages/stimulus.html.twig b/ux.symfony.com/templates/ux_packages/stimulus.html.twig new file mode 100644 index 00000000000..7b11dc69cd8 --- /dev/null +++ b/ux.symfony.com/templates/ux_packages/stimulus.html.twig @@ -0,0 +1,130 @@ +{% extends 'ux_packages/package.html.twig' %} + +{% block package_header %} + + + Connects Stimulus, + UX packages, Asset Mapper, Webpack Encore... + Making it easy to add JavaScript interactivity to your Symfony apps! + + +{% endblock %} + +{% block package_content %} + +
+
+
+ + + + + +
+
+
+ +
+
+ +
+

Stimulus Twig Helpers

+
+ + + {% block stimulus_controller %} +
+ Welcome to your profile! +
+ + {# would render as #} + +
+ Welcome to your profile! +
+ {% endblock %} + +

stimulus_controller

+ + This function attaches a Stimulus controller to an HTML element and allows passing values (via + __data-attributes__) that can be accessed within the controller. + + These values are useful for providing dynamic data or configuration to your controller’s logic. +
+ + + {% block stimulus_target %} +
+ John Doe + + John's Avatar + +
+ + {# would render as #} + +
+ John Doe + + John's Avatar + +
+ {% endblock %} + +

stimulus_target

+ + This function defines one or more targets within a Stimulus controller. These targets allow you + to interact with specific DOM elements directly from your controller’s logic. +
+ + + {% block stimulus_action %} + + + {# would render as #} + + + {% endblock %} + +

stimulus_action

+ + This function attaches an event listener to an HTML element, defining actions that trigger specific + methods in the controller. + + This simplifies event handling by mapping DOM events (like `click`, `input`, etc.) directly to + controller methods, improving the clarity and maintainability of your code. +
+ +
+
+{% endblock %}