Merge pull request 'Add theme switching!!!!' (#18) from settings-appearance into main
All checks were successful
ci/woodpecker/push/build-and-publish Pipeline was successful

Reviewed-on: #18
Reviewed-by: SauceyRed <saucey@saucey.red>
This commit is contained in:
Twig 2025-07-05 17:29:45 +00:00
commit fb35be390e
10 changed files with 145 additions and 27 deletions

View file

@ -1,14 +1,100 @@
<template>
<div>
<h1>hi</h1>
<h5>TEST</h5>
<h5>TEST</h5>
<h1>Appearance</h1>
<p class="subtitle">THEMES</p>
<div class="themes">
<div v-for="theme of themes" class="theme-preview-container">
<span class="theme-preview"
:title="theme.displayName"
:style="{background:`linear-gradient(${theme.previewGradient})`}"
@click="changeTheme(theme.id, theme.themeUrl)"
>
<span class="theme-title" :style="{color:`${theme.complementaryColor}`}">
{{ theme.displayName }}
</span>
</span>
</div>
</div>
<p class="subtitle">ICONS</p>
<div class="themes">
</div>
</div>
</template>
<script lang="ts" setup>
const runtimeConfig = useRuntimeConfig()
const defaultThemes = runtimeConfig.public.defaultThemes
const baseURL = runtimeConfig.app.baseURL;
let themeLinkElement: HTMLLinkElement | null = null;
const themes: Array<Theme> = []
interface Theme {
id: string
displayName: string
previewGradient: string
complementaryColor: string
themeUrl: string
}
function changeTheme(id: string, url: string) {
if (themeLinkElement && themeLinkElement.getAttribute('href') === `${baseURL}themes/${url}`) {
return;
}
localStorage.setItem("selectedTheme", id);
// if the theme didn't originally load for some reason, create it
if (!themeLinkElement) {
themeLinkElement = document.createElement('link');
themeLinkElement.rel = 'stylesheet';
document.head.appendChild(themeLinkElement);
}
themeLinkElement.href = `${baseURL}themes/${url}`;
}
async function fetchThemes() {
for (const theme of defaultThemes) {
const themeConfig = await $fetch(`${baseURL}themes/${theme}.json`) as Theme
themeConfig.id = theme
themes.push(themeConfig)
}
}
await fetchThemes()
</script>
<style scoped>
.themes {
display: flex;
}
</style>
.theme-preview-container {
margin: .5em;
width: 5em;
height: 5em;
}
.theme-preview {
width: 5em;
height: 5em;
border-radius: 100%;
border: .1em solid var(--primary-color);
display: inline-block;
text-align: center;
align-content: center;
cursor: pointer;
}
.theme-title {
font-size: .8em;
line-height: 5em; /* same height as the parent to centre it vertically */
}
</style>

View file

@ -70,13 +70,6 @@ async function deleteAccount() {
</script>
<style scoped>
.subtitle {
display: block;
font-size: 0.8em;
font-weight: 800;
margin: 4dvh 0 0.5dvh 0.25dvw;
}
.user-data-fields {
min-width: 35dvw;
max-width: 35dvw;

View file

@ -108,13 +108,6 @@ async function changeAvatar() {
display: flex;
}
.subtitle {
display: block;
font-size: 0.8em;
font-weight: 800;
margin: 1.5dvh 0 0.5dvh 0.25dvw;
}
.user-data-fields {
min-width: 35dvw;
max-width: 35dvw;

View file

@ -30,6 +30,9 @@ export default defineNuxtConfig({
messageGroupingMaxDifference: 300000,
buildTimeString: new Date().toISOString(),
gitHash: process.env.GIT_SHORT_REV || "N/A",
defaultThemes: [
"light", "ash", "dark"
]
}
},
/* nitro: {

View file

@ -40,10 +40,7 @@
<script lang="ts" setup>
import Button from '~/components/Button.vue';
const { logout } = useAuth()
const appConfig = useRuntimeConfig()
interface Page {
@ -99,6 +96,16 @@ function selectCategory(page: Page) {
selectedPage.value = page.displayName;
};
// redirects to you privacy if you go to settings#privacy
onMounted(() => {
const hash = window.location.hash.substring(1).toLowerCase();
const foundPage = categories.flatMap(category => category.pages).find(page => page.displayName.toLowerCase() === hash);
if (foundPage) {
currentPage.value = foundPage;
selectedPage.value = foundPage.displayName;
}
});
</script>
<style scoped>
@ -180,7 +187,10 @@ function selectCategory(page: Page) {
}
/* applies to child pages too */
:deep(h5) {
color: red;
:deep(.subtitle) {
display: block;
font-size: 0.8em;
font-weight: 800;
margin: 4dvh 0 0.5dvh 0.25dvw;
}
</style>

19
public/themes/ash.css Normal file
View file

@ -0,0 +1,19 @@
:root {
--text-color: #f0e5e0;
--secondary-text-color: #e8e0db;
--chat-background-color: #2f2e2d;
--chat-highlighted-background-color: #3f3b38;
--sidebar-background-color: #3e3a37;
--sidebar-highlighted-background-color: #46423b;
--topbar-background-color: #3a3733;
--padding-color: #e0e0e0;
--primary-color: #f07028;
--primary-highlighted-color: #f28f4b;
--secondary-color: #683820;
--secondary-highlighted-color: #885830;
--accent-color: #a04b24;
--accent-highlighted-color: #b86038;
}

6
public/themes/ash.json Normal file
View file

@ -0,0 +1,6 @@
{
"displayName": "Ash",
"previewGradient": "45deg, #2f2e2d, #46423b",
"complementaryColor": "white",
"themeUrl": "ash.css"
}

6
public/themes/dark.json Normal file
View file

@ -0,0 +1,6 @@
{
"displayName": "Dark",
"previewGradient": "45deg, #1f1e1d, #36322b",
"complementaryColor": "white",
"themeUrl": "dark.css"
}

View file

@ -1,4 +0,0 @@
[
"dark.css",
"light.css"
]

6
public/themes/light.json Normal file
View file

@ -0,0 +1,6 @@
{
"displayName": "Light",
"previewGradient": "45deg, #f0ebe8, #d4d0ca",
"complementaryColor": "black",
"themeUrl": "light.css"
}