YourBOX Frontend
Purpose
Section titled “Purpose”ADR-0007 commits YourBOX to a Twig plus Tailwind CSS plus Stimulus stack. This page documents the asset pipeline, the design tokens, the Stimulus controller layout, the Turbo integration and the testing strategy.
Asset Pipeline
Section titled “Asset Pipeline”Assets live under app/assets/ and are mapped by the Symfony AssetMapper bundle.
The Tailwind compiler runs at container build time through the
symfony/ux-twig-component integration.
app/├── assets/│ ├── app.js # Stimulus boot, Turbo import│ ├── controllers/ # Stimulus controllers│ │ ├── like_dislike_controller.js│ │ ├── comment_reply_controller.js│ │ ├── upload_progress_controller.js│ │ ├── video_player_controller.js│ │ └── search_autosubmit_controller.js│ ├── styles/│ │ ├── app.css # Tailwind entry: @import "tailwindcss";│ │ ├── tokens.css # Design tokens (colors, spacing, typography)│ │ ├── components.css # Custom component classes│ │ └── admin.css # Tailwind theme for EasyAdmin│ └── images/└── public/assets/ # Compiled output (gitignored)The Dockerfile build stage runs:
php bin/console asset-map:compilenpx @tailwindcss/cli -i assets/styles/app.css -o public/assets/styles/app.<hash>.css --minifyThe hashed filename invalidates the browser cache on every change.
Design Tokens
Section titled “Design Tokens”The token file lives at app/assets/styles/tokens.css and exposes the palette,
typography scale and spacing scale as CSS variables. The values follow the homelab
visual identity used by the documentation site so that the brand is consistent
across YourBOX and docs.yourbox.site.
@theme { --color-brand-50: #fef2f2; --color-brand-100: #fee2e2; --color-brand-500: #ef4444; --color-brand-700: #b91c1c; --color-brand-900: #7f1d1d;
--font-display: "Inter", system-ui, sans-serif; --font-mono: "JetBrains Mono", monospace;
--radius-card: 0.75rem; --shadow-card: 0 1px 2px rgb(0 0 0 / 0.05), 0 4px 12px rgb(0 0 0 / 0.06);
--container-prose: 70ch;}Pages and components use Tailwind utilities first. Repeated patterns (a video
card, a comment bubble, a pagination strip) live as component classes in
components.css:
.video-card { @apply rounded-[var(--radius-card)] bg-white shadow-[var(--shadow-card)] transition hover:shadow-lg overflow-hidden;}.comment-bubble { @apply rounded-2xl bg-zinc-50 px-4 py-3 ring-1 ring-zinc-200;}Template Layout
Section titled “Template Layout”Templates live under app/templates/ and follow the bounded contexts:
templates/├── base.html.twig # Shell, head, nav, footer, flash├── components/ # Reusable Twig partials│ ├── flash.html.twig│ ├── pagination.html.twig│ └── video_card.html.twig├── catalog/│ ├── index.html.twig│ ├── search.html.twig│ ├── show.html.twig│ └── upload.html.twig├── engagement/│ └── comment_thread.html.twig├── identity/│ ├── login.html.twig│ └── profile.html.twig└── admin/ # EasyAdmin overrides └── layout.html.twigbase.html.twig carries the shell, the menu, the flash bag rendering and the
asset import. Concrete templates extend it and only fill the content block.
Stimulus Controllers
Section titled “Stimulus Controllers”Stimulus replaces every piece of jQuery in the 2020 codebase. Controllers live
under app/assets/controllers/ and are wired automatically by the Symfony
StimulusBundle. Each controller covers one feature:
like_dislike_controller.jstoggles the like and dislike buttons, posts the vote through Fetch with the CSRF token, updates the counter and applies the active class on success.comment_reply_controller.jstoggles the reply form, manages the focus and posts the comment through a Turbo Frame so the thread updates without a full page reload.upload_progress_controller.jslistens for the XHR progress events on the upload form, renders a Tailwind styled progress bar and displays the queued transcoding state once the upload completes.video_player_controller.jswraps the native HTML5 video element, handles keyboard shortcuts (space to play and pause, arrow keys to seek), and emits aVideoViewedevent after 5 seconds of playback.search_autosubmit_controller.jsdebounces the search input by 250 ms and triggers the surrounding Turbo Frame submission.
Symfony UX Turbo
Section titled “Symfony UX Turbo”Turbo is enabled on the catalog, the comment threads and the search results. Link
clicks within the same site swap the body without a full reload. Form submissions
that target a Turbo Frame replace the frame content. The base layout opts in by
adding the data-turbo-track="reload" attribute to its asset imports.
The legacy fallback bundle is opted out: requests served by the legacy controller
add a Turbo-Visit-Control: reload header so that navigation between a Symfony
page and a legacy page does a clean full reload. This avoids accidentally
hot swapping a Turbo enabled page with a legacy DOM.
Accessibility
Section titled “Accessibility”Every page passes axe-core in the Cypress test suite. Specific commitments:
- Form fields carry an explicit
labelelement. No placeholder is used as a label substitute. - Buttons have visible focus rings provided by Tailwind’s
focus-visibleutilities. - The video player exposes the native controls plus a Stimulus controller that preserves keyboard navigation.
- The contrast ratio respects WCAG AA. The token palette is calibrated for this.
Testing Strategy
Section titled “Testing Strategy”- Jest for pure JavaScript logic inside Stimulus controllers. The DOM
contract is mocked with
@testing-library/dom. - Symfony WebTestCase for server rendered template assertions. The page source is parsed and matched against expected DOM nodes.
- Cypress for end to end flows. The Cypress suite runs against docker compose in CI and against the VPS smoke test deployment.
- axe-core runs inside the Cypress suite to catch accessibility regressions.
Migration From The Legacy Frontend
Section titled “Migration From The Legacy Frontend”The migration is per route per the Symfony Migration page. When a route is ported:
- The Twig template replaces the inline HTML in the corresponding 2020 PHP file.
- The Stimulus controller replaces the jQuery snippet. The jQuery global stays available on legacy pages only.
- The Tailwind tokens replace the per page stylesheet. The legacy CSS file under
YourBOX/src/assets/stylesheets/is deleted. - The Turbo Frame wrapping the new content is added once at least two pages share the same shell, otherwise the page stays a full document.