1. Home
  2. Documentation

Documentation

Everything you need to build with Vantage.

Getting started

Vantage Laravel is an ordinary Laravel 12 application. There is no starter kit to unpick and no admin package wrapping the framework — routes are routes, views are Blade, and the asset pipeline is stock Vite.

It runs with no database. Every screen reads from a plain PHP class in app/Support/Demo, so php artisan serve is enough to see the whole template working.

1

Install dependencies

composer install
npm install

Requires PHP 8.2 or newer and Node 18 or newer.

2

Build the assets

npm run build

Compiles the stylesheet and the script into public/build.

3

Serve it

php artisan serve
npm run dev

The app runs at http://127.0.0.1:8000, with Vite hot-reloading your edits.

The stylesheet is shared, not copied

resources/sass/app.scss compiles the same layers under packages/ui/scss that the static, React and WordPress editions use. A change to a token or a component rule moves all of them at once.

File structure

app/
├── Http/Controllers/       DashboardController · OrderController · CalendarController
├── Providers/              Registers the pager view
└── Support/Demo/           Mock data — replace with your models
config/
├── vantage.php             Branding, default skin, the signed-in user
└── navigation.php          The sidebar, as data
resources/
├── sass/app.scss           tokens → Bootstrap → shared layers → product shell
├── js/app.js               Bootstrap's bundle + the shared behaviour script
└── views/
    ├── layouts/            app · auth · blank
    ├── partials/           sidebar · topbar · icons · auth art · theme boot
    ├── components/         The Blade component library
    ├── pages/              One view per screen
    └── vendor/pagination/  The template's pager
routes/web.php              Every screen, with named routes

Routing & layouts

Every screen is a named route in routes/web.php. The sidebar resolves those names from config/navigation.php, so renaming a route is caught at render time rather than shipping a dead link — and the active state works itself out from request()->routeIs().

To add a screen:

  • Add a view under resources/views/pages/ that extends a layout.
  • Add a named route in routes/web.php.
  • If it belongs in the sidebar, add a line to config/navigation.php.

Three layouts ship: layouts.app (sidebar and topbar), layouts.auth (the split sign-in screen) and layouts.blank (a bare shell for pages like the 404).

No authentication is included

The template has no auth layer, and guessing at one would only be in your way. The sign-in screens are presentation only. Install Laravel Breeze — the field names already match what it expects — then wrap the application routes in ->middleware('auth').

Blade components

resources/views/components holds anonymous Blade components for every recurring piece of the interface. They are plain files — no class, no registration.

<x-card hover>
  <x-card-header title="Recent orders" subtitle="Updated 4 minutes ago" />
  <x-card-body>
    <x-badge tone="success">Paid</x-badge>
    <x-meter :value="68" label="Storage used" />
  </x-card-body>
</x-card>
The Blade component library
ComponentPurpose
x-card and friendsThe surface every panel is built on.
x-page-headerBreadcrumb, title, lede and an actions slot.
x-stat-tileA figure with an optional icon and trend.
x-badgeStatus, with a dot so it is not colour alone.
x-trendAn arrow and words, for direction of travel.
x-meterA progress bar with the right ARIA built in.
x-alertFour tones, each with its own icon.
x-empty-stateWhat a table shows when it has nothing.
x-avatarInitials, three sizes.
x-chartArea, bar or donut. See below.
x-iconOne symbol from the sprite.

A card header that holds controls rather than a heading — the filter bars on Orders and Customers, for instance — is written out as a plain <div class="spm-card__header">, because a tablist must not sit inside an <h2>.

Replacing the data

The demo classes return Laravel collections, so the controllers already read the way they would against Eloquent. Swapping in real models is mostly deleting code.

// Before — a collection built in PHP
$orders = Orders::all()->where('status', $status);

// After — an Eloquent query
$orders = Order::query()
    ->when($status, fn ($q) => $q->where('status', $status))
    ->paginate(8)
    ->withQueryString();

OrderController builds its paginator by hand only because these rows come from an array. With Eloquent you call ->paginate() and delete that method — the view does not change, because it already speaks $orders->links(), ->firstItem() and ->total().

