Add dark theme to main css (some colors are wrong)

This commit is contained in:
Kloon ImKloon 2023-10-06 19:46:00 +02:00
parent cc16511c36
commit 6332514ccc
No known key found for this signature in database
GPG Key ID: CCF1C86A995C5B6A
13 changed files with 128 additions and 76 deletions

View File

@ -181,12 +181,7 @@
<script type="module" src="/src/main.ts"></script> <script type="module" src="/src/main.ts"></script>
[{[ if .Theme -]}] [{[ if .CSS -]}]
<link
rel="stylesheet"
href="[{[ .StaticURL ]}]/themes/[{[ .Theme ]}].css"
/>
[{[ end ]}] [{[ if .CSS -]}]
<link rel="stylesheet" href="[{[ .StaticURL ]}]/custom.css" /> <link rel="stylesheet" href="[{[ .StaticURL ]}]/custom.css" />
[{[ end ]}] [{[ end ]}]
</body> </body>

View File

@ -5,13 +5,17 @@
</template> </template>
<script setup lang="ts"> <script setup lang="ts">
import { onMounted, watch } from "vue"; import { ref, onMounted, watch } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { setHtmlLocale } from "./i18n"; import { setHtmlLocale } from "./i18n";
import { getMediaPreference, getTheme, setTheme } from "./utils/theme";
const { locale } = useI18n(); const { locale } = useI18n();
const userTheme = ref<UserTheme>(getTheme() || getMediaPreference());
onMounted(() => { onMounted(() => {
setTheme(userTheme.value);
setHtmlLocale(locale.value); setHtmlLocale(locale.value);
// this might be null during HMR // this might be null during HMR
const loading = document.getElementById("loading"); const loading = document.getElementById("loading");

View File

@ -1,6 +1,7 @@
<template> <template>
<select v-on:change="change" :value="theme"> <select v-on:change="change" :value="theme">
<option value="">{{ t("settings.themes.light") }}</option> <option value="">{{ t("settings.themes.default") }}</option>
<option value="light">{{ t("settings.themes.light") }}</option>
<option value="dark">{{ t("settings.themes.dark") }}</option> <option value="dark">{{ t("settings.themes.dark") }}</option>
</select> </select>
</template> </template>
@ -12,7 +13,7 @@ import { useI18n } from "vue-i18n";
const { t } = useI18n(); const { t } = useI18n();
defineProps<{ defineProps<{
theme: any; theme: UserTheme;
}>(); }>();
const emit = defineEmits<{ const emit = defineEmits<{

View File

@ -1,16 +1,16 @@
.input { .input {
background: var(--surfacePrimary);
color: var(--textPrimary);
border: 1px solid var(--borderPrimary);
border-radius: 0.1em; border-radius: 0.1em;
padding: 0.5em 1em; padding: 0.5em 1em;
background: white;
border: 1px solid rgba(0, 0, 0, 0.1);
transition: 0.2s ease all; transition: 0.2s ease all;
color: #333;
margin: 0; margin: 0;
} }
.input:hover, .input:hover,
.input:focus { .input:focus {
border-color: rgba(0, 0, 0, 0.2); border-color: var(--borderSecondary);
} }
.input--block { .input--block {
@ -27,9 +27,9 @@
} }
.input--red { .input--red {
background: #fcd0cd; background: var(--input-red) !important;
} }
.input--green { .input--green {
background: #c9f2da; background: var(--input-green) !important;
} }

View File

@ -11,4 +11,38 @@
--icon-green: #2ecc71; --icon-green: #2ecc71;
--icon-blue: #1d99f3; --icon-blue: #1d99f3;
--icon-violet: #9b59b6; --icon-violet: #9b59b6;
--input-red: #fcd0cd;
--input-green: #c9f2da;
--background: rgb(250, 250, 250);
--surfacePrimary: #fff;
--surfaceSecondary: #f5f5f5;
--divider: rgba(0, 0, 0, 0.05);
--iconPrimary: var(--icon-blue);
--iconSecondary: #fff;
--action: rgb(84, 110, 122);
--textPrimary: rgb(111, 111, 111);
--textSecondary: rgb(51, 51, 51);
--hover: rgba(255, 255, 255, 0.1);
--borderPrimary: rgba(0, 0, 0, 0.1);
--borderSecondary: rgba(0, 0, 0, 0.2);
}
:root.dark {
--input-red: #73302d;
--input-green: #147a41;
--background: #141d24;
--surfacePrimary: #20292f;
--surfaceSecondary: #3a4147;
--textPrimary: rgba(255, 255, 255, 0.6);
--textSecondary: rgba(255, 255, 255, 0.87);
--divider: rgba(255, 255, 255, 0.12);
--iconPrimary: #fff;
--iconSecondary: #fff;
--action: #fff;
--hover: rgba(255, 255, 255, 0.1);
--borderPrimary: rgba(255, 255, 255, 0.05);
--borderSecondary: rgba(255, 255, 255, 0.15);
} }

View File

@ -1,16 +1,6 @@
:root {
--background: #141d24;
--surfacePrimary: #20292f;
--surfaceSecondary: #3a4147;
--divider: rgba(255, 255, 255, 0.12);
--icon: #ffffff;
--textPrimary: rgba(255, 255, 255, 0.87);
--textSecondary: rgba(255, 255, 255, 0.6);
}
body { body {
background: var(--background); background: var(--background);
color: var(--textPrimary); color: var(--textSecondary);
} }
#loading { #loading {
@ -18,11 +8,11 @@ body {
} }
#loading .spinner div, #loading .spinner div,
main .spinner div { main .spinner div {
background: var(--icon); background: var(--iconPrimary);
} }
#login { #login {
background: var(--background); background: var(--surfacePrimary);
} }
header { header {
@ -47,20 +37,20 @@ header {
color: var(--textPrimary); color: var(--textPrimary);
} }
#search .boxes { #search .boxes {
background: var(--surfaceSecondary); background: var(--surfacePrimary);
} }
#search .boxes h3 { #search .boxes h3 {
color: var(--textPrimary); color: var(--textSecondary);
} }
.action { .action {
color: var(--textPrimary) !important; color: var(--action) !important;
} }
.action:hover { .action:hover {
background-color: rgba(255, 255, 255, 0.1); background-color: var(--hover);
} }
.action i { .action i {
color: var(--icon) !important; color: var(--action) !important;
} }
.action .counter { .action .counter {
border-color: var(--surfacePrimary); border-color: var(--surfacePrimary);
@ -78,7 +68,7 @@ nav > div {
color: var(--textPrimary) !important; color: var(--textPrimary) !important;
} }
.breadcrumbs a:hover { .breadcrumbs a:hover {
background-color: rgba(255, 255, 255, 0.1); background-color: var(--hover);
} }
#listing .item { #listing .item {
@ -87,20 +77,17 @@ nav > div {
border-color: var(--divider) !important; border-color: var(--divider) !important;
} }
#listing .item i { #listing .item i {
color: var(--icon); color: var(--iconPrimary);
} }
#listing .item .modified { #listing .item[aria-selected="true"] i {
color: var(--textSecondary); color: var(--iconSecondary);
} }
#listing h2, #listing h2,
#listing.list .header span { #listing.list .header span {
color: var(--textPrimary) !important; color: var(--textPrimary) !important;
} }
#listing.list .header span {
color: var(--textPrimary);
}
#listing.list .header i { #listing.list .header i {
color: var(--icon); color: var(--textPrimary);
} }
#listing.list .item.header { #listing.list .item.header {
background: var(--background); background: var(--background);
@ -112,14 +99,14 @@ nav > div {
.card { .card {
background: var(--surfacePrimary); background: var(--surfacePrimary);
color: var(--textPrimary); color: var(--textSecondary);
} }
.button--flat:hover { .button--flat:hover {
background: var(--surfaceSecondary); background: var(--surfaceSecondary);
} }
.dashboard #nav ul li { .dashboard #nav ul li {
color: var(--textSecondary); color: var(--action);
} }
.dashboard #nav ul li:hover { .dashboard #nav ul li:hover {
background: var(--surfaceSecondary); background: var(--surfaceSecondary);
@ -131,22 +118,10 @@ nav > div {
color: var(--textPrimary); color: var(--textPrimary);
} }
.card#share input, .card#share input,
.card#share select, .card#share select {
.input { background: var(--surfacePrimary);
background: var(--surfaceSecondary);
color: var(--textPrimary); color: var(--textPrimary);
border: 1px solid rgba(255, 255, 255, 0.05); border: 1px solid var(--borderPrimary);
}
.input:hover,
.input:focus {
border-color: rgba(255, 255, 255, 0.15);
}
.input--red {
background: #73302d;
}
.input--green {
background: #147a41;
} }
.dashboard #nav .wrapper, .dashboard #nav .wrapper,
@ -168,7 +143,7 @@ table th {
color: var(--textSecondary); color: var(--textSecondary);
} }
.file-list li[aria-selected="true"]:before { .file-list li[aria-selected="true"]:before {
color: var(--icon); color: var(--iconSecondary);
} }
.shell { .shell {

View File

@ -14,6 +14,7 @@
@import "./dashboard.css"; @import "./dashboard.css";
@import "./login.css"; @import "./login.css";
@import "./mobile.css"; @import "./mobile.css";
@import "./dark.css";
.link { .link {
color: var(--blue); color: var(--blue);

View File

@ -239,6 +239,7 @@
"shareDeleted": "Share deleted!", "shareDeleted": "Share deleted!",
"singleClick": "Use single clicks to open files and directories", "singleClick": "Use single clicks to open files and directories",
"themes": { "themes": {
"default": "System default",
"dark": "Dark", "dark": "Dark",
"light": "Light", "light": "Light",
"title": "Theme" "title": "Theme"

View File

@ -27,7 +27,7 @@ interface SettingsBranding {
disableExternal: boolean; disableExternal: boolean;
disableUsedPercentage: boolean; disableUsedPercentage: boolean;
files: string; files: string;
theme: string; theme: UserTheme;
color: string; color: string;
} }

View File

@ -62,3 +62,5 @@ interface IRule {
interface IRegexp { interface IRegexp {
raw: string; raw: string;
} }
type UserTheme = "light" | "dark" | "";

View File

@ -1,20 +1,20 @@
const name = window.FileBrowser.Name || "File Browser"; const name: string = window.FileBrowser.Name || "File Browser";
const disableExternal = window.FileBrowser.DisableExternal; const disableExternal: boolean = window.FileBrowser.DisableExternal;
const disableUsedPercentage = window.FileBrowser.DisableUsedPercentage; const disableUsedPercentage: boolean = window.FileBrowser.DisableUsedPercentage;
const baseURL = window.FileBrowser.BaseURL; const baseURL: string = window.FileBrowser.BaseURL;
const staticURL = window.FileBrowser.StaticURL; const staticURL: string = window.FileBrowser.StaticURL;
const recaptcha = window.FileBrowser.ReCaptcha; const recaptcha: string = window.FileBrowser.ReCaptcha;
const recaptchaKey = window.FileBrowser.ReCaptchaKey; const recaptchaKey: string = window.FileBrowser.ReCaptchaKey;
const signup = window.FileBrowser.Signup; const signup: boolean = window.FileBrowser.Signup;
const version = window.FileBrowser.Version; const version: string = window.FileBrowser.Version;
const logoURL = `${staticURL}/img/logo.svg`; const logoURL = `${staticURL}/img/logo.svg`;
const noAuth = window.FileBrowser.NoAuth; const noAuth: boolean = window.FileBrowser.NoAuth;
const authMethod = window.FileBrowser.AuthMethod; const authMethod = window.FileBrowser.AuthMethod;
const loginPage = window.FileBrowser.LoginPage; const loginPage: boolean = window.FileBrowser.LoginPage;
const theme = window.FileBrowser.Theme; const theme: UserTheme = window.FileBrowser.Theme;
const enableThumbs = window.FileBrowser.EnableThumbs; const enableThumbs: boolean = window.FileBrowser.EnableThumbs;
const resizePreview = window.FileBrowser.ResizePreview; const resizePreview: boolean = window.FileBrowser.ResizePreview;
const enableExec = window.FileBrowser.EnableExec; const enableExec: boolean = window.FileBrowser.EnableExec;
const tusSettings = window.FileBrowser.TusSettings; const tusSettings = window.FileBrowser.TusSettings;
const origin = window.location.origin; const origin = window.location.origin;
const tusEndpoint = `/api/tus`; const tusEndpoint = `/api/tus`;

View File

@ -0,0 +1,34 @@
import { theme } from "./constants";
export const getTheme = (): UserTheme => {
return (document.documentElement.className as UserTheme) || theme;
};
export const setTheme = (theme: UserTheme) => {
const html = document.documentElement;
if (!theme) {
html.className = getMediaPreference();
} else {
html.className = theme;
}
};
export const toggleTheme = (): void => {
const activeTheme = getTheme();
if (activeTheme === "light") {
setTheme("dark");
} else {
setTheme("light");
}
};
export const getMediaPreference = (): UserTheme => {
const hasDarkPreference = window.matchMedia(
"(prefers-color-scheme: dark)"
).matches;
if (hasDarkPreference) {
return "dark";
} else {
return "light";
}
};

View File

@ -240,6 +240,7 @@ import Errors from "@/views/Errors.vue";
import { computed, inject, onBeforeUnmount, onMounted, ref } from "vue"; import { computed, inject, onBeforeUnmount, onMounted, ref } from "vue";
import { useI18n } from "vue-i18n"; import { useI18n } from "vue-i18n";
import { StatusError } from "@/api/utils"; import { StatusError } from "@/api/utils";
import { getTheme, setTheme } from "@/utils/theme";
const error = ref<StatusError | null>(null); const error = ref<StatusError | null>(null);
const originalSettings = ref<ISettings | null>(null); const originalSettings = ref<ISettings | null>(null);
@ -264,7 +265,7 @@ const formattedChunkSize = computed({
? formatBytes(settings?.value?.tus?.chunkSize) ? formatBytes(settings?.value?.tus?.chunkSize)
: ""; : "";
}, },
set(value: any) { set(value: string) {
// Use debouncing to allow the user to type freely without // Use debouncing to allow the user to type freely without
// interruption by the formatter // interruption by the formatter
// Clear the previous timeout if it exists // Clear the previous timeout if it exists
@ -323,6 +324,10 @@ const save = async () => {
} }
newSettings.shell = shellValue.value.split("\n"); newSettings.shell = shellValue.value.split("\n");
if (newSettings.branding.theme !== getTheme()) {
setTheme(newSettings.branding.theme);
}
try { try {
await api.update(newSettings); await api.update(newSettings);
$showSuccess(t("settings.settingsUpdated")); $showSuccess(t("settings.settingsUpdated"));