Skip to content

Commit 55dbbc1

Browse files
committed
Theme selector added
1 parent d54187e commit 55dbbc1

63 files changed

Lines changed: 1351 additions & 583 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/Http/Controllers/Api/Registries/RegistrySearchController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ public function search(Request $request): JsonResponse
2626
'category' => $item->meta['category'] ?? null,
2727
'description' => $item->meta['description'] ?? null,
2828
'baseColor' => $item->baseColor ?? null,
29+
'css_vars' => $item->css_vars ?? null,
2930
]);
3031

3132
return response()->json($results);

app/Http/Controllers/Api/ThemeCssController.php

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
use App\Http\Controllers\Controller;
66
use App\Models\Registry;
77
use App\Services\ThemeCssGenerator;
8+
use Illuminate\Http\Request;
89
use Illuminate\Http\Response;
910

1011
class ThemeCssController extends Controller
@@ -13,17 +14,36 @@ public function __construct(
1314
private readonly ThemeCssGenerator $generator,
1415
) {}
1516

16-
public function show(string $name): Response
17+
public function show(string $name, Request $request): Response
1718
{
1819
$theme = Registry::where('name', $name)
1920
->where('type', 'registry:theme')
2021
->firstOrFail();
2122

2223
$css = $this->generator->generate($theme);
2324

25+
if ($request->boolean('inject')) {
26+
$css = $this->extractVariableBlocks($css);
27+
}
28+
2429
return response($css, 200, [
2530
'Content-Type' => 'text/css',
2631
'Cache-Control' => 'public, max-age=3600',
2732
]);
2833
}
34+
35+
private function extractVariableBlocks(string $css): string
36+
{
37+
$blocks = [];
38+
39+
if (preg_match('/:root\s*\{[^}]*\}/s', $css, $matches)) {
40+
$blocks[] = $matches[0];
41+
}
42+
43+
if (preg_match('/\.dark\s*\{[^}]*\}/s', $css, $matches)) {
44+
$blocks[] = $matches[0];
45+
}
46+
47+
return implode("\n\n", $blocks);
48+
}
2949
}

