From 63582531e37d3fa7ec67e5f3388d0a928313d69a Mon Sep 17 00:00:00 2001 From: Mark Gregory Date: Tue, 20 Oct 2026 10:29:35 +0100 Subject: [PATCH] added theme support --- .../Stylist/Resources/views/index.blade.php | 533 +++++++++++++++--- .../views/index.blade.php.bak-20261020-102848 | 86 +++ resources/views/admin/index.blade.php | 2 +- .../admin/index.blade.php.bak-20261020-102848 | 6 + resources/views/layouts/app.blade.php | 1 + .../layouts/app.blade.php.bak-20261020-102848 | 529 +++++++++++++++++ 6 files changed, 1083 insertions(+), 74 deletions(-) create mode 100644 modules/Stylist/Resources/views/index.blade.php.bak-20261020-102848 create mode 100644 resources/views/admin/index.blade.php.bak-20261020-102848 create mode 100644 resources/views/layouts/app.blade.php.bak-20261020-102848 diff --git a/modules/Stylist/Resources/views/index.blade.php b/modules/Stylist/Resources/views/index.blade.php index 8c4abf2..c667fc3 100644 --- a/modules/Stylist/Resources/views/index.blade.php +++ b/modules/Stylist/Resources/views/index.blade.php @@ -1,86 +1,473 @@ -@extends('stylist::layouts.app') +@extends('layouts.app', ['title' => 'Stylist — SonarDesk Administration']) @section('content') -
- Administration -

Stylist

-

Install, configure, validate and export self-contained themes.

-
- - @if (session('status')) -
{{ session('status') }}
- @endif - @if ($errors->any()) -
{{ $errors->first() }}
+
+ +
+
+ Administration / Appearance +

Stylist

+

+ Manage frontend and administration themes independently. + Install, configure, preview and export complete themes. +

+
+ + + Back to administration + +
+ + @if(session('status')) +
{{ session('status') }}
@endif -
- @csrf - - -
+ @if($errors->any()) +
{{ $errors->first() }}
+ @endif + +
+
+ Installed themes + {{ count($themes) }} + Available designs +
+ +
+ Frontend theme + {{ $activeFrontendTheme }} + Public website +
+ +
+ Backend theme + {{ $activeBackendTheme }} + Administration interface +
+
+ +
+
+
+ Theme library +

Install a theme

+

Upload a self-contained theme package in ZIP format.

+
+
+ +
+ + @csrf + + + + +
+
+ +
+ +
+
+ Appearance +

Installed themes

+

Frontend and backend themes can be activated independently.

