mirror of
https://github.com/sysadminsmedia/homebox.git
synced 2025-12-25 06:49:18 +01:00
feat: move theme picker to its own component and improve contrast on login screen
This commit is contained in:
45
frontend/components/App/ThemePicker.vue
Normal file
45
frontend/components/App/ThemePicker.vue
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
<script setup lang="ts">
|
||||||
|
import { themes } from "~~/lib/data/themes";
|
||||||
|
import { useTheme } from "~/composables/use-theme";
|
||||||
|
|
||||||
|
const { setTheme } = useTheme();
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<template>
|
||||||
|
<div class="homebox grid grid-cols-1 gap-4 font-sans sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5">
|
||||||
|
<div
|
||||||
|
v-for="theme in themes"
|
||||||
|
:key="theme.value"
|
||||||
|
:class="'theme-' + theme.value"
|
||||||
|
class="overflow-hidden rounded-lg border outline-2 outline-offset-2"
|
||||||
|
:data-theme="theme.value"
|
||||||
|
:data-set-theme="theme.value"
|
||||||
|
data-act-class="outline"
|
||||||
|
@click="setTheme(theme.value)"
|
||||||
|
>
|
||||||
|
<div :data-theme="theme.value" class="w-full cursor-pointer bg-background-accent text-foreground">
|
||||||
|
<div class="grid grid-cols-5 grid-rows-3">
|
||||||
|
<div class="col-start-1 row-start-1 bg-background"></div>
|
||||||
|
<div class="col-start-1 row-start-2 bg-sidebar"></div>
|
||||||
|
<div class="col-start-1 row-start-3 bg-background-accent"></div>
|
||||||
|
<div class="col-span-4 col-start-2 row-span-3 row-start-1 flex flex-col gap-1 bg-background p-2">
|
||||||
|
<div class="font-bold">{{ theme.label }}</div>
|
||||||
|
<div class="flex flex-wrap gap-1">
|
||||||
|
<div class="flex size-5 items-center justify-center rounded bg-primary lg:size-6">
|
||||||
|
<div class="text-sm font-bold text-primary-foreground">A</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex size-5 items-center justify-center rounded bg-secondary lg:size-6">
|
||||||
|
<div class="text-sm font-bold text-secondary-foreground">A</div>
|
||||||
|
</div>
|
||||||
|
<div class="flex size-5 items-center justify-center rounded bg-accent lg:size-6">
|
||||||
|
<div class="text-sm font-bold text-accent-foreground">A</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<style scoped></style>
|
||||||
@@ -15,6 +15,7 @@
|
|||||||
import "@vuepic/vue-datepicker/dist/main.css";
|
import "@vuepic/vue-datepicker/dist/main.css";
|
||||||
import * as datelib from "~/lib/datelib/datelib";
|
import * as datelib from "~/lib/datelib/datelib";
|
||||||
import { Label } from "@/components/ui/label";
|
import { Label } from "@/components/ui/label";
|
||||||
|
import { darkThemes } from "~/lib/data/themes";
|
||||||
|
|
||||||
const emit = defineEmits(["update:modelValue", "update:text"]);
|
const emit = defineEmits(["update:modelValue", "update:text"]);
|
||||||
|
|
||||||
@@ -34,7 +35,7 @@
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
const isDark = useIsDark();
|
const isDark = useIsThemeInList(darkThemes);
|
||||||
|
|
||||||
const formatDate = (date: Date | string | number) => fmtDate(date, "human", "date");
|
const formatDate = (date: Date | string | number) => fmtDate(date, "human", "date");
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
import type { ComputedRef } from "vue";
|
import type { ComputedRef } from "vue";
|
||||||
import type { DaisyTheme } from "~~/lib/data/themes";
|
import { type DaisyTheme } from "~~/lib/data/themes";
|
||||||
|
|
||||||
export interface UseTheme {
|
export interface UseTheme {
|
||||||
theme: ComputedRef<DaisyTheme>;
|
theme: ComputedRef<DaisyTheme>;
|
||||||
@@ -42,27 +42,11 @@ export function useTheme(): UseTheme {
|
|||||||
return { theme, setTheme };
|
return { theme, setTheme };
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useIsDark() {
|
export function useIsThemeInList(list: DaisyTheme[]) {
|
||||||
const theme = useTheme();
|
const theme = useTheme();
|
||||||
|
|
||||||
const darkthemes = [
|
|
||||||
"synthwave",
|
|
||||||
"retro",
|
|
||||||
"cyberpunk",
|
|
||||||
"valentine",
|
|
||||||
"halloween",
|
|
||||||
"forest",
|
|
||||||
"aqua",
|
|
||||||
"black",
|
|
||||||
"luxury",
|
|
||||||
"dracula",
|
|
||||||
"business",
|
|
||||||
"night",
|
|
||||||
"coffee",
|
|
||||||
];
|
|
||||||
|
|
||||||
return computed(() => {
|
return computed(() => {
|
||||||
return darkthemes.includes(theme.theme.value);
|
return list.includes(theme.theme.value);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -153,3 +153,19 @@ export const themes: ThemeOption[] = [
|
|||||||
value: "winter",
|
value: "winter",
|
||||||
},
|
},
|
||||||
];
|
];
|
||||||
|
|
||||||
|
export const darkThemes: DaisyTheme[] = [
|
||||||
|
"synthwave",
|
||||||
|
"retro",
|
||||||
|
"cyberpunk",
|
||||||
|
"valentine",
|
||||||
|
"halloween",
|
||||||
|
"forest",
|
||||||
|
"aqua",
|
||||||
|
"black",
|
||||||
|
"luxury",
|
||||||
|
"dracula",
|
||||||
|
"business",
|
||||||
|
"night",
|
||||||
|
"coffee",
|
||||||
|
];
|
||||||
|
|||||||
@@ -54,6 +54,20 @@
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const isEvilAccentTheme = useIsThemeInList([
|
||||||
|
"bumblebee",
|
||||||
|
"corporate",
|
||||||
|
"forest",
|
||||||
|
"pastel",
|
||||||
|
"wireframe",
|
||||||
|
"black",
|
||||||
|
"dracula",
|
||||||
|
"autumn",
|
||||||
|
"acid",
|
||||||
|
]);
|
||||||
|
const isEvilForegroundTheme = useIsThemeInList(["light", "aqua", "fantasy", "autumn", "night"]);
|
||||||
|
const isLofiTheme = useIsThemeInList(["lofi"]);
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
@@ -166,14 +180,19 @@
|
|||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<header class="mx-auto p-4 text-accent sm:flex sm:items-end sm:p-6 lg:p-14">
|
<header
|
||||||
|
class="mx-auto p-4 sm:flex sm:items-end sm:p-6 lg:p-14"
|
||||||
|
:class="{ 'text-accent': !isEvilAccentTheme, 'text-white': isLofiTheme }"
|
||||||
|
>
|
||||||
<div class="z-10">
|
<div class="z-10">
|
||||||
<h2 class="mt-1 flex text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl">
|
<h2 class="mt-1 flex text-4xl font-bold tracking-tight sm:text-5xl lg:text-6xl">
|
||||||
HomeB
|
HomeB
|
||||||
<AppLogo class="-mb-4 w-12" />
|
<AppLogo class="-mb-4 w-12" />
|
||||||
x
|
x
|
||||||
</h2>
|
</h2>
|
||||||
<p class="ml-1 text-lg text-foreground">{{ $t("index.tagline") }}</p>
|
<p class="ml-1 text-lg" :class="{ 'text-foreground': !isEvilForegroundTheme, 'text-white': isLofiTheme }">
|
||||||
|
{{ $t("index.tagline") }}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<TooltipProvider :delay-duration="0">
|
<TooltipProvider :delay-duration="0">
|
||||||
<div class="z-10 ml-auto mt-6 flex items-center gap-4 sm:mt-0">
|
<div class="z-10 ml-auto mt-6 flex items-center gap-4 sm:mt-0">
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
import { useI18n } from "vue-i18n";
|
import { useI18n } from "vue-i18n";
|
||||||
import { toast } from "@/components/ui/sonner";
|
import { toast } from "@/components/ui/sonner";
|
||||||
import type { Detail } from "~~/components/global/DetailsSection/types";
|
import type { Detail } from "~~/components/global/DetailsSection/types";
|
||||||
import { themes } from "~~/lib/data/themes";
|
|
||||||
import type { CurrenciesCurrency, NotifierCreate, NotifierOut } from "~~/lib/api/types/data-contracts";
|
import type { CurrenciesCurrency, NotifierCreate, NotifierOut } from "~~/lib/api/types/data-contracts";
|
||||||
import MdiLoading from "~icons/mdi/loading";
|
import MdiLoading from "~icons/mdi/loading";
|
||||||
import MdiAccount from "~icons/mdi/account";
|
import MdiAccount from "~icons/mdi/account";
|
||||||
@@ -21,6 +20,7 @@
|
|||||||
import LanguageSelector from "~/components/App/LanguageSelector.vue";
|
import LanguageSelector from "~/components/App/LanguageSelector.vue";
|
||||||
import { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider } from "@/components/ui/tooltip";
|
import { Tooltip, TooltipContent, TooltipTrigger, TooltipProvider } from "@/components/ui/tooltip";
|
||||||
import { DialogID } from "~/components/ui/dialog-provider/utils";
|
import { DialogID } from "~/components/ui/dialog-provider/utils";
|
||||||
|
import ThemePicker from "~/components/App/ThemePicker.vue";
|
||||||
|
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
|
|
||||||
@@ -105,8 +105,6 @@
|
|||||||
toast.success(t("profile.toast.group_updated"));
|
toast.success(t("profile.toast.group_updated"));
|
||||||
}
|
}
|
||||||
|
|
||||||
const { setTheme } = useTheme();
|
|
||||||
|
|
||||||
const auth = useAuthContext();
|
const auth = useAuthContext();
|
||||||
|
|
||||||
const details = computed(() => {
|
const details = computed(() => {
|
||||||
@@ -516,40 +514,7 @@
|
|||||||
{{ $t("profile.display_legacy_header", { currentValue: preferences.displayLegacyHeader }) }}
|
{{ $t("profile.display_legacy_header", { currentValue: preferences.displayLegacyHeader }) }}
|
||||||
</Button>
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
<div class="homebox grid grid-cols-1 gap-4 font-sans sm:grid-cols-3 md:grid-cols-4 lg:grid-cols-5">
|
<ThemePicker />
|
||||||
<div
|
|
||||||
v-for="theme in themes"
|
|
||||||
:key="theme.value"
|
|
||||||
:class="'theme-' + theme.value"
|
|
||||||
class="overflow-hidden rounded-lg border outline-2 outline-offset-2"
|
|
||||||
:data-theme="theme.value"
|
|
||||||
:data-set-theme="theme.value"
|
|
||||||
data-act-class="outline"
|
|
||||||
@click="setTheme(theme.value)"
|
|
||||||
>
|
|
||||||
<div :data-theme="theme.value" class="w-full cursor-pointer bg-background-accent text-foreground">
|
|
||||||
<div class="grid grid-cols-5 grid-rows-3">
|
|
||||||
<div class="col-start-1 row-start-1 bg-background"></div>
|
|
||||||
<div class="col-start-1 row-start-2 bg-sidebar"></div>
|
|
||||||
<div class="col-start-1 row-start-3 bg-background-accent"></div>
|
|
||||||
<div class="col-span-4 col-start-2 row-span-3 row-start-1 flex flex-col gap-1 bg-background p-2">
|
|
||||||
<div class="font-bold">{{ theme.label }}</div>
|
|
||||||
<div class="flex flex-wrap gap-1">
|
|
||||||
<div class="flex size-5 items-center justify-center rounded bg-primary lg:size-6">
|
|
||||||
<div class="text-sm font-bold text-primary-foreground">A</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex size-5 items-center justify-center rounded bg-secondary lg:size-6">
|
|
||||||
<div class="text-sm font-bold text-secondary-foreground">A</div>
|
|
||||||
</div>
|
|
||||||
<div class="flex size-5 items-center justify-center rounded bg-accent lg:size-6">
|
|
||||||
<div class="text-sm font-bold text-accent-foreground">A</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</BaseCard>
|
</BaseCard>
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user