Skip to content

Theme preset selector #40

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
May 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 11 additions & 5 deletions src/app.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,6 @@ import './assets/css/app.css';
import './assets/css/tailwind.css';
import 'nprogress/nprogress.css';

import { useColorMode } from '@vueuse/core';
import customThemePreset from './theme/noir-preset';

import { createApp } from 'vue';
import { createPinia } from 'pinia';

Expand All @@ -17,16 +14,25 @@ import ToastService from 'primevue/toastservice';
import Container from '@/components/Container.vue';
import PageTitleSection from '@/components/PageTitleSection.vue';

import { useColorMode } from '@vueuse/core';
import { useThemePreset } from '@/composables/useThemePreset';

// Site light/dark mode
const colorMode = useColorMode({ emitAuto: true });

// Site theme preset
const { getCurrentPreset } = useThemePreset();
const themePreset = getCurrentPreset();

const app = createApp(App);
const pinia = createPinia();
const colorMode = useColorMode({ emitAuto: true });

app.provide('colorMode', colorMode)
.use(pinia)
.use(router)
.use(PrimeVue, {
theme: {
preset: customThemePreset,
preset: themePreset,
options: {
darkModeSelector: '.dark',
cssLayer: {
Expand Down
15 changes: 15 additions & 0 deletions src/components/ThemePresetSelector.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<script setup>
import { useThemePreset } from '@/composables/useThemePreset';

const { presets, selectedPreset, setPreset } = useThemePreset();
</script>

<template>
<Select
v-model="selectedPreset"
:options="presets"
optionLabel="label"
optionValue="value"
@change="setPreset(selectedPreset)"
/>
</template>
50 changes: 50 additions & 0 deletions src/composables/useThemePreset.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
import { ref, Ref } from 'vue';
import { usePreset } from '@primeuix/themes';
import { Preset } from '@primeuix/themes/types';
import { useStorage } from '@vueuse/core';
import bootstrap from '@/theme/bootstrap-preset';
import breeze from '@/theme/breeze-preset';
import enterprise from '@/theme/enterprise-preset';
import noir from '@/theme/noir-preset';
import warm from '@/theme/warm-preset';

interface ThemePreset {
label: string,
value: string,
preset: Preset,
}

const presets = ref<ThemePreset[]>([
{ label: 'Bootstrap', value: 'bootstrap', preset: bootstrap },
{ label: 'Breeze', value: 'breeze', preset: breeze },
{ label: 'Enterprise', value: 'enterprise', preset: enterprise },
{ label: 'Noir', value: 'noir', preset: noir },
{ label: 'Warm', value: 'warm', preset: warm },
]);

const selectedPreset: Ref<string> = useStorage('theme-preset', 'noir');

function getCurrentPreset(): Preset {
return (
presets.value.find((p) => p.value === selectedPreset.value)?.preset ||
presets.value[3].preset
);
}

function setPreset(presetValue: string): void {
const themePreset = presets.value.find((p) => p.value === presetValue);
if (themePreset) {
usePreset(themePreset.preset);
}
}

setPreset(selectedPreset.value);

export function useThemePreset() {
return {
presets,
selectedPreset,
getCurrentPreset,
setPreset,
};
}
2 changes: 1 addition & 1 deletion src/layouts/app/HeaderLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ const toggleMobileUserMenu = (event) => {
<div>
<PanelMenu
:model="menuItems"
class="w-full"
class="mt-1 w-full"
/>
</div>
<template #footer>
Expand Down
4 changes: 2 additions & 2 deletions src/layouts/app/SidebarLayout.vue
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ const toggleMobileUserMenu = (event) => {
<div>
<PanelMenu
:model="menuItems"
class="w-full"
class="mt-1 w-full"
/>
</div>
<template #footer>
Expand Down Expand Up @@ -117,7 +117,7 @@ const toggleMobileUserMenu = (event) => {
<div>
<PanelMenu
:model="menuItems"
class="w-full"
class="mt-1 w-full"
/>
</div>
</div>
Expand Down
12 changes: 11 additions & 1 deletion src/views/settings/Appearance.vue
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
import AppLayout from '@/layouts/AppLayout.vue';
import SettingsLayout from '@/layouts/UserSettingsLayout.vue';
import SelectColorModeButton from '@/components/SelectColorModeButton.vue';
import ThemePresetSelector from '@/components/ThemePresetSelector.vue';
</script>

<template>
Expand All @@ -18,7 +19,16 @@ import SelectColorModeButton from '@/components/SelectColorModeButton.vue';
Update your account's appearance settings
</template>
<template #content>
<SelectColorModeButton />
<div class="space-y-6">
<div class="flex flex-col gap-2">
<label for="color-mode-selector">Color Mode</label>
<SelectColorModeButton id="color-mode-selector" />
</div>
<div class="flex flex-col gap-2">
<label for="theme-preset-selector">Theme</label>
<ThemePresetSelector id="theme-preset-selector" />
</div>
</div>
</template>
</Card>
</SettingsLayout>
Expand Down