summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorpsvenk <45520974+psvenk@users.noreply.github.com>2019-08-15 16:29:55 +0000
committerOmar Roth <omarroth@protonmail.com>2019-08-15 11:29:55 -0500
commitf54fbd057ebb8d1e9631782b6d182b403598648f (patch)
treefb2e56fed7d71bbcdeff59b711803057af330ca9
parent19eceb4ecc8b8261c6268f82b8c5d550604e9f4f (diff)
downloadinvidious-f54fbd057ebb8d1e9631782b6d182b403598648f.tar.gz
invidious-f54fbd057ebb8d1e9631782b6d182b403598648f.tar.bz2
invidious-f54fbd057ebb8d1e9631782b6d182b403598648f.zip
Add prefers-color-scheme support (#601)
* Add prefers-color-scheme support This should fix <https://github.com/omarroth/invidious/issues/559>. The cookie storage format has been changed from boolean ("true"/"false") to tri-state ("dark"/"light"/""), so that users without a cookie set will get dark mode if they have enabled the dark theme in their operating system. The code for handling the cookie state, along with the user's operating system theme, has been factored out into a new function `update_mode`, which is called both at window load and at the "storage" event listener, because the "storage" event listener is only trigerred when a change is made to the localStorage from another tab/window (for more info - see <https://stackoverflow.com/a/4679754>).
-rw-r--r--assets/js/themes.js37
-rw-r--r--locales/ar.json4
-rw-r--r--locales/de.json4
-rw-r--r--locales/el.json4
-rw-r--r--locales/en-US.json4
-rw-r--r--locales/eo.json4
-rw-r--r--locales/es.json4
-rw-r--r--locales/eu.json4
-rw-r--r--locales/fr.json4
-rw-r--r--locales/is.json4
-rw-r--r--locales/it.json4
-rw-r--r--locales/nb_NO.json4
-rw-r--r--locales/nl.json4
-rw-r--r--locales/pl.json4
-rw-r--r--locales/ru.json4
-rw-r--r--locales/uk.json4
-rw-r--r--locales/zh-CN.json4
-rw-r--r--src/invidious.cr30
-rw-r--r--src/invidious/helpers/helpers.cr74
-rw-r--r--src/invidious/helpers/patch_mapping.cr2
-rw-r--r--src/invidious/helpers/utils.cr13
-rw-r--r--src/invidious/users.cr62
-rw-r--r--src/invidious/views/preferences.ecr8
-rw-r--r--src/invidious/views/template.ecr9
24 files changed, 215 insertions, 84 deletions
diff --git a/assets/js/themes.js b/assets/js/themes.js
index 683aea39..90a05c36 100644
--- a/assets/js/themes.js
+++ b/assets/js/themes.js
@@ -1,8 +1,8 @@
-var toggle_theme = document.getElementById('toggle_theme')
+var toggle_theme = document.getElementById('toggle_theme');
toggle_theme.href = 'javascript:void(0);';
toggle_theme.addEventListener('click', function () {
- var dark_mode = document.getElementById('dark_theme').media == 'none';
+ var dark_mode = document.getElementById('dark_theme').media === 'none';
var url = '/toggle_theme?redirect=false';
var xhr = new XMLHttpRequest();
@@ -11,19 +11,24 @@ toggle_theme.addEventListener('click', function () {
xhr.open('GET', url, true);
set_mode(dark_mode);
- localStorage.setItem('dark_mode', dark_mode);
+ window.localStorage.setItem('dark_mode', dark_mode ? 'dark' : 'light');
xhr.send();
});
window.addEventListener('storage', function (e) {
- if (e.key == 'dark_mode') {
- var dark_mode = e.newValue === 'true';
- set_mode(dark_mode);
+ if (e.key === 'dark_mode') {
+ update_mode(e.newValue);
}
});
-function set_mode(bool) {
+window.addEventListener('load', function () {
+ window.localStorage.setItem('dark_mode', document.getElementById('dark_mode_pref').textContent);
+ // Update localStorage if dark mode preference changed on preferences page
+ update_mode(window.localStorage.dark_mode);
+});
+
+function set_mode (bool) {
document.getElementById('dark_theme').media = !bool ? 'none' : '';
document.getElementById('light_theme').media = bool ? 'none' : '';
@@ -33,3 +38,21 @@ function set_mode(bool) {
toggle_theme.children[0].setAttribute('class', 'icon ion-ios-moon');
}
}
+
+function update_mode (mode) {
+ if (mode === 'true' /* for backwards compatibility */ || mode === 'dark') {
+ // If preference for dark mode indicated
+ set_mode(true);
+ }
+ else if (mode === 'false' /* for backwards compaibility */ || mode === 'light') {
+ // If preference for light mode indicated
+ set_mode(false);
+ }
+ else if (document.getElementById('dark_mode_pref').textContent === '' && window.matchMedia('(prefers-color-scheme: dark)').matches) {
+ // If no preference indicated here and no preference indicated on the preferences page (backend), but the browser tells us that the operating system has a dark theme
+ set_mode(true);
+ }
+ // else do nothing, falling back to the mode defined by the `dark_mode` preference on the preferences page (backend)
+}
+
+
diff --git a/locales/ar.json b/locales/ar.json
index e3716008..f2ed450c 100644
--- a/locales/ar.json
+++ b/locales/ar.json
@@ -68,7 +68,11 @@
"Show related videos: ": "عرض مقاطع الفيديو ذات الصلة؟",
"Show annotations by default: ": "عرض الملاحظات فى الفيديو تلقائيا ؟",
"Visual preferences": "التفضيلات المرئية",
+ "Player style: ": "",
"Dark mode: ": "الوضع الليلى: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "الوضع الخفيف: ",
"Subscription preferences": "تفضيلات الإشتراك",
"Show annotations by default for subscribed channels: ": "عرض الملاحظات فى الفيديوهات تلقائيا فى القنوات المشترك بها فقط ؟",
diff --git a/locales/de.json b/locales/de.json
index 33edb706..e0ef9d67 100644
--- a/locales/de.json
+++ b/locales/de.json
@@ -68,7 +68,11 @@
"Show related videos: ": "Ähnliche Videos anzeigen? ",
"Show annotations by default: ": "Standardmäßig Anmerkungen anzeigen? ",
"Visual preferences": "Anzeigeeinstellungen",
+ "Player style: ": "",
"Dark mode: ": "Nachtmodus: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Schlanker Modus: ",
"Subscription preferences": "Abonnementeinstellungen",
"Show annotations by default for subscribed channels: ": "Anmerkungen für abonnierte Kanäle standardmäßig anzeigen? ",
diff --git a/locales/el.json b/locales/el.json
index 03d25533..32f154a1 100644
--- a/locales/el.json
+++ b/locales/el.json
@@ -74,7 +74,11 @@
"Show related videos: ": "Προβολή σχετικών βίντεο; ",
"Show annotations by default: ": "Αυτόματη προβολή σημειώσεων; :",
"Visual preferences": "Προτιμήσεις εμφάνισης",
+ "Player style: ": "",
"Dark mode: ": "Σκοτεινή λειτουργία: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Ελαφριά λειτουργία: ",
"Subscription preferences": "Προτιμήσεις συνδρομών",
"Show annotations by default for subscribed channels: ": "Προβολή σημειώσεων μόνο για κανάλια στα οποία είστε συνδρομητής; ",
diff --git a/locales/en-US.json b/locales/en-US.json
index 16301b1d..580d9ead 100644
--- a/locales/en-US.json
+++ b/locales/en-US.json
@@ -74,7 +74,11 @@
"Show related videos: ": "Show related videos: ",
"Show annotations by default: ": "Show annotations by default: ",
"Visual preferences": "Visual preferences",
+ "Player style: ": "",
"Dark mode: ": "Dark mode: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Thin mode: ",
"Subscription preferences": "Subscription preferences",
"Show annotations by default for subscribed channels: ": "Show annotations by default for subscribed channels? ",
diff --git a/locales/eo.json b/locales/eo.json
index fe85edf2..2c22af59 100644
--- a/locales/eo.json
+++ b/locales/eo.json
@@ -68,7 +68,11 @@
"Show related videos: ": "Ĉu montri rilatajn videojn? ",
"Show annotations by default: ": "Ĉu montri prinotojn defaŭlte? ",
"Visual preferences": "Vidaj preferoj",
+ "Player style: ": "",
"Dark mode: ": "Malhela reĝimo: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Maldika reĝimo: ",
"Subscription preferences": "Abonaj agordoj",
"Show annotations by default for subscribed channels: ": "Ĉu montri prinotojn defaŭlte por abonitaj kanaloj? ",
diff --git a/locales/es.json b/locales/es.json
index fdbf2fb2..5860b882 100644
--- a/locales/es.json
+++ b/locales/es.json
@@ -68,7 +68,11 @@
"Show related videos: ": "¿Mostrar vídeos relacionados? ",
"Show annotations by default: ": "¿Mostrar anotaciones por defecto? ",
"Visual preferences": "Preferencias visuales",
+ "Player style: ": "",
"Dark mode: ": "Modo oscuro: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Modo compacto: ",
"Subscription preferences": "Preferencias de la suscripción",
"Show annotations by default for subscribed channels: ": "¿Mostrar anotaciones por defecto para los canales suscritos? ",
diff --git a/locales/eu.json b/locales/eu.json
index 5a756154..cbdbbefc 100644
--- a/locales/eu.json
+++ b/locales/eu.json
@@ -68,7 +68,11 @@
"Show related videos: ": "",
"Show annotations by default: ": "",
"Visual preferences": "",
+ "Player style: ": "",
"Dark mode: ": "",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "",
"Subscription preferences": "",
"Show annotations by default for subscribed channels: ": "",
diff --git a/locales/fr.json b/locales/fr.json
index 37a773f1..af561a0c 100644
--- a/locales/fr.json
+++ b/locales/fr.json
@@ -68,7 +68,11 @@
"Show related videos: ": "Voir les vidéos liées : ",
"Show annotations by default: ": "Voir les annotations par défaut : ",
"Visual preferences": "Préférences du site",
+ "Player style: ": "",
"Dark mode: ": "Mode Sombre : ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Mode Simplifié : ",
"Subscription preferences": "Préférences de la page d'abonnements",
"Show annotations by default for subscribed channels: ": "Voir les annotations par défaut sur les chaînes suivies : ",
diff --git a/locales/is.json b/locales/is.json
index 43ba26e9..808063c4 100644
--- a/locales/is.json
+++ b/locales/is.json
@@ -68,7 +68,11 @@
"Show related videos: ": "Sýna tengd myndbönd? ",
"Show annotations by default: ": "Á að sýna glósur sjálfgefið? ",
"Visual preferences": "Sjónrænar stillingar",
+ "Player style: ": "",
"Dark mode: ": "Myrkur ham: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Þunnt ham: ",
"Subscription preferences": "Áskriftarstillingar",
"Show annotations by default for subscribed channels: ": "Á að sýna glósur sjálfgefið fyrir áskriftarrásir? ",
diff --git a/locales/it.json b/locales/it.json
index bf028c91..7f532d0d 100644
--- a/locales/it.json
+++ b/locales/it.json
@@ -68,7 +68,11 @@
"Show related videos: ": "Mostra video correlati? ",
"Show annotations by default: ": "Mostra le annotazioni per impostazione predefinita? ",
"Visual preferences": "Preferenze grafiche",
+ "Player style: ": "",
"Dark mode: ": "Tema scuro: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Modalità per connessioni lente: ",
"Subscription preferences": "Preferenze iscrizioni",
"Show annotations by default for subscribed channels: ": "",
diff --git a/locales/nb_NO.json b/locales/nb_NO.json
index 589512d4..f50e2290 100644
--- a/locales/nb_NO.json
+++ b/locales/nb_NO.json
@@ -68,7 +68,11 @@
"Show related videos: ": "Vis relaterte videoer? ",
"Show annotations by default: ": "Vis merknader som forvalg? ",
"Visual preferences": "Visuelle innstillinger",
+ "Player style: ": "",
"Dark mode: ": "Mørk drakt: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Tynt modus: ",
"Subscription preferences": "Abonnementsinnstillinger",
"Show annotations by default for subscribed channels: ": "Vis merknader som forvalg for kanaler det abonneres på? ",
diff --git a/locales/nl.json b/locales/nl.json
index b24b13b8..3e2c6c64 100644
--- a/locales/nl.json
+++ b/locales/nl.json
@@ -68,7 +68,11 @@
"Show related videos: ": "Gerelateerde video's tonen? ",
"Show annotations by default: ": "Standaard annotaties tonen? ",
"Visual preferences": "Visuele instellingen",
+ "Player style: ": "",
"Dark mode: ": "Donkere modus: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Smalle modus: ",
"Subscription preferences": "Abonnementsinstellingen",
"Show annotations by default for subscribed channels: ": "Standaard annotaties tonen voor geabonneerde kanalen? ",
diff --git a/locales/pl.json b/locales/pl.json
index 550e664b..1e3a2068 100644
--- a/locales/pl.json
+++ b/locales/pl.json
@@ -68,7 +68,11 @@
"Show related videos: ": "Pokaż powiązane filmy? ",
"Show annotations by default: ": "",
"Visual preferences": "Preferencje Wizualne",
+ "Player style: ": "",
"Dark mode: ": "Ciemny motyw: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Tryb minimalny: ",
"Subscription preferences": "Preferencje subskrybcji",
"Show annotations by default for subscribed channels: ": "",
diff --git a/locales/ru.json b/locales/ru.json
index f9cc1e2d..90aa4a3b 100644
--- a/locales/ru.json
+++ b/locales/ru.json
@@ -68,7 +68,11 @@
"Show related videos: ": "Показывать похожие видео? ",
"Show annotations by default: ": "Всегда показывать аннотации? ",
"Visual preferences": "Настройки сайта",
+ "Player style: ": "",
"Dark mode: ": "Тёмное оформление: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Облегчённое оформление: ",
"Subscription preferences": "Настройки подписок",
"Show annotations by default for subscribed channels: ": "Всегда показывать аннотации в видео каналов, на которые вы подписаны? ",
diff --git a/locales/uk.json b/locales/uk.json
index 95e5798d..e537008c 100644
--- a/locales/uk.json
+++ b/locales/uk.json
@@ -68,7 +68,11 @@
"Show related videos: ": "Показувати схожі відео? ",
"Show annotations by default: ": "Завжди показувати анотації? ",
"Visual preferences": "Налаштування сайту",
+ "Player style: ": "",
"Dark mode: ": "Темне оформлення: ",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "Полегшене оформлення: ",
"Subscription preferences": "Налаштування підписок",
"Show annotations by default for subscribed channels: ": "Завжди показувати анотації у відео каналів, на які ви підписані? ",
diff --git a/locales/zh-CN.json b/locales/zh-CN.json
index 0a3f53d9..23617d04 100644
--- a/locales/zh-CN.json
+++ b/locales/zh-CN.json
@@ -68,7 +68,11 @@
"Show related videos: ": "显示相关视频?",
"Show annotations by default: ": "默认显示视频注释?",
"Visual preferences": "视觉选项",
+ "Player style: ": "",
"Dark mode: ": "暗色模式:",
+ "Theme: ": "",
+ "dark": "",
+ "light": "",
"Thin mode: ": "窄页模式:",
"Subscription preferences": "订阅设置",
"Show annotations by default for subscribed channels: ": "在订阅频道的视频默认显示注释?",
diff --git a/src/invidious.cr b/src/invidious.cr
index 16695c5f..712a408f 100644
--- a/src/invidious.cr
+++ b/src/invidious.cr
@@ -267,8 +267,7 @@ before_all do |env|
end
end
- dark_mode = env.params.query["dark_mode"]? || preferences.dark_mode.to_s
- dark_mode = dark_mode == "true"
+ dark_mode = convert_theme(env.params.query["dark_mode"]?) || preferences.dark_mode.to_s
thin_mode = env.params.query["thin_mode"]? || preferences.thin_mode.to_s
thin_mode = thin_mode == "true"
@@ -1528,8 +1527,7 @@ post "/preferences" do |env|
locale ||= CONFIG.default_user_preferences.locale
dark_mode = env.params.body["dark_mode"]?.try &.as(String)
- dark_mode ||= "off"
- dark_mode = dark_mode == "on"
+ dark_mode ||= CONFIG.default_user_preferences.dark_mode
thin_mode = env.params.body["thin_mode"]?.try &.as(String)
thin_mode ||= "off"
@@ -1553,6 +1551,7 @@ post "/preferences" do |env|
notifications_only ||= "off"
notifications_only = notifications_only == "on"
+ # Convert to JSON and back again to take advantage of converters used for compatability
preferences = Preferences.from_json({
annotations: annotations,
annotations_subscribed: annotations_subscribed,
@@ -1648,12 +1647,27 @@ get "/toggle_theme" do |env|
if user = env.get? "user"
user = user.as(User)
preferences = user.preferences
- preferences.dark_mode = !preferences.dark_mode
- PG_DB.exec("UPDATE users SET preferences = $1 WHERE email = $2", preferences.to_json, user.email)
+ case preferences.dark_mode
+ when "dark"
+ preferences.dark_mode = "light"
+ else
+ preferences.dark_mode = "dark"
+ end
+
+ preferences = preferences.to_json
+
+ PG_DB.exec("UPDATE users SET preferences = $1 WHERE email = $2", preferences, user.email)
else
preferences = env.get("preferences").as(Preferences)
- preferences.dark_mode = !preferences.dark_mode
+
+ case preferences.dark_mode
+ when "dark"
+ preferences.dark_mode = "light"
+ else
+ preferences.dark_mode = "dark"
+ end
+
preferences = preferences.to_json
if Kemal.config.ssl || config.https_only
@@ -2026,7 +2040,7 @@ post "/data_control" do |env|
env.response.puts %(<meta http-equiv="refresh" content="0; url=#{referer}">)
env.response.puts %(<link rel="stylesheet" href="/css/ionicons.min.css?v=#{ASSET_COMMIT}">)
env.response.puts %(<link rel="stylesheet" href="/css/default.css?v=#{ASSET_COMMIT}">)
- if env.get("preferences").as(Preferences).dark_mode
+ if env.get("preferences").as(Preferences).dark_mode == "dark"
env.response.puts %(<link rel="stylesheet" href="/css/darktheme.css?v=#{ASSET_COMMIT}">)
else
env.response.puts %(<link rel="stylesheet" href="/css/lighttheme.css?v=#{ASSET_COMMIT}">)
diff --git a/src/invidious/helpers/helpers.cr b/src/invidious/helpers/helpers.cr
index ce0ded32..03c1654c 100644
--- a/src/invidious/helpers/helpers.cr
+++ b/src/invidious/helpers/helpers.cr
@@ -24,6 +24,27 @@ end
struct ConfigPreferences
module StringToArray
+ def self.to_json(value : Array(String), json : JSON::Builder)
+ json.array do
+ value.each do |element|
+ json.string element
+ end
+ end
+ end
+
+ def self.from_json(value : JSON::PullParser) : Array(String)
+ begin
+ result = [] of String
+ value.read_array do
+ result << HTML.escape(value.read_string[0, 100])
+ end
+ rescue ex
+ result = [HTML.escape(value.read_string[0, 100]), ""]
+ end
+
+ result
+ end
+
def self.to_yaml(value : Array(String), yaml : YAML::Nodes::Builder)
yaml.sequence do
value.each do |element|
@@ -44,11 +65,11 @@ struct ConfigPreferences
node.raise "Expected scalar, not #{item.class}"
end
- result << item.value
+ result << HTML.escape(item.value[0, 100])
end
rescue ex
if node.is_a?(YAML::Nodes::Scalar)
- result = [node.value, ""]
+ result = [HTML.escape(node.value[0, 100]), ""]
else
result = ["", ""]
end
@@ -58,6 +79,53 @@ struct ConfigPreferences
end
end
+ module BoolToString
+ def self.to_json(value : String, json : JSON::Builder)
+ json.string value
+ end
+
+ def self.from_json(value : JSON::PullParser) : String
+ begin
+ result = value.read_string
+
+ if result.empty?
+ CONFIG.default_user_preferences.dark_mode
+ else
+ result
+ end
+ rescue ex
+ result = value.read_bool
+
+ if result
+ "dark"
+ else
+ "light"
+ end
+ end
+ end
+
+ def self.to_yaml(value : String, yaml : YAML::Nodes::Builder)
+ yaml.scalar value
+ end
+
+ def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : String
+ unless node.is_a?(YAML::Nodes::Scalar)
+ node.raise "Expected sequence, not #{node.class}"
+ end
+
+ case node.value
+ when "true"
+ "dark"
+ when "false"
+ "light"
+ when ""
+ CONFIG.default_user_preferences.dark_mode
+ else
+ node.value
+ end
+ end
+ end
+
yaml_mapping({
annotations: {type: Bool, default: false},
annotations_subscribed: {type: Bool, default: false},
@@ -66,7 +134,7 @@ struct ConfigPreferences
comments: {type: Array(String), default: ["youtube", ""], converter: StringToArray},
continue: {type: Bool, default: false},
continue_autoplay: {type: Bool, default: true},
- dark_mode: {type: Bool, default: false},
+ dark_mode: {type: String, default: "", converter: BoolToString},
latest_only: {type: Bool, default: false},
listen: {type: Bool, default: false},
local: {type: Bool, default: false},
diff --git a/src/invidious/helpers/patch_mapping.cr b/src/invidious/helpers/patch_mapping.cr
index 8360caa6..e138aa1c 100644
--- a/src/invidious/helpers/patch_mapping.cr
+++ b/src/invidious/helpers/patch_mapping.cr
@@ -4,7 +4,7 @@ def Object.from_json(string_or_io, default) : self
new parser, default
end
-# Adds configurable 'default' to
+# Adds configurable 'default'
macro patched_json_mapping(_properties_, strict = false)
{% for key, value in _properties_ %}
{% _properties_[key] = {type: value} unless value.is_a?(HashLiteral) || value.is_a?(NamedTupleLiteral) %}
diff --git a/src/invidious/helpers/utils.cr b/src/invidious/helpers/utils.cr
index 69aae839..b39f65c5 100644
--- a/src/invidious/helpers/utils.cr
+++ b/src/invidious/helpers/utils.cr
@@ -356,3 +356,16 @@ def parse_range(range)
return 0_i64, nil
end
+
+def convert_theme(theme)
+ case theme
+ when "true"
+ "dark"
+ when "false"
+ "light"
+ when "", nil
+ nil
+ else
+ theme
+ end
+end
diff --git a/src/invidious/users.cr b/src/invidious/users.cr
index 35d8a49e..8bd82bf1 100644
--- a/src/invidious/users.cr
+++ b/src/invidious/users.cr
@@ -31,62 +31,6 @@ struct User
end
struct Preferences
- module StringToArray
- def self.to_json(value : Array(String), json : JSON::Builder)
- json.array do
- value.each do |element|
- json.string element
- end
- end
- end
-
- def self.from_json(value : JSON::PullParser) : Array(String)
- begin
- result = [] of String
- value.read_array do
- result << HTML.escape(value.read_string[0, 100])
- end
- rescue ex
- result = [HTML.escape(value.read_string[0, 100]), ""]
- end
-
- result
- end
-
- def self.to_yaml(value : Array(String), yaml : YAML::Nodes::Builder)
- yaml.sequence do
- value.each do |element|
- yaml.scalar element
- end
- end
- end
-
- def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : Array(String)
- begin
- unless node.is_a?(YAML::Nodes::Sequence)
- node.raise "Expected sequence, not #{node.class}"
- end
-
- result = [] of String
- node.nodes.each do |item|
- unless item.is_a?(YAML::Nodes::Scalar)
- node.raise "Expected scalar, not #{item.class}"
- end
-
- result << HTML.escape(item.value[0, 100])
- end
- rescue ex
- if node.is_a?(YAML::Nodes::Scalar)
- result = [HTML.escape(node.value[0, 100]), ""]
- else
- result = ["", ""]
- end
- end
-
- result
- end
- end
-
module ProcessString
def self.to_json(value : String, json : JSON::Builder)
json.string value
@@ -127,11 +71,11 @@ struct Preferences
annotations: {type: Bool, default: CONFIG.default_user_preferences.annotations},
annotations_subscribed: {type: Bool, default: CONFIG.default_user_preferences.annotations_subscribed},
autoplay: {type: Bool, default: CONFIG.default_user_preferences.autoplay},
- captions: {type: Array(String), default: CONFIG.default_user_preferences.captions, converter: StringToArray},
- comments: {type: Array(String), default: CONFIG.default_user_preferences.comments, converter: StringToArray},
+ captions: {type: Array(String), default: CONFIG.default_user_preferences.captions, converter: ConfigPreferences::StringToArray},
+ comments: {type: Array(String), default: CONFIG.default_user_preferences.comments, converter: ConfigPreferences::StringToArray},
continue: {type: Bool, default: CONFIG.default_user_preferences.continue},
continue_autoplay: {type: Bool, default: CONFIG.default_user_preferences.continue_autoplay},
- dark_mode: {type: Bool, default: CONFIG.default_user_preferences.dark_mode},
+ dark_mode: {type: String, default: CONFIG.default_user_preferences.dark_mode, converter: ConfigPreferences::BoolToString},
latest_only: {type: Bool, default: CONFIG.default_user_preferences.latest_only},
listen: {type: Bool, default: CONFIG.default_user_preferences.listen},
local: {type: Bool, default: CONFIG.default_user_preferences.local},
diff --git a/src/invidious/views/preferences.ecr b/src/invidious/views/preferences.ecr
index b04bcd4d..6ea01fba 100644
--- a/src/invidious/views/preferences.ecr
+++ b/src/invidious/views/preferences.ecr
@@ -122,8 +122,12 @@ function update_value(element) {
</div>
<div class="pure-control-group">
- <label for="dark_mode"><%= translate(locale, "Dark mode: ") %></label>
- <input name="dark_mode" id="dark_mode" type="checkbox" <% if preferences.dark_mode %>checked<% end %>>
+ <label for="dark_mode"><%= translate(locale, "Theme: ") %></label>
+ <select name="dark_mode" id="dark_mode">
+ <% {"", "light", "dark"}.each do |option| %>
+ <option value="<%= option %>" <% if preferences.dark_mode == option %> selected <% end %>><%= translate(locale, option) %></option>
+ <% end %>
+ </select>
</div>
<div class="pure-control-group">
diff --git a/src/invidious/views/template.ecr b/src/invidious/views/template.ecr
index 6272d2be..8d8cec88 100644
--- a/src/invidious/views/template.ecr
+++ b/src/invidious/views/template.ecr
@@ -18,13 +18,14 @@
<link rel="stylesheet" href="/css/grids-responsive-min.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/css/ionicons.min.css?v=<%= ASSET_COMMIT %>">
<link rel="stylesheet" href="/css/default.css?v=<%= ASSET_COMMIT %>">
- <link rel="stylesheet" href="/css/darktheme.css?v=<%= ASSET_COMMIT %>" id="dark_theme" <% if !env.get("preferences").as(Preferences).dark_mode %>media="none"<% end %>>
- <link rel="stylesheet" href="/css/lighttheme.css?v=<%= ASSET_COMMIT %>" id="light_theme" <% if env.get("preferences").as(Preferences).dark_mode %>media="none"<% end %>>
+ <link rel="stylesheet" href="/css/darktheme.css?v=<%= ASSET_COMMIT %>" id="dark_theme" <% if env.get("preferences").as(Preferences).dark_mode != "dark" %>media="none"<% end %>>
+ <link rel="stylesheet" href="/css/lighttheme.css?v=<%= ASSET_COMMIT %>" id="light_theme" <% if env.get("preferences").as(Preferences).dark_mode == "dark" %>media="none"<% end %>>
</head>
<% locale = LOCALES[env.get("preferences").as(Preferences).locale]? %>
<body>
+ <span style="display:none" id="dark_mode_pref"><%= env.get("preferences").as(Preferences).dark_mode %></span>
<div class="pure-g">
<div class="pure-u-1 pure-u-md-2-24"></div>
<div class="pure-u-1 pure-u-md-20-24">
@@ -43,7 +44,7 @@
<% if env.get? "user" %>
<div class="pure-u-1-4">
<a id="toggle_theme" href="/toggle_theme?referer=<%= env.get?("current_page") %>" class="pure-menu-heading">
- <% if env.get("preferences").as(Preferences).dark_mode %>
+ <% if env.get("preferences").as(Preferences).dark_mode == "dark" %>
<i class="icon ion-ios-sunny"></i>
<% else %>
<i class="icon ion-ios-moon"></i>
@@ -76,7 +77,7 @@
<% else %>
<div class="pure-u-1-3">
<a id="toggle_theme" href="/toggle_theme?referer=<%= env.get?("current_page") %>" class="pure-menu-heading">
- <% if env.get("preferences").as(Preferences).dark_mode %>
+ <% if env.get("preferences").as(Preferences).dark_mode == "dark" %>
<i class="icon ion-ios-sunny"></i>
<% else %>
<i class="icon ion-ios-moon"></i>