Implemented the dynamic theme manager and merged the supplied themes.
Included
* Standardised all six theme.json files to manifest version 2:
* admin
* common
* corporate
* saasland
* swiss
* welcome
* Every manifest now uses the same fields and structure.
* Separate active frontend and backend themes.
* One-click theme activation.
* Theme preview in a new browser tab without activating it.
* Theme cards showing:
* Preview
* Name
* Version
* Author
* Description
* Theme type
* Active status
* Dynamic theme-specific settings.
* Support for:
* Text
* URL
* Colour
* Textarea
* Checkbox fields
* Variants
* Appearance
* Accent palettes
* Theme ZIP installation.
* Theme ZIP export.
* Asset optimisation.
* Accessibility validation.
* Safe ZIP path validation.
* Theme inheritance.
* Active themes cannot be uninstalled.
* Parent themes cannot be uninstalled while child themes depend on them.
* Stylist administration routes now require an authenticated, verified user.
* Manifest validation now restricts theme types to:
* frontend
* backend
* common
* Added activation tests for independent frontend and backend theme selection.
The supplied corporate theme was incomplete, so I added the required backend entry view and placeholder asset files while preserving its supplied layout.
This commit is contained in:
@@ -7,14 +7,17 @@ use Modules\Stylist\Services\ThemeAccessibilityValidator;
|
|||||||
use Modules\Stylist\Services\ThemeSettings;
|
use Modules\Stylist\Services\ThemeSettings;
|
||||||
use Modules\Stylist\Theme\Stylist;
|
use Modules\Stylist\Theme\Stylist;
|
||||||
use Modules\Stylist\Theme\UrlGenerator;
|
use Modules\Stylist\Theme\UrlGenerator;
|
||||||
|
use Modules\Settings\Services\SettingsRepository;
|
||||||
|
|
||||||
final class StylistController extends Controller
|
final class StylistController extends Controller
|
||||||
{
|
{
|
||||||
public function __invoke(Stylist $stylist, ThemeSettings $settings, ThemeAccessibilityValidator $accessibility, UrlGenerator $urls)
|
public function __invoke(Stylist $stylist, ThemeSettings $settings, ThemeAccessibilityValidator $accessibility, UrlGenerator $urls, SettingsRepository $siteSettings)
|
||||||
{
|
{
|
||||||
return view('stylist::index', [
|
return view('stylist::index', [
|
||||||
'theme' => $stylist->current(), 'themes' => $stylist->all(), 'variables' => $stylist->variables(),
|
'theme' => $stylist->current(), 'themes' => $stylist->all(), 'variables' => $stylist->variables(),
|
||||||
'settingsService' => $settings, 'accessibility' => $accessibility, 'urls' => $urls,
|
'settingsService' => $settings, 'accessibility' => $accessibility, 'urls' => $urls,
|
||||||
|
'activeFrontendTheme' => $siteSettings->get('frontend_theme', config('stylist.default_frontend_theme', 'saasland'), 'site'),
|
||||||
|
'activeBackendTheme' => $siteSettings->get('backend_theme', config('stylist.default_backend_theme', 'admin'), 'site'),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,14 +4,36 @@ namespace Modules\Stylist\Http\Controllers;
|
|||||||
|
|
||||||
use Illuminate\Http\Request;
|
use Illuminate\Http\Request;
|
||||||
use Illuminate\Routing\Controller;
|
use Illuminate\Routing\Controller;
|
||||||
|
use Modules\Settings\Services\SettingsRepository;
|
||||||
use Modules\Stylist\Services\ThemeAccessibilityValidator;
|
use Modules\Stylist\Services\ThemeAccessibilityValidator;
|
||||||
use Modules\Stylist\Services\ThemeOptimizer;
|
use Modules\Stylist\Services\ThemeOptimizer;
|
||||||
use Modules\Stylist\Services\ThemePackageManager;
|
use Modules\Stylist\Services\ThemePackageManager;
|
||||||
use Modules\Stylist\Services\ThemeSettings;
|
use Modules\Stylist\Services\ThemeSettings;
|
||||||
use Modules\Stylist\Theme\Loader;
|
use Modules\Stylist\Theme\Loader;
|
||||||
|
use Modules\Stylist\View\ThemeViewResolver;
|
||||||
|
|
||||||
final class ThemeManagementController extends Controller
|
final class ThemeManagementController extends Controller
|
||||||
{
|
{
|
||||||
|
public function activate(string $theme, Loader $loader, SettingsRepository $settings)
|
||||||
|
{
|
||||||
|
$item = $loader->find($theme);
|
||||||
|
abort_unless(in_array($item->type(), ['frontend', 'backend'], true), 422, 'Only frontend and backend themes can be activated.');
|
||||||
|
|
||||||
|
$settings->put($item->type().'_theme', $item->key(), 'site', 'string', true);
|
||||||
|
|
||||||
|
return back()->with('status', $item->name().' is now the active '.$item->type().' theme.');
|
||||||
|
}
|
||||||
|
|
||||||
|
public function preview(string $theme, Loader $loader, ThemeViewResolver $views)
|
||||||
|
{
|
||||||
|
$item = $loader->find($theme);
|
||||||
|
|
||||||
|
return $views->makeForTheme($item->key(), $item->entryView(), [
|
||||||
|
'themePreview' => true,
|
||||||
|
'previewTheme' => $item,
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
public function settings(Request $request, string $theme, Loader $loader, ThemeSettings $settings)
|
public function settings(Request $request, string $theme, Loader $loader, ThemeSettings $settings)
|
||||||
{
|
{
|
||||||
$item = $loader->find($theme);
|
$item = $loader->find($theme);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
@php($issues = $accessibility->validate($item))
|
@php($issues = $accessibility->validate($item))
|
||||||
@php($appearance = $settingsService->appearance($item))
|
@php($appearance = $settingsService->appearance($item))
|
||||||
@php($accent = $settingsService->accent($item))
|
@php($accent = $settingsService->accent($item))
|
||||||
<article class="overflow-hidden rounded-2xl border {{ $item->key() === $theme->key() ? 'border-blue-400 ring-2 ring-blue-100' : 'border-slate-200' }} bg-white shadow-sm">
|
<article class="overflow-hidden rounded-2xl border {{ (($item->type() === 'frontend' && $item->key() === $activeFrontendTheme) || ($item->type() === 'backend' && $item->key() === $activeBackendTheme)) ? 'border-blue-400 ring-2 ring-blue-100' : 'border-slate-200' }} bg-white shadow-sm">
|
||||||
<div class="aspect-[16/7] bg-slate-100">
|
<div class="aspect-[16/7] bg-slate-100">
|
||||||
@if ($item->preview() && $item->has($item->preview()))
|
@if ($item->preview() && $item->has($item->preview()))
|
||||||
<img src="{{ $urls->forTheme($item, $item->preview()) }}" alt="{{ $item->name() }} theme preview" class="h-full w-full object-cover">
|
<img src="{{ $urls->forTheme($item, $item->preview()) }}" alt="{{ $item->name() }} theme preview" class="h-full w-full object-cover">
|
||||||
@@ -30,10 +30,14 @@
|
|||||||
@endif
|
@endif
|
||||||
</div>
|
</div>
|
||||||
<div class="p-5">
|
<div class="p-5">
|
||||||
<div class="flex items-start justify-between gap-4"><div><h2 class="text-xl font-bold text-slate-950">{{ $item->name() }}</h2><p class="text-sm text-slate-500">v{{ $item->version() }}@if($item->author()) · {{ $item->author() }}@endif</p></div>@if($item->key() === $theme->key())<span class="rounded-full bg-blue-100 px-3 py-1 text-xs font-semibold text-blue-700">Active</span>@endif</div>
|
<div class="flex items-start justify-between gap-4"><div><h2 class="text-xl font-bold text-slate-950">{{ $item->name() }}</h2><p class="text-sm text-slate-500">v{{ $item->version() }}@if($item->author()) · {{ $item->author() }}@endif</p></div>@if(($item->type() === 'frontend' && $item->key() === $activeFrontendTheme) || ($item->type() === 'backend' && $item->key() === $activeBackendTheme))<span class="rounded-full bg-blue-100 px-3 py-1 text-xs font-semibold text-blue-700">Active {{ ucfirst($item->type()) }}</span>@endif</div>
|
||||||
@if($item->description())<p class="mt-3 text-sm text-slate-600">{{ $item->description() }}</p>@endif
|
@if($item->description())<p class="mt-3 text-sm text-slate-600">{{ $item->description() }}</p>@endif
|
||||||
@if($item->parent())<p class="mt-2 text-xs font-medium text-violet-700">Child of {{ $item->parent() }}</p>@endif
|
@if($item->parent())<p class="mt-2 text-xs font-medium text-violet-700">Child of {{ $item->parent() }}</p>@endif
|
||||||
<div class="mt-4 flex flex-wrap gap-2">
|
<div class="mt-4 flex flex-wrap gap-2">
|
||||||
|
@if(in_array($item->type(), ['frontend', 'backend'], true))
|
||||||
|
<form method="POST" action="{{ route('stylist.activate', $item->key()) }}">@csrf<button class="rounded-lg bg-blue-600 px-3 py-2 text-sm font-semibold text-white">Activate {{ ucfirst($item->type()) }}</button></form>
|
||||||
|
<a href="{{ route('stylist.preview', $item->key()) }}" target="_blank" rel="noopener" class="rounded-lg border border-blue-300 px-3 py-2 text-sm font-medium text-blue-700">Preview</a>
|
||||||
|
@endif
|
||||||
<a href="{{ route('stylist.export', $item->key()) }}" class="rounded-lg border border-slate-300 px-3 py-2 text-sm font-medium">Export ZIP</a>
|
<a href="{{ route('stylist.export', $item->key()) }}" class="rounded-lg border border-slate-300 px-3 py-2 text-sm font-medium">Export ZIP</a>
|
||||||
<form method="POST" action="{{ route('stylist.optimize', $item->key()) }}">@csrf<button class="rounded-lg border border-slate-300 px-3 py-2 text-sm font-medium">Optimise assets</button></form>
|
<form method="POST" action="{{ route('stylist.optimize', $item->key()) }}">@csrf<button class="rounded-lg border border-slate-300 px-3 py-2 text-sm font-medium">Optimise assets</button></form>
|
||||||
@if(str_starts_with(realpath($item->path()) ?: '', realpath(config('stylist.themes_path')) ?: '/__never__'))
|
@if(str_starts_with(realpath($item->path()) ?: '', realpath(config('stylist.themes_path')) ?: '/__never__'))
|
||||||
@@ -55,8 +59,12 @@
|
|||||||
@foreach($item->settingsSchema() as $key => $definition)
|
@foreach($item->settingsSchema() as $key => $definition)
|
||||||
@php($definition = is_array($definition) ? $definition : ['default' => $definition])
|
@php($definition = is_array($definition) ? $definition : ['default' => $definition])
|
||||||
<label class="block"><span class="mb-1 block text-sm font-medium">{{ $definition['label'] ?? str($key)->headline() }}</span>
|
<label class="block"><span class="mb-1 block text-sm font-medium">{{ $definition['label'] ?? str($key)->headline() }}</span>
|
||||||
@if(($definition['type'] ?? 'text') === 'color')<input type="color" name="settings[{{ $key }}]" value="{{ $saved[$key] ?? '#000000' }}" class="h-10 w-full rounded-lg border-slate-300">
|
@switch($definition['type'] ?? 'text')
|
||||||
@else<input type="{{ ($definition['type'] ?? 'text') === 'url' ? 'url' : 'text' }}" name="settings[{{ $key }}]" value="{{ $saved[$key] ?? '' }}" class="w-full rounded-lg border-slate-300">@endif
|
@case('color')<input type="color" name="settings[{{ $key }}]" value="{{ $saved[$key] ?? ($definition['default'] ?? '#000000') }}" class="h-10 w-full rounded-lg border-slate-300">@break
|
||||||
|
@case('textarea')<textarea name="settings[{{ $key }}]" rows="4" class="w-full rounded-lg border-slate-300">{{ $saved[$key] ?? ($definition['default'] ?? '') }}</textarea>@break
|
||||||
|
@case('checkbox')<input type="hidden" name="settings[{{ $key }}]" value="0"><label class="inline-flex items-center gap-2"><input type="checkbox" name="settings[{{ $key }}]" value="1" @checked((bool)($saved[$key] ?? ($definition['default'] ?? false))) class="rounded border-slate-300"><span>Enabled</span></label>@break
|
||||||
|
@default<input type="{{ ($definition['type'] ?? 'text') === 'url' ? 'url' : 'text' }}" name="settings[{{ $key }}]" value="{{ $saved[$key] ?? ($definition['default'] ?? '') }}" class="w-full rounded-lg border-slate-300">
|
||||||
|
@endswitch
|
||||||
</label>
|
</label>
|
||||||
@endforeach
|
@endforeach
|
||||||
<button class="rounded-lg bg-blue-600 px-4 py-2 font-semibold text-white">Save settings</button>
|
<button class="rounded-lg bg-blue-600 px-4 py-2 font-semibold text-white">Save settings</button>
|
||||||
|
|||||||
@@ -4,10 +4,14 @@ use Illuminate\Support\Facades\Route;
|
|||||||
use Modules\Stylist\Http\Controllers\StylistController;
|
use Modules\Stylist\Http\Controllers\StylistController;
|
||||||
use Modules\Stylist\Http\Controllers\ThemeManagementController;
|
use Modules\Stylist\Http\Controllers\ThemeManagementController;
|
||||||
|
|
||||||
Route::get('/', StylistController::class)->name('index');
|
Route::middleware(['auth', 'verified'])->group(function (): void {
|
||||||
Route::post('/install', [ThemeManagementController::class, 'install'])->name('install');
|
Route::get('/', StylistController::class)->name('index');
|
||||||
Route::put('/{theme}/settings', [ThemeManagementController::class, 'settings'])->name('settings');
|
Route::post('/install', [ThemeManagementController::class, 'install'])->name('install');
|
||||||
Route::delete('/{theme}', [ThemeManagementController::class, 'uninstall'])->name('uninstall');
|
Route::put('/{theme}/settings', [ThemeManagementController::class, 'settings'])->name('settings');
|
||||||
Route::get('/{theme}/export', [ThemeManagementController::class, 'export'])->name('export');
|
Route::post('/{theme}/activate', [ThemeManagementController::class, 'activate'])->name('activate');
|
||||||
Route::post('/{theme}/optimize', [ThemeManagementController::class, 'optimize'])->name('optimize');
|
Route::get('/{theme}/preview', [ThemeManagementController::class, 'preview'])->name('preview');
|
||||||
Route::get('/{theme}/accessibility', [ThemeManagementController::class, 'validateTheme'])->name('accessibility');
|
Route::delete('/{theme}', [ThemeManagementController::class, 'uninstall'])->name('uninstall');
|
||||||
|
Route::get('/{theme}/export', [ThemeManagementController::class, 'export'])->name('export');
|
||||||
|
Route::post('/{theme}/optimize', [ThemeManagementController::class, 'optimize'])->name('optimize');
|
||||||
|
Route::get('/{theme}/accessibility', [ThemeManagementController::class, 'validateTheme'])->name('accessibility');
|
||||||
|
});
|
||||||
|
|||||||
@@ -6,12 +6,13 @@ use Illuminate\Filesystem\Filesystem;
|
|||||||
use Illuminate\Http\UploadedFile;
|
use Illuminate\Http\UploadedFile;
|
||||||
use Modules\Stylist\Theme\Loader;
|
use Modules\Stylist\Theme\Loader;
|
||||||
use Modules\Stylist\Theme\Theme;
|
use Modules\Stylist\Theme\Theme;
|
||||||
|
use Modules\Settings\Services\SettingsRepository;
|
||||||
use RuntimeException;
|
use RuntimeException;
|
||||||
use ZipArchive;
|
use ZipArchive;
|
||||||
|
|
||||||
final class ThemePackageManager
|
final class ThemePackageManager
|
||||||
{
|
{
|
||||||
public function __construct(private readonly Filesystem $files, private readonly Loader $loader, private readonly ThemeValidator $validator) {}
|
public function __construct(private readonly Filesystem $files, private readonly Loader $loader, private readonly ThemeValidator $validator, private readonly SettingsRepository $settings) {}
|
||||||
|
|
||||||
public function install(UploadedFile $upload): Theme
|
public function install(UploadedFile $upload): Theme
|
||||||
{
|
{
|
||||||
@@ -60,6 +61,12 @@ final class ThemePackageManager
|
|||||||
|
|
||||||
public function uninstall(Theme $theme): void
|
public function uninstall(Theme $theme): void
|
||||||
{
|
{
|
||||||
|
$active = $theme->type() === 'frontend'
|
||||||
|
? $this->settings->get('frontend_theme', config('stylist.default_frontend_theme'), 'site')
|
||||||
|
: $this->settings->get('backend_theme', config('stylist.default_backend_theme'), 'site');
|
||||||
|
if ($active === $theme->key()) {
|
||||||
|
throw new RuntimeException('The active theme cannot be uninstalled. Activate another theme first.');
|
||||||
|
}
|
||||||
$projectRoot = realpath((string) config('stylist.themes_path'));
|
$projectRoot = realpath((string) config('stylist.themes_path'));
|
||||||
$themePath = realpath($theme->path());
|
$themePath = realpath($theme->path());
|
||||||
if (! $projectRoot || ! $themePath || ! str_starts_with($themePath, $projectRoot.DIRECTORY_SEPARATOR)) {
|
if (! $projectRoot || ! $themePath || ! str_starts_with($themePath, $projectRoot.DIRECTORY_SEPARATOR)) {
|
||||||
|
|||||||
@@ -29,6 +29,9 @@ final class ManifestValidator
|
|||||||
if (isset($manifest['version']) && (! is_string($manifest['version']) || ! preg_match('/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/', $manifest['version']))) {
|
if (isset($manifest['version']) && (! is_string($manifest['version']) || ! preg_match('/^\d+\.\d+\.\d+(?:[-+][0-9A-Za-z.-]+)?$/', $manifest['version']))) {
|
||||||
$errors[] = 'The version must use semantic versioning, for example 1.2.0.';
|
$errors[] = 'The version must use semantic versioning, for example 1.2.0.';
|
||||||
}
|
}
|
||||||
|
if (isset($manifest['type']) && ! in_array($manifest['type'], ['frontend', 'backend', 'common'], true)) {
|
||||||
|
$errors[] = 'The type must be frontend, backend, or common.';
|
||||||
|
}
|
||||||
$parent = $manifest['extends'] ?? $manifest['parent'] ?? null;
|
$parent = $manifest['extends'] ?? $manifest['parent'] ?? null;
|
||||||
if ($parent !== null && (! is_string($parent) || ! preg_match('/^[a-z0-9][a-z0-9_-]*$/', $parent))) {
|
if ($parent !== null && (! is_string($parent) || ! preg_match('/^[a-z0-9][a-z0-9_-]*$/', $parent))) {
|
||||||
$errors[] = 'The extends/parent value must be a valid theme key.';
|
$errors[] = 'The extends/parent value must be a valid theme key.';
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
{
|
{
|
||||||
|
"manifest_version": 2,
|
||||||
"name": "Dashboard",
|
"name": "Dashboard",
|
||||||
"slug": "admin",
|
"slug": "admin",
|
||||||
"extends": "common",
|
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"author": "ABSDEV",
|
"author": "ABSDEV",
|
||||||
"description": "Backend-only Laravel Livewire and Flux dashboard theme.",
|
"description": "Backend-only Laravel Livewire and Flux dashboard theme.",
|
||||||
|
"type": "backend",
|
||||||
|
"extends": "common",
|
||||||
"entry_view": "dashboard",
|
"entry_view": "dashboard",
|
||||||
"stylesheet": "css/theme.css",
|
"stylesheet": "css/theme.css",
|
||||||
"script": "js/app.js",
|
"script": "js/app.js",
|
||||||
"type": "backend",
|
"preview": "images/preview.webp",
|
||||||
"views": true,
|
"views": true,
|
||||||
"livewire_views": true,
|
"livewire_views": true,
|
||||||
"supports": {
|
"supports": {
|
||||||
"dark_mode": true,
|
"dark_mode": true,
|
||||||
"animations": false,
|
"animations": false,
|
||||||
|
"privacy": false,
|
||||||
|
"terms": false,
|
||||||
"auth": false,
|
"auth": false,
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"variants": true,
|
"variants": true,
|
||||||
@@ -23,7 +27,6 @@
|
|||||||
"accessibility_validation": true
|
"accessibility_validation": true
|
||||||
},
|
},
|
||||||
"variables": {},
|
"variables": {},
|
||||||
"preview": "images/preview.webp",
|
|
||||||
"variants": {
|
"variants": {
|
||||||
"light": {
|
"light": {
|
||||||
"label": "Light",
|
"label": "Light",
|
||||||
@@ -38,6 +41,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"appearances": {},
|
||||||
|
"accents": {},
|
||||||
|
"default_appearance": null,
|
||||||
|
"default_accent": null,
|
||||||
"settings": {
|
"settings": {
|
||||||
"site_title": {
|
"site_title": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
@@ -54,5 +61,6 @@
|
|||||||
"label": "Primary colour",
|
"label": "Primary colour",
|
||||||
"default": "#2563eb"
|
"default": "#2563eb"
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
"seo": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,37 @@
|
|||||||
{
|
{
|
||||||
|
"manifest_version": 2,
|
||||||
"name": "Common Application Theme",
|
"name": "Common Application Theme",
|
||||||
"slug": "common",
|
"slug": "common",
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"author": "ABSDEV",
|
"author": "ABSDEV",
|
||||||
"description": "Application-wide layouts, authentication, settings and shared Blade components.",
|
"description": "Application-wide layouts, authentication, settings and shared Blade components.",
|
||||||
"entry_view": "livewire.auth.login",
|
|
||||||
"type": "common",
|
"type": "common",
|
||||||
|
"extends": null,
|
||||||
|
"entry_view": "livewire.auth.login",
|
||||||
|
"stylesheet": "css/theme.css",
|
||||||
|
"script": "js/app.js",
|
||||||
|
"preview": null,
|
||||||
"views": true,
|
"views": true,
|
||||||
"livewire_views": true,
|
"livewire_views": true,
|
||||||
"supports": {
|
"supports": {
|
||||||
"auth": true,
|
|
||||||
"settings": true,
|
|
||||||
"dark_mode": true,
|
"dark_mode": true,
|
||||||
"preview": false
|
"animations": false,
|
||||||
|
"privacy": false,
|
||||||
|
"terms": false,
|
||||||
|
"auth": true,
|
||||||
|
"preview": false,
|
||||||
|
"variants": false,
|
||||||
|
"settings": true,
|
||||||
|
"seo": false,
|
||||||
|
"export": true,
|
||||||
|
"accessibility_validation": true
|
||||||
},
|
},
|
||||||
"variables": {},
|
"variables": {},
|
||||||
"settings": {}
|
"variants": {},
|
||||||
|
"appearances": {},
|
||||||
|
"accents": {},
|
||||||
|
"default_appearance": null,
|
||||||
|
"default_accent": null,
|
||||||
|
"settings": {},
|
||||||
|
"seo": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,37 @@
|
|||||||
{
|
{
|
||||||
"name": "Corporate",
|
"manifest_version": 2,
|
||||||
"slug": "corporate",
|
"name": "Corporate",
|
||||||
"version": "1.0.0",
|
"slug": "corporate",
|
||||||
"parent": "common",
|
"version": "1.0.0",
|
||||||
"type": "backend"
|
"author": "ABSDEV",
|
||||||
|
"description": "Corporate backend theme extending the common application theme.",
|
||||||
|
"type": "backend",
|
||||||
|
"extends": "common",
|
||||||
|
"entry_view": "dashboard",
|
||||||
|
"stylesheet": "css/theme.css",
|
||||||
|
"script": "js/app.js",
|
||||||
|
"preview": null,
|
||||||
|
"views": true,
|
||||||
|
"livewire_views": true,
|
||||||
|
"supports": {
|
||||||
|
"dark_mode": false,
|
||||||
|
"animations": false,
|
||||||
|
"privacy": false,
|
||||||
|
"terms": false,
|
||||||
|
"auth": false,
|
||||||
|
"preview": false,
|
||||||
|
"variants": false,
|
||||||
|
"settings": false,
|
||||||
|
"seo": false,
|
||||||
|
"export": true,
|
||||||
|
"accessibility_validation": true
|
||||||
|
},
|
||||||
|
"variables": {},
|
||||||
|
"variants": {},
|
||||||
|
"appearances": {},
|
||||||
|
"accents": {},
|
||||||
|
"default_appearance": null,
|
||||||
|
"default_accent": null,
|
||||||
|
"settings": {},
|
||||||
|
"seo": {}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,186 +1,192 @@
|
|||||||
{
|
{
|
||||||
"name": "Saasland",
|
"manifest_version": 2,
|
||||||
"slug": "saasland",
|
"name": "Saasland",
|
||||||
"version": "1.3.0",
|
"slug": "saasland",
|
||||||
"author": "ABSDEV",
|
"version": "1.3.0",
|
||||||
"description": "Premium dark SaaS frontend with compact section spacing, responsive dashboard hero, CMS-driven content and an expanded lead-generation footer.",
|
"author": "ABSDEV",
|
||||||
"entry_view": "home",
|
"description": "Premium dark SaaS frontend with compact section spacing, responsive dashboard hero, CMS-driven content and an expanded lead-generation footer.",
|
||||||
"stylesheet": "css/theme.css",
|
"type": "frontend",
|
||||||
"script": "js/app.js",
|
"extends": null,
|
||||||
"preview": "images/preview.webp",
|
"entry_view": "home",
|
||||||
"type": "frontend",
|
"stylesheet": "css/theme.css",
|
||||||
"views": true,
|
"script": "js/app.js",
|
||||||
"livewire_views": true,
|
"preview": "images/preview.webp",
|
||||||
"supports": {
|
"views": true,
|
||||||
"dark_mode": true,
|
"livewire_views": true,
|
||||||
"animations": true,
|
"supports": {
|
||||||
"privacy": true,
|
"dark_mode": true,
|
||||||
"terms": true,
|
"animations": true,
|
||||||
"auth": true,
|
"privacy": true,
|
||||||
"preview": true,
|
"terms": true,
|
||||||
"variants": true,
|
"auth": true,
|
||||||
"settings": true,
|
"preview": true,
|
||||||
"seo": true,
|
"variants": true,
|
||||||
"export": true,
|
"settings": true,
|
||||||
"accessibility_validation": true
|
"seo": true,
|
||||||
|
"export": true,
|
||||||
|
"accessibility_validation": true
|
||||||
|
},
|
||||||
|
"variables": {
|
||||||
|
"brand-primary": "#f97316",
|
||||||
|
"brand-secondary": "#111111",
|
||||||
|
"brand-accent": "#fb923c",
|
||||||
|
"surface": "#0f0e0d",
|
||||||
|
"surface-muted": "#191714",
|
||||||
|
"text-primary": "#f7f3ef"
|
||||||
|
},
|
||||||
|
"variants": {
|
||||||
|
"light": {
|
||||||
|
"label": "Light",
|
||||||
|
"variables": {}
|
||||||
},
|
},
|
||||||
"variables": {
|
"dark": {
|
||||||
"brand-primary": "#f97316",
|
"label": "Dark",
|
||||||
"brand-secondary": "#111111",
|
"variables": {
|
||||||
"brand-accent": "#fb923c",
|
"surface": "#0f172a",
|
||||||
"surface": "#0f0e0d",
|
"surface-muted": "#111827",
|
||||||
"surface-muted": "#191714",
|
"text-primary": "#f8fafc"
|
||||||
"text-primary": "#f7f3ef"
|
}
|
||||||
},
|
|
||||||
"variants": {
|
|
||||||
"light": {
|
|
||||||
"label": "Light",
|
|
||||||
"variables": {}
|
|
||||||
},
|
|
||||||
"dark": {
|
|
||||||
"label": "Dark",
|
|
||||||
"variables": {
|
|
||||||
"surface": "#0f172a",
|
|
||||||
"surface-muted": "#111827",
|
|
||||||
"text-primary": "#f8fafc"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"site_title": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Site title",
|
|
||||||
"default": "Abbey Software Development"
|
|
||||||
},
|
|
||||||
"site_description": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Site description",
|
|
||||||
"default": "Dark SaaS marketing theme with integrated feature, pricing, privacy and terms sections."
|
|
||||||
},
|
|
||||||
"logo_url": {
|
|
||||||
"type": "url",
|
|
||||||
"label": "Logo URL",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"--brand-primary": {
|
|
||||||
"type": "color",
|
|
||||||
"label": "Primary colour",
|
|
||||||
"default": "#f97316"
|
|
||||||
},
|
|
||||||
"hero_title": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Hero title",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"facebook_url": {
|
|
||||||
"type": "url",
|
|
||||||
"label": "Facebook URL",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"x_url": {
|
|
||||||
"type": "url",
|
|
||||||
"label": "X URL",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"linkedin_url": {
|
|
||||||
"type": "url",
|
|
||||||
"label": "LinkedIn URL",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"hero_eyebrow": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Hero eyebrow",
|
|
||||||
"default": "A better way to run your business"
|
|
||||||
},
|
|
||||||
"hero_description": {
|
|
||||||
"type": "textarea",
|
|
||||||
"label": "Hero description",
|
|
||||||
"default": "Streamline operations, boost productivity, and improve customer satisfaction with one connected platform built for modern teams."
|
|
||||||
},
|
|
||||||
"primary_cta_label": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Primary button label",
|
|
||||||
"default": "Get started free"
|
|
||||||
},
|
|
||||||
"primary_cta_url": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Primary button URL",
|
|
||||||
"default": "/register"
|
|
||||||
},
|
|
||||||
"secondary_cta_label": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Secondary button label",
|
|
||||||
"default": "Book demo"
|
|
||||||
},
|
|
||||||
"secondary_cta_url": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Secondary button URL",
|
|
||||||
"default": "#contact"
|
|
||||||
},
|
|
||||||
"show_metrics": {
|
|
||||||
"type": "checkbox",
|
|
||||||
"label": "Show performance preview",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"show_features": {
|
|
||||||
"type": "checkbox",
|
|
||||||
"label": "Show features",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"show_pricing": {
|
|
||||||
"type": "checkbox",
|
|
||||||
"label": "Show pricing",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"show_testimonials": {
|
|
||||||
"type": "checkbox",
|
|
||||||
"label": "Show testimonials",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"show_team": {
|
|
||||||
"type": "checkbox",
|
|
||||||
"label": "Show team",
|
|
||||||
"default": false
|
|
||||||
},
|
|
||||||
"show_blog": {
|
|
||||||
"type": "checkbox",
|
|
||||||
"label": "Show blog",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"show_news": {
|
|
||||||
"type": "checkbox",
|
|
||||||
"label": "Show news",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"show_faq": {
|
|
||||||
"type": "checkbox",
|
|
||||||
"label": "Show FAQ",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"show_newsletter": {
|
|
||||||
"type": "checkbox",
|
|
||||||
"label": "Show newsletter signup",
|
|
||||||
"default": true
|
|
||||||
},
|
|
||||||
"cta_title": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Final CTA title",
|
|
||||||
"default": "Ready to transform your business?"
|
|
||||||
},
|
|
||||||
"cta_description": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Final CTA description",
|
|
||||||
"default": "Start building a faster, more connected operation today."
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"seo": {
|
|
||||||
"title": "Saasland",
|
|
||||||
"description": "Dark SaaS marketing theme with integrated feature, pricing, privacy and terms sections.",
|
|
||||||
"image": "images/preview.webp",
|
|
||||||
"json_ld": {
|
|
||||||
"@context": "https://schema.org",
|
|
||||||
"@type": "WebSite",
|
|
||||||
"name": "Saasland"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"appearances": {},
|
||||||
|
"accents": {},
|
||||||
|
"default_appearance": null,
|
||||||
|
"default_accent": null,
|
||||||
|
"settings": {
|
||||||
|
"site_title": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Site title",
|
||||||
|
"default": "Abbey Software Development"
|
||||||
|
},
|
||||||
|
"site_description": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Site description",
|
||||||
|
"default": "Dark SaaS marketing theme with integrated feature, pricing, privacy and terms sections."
|
||||||
|
},
|
||||||
|
"logo_url": {
|
||||||
|
"type": "url",
|
||||||
|
"label": "Logo URL",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"--brand-primary": {
|
||||||
|
"type": "color",
|
||||||
|
"label": "Primary colour",
|
||||||
|
"default": "#f97316"
|
||||||
|
},
|
||||||
|
"hero_title": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Hero title",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"facebook_url": {
|
||||||
|
"type": "url",
|
||||||
|
"label": "Facebook URL",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"x_url": {
|
||||||
|
"type": "url",
|
||||||
|
"label": "X URL",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"linkedin_url": {
|
||||||
|
"type": "url",
|
||||||
|
"label": "LinkedIn URL",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"hero_eyebrow": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Hero eyebrow",
|
||||||
|
"default": "A better way to run your business"
|
||||||
|
},
|
||||||
|
"hero_description": {
|
||||||
|
"type": "textarea",
|
||||||
|
"label": "Hero description",
|
||||||
|
"default": "Streamline operations, boost productivity, and improve customer satisfaction with one connected platform built for modern teams."
|
||||||
|
},
|
||||||
|
"primary_cta_label": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Primary button label",
|
||||||
|
"default": "Get started free"
|
||||||
|
},
|
||||||
|
"primary_cta_url": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Primary button URL",
|
||||||
|
"default": "/register"
|
||||||
|
},
|
||||||
|
"secondary_cta_label": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Secondary button label",
|
||||||
|
"default": "Book demo"
|
||||||
|
},
|
||||||
|
"secondary_cta_url": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Secondary button URL",
|
||||||
|
"default": "#contact"
|
||||||
|
},
|
||||||
|
"show_metrics": {
|
||||||
|
"type": "checkbox",
|
||||||
|
"label": "Show performance preview",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"show_features": {
|
||||||
|
"type": "checkbox",
|
||||||
|
"label": "Show features",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"show_pricing": {
|
||||||
|
"type": "checkbox",
|
||||||
|
"label": "Show pricing",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"show_testimonials": {
|
||||||
|
"type": "checkbox",
|
||||||
|
"label": "Show testimonials",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"show_team": {
|
||||||
|
"type": "checkbox",
|
||||||
|
"label": "Show team",
|
||||||
|
"default": false
|
||||||
|
},
|
||||||
|
"show_blog": {
|
||||||
|
"type": "checkbox",
|
||||||
|
"label": "Show blog",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"show_news": {
|
||||||
|
"type": "checkbox",
|
||||||
|
"label": "Show news",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"show_faq": {
|
||||||
|
"type": "checkbox",
|
||||||
|
"label": "Show FAQ",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"show_newsletter": {
|
||||||
|
"type": "checkbox",
|
||||||
|
"label": "Show newsletter signup",
|
||||||
|
"default": true
|
||||||
|
},
|
||||||
|
"cta_title": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Final CTA title",
|
||||||
|
"default": "Ready to transform your business?"
|
||||||
|
},
|
||||||
|
"cta_description": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Final CTA description",
|
||||||
|
"default": "Start building a faster, more connected operation today."
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seo": {
|
||||||
|
"title": "Saasland",
|
||||||
|
"description": "Dark SaaS marketing theme with integrated feature, pricing, privacy and terms sections.",
|
||||||
|
"image": "images/preview.webp",
|
||||||
|
"json_ld": {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "WebSite",
|
||||||
|
"name": "Saasland"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,101 +1,107 @@
|
|||||||
{
|
{
|
||||||
"name": "Swiss",
|
"manifest_version": 2,
|
||||||
"slug": "swiss",
|
"name": "Swiss",
|
||||||
"version": "1.1.0",
|
"slug": "swiss",
|
||||||
"author": "ABSDEV",
|
"version": "1.1.0",
|
||||||
"description": "Dark Marketing Theme with integrated feature, pricing, privacy and terms sections.",
|
"author": "ABSDEV",
|
||||||
"entry_view": "home",
|
"description": "Dark Marketing Theme with integrated feature, pricing, privacy and terms sections.",
|
||||||
"stylesheet": "css/theme.css",
|
"type": "frontend",
|
||||||
"script": "js/app.js",
|
"extends": null,
|
||||||
"preview": "images/preview.webp",
|
"entry_view": "home",
|
||||||
"type": "frontend",
|
"stylesheet": "css/theme.css",
|
||||||
"views": true,
|
"script": "js/app.js",
|
||||||
"livewire_views": true,
|
"preview": "images/preview.webp",
|
||||||
"supports": {
|
"views": true,
|
||||||
"dark_mode": true,
|
"livewire_views": true,
|
||||||
"animations": true,
|
"supports": {
|
||||||
"privacy": true,
|
"dark_mode": true,
|
||||||
"terms": true,
|
"animations": true,
|
||||||
"auth": false,
|
"privacy": true,
|
||||||
"preview": true,
|
"terms": true,
|
||||||
"variants": true,
|
"auth": false,
|
||||||
"settings": true,
|
"preview": true,
|
||||||
"seo": true,
|
"variants": true,
|
||||||
"export": true,
|
"settings": true,
|
||||||
"accessibility_validation": true
|
"seo": true,
|
||||||
|
"export": true,
|
||||||
|
"accessibility_validation": true
|
||||||
|
},
|
||||||
|
"variables": {
|
||||||
|
"brand-primary": "#f97316",
|
||||||
|
"brand-secondary": "#111111",
|
||||||
|
"brand-accent": "#fb923c",
|
||||||
|
"surface": "#0f0e0d",
|
||||||
|
"surface-muted": "#191714",
|
||||||
|
"text-primary": "#f7f3ef"
|
||||||
|
},
|
||||||
|
"variants": {
|
||||||
|
"light": {
|
||||||
|
"label": "Light",
|
||||||
|
"variables": {}
|
||||||
},
|
},
|
||||||
"variables": {
|
"dark": {
|
||||||
"brand-primary": "#f97316",
|
"label": "Dark",
|
||||||
"brand-secondary": "#111111",
|
"variables": {
|
||||||
"brand-accent": "#fb923c",
|
"surface": "#0f172a",
|
||||||
"surface": "#0f0e0d",
|
"surface-muted": "#111827",
|
||||||
"surface-muted": "#191714",
|
"text-primary": "#f8fafc"
|
||||||
"text-primary": "#f7f3ef"
|
}
|
||||||
},
|
|
||||||
"variants": {
|
|
||||||
"light": {
|
|
||||||
"label": "Light",
|
|
||||||
"variables": {}
|
|
||||||
},
|
|
||||||
"dark": {
|
|
||||||
"label": "Dark",
|
|
||||||
"variables": {
|
|
||||||
"surface": "#0f172a",
|
|
||||||
"surface-muted": "#111827",
|
|
||||||
"text-primary": "#f8fafc"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"settings": {
|
|
||||||
"site_title": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Site title",
|
|
||||||
"default": "Saasland"
|
|
||||||
},
|
|
||||||
"site_description": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Site description",
|
|
||||||
"default": "Dark SaaS marketing theme with integrated feature, pricing, privacy and terms sections."
|
|
||||||
},
|
|
||||||
"logo_url": {
|
|
||||||
"type": "url",
|
|
||||||
"label": "Logo URL",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"--brand-primary": {
|
|
||||||
"type": "color",
|
|
||||||
"label": "Primary colour",
|
|
||||||
"default": "#f97316"
|
|
||||||
},
|
|
||||||
"hero_title": {
|
|
||||||
"type": "text",
|
|
||||||
"label": "Hero title",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"facebook_url": {
|
|
||||||
"type": "url",
|
|
||||||
"label": "Facebook URL",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"x_url": {
|
|
||||||
"type": "url",
|
|
||||||
"label": "X URL",
|
|
||||||
"default": ""
|
|
||||||
},
|
|
||||||
"linkedin_url": {
|
|
||||||
"type": "url",
|
|
||||||
"label": "LinkedIn URL",
|
|
||||||
"default": ""
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"seo": {
|
|
||||||
"title": "Saasland",
|
|
||||||
"description": "Dark SaaS marketing theme with integrated feature, pricing, privacy and terms sections.",
|
|
||||||
"image": "images/preview.webp",
|
|
||||||
"json_ld": {
|
|
||||||
"@context": "https://schema.org",
|
|
||||||
"@type": "WebSite",
|
|
||||||
"name": "Saasland"
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"appearances": {},
|
||||||
|
"accents": {},
|
||||||
|
"default_appearance": null,
|
||||||
|
"default_accent": null,
|
||||||
|
"settings": {
|
||||||
|
"site_title": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Site title",
|
||||||
|
"default": "Saasland"
|
||||||
|
},
|
||||||
|
"site_description": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Site description",
|
||||||
|
"default": "Dark SaaS marketing theme with integrated feature, pricing, privacy and terms sections."
|
||||||
|
},
|
||||||
|
"logo_url": {
|
||||||
|
"type": "url",
|
||||||
|
"label": "Logo URL",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"--brand-primary": {
|
||||||
|
"type": "color",
|
||||||
|
"label": "Primary colour",
|
||||||
|
"default": "#f97316"
|
||||||
|
},
|
||||||
|
"hero_title": {
|
||||||
|
"type": "text",
|
||||||
|
"label": "Hero title",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"facebook_url": {
|
||||||
|
"type": "url",
|
||||||
|
"label": "Facebook URL",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"x_url": {
|
||||||
|
"type": "url",
|
||||||
|
"label": "X URL",
|
||||||
|
"default": ""
|
||||||
|
},
|
||||||
|
"linkedin_url": {
|
||||||
|
"type": "url",
|
||||||
|
"label": "LinkedIn URL",
|
||||||
|
"default": ""
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"seo": {
|
||||||
|
"title": "Saasland",
|
||||||
|
"description": "Dark SaaS marketing theme with integrated feature, pricing, privacy and terms sections.",
|
||||||
|
"image": "images/preview.webp",
|
||||||
|
"json_ld": {
|
||||||
|
"@context": "https://schema.org",
|
||||||
|
"@type": "WebSite",
|
||||||
|
"name": "Saasland"
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,19 +1,23 @@
|
|||||||
{
|
{
|
||||||
|
"manifest_version": 2,
|
||||||
"name": "Welcome",
|
"name": "Welcome",
|
||||||
"slug": "welcome",
|
"slug": "welcome",
|
||||||
"extends": "common",
|
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"author": "ABSDEV",
|
"author": "ABSDEV",
|
||||||
"description": "Laravel 13 welcome theme.",
|
"description": "Laravel 13 welcome theme.",
|
||||||
|
"type": "frontend",
|
||||||
|
"extends": "common",
|
||||||
"entry_view": "welcome",
|
"entry_view": "welcome",
|
||||||
"stylesheet": "css/theme.css",
|
"stylesheet": "css/theme.css",
|
||||||
"script": "js/app.js",
|
"script": "js/app.js",
|
||||||
"type": "frontend",
|
"preview": "images/preview.webp",
|
||||||
"views": true,
|
"views": true,
|
||||||
"livewire_views": true,
|
"livewire_views": true,
|
||||||
"supports": {
|
"supports": {
|
||||||
"dark_mode": false,
|
"dark_mode": false,
|
||||||
"animations": false,
|
"animations": false,
|
||||||
|
"privacy": false,
|
||||||
|
"terms": false,
|
||||||
"auth": false,
|
"auth": false,
|
||||||
"preview": true,
|
"preview": true,
|
||||||
"variants": true,
|
"variants": true,
|
||||||
@@ -30,7 +34,6 @@
|
|||||||
"surface-muted": "#f8fafc",
|
"surface-muted": "#f8fafc",
|
||||||
"text-primary": "#0f172a"
|
"text-primary": "#0f172a"
|
||||||
},
|
},
|
||||||
"preview": "images/preview.webp",
|
|
||||||
"variants": {
|
"variants": {
|
||||||
"light": {
|
"light": {
|
||||||
"label": "Light",
|
"label": "Light",
|
||||||
@@ -45,6 +48,10 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"appearances": {},
|
||||||
|
"accents": {},
|
||||||
|
"default_appearance": null,
|
||||||
|
"default_accent": null,
|
||||||
"settings": {
|
"settings": {
|
||||||
"site_title": {
|
"site_title": {
|
||||||
"type": "text",
|
"type": "text",
|
||||||
|
|||||||
Reference in New Issue
Block a user