+
+
+ +
+ + @foreach($themes as $item) + + @php + $saved = $settingsService->get($item); + $variant = $settingsService->variant($item); + $appearance = $settingsService->appearance($item); + $accent = $settingsService->accent($item); + $issues = $accessibility->validate($item); + + $isActive = + ($item->type() === 'frontend' && $item->key() === $activeFrontendTheme) + || ($item->type() === 'backend' && $item->key() === $activeBackendTheme); + + $isBundled = in_array( + $item->key(), + ['sonardesk', 'sonardesk-admin'], + true + ); + + $themeRoot = realpath(config('stylist.themes_path')); + $themePath = realpath($item->path()); + + $isInstalled = $themeRoot + && $themePath + && str_starts_with( + $themePath, + rtrim($themeRoot, DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR + ); + @endphp + +
+ +
+ + @if($item->preview() && $item->has($item->preview())) + + {{ $item->name() }} preview + + @else + +
+ ◈ + {{ $item->name() }} + No preview image available +
-
- @foreach ($themes as $item) - @php($saved = $settingsService->get($item)) - @php($variant = $settingsService->variant($item)) - @php($issues = $accessibility->validate($item)) - @php($appearance = $settingsService->appearance($item)) - @php($accent = $settingsService->accent($item)) -
-
- @if ($item->preview() && $item->has($item->preview())) - {{ $item->name() }} theme preview - @else -
Add preview.webp to this theme
- @endif -
-
-

{{ $item->name() }}

v{{ $item->version() }}@if($item->author()) · {{ $item->author() }}@endif

@if(($item->type() === 'frontend' && $item->key() === $activeFrontendTheme) || ($item->type() === 'backend' && $item->key() === $activeBackendTheme))Active {{ ucfirst($item->type()) }}@endif
- @if($item->description())

{{ $item->description() }}

@endif - @if($item->parent())

Child of {{ $item->parent() }}

@endif -
- @if(in_array($item->type(), ['frontend', 'backend'], true)) -
@csrf
- Preview - @endif - Export ZIP -
@csrf
- @if(str_starts_with(realpath($item->path()) ?: '', realpath(config('stylist.themes_path')) ?: '/__never__')) -
@csrf @method('DELETE')
@endif +
-
- Theme settings -
@csrf @method('PUT') - @if($item->variants()) - + +
+ +
+ +
+ + {{ ucfirst($item->type()) }} theme + + +

{{ $item->name() }}

+ +

+ Version {{ $item->version() }} + @if($item->author()) + · {{ $item->author() }} + @endif +

+
+ + @if($isActive) + + Active + @endif - @if($item->supports('dark_mode') || $item->appearances()) - + +
+ + @if($item->description()) +

+ {{ $item->description() }} +

+ @endif + + @if($item->parent()) +

+ Based on {{ $item->parent() }} +

+ @endif + +
+ + @if(in_array($item->type(), ['frontend', 'backend'], true)) + + @unless($isActive) + + + @csrf + + + + + @endunless + + + Preview + + @endif - @if($item->accents()) -
Accent colour
@foreach($item->accents() as $name => $definition)@endforeach
+ + + Export ZIP + + +
+ @csrf + + +
+ +
+ +
+ + + Theme configuration + ⌄ + + +
+ + @csrf + @method('PUT') + + @if($item->variants()) + + + + @endif + + @if($item->supports('dark_mode') || $item->appearances()) + + + + @endif + + @if($item->accents()) + +
+ Accent colour + + @foreach($item->accents() as $name => $definition) + + + + @endforeach + +
+ + @endif + + @foreach($item->settingsSchema() as $key => $definition) + + @php + $definition = is_array($definition) + ? $definition + : ['default' => $definition]; + + $fieldType = $definition['type'] ?? 'text'; + $fieldLabel = $definition['label'] ?? str($key)->headline(); + $fieldValue = $saved[$key] ?? ($definition['default'] ?? ''); + @endphp + +
+ + + + @switch($fieldType) + + @case('color') + + + @break + + @case('textarea') + + + @break + + @case('checkbox') + + + + + @break + + @default + + + + @endswitch + +
+ + @endforeach + + + +
+ +
+ +
-
Accessibility: {{ count($issues) ? count($issues).' issue(s)' : 'passed static checks' }}
-
-
- @endforeach -
+ +
+ +
+ + + + @endforeach + +
+ + + + + + @endsection diff --git a/modules/Stylist/Resources/views/index.blade.php.bak-20261020-102848 b/modules/Stylist/Resources/views/index.blade.php.bak-20261020-102848 new file mode 100644 index 0000000..8c4abf2 --- /dev/null +++ b/modules/Stylist/Resources/views/index.blade.php.bak-20261020-102848 @@ -0,0 +1,86 @@ +@extends('stylist::layouts.app') + +@section('content') +
+ Administration +

Stylist

+

Install, configure, validate and export self-contained themes.

+
+ + + @if (session('status')) +
{{ session('status') }}
+ @endif + @if ($errors->any()) +
{{ $errors->first() }}
+ @endif + +
+ @csrf + + +
+ +
+ @foreach ($themes as $item) + @php($saved = $settingsService->get($item)) + @php($variant = $settingsService->variant($item)) + @php($issues = $accessibility->validate($item)) + @php($appearance = $settingsService->appearance($item)) + @php($accent = $settingsService->accent($item)) +
+
+ @if ($item->preview() && $item->has($item->preview())) + {{ $item->name() }} theme preview + @else +
Add preview.webp to this theme
+ @endif +
+
+

{{ $item->name() }}

v{{ $item->version() }}@if($item->author()) · {{ $item->author() }}@endif

@if(($item->type() === 'frontend' && $item->key() === $activeFrontendTheme) || ($item->type() === 'backend' && $item->key() === $activeBackendTheme))Active {{ ucfirst($item->type()) }}@endif
+ @if($item->description())

{{ $item->description() }}

@endif + @if($item->parent())

Child of {{ $item->parent() }}

@endif +
+ @if(in_array($item->type(), ['frontend', 'backend'], true)) +
@csrf
+ Preview + @endif + Export ZIP +
@csrf
+ @if(str_starts_with(realpath($item->path()) ?: '', realpath(config('stylist.themes_path')) ?: '/__never__')) +
@csrf @method('DELETE')
+ @endif +
+
+ Theme settings +
@csrf @method('PUT') + @if($item->variants()) + + @endif + @if($item->supports('dark_mode') || $item->appearances()) + + @endif + @if($item->accents()) +
Accent colour
@foreach($item->accents() as $name => $definition)@endforeach
+ @endif + @foreach($item->settingsSchema() as $key => $definition) + @php($definition = is_array($definition) ? $definition : ['default' => $definition]) + + @endforeach + +
+
+
Accessibility: {{ count($issues) ? count($issues).' issue(s)' : 'passed static checks' }}
+
+
+ @endforeach +
+ +@endsection diff --git a/resources/views/admin/index.blade.php b/resources/views/admin/index.blade.php index 61766a6..dd50ff8 100755 --- a/resources/views/admin/index.blade.php +++ b/resources/views/admin/index.blade.php @@ -2,5 +2,5 @@ @section('content')
Admin

Licensing administration

Manage licences, activations and customer support.

{{ $licenseCount }}

Licences

{{ $activeCount }}

Not revoked

{{ $activationCount }}

Active installations

{{ $userCount }}

Portal users

-
Manage releasesManage licencesManage usersManage contentSEO & searchSupport inbox
+
Manage releasesManage licencesManage usersManage contentManage themesSEO & searchSupport inbox
@endsection diff --git a/resources/views/admin/index.blade.php.bak-20261020-102848 b/resources/views/admin/index.blade.php.bak-20261020-102848 new file mode 100644 index 0000000..61766a6 --- /dev/null +++ b/resources/views/admin/index.blade.php.bak-20261020-102848 @@ -0,0 +1,6 @@ +@extends('layouts.app') +@section('content') +
Admin

Licensing administration

Manage licences, activations and customer support.

+
{{ $licenseCount }}

Licences

{{ $activeCount }}

Not revoked

{{ $activationCount }}

Active installations

{{ $userCount }}

Portal users

+
Manage releasesManage licencesManage usersManage contentSEO & searchSupport inbox
+@endsection diff --git a/resources/views/layouts/app.blade.php b/resources/views/layouts/app.blade.php index 8defb68..0ebefd3 100644 --- a/resources/views/layouts/app.blade.php +++ b/resources/views/layouts/app.blade.php @@ -403,6 +403,7 @@ Admin Users Releases + Themes Download products Support diff --git a/resources/views/layouts/app.blade.php.bak-20261020-102848 b/resources/views/layouts/app.blade.php.bak-20261020-102848 new file mode 100644 index 0000000..8defb68 --- /dev/null +++ b/resources/views/layouts/app.blade.php.bak-20261020-102848 @@ -0,0 +1,529 @@ + + + + + + + + @php + $seoSiteName = \App\Models\SiteSetting::valueFor('seo_site_name', 'SonarDesk'); + $seoDefaultTitle = \App\Models\SiteSetting::valueFor('seo_default_title', 'SonarDesk — Native SonarQube Monitoring for macOS'); + $seoDefaultDescription = \App\Models\SiteSetting::valueFor('seo_default_description', 'Native SonarQube monitoring for macOS. Track projects, quality gates, bugs, vulnerabilities and code smells from one professional desktop app.'); + $pageTitle = $title ?? $seoDefaultTitle; + $pageDescription = $description ?? $seoDefaultDescription; + $pageKeywords = $keywords ?? \App\Models\SiteSetting::valueFor('seo_default_keywords'); + $canonicalBase = rtrim(\App\Models\SiteSetting::valueFor('seo_canonical_base_url', config('app.url')), '/'); + $canonicalUrl = $canonical ?? ($canonicalBase . request()->getPathInfo()); + $socialImage = $ogImage ?? \App\Models\SiteSetting::valueFor('seo_default_og_image', url('/icons/og-sonardesk.png')); + $ogTitle = $ogTitle ?? $pageTitle; + $ogDescription = $ogDescription ?? $pageDescription; + $robotsIndex = $robotsIndex ?? true; + $robotsFollow = $robotsFollow ?? true; + $productionIndexing = app()->environment('production') && \App\Models\SiteSetting::booleanFor('seo_robots_enabled', true); + $robots = $productionIndexing ? (($robotsIndex ? 'index' : 'noindex').','.($robotsFollow ? 'follow' : 'nofollow').',max-image-preview:large,max-snippet:-1,max-video-preview:-1') : 'noindex,nofollow'; + $twitterSite = \App\Models\SiteSetting::valueFor('seo_twitter_site'); + $googleVerification = \App\Models\SiteSetting::valueFor('seo_google_site_verification'); + $organizationName = \App\Models\SiteSetting::valueFor('seo_organization_name', $seoSiteName); + $organizationLogo = \App\Models\SiteSetting::valueFor('seo_organization_logo', url('/icons/sonardesk-icon-512.png')); + $schema = [ + '@context' => 'https://schema.org', '@type' => 'SoftwareApplication', 'name' => $seoSiteName, + 'applicationCategory' => 'DeveloperApplication', 'operatingSystem' => 'macOS', 'url' => route('home'), + 'description' => $seoDefaultDescription, 'publisher' => ['@type' => 'Organization', 'name' => $organizationName, 'logo' => ['@type' => 'ImageObject', 'url' => $organizationLogo]], + ]; + @endphp + + {{ $pageTitle }} + + @if($pageKeywords)@endif + + + @if($googleVerification)@endif + + + + + + + + + + + + + + + + + + + + + + + + + @if($twitterSite)@endif + + + + + + + @stack('head') + + + + +@hasSection('fullbleed') + @yield('fullbleed') +@else +
+ @if(session('status'))
{{ session('status') }}
@endif + @if($errors->any())
{{ $errors->first() }}
@endif + @yield('content') +
+@endif + + + + + + + + + + + +