Add custom theming (#2081)

Adds support for user-created custom themes. Custom theme interface is
tucked into the global settings in a non-invasive manner to avoid major
design changes. Builds on the theme structure established by the dark
theme update.

<img width="1486" height="953" alt="image"
src="https://github.com/user-attachments/assets/716bcfc7-af74-41dc-b14a-cfc2f2d2caa9"
/>

<img width="1486" height="956" alt="image"
src="https://github.com/user-attachments/assets/a00f9620-0b1d-4f67-b010-e94dda5dc212"
/>



Here's a few examples of what teams could do, using a few color schemes
from local teams. Imagine the possibilities!

<img width="1485" height="951" alt="image"
src="https://github.com/user-attachments/assets/c3da37b8-f6be-4152-81e0-533297f517fc"
/>

<img width="1483" height="951" alt="image"
src="https://github.com/user-attachments/assets/0d453f7a-cf6f-4c27-97db-603b54c1f73e"
/>

<img width="1485" height="952" alt="image"
src="https://github.com/user-attachments/assets/bf8c7770-e60d-4875-9580-ed7e54e089f4"
/>

<img width="1484" height="952" alt="image"
src="https://github.com/user-attachments/assets/326d89e6-dd6e-4e05-a9fa-c9fc6f880847"
/>

<img width="1482" height="951" alt="image"
src="https://github.com/user-attachments/assets/eb5a2a5d-c103-482c-a62a-5ccd5ba21cc5"
/>

<img width="1482" height="950" alt="image"
src="https://github.com/user-attachments/assets/4831ca56-f322-4345-97af-8963ae8539b1"
/>



Looking for high contrast? Just moments away:
<img width="1484" height="949" alt="image"
src="https://github.com/user-attachments/assets/7ffc65c6-7000-4566-b4f0-c8247f75fb3d"
/>
This commit is contained in:
Devon Doyle
2025-09-07 00:33:37 -04:00
committed by GitHub
parent 3300b90823
commit b43d0dde20
9 changed files with 397 additions and 38 deletions

View File

@@ -2,10 +2,10 @@
import { computed, inject, ref, onBeforeUnmount } from "vue";
import { useStateStore } from "@/stores/StateStore";
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import loadingImage from "@/assets/images/loading-transparent.svg";
import type { StyleValue } from "vue";
import PvIcon from "@/components/common/pv-icon.vue";
import type { UiCameraConfiguration } from "@/types/SettingTypes";
import PvLoading from "@/components/common/pv-loading.vue";
const props = defineProps<{
streamType: "Raw" | "Processed";
@@ -92,7 +92,7 @@ onBeforeUnmount(() => {
<template>
<div class="stream-container" :style="containerStyle">
<img :src="loadingImage" class="stream-loading" />
<pv-loading class="stream-loading" />
<img
:id="id"
ref="mjpgStream"

View File

@@ -5,7 +5,7 @@ import { useStateStore } from "@/stores/StateStore";
import { useCameraSettingsStore } from "@/stores/settings/CameraSettingsStore";
import { useRoute } from "vue-router";
import { useDisplay, useTheme } from "vuetify";
import { onBeforeMount } from "vue";
import { toggleTheme } from "@/lib/ThemeManager";
const compact = computed<boolean>({
get: () => {
@@ -19,19 +19,6 @@ const { mdAndUp } = useDisplay();
const theme = useTheme();
const changeTheme = () => {
const newTheme = theme.global.name.value === "LightTheme" ? "DarkTheme" : "LightTheme";
theme.global.name.value = newTheme;
localStorage.setItem("theme", newTheme);
};
onBeforeMount(() => {
const storedTheme = localStorage.getItem("theme");
if (storedTheme) {
theme.global.name.value = storedTheme;
}
});
const renderCompact = computed<boolean>(() => compact.value || !mdAndUp.value);
</script>
@@ -88,7 +75,7 @@ const renderCompact = computed<boolean>(() => compact.value || !mdAndUp.value);
<v-list-item
link
:prepend-icon="theme.global.name.value === 'LightTheme' ? 'mdi-white-balance-sunny' : 'mdi-weather-night'"
@click="changeTheme"
@click="() => toggleTheme(theme)"
>
<v-list-item-title>Theme</v-list-item-title>
</v-list-item>