websemantics/stone-theme
Stone Theme is a clean, responsive theme package for Laravel applications, offering ready-made Blade layouts, view scaffolding, and publishable assets to quickly style your project with minimal setup.
Install and wire up the package
composer require <vendor>/<package>
php artisan vendor:publish --provider="<Vendor>\<Package>\<PackageServiceProvider>"
Publish the config and any theme scaffolding (base variables.less, default theme folder, asset stubs). If the package predates Laravel package auto-discovery, add the service provider to config/app.php.
Where to look first
config/<package>.php — theme paths, default theme name, asset publishing targets, compiler settings.resources/themes/{theme}/) — variables.less is the single most important file. Everything visual in the theme is driven from there.lcss2php v1.1, so the LESS → PHP variable conversion is the entry point for using theme variables in Blade/PHP.First use case: expose theme variables to your views
// resources/themes/default/variables.less
@brand-primary: #2563eb;
@brand-radius: 6px;
@font-stack: "Inter", system-ui, sans-serif;
Run the package's compile/publish command (or the lcss2php conversion step directly) so those LESS variables become a PHP array, then consume them:
<style>
:root {
--brand-primary: {{ theme_var('brand-primary') }};
--brand-radius: {{ theme_var('brand-radius') }};
}
</style>
This is the day-to-day loop: edit variables.less → recompile → variables are available to Blade, CSS custom properties, or inline styles without hand-syncing a PHP config array.
Single source of truth for design tokens
Treat variables.less as the canonical token store. Do not duplicate colors/spacing into config/<package>.php or hard-code them in Blade. Everything (compiled CSS and PHP consumers) should read from the same file, which is exactly what the 1.0.5 variable cleanup plus lcss2php v1.1 support is meant to enable.
Theme override / inheritance chain Keep the package's base theme untouched and layer a child theme:
resources/themes/base/variables.less # package defaults
resources/themes/acme/variables.less # @import base + overrides
Then switch the active theme via config or at runtime:
config(['<package>.theme' => 'acme']);
For per-request/per-tenant theming, set this in a middleware after resolving the tenant, before views render.
Runtime theme switching (multi-tenant / white-label)
class SetTheme
{
public function handle($request, Closure $next)
{
$theme = $request->user()?->tenant?->theme ?? config('<package>.default_theme');
config(['<package>.theme' => $theme]);
return $next($request);
}
}
Because LESS compilation is expensive, pair this with a compiled variable cache keyed by theme name rather than compiling on every request.
Cache compiled variables, not raw LESS
$vars = Cache::rememberForever("theme.vars.{$theme}", function () use ($theme) {
return $this->lessCompiler->toArray("resources/themes/{$theme}/variables.less");
});
Bust the key from a deploy hook or a file-mtime check. This is the pattern that makes the package viable in production without a build step.
Blade helper / facade usage Wrap variable access in one helper so the underlying storage can change without touching views:
function theme_var(string $key, $default = null) {
return app(ThemeVariables::class)->get($key, $default);
}
Then use it for CSS custom properties, meta theme-color, email templates, and PDF rendering — anywhere you can't rely on a compiled stylesheet.
Asset pipeline coexistence If you already use Vite/Mix, keep compiled CSS in the asset pipeline and use the package only for the variable/token layer. Duplicating LESS compilation between Vite and the package leads to two sources of truth and divergent output.
variables.less syntax vs. PHP keys. LESS variable names drop the @ when converted (@brand-primary → brand-primary). Hyphens in keys mean you cannot use dot access on the resulting array in every context — use array access or your helper's get() with a string key.@a: @b; @b: red; resolves to red regardless of order. If lcss2php resolves variables at conversion time, an override placed after the reference still wins in LESS but may not in a naive PHP parser. Verify overrides by inspecting the compiled output, not just the file.php artisan cache:clear && php artisan view:clear
lcss2php v1.1 compatibility is the headline fix here. If you pinned an older lcss2php, upgrade alongside this release. Mismatched versions are the likely cause of half-populated variable arrays or silently skipped declarations after 1.0.5.darken(@brand-primary, 10%)), ~"..." escaping, and calc() expressions are not plain scalars — don't expect them to come back as usable PHP values. Compute derived colors in PHP or emit them as CSS custom properties instead.public/. Mixing the two is the second most common misconfiguration after caching. Keep theme.path and theme.assets_url explicitly separate in config.vendor:publish --force.1.0.x release that touches variables.less can shift default tokens. Snapshot-test your compiled variable array so a patch release that renames or reorders variables fails loudly instead of silently restyling the app.How can I help you explore Laravel packages today?