14 marca światło dzienne ujrzał nowy motyw graficzny dla Składu Muzycznego, kodowo nazwany Groove-2026. 🚀
Motyw powstał jednoosobowo — od koncepcji, przez design tokens, po implementację i wdrożenie (nie jestem programistą PHP). 🛠️
Głównym założeniem było stworzenie wyrazistego, zapamiętywalnego designu w stylu "vintage comic" z zachowaniem norm dostępności (WCAG) i wydajności. Brzmi jak standardowy projekt e-commerce? Być może, dopóki nie spojrzy się na architekturę, na której postawiony jest sklep.
Zderzenie dwóch światów ⚔️
Na co dzień pracuję w technologiach, takich jak to portfolio — oparte na Next.js i React. To nowoczesne podejście, gdzie wszystko jest komponentem, style mogą być izolowane, a system budowania dba o minifikację i optymalne ładowanie zasobów. Jeśli potrzebuję nowego przycisku, tworzę <Button />, przekazuję mu propsy, używam Tailwind CSS i mam pewność, że to zadziała. ⚛️
Tymczasem w projekcie Groove-2026 musiałem wdrożyć te same nowoczesne koncepcje (modularyzację, design tokens, a11y) na platformie opartej na Symfony 1.0.19 (z 2010 roku) i silniku szablonów Smarty 2.6.33, uruchomionej na PHP 7.4. Bez znajomości PHP oznaczało to dodatkową pokorę i sporo pracy "na zimno" w legacy stosie. 🧩
Jak to wygląda w praktyce?
1. Style i Modularyzacja 🎨
W Next.js / React: Tailwind i CSS Modules rozwiązują problem zakresu stylów. Komponenty są izolowane.
W Smarty (Legacy): Przed przebudową miałem do czynienia ze "spaghetti CSS" z 444 deklaracjami !important i globalnym zasięgiem. Zamiast bundlera, trzeba było zaimplementować warstwowy, własny loader CSS w Smarty (_css_loader.html) wraz z odpowiadającym mu wrapperem PHP (_css_loader.php). Loader odczytuje aktualny moduł i akcję z kontekstu Symfony (sfContext::getModuleName(), getActionName()) i na tej podstawie rejestruje tylko potrzebne pliki stylów. Plik dla koszyka ładuje się w koszyku, dla bloga tylko na blogu, itd.
2. Zmienne (Design Tokens) 🧬
W Next.js / React: Zmienne definiuję raz w tailwind.config.ts (dla wersji 3) i korzysta się z klas użytkowych w całym projekcie.
W Smarty (Legacy): Został zbudowany cały kanoniczny system w natywnym CSS w :root. Fonty (Bangers, Quicksand) są hostowane lokalnie jako pliki .woff2/.ttf dla pełnej kontroli nad ładowaniem. Odstępy, typografia i kolory musiały zostać ręcznie ujednolicone we wszystkich 197 przebudowanych plikach szablonów (.html), by zyskać pełną spójność i skalowalność przy zmianach, np. w ramach sezonowych modyfikacji sklepu.
3. Komponenty a Szablony 🧱
W Next.js / React: Wszystko to stan, propsy i reużywalne funkcje składowe widoku.
W Smarty (Legacy): Praca z klasycznym cyklem żądanie-odpowiedź. Aby zaimplementować zaawansowaną dostępność — skip link do #main-content w każdym layoucie, regiony aria-live dla dynamicznych zmian w koszyku i wyszukiwarce, czy pełne atrybuty role="dialog" i aria-modal w modalach — trzeba było ingerować w statyczne pliki HTML generowane przez serwer i we wbudowany kod jQuery (w wersji 1.8.3, z 2012 roku), uważając by nie zepsuć dziesiątek zależności sprzed lat.
Czego uczy to wdrożenie? 🤔
Największym sukcesem w tym projekcie nie jest tylko unikalny wygląd (chociaż te grube, komiksowe bordery i mocne cienie robią świetną robotę). Najważniejsze jest udowodnienie, że nowoczesne koncepcje inżynieryjne (Design Tokens, modularyzacja, WCAG) są całkowicie niezależne od frameworka.
Groove-2026 pokazuje, że nawet na dojrzałym, wieloletnim systemie e-commerce nie trzeba tkwić w technologicznym długu. Wystarczy przenieść pragmatyczne podejście i inżynieryjną rygorystyczność z Reacta w środowisko legacy.
To była solidna, niemal chirurgiczna operacja na żywym organizmie. I zdecydowanie było warto, zwłaszcza że nie znam PHP.
Na koniec: klasyczne "u mnie działa" z DEV nie przeniosło się w 100% na PROD. Są zakamarki serwisu, gdzie style się nie ładują — i tak miało być: prace trwają, jest co poprawiać, a dzięki temu motyw wciąż ewoluuje. A co dalej? W planach jest postawienie sklepu na Next.js z wykorzystaniem nowych technologii i architektury, ale jeszcze nie teraz, może za jakiś czas (może za tydzień 😉).