Derived figures are computed rather than stored — invoice totals come from their line items, device percentages from the same numbers the donut draws — so the text beside a chart cannot drift out of step with it. Keep that habit.

Design tokens

Colour, type, spacing, radii, shadows and motion all live in one file: packages/tokens/tokens.json. Running npm run tokens from the repository root compiles it into Bootstrap Sass variables and CSS custom properties.

/* Every token is also a CSS custom property at runtime */
.my-component {
  color: var(--spm-neutral-700);
  background: var(--spm-neutral-0);
  padding: var(--spm-space-5);
  border-radius: var(--spm-radius-lg);
  box-shadow: var(--spm-shadow-md);
  transition: all var(--spm-motion-base) var(--spm-motion-ease);
}

To change the palette, edit the JSON and rebuild. Nothing else needs touching.

Theming &amp; skins

Dark mode uses Bootstrap 5.3's native colour modes:

<html data-bs-theme="dark">

resources/views/partials/theme-boot.blade.php is a small inline script that sets this before first paint, reading a saved preference from localStorage and falling back to the operating system setting. That is what prevents the white flash you get with a bundled theme script. Keep it inline and keep it ahead of the stylesheet.

Skins are accent presets on the same element:

<html data-spm-skin="ocean">

The default comes from config/vantage.php, and a visitor's choice is remembered. Six ship with the template: indigo, ocean, forest, ember, rose and slate. Add your own in the skins block of tokens.json.

Skins recolour the whole interface

Accents derive from --bs-primary-rgb, so navigation, avatars, badges, selection states and charts all follow the skin — not only buttons.

Charts

Vantage includes a small SVG chart renderer with no dependencies — no Chart.js, no ApexCharts, nothing to license or keep updated. Pass PHP arrays; the component encodes them for you.

<x-chart
  type="area"
  :height="280"
  :series="[18400, 21200, 19800, 24600]"
  :labels="['Jan', 'Feb', 'Mar', 'Apr']"
  alt="Revenue by month, rising from 18,400 to 24,600" />
Chart component props
PropPurpose
typearea, bars or donut.
seriesArray of numbers, or of ['label' => …, 'value' => …] for donuts.
labelsAxis labels. Not used by donuts.
heightHeight in pixels. Optional.
altDescribes the chart for screen readers. Always write one.

Charts measure their container and redraw on resize and on theme change, so they stay proportional in narrow columns instead of being squashed by a fixed viewBox. If you prefer a full charting library, keep the div and point your own code at it.

Icons

The icon set is original, drawn on a 24×24 grid, and inlined as an SVG sprite from resources/views/partials/icons.blade.php. There is no icon font and no external request.

<x-icon name="i-search" />
<x-icon name="i-bell" label="Notifications" />

Icons inherit currentColor and their size from the .icon class, so they match the text beside them automatically. An icon with no label is decorative and hidden from assistive technology; if an icon is the only content of a control, label the control instead.

The UI Kit lists every icon and copies its tag when you choose one.

Accessibility

What is built in, so you do not undo it by accident:

  • Every page opens with a skip link to the main region.
  • Focus is never removed — :focus-visible draws a visible ring for keyboard users.
  • Status is never carried by colour alone; badges have dots, trends have arrows and words.
  • Tables use real <th scope> headers and a visually hidden <caption>.
  • Icon-only buttons carry an aria-label.
  • Charts expose role="img" with a written description.
  • Filters are links with real URLs, so they work without JavaScript and survive the back button.
  • prefers-reduced-motion disables every animation in the template.
  • Body text meets WCAG AA contrast in both light and dark modes.

When you add content

Keep the aria-label on icon-only buttons and write an alt for every chart. Those are the two that get dropped most often.

Support

Support covers template bugs, build problems and questions about how something in Vantage works. It does not cover customisation of your own application code, third-party packages, or hosting.

Include your PHP and Laravel versions, the screen you are on, and a screenshot or short description of what you expected. That usually turns a two-day thread into a one-reply answer.

Social Points Media — see the item page for current support contact details.