Seperate themes and layouts into seperate settings #63

Merged
twig merged 13 commits from better-themes into main 2025-08-05 21:47:20 +00:00
16 changed files with 219 additions and 98 deletions
Showing only changes of commit 5191ac7df7 - Show all commits

View file

@ -2,18 +2,37 @@
<div>
<h1>Appearance</h1>
<p class="subtitle">THEMES</p>
<h2>Themes</h2>
<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>
<p class="subtitle">STYLES</p>
<div class="styles">
<div v-for="style of styles" class="theme-preview-container">
<div class="theme-instance" :title="style.displayName">
<div class="theme-content-container">
<span class="style-background"
:style="{background:`linear-gradient(${style.previewGradient})`}"
></span>
<span class="theme-title" :style="{color:`${style.complementaryColor}`}">
{{ style.displayName }}
</span>
</div>
</div>
</div>
</div>
<p class="subtitle">LAYOUTS</p>
<div class="layouts">
<div v-for="layout of layouts" class="theme-preview-container">
<div class="theme-instance" :title="layout.displayName">
<div class="theme-content-container">
<span class="layout-background"
:style="{backgroundImage:`url(${layout.previewImageUrl})`}"
></span>
<span class="theme-title" :style="{color:`${layout.complementaryColor}`}">
{{ layout.displayName }}
</span>
</div>
</div>
</div>
</div>
</div>
@ -36,35 +55,103 @@ import loadPreferredTheme from '~/utils/loadPreferredTheme';
import settingSave from '~/utils/settingSave';
const runtimeConfig = useRuntimeConfig()
const defaultThemes = runtimeConfig.public.defaultThemes
const baseURL = runtimeConfig.app.baseURL;
const styleFolder = `${baseURL}themes/style`
const layoutFolder = `${baseURL}themes/layout`
const timeFormatTextStrings = ["Auto", "12-Hour", "24-Hour"]
const themes: Array<Theme> = []
interface Theme {
id: string
displayName: string
previewGradient: string
complementaryColor: string
themeUrl: string
cssData: string
previewGradient?: string
twig marked this conversation as resolved Outdated

Enum options should use PascalCase

Enum options should use PascalCase
twig marked this conversation as resolved Outdated

Both enum and enum options should use PascalCase/CamelCase, that's what I meant.

enum StyleLayout  {
  Style,
  Layout
}
Both _enum_ and enum _options_ should use PascalCase/CamelCase, that's what I meant. ```ts enum StyleLayout { Style, Layout } ```

okay this makes more sense

okay this makes more sense
previewImageUrl?: string
}
function changeTheme(id: string, url: string) {
settingSave("selectedThemeId", id)
loadPreferredTheme()
}
async function parseThemeCss(styleData: string): Promise<Theme | void> {
const metadataMatch = styleData.match(/\/\*([\s\S]*?)\*\//);
if (!metadataMatch) {
alert(`Failed to fetch metadata for a theme, panicing`)
return
}
async function fetchThemes() {
for (const theme of defaultThemes) {
const themeConfig = await $fetch(`${baseURL}themes/${theme}.json`) as Theme
themeConfig.id = theme
const commentContent = metadataMatch[0].trim().split("\n");
const cssData = styleData.substring(metadataMatch[0].length).trim();
themes.push(themeConfig)
let displayName: string | undefined
let complementaryColor: string | undefined
let previewGradient: string | undefined
let previewImageUrl: string | undefined
for (const line of commentContent) {
const line_array = line.split("=")
if (line_array.length === 2) {
switch (line_array[0].trim()) {
case "displayName":
twig marked this conversation as resolved Outdated

Should be "panicking"

Should be "panicking"
displayName = line_array[1].trim()
break
case "complementaryColor":
complementaryColor = line_array[1].trim()
break
case "previewGradient":
previewGradient = line_array[1].trim()
break
case "previewImageUrl":
previewImageUrl = `${layoutFolder}/${line_array[1].trim()}`
break
}
}
twig marked this conversation as resolved Outdated

lineArray please

`lineArray` please
}
console.log(displayName, complementaryColor, previewGradient, previewImageUrl, cssData)
if (!(displayName && complementaryColor && cssData && (previewGradient || previewImageUrl))) {
return
}
return {
displayName,
complementaryColor,
cssData,
previewGradient,
previewImageUrl,
}
}
await fetchThemes()
async function parseThemeData(
folder: string,
incomingThemeList: Array<string>,
outputThemeList: Array<Theme>) {
for (const theme of incomingThemeList) {
const themeData = await $fetch(`${folder}/${theme}`)
const parsedThemeData = await parseThemeCss(themeData)
if (parsedThemeData) {
outputThemeList.push(parsedThemeData)
}
}
}
const styles: Array<Theme> = [];
const layouts: Array<Theme> = [];
const styleList: any = await $fetch(`${styleFolder}/styles.json`)
const layoutList: any = await $fetch(`${layoutFolder}/layouts.json`)
twig marked this conversation as resolved Outdated

string[] instead of Array<string>

`string[]` instead of `Array<string>`
if (Array.isArray(styleList)) {
twig marked this conversation as resolved Outdated

string[] instead of Array<string>

`string[]` instead of `Array<string>`
await parseThemeData(styleFolder, styleList, styles)
}
if (Array.isArray(layoutList)) {
await parseThemeData(layoutFolder, layoutList, layouts)
}
console.log(layouts)
function changeTheme(id: string, url: string) {
twig marked this conversation as resolved Outdated

string[] instead of Array<string>

`string[]` instead of `Array<string>`
settingSave("selectedThemeStyle", id)
twig marked this conversation as resolved Outdated

Theme[] instead of Array<Theme>

`Theme[]` instead of `Array<Theme>`
loadPreferredTheme()
}
twig marked this conversation as resolved Outdated

Avoid use of any

Avoid use of `any`
twig marked this conversation as resolved Outdated

Avoid use of any

Avoid use of `any`
async function onTimeFormatClicked(index: number) {
let format: "auto" | "12" | "24" = "auto"
@ -84,29 +171,68 @@ async function onTimeFormatClicked(index: number) {
<style scoped>
.themes {
--instance-size: 5em;
}
.styles, .layouts {
display: flex;
}
.theme-preview-container {
margin: .5em;
width: 5em;
height: 5em;
width: var(--instance-size);
height: var(--instance-size);
}
.theme-preview {
width: 5em;
height: 5em;
.theme-instance {
width: var(--instance-size);
height: var(--instance-size);
border-radius: 100%;
border: .1em solid var(--primary-color);
display: inline-block;
text-align: center;
align-content: center;
cursor: pointer;
}
.theme-content-container {
position: relative;
text-align: center;
align-content: center;
}
.style-background, .layout-background {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: var(--instance-size);
height: var(--instance-size);
border-radius: 100%;
}
.layout-background {
background-size: cover;
background-repeat: no-repeat;
filter: brightness(35%);
}
.theme-title {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
width: 100%;
height: 100%;
font-size: .8em;
line-height: 5em; /* same height as the parent to centre it vertically */
/* i CANNOT explain this line height calculation, but it works for a font size of .8em no matter what size the instances are */
line-height: calc(var(--instance-size) * 1.25);
}
</style>

View file

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

View file

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

View file

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

View file

@ -0,0 +1,17 @@
/*
displayName = Gorb
previewImageUrl = gorb.jpg
complementaryColor = white
*/
:root {
--sidebar-icon-width: 2.5em;
--sidebar-icon-gap: .25em;
--sidebar-margin: .5em;
--standard-radius: .5em;
--button-radius: .6em;
--guild-icon-radius: 15%;
--pfp-radius: 50%;
--preferred-font: Arial;
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

View file

@ -0,0 +1,3 @@
[
"gorb.css"
]

View file

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

View file

@ -1,6 +0,0 @@
{
"displayName": "Woke",
"previewGradient": "45deg, #ed2224, #ed2224, #f35b22, #f99621, #f5c11e, #f1eb1b 27%, #f1eb1b, #f1eb1b 33%, #63c720, #0c9b49, #21878d, #3954a5, #61379b, #93288e, #93288e",
"complementaryColor": "white",
"themeUrl": "rainbow-capitalism.css"
}

View file

@ -1,3 +1,9 @@
/*
displayName = Ash
previewGradient = 45deg, #2f2e2d, #46423b
complementaryColor = white
*/
:root {
--text-color: #f0e5e0;
--secondary-text-color: #e8e0db;
@ -19,11 +25,4 @@
--secondary-highlighted-color: #885830;
--accent-color: #a04b24;
--accent-highlighted-color: #b86038;
--sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
--guild-icon-radius: 20%;
--pfp-radius: 50%;
--preferred-font: Arial;
}

View file

@ -1,3 +1,9 @@
/*
displayName = Dark
previewGradient = 45deg, #1f1e1d, #36322b
complementaryColor = white
*/
:root {
--text-color: #f7eee8;
--secondary-text-color: #f0e8e4;
@ -19,14 +25,4 @@
--secondary-highlighted-color: #8f5b2c;
--accent-color: #b35719;
--accent-highlighted-color: #c76a2e;
--sidebar-icon-width: 2.5em;
--sidebar-icon-gap: .25em;
--sidebar-margin: .5em;
--standard-radius: .5em;
--button-radius: .6em;
--guild-icon-radius: 15%;
--pfp-radius: 50%;
--preferred-font: Arial;
}

View file

@ -1,4 +1,11 @@
/*
displayName = Description
previewGradient = 45deg, #ff8f8f, #8f8fff
complementaryColor = black
*/
/* this is not a real theme, but rather a template for themes */
:root {
--text-color: #161518;
--secondary-text-color: #2b2930;
@ -20,12 +27,6 @@
--accent-color: #ff218c80;
--accent-highlighted-color: #df1b6f80;
--sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
--pfp-radius: 50%;
--preferred-font: Arial;
--optional-body-background: ; /* background element for the body */
--optional-chat-background: ; /* background element for the chat box */
--optional-topbar-background: ; /* background element for the topbar */

View file

@ -1,3 +1,9 @@
/*
displayName = Light
previewGradient = 45deg, #f0ebe8, #d4d0ca
complementaryColor = black
*/
:root {
--text-color: #170f08;
--secondary-text-color: #2f2b28;
@ -19,10 +25,4 @@
--secondary-highlighted-color: #f8b68a;
--accent-color: #e68b4e;
--accent-highlighted-color: #f69254;
--sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
--pfp-radius: 50%;
--preferred-font: Arial;
}

View file

@ -1,3 +1,9 @@
/*
displayName = Woke
previewGradient = 45deg, #ed2224, #ed2224, #f35b22, #f99621, #f5c11e, #f1eb1b 27%, #f1eb1b, #f1eb1b 33%, #63c720, #0c9b49, #21878d, #3954a5, #61379b, #93288e, #93288e
complementaryColor = white
*/
:root {
--text-color: #161518;
--secondary-text-color: #2b2930;
@ -20,12 +26,6 @@
--accent-color: #ff218c80;
--accent-highlighted-color: #df1b6f80;
--sidebar-width: 2.5em;
--standard-radius: .5em;
--button-radius: .6em;
--pfp-radius: 50%;
--preferred-font: Arial;
/* --optional-body-background: background */
--optional-body-background: linear-gradient(45deg, #ed222480, #ed222480, #ed222480, #ed222480, #ed222480, #ed222480, #f35b2280, #f9962180, #f5c11e80, #f1eb1b80, #f1eb1b80, #f1eb1b80, #63c72080, #0c9b4980, #21878d80, #3954a580, #61379b80, #93288e80);
--optional-topbar-background: linear-gradient(-12.5deg, cyan, pink, white, pink, cyan);

View file

@ -0,0 +1,6 @@
[
"ash.css",
"dark.css",
"light.css",
"rainbow-capitalism.css"
]

View file

@ -24,5 +24,5 @@ function getThemeUrl(id: string): string {
const baseURL = runtimeConfig.app.baseURL;
// this should preferrably use version hash, but that's not implemented yet
return `${baseURL}themes/${id}.css?v=${runtimeConfig.public.buildTimeString}`
return `${baseURL}themes/style/${id}.css?v=${runtimeConfig.public.buildTimeString}`
}