Add support for System theme - dynamic switching between Light and Dark themes (#405)

* add support for system theme

* add EN texts
This commit is contained in:
Ilya Popovs 2022-08-30 14:33:49 +03:00 committed by GitHub
parent 717a2ace25
commit eaa57925ff
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
12 changed files with 229 additions and 63 deletions

View file

@ -227,6 +227,9 @@
"darkLabel": { "darkLabel": {
"message": "Dark" "message": "Dark"
}, },
"systemLabel": {
"message": "System"
},
"buttonStyleLabel": { "buttonStyleLabel": {
"message": "Translation button" "message": "Translation button"
}, },
@ -299,6 +302,9 @@
"resultFontColorLabel": { "resultFontColorLabel": {
"message": "Font color of translation result" "message": "Font color of translation result"
}, },
"isOverrideColorsLabel": {
"message": "Override default colors with colors below"
},
"candidateFontColorLabel": { "candidateFontColorLabel": {
"message": "Font color of translation candidates" "message": "Font color of translation candidates"
}, },

View file

@ -3,6 +3,7 @@ import React, { Component } from "react";
import ReactDOM from "react-dom"; import ReactDOM from "react-dom";
import { getSettings } from "src/settings/settings"; import { getSettings } from "src/settings/settings";
import "../styles/TranslatePanel.scss"; import "../styles/TranslatePanel.scss";
import { getBackgroundColor, getCandidateFontColor, getResultFontColor } from "../../settings/defaultColors";
const splitLine = text => { const splitLine = text => {
const regex = /(\n)/g; const regex = /(\n)/g;
@ -173,17 +174,17 @@ export default class TranslatePanel extends Component {
top: this.state.panelPosition.y, top: this.state.panelPosition.y,
left: this.state.panelPosition.x, left: this.state.panelPosition.x,
fontSize: parseInt(getSettings("fontSize")), fontSize: parseInt(getSettings("fontSize")),
backgroundColor: getSettings("bgColor")
}; };
const backgroundColor = getBackgroundColor()
if (backgroundColor) {
panelStyles.backgroundColor = backgroundColor.backgroundColor
}
const wrapperStyles = { const wrapperStyles = {
overflow: this.state.isOverflow ? "auto" : "hidden" overflow: this.state.isOverflow ? "auto" : "hidden"
}; };
const resultStyles = {
color: getSettings("resultFontColor")
};
const candidateStyles = {
color: getSettings("candidateFontColor")
};
const translationApi = getSettings("translationApi"); const translationApi = getSettings("translationApi");
return ( return (
@ -195,10 +196,10 @@ export default class TranslatePanel extends Component {
<div className="simple-translate-result-wrapper" ref="wrapper" style={wrapperStyles}> <div className="simple-translate-result-wrapper" ref="wrapper" style={wrapperStyles}>
<div className="simple-translate-move" draggable="true" ref="move"></div> <div className="simple-translate-move" draggable="true" ref="move"></div>
<div className="simple-translate-result-contents"> <div className="simple-translate-result-contents">
<p className="simple-translate-result" style={resultStyles} dir="auto"> <p className="simple-translate-result" style={getResultFontColor()} dir="auto">
{splitLine(resultText)} {splitLine(resultText)}
</p> </p>
<p className="simple-translate-candidate" style={candidateStyles} dir="auto"> <p className="simple-translate-candidate" style={getCandidateFontColor()} dir="auto">
{splitLine(candidateText)} {splitLine(candidateText)}
</p> </p>
{isError && ( {isError && (

View file

@ -216,7 +216,9 @@ const showTranslateContainer = (
if (element) return; if (element) return;
if (!isEnabled) return; if (!isEnabled) return;
document.body.insertAdjacentHTML("beforeend", "<div id='simple-translate'></div>"); const themeClass = getSettings("theme") + "-theme";
document.body.insertAdjacentHTML("beforeend", `<div id="simple-translate" class="${themeClass}"></div>`);
ReactDOM.render( ReactDOM.render(
<TranslateContainer <TranslateContainer
removeContainer={removeTranslatecontainer} removeContainer={removeTranslatecontainer}

View file

@ -1,7 +1,7 @@
#simple-translate { #simple-translate {
.simple-translate-button { .simple-translate-button {
all: initial; all: initial;
background-color: #fff; background-color: var(--simple-translate-main-bg);
box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08); box-shadow: 0 2px 2px 0 rgba(0, 0, 0, 0.16), 0 0 0 1px rgba(0, 0, 0, 0.08);
border-radius: 10%; border-radius: 10%;
background-size: 75%; background-size: 75%;

View file

@ -5,10 +5,35 @@
} }
position: absolute; position: absolute;
--simple-translate-main-text: #0c0c0d;
--simple-translate-sub-text: #737373;
--simple-translate-line: #ededf0; --simple-translate-line: #ededf0;
--simple-translate-button: #d7d7db; --simple-translate-button: #d7d7db;
--simple-translate-highlight: #5595ff; --simple-translate-highlight: #5595ff;
}
.light-theme {
--simple-translate-main-text: #0c0c0d;
--simple-translate-sub-text: #737373;
--simple-translate-main-bg: #ffffff; --simple-translate-main-bg: #ffffff;
} }
.dark-theme {
--simple-translate-main-text: #e6e6e6;
--simple-translate-sub-text: #aaaaaa;
--simple-translate-main-bg: #181818;
}
// copy of .light-theme
.system-theme {
--simple-translate-main-text: #000000;
--simple-translate-sub-text: #737373;
--simple-translate-main-bg: #ffffff;
}
@media (prefers-color-scheme: dark) {
// copy of .dark-theme
.system-theme {
--simple-translate-main-text: #e6e6e6;
--simple-translate-sub-text: #aaaaaa;
--simple-translate-main-bg: #181818;
}
}

View file

@ -44,8 +44,8 @@
all: initial; all: initial;
display: block; display: block;
margin: 0; margin: 0;
font-family: "Segoe UI", "San Francisco", "Ubuntu", "Fira Sans", "Roboto", "Arial", font-family: "Segoe UI", "San Francisco", "Ubuntu", "Fira Sans",
"Helvetica", sans-serif !important; "Roboto", "Arial", "Helvetica", sans-serif !important;
word-wrap: break-word; word-wrap: break-word;
font-size: inherit; font-size: inherit;
line-height: 150%; line-height: 150%;
@ -62,11 +62,11 @@
background: var(--simple-translate-line); background: var(--simple-translate-line);
} }
&.simple-translate-result { .simple-translate-result {
color: var(--simple-translate-main-text); color: var(--simple-translate-main-text);
} }
&.simple-translate-candidate, .simple-translate-candidate,
&.simple-translate-error { .simple-translate-error {
color: var(--simple-translate-sub-text); color: var(--simple-translate-sub-text);
margin-top: 1em; margin-top: 1em;
&:empty { &:empty {

View file

@ -9,11 +9,16 @@ import "../styles/OptionsPage.scss";
const setupTheme = async () => { const setupTheme = async () => {
await initSettings(); await initSettings();
document.body.dataset.theme = getSettings("theme"); document.body.classList.add(getSettings("theme") + "-theme");
browser.storage.onChanged.addListener((changes) => { browser.storage.onChanged.addListener((changes) => {
if (changes.Settings.newValue.theme === changes.Settings.oldValue.theme) return; if (changes.Settings.newValue.theme === changes.Settings.oldValue.theme)
document.body.dataset.theme = changes.Settings.newValue.theme; return;
document.body.classList.replace(
changes.Settings.oldValue.theme + "-theme",
changes.Settings.newValue.theme + "-theme"
);
}); });
}; };

View file

@ -1,6 +1,4 @@
body { .light-theme {
background-color: var(--main-bg);
--main-text: #0c0c0d; --main-text: #0c0c0d;
--sub-text: #737373; --sub-text: #737373;
--line: #ededf0; --line: #ededf0;
@ -9,8 +7,32 @@ body {
--main-bg: #ffffff; --main-bg: #ffffff;
--sub-bg: #ffffff; --sub-bg: #ffffff;
--new: #ff4f4f; --new: #ff4f4f;
}
&[data-theme="dark"] { .dark-theme {
--main-text: #e6e6e6;
--sub-text: #aaaaaa;
--line: #373737;
--button: #929292;
--highlight: #5595ff;
--main-bg: #181818;
--sub-bg: #101010;
--new: #ed5f5f;
}
.system-theme {
--main-text: #0c0c0d;
--sub-text: #737373;
--line: #ededf0;
--button: #d7d7db;
--highlight: #5595ff;
--main-bg: #ffffff;
--sub-bg: #ffffff;
--new: #ff4f4f;
}
@media (prefers-color-scheme: dark) {
.system-theme {
--main-text: #e6e6e6; --main-text: #e6e6e6;
--sub-text: #aaaaaa; --sub-text: #aaaaaa;
--line: #373737; --line: #373737;
@ -22,9 +44,13 @@ body {
} }
} }
body {
background-color: var(--main-bg);
}
.optionsPage { .optionsPage {
font-family: "Segoe UI", "San Francisco", "Ubuntu", "Fira Sans", "Roboto", "Arial", "Helvetica", font-family: "Segoe UI", "San Francisco", "Ubuntu", "Fira Sans", "Roboto",
sans-serif; "Arial", "Helvetica", sans-serif;
font-size: 15px; font-size: 15px;
font-weight: 400; font-weight: 400;
color: var(--main-text); color: var(--main-text);

View file

@ -10,6 +10,7 @@ import InputArea from "./InputArea";
import ResultArea from "./ResultArea"; import ResultArea from "./ResultArea";
import Footer from "./Footer"; import Footer from "./Footer";
import "../styles/PopupPage.scss"; import "../styles/PopupPage.scss";
import { getBackgroundColor } from "../../settings/defaultColors";
const logDir = "popup/PopupPage"; const logDir = "popup/PopupPage";
@ -58,7 +59,8 @@ export default class PopupPage extends Component {
overWriteLogLevel(); overWriteLogLevel();
updateLogLevel(); updateLogLevel();
document.body.dataset.theme = getSettings("theme"); this.themeClass = getSettings("theme") + "-theme";
document.body.classList.add(this.themeClass)
const targetLang = getSettings("targetLang"); const targetLang = getSettings("targetLang");
let langHistory = getSettings("langHistory"); let langHistory = getSettings("langHistory");
if (!langHistory) { if (!langHistory) {

View file

@ -1,11 +1,71 @@
.light-theme {
--main-text: #0c0c0d;
--sub-text: #737373;
--line: #ededf0;
--button: #d7d7db;
--highlight: #5595ff;
--main-bg: #ffffff;
--confirm: #ff4f4f;
--error: #d70022;
--warn: #ff8f00;
--success: #058b00;
--info: #0a84ff;
}
.dark-theme {
--main-text: #e6e6e6;
--sub-text: #aaaaaa;
--line: #373737;
--button: #929292;
--highlight: #5595ff;
--main-bg: #181818;
--highlight-bg: #2e4343;
--confirm: #ed5f5f;
--error: #ca1532;
--warn: #ee8e12;
--success: #2a9c26;
--info: #1471d0;
}
.system-theme {
--main-text: #0c0c0d;
--sub-text: #737373;
--line: #ededf0;
--button: #d7d7db;
--highlight: #5595ff;
--main-bg: #ffffff;
--confirm: #ff4f4f;
--error: #d70022;
--warn: #ff8f00;
--success: #058b00;
--info: #0a84ff;
}
@media (prefers-color-scheme: dark) {
.system-theme {
--main-text: #e6e6e6;
--sub-text: #aaaaaa;
--line: #373737;
--button: #929292;
--highlight: #5595ff;
--main-bg: #181818;
--highlight-bg: #2e4343;
--confirm: #ed5f5f;
--error: #ca1532;
--warn: #ee8e12;
--success: #2a9c26;
--info: #1471d0;
}
}
html { html {
scrollbar-width: none; scrollbar-width: none;
} }
body { body {
margin: 0; margin: 0;
font-family: "Segoe UI", "San Francisco", "Ubuntu", "Fira Sans", "Roboto", "Arial", "Helvetica", font-family: "Segoe UI", "San Francisco", "Ubuntu", "Fira Sans", "Roboto",
sans-serif; "Arial", "Helvetica", sans-serif;
font-size: 13px; font-size: 13px;
width: 100%; width: 100%;
min-width: 348px; min-width: 348px;
@ -26,31 +86,4 @@ body {
::-moz-selection { ::-moz-selection {
background: var(--line); background: var(--line);
} }
--main-text: #0c0c0d;
--sub-text: #737373;
--line: #ededf0;
--button: #d7d7db;
--highlight: #5595ff;
--main-bg: #ffffff;
--confirm: #ff4f4f;
--error: #d70022;
--warn: #ff8f00;
--success: #058b00;
--info: #0a84ff;
&[data-theme="dark"] {
--main-text: #e6e6e6;
--sub-text: #aaaaaa;
--line: #373737;
--button: #929292;
--highlight: #5595ff;
--main-bg: #181818;
--highlight-bg: #2e4343;
--confirm: #ed5f5f;
--error: #ca1532;
--warn: #ee8e12;
--success: #2a9c26;
--info: #1471d0;
}
} }

View file

@ -0,0 +1,41 @@
import { getSettings } from "./settings";
export const RESULT_FONT_COLOR_LIGHT = "#000000";
export const RESULT_FONT_COLOR_DARK = "#e6e6e6";
export const CANDIDATE_FONT_COLOR_LIGHT = "#737373";
export const CANDIDATE_FONT_COLOR_DARK = "#aaaaaa";
export const BG_COLOR_LIGHT = "#ffffff";
export const BG_COLOR_DARK = "#181818";
/**
* Return style object if color override is enabled
*/
export function getResultFontColor() {
const isOverrideColors = getSettings("isOverrideColors");
if (!isOverrideColors) return undefined;
return { color: getSettings("resultFontColor") };
}
/**
* Return style object if color override is enabled
*/
export function getCandidateFontColor() {
const isOverrideColors = getSettings("isOverrideColors");
if (!isOverrideColors) return undefined;
return { color: getSettings("candidateFontColor") };
}
/**
* Return style object if color override is enabled
*/
export function getBackgroundColor() {
const isOverrideColors = getSettings("isOverrideColors");
if (!isOverrideColors) return undefined;
return { backgroundColor: getSettings("bgColor") };
}

View file

@ -2,6 +2,14 @@ import React from "react";
import browser from "webextension-polyfill"; import browser from "webextension-polyfill";
import generateLangOptions from "src/common/generateLangOptions"; import generateLangOptions from "src/common/generateLangOptions";
import { getSettings, setSettings } from "./settings"; import { getSettings, setSettings } from "./settings";
import {
RESULT_FONT_COLOR_LIGHT,
RESULT_FONT_COLOR_DARK,
CANDIDATE_FONT_COLOR_LIGHT,
CANDIDATE_FONT_COLOR_DARK,
BG_COLOR_LIGHT,
BG_COLOR_DARK
} from "./defaultColors"
const getDefaultLangs = () => { const getDefaultLangs = () => {
const uiLang = browser.i18n.getUILanguage(); const uiLang = browser.i18n.getUILanguage();
@ -300,7 +308,7 @@ export default [
title: "themeLabel", title: "themeLabel",
captions: ["themeCaptionLabel"], captions: ["themeCaptionLabel"],
type: "select", type: "select",
default: getTheme(), default: 'system',
options: [ options: [
{ {
name: "lightLabel", name: "lightLabel",
@ -309,6 +317,10 @@ export default [
{ {
name: "darkLabel", name: "darkLabel",
value: "dark" value: "dark"
},
{
name: "systemLabel",
value: "system"
} }
] ]
}, },
@ -479,27 +491,40 @@ export default [
default: 10, default: 10,
placeholder: 10 placeholder: 10
}, },
{
id: "isOverrideColors",
title: "isOverrideColorsLabel",
captions: [],
type: "checkbox",
default: false
},
{ {
id: "resultFontColor", id: "resultFontColor",
title: "resultFontColorLabel", title: "resultFontColorLabel",
captions: [], captions: [],
type: "color", type: "color",
default: getTheme() === "light" ? "#000000" : "#e6e6e6" default:
getTheme() === "light"
? RESULT_FONT_COLOR_LIGHT
: RESULT_FONT_COLOR_DARK,
}, },
{ {
id: "candidateFontColor", id: "candidateFontColor",
title: "candidateFontColorLabel", title: "candidateFontColorLabel",
captions: [], captions: [],
type: "color", type: "color",
default: getTheme() === "light" ? "#737373" : "#aaaaaa" default:
getTheme() === "light"
? CANDIDATE_FONT_COLOR_LIGHT
: CANDIDATE_FONT_COLOR_DARK,
}, },
{ {
id: "bgColor", id: "bgColor",
title: "bgColorLabel", title: "bgColorLabel",
captions: [], captions: [],
type: "color", type: "color",
default: getTheme() === "light" ? "#ffffff" : "#181818" default: getTheme() === "light" ? BG_COLOR_LIGHT : BG_COLOR_DARK,
} },
] ]
} }
] ]