Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
70.59% covered (warning)
70.59%
24 / 34
80.00% covered (warning)
80.00%
4 / 5
CRAP
0.00% covered (danger)
0.00%
0 / 1
ThemeController
70.59% covered (warning)
70.59%
24 / 34
80.00% covered (warning)
80.00%
4 / 5
6.92
0.00% covered (danger)
0.00%
0 / 1
 __construct
100.00% covered (success)
100.00%
1 / 1
100.00% covered (success)
100.00%
1 / 1
1
 index
100.00% covered (success)
100.00%
11 / 11
100.00% covered (success)
100.00%
1 / 1
1
 activate
100.00% covered (success)
100.00%
7 / 7
100.00% covered (success)
100.00%
1 / 1
1
 customize
0.00% covered (danger)
0.00%
0 / 10
0.00% covered (danger)
0.00%
0 / 1
6
 saveCustomizer
100.00% covered (success)
100.00%
5 / 5
100.00% covered (success)
100.00%
1 / 1
1
1<?php
2
3namespace App\Http\Controllers\admin;
4
5use App\Http\Controllers\Controller;
6use App\Models\Theme;
7use App\Services\Theme\ThemeService;
8use Illuminate\Http\RedirectResponse;
9use Illuminate\Http\Request;
10use Illuminate\Validation\Rule;
11use Illuminate\View\View;
12
13/**
14 * Settings → Appearance → Themes. Install-time themes are discovered from
15 * resources/views/themes/*; here the operator picks the active one and
16 * tweaks its customizer (colours / fonts / layout from theme.json).
17 */
18class ThemeController extends Controller
19{
20    public function __construct(private ThemeService $themes) {}
21
22    public function index(): View
23    {
24        $this->themes->sync();
25
26        $active = $this->themes->activeHandle();
27
28        $list = $this->themes->discover()->map(function ($t) use ($active) {
29            $t['active'] = $t['handle'] === $active;
30            $t['customizable'] = ! empty($t['customizer']);
31
32            return $t;
33        })->values();
34
35        return view('admin.appearance.themes', [
36            'themes' => $list,
37            'settingsGroups' => config('settings', []),
38        ]);
39    }
40
41    public function activate(Request $request): RedirectResponse
42    {
43        $data = $request->validate([
44            'handle' => ['required', 'string', Rule::in($this->themes->discover()->keys())],
45        ]);
46
47        $this->themes->activate($data['handle']);
48
49        return redirect()
50            ->route('admin.themes.index')
51            ->with('success', ($this->themes->manifest($data['handle'])['name'] ?? 'Theme') . ' is now live.');
52    }
53
54    public function customize(string $handle): View|RedirectResponse
55    {
56        $manifest = $this->themes->manifest($handle);
57        if (! $manifest) {
58            return redirect()->route('admin.themes.index');
59        }
60
61        return view('admin.appearance.customize', [
62            'handle' => $handle,
63            'manifest' => $manifest,
64            'fields' => $this->themes->customizerFields($handle),
65            'values' => $this->themes->customizerValues($handle),
66            'settingsGroups' => config('settings', []),
67        ]);
68    }
69
70    public function saveCustomizer(Request $request, string $handle): RedirectResponse
71    {
72        abort_unless($this->themes->manifest($handle), 404);
73
74        $this->themes->saveCustomizer($handle, (array) $request->input('customizer', []));
75
76        return redirect()
77            ->route('admin.themes.customize', $handle)
78            ->with('success', 'Theme customiser saved.');
79    }
80}