Add dark theme to main css (some colors are wrong)
This commit is contained in:
parent
cc16511c36
commit
6332514ccc
@ -181,12 +181,7 @@
|
||||
|
||||
<script type="module" src="/src/main.ts"></script>
|
||||
|
||||
[{[ if .Theme -]}]
|
||||
<link
|
||||
rel="stylesheet"
|
||||
href="[{[ .StaticURL ]}]/themes/[{[ .Theme ]}].css"
|
||||
/>
|
||||
[{[ end ]}] [{[ if .CSS -]}]
|
||||
[{[ if .CSS -]}]
|
||||
<link rel="stylesheet" href="[{[ .StaticURL ]}]/custom.css" />
|
||||
[{[ end ]}]
|
||||
</body>
|
||||
|
||||
@ -5,13 +5,17 @@
|
||||
</template>
|
||||
|
||||
<script setup lang="ts">
|
||||
import { onMounted, watch } from "vue";
|
||||
import { ref, onMounted, watch } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { setHtmlLocale } from "./i18n";
|
||||
import { getMediaPreference, getTheme, setTheme } from "./utils/theme";
|
||||
|
||||
const { locale } = useI18n();
|
||||
|
||||
const userTheme = ref<UserTheme>(getTheme() || getMediaPreference());
|
||||
|
||||
onMounted(() => {
|
||||
setTheme(userTheme.value);
|
||||
setHtmlLocale(locale.value);
|
||||
// this might be null during HMR
|
||||
const loading = document.getElementById("loading");
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
<template>
|
||||
<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>
|
||||
</select>
|
||||
</template>
|
||||
@ -12,7 +13,7 @@ import { useI18n } from "vue-i18n";
|
||||
const { t } = useI18n();
|
||||
|
||||
defineProps<{
|
||||
theme: any;
|
||||
theme: UserTheme;
|
||||
}>();
|
||||
|
||||
const emit = defineEmits<{
|
||||
|
||||
@ -1,16 +1,16 @@
|
||||
.input {
|
||||
background: var(--surfacePrimary);
|
||||
color: var(--textPrimary);
|
||||
border: 1px solid var(--borderPrimary);
|
||||
border-radius: 0.1em;
|
||||
padding: 0.5em 1em;
|
||||
background: white;
|
||||
border: 1px solid rgba(0, 0, 0, 0.1);
|
||||
transition: 0.2s ease all;
|
||||
color: #333;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.input:hover,
|
||||
.input:focus {
|
||||
border-color: rgba(0, 0, 0, 0.2);
|
||||
border-color: var(--borderSecondary);
|
||||
}
|
||||
|
||||
.input--block {
|
||||
@ -27,9 +27,9 @@
|
||||
}
|
||||
|
||||
.input--red {
|
||||
background: #fcd0cd;
|
||||
background: var(--input-red) !important;
|
||||
}
|
||||
|
||||
.input--green {
|
||||
background: #c9f2da;
|
||||
background: var(--input-green) !important;
|
||||
}
|
||||
|
||||
@ -11,4 +11,38 @@
|
||||
--icon-green: #2ecc71;
|
||||
--icon-blue: #1d99f3;
|
||||
--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);
|
||||
}
|
||||
|
||||
@ -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 {
|
||||
background: var(--background);
|
||||
color: var(--textPrimary);
|
||||
color: var(--textSecondary);
|
||||
}
|
||||
|
||||
#loading {
|
||||
@ -18,11 +8,11 @@ body {
|
||||
}
|
||||
#loading .spinner div,
|
||||
main .spinner div {
|
||||
background: var(--icon);
|
||||
background: var(--iconPrimary);
|
||||
}
|
||||
|
||||
#login {
|
||||
background: var(--background);
|
||||
background: var(--surfacePrimary);
|
||||
}
|
||||
|
||||
header {
|
||||
@ -47,20 +37,20 @@ header {
|
||||
color: var(--textPrimary);
|
||||
}
|
||||
#search .boxes {
|
||||
background: var(--surfaceSecondary);
|
||||
background: var(--surfacePrimary);
|
||||
}
|
||||
#search .boxes h3 {
|
||||
color: var(--textPrimary);
|
||||
color: var(--textSecondary);
|
||||
}
|
||||
|
||||
.action {
|
||||
color: var(--textPrimary) !important;
|
||||
color: var(--action) !important;
|
||||
}
|
||||
.action:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
background-color: var(--hover);
|
||||
}
|
||||
.action i {
|
||||
color: var(--icon) !important;
|
||||
color: var(--action) !important;
|
||||
}
|
||||
.action .counter {
|
||||
border-color: var(--surfacePrimary);
|
||||
@ -78,7 +68,7 @@ nav > div {
|
||||
color: var(--textPrimary) !important;
|
||||
}
|
||||
.breadcrumbs a:hover {
|
||||
background-color: rgba(255, 255, 255, 0.1);
|
||||
background-color: var(--hover);
|
||||
}
|
||||
|
||||
#listing .item {
|
||||
@ -87,20 +77,17 @@ nav > div {
|
||||
border-color: var(--divider) !important;
|
||||
}
|
||||
#listing .item i {
|
||||
color: var(--icon);
|
||||
color: var(--iconPrimary);
|
||||
}
|
||||
#listing .item .modified {
|
||||
color: var(--textSecondary);
|
||||
#listing .item[aria-selected="true"] i {
|
||||
color: var(--iconSecondary);
|
||||
}
|
||||
#listing h2,
|
||||
#listing.list .header span {
|
||||
color: var(--textPrimary) !important;
|
||||
}
|
||||
#listing.list .header span {
|
||||
color: var(--textPrimary);
|
||||
}
|
||||
#listing.list .header i {
|
||||
color: var(--icon);
|
||||
color: var(--textPrimary);
|
||||
}
|
||||
#listing.list .item.header {
|
||||
background: var(--background);
|
||||
@ -112,14 +99,14 @@ nav > div {
|
||||
|
||||
.card {
|
||||
background: var(--surfacePrimary);
|
||||
color: var(--textPrimary);
|
||||
color: var(--textSecondary);
|
||||
}
|
||||
.button--flat:hover {
|
||||
background: var(--surfaceSecondary);
|
||||
}
|
||||
|
||||
.dashboard #nav ul li {
|
||||
color: var(--textSecondary);
|
||||
color: var(--action);
|
||||
}
|
||||
.dashboard #nav ul li:hover {
|
||||
background: var(--surfaceSecondary);
|
||||
@ -131,22 +118,10 @@ nav > div {
|
||||
color: var(--textPrimary);
|
||||
}
|
||||
.card#share input,
|
||||
.card#share select,
|
||||
.input {
|
||||
background: var(--surfaceSecondary);
|
||||
.card#share select {
|
||||
background: var(--surfacePrimary);
|
||||
color: var(--textPrimary);
|
||||
border: 1px solid rgba(255, 255, 255, 0.05);
|
||||
}
|
||||
.input:hover,
|
||||
.input:focus {
|
||||
border-color: rgba(255, 255, 255, 0.15);
|
||||
}
|
||||
.input--red {
|
||||
background: #73302d;
|
||||
}
|
||||
|
||||
.input--green {
|
||||
background: #147a41;
|
||||
border: 1px solid var(--borderPrimary);
|
||||
}
|
||||
|
||||
.dashboard #nav .wrapper,
|
||||
@ -168,7 +143,7 @@ table th {
|
||||
color: var(--textSecondary);
|
||||
}
|
||||
.file-list li[aria-selected="true"]:before {
|
||||
color: var(--icon);
|
||||
color: var(--iconSecondary);
|
||||
}
|
||||
|
||||
.shell {
|
||||
@ -14,6 +14,7 @@
|
||||
@import "./dashboard.css";
|
||||
@import "./login.css";
|
||||
@import "./mobile.css";
|
||||
@import "./dark.css";
|
||||
|
||||
.link {
|
||||
color: var(--blue);
|
||||
|
||||
@ -239,6 +239,7 @@
|
||||
"shareDeleted": "Share deleted!",
|
||||
"singleClick": "Use single clicks to open files and directories",
|
||||
"themes": {
|
||||
"default": "System default",
|
||||
"dark": "Dark",
|
||||
"light": "Light",
|
||||
"title": "Theme"
|
||||
|
||||
2
frontend/src/types/settings.d.ts
vendored
2
frontend/src/types/settings.d.ts
vendored
@ -27,7 +27,7 @@ interface SettingsBranding {
|
||||
disableExternal: boolean;
|
||||
disableUsedPercentage: boolean;
|
||||
files: string;
|
||||
theme: string;
|
||||
theme: UserTheme;
|
||||
color: string;
|
||||
}
|
||||
|
||||
|
||||
2
frontend/src/types/user.d.ts
vendored
2
frontend/src/types/user.d.ts
vendored
@ -62,3 +62,5 @@ interface IRule {
|
||||
interface IRegexp {
|
||||
raw: string;
|
||||
}
|
||||
|
||||
type UserTheme = "light" | "dark" | "";
|
||||
|
||||
@ -1,20 +1,20 @@
|
||||
const name = window.FileBrowser.Name || "File Browser";
|
||||
const disableExternal = window.FileBrowser.DisableExternal;
|
||||
const disableUsedPercentage = window.FileBrowser.DisableUsedPercentage;
|
||||
const baseURL = window.FileBrowser.BaseURL;
|
||||
const staticURL = window.FileBrowser.StaticURL;
|
||||
const recaptcha = window.FileBrowser.ReCaptcha;
|
||||
const recaptchaKey = window.FileBrowser.ReCaptchaKey;
|
||||
const signup = window.FileBrowser.Signup;
|
||||
const version = window.FileBrowser.Version;
|
||||
const name: string = window.FileBrowser.Name || "File Browser";
|
||||
const disableExternal: boolean = window.FileBrowser.DisableExternal;
|
||||
const disableUsedPercentage: boolean = window.FileBrowser.DisableUsedPercentage;
|
||||
const baseURL: string = window.FileBrowser.BaseURL;
|
||||
const staticURL: string = window.FileBrowser.StaticURL;
|
||||
const recaptcha: string = window.FileBrowser.ReCaptcha;
|
||||
const recaptchaKey: string = window.FileBrowser.ReCaptchaKey;
|
||||
const signup: boolean = window.FileBrowser.Signup;
|
||||
const version: string = window.FileBrowser.Version;
|
||||
const logoURL = `${staticURL}/img/logo.svg`;
|
||||
const noAuth = window.FileBrowser.NoAuth;
|
||||
const noAuth: boolean = window.FileBrowser.NoAuth;
|
||||
const authMethod = window.FileBrowser.AuthMethod;
|
||||
const loginPage = window.FileBrowser.LoginPage;
|
||||
const theme = window.FileBrowser.Theme;
|
||||
const enableThumbs = window.FileBrowser.EnableThumbs;
|
||||
const resizePreview = window.FileBrowser.ResizePreview;
|
||||
const enableExec = window.FileBrowser.EnableExec;
|
||||
const loginPage: boolean = window.FileBrowser.LoginPage;
|
||||
const theme: UserTheme = window.FileBrowser.Theme;
|
||||
const enableThumbs: boolean = window.FileBrowser.EnableThumbs;
|
||||
const resizePreview: boolean = window.FileBrowser.ResizePreview;
|
||||
const enableExec: boolean = window.FileBrowser.EnableExec;
|
||||
const tusSettings = window.FileBrowser.TusSettings;
|
||||
const origin = window.location.origin;
|
||||
const tusEndpoint = `/api/tus`;
|
||||
|
||||
34
frontend/src/utils/theme.ts
Normal file
34
frontend/src/utils/theme.ts
Normal 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";
|
||||
}
|
||||
};
|
||||
@ -240,6 +240,7 @@ import Errors from "@/views/Errors.vue";
|
||||
import { computed, inject, onBeforeUnmount, onMounted, ref } from "vue";
|
||||
import { useI18n } from "vue-i18n";
|
||||
import { StatusError } from "@/api/utils";
|
||||
import { getTheme, setTheme } from "@/utils/theme";
|
||||
|
||||
const error = ref<StatusError | null>(null);
|
||||
const originalSettings = ref<ISettings | null>(null);
|
||||
@ -264,7 +265,7 @@ const formattedChunkSize = computed({
|
||||
? formatBytes(settings?.value?.tus?.chunkSize)
|
||||
: "";
|
||||
},
|
||||
set(value: any) {
|
||||
set(value: string) {
|
||||
// Use debouncing to allow the user to type freely without
|
||||
// interruption by the formatter
|
||||
// Clear the previous timeout if it exists
|
||||
@ -323,6 +324,10 @@ const save = async () => {
|
||||
}
|
||||
newSettings.shell = shellValue.value.split("\n");
|
||||
|
||||
if (newSettings.branding.theme !== getTheme()) {
|
||||
setTheme(newSettings.branding.theme);
|
||||
}
|
||||
|
||||
try {
|
||||
await api.update(newSettings);
|
||||
$showSuccess(t("settings.settingsUpdated"));
|
||||
|
||||
Loading…
Reference in New Issue
Block a user