Skip to content

Inertia/React + Wayfinder Frontend

The parts of Yaya Engine that are not the Filament admin panel run on Inertia.js v2 with React: a Laravel controller renders Inertia::render('page-name'), and the React component whose file matches that name (under resources/js/pages/) is what the browser shows — there is no client-side router and no separate SPA build, just one component per server route [@pages-dir]. This pattern applies to both the small set of general pages under resources/js/pages/ and to the whole Yaya Manager console under resources/js/pages/manager/. Outside manager/, the page set is deliberately small: welcome.tsx (the public landing page), dashboard.tsx, settings/profile.tsx, settings/appearance.tsx, and mcp/auth/login.tsx — a separate login screen for MCP-token administration, distinct from both the Filament login and the Manager login [@pages-dir].

From a Laravel route to a typed helper

The bridge between the two languages is Wayfinder, wired into the build as @laravel/vite-plugin-wayfinder in vite.config.ts with wayfinder({ formVariants: true }) [@vite-config]. The workflow runs in one direction: a route is declared in PHP first — in routes/web.php, routes/auth.php, routes/settings.php, routes/manager.php, or as a Filament resource/page class — and Wayfinder generates a matching TypeScript file under resources/js/routes/** or resources/js/actions/** the next time Vite runs. These files are 100% generated and are never hand-edited; the plugin regenerates them automatically on every dev server start and build.

The generated shape is consistent everywhere. Take the root route, Route::get('/', fn () => Inertia::render('welcome'))->name('home') at routes/web.php:22 [@web-routes]. Wayfinder emits a home export in resources/js/routes/index.ts with a .url() method, verb-named callables (.get(), .head()), a matching homeForm object for progressive-enhancement <form> submission, and a @see routes/web.php:22 JSDoc comment repeated above every generated member, linking each generated function straight back to the PHP line that produced it [@routes-index]. welcome.tsx consumes this directly — import { dashboard, login } from '@/routes' and <Link href={dashboard()}> — so navigation targets are typed and refactor-safe: renaming or moving a Laravel route regenerates the helper and produces a TypeScript error at every call site that still points at the old shape, instead of a silent broken link discovered at runtime [@welcome-page].

Wayfinder does not stop at plain routes. It walks the full App\... namespace, so Filament resource and page classes get the same generated helpers under resources/js/actions/App/Filament/Resources/** and .../Pages/**, even though those classes are never rendered as Inertia pages themselves [@actions-filament-dir]. This matters because it means any PHP route or Filament action anywhere in the app is reachable from the frontend through the same typed pattern — a future integration between the Manager console and a Filament action would not need a hand-written fetch call, just an import from the generated tree.

Styling and components

Tailwind is configured CSS-first, the Tailwind v4 pattern: there is no tailwind.config.js in the repo, and the @tailwindcss/vite plugin reads configuration straight out of resources/css/app.css, which uses @import 'tailwindcss', @plugin 'tailwindcss-animate', @source directives to point at Blade views, and an @theme block for design tokens like --color-background [@app-css] [@vite-config]. components.json still declares a tailwind.config path for tooling compatibility, but the file it points to does not exist — shadcn's CLI and Tailwind v4 both tolerate this because the real configuration lives in the CSS file [@components-json].

components.json configures shadcn/ui with style: "default", baseColor: "neutral", cssVariables: true, and iconLibrary: "lucide" [@components-json]. resources/js/components/ui/ holds the generated primitives this produces — alert, avatar, badge, breadcrumb, button, card, checkbox, collapsible, dialog, dropdown-menu, icon, input, label, navigation-menu, select, separator, sheet, sidebar, skeleton, table, textarea, toggle, toggle-group, and tooltip, each a thin Radix wrapper styled with Tailwind [@ui-components-dir]. resources/js/lib/utils.ts exports the cn() helper (clsx plus tailwind-merge) that every one of those components uses to merge caller-supplied class names with its own defaults, plus a toUrl() helper that normalizes Inertia's InertiaLinkProps['href'] — which can be either a plain string or a Wayfinder route-definition object — down to a string, so components that need a raw URL do not have to special-case which form a href prop arrived in [@utils-ts].