# Front-end Guidelines This is a Laravel 12 e-commerce project using Lunar PHP (headless). These guidelines apply to all front-end work. --- ## Project Language Settings - **Greek register:** `singular` — use the informal second person (εσύ/σου/σε). e.g. "Η κριτική σου", "Το όνομά σου", "Το email σου" All UI text written for this project must follow the register above. --- ## Localization Uses classic Laravel localization (https://laravel.com/docs/13.x/localization) — no third-party i18n routing package. **Locales:** Greek (`el`) is primary/default, English (`en`) is secondary. Set in `config('app.available_locales')` (`config/app.php`). **URL structure:** every route is prefixed with `{locale}`, including the default — `3dealer.gr/el/...` and `3dealer.gr/en/...`. Bare root (`/`) 301-redirects to `/el` (see `routes/web.php`). This avoids the ambiguity of an unprefixed default locale (see the reasoning in project memory / past conversation — prefixing every locale keeps hreflang symmetrical and scales cleanly to a third language later). **URL slugs are the same across both locales, permanently** — e.g. `/el/products/{x}` and `/en/products/{x}`, not `/el/proionta/{x}` vs `/en/products/{x}`. This is a deliberate, standing decision for this project, not a placeholder to revisit later. Only the visible content is translated, not the slug. Do not introduce per-locale translated slugs (e.g. a `lang/{locale}/routes.php` segment map) unless the user explicitly asks for that to change. **How it's wired:** - All routes live inside `Route::prefix('{locale}')->where('locale', ...)->middleware('setlocale')` in `routes/web.php`. - `App\Http\Middleware\SetLocale` validates the `{locale}` segment (404s if not in `available_locales`), calls `App::setLocale()`, and shares `$currentLocale`, `$altLocale`, and `$altLocaleUrl` (the same page in the other locale) to every view — this is what powers both the header's language switcher and the `
` hreflang tags in `resources/views/layouts/app.blade.php`. Don't recompute this logic elsewhere; read those shared variables instead. - When adding a new route, put it inside that `{locale}` group and give it a route `name()` — the alt-locale URL generation in the middleware depends on the current route being named (falls back to the locale root if unnamed). - When linking to a page in Blade, prefer `route('name', [...])` (locale is a normal route param, defaults to `app()->getLocale()` implicitly via the shared route group) over hand-built path strings, except for pages that don't have a controller/route yet (e.g. `/products`, `/contact`, `/cart` placeholders in the header currently use `url('/'.app()->getLocale().'/products')` — replace with `route()` once those pages exist). - **Every controller action for a route inside the `{locale}` group must declare `$locale` as its first parameter, even if unused** — e.g. `show(string $locale, Product $product)`. Laravel's `ControllerDispatcher` ultimately calls the controller with `...array_values($parameters)`, i.e. **positionally**. If a route-bound model parameter (like `$product`) isn't preceded by a matching `$locale` parameter in the method signature, the resolved values shift out of position and the wrong value (the locale string) gets passed where the model was expected — a `TypeError` that's easy to misread as a binding failure. Closures with zero declared parameters are unaffected (PHP just ignores the extra positional arg), so this only bites real controller methods. **Where translatable strings go:** - Most UI copy is editable by the client/marketing team via **Stoic** (the headless CMS) — don't hardcode it here. - Small strings that don't need client editing (nav labels, aria-labels, tab labels, pluralized counts) go in Laravel's own lang files at **`lang/{locale}/*.php`** (project root, per Laravel 12+ convention — not `resources/lang`). Current file: `lang/el/general.php` / `lang/en/general.php`. Use `__('general.key')` or `trans_choice('general.key', $count, [...])` for pluralized strings. --- ## Tech Stack - **Laravel 12** + **Lunar PHP 1.3** (headless e-commerce) - **Blade** for templating (`@extends`, `@section`, `@yield`, components) - **Tailwind CSS v4** via `@tailwindcss/vite` — zero config, `@import 'tailwindcss'` only - **Stimulus JS** for interactivity — controllers registered in `resources/js/stimulus/index.js` - **Popover API** (native browser) for overlays — no JS overlay libraries - SQLite database, `npm run dev` for local asset compilation --- ## Key File Locations | What | Where | |---|---| | CSS entry point | `resources/css/app.css` | | Font definitions | `resources/css/fonts.css` | | JS entry point | `resources/js/app.js` | | Stimulus controllers | `resources/js/stimulus/` | | JS utilities | `resources/js/utils/` | | Layout | `resources/views/layouts/app.blade.php` | | UI components (atomic) | `resources/views/components/ui/` | | Section components | `resources/views/components/` | | Page views | `resources/views/{page}/` | | Public assets | `public/images/` | --- ## Design Reference The Bluebeard template (`resources/css/bluebeard.css`) is used as a **reference only** for colors, spacing, typography, and effects. It is never imported or used directly. Everything is translated to Tailwind utilities or custom CSS where unavoidable. The boboko project at `/Users/farenoubi/Projects/boboko-test` can be referenced for CSS architecture patterns. --- ## Tailwind vs. Custom CSS **Prefer Tailwind utilities by default.** Write custom CSS only when something genuinely cannot be expressed as a utility: - Pseudo-elements (`::before`, `::after`) with dynamic transforms or transitions - Complex descendant/sibling selectors (e.g. `.group:hover .nav-dropdown`) - Keyframe animations - The underline-slide animation on nav links (background-size trick) **Never** write inline CSS (`style="..."`). **Never** write custom CSS for something Tailwind already covers. When a component requires a CSS class (e.g. as a hook for a pseudo-element), still put all properties that can be Tailwind utilities as classes on the element in the component file. The CSS rule should contain only what genuinely cannot be a utility — pseudo-elements, complex selectors, keyframes. Do not default to putting all styles in the CSS class just because the class exists. When custom CSS is needed, add it to `resources/css/app.css` inside `@layer components`. Keep the rule minimal — only what can't be a utility. --- ## Design Tokens Defined in `@theme {}` in `app.css`: - `--font-sans`: Manrope (body text) - `--font-display`: Manrope (headings, nav, buttons) — kept separate from `--font-sans` in case they diverge later Reuse existing colors (`neutral-200`, `black`), font sizes, spacing, and border styles as components are built. Do not invent new values — check what's already in use first. --- ## Component Structure ### `resources/views/components/ui/` — atomic, reusable UI elements Single-purpose, stateless or minimally stateful elements used across many contexts: - `button.blade.php` ✓ - `input.blade.php` - `input-group.blade.php` - `icon.blade.php` - `image.blade.php` - `tabs.blade.php` / `tab.blade.php` - `accordion.blade.php` - `tooltip.blade.php` - `badge.blade.php` - etc. ### `resources/views/components/` — section-level or composite components Larger reusable blocks made of several elements, often with real content: - `header.blade.php` ✓ - `footer.blade.php` - `cta.blade.php` - `product-card.blade.php` - `contact-section.blade.php` - etc. --- ## Interactivity ### Popover API for overlays For **tooltips, modals, dropdowns, and any overlay**: use the native [Popover API](https://developer.mozilla.org/en-US/docs/Web/API/Popover_API) with CSS — no JS, no libraries. ```html