Install, upgrade, and configure the takielias/tablar starter kit — composer require, tablar:install, layout selection, post-install patches (SoftDeletes on User, base Controller class for L12+), and recovery from common install failures.
php artisan boost:add-skill takielias/tablar
Save this content to: .claude/skills/tablar-installation-development/SKILL.md
# Tablar — Installation
## When to use this skill
- User runs `composer require takielias/tablar` and asks how to finish setup.
- User wants to switch layout (`horizontal`, `condensed`, `combined`, etc.).
- User upgrades tablar across major versions.
- User reports broken styling, missing routes, or `Route [profile] not defined` after install.
## Install flow
```bash
composer require takielias/tablar
php artisan tablar:install
npm install && npm run dev # or: npm run build
php artisan tablar:export-auth # publishes Breeze-style auth controllers + views
```
`tablar:install` flags:
- `--force` — overwrite user-modified files without prompting. Without it, install will diff each destination against the stub and prompt per file.
- `--no-credits` — suppress the "Star us on GitHub" credits line.
After install completes, the command prints:
```
✅ Tablar installed (Laravel {N}).
Next: npm install && npm run dev
Then: php artisan tablar:export-auth
```
## What `tablar:install` does
1. Runs `TablarPreset::install()`:
- Updates `package.json` dependencies (Tabler core, Vite, sass-embedded, tabler-icons). Does not install jQuery — nothing in Tablar uses it. A first install also drops the skeleton's `tailwindcss` and `@tailwindcss/vite`.
- Updates `vite.config.js` and `resources/sass/tabler.scss`.
- Updates `resources/js/app.js` bootstrapping.
- Updates `resources/views/welcome.blade.php`.
- Removes `node_modules/` (forces a clean `npm install`).
2. Runs `TablarPreset::exportConfig()` — publishes `config/tablar.php`.
3. Calls `checkController()` — Laravel 12+ only: rewrites `app/Http/Controllers/Controller.php` to extend `\Illuminate\Routing\Controller`. Idempotent.
4. Calls `patchUserModelForSoftDeletes()` — adds `Illuminate\Database\Eloquent\SoftDeletes` import + trait to `App\Models\User`. Idempotent. Both single-line `use HasFactory, Notifiable;` and multi-line `use HasFactory;\nuse Notifiable;` patterns handled.
`safeCopy()` applies to every published stub:
- destination missing → write silently
- destination matches the stub hash → skip silently
- **first install** (no `config/tablar.php` yet) → write silently; there are no user edits to protect
- otherwise → prompt, or honor `--force`
Anything skipped is listed at the end of the install, so a skip cannot pass as success. Before this, Laravel's own `vite.config.js` was treated as user-modified on a fresh app, so Tablar's config never landed and the build ran Tabler's Sass through Laravel's Tailwind config.
## Companion artisan commands
| Command | Purpose |
|---|---|
| `tablar:install` | Full install (config, packages, view bootstrap, controller patch, soft-deletes patch). |
| `tablar:export-auth` | Publish auth controllers, views, FormRequests (Profile/Settings/Login/Register/etc.). Run after `tablar:install`. |
| `tablar:export-config` | Re-publish `config/tablar.php` only. |
| `tablar:export-views` | Re-publish all view stubs. |
| `tablar:export-assets` | Re-publish SCSS/JS assets. |
| `tablar:export-js` | JS-only re-publish. |
| `tablar:export-all` | Re-publish everything (views + assets + JS + auth). |
| `tablar:update` | Refresh package deps + assets without re-running scaffolding. |
| `tablar:doctor` | One-shot environment snapshot for debugging install issues. |
## Layout selection
`config('tablar.layout')` — default `'horizontal'`.
Other supported values resolve view partials at `resources/views/layouts/{layout}.blade.php` (verify by reading `resources/views/page.blade.php` line 16 — `@includeIf('tablar::layouts.'. config('tablar.layout'))`).
Auxiliary keys interact with layout choice:
- `'layout_light_topbar'` (true / false / null) — `data-bs-theme` on the top bar.
- `'layout_light_sidebar'` (true / false / null) — `data-bs-theme` on the sidebar.
- `'layout_enable_top_header'` (bool) — render top header row in sidebar layouts.
For RTL: set `'layout' => 'rtl'` — `master.blade.php` adds `dir="rtl"` to `<html>` automatically.
## Post-install patches
### User model — SoftDeletes
After install:
```php
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Authenticatable
{
use HasFactory, Notifiable, SoftDeletes;
}
```
Migration to add `deleted_at` is shipped at `database/migrations/2014_10_12_100000_add_soft_deletes_to_users_table.php` via `tablar:export-auth`.
### Base Controller class (L12+)
Laravel 12+ ships streamlined `app/Http/Controllers/Controller.php` as `abstract class Controller {}` (no parent). Tablar patches it to:
```php
abstract class Controller extends \Illuminate\Routing\Controller
{
}
```
Without this patch, controller traits + middleware helpers break.
### Profile + Settings controllers
`tablar:export-auth` publishes:
- `app/Http/Controllers/ProfileController.php` — name-only profile form (email read-only).
- `app/Http/Controllers/SettingsController.php` — appearance + password + delete-account.
- `app/Http/Requests/{UpdateProfileRequest,UpdatePasswordRequest,DeleteAccountRequest}.php` — FormRequests with named error bags (`updatePassword`, `deleteAccount`) so validation errors surface inside Tabler tabs.
Routes published to `routes/auth.php` under `auth` middleware:
```
GET /profile → ProfileController@show (profile)
PATCH /profile → ProfileController@update (profile.update)
GET /settings → SettingsController@show (settings)
PUT /settings/password→ SettingsController@updatePassword (settings.password)
DELETE /settings → SettingsController@destroy (settings.destroy)
```
## Recipes
### 1. Fresh install (Laravel 12, no auth scaffolding yet)
```bash
laravel new myapp && cd myapp
composer require takielias/tablar
php artisan tablar:install
npm install && npm run dev
php artisan tablar:export-auth
php artisan migrate
```
Visit `/login`, `/profile`, `/settings`.
### 2. Adding tablar to an existing Breeze app
```bash
composer require takielias/tablar
php artisan tablar:install --force=false # prompts per file
```
When `tablar:install` prompts about `Controller.php` or `User.php`:
- `Controller.php` — accept overwrite. The patch only adds `extends \Illuminate\Routing\Controller`; keeps the rest.
- `User.php` — accept. Patch is regex-based and adds SoftDeletes alongside Breeze's existing traits.
Skip `tablar:export-auth` — Breeze's auth scaffolding already exists. Profile/Settings stubs from Breeze remain in place.
### 3. Switching layout post-install
Edit `config/tablar.php`:
```php
'layout' => 'condensed-top', // or other variant — see published config comments
'layout_light_topbar' => null,
'layout_light_sidebar' => true,
```
No file republish needed — value is read at render time.
### 4. Re-running install after upstream package update
```bash
composer update takielias/tablar
php artisan tablar:update
npm install && npm run dev
```
`tablar:update` refreshes deps + assets without re-running scaffolding (won't touch `Controller.php`, `User.php`, or auth views).
## Common pitfalls
- **`Route [profile] not defined`** — `tablar:export-auth` not run after `tablar:install`. Either run it OR set `'profile_url' => false` in `config/tablar.php` to hide the dropdown link.
- **Unstyled layout** — `npm run dev` (or `build`) not run. Vite manifest missing. The published `tabler.scss` and `tabler-init.js` need to be compiled.
- **`tabler-icons` font not loading** — `npm install` skipped or `node_modules/` not removed. `tablar:install` removes `node_modules/` to force a clean install; if you skipped that step, run `rm -rf node_modules && npm install`.
- **Theme toggle resets on navigation** — Tabler core's `tabler-theme.js` strips `data-bs-theme` on default `light`. Master layout's inline `<head>` script syncs `tablar.theme` → `tabler-theme` on every load to compensate. Don't write `tabler-theme` directly.
- **Controller patch reverts on every `composer install`** — published `Controller.php` lives in your app. If you re-publish via `--force`, it re-patches. Should not happen in CI as long as `app/` is committed.
- **Multiple `use SoftDeletes` insertions on rerun** — patcher is idempotent; checks `\bSoftDeletes\b` before inserting. Safe.
## Configuration reference (top keys)
```php
'use_route_url' => true, // resolve menu route keys via route() vs raw URL
'profile_url' => 'profile', // route name OR path; false to hide dropdown link
'setting_url' => 'settings',
'enable_notifications' => true, // bell-icon dropdown visibility
'header_buttons' => [...], // empty array hides chrome
'footer_buttons' => [...],
'layout' => 'horizontal',
'menu' => [...],
```
## Related
- Skill `tablar-menu-development` — menu schema and authoring.
- Slash command `/laravel-boost:install-tablar-kit` — wire tablar-kit on top of tablar.
- Source: `src/Console/TablarInstallCommand.php`, `src/TablarPreset.php`, `src/stubs/`.
composer require takielias/tablar and asks how to finish setup.horizontal, condensed, combined, etc.).Route [profile] not defined after install.composer require takielias/tablar
php artisan tablar:install
npm install && npm run dev # or: npm run build
php artisan tablar:export-auth # publishes Breeze-style auth controllers + views
tablar:install flags:
--force — overwrite user-modified files without prompting. Without it, install will diff each destination against the stub and prompt per file.--no-credits — suppress the "Star us on GitHub" credits line.After install completes, the command prints:
✅ Tablar installed (Laravel {N}).
Next: npm install && npm run dev
Then: php artisan tablar:export-auth
tablar:install doesTablarPreset::install():
package.json dependencies (Tabler core, Vite, sass-embedded, tabler-icons). Does not install jQuery — nothing in Tablar uses it. A first install also drops the skeleton's tailwindcss and @tailwindcss/vite.vite.config.js and resources/sass/tabler.scss.resources/js/app.js bootstrapping.resources/views/welcome.blade.php.node_modules/ (forces a clean npm install).TablarPreset::exportConfig() — publishes config/tablar.php.checkController() — Laravel 12+ only: rewrites app/Http/Controllers/Controller.php to extend \Illuminate\Routing\Controller. Idempotent.patchUserModelForSoftDeletes() — adds Illuminate\Database\Eloquent\SoftDeletes import + trait to App\Models\User. Idempotent. Both single-line use HasFactory, Notifiable; and multi-line use HasFactory;\nuse Notifiable; patterns handled.safeCopy() applies to every published stub:
config/tablar.php yet) → write silently; there are no user edits to protect--forceAnything skipped is listed at the end of the install, so a skip cannot pass as success. Before this, Laravel's own vite.config.js was treated as user-modified on a fresh app, so Tablar's config never landed and the build ran Tabler's Sass through Laravel's Tailwind config.
| Command | Purpose |
|---|---|
tablar:install |
Full install (config, packages, view bootstrap, controller patch, soft-deletes patch). |
tablar:export-auth |
Publish auth controllers, views, FormRequests (Profile/Settings/Login/Register/etc.). Run after tablar:install. |
tablar:export-config |
Re-publish config/tablar.php only. |
tablar:export-views |
Re-publish all view stubs. |
tablar:export-assets |
Re-publish SCSS/JS assets. |
tablar:export-js |
JS-only re-publish. |
tablar:export-all |
Re-publish everything (views + assets + JS + auth). |
tablar:update |
Refresh package deps + assets without re-running scaffolding. |
tablar:doctor |
One-shot environment snapshot for debugging install issues. |
config('tablar.layout') — default 'horizontal'.
Other supported values resolve view partials at resources/views/layouts/{layout}.blade.php (verify by reading resources/views/page.blade.php line 16 — @includeIf('tablar::layouts.'. config('tablar.layout'))).
Auxiliary keys interact with layout choice:
'layout_light_topbar' (true / false / null) — data-bs-theme on the top bar.'layout_light_sidebar' (true / false / null) — data-bs-theme on the sidebar.'layout_enable_top_header' (bool) — render top header row in sidebar layouts.For RTL: set 'layout' => 'rtl' — master.blade.php adds dir="rtl" to <html> automatically.
After install:
use Illuminate\Database\Eloquent\SoftDeletes;
class User extends Authenticatable
{
use HasFactory, Notifiable, SoftDeletes;
}
Migration to add deleted_at is shipped at database/migrations/2014_10_12_100000_add_soft_deletes_to_users_table.php via tablar:export-auth.
Laravel 12+ ships streamlined app/Http/Controllers/Controller.php as abstract class Controller {} (no parent). Tablar patches it to:
abstract class Controller extends \Illuminate\Routing\Controller
{
}
Without this patch, controller traits + middleware helpers break.
tablar:export-auth publishes:
app/Http/Controllers/ProfileController.php — name-only profile form (email read-only).app/Http/Controllers/SettingsController.php — appearance + password + delete-account.app/Http/Requests/{UpdateProfileRequest,UpdatePasswordRequest,DeleteAccountRequest}.php — FormRequests with named error bags (updatePassword, deleteAccount) so validation errors surface inside Tabler tabs.Routes published to routes/auth.php under auth middleware:
GET /profile → ProfileController@show (profile)
PATCH /profile → ProfileController@update (profile.update)
GET /settings → SettingsController@show (settings)
PUT /settings/password→ SettingsController@updatePassword (settings.password)
DELETE /settings → SettingsController@destroy (settings.destroy)
laravel new myapp && cd myapp
composer require takielias/tablar
php artisan tablar:install
npm install && npm run dev
php artisan tablar:export-auth
php artisan migrate
Visit /login, /profile, /settings.
composer require takielias/tablar
php artisan tablar:install --force=false # prompts per file
When tablar:install prompts about Controller.php or User.php:
Controller.php — accept overwrite. The patch only adds extends \Illuminate\Routing\Controller; keeps the rest.User.php — accept. Patch is regex-based and adds SoftDeletes alongside Breeze's existing traits.Skip tablar:export-auth — Breeze's auth scaffolding already exists. Profile/Settings stubs from Breeze remain in place.
Edit config/tablar.php:
'layout' => 'condensed-top', // or other variant — see published config comments
'layout_light_topbar' => null,
'layout_light_sidebar' => true,
No file republish needed — value is read at render time.
composer update takielias/tablar
php artisan tablar:update
npm install && npm run dev
tablar:update refreshes deps + assets without re-running scaffolding (won't touch Controller.php, User.php, or auth views).
Route [profile] not defined — tablar:export-auth not run after tablar:install. Either run it OR set 'profile_url' => false in config/tablar.php to hide the dropdown link.npm run dev (or build) not run. Vite manifest missing. The published tabler.scss and tabler-init.js need to be compiled.tabler-icons font not loading — npm install skipped or node_modules/ not removed. tablar:install removes node_modules/ to force a clean install; if you skipped that step, run rm -rf node_modules && npm install.tabler-theme.js strips data-bs-theme on default light. Master layout's inline <head> script syncs tablar.theme → tabler-theme on every load to compensate. Don't write tabler-theme directly.composer install — published Controller.php lives in your app. If you re-publish via --force, it re-patches. Should not happen in CI as long as app/ is committed.use SoftDeletes insertions on rerun — patcher is idempotent; checks \bSoftDeletes\b before inserting. Safe.'use_route_url' => true, // resolve menu route keys via route() vs raw URL
'profile_url' => 'profile', // route name OR path; false to hide dropdown link
'setting_url' => 'settings',
'enable_notifications' => true, // bell-icon dropdown visibility
'header_buttons' => [...], // empty array hides chrome
'footer_buttons' => [...],
'layout' => 'horizontal',
'menu' => [...],
tablar-menu-development — menu schema and authoring./laravel-boost:install-tablar-kit — wire tablar-kit on top of tablar.src/Console/TablarInstallCommand.php, src/TablarPreset.php, src/stubs/.How can I help you explore Laravel packages today?