Installation
composer require qirolab/laravel-themer
php artisan themer:install
themer:install command publishes config, migrations, and assets.Publish Config & Migrations
php artisan vendor:publish --provider="Qirolab\Themer\ThemerServiceProvider"
config/themer.php for theme settings (default theme, storage paths, etc.).php artisan migrate
Basic Theme Switching
use Qirolab\Themer\Facades\Themer;
Themer::setTheme('dark'); // Switch to 'dark' theme
// In App\Http\Kernel.php
'web' => [
\Qirolab\Themer\Http\Middleware\ThemeMiddleware::class,
],
Configure middleware in config/themer.php:
'middleware' => [
'web' => 'dark', // Default theme for web
],
First Use Case: Dynamic Theme Selection
<select id="theme-selector">
@foreach(Themer::getAvailableThemes() as $theme)
<option value="{{ $theme }}" {{ Themer::getCurrentTheme() === $theme ? 'selected' : '' }}>
{{ ucfirst($theme) }}
</option>
@endforeach
</select>
document.getElementById('theme-selector').addEventListener('change', (e) => {
fetch('/themer/set-theme', {
method: 'POST',
headers: { 'X-CSRF-TOKEN': '{{ csrf_token() }}' },
body: JSON.stringify({ theme: e.target.value })
});
});
User-Specific Themes
Store themes per user in the database (default table: themer_themes):
// Set theme for current user
Themer::setTheme('light', auth()->id());
// Get user's theme
$userTheme = Themer::getTheme(auth()->id());
Cookie-Based Themes (Session-Wide) Useful for anonymous users:
Themer::setTheme('system', null, 'cookie'); // 'system' theme via cookie
URL-Based Themes (Query Parameter)
Enable in config/themer.php:
'url' => [
'enabled' => true,
'param' => 'theme',
],
Access via /dashboard?theme=dark.
Asset Organization
Structure themes in resources/themes/:
resources/
themes/
dark/
css/
app.css
js/
app.js
light/
css/
app.css
<link href="{{ Themer::asset('css/app.css') }}" rel="stylesheet">
Vite/Laravel Mix Integration
Configure vite.config.js to handle theme-specific assets:
import { defineConfig } from 'vite';
import laravel from 'laravel-vite-plugin';
import { Themer } from 'qirolab/laravel-themer';
export default defineConfig({
plugins: [
laravel({
input: Object.fromEntries(
Themer.themes().map(theme => [`./resources/themes/${theme}/js/app.js`, `public/themes/${theme}/js/app.js`])
),
}),
],
});
Middleware-Based Routing Override themes per route:
Route::middleware(['theme:admin'])->group(function () {
// Admin dashboard with 'admin' theme
});
Register in config/themer.php:
'middleware' => [
'admin' => 'admin',
],
Event-Based Theme Changes Listen for theme changes:
use Qirolab\Themer\Events\ThemeChanged;
ThemeChanged::listen(function (ThemeChanged $event) {
\Log::info("Theme switched to {$event->theme} for user {$event->userId}");
});
Fallback Chain
Define fallbacks in config/themer.php:
'fallbacks' => [
'dark' => ['dark', 'system'],
'light' => ['light', 'system'],
],
dark theme fails, it falls back to system (OS preference).System Theme Detection
Use system theme to respect OS preferences:
Themer::setTheme('system');
Requires JavaScript detection (e.g., prefers-color-scheme).
ThemerTheme model to support tenants:
use Qirolab\Themer\Models\ThemerTheme;
$tenantTheme = ThemerTheme::where('tenant_id', $tenant->id)->first();
Themer::setTheme($tenantTheme->name);
Asset Path Caching
/css/app.css) break when switching themes.Themer::asset():
<link href="{{ Themer::asset('css/app.css') }}" rel="stylesheet">
Middleware Order Matters
ShareButtons).ThemeMiddleware early in $middlewareGroups['web'].Database Locking
DB::transaction(function () {
Themer::setTheme('dark', $user->id);
});
Theme Asset Compilation
// vite.config.js
input: {
'dark': './resources/themes/dark/js/app.js',
'light': './resources/themes/light/js/app.js',
}
CORS with Dynamic Themes
X-Theme header:
public function handle($request, Closure $next) {
return $next($request)->header('X-Theme', Themer::getCurrentTheme());
}
Log Theme Changes
Enable debug mode in config/themer.php:
'debug' => env('THEMER_DEBUG', false),
Logs theme switches to storage/logs/laravel.log.
Check Active Theme Add a debug Blade component:
@component('themer::debug')
@endcomponent
Displays current theme, fallbacks, and assets.
Verify Asset Paths Use Artisan command to list available assets:
php artisan themer:list-assets
Clear Cached Themes If themes aren’t updating:
php artisan cache:clear
php artisan view:clear
Custom Theme Providers Extend theme resolution logic by creating a custom provider:
use Qirolab\Themer\Contracts\ThemeProvider;
class CustomThemeProvider implements ThemeProvider {
public function getTheme(): string {
return request()->input('custom_theme') ?: 'default';
}
}
Register in config/themer.php:
'providers' => [
\App\Providers\CustomThemeProvider::class,
],
Theme Events Extend core events for custom logic:
// Listen for theme resolution
Themer::resolving(function ($theme) {
if (auth()->check() && auth()->user()->isAdmin()) {
return 'admin';
}
return $theme;
});
Dynamic Theme Assets Override asset resolution:
Themer::extend(function ($themer) {
$the
How can I help you explore Laravel packages today?