mirror of
https://github.com/unraid/api.git
synced 2026-01-01 06:01:18 -06:00
feat: lots of progress on colors
This commit is contained in:
74
web/components/ColorSwitcher.ce.vue
Normal file
74
web/components/ColorSwitcher.ce.vue
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
<script lang="ts" setup>
|
||||||
|
import Input from '~/components/shadcn/input/Input.vue';
|
||||||
|
import Label from '~/components/shadcn/label/Label.vue';
|
||||||
|
import { defaultColors, useThemeStore, type Theme } from '~/store/theme';
|
||||||
|
|
||||||
|
const themeStore = useThemeStore();
|
||||||
|
const { darkMode, theme } = toRefs(themeStore);
|
||||||
|
|
||||||
|
const setDarkMode = ref<boolean>(false);
|
||||||
|
|
||||||
|
const toggleSwitch= (value: boolean) => {
|
||||||
|
setDarkMode.value = value;
|
||||||
|
}
|
||||||
|
const textPrimary = ref<string>("");
|
||||||
|
const textSecondary = ref<string>("");
|
||||||
|
const bgColor = ref<string>("");
|
||||||
|
|
||||||
|
const textPrimaryToSet = computed(() => {
|
||||||
|
if (textPrimary.value) {
|
||||||
|
return textPrimary.value;
|
||||||
|
}
|
||||||
|
return darkMode.value ? defaultColors.dark.headerTextPrimary : defaultColors.light.headerTextPrimary;
|
||||||
|
})
|
||||||
|
|
||||||
|
const textSecondaryToSet = computed(() => {
|
||||||
|
if (textSecondary.value) {
|
||||||
|
return textSecondary.value;
|
||||||
|
}
|
||||||
|
return darkMode.value ? defaultColors.dark.headerTextSecondary : defaultColors.light.headerTextSecondary;
|
||||||
|
})
|
||||||
|
|
||||||
|
const bgColorToSet = computed(() => {
|
||||||
|
if (bgColor.value) {
|
||||||
|
return bgColor.value;
|
||||||
|
}
|
||||||
|
return darkMode.value ? defaultColors.dark.headerBackgroundColor : defaultColors.light.headerBackgroundColor;
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
watch([setDarkMode, bgColorToSet, textSecondaryToSet, textPrimaryToSet], (newVal) => {
|
||||||
|
console.log(newVal);
|
||||||
|
const themeToSet: Theme = {
|
||||||
|
banner: true,
|
||||||
|
bannerGradient: true,
|
||||||
|
descriptionShow: true,
|
||||||
|
textColor: textPrimaryToSet.value,
|
||||||
|
metaColor: textSecondaryToSet.value,
|
||||||
|
bgColor: bgColorToSet.value,
|
||||||
|
name: setDarkMode.value ? 'black' : 'light',
|
||||||
|
}
|
||||||
|
themeStore.setTheme(themeToSet);
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
|
||||||
|
<div class="flex flex-col gap-2 border-solid border-2 p-2 border-r-2">
|
||||||
|
<h1 class="text-lg">Color Theme Customization</h1>
|
||||||
|
<Label for="primary-text-color">Header Primary Text Color</label>
|
||||||
|
<Input id="primary-text-color" v-model="textPrimary" />
|
||||||
|
<Label for="primary-text-color">Header Secondary Text Color</label>
|
||||||
|
<Input id="primary-text-color" v-model="textSecondary" />
|
||||||
|
<Label for="primary-text-color">Header Background Color</label>
|
||||||
|
<Input id="primary-text-color" v-model="bgColor" />
|
||||||
|
<Label for="dark-mode">Dark Mode</Label>
|
||||||
|
<Switch id="dark-mode" @update:checked="toggleSwitch"/>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style lang="postcss">
|
||||||
|
@tailwind base;
|
||||||
|
@tailwind components;
|
||||||
|
@tailwind utilities;
|
||||||
|
</style>
|
||||||
@@ -16,7 +16,6 @@ import { useUpdateOsStore } from '~/store/updateOs';
|
|||||||
import { useUpdateOsActionsStore } from '~/store/updateOsActions';
|
import { useUpdateOsActionsStore } from '~/store/updateOsActions';
|
||||||
import type { UserProfileLink } from '~/types/userProfile';
|
import type { UserProfileLink } from '~/types/userProfile';
|
||||||
import type { UiBadgeProps, UiBadgePropsColor } from '~/types/ui/badge';
|
import type { UiBadgeProps, UiBadgePropsColor } from '~/types/ui/badge';
|
||||||
import { useThemeStore } from '~/store/theme';
|
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@@ -67,16 +66,6 @@ const updateOsStatus = computed(() => {
|
|||||||
|
|
||||||
return null;
|
return null;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
const themeStore = useThemeStore();
|
|
||||||
const { darkMode, theme } = toRefs(themeStore);
|
|
||||||
const toggleDarkMode = () => {
|
|
||||||
const themeNameToSet = darkMode.value ? 'light' : 'black';
|
|
||||||
if (theme.value) {
|
|
||||||
themeStore.setTheme({ ...theme.value, name: themeNameToSet });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -89,17 +78,13 @@ const toggleDarkMode = () => {
|
|||||||
<UiBadge
|
<UiBadge
|
||||||
color="custom"
|
color="custom"
|
||||||
:icon="InformationCircleIcon"
|
:icon="InformationCircleIcon"
|
||||||
icon-styles="text-gamma"
|
icon-styles="text-header-text-secondary"
|
||||||
size="14px"
|
size="14px"
|
||||||
class="text-gamma group-hover:text-orange-dark group-focus:text-orange-dark group-hover:underline group-focus:underline"
|
class="text-header-text-secondary group-hover:text-orange-dark group-focus:text-orange-dark group-hover:underline group-focus:underline"
|
||||||
>
|
>
|
||||||
{{ osVersion }}
|
{{ osVersion }}
|
||||||
</UiBadge>
|
</UiBadge>
|
||||||
</button>
|
</button>
|
||||||
<button @click="toggleDarkMode">
|
|
||||||
Toggle Dark / Light Theme - Current is: {{ darkMode ? 'Dark' : 'Light' }}
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<component
|
<component
|
||||||
:is="updateOsStatus.href ? 'a' : 'button'"
|
:is="updateOsStatus.href ? 'a' : 'button'"
|
||||||
v-if="updateOsStatus"
|
v-if="updateOsStatus"
|
||||||
|
|||||||
@@ -42,9 +42,6 @@ const closeModal = () => {
|
|||||||
|
|
||||||
const ariaLablledById = computed((): string|undefined => props.title ? `ModalTitle-${Math.random()}`.replace('0.', '') : undefined);
|
const ariaLablledById = computed((): string|undefined => props.title ? `ModalTitle-${Math.random()}`.replace('0.', '') : undefined);
|
||||||
|
|
||||||
/**
|
|
||||||
* @todo when providing custom colors for theme we should invert text-beta bg-alpha to text-alpha bg-beta
|
|
||||||
*/
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
|
|||||||
@@ -39,16 +39,24 @@ const icon = computed<{ component: Component; color: string } | null>(() => {
|
|||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
<div class="relative">
|
<div class="flex items-end gap-1 text-header-text-primary">
|
||||||
<BellIcon class="w-6 h-6" />
|
<div class="relative">
|
||||||
<div
|
<BellIcon class="w-6 h-6" />
|
||||||
v-if="indicatorLevel === 'UNREAD'"
|
<div
|
||||||
class="absolute top-0 right-0 size-2.5 rounded-full border border-neutral-800 bg-unraid-green"
|
v-if="indicatorLevel"
|
||||||
/>
|
:class="
|
||||||
<component
|
cn('absolute top-0 right-0 size-2.5 rounded-full border border-neutral-800', {
|
||||||
:is="icon.component"
|
'bg-unraid-red': indicatorLevel === Importance.Alert,
|
||||||
v-else-if="icon && indicatorLevel"
|
'bg-yellow-accent': indicatorLevel === Importance.Warning,
|
||||||
:class="cn('absolute -top-1 -right-1 size-4 rounded-full', icon.color)"
|
'bg-unraid-green': indicatorLevel === 'UNREAD',
|
||||||
/>
|
})
|
||||||
|
"
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
v-if="hasNewNotifications || indicatorLevel === Importance.Alert"
|
||||||
|
class="absolute top-0 right-0 size-2.5 rounded-full bg-unraid-red animate-ping"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
|
<component :is="icon.component" v-if="icon" :class="cn('size-6', icon.color)" />
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|||||||
@@ -97,21 +97,21 @@ onBeforeMount(() => {
|
|||||||
<template>
|
<template>
|
||||||
<div
|
<div
|
||||||
id="UserProfile"
|
id="UserProfile"
|
||||||
class="text-alpha relative z-20 flex flex-col h-full gap-y-4px pt-4px pr-16px pl-40px"
|
class="text-primary relative z-20 flex flex-col h-full gap-y-4px pt-4px pr-16px pl-40px"
|
||||||
>
|
>
|
||||||
<div v-if="bannerGradient" class="absolute z-0 w-[125%] top-0 bottom-0 right-0" :style="bannerGradient" />
|
<div v-if="bannerGradient" class="absolute z-0 w-[125%] top-0 bottom-0 right-0" :style="bannerGradient" />
|
||||||
|
|
||||||
<div class="text-xs text-gamma text-right font-semibold leading-normal relative z-10 flex flex-col items-end justify-end gap-x-4px xs:flex-row xs:items-baseline xs:gap-x-12px">
|
<div class="text-xs text-header-text-secondary text-right font-semibold leading-normal relative z-10 flex flex-col items-end justify-end gap-x-4px xs:flex-row xs:items-baseline xs:gap-x-12px">
|
||||||
<UpcUptimeExpire :t="t" />
|
<UpcUptimeExpire :t="t" />
|
||||||
<span class="hidden xs:block">•</span>
|
<span class="hidden xs:block">•</span>
|
||||||
<UpcServerState :t="t" />
|
<UpcServerState :t="t" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="relative z-10 flex flex-row items-center justify-end gap-x-16px h-full">
|
<div class="relative z-10 flex flex-row items-center justify-end gap-x-16px h-full">
|
||||||
<h1 class="text-14px sm:text-18px relative flex flex-col-reverse items-end md:flex-row border-0">
|
<h1 class="text-14px sm:text-18px relative flex flex-col-reverse items-end md:flex-row border-0 text-header-text-primary">
|
||||||
<template v-if="description && theme?.descriptionShow">
|
<template v-if="description && theme?.descriptionShow">
|
||||||
<span class="text-right text-12px sm:text-18px hidden 2xs:block" v-html="description" />
|
<span class="text-right text-12px sm:text-18px hidden 2xs:block" v-html="description" />
|
||||||
<span class="text-gamma hidden md:inline-block px-8px">•</span>
|
<span class="text-header-text-secondary hidden md:inline-block px-8px">•</span>
|
||||||
</template>
|
</template>
|
||||||
<button :title="t('Click to Copy LAN IP {0}', [lanIp])" class="opacity-100 hover:opacity-75 focus:opacity-75 transition-opacity" @click="copyLanIp()">
|
<button :title="t('Click to Copy LAN IP {0}', [lanIp])" class="opacity-100 hover:opacity-75 focus:opacity-75 transition-opacity" @click="copyLanIp()">
|
||||||
{{ name }}
|
{{ name }}
|
||||||
@@ -155,7 +155,7 @@ onBeforeMount(() => {
|
|||||||
top: -10px;
|
top: -10px;
|
||||||
right: 42px;
|
right: 42px;
|
||||||
border-right: 11px solid transparent;
|
border-right: 11px solid transparent;
|
||||||
border-bottom: 11px solid var(--color-alpha);
|
border-bottom: 11px solid var(--color-headerTextPrimary);
|
||||||
border-left: 11px solid transparent;
|
border-left: 11px solid transparent;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ const title = computed((): string => {
|
|||||||
|
|
||||||
<template>
|
<template>
|
||||||
<button
|
<button
|
||||||
class="group text-18px border-0 relative flex flex-row justify-end items-center h-full gap-x-8px opacity-100 hover:opacity-75 focus:opacity-75 transition-opacity"
|
class="group text-18px border-0 relative flex flex-row justify-end items-center h-full gap-x-8px opacity-100 hover:opacity-75 focus:opacity-75 transition-opacity text-header-text-primary"
|
||||||
:title="title"
|
:title="title"
|
||||||
@click="dropdownStore.dropdownToggle()"
|
@click="dropdownStore.dropdownToggle()"
|
||||||
>
|
>
|
||||||
@@ -49,7 +49,7 @@ const title = computed((): string => {
|
|||||||
<ExclamationTriangleIcon v-if="errors[0].level === 'warning'" class="text-unraid-red fill-current relative w-24px h-24px" />
|
<ExclamationTriangleIcon v-if="errors[0].level === 'warning'" class="text-unraid-red fill-current relative w-24px h-24px" />
|
||||||
<ShieldExclamationIcon v-if="errors[0].level === 'error'" class="text-unraid-red fill-current relative w-24px h-24px" />
|
<ShieldExclamationIcon v-if="errors[0].level === 'error'" class="text-unraid-red fill-current relative w-24px h-24px" />
|
||||||
</template>
|
</template>
|
||||||
<span v-if="text" class="relative leading-none">
|
<span v-if="text" class="relative leading-none ">
|
||||||
<span>{{ text }}</span>
|
<span>{{ text }}</span>
|
||||||
<span class="absolute bottom-[-3px] inset-x-0 h-2px w-full bg-gradient-to-r from-unraid-red to-orange rounded opacity-0 group-hover:opacity-100 group-focus:opacity-100 transition-opacity" />
|
<span class="absolute bottom-[-3px] inset-x-0 h-2px w-full bg-gradient-to-r from-unraid-red to-orange rounded opacity-0 group-hover:opacity-100 group-focus:opacity-100 transition-opacity" />
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ export { default as SheetDescription } from './SheetDescription.vue'
|
|||||||
export { default as SheetFooter } from './SheetFooter.vue'
|
export { default as SheetFooter } from './SheetFooter.vue'
|
||||||
|
|
||||||
export const sheetVariants = cva(
|
export const sheetVariants = cva(
|
||||||
'fixed z-50 gap-4 bg-beta shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
|
'fixed z-50 gap-4 bg-alpha shadow-lg transition ease-in-out data-[state=open]:animate-in data-[state=closed]:animate-out data-[state=closed]:duration-300 data-[state=open]:duration-500',
|
||||||
{
|
{
|
||||||
variants: {
|
variants: {
|
||||||
side: {
|
side: {
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
"lint:fix": "eslint . --fix",
|
"lint:fix": "eslint . --fix",
|
||||||
"type-check": "nuxi typecheck",
|
"type-check": "nuxi typecheck",
|
||||||
"prebuild:dev": "./scripts/prebuild-webgui-set-env.sh .env.staging",
|
"prebuild:dev": "./scripts/prebuild-webgui-set-env.sh .env.staging",
|
||||||
"build:dev": "npm run type-check && nuxt build && npm run manifest-ts && npm run deploy-to-unraid:dev",
|
"build:dev": "nuxt build && npm run manifest-ts && npm run deploy-to-unraid:dev",
|
||||||
"postbuild:dev": "./scripts/postbuild-webgui-restore-env.sh",
|
"postbuild:dev": "./scripts/postbuild-webgui-restore-env.sh",
|
||||||
"prebuild:webgui": "./scripts/prebuild-webgui-set-env.sh",
|
"prebuild:webgui": "./scripts/prebuild-webgui-set-env.sh",
|
||||||
"build:webgui": "npm run type-check && nuxt build && npm run manifest-ts && npm run copy-to-webgui-repo",
|
"build:webgui": "npm run type-check && nuxt build && npm run manifest-ts && npm run copy-to-webgui-repo",
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
<script lang="ts" setup>
|
<script lang="ts" setup>
|
||||||
import { serverState } from '~/_data/serverState';
|
import { serverState } from '~/_data/serverState';
|
||||||
import type { SendPayloads } from '~/store/callback';
|
import type { SendPayloads } from '~/store/callback';
|
||||||
import { useThemeStore, type Theme } from '~/store/theme';
|
|
||||||
import AES from 'crypto-js/aes';
|
import AES from 'crypto-js/aes';
|
||||||
|
|
||||||
const { registerEntry } = useCustomElements();
|
const { registerEntry } = useCustomElements();
|
||||||
@@ -49,16 +48,7 @@ onMounted(() => {
|
|||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|
||||||
const isDarkMode = ref(false);
|
|
||||||
|
|
||||||
const themeStore = useThemeStore();
|
|
||||||
const { darkMode, theme } = toRefs(themeStore);
|
|
||||||
const toggleDarkMode = () => {
|
|
||||||
const themeNameToSet = darkMode.value ? 'light' : 'black';
|
|
||||||
if (theme.value) {
|
|
||||||
themeStore.setTheme({ ...theme.value, name: themeNameToSet });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<template>
|
<template>
|
||||||
@@ -66,12 +56,10 @@ const toggleDarkMode = () => {
|
|||||||
<div class="pb-12 mx-auto">
|
<div class="pb-12 mx-auto">
|
||||||
<client-only>
|
<client-only>
|
||||||
<div class="flex flex-col gap-6 p-6">
|
<div class="flex flex-col gap-6 p-6">
|
||||||
<button @click="toggleDarkMode">
|
<ColorSwitcherCe />
|
||||||
Toggle Dark / Light Theme - Current is: {{ darkMode ? 'Dark' : 'Light' }}
|
|
||||||
</button>
|
|
||||||
<h2 class="text-xl font-semibold font-mono">Vue Components</h2>
|
<h2 class="text-xl font-semibold font-mono">Vue Components</h2>
|
||||||
<h3 class="text-lg font-semibold font-mono">UserProfileCe</h3>
|
<h3 class="text-lg font-semibold font-mono">UserProfileCe</h3>
|
||||||
<header class="bg-gray py-4 flex flex-row justify-between items-center">
|
<header class="bg-header-background-color py-4 flex flex-row justify-between items-center">
|
||||||
<div class="inline-flex flex-col gap-4 items-start px-4">
|
<div class="inline-flex flex-col gap-4 items-start px-4">
|
||||||
<a href="https://unraid.net" target="_blank">
|
<a href="https://unraid.net" target="_blank">
|
||||||
<BrandLogo class="w-[100px] sm:w-[150px]" />
|
<BrandLogo class="w-[100px] sm:w-[150px]" />
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import { defineStore, createPinia, setActivePinia } from 'pinia';
|
|
||||||
import hexToRgba from 'hex-to-rgba';
|
import hexToRgba from 'hex-to-rgba';
|
||||||
|
import { createPinia, defineStore, setActivePinia } from 'pinia';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
* @see https://stackoverflow.com/questions/73476371/using-pinia-with-vue-js-web-components
|
||||||
@@ -17,14 +17,46 @@ export interface Theme {
|
|||||||
textColor: string;
|
textColor: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface ColorMode {
|
||||||
|
headerTextPrimary: string;
|
||||||
|
headerTextSecondary: string;
|
||||||
|
headerBackgroundColor: string;
|
||||||
|
alpha: string;
|
||||||
|
beta: string;
|
||||||
|
gamma: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export const defaultColors: Record<string, ColorMode> = {
|
||||||
|
dark: {
|
||||||
|
alpha: '#1c1c1c', // previously header custom text color
|
||||||
|
beta: '#f2f2f2', // previously header background color
|
||||||
|
gamma: '#999999', // previously header custom secondary text color
|
||||||
|
headerTextPrimary: '#1c1c1c',
|
||||||
|
headerBackgroundColor: '#f2f2f2',
|
||||||
|
headerTextSecondary: '#999999',
|
||||||
|
},
|
||||||
|
light: {
|
||||||
|
alpha: '#f2f2f2', // previously header custom text color
|
||||||
|
beta: '#1c1b1b', // previously header background color
|
||||||
|
gamma: '#999999', // previously header custom secondary text color
|
||||||
|
headerTextPrimary: '#f2f2f2',
|
||||||
|
headerBackgroundColor: '#1c1b1b',
|
||||||
|
headerTextSecondary: '#999999',
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
export const useThemeStore = defineStore('theme', () => {
|
export const useThemeStore = defineStore('theme', () => {
|
||||||
// State
|
// State
|
||||||
const theme = ref<Theme | undefined>();
|
const theme = ref<Theme | undefined>();
|
||||||
// Getters
|
// Getters
|
||||||
const darkMode = computed(() => (theme.value?.name === 'black' || theme.value?.name === 'azure') ?? false);
|
const darkMode = computed(
|
||||||
|
() => (theme.value?.name === 'black' || theme.value?.name === 'azure') ?? false
|
||||||
|
);
|
||||||
// used to swap the UPC text color when using the azure or gray theme
|
// used to swap the UPC text color when using the azure or gray theme
|
||||||
const bannerGradient = computed(() => {
|
const bannerGradient = computed(() => {
|
||||||
if (!theme.value?.banner || !theme.value?.bannerGradient) { return undefined; }
|
if (!theme.value?.banner || !theme.value?.bannerGradient) {
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
const start = theme.value?.bgColor ? 'var(--color-customgradient-start)' : 'rgba(0, 0, 0, 0)';
|
const start = theme.value?.bgColor ? 'var(--color-customgradient-start)' : 'rgba(0, 0, 0, 0)';
|
||||||
const end = theme.value?.bgColor ? 'var(--color-customgradient-end)' : 'var(--color-beta)';
|
const end = theme.value?.bgColor ? 'var(--color-customgradient-end)' : 'var(--color-beta)';
|
||||||
return `background-image: linear-gradient(90deg, ${start} 0, ${end} 30%);`;
|
return `background-image: linear-gradient(90deg, ${start} 0, ${end} 30%);`;
|
||||||
@@ -35,39 +67,44 @@ export const useThemeStore = defineStore('theme', () => {
|
|||||||
};
|
};
|
||||||
const setCssVars = () => {
|
const setCssVars = () => {
|
||||||
const body = document.body;
|
const body = document.body;
|
||||||
const defaultColors = {
|
|
||||||
darkTheme: {
|
let { alpha, beta, gamma, headerTextPrimary, headerTextSecondary, headerBackgroundColor } =
|
||||||
alpha: '#1c1b1b',
|
darkMode.value ? defaultColors.dark : defaultColors.light;
|
||||||
beta: '#f2f2f2',
|
|
||||||
gamma: '#999999',
|
|
||||||
},
|
|
||||||
lightTheme: {
|
|
||||||
alpha: '#f2f2f2',
|
|
||||||
beta: '#1c1b1b',
|
|
||||||
gamma: '#999999',
|
|
||||||
},
|
|
||||||
};
|
|
||||||
let { alpha, beta, gamma } = darkMode.value ? defaultColors.darkTheme : defaultColors.lightTheme;
|
|
||||||
// overwrite with hex colors set in webGUI @ /Settings/DisplaySettings
|
// overwrite with hex colors set in webGUI @ /Settings/DisplaySettings
|
||||||
if (theme.value?.textColor) { alpha = theme.value?.textColor; }
|
if (theme.value?.textColor) {
|
||||||
|
headerTextPrimary = theme.value?.textColor;
|
||||||
|
}
|
||||||
if (theme.value?.bgColor) {
|
if (theme.value?.bgColor) {
|
||||||
beta = theme.value?.bgColor;
|
headerBackgroundColor = theme.value.bgColor;
|
||||||
body.style.setProperty('--color-customgradient-start', hexToRgba(beta, 0));
|
body.style.setProperty('--color-customgradient-start', hexToRgba(beta, 0));
|
||||||
body.style.setProperty('--color-customgradient-end', hexToRgba(beta, 0.7));
|
body.style.setProperty('--color-customgradient-end', hexToRgba(beta, 0.7));
|
||||||
}
|
}
|
||||||
if (theme.value?.metaColor) { gamma = theme.value?.metaColor; }
|
if (theme.value?.metaColor) {
|
||||||
|
headerTextSecondary = theme.value?.metaColor;
|
||||||
|
}
|
||||||
body.style.setProperty('--color-alpha', alpha);
|
body.style.setProperty('--color-alpha', alpha);
|
||||||
body.style.setProperty('--color-beta', beta);
|
body.style.setProperty('--color-beta', beta);
|
||||||
body.style.setProperty('--color-gamma', gamma);
|
body.style.setProperty('--color-gamma', gamma);
|
||||||
|
body.style.setProperty('--header-text-primary', headerTextPrimary);
|
||||||
|
body.style.setProperty('--header-text-secondary', headerTextSecondary);
|
||||||
|
body.style.setProperty('--header-background-color', headerBackgroundColor);
|
||||||
body.style.setProperty('--color-gamma-opaque', hexToRgba(gamma, 0.25));
|
body.style.setProperty('--color-gamma-opaque', hexToRgba(gamma, 0.25));
|
||||||
// box shadow
|
// box shadow
|
||||||
body.style.setProperty('--shadow-beta', `0 25px 50px -12px ${hexToRgba(beta, 0.15)}`);
|
body.style.setProperty('--shadow-beta', `0 25px 50px -12px ${hexToRgba(beta, 0.15)}`);
|
||||||
body.style.setProperty('--ring-offset-shadow', `0 0 ${beta}`);
|
body.style.setProperty('--ring-offset-shadow', `0 0 ${beta}`);
|
||||||
body.style.setProperty('--ring-shadow', `0 0 ${beta}`);
|
body.style.setProperty('--ring-shadow', `0 0 ${beta}`);
|
||||||
body.style.setProperty('--dev-test', `0 0 ${beta}`);
|
body.style.setProperty('--dev-test', `0 0 ${beta}`);
|
||||||
|
|
||||||
|
if (darkMode.value) {
|
||||||
|
document.body.classList.add('dark');
|
||||||
|
} else {
|
||||||
|
document.body.classList.remove('dark');
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
watch(theme, () => {
|
watch(theme, () => {
|
||||||
|
console.log(theme.value);
|
||||||
|
console.log('theme changed');
|
||||||
setCssVars();
|
setCssVars();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -69,7 +69,7 @@ export const useUpdateOsStore = defineStore('updateOs', () => {
|
|||||||
serverStore.setUpdateOsResponse(response as ServerUpdateOsResponse);
|
serverStore.setUpdateOsResponse(response as ServerUpdateOsResponse);
|
||||||
checkForUpdatesLoading.value = false;
|
checkForUpdatesLoading.value = false;
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
throw new Error('[localCheckForUpdate] Error checking for updates');
|
throw new Error("[localCheckForUpdate] Error checking for updates\n" + JSON.stringify(error));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dotenv/config';
|
|||||||
import type { Config } from 'tailwindcss';
|
import type { Config } from 'tailwindcss';
|
||||||
import type { PluginAPI } from 'tailwindcss/types/config';
|
import type { PluginAPI } from 'tailwindcss/types/config';
|
||||||
|
|
||||||
|
|
||||||
// @ts-expect-error - just trying to get this to build @fixme
|
// @ts-expect-error - just trying to get this to build @fixme
|
||||||
export default <Partial<Config>>{
|
export default <Partial<Config>>{
|
||||||
darkMode: ['selector'],
|
darkMode: ['selector'],
|
||||||
@@ -44,11 +45,6 @@ export default <Partial<Config>>{
|
|||||||
'grey-lightest': '#f2f2f2',
|
'grey-lightest': '#f2f2f2',
|
||||||
white: '#ffffff',
|
white: '#ffffff',
|
||||||
|
|
||||||
|
|
||||||
// New Color Palette
|
|
||||||
'sidebar': '#f2f2f2',
|
|
||||||
'sidebar-dark': '#1c1b1b',
|
|
||||||
|
|
||||||
// unraid colors
|
// unraid colors
|
||||||
'yellow-accent': '#E9BF41',
|
'yellow-accent': '#E9BF41',
|
||||||
'orange-dark': '#f15a2c',
|
'orange-dark': '#f15a2c',
|
||||||
@@ -88,40 +84,42 @@ export default <Partial<Config>>{
|
|||||||
beta: 'var(--color-beta)',
|
beta: 'var(--color-beta)',
|
||||||
gamma: 'var(--color-gamma)',
|
gamma: 'var(--color-gamma)',
|
||||||
'gamma-opaque': 'var(--color-gamma-opaque)',
|
'gamma-opaque': 'var(--color-gamma-opaque)',
|
||||||
|
'header-text-primary': 'var(--header-text-primary)',
|
||||||
// shadcn specific
|
'header-text-secondary': 'var(--header-text-secondary)',
|
||||||
border: 'hsl(0 0% 89.8%)',
|
'header-background-color': 'var(--header-background-color)',
|
||||||
input: 'hsl(0 0% 89.8%)',
|
// ShadCN
|
||||||
ring: 'hsl(0 0% 3.9%)',
|
border: 'hsl(var(--border))',
|
||||||
background: 'hsl(0 0% 100%)',
|
input: 'hsl(var(--input))',
|
||||||
foreground: 'hsl(0 0% 3.9%)',
|
ring: 'hsl(var(--ring))',
|
||||||
|
background: 'hsl(var(--background))',
|
||||||
|
foreground: 'hsl(var(--foreground))',
|
||||||
primary: {
|
primary: {
|
||||||
DEFAULT: 'hsl(0 0% 9%)',
|
DEFAULT: 'hsl(var(--primary))',
|
||||||
foreground: 'hsl(0 0% 98%)',
|
foreground: 'hsl(var(--primary-foreground))',
|
||||||
},
|
},
|
||||||
secondary: {
|
secondary: {
|
||||||
DEFAULT: 'hsl(0 0% 96.1%)',
|
DEFAULT: 'hsl(var(--secondary))',
|
||||||
foreground: 'hsl(0 0% 9%)',
|
foreground: 'hsl(var(--secondary-foreground))',
|
||||||
},
|
},
|
||||||
destructive: {
|
destructive: {
|
||||||
DEFAULT: 'hsl(0 84.2% 60.2%)',
|
DEFAULT: 'hsl(var(--destructive))',
|
||||||
foreground: 'hsl(0 0% 98%)',
|
foreground: 'hsl(var(--destructive-foreground))',
|
||||||
},
|
},
|
||||||
muted: {
|
muted: {
|
||||||
DEFAULT: 'hsl(0 0% 96.1%)',
|
DEFAULT: 'hsl(var(--muted))',
|
||||||
foreground: 'hsl(0 0% 45.1%)',
|
foreground: 'hsl(var(--muted-foreground))',
|
||||||
},
|
},
|
||||||
accent: {
|
accent: {
|
||||||
DEFAULT: 'hsl(0 0% 96.1%)',
|
DEFAULT: 'hsl(var(--accent))',
|
||||||
foreground: 'hsl(0 0% 9%)',
|
foreground: 'hsl(var(--accent-foreground))',
|
||||||
},
|
},
|
||||||
popover: {
|
popover: {
|
||||||
DEFAULT: 'hsl(0 0% 100%)',
|
DEFAULT: 'hsl(var(--popover))',
|
||||||
foreground: 'hsl(0 0% 3.9%)',
|
foreground: 'hsl(var(--popover-foreground))',
|
||||||
},
|
},
|
||||||
card: {
|
card: {
|
||||||
DEFAULT: 'hsl(0 0% 100%)',
|
DEFAULT: 'hsl(var(--card))',
|
||||||
foreground: 'hsl(0 0% 3.9%)',
|
foreground: 'hsl(var(--card-foreground))',
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
// Unfortunately due to webGUI CSS setting base HTML font-size to .65% or something we must use pixel values for web components
|
// Unfortunately due to webGUI CSS setting base HTML font-size to .65% or something we must use pixel values for web components
|
||||||
@@ -319,4 +317,4 @@ export default <Partial<Config>>{
|
|||||||
newFontSize: process.env.VITE_TAILWIND_BASE_FONT_SIZE ?? 10,
|
newFontSize: process.env.VITE_TAILWIND_BASE_FONT_SIZE ?? 10,
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
Reference in New Issue
Block a user