Frontend
Stack
React 19, Inertia 2, Vite, TypeScript, Tailwind CSS v4, Shadcn/Radix, i18next, Zustand, Motion (LazyMotion + domAnimation). Path alias @/ → resources/js.
Inertia pages and resolution
- Pages live in
resources/js/features/<name>/pages/(e.g.blog/Index→features/blog/pages/Index.tsx). The backend renders a component name likeblog/Indexorwelcome;app.tsxandssr.tsxuse a sharedpagePath()and glob to resolve it. Single-segment namewelcomemaps tofeatures/landing/pages/welcome.tsx. - PHP tests use
App\Core\Inertia\TestingViewFindersoassertInertia()->component('blog/Index')finds the correct file.
Layouts and components
- Layouts —
resources/js/layouts/(auth, app, settings, public). - components/ui/ — Shadcn primitives (Button, Input, Card, etc.). Prefer these for all interactive UI.
- components/common/ — Shared compositions (NavSearch, language switcher, SeoHead, motion presets). NavSearch shows results for pages, blog, FAQ, and testimonials (each only when its feature flag is active). Feature-specific UI in
features/<name>/components/.
Theme and i18n
- Single source of truth for appearance:
useAppearance(light/dark/system), persisted via cookie and localStorage. Language switcher uses sharedlocale_switch_urlsfrom the backend. - RTL: set
diron the document from locale; use logical spacing (ps-*,pe-*) and direction-aware icons.
Motion
- Page/section animation config in
components/common/motion-presets.ts(pageEnter, fadeInUp, fadeInUpView). Usemfrom motion/react with these presets; use Tailwind enter/exit for Shadcn overlays.
Adding a new page
- Add a file under
resources/js/features/<name>/pages/(e.g.Show.tsx). - Backend must call
Inertia::render('<name>/Show', ...). Runnpm run build(or dev) after adding routes so Wayfinder stays in sync.