Vue Starter Kit - v1.0.1

Getting Started

After installation, here's a 5-minute tour.

What's where

app/
├── Http/
│   ├── Controllers/
│   │   ├── Auth/                    Login, register, password reset, etc.
│   │   ├── Settings/                Profile / Password / Appearance
│   │   └── Controller.php           Base controller
│   ├── Middleware/
│   │   └── HandleInertiaRequests.php  Shared props (auth, flash, etc.)
│   └── Requests/
│       ├── Auth/LoginRequest.php
│       └── Settings/{ProfileUpdate,PasswordUpdate}Request.php
├── Models/User.php
└── Console/Commands/OptionalPackagesCommand.php

resources/
├── css/app.css                      Tailwind + DaisyUI + tokens
├── js/
│   ├── app.vue                      Inertia client entry
│   ├── ssr.vue                      Inertia SSR entry
│   ├── components/AppLogo.vue
│   ├── layouts/
│   │   ├── AppLayout.vue            Sidebar + mobile navbar + toast region
│   │   ├── AuthLayout.vue           Centered card for auth pages
│   │   └── SettingsLayout.vue       AppLayout + settings tabs sidebar
│   ├── lib/InertiaToastProvider.vue Local copy bypassing adapter root-import bug
│   ├── pages/                       Inertia pages (resolved by createInertiaApp)
│   ├── actions/                     ⟵ generated by wayfinder
│   └── routes/                      ⟵ generated by wayfinder
└── views/
    └── app.blade.php                Inertia root template

routes/
├── web.php                          Welcome, dashboard, settings
├── auth.php                         Login/register/forgot/reset/etc.
└── console.php

Add a new page

  1. Add the route in routes/web.php:

    Route::get('reports', function () {
        return Inertia::render('Reports', [
            'rows' => Report::latest()->get(),
        ]);
    })->middleware(['auth'])->name('reports');
    
  2. Run php artisan wayfinder:generate (or just keep the dev server running — the Vite plugin regenerates on save).

  3. Create resources/js/pages/Reports.vue:

    import { Head } from '@inertiajs/vue3';
    import AppLayout from '@/layouts/AppLayout';
    import type { ReactNode } from 'react';
    
    interface Report {
        id: number;
        title: string;
    }
    
    interface Props {
        rows: Report[];
    }
    
    export default function Reports({ rows }: Props) {
        return (
            <>
                <Head title="Reports" />
                <div className="p-6 max-w-6xl mx-auto">
                    <h1 className="text-2xl font-semibold">Reports</h1>
                    <ul className="menu mt-4">
                        {rows.map((r) => (
                            <li key={r.id}>{r.title}</li>
                        ))}
                    </ul>
                </div>
            </>
        );
    }
    
    Reports.layout = (page: ReactNode) => <AppLayout>{page}</AppLayout>;
    
  4. Optional: add a sidebar entry in resources/js/layouts/AppLayout.vue's NAV array.

Forms

Use Inertia's useForm with @artisanpack-ui/vue/form components:

import { useForm } from '@inertiajs/vue3';
import { Button, Input } from '@artisanpack-ui/vue/form';

const form = useForm({ title: '' });

<form onSubmit={(e) => { e.preventDefault(); form.post('/reports'); }}>
    <Input
        name="title"
        label="Title"
        value={form.data.title}
        error={form.errors.title}
        onChange={(e) => form.setData('title', e.target.value)}
        required
    />
    <Button type="submit" color="primary" loading={form.processing}>Save</Button>
</form>

Flash messages

Returning back()->with('success', '...') from a controller surfaces as a toast — HandleInertiaRequests shares flash and InertiaToastProvider (in AppLayout/AuthLayout) listens for it.

Next steps