mirror of
https://github.com/monkeytypegame/monkeytype.git
synced 2024-09-20 15:26:15 +08:00
added auto switch theme
allows auto switching between light and dark theme based on system theme closes #2088 and #1629
This commit is contained in:
parent
2c9125124c
commit
775fe34851
|
@ -13,6 +13,9 @@ const CARET_STYLES = [
|
|||
|
||||
const CONFIG_SCHEMA = joi.object({
|
||||
theme: joi.string(),
|
||||
themeLight: joi.string(),
|
||||
themeDark: joi.string(),
|
||||
autoSwitchTheme: joi.boolean(),
|
||||
customTheme: joi.boolean(),
|
||||
customThemeColors: joi
|
||||
.array()
|
||||
|
|
|
@ -24,6 +24,9 @@ let loadDone: (...stuff: any[]) => any;
|
|||
|
||||
const defaultConfig: MonkeyTypes.Config = {
|
||||
theme: "serika_dark",
|
||||
themeLight: "serika",
|
||||
themeDark: "serika_dark",
|
||||
autoSwitchTheme: false,
|
||||
customTheme: false,
|
||||
customThemeColors: [
|
||||
"#323437",
|
||||
|
@ -1036,6 +1039,13 @@ export function setIndicateTypos(
|
|||
ConfigEvent.dispatch("indicateTypos", config.indicateTypos);
|
||||
}
|
||||
|
||||
export function setAutoSwitchTheme(boolean: boolean, nosave?: boolean): void {
|
||||
boolean = boolean ?? defaultConfig.autoSwitchTheme;
|
||||
config.autoSwitchTheme = boolean;
|
||||
if (!nosave) saveToLocalStorage();
|
||||
ConfigEvent.dispatch("autoSwitchTheme", config.autoSwitchTheme);
|
||||
}
|
||||
|
||||
export function setCustomTheme(boolean: boolean, nosave?: boolean): void {
|
||||
if (boolean !== undefined) config.customTheme = boolean;
|
||||
if (!nosave) saveToLocalStorage();
|
||||
|
@ -1049,6 +1059,18 @@ export function setTheme(name: string, nosave?: boolean): void {
|
|||
ConfigEvent.dispatch("theme", config.theme);
|
||||
}
|
||||
|
||||
export function setThemeLight(name: string, nosave?: boolean): void {
|
||||
config.themeLight = name;
|
||||
if (!nosave) saveToLocalStorage();
|
||||
ConfigEvent.dispatch("themeLight", config.themeLight, nosave);
|
||||
}
|
||||
|
||||
export function setThemeDark(name: string, nosave?: boolean): void {
|
||||
config.themeDark = name;
|
||||
if (!nosave) saveToLocalStorage();
|
||||
ConfigEvent.dispatch("themeDark", config.themeDark, nosave);
|
||||
}
|
||||
|
||||
function setThemes(
|
||||
theme: string,
|
||||
customState: boolean,
|
||||
|
@ -1379,6 +1401,9 @@ export function apply(configObj: MonkeyTypes.Config | null | "null"): void {
|
|||
);
|
||||
if (configObj && configObj !== null) {
|
||||
setCustomThemeColors(configObj.customThemeColors, true);
|
||||
setThemeLight(configObj.themeLight, true);
|
||||
setThemeDark(configObj.themeDark, true);
|
||||
setAutoSwitchTheme(configObj.autoSwitchTheme, true);
|
||||
setThemes(configObj.theme, configObj.customTheme, true);
|
||||
// setTheme(configObj.theme, true);
|
||||
// setCustomTheme(configObj.customTheme, true, true);
|
||||
|
|
|
@ -224,7 +224,18 @@ export function applyCustomBackground(): void {
|
|||
}
|
||||
}
|
||||
|
||||
ConfigEvent.subscribe((eventKey, eventValue) => {
|
||||
window
|
||||
.matchMedia("(prefers-color-scheme: dark)")
|
||||
.addEventListener("change", (event) => {
|
||||
if (!Config.autoSwitchTheme || Config.customTheme) return;
|
||||
if (event.matches) {
|
||||
set(Config.themeDark);
|
||||
} else {
|
||||
set(Config.themeLight);
|
||||
}
|
||||
});
|
||||
|
||||
ConfigEvent.subscribe((eventKey, eventValue, nosave) => {
|
||||
if (eventKey === "customTheme")
|
||||
eventValue ? set("custom") : set(Config.theme);
|
||||
if (eventKey === "theme") {
|
||||
|
@ -236,10 +247,55 @@ ConfigEvent.subscribe((eventKey, eventValue) => {
|
|||
if (eventValue) {
|
||||
set("custom");
|
||||
} else {
|
||||
set(Config.theme);
|
||||
if (Config.autoSwitchTheme) {
|
||||
if (
|
||||
window.matchMedia &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
) {
|
||||
set(Config.themeDark);
|
||||
} else {
|
||||
set(Config.themeLight);
|
||||
}
|
||||
} else {
|
||||
set(Config.theme);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (eventKey === "randomTheme" && eventValue === "off") clearRandom();
|
||||
if (eventKey === "customBackground") applyCustomBackground();
|
||||
if (eventKey === "customBackgroundSize") applyCustomBackgroundSize();
|
||||
if (eventKey === "autoSwitchTheme") {
|
||||
if (eventValue) {
|
||||
if (
|
||||
window.matchMedia &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
) {
|
||||
set(Config.themeDark);
|
||||
} else {
|
||||
set(Config.themeLight);
|
||||
}
|
||||
} else {
|
||||
set(Config.theme);
|
||||
}
|
||||
}
|
||||
if (
|
||||
eventKey === "themeLight" &&
|
||||
Config.autoSwitchTheme &&
|
||||
!(
|
||||
window.matchMedia &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches
|
||||
) &&
|
||||
!nosave
|
||||
) {
|
||||
set(Config.themeLight);
|
||||
}
|
||||
if (
|
||||
eventKey === "themeDark" &&
|
||||
Config.autoSwitchTheme &&
|
||||
window.matchMedia &&
|
||||
window.matchMedia("(prefers-color-scheme: dark)").matches &&
|
||||
!nosave
|
||||
) {
|
||||
set(Config.themeDark);
|
||||
}
|
||||
});
|
||||
|
|
|
@ -209,6 +209,11 @@ async function initGroups(): Promise<void> {
|
|||
UpdateConfig.setStartGraphsAtZero,
|
||||
"button"
|
||||
);
|
||||
groups["autoSwitchTheme"] = new SettingsGroup(
|
||||
"autoSwitchTheme",
|
||||
UpdateConfig.setAutoSwitchTheme,
|
||||
"button"
|
||||
);
|
||||
groups["randomTheme"] = new SettingsGroup(
|
||||
"randomTheme",
|
||||
UpdateConfig.setRandomTheme,
|
||||
|
@ -377,9 +382,7 @@ export function reset(): void {
|
|||
$(".pageSettings .section.themes .favThemes.buttons").empty();
|
||||
$(".pageSettings .section.themes .allThemes.buttons").empty();
|
||||
$(".pageSettings .section.languageGroups .buttons").empty();
|
||||
$(".pageSettings .section.layout select").empty().select2("destroy");
|
||||
$(".pageSettings .section.keymapLayout select").empty().select2("destroy");
|
||||
$(".pageSettings .section.language select").empty().select2("destroy");
|
||||
$(".pageSettings select").empty().select2("destroy");
|
||||
$(".pageSettings .section.funbox .buttons").empty();
|
||||
$(".pageSettings .section.fontFamily .buttons").empty();
|
||||
}
|
||||
|
@ -404,7 +407,9 @@ export async function fillSettingsPage(): Promise<void> {
|
|||
langComboBox += `</optgroup>`;
|
||||
languageEl.append(langComboBox);
|
||||
});
|
||||
languageEl.select2();
|
||||
languageEl.select2({
|
||||
width: "100%",
|
||||
});
|
||||
|
||||
const layoutEl = $(".pageSettings .section.layout select").empty();
|
||||
layoutEl.append(`<option value='default'>off</option>`);
|
||||
|
@ -413,7 +418,9 @@ export async function fillSettingsPage(): Promise<void> {
|
|||
`<option value='${layout}'>${layout.replace(/_/g, " ")}</option>`
|
||||
);
|
||||
});
|
||||
layoutEl.select2();
|
||||
layoutEl.select2({
|
||||
width: "100%",
|
||||
});
|
||||
|
||||
const keymapEl = $(".pageSettings .section.keymapLayout select").empty();
|
||||
keymapEl.append(`<option value='overrideSync'>emulator sync</option>`);
|
||||
|
@ -424,7 +431,37 @@ export async function fillSettingsPage(): Promise<void> {
|
|||
);
|
||||
}
|
||||
});
|
||||
keymapEl.select2();
|
||||
keymapEl.select2({
|
||||
width: "100%",
|
||||
});
|
||||
|
||||
const themeEl1 = $(
|
||||
".pageSettings .section.autoSwitchThemeInputs select.light"
|
||||
).empty();
|
||||
const themeEl2 = $(
|
||||
".pageSettings .section.autoSwitchThemeInputs select.dark"
|
||||
).empty();
|
||||
for (const theme of await Misc.getThemesList()) {
|
||||
themeEl1.append(
|
||||
`<option value='${theme.name}'>${theme.name.replace(/_/g, " ")}</option>`
|
||||
);
|
||||
themeEl2.append(
|
||||
`<option value='${theme.name}'>${theme.name.replace(/_/g, " ")}</option>`
|
||||
);
|
||||
}
|
||||
themeEl1.select2({
|
||||
width: "100%",
|
||||
});
|
||||
themeEl2.select2({
|
||||
width: "100%",
|
||||
});
|
||||
|
||||
$(`.pageSettings .section.autoSwitchThemeInputs select.light`)
|
||||
.val(Config.themeLight)
|
||||
.trigger("change.select2");
|
||||
$(`.pageSettings .section.autoSwitchThemeInputs select.dark`)
|
||||
.val(Config.themeDark)
|
||||
.trigger("change.select2");
|
||||
|
||||
const funboxEl = $(".pageSettings .section.funbox .buttons").empty();
|
||||
funboxEl.append(`<div class="funbox button" funbox='none'>none</div>`);
|
||||
|
@ -680,6 +717,12 @@ export function update(): void {
|
|||
$(".pageSettings .section.minBurst input.customMinBurst").val(
|
||||
Config.minBurstCustomSpeed
|
||||
);
|
||||
|
||||
if (Config.autoSwitchTheme) {
|
||||
$(".pageSettings .section.autoSwitchThemeInputs").removeClass("hidden");
|
||||
} else {
|
||||
$(".pageSettings .section.autoSwitchThemeInputs").addClass("hidden");
|
||||
}
|
||||
}
|
||||
|
||||
function toggleSettingsGroup(groupName: string): void {
|
||||
|
@ -954,6 +997,28 @@ $(".quickNav .links a").on("click", (e) => {
|
|||
isOpen && toggleSettingsGroup(settingsGroup);
|
||||
});
|
||||
|
||||
$(document).on(
|
||||
"change",
|
||||
`.pageSettings .section.autoSwitchThemeInputs select.light`,
|
||||
(e) => {
|
||||
const target = $(e.currentTarget);
|
||||
if (target.hasClass("disabled") || target.hasClass("no-auto-handle"))
|
||||
return;
|
||||
UpdateConfig.setThemeLight(target.val() as string);
|
||||
}
|
||||
);
|
||||
|
||||
$(document).on(
|
||||
"change",
|
||||
`.pageSettings .section.autoSwitchThemeInputs select.dark`,
|
||||
(e) => {
|
||||
const target = $(e.currentTarget);
|
||||
if (target.hasClass("disabled") || target.hasClass("no-auto-handle"))
|
||||
return;
|
||||
UpdateConfig.setThemeDark(target.val() as string);
|
||||
}
|
||||
);
|
||||
|
||||
let configEventDisabled = false;
|
||||
export function setEventDisabled(value: boolean): void {
|
||||
configEventDisabled = value;
|
||||
|
|
3
frontend/src/scripts/types/types.d.ts
vendored
3
frontend/src/scripts/types/types.d.ts
vendored
|
@ -229,6 +229,9 @@ declare namespace MonkeyTypes {
|
|||
|
||||
interface Config {
|
||||
theme: string;
|
||||
themeLight: string;
|
||||
themeDark: string;
|
||||
autoSwitchTheme: boolean;
|
||||
customTheme: boolean;
|
||||
customThemeColors: string[];
|
||||
favThemes: string[];
|
||||
|
|
|
@ -85,6 +85,15 @@
|
|||
}
|
||||
}
|
||||
|
||||
&.autoSwitchThemeInputs {
|
||||
grid-template-areas: unset;
|
||||
grid-template-columns: 1fr 3fr 1fr 3fr;
|
||||
gap: 1rem;
|
||||
select {
|
||||
width: 100%;
|
||||
}
|
||||
}
|
||||
|
||||
&.themes .tabContainer [tabcontent="custom"] {
|
||||
label.button:first-child {
|
||||
color: var(--text-color);
|
||||
|
|
|
@ -119,6 +119,11 @@
|
|||
padding: 0.25rem 0;
|
||||
}
|
||||
}
|
||||
.pageSettings {
|
||||
.section.autoSwitchThemeInputs {
|
||||
grid-template-columns: 1fr 3fr;
|
||||
}
|
||||
}
|
||||
.pageAccount {
|
||||
.group.personalBestTables {
|
||||
.tables {
|
||||
|
|
|
@ -3513,6 +3513,38 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section autoSwitchTheme">
|
||||
<h1>auto switch theme</h1>
|
||||
<div class="text">
|
||||
Enabling this will automatically switch the theme between
|
||||
light and dark depending on the system theme (this will not
|
||||
override custom theme).
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<div
|
||||
class="button"
|
||||
autoSwitchTheme="false"
|
||||
tabindex="0"
|
||||
onclick="this.blur();"
|
||||
>
|
||||
off
|
||||
</div>
|
||||
<div
|
||||
class="button"
|
||||
autoSwitchTheme="true"
|
||||
tabindex="0"
|
||||
onclick="this.blur();"
|
||||
>
|
||||
on
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="section autoSwitchThemeInputs">
|
||||
<div>light</div>
|
||||
<div><select class="light"></select></div>
|
||||
<div>dark</div>
|
||||
<div><select class="dark"></select></div>
|
||||
</div>
|
||||
<div class="section randomTheme fullWidth">
|
||||
<h1>randomize theme</h1>
|
||||
<div class="text">
|
||||
|
|
Loading…
Reference in a new issue