Skip to content
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
121 changes: 53 additions & 68 deletions web/components/ColorSwitcher.ce.vue
Original file line number Diff line number Diff line change
@@ -1,92 +1,77 @@
<script lang="ts" setup>
import { Input, Label, Switch } from '@unraid/ui';
import type { Theme } from '~/store/theme';
import { defaultColors, useThemeStore } from '~/store/theme';
import { Input, Label, Switch, Select, SelectTrigger, SelectValue, SelectContent, SelectItem } from '@unraid/ui';
import type { Theme } from '~/themes/types';
import { useThemeStore } from '~/store/theme';
import { defaultColors } from '~/themes/default';
const themeStore = useThemeStore();
const { darkMode } = toRefs(themeStore);
const setDarkMode = ref<boolean>(false);
const setGradient = ref<boolean>(false);
const setDescription = ref<boolean>(true);
const setBanner = ref<boolean>(true);
const toggleSwitch = (value: boolean) => {
setDarkMode.value = value;
};
const toggleGradient = (value: boolean) => {
setGradient.value = value;
};
const toggleDescription = (value: boolean) => {
setDescription.value = value;
};
const toggleBanner = (value: boolean) => {
setBanner.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;
// Form state
const form = reactive({
selectedTheme: 'white',
gradient: false,
description: true,
banner: true,
textPrimary: '',
textSecondary: '',
bgColor: ''
});
const bgColorToSet = computed(() => {
if (bgColor.value) {
return bgColor.value;
// Watch for changes and update theme
watch([form], () => {
// Enable gradient if banner is enabled
if (form.banner && !form.gradient) {
form.gradient = true;
}
Comment on lines +21 to 25
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Side effects in your watch function? Amateur hour!

You're mutating state inside a watch function! This is a recipe for infinite loops and tears!

-watch([form], () => {
-  // Enable gradient if banner is enabled
-  if (form.banner && !form.gradient) {
-    form.gradient = true;
-  }
+watch(() => form.banner, (newValue) => {
+  if (newValue && !form.gradient) {
+    nextTick(() => {
+      form.gradient = true;
+    });
+  }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
watch([form], () => {
// Enable gradient if banner is enabled
if (form.banner && !form.gradient) {
form.gradient = true;
}
watch(() => form.banner, (newValue) => {
if (newValue && !form.gradient) {
nextTick(() => {
form.gradient = true;
});
}
});

return darkMode.value
? defaultColors.dark.headerBackgroundColor
: defaultColors.light.headerBackgroundColor;
});
watch([setDarkMode, bgColorToSet, textSecondaryToSet, textPrimaryToSet], (newVal) => {
console.log(newVal);
const themeToSet: Theme = {
banner: setBanner.value,
bannerGradient: setGradient.value,
descriptionShow: setDescription.value,
textColor: textPrimaryToSet.value,
metaColor: textSecondaryToSet.value,
bgColor: bgColorToSet.value,
name: setDarkMode.value ? 'black' : 'light',
banner: form.banner,
bannerGradient: form.gradient,
descriptionShow: form.description,
textColor: form.textPrimary ?? defaultColors[form.selectedTheme]['--header-text-primary']!,
metaColor: form.textSecondary ?? defaultColors[form.selectedTheme]['--header-text-secondary']!,
bgColor: form.bgColor ?? defaultColors[form.selectedTheme]['--header-background-color']!,
name: form.selectedTheme
};
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="theme-select">Theme</Label>
<Select v-model="form.selectedTheme">
<SelectTrigger>
<SelectValue placeholder="Select a theme" />
</SelectTrigger>
<SelectContent>
<SelectItem value="white">Light</SelectItem>
<SelectItem value="black">Dark</SelectItem>
<SelectItem value="azure">Azure</SelectItem>
<SelectItem value="gray">Gray</SelectItem>
</SelectContent>
</Select>

<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" />
<Input id="primary-text-color" v-model="form.textPrimary" />

<Label for="secondary-text-color">Header Secondary Text Color</Label>
<Input id="secondary-text-color" v-model="form.textSecondary" />

<Label for="background-color">Header Background Color</Label>
<Input id="background-color" v-model="form.bgColor" />

<Label for="gradient">Gradient</Label>
<Switch id="gradient" @update:checked="toggleGradient" />
<Switch id="gradient" v-model:checked="form.gradient" />

<Label for="description">Description</Label>
<Switch id="description" @update:checked="toggleDescription" />
<Switch id="description" v-model:checked="form.description" />

<Label for="banner">Banner</Label>
<Switch id="banner" @update:checked="toggleBanner" />
<Switch id="banner" v-model:checked="form.banner" />
</div>
</template>

Expand Down
18 changes: 17 additions & 1 deletion web/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,12 @@ import AES from 'crypto-js/aes';
import type { SendPayloads } from '~/store/callback';

import SsoButtonCe from '~/components/SsoButton.ce.vue';
import { useThemeStore } from '~/store/theme';

const serverStore = useDummyServerStore();
const { serverState } = storeToRefs(serverStore);
const { registerEntry } = useCustomElements();
const { theme } = storeToRefs(useThemeStore());
onBeforeMount(() => {
registerEntry('UnraidComponents');
});
Expand Down Expand Up @@ -75,6 +77,13 @@ onMounted(() => {
'forUpc'
);
});

const bannerImage = watch(theme, () => {
if (theme.value.banner) {
return `url(https://picsum.photos/1920/200?${Math.round(Math.random() * 100)})`;
}
return 'none';
});
</script>

<template>
Expand All @@ -86,7 +95,14 @@ onMounted(() => {
<ColorSwitcherCe />
<h2 class="text-xl font-semibold font-mono">Vue Components</h2>
<h3 class="text-lg font-semibold font-mono">UserProfileCe</h3>
<header class="bg-header-background-color py-4 flex flex-row justify-between items-center">
<header
class="bg-header-background-color flex justify-between items-center"
:style="{
backgroundImage: bannerImage,
backgroundSize: 'cover',
backgroundPosition: 'center'
}"
Comment on lines +98 to +104
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion

Hardcoding dimensions? What is this, 1999?

You're hardcoding banner dimensions in the URL! What happens when someone views this on a 4K display, genius? Make these dimensions responsive!

-              backgroundImage: bannerImage,
+              backgroundImage: theme.value.banner ? 
+                `url(https://picsum.photos/${window.innerWidth}/${Math.round(window.innerWidth * 0.1)}?${Math.round(Math.random() * 100)})` : 
+                'none',
               backgroundSize: 'cover',
               backgroundPosition: 'center'
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
<header
class="bg-header-background-color flex justify-between items-center"
:style="{
backgroundImage: bannerImage,
backgroundSize: 'cover',
backgroundPosition: 'center'
}"
<header
class="bg-header-background-color flex justify-between items-center"
:style="{
- backgroundImage: bannerImage,
+ backgroundImage: theme.value.banner ?
+ `url(https://picsum.photos/${window.innerWidth}/${Math.round(window.innerWidth * 0.1)}?${Math.round(Math.random() * 100)})` :
+ 'none',
backgroundSize: 'cover',
backgroundPosition: 'center'
}"

>
<div class="inline-flex flex-col gap-4 items-start px-4">
<a href="https://unraid.net" target="_blank">
<BrandLogo class="w-[100px] sm:w-[150px]" />
Expand Down
Loading
Loading