feat(story-1.5): theme selection and persistence
- SpaController: injects data-theme on <html> and window.__PF_USER__ before JS
hydrates — theme applied without FOUC; no initial API call needed for user data
- UserApiController: PATCH /api/user/theme validates against 6 allowed theme IDs,
persists to user.theme column, returns {theme}
- useTheme composable: applyTheme() sets html[data-theme], saveTheme() calls API
and falls back with toast on error
- SettingsView: 3-col theme grid with swatch previews, aria-checked radio semantics,
active indicator; Sign out link; signed-in email display
- App.vue: onMounted syncs Pinia theme state with SpaController-stamped html[data-theme]
Verified: data-theme injected on / load; PATCH saves to DB; reload shows persisted theme
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -5,6 +5,22 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted } from 'vue'
|
||||
import BottomNav from '@/components/BottomNav.vue'
|
||||
import BaseToast from '@/components/BaseToast.vue'
|
||||
import { useAuthStore } from '@/stores/auth'
|
||||
import { useTheme } from '@/composables/useTheme'
|
||||
|
||||
const auth = useAuthStore()
|
||||
const { applyTheme } = useTheme()
|
||||
|
||||
onMounted(() => {
|
||||
// Sync Vue's theme state with whatever SpaController stamped on <html>
|
||||
const stamped = document.documentElement.dataset.theme
|
||||
if (stamped && auth.user) {
|
||||
auth.user.theme = stamped
|
||||
} else if (auth.user?.theme) {
|
||||
applyTheme(auth.user.theme)
|
||||
}
|
||||
})
|
||||
</script>
|
||||
|
||||
Reference in New Issue
Block a user