diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml
index f588c15..6542a63 100644
--- a/.github/workflows/test.yml
+++ b/.github/workflows/test.yml
@@ -13,4 +13,4 @@ jobs:
test:
uses: saucebase-dev/saucebase/.github/workflows/test-module.yml@main
with:
- module: Themes
+ module: themes
diff --git a/CLAUDE.md b/CLAUDE.md
index b36739c..422945c 100644
--- a/CLAUDE.md
+++ b/CLAUDE.md
@@ -112,9 +112,9 @@ documentElement inline styles ← set by applyThemeVars() when a theme is activ
|------|------|
| `resources/themes/*.json` | Theme definitions — committed source of truth |
| `resources/css/theme.css` | (in `resources/css/`, not inside module) — baked CSS output |
-| `app/Console/Commands/ApplyThemeCommand.php` | Patches theme.css from JSON; writes `:root` and `.dark` blocks |
-| `app/Providers/ThemesServiceProvider.php` | Discovers themes, parses JSON, shares via Inertia |
-| `app/Http/Controllers/ThemesController.php` | REST API for save/update/delete of user themes |
+| `src/Console/Commands/ApplyThemeCommand.php` | Patches theme.css from JSON; writes `:root` and `.dark` blocks |
+| `src/Providers/ThemesServiceProvider.php` | Discovers themes, parses JSON, shares via Inertia |
+| `src/Http/Controllers/ThemesController.php` | REST API for save/update/delete of user themes |
| `resources/js/fields.ts` | Canonical list of all editable fields with type, vars, constraints |
| `resources/js/utils/theme.ts` | Core utilities: `applyThemeVars`, `computeShadows`, `computeRadiusScale`, `computeTrackingScale`, font loading |
| `resources/js/components/ThemePanel.vue` | Full visual editor — field rendering, per-field mode sync, save dropdown |
@@ -242,7 +242,7 @@ ls modules/Themes/resources/themes/
php -d memory_limit=2048M artisan test --compact modules/Themes/tests/
# E2E
-npx playwright test --project="@Themes*"
+npx playwright test --project="@themes*"
```
Key test files:
diff --git a/LICENSE b/LICENSE
index f9a509b..cf78a69 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT License
-Copyright (c) 2025 Saucebase
+Copyright (c) 2026 Saucebase
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/Taskfile.yml b/Taskfile.yml
index 9df1742..d1d61d2 100644
--- a/Taskfile.yml
+++ b/Taskfile.yml
@@ -9,11 +9,17 @@ tasks:
test:e2e:
desc: Run E2E tests for Themes module
- cmd: npx playwright test --project="@Themes*" {{.CLI_ARGS}}
+ cmd: npx playwright test --project="@themes*" {{.CLI_ARGS}}
interactive: true
+ # ── Database ──────────────────────────────────────────────────
+
+ db:seed:
+ desc: Seed the Themes module database
+ cmd: php artisan modules:seed --module=themes
+
# ── Code Generation ────────────────────────────────────────────
types:generate:
desc: Generate TypeScript types from PHP DTOs and enums
- cmd: php artisan module:generate-types Themes
+ cmd: php artisan module:generate-types themes
diff --git a/app/Providers/RouteServiceProvider.php b/app/Providers/RouteServiceProvider.php
deleted file mode 100644
index 165cb09..0000000
--- a/app/Providers/RouteServiceProvider.php
+++ /dev/null
@@ -1,15 +0,0 @@
-group(module_path('Themes', '/routes/web.php'));
- }
-}
diff --git a/composer.json b/composer.json
index 2ce03c1..108ebd8 100644
--- a/composer.json
+++ b/composer.json
@@ -1,7 +1,9 @@
{
"name": "saucebase/themes",
- "description": "",
+ "description": "Themes module",
"type": "saucebase-module",
+ "license": "proprietary",
+ "version": "1.2.2",
"authors": [
{
"name": "Saucebase",
@@ -10,20 +12,24 @@
],
"extra": {
"laravel": {
- "providers": [],
+ "providers": [
+ "Modules\\Themes\\Providers\\ThemesServiceProvider"
+ ],
"aliases": {}
}
},
"autoload": {
"psr-4": {
- "Modules\\Themes\\": "app/",
+ "Modules\\Themes\\": "src/",
"Modules\\Themes\\Database\\Factories\\": "database/factories/",
- "Modules\\Themes\\Database\\Seeders\\": "database/seeders/"
+ "Modules\\Themes\\Database\\Seeders\\": "database/seeders/",
+ "Modules\\Themes\\Tests\\Support\\": "tests/Support/"
}
},
"autoload-dev": {
"psr-4": {
"Modules\\Themes\\Tests\\": "tests/"
}
- }
+ },
+ "minimum-stability": "stable"
}
diff --git a/module.json b/module.json
deleted file mode 100644
index 938ea17..0000000
--- a/module.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
- "name": "Themes",
- "alias": "themes",
- "description": "Themes module",
- "author": "Saucebase",
- "version": "v1.2.2",
- "keywords": [
- "themes"
- ],
- "priority": 0,
- "providers": [
- "Modules\\Themes\\Providers\\ThemesServiceProvider"
- ],
- "files": []
-}
diff --git a/resources/js/app.ts b/resources/js/app.ts
index 13179b5..3043f15 100644
--- a/resources/js/app.ts
+++ b/resources/js/app.ts
@@ -1,9 +1 @@
-import { registerGlobalComponent } from '@/lib/globalComponents';
-import '../css/app.css';
-import ThemePanel from './components/ThemePanel.vue';
-
-export function setup() {
- registerGlobalComponent('top', ThemePanel);
-}
-
-export function afterMount() {}
+export * from './vue/app';
diff --git a/resources/js/vue/app.ts b/resources/js/vue/app.ts
new file mode 100644
index 0000000..4d2ca36
--- /dev/null
+++ b/resources/js/vue/app.ts
@@ -0,0 +1,9 @@
+import { registerGlobalComponent } from '@/lib/globalComponents';
+import '@modules/themes/resources/css/app.css';
+import ThemePanel from './components/ThemePanel.vue';
+
+export function setup() {
+ registerGlobalComponent('top', ThemePanel);
+}
+
+export function afterMount() {}
diff --git a/resources/js/components/ColorInput.vue b/resources/js/vue/components/ColorInput.vue
similarity index 100%
rename from resources/js/components/ColorInput.vue
rename to resources/js/vue/components/ColorInput.vue
diff --git a/resources/js/components/ColorPickerPopover.vue b/resources/js/vue/components/ColorPickerPopover.vue
similarity index 100%
rename from resources/js/components/ColorPickerPopover.vue
rename to resources/js/vue/components/ColorPickerPopover.vue
diff --git a/resources/js/components/DialogCommand.vue b/resources/js/vue/components/DialogCommand.vue
similarity index 100%
rename from resources/js/components/DialogCommand.vue
rename to resources/js/vue/components/DialogCommand.vue
diff --git a/resources/js/components/DialogSave.vue b/resources/js/vue/components/DialogSave.vue
similarity index 100%
rename from resources/js/components/DialogSave.vue
rename to resources/js/vue/components/DialogSave.vue
diff --git a/resources/js/components/FontPicker.vue b/resources/js/vue/components/FontPicker.vue
similarity index 100%
rename from resources/js/components/FontPicker.vue
rename to resources/js/vue/components/FontPicker.vue
diff --git a/resources/js/components/LinkToggle.vue b/resources/js/vue/components/LinkToggle.vue
similarity index 100%
rename from resources/js/components/LinkToggle.vue
rename to resources/js/vue/components/LinkToggle.vue
diff --git a/resources/js/components/SearchInput.vue b/resources/js/vue/components/SearchInput.vue
similarity index 100%
rename from resources/js/components/SearchInput.vue
rename to resources/js/vue/components/SearchInput.vue
diff --git a/resources/js/components/SliderInput.vue b/resources/js/vue/components/SliderInput.vue
similarity index 100%
rename from resources/js/components/SliderInput.vue
rename to resources/js/vue/components/SliderInput.vue
diff --git a/resources/js/components/TailwindColorPicker.vue b/resources/js/vue/components/TailwindColorPicker.vue
similarity index 100%
rename from resources/js/components/TailwindColorPicker.vue
rename to resources/js/vue/components/TailwindColorPicker.vue
diff --git a/resources/js/components/ThemeColorSwatch.vue b/resources/js/vue/components/ThemeColorSwatch.vue
similarity index 100%
rename from resources/js/components/ThemeColorSwatch.vue
rename to resources/js/vue/components/ThemeColorSwatch.vue
diff --git a/resources/js/components/ThemePanel.vue b/resources/js/vue/components/ThemePanel.vue
similarity index 97%
rename from resources/js/components/ThemePanel.vue
rename to resources/js/vue/components/ThemePanel.vue
index 377160d..dd6b046 100644
--- a/resources/js/components/ThemePanel.vue
+++ b/resources/js/vue/components/ThemePanel.vue
@@ -37,7 +37,7 @@ import type { FieldState, Font, Theme } from '../types';
import { useDialog } from '@/composables/useDialog';
import { useHttp, usePage } from '@inertiajs/vue3';
-import { useDark } from '@vueuse/core';
+import { useColorMode } from '@vueuse/core';
import { trans } from 'laravel-vue-i18n';
import { toast } from 'vue-sonner';
import ColorInput from './ColorInput.vue';
@@ -75,7 +75,8 @@ const http = useHttp({
dark: {} as Record