Update preferences page to support prefers-color-scheme

This commit is contained in:
Omar Roth 2019-06-23 15:04:04 -05:00
parent 365a261af3
commit 90cd3571ae
No known key found for this signature in database
GPG Key ID: B8254FB7EC3D37F2
7 changed files with 120 additions and 77 deletions

View File

@ -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}">)

View File

@ -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: "light", converter: BoolToString},
latest_only: {type: Bool, default: false},
listen: {type: Bool, default: false},
local: {type: Bool, default: false},

View File

@ -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) %}

View File

@ -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

View File

@ -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},

View File

@ -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">

View File

@ -18,8 +18,8 @@
<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 != "light" %>media="none"<% end %>>
</head>
<% locale = LOCALES[env.get("preferences").as(Preferences).locale]? %>
@ -43,7 +43,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 +76,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>