app/Http/Controllers/ThemePageController.php

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ class ThemePageController extends Controller
1313
*/
1414
public function __invoke(Request $request)
1515
{
16+
1617
return Inertia::render('theme/index', [
1718
'themes' => Registry::query()->themes()->get(),
1819
]);

app/Services/ThemeCssGenerator.php

Lines changed: 92 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ public function generate(Registry $registry): string
2222

2323
$light = $cssVars['light'] ?? [];
2424
$dark = $cssVars['dark'] ?? [];
25-
$theme = $cssVars['theme'] ?? [];
25+
$themeVars = $cssVars['theme'] ?? [];
2626

27-
$rootVars = array_merge($light, $theme);
28-
$darkVars = array_merge($dark, $theme);
27+
$rootVars = array_merge($light, $themeVars);
28+
$darkVars = array_merge($dark, $themeVars);
2929

3030
$rootVars = $this->normalizeKeys($rootVars);
3131
$darkVars = $this->normalizeKeys($darkVars);
@@ -35,7 +35,13 @@ public function generate(Registry $registry): string
3535

3636
$rootBlock = $this->objectToVars($rootVars);
3737
$darkBlock = $this->objectToVars($darkVars);
38-
$layerBase = $this->convertLayerBase($css);
38+
39+
// Use css from registry if available, otherwise use default
40+
if (!empty($css)) {
41+
$cssBlock = $this->convertCss($css);
42+
} else {
43+
$cssBlock = $this->getDefaultCssBlock();
44+
}
3945

4046
return <<<CSS
4147
@import "tailwindcss";
@@ -50,6 +56,79 @@ public function generate(Registry $registry): string
5056
{$darkBlock}
5157
}
5258
59+
{$cssBlock}
60+
CSS;
61+
}
62+
63+
private function normalizeKeys(array $obj): array
64+
{
65+
$normalized = [];
66+
67+
foreach ($obj as $key => $value) {
68+
$newKey = self::KEY_MAP[$key] ?? $key;
69+
$normalized[$newKey] = $value;
70+
}
71+
72+
return $normalized;
73+
}
74+
75+
private function objectToVars(array $obj): string
76+
{
77+
return collect($obj)
78+
->map(fn ($v, $k) => " --{$k}: {$v};")
79+
->join("\n");
80+
}
81+
82+
private function convertCss(array $css): string
83+
{
84+
$blocks = [];
85+
86+
// Handle @theme inline
87+
if (!empty($css['@theme inline'])) {
88+
$themeInline = $this->convertThemeInline($css['@theme inline']);
89+
$blocks[] = "@theme inline {\n{$themeInline}\n}";
90+
}
91+
92+
// Handle @layer base
93+
if (!empty($css['@layer base'])) {
94+
$layerBase = $this->convertLayerBase($css['@layer base']);
95+
$blocks[] = "@layer base {\n{$layerBase}\n}";
96+
}
97+
98+
return implode("\n\n", $blocks);
99+
}
100+
101+
private function convertThemeInline(array $theme): string
102+
{
103+
return collect($theme)
104+
->map(fn ($v, $k) => " {$k}: {$v};")
105+
->join("\n");
106+
}
107+
108+
private function convertLayerBase(array $rules): string
109+
{
110+
return collect($rules)
111+
->map(function ($styles, $selector) {
112+
if (is_string($styles)) {
113+
$indentedStyles = collect(explode("\n", $styles))
114+
->map(fn ($line) => ' '.$line)
115+
->join("\n");
116+
117+
return " {$selector} {\n{$indentedStyles}\n }";
118+
}
119+
120+
$props = collect($styles)
121+
->map(fn ($v, $k) => " {$k}: {$v};")
122+
->join("\n");
123+
124+
return " {$selector} {\n{$props}\n }";
125+
})
126+
->join("\n");
127+
}
128+
129+
private function getDefaultCssBlock(): string
130+
{
131+
return <<<CSS
53132
@theme inline {
54133
--color-background: var(--background);
55134
--color-foreground: var(--foreground);
@@ -103,55 +182,15 @@ public function generate(Registry $registry): string
103182
--shadow-2xl: var(--shadow-2xl);
104183
}
105184
106-
{$layerBase}
107-
CSS;
108-
}
109-
110-
private function normalizeKeys(array $obj): array
111-
{
112-
$normalized = [];
113-
114-
foreach ($obj as $key => $value) {
115-
$newKey = self::KEY_MAP[$key] ?? $key;
116-
$normalized[$newKey] = $value;
117-
}
118-
119-
return $normalized;
120-
}
121-
122-
private function objectToVars(array $obj): string
123-
{
124-
return collect($obj)
125-
->map(fn ($v, $k) => " --{$k}: {$v};")
126-
->join("\n");
127-
}
128-
129-
private function convertLayerBase(?array $css): string
130-
{
131-
if (empty($css['@layer base'])) {
132-
return '';
133-
}
134-
135-
$rules = $css['@layer base'];
185+
@layer base {
186+
* {
187+
@apply border-border;
188+
}
136189
137-
$body = collect($rules)
138-
->map(function ($styles, $selector) {
139-
if (is_string($styles)) {
140-
$indentedStyles = collect(explode("\n", $styles))
141-
->map(fn ($line) => ' '.$line)
142-
->join("\n");
143-
144-
return " {$selector} {\n{$indentedStyles}\n }";
145-
}
146-
147-
$props = collect($styles)
148-
->map(fn ($v, $k) => " {$k}: {$v};")
149-
->join("\n");
150-
151-
return " {$selector} {\n{$props}\n }";
152-
})
153-
->join("\n");
154-
155-
return "@layer base {\n{$body}\n}";
190+
body {
191+
@apply bg-background text-foreground;
192+
}
193+
}
194+
CSS;
156195
}
157196
}

public/build/assets/app-BKvygTdv.js

Lines changed: 0 additions & 142 deletions
This file was deleted.

public/build/assets/app-Bmb-Z7_l.css

Lines changed: 0 additions & 2 deletions
This file was deleted.

public/build/assets/app-BpL40ehJ.css

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/build/assets/app-C8kLBGzT.js

Lines changed: 142 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/build/assets/appearance-BdVHp9XD.js renamed to public/build/assets/appearance-DyZjeflB.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

public/build/assets/check-BxvHKLhU.js

Lines changed: 0 additions & 1 deletion
This file was deleted.

0 commit comments

Comments
 (0)