diff --git a/app/assets/stylesheets/wcag.scss b/app/assets/stylesheets/wcag.scss new file mode 100644 index 00000000000..ade65af9445 --- /dev/null +++ b/app/assets/stylesheets/wcag.scss @@ -0,0 +1,307 @@ +// Overrides for WCAG color schemes only + +// Global + +::placeholder { + color: var(--primary-medium); + opacity: 1; +} + +.discourse-no-touch { + .btn-default, + .btn-icon { + &.btn-default { + .d-icon { + color: var(--primary-medium); + } + } + &:hover, + &.btn-hover { + .d-icon { + color: var(--secondary); + } + } + } + .btn-primary .d-icon { + color: var(--secondary); + } + .btn-icon.ok, + .btn-icon.cancel, + .btn-danger { + .d-icon { + color: var(--secondary); + } + } + .btn-flat.delete.d-hover { + background: var(--danger); + } +} + +.nav-pills > li > a:not(.active):hover { + background: var(--tertiary-low); + color: var(--primary); +} + +// Composer + +#reply-control .reply-to .reply-details .d-icon { + opacity: 1; + color: var(--primary-low-mid); +} + +.d-editor-button-bar { + .btn-icon.btn-default .d-icon { + color: var(--primary-low-mid); + .discourse-no-touch & { + &:hover { + color: var(--secondary); + } + } + } +} + +// Site header + +.menu-panel li a.widget-link:hover, +.menu-panel li a.widget-link:focus, +.menu-panel li.heading a.widget-link:hover, +.menu-panel li.heading a.widget-link:focus { + color: var(--primary); + background-color: var(--highlight-medium); + .d-icon { + color: var(--primary); + } +} + +.menu-panel .panel-body-bottom .btn:hover { + .d-icon { + color: var(--primary); + } +} + +.d-header-icons .d-icon { + color: var(--primary-low-mid); +} + +.d-header-icons .icon:hover .d-icon, +.d-header-icons .icon:focus .d-icon { + color: var(--primary-high); +} + +.d-header-icons .unread-notifications { + background: var(--tertiary); +} + +// Topic list + +table th { + color: var(--primary-medium); +} + +.coldmap { + &-high { + color: #6c77cc !important; + } + + &-med { + color: #548eaa !important; + } + + &-low { + color: #32a1a5 !important; + } +} + +.heatmap-high, +.heatmap-high a { + color: #dc3249 !important; +} +.heatmap-med, +.heatmap-med a { + color: #ae5b54 !important; +} +.heatmap-low, +.heatmap-low a { + color: #8f6d5b !important; +} + +.badge-notification { + background: var(--primary-medium); +} + +.badge-notification.new-posts, +.badge-notification.unread-posts { + background: var(--tertiary); +} +.select-kit.dropdown-select-box.period-chooser + .period-chooser-header + h2.selected-name + .top-date-string, +.select-kit.dropdown-select-box.period-chooser + .period-chooser-row + .top-date-string { + color: var(--primary-high); +} + +// Posts + +.discourse-no-touch .topic-body .actions .fade-out { + opacity: 1; +} + +.topic-body .reply-to-tab { + color: var(--primary-medium); + .d-icon { + color: var(--primary-low-mid); + } +} + +.timeline-container .topic-timeline { + .timeline-scrollarea { + border-color: var(--primary-low-mid); + } + .timeline-handle { + background: var(--primary-low-mid); + } +} + +.topic-map h4 { + color: var(--primary); +} + +.quote-controls, +.quote-controls .d-icon { + color: var(--primary-medium); +} + +blockquote { + a, + a:visited { + color: var(--tertiary); + } +} +.meta .d-icon + .filename, +.meta .informations { + color: var(--secondary); +} + +#topic-footer-buttons .bookmark.bookmarked:hover .d-icon-bookmark { + color: var(--secondary); +} + +.gap { + color: var(--primary-medium); +} + +.badge-notification.clicks { + color: var(--primary-high); +} + +.topic-map { + background: transparent; +} + +// Post controls + +nav.post-controls { + // this is a bit tedious + a, + button { + color: var(--primary-medium); + .d-icon { + color: var(--primary-low-mid); + } + .discourse-no-touch & { + &:hover { + color: var(--secondary); + background: var(--primary-medium); + .d-icon { + color: var(--secondary); + } + } + } + &:focus { + background: var(--primary-medium); + } + } + .discourse-no-touch & { + .double-button:hover { + button { + background: var(--primary-medium); + color: var(--secondary); + .d-icon { + color: var(--secondary); + } + &.has-like { + .d-icon { + color: var(--secondary); + } + } + } + } + } + button.bookmark.bookmarked.d-hover .d-icon { + color: var(--secondary); + } + .double-button button.button-count + .toggle-like.d-hover { + background: var(--primary-medium); + .d-icon { + color: var(--love-low); + } + } + .discourse-no-touch & { + .double-button button.button-count.d-hover { + background: var(--primary-medium); + color: var(--secondary); + } + } + button.create { + .d-icon { + color: var(--primary-low-mid); + } + &.d-hover { + color: var(--secondary); + .d-icon { + color: var(--secondary); + } + } + } + .actions a, + .actions button { + color: var(--primary-medium); + } +} + +nav.post-controls + .actions + .double-button + button.button-count + + .toggle-like.d-hover { + background: var(--primary-medium); +} + +.topic-admin-menu-button-container, +.timeline-controls { + .btn .d-icon { + // admin wrenches + color: var(--primary-medium); + } +} + +// Categories + +.list-cell, +.table-heading, +.category-list td, +.category-list th { + color: var(--primary-medium); +} + +// Admin + +.admin-controls { + .nav-pills > li > a:not(.active):hover { + background: var(--primary-medium); + color: var(--secondary); + } +} diff --git a/app/models/color_scheme.rb b/app/models/color_scheme.rb index 66328721f4d..19a88ccc589 100644 --- a/app/models/color_scheme.rb +++ b/app/models/color_scheme.rb @@ -94,6 +94,37 @@ class ColorScheme < ActiveRecord::Base "danger" => '6c3e63', "success" => 'd9b2bb', "love" => 'd9b2bb' + }, + "WCAG": { + "primary" => '000000', + "primary-medium" => '696969', + "primary-low-mid" => '909090', + "secondary" => 'ffffff', + "tertiary" => '3369FF', + "quaternary" => '3369FF', + "header_background" => 'ffffff', + "header_primary" => '000000', + "highlight" => '3369FF', + "highlight-high" => '0036E6', + "highlight-medium" => 'e0e9ff', + "highlight-low" => 'e0e9ff', + "danger" => 'BB1122', + "success" => '3d854d', + "love" => '9D256B' + }, + "WCAG Dark": { + "primary" => 'ffffff', + "primary-medium" => '999999', + "primary-low-mid" => '888888', + "secondary" => '0c0c0c', + "tertiary" => '759AFF', + "quaternary" => '759AFF', + "header_background" => '000000', + "header_primary" => 'ffffff', + "highlight" => '3369FF', + "danger" => 'BB1122', + "success" => '3d854d', + "love" => '9D256B' } } @@ -307,6 +338,10 @@ class ColorScheme < ActiveRecord::Base primary_b > secondary_b end + def is_wcag? + base_scheme_id&.start_with?('WCAG') + end + # Equivalent to dc-color-brightness() in variables.scss def brightness(color) rgb = color.scan(/../).map { |c| c.to_i(16) } diff --git a/config/locales/client.en.yml b/config/locales/client.en.yml index 0f5ed522050..3ab98418c28 100644 --- a/config/locales/client.en.yml +++ b/config/locales/client.en.yml @@ -4058,6 +4058,12 @@ en: primary: name: "primary" description: "Most text, icons, and borders." + primary-medium: + name: "primary-medium" + description: "" + primary-low-mid: + name: "primary-low-mid" + description: "" secondary: name: "secondary" description: "The main background color, and text color of some buttons." @@ -4076,6 +4082,15 @@ en: highlight: name: "highlight" description: "The background color of highlighted elements on the page, such as posts and topics." + highlight-high: + name: "highlight-high" + description: "" + highlight-medium: + name: "highlight-medium" + description: "" + highlight-low: + name: "highlight-low" + description: "" danger: name: "danger" description: "Highlight color for actions like deleting posts and topics." diff --git a/config/locales/server.en.yml b/config/locales/server.en.yml index 3557859c24e..2ef198f219b 100644 --- a/config/locales/server.en.yml +++ b/config/locales/server.en.yml @@ -3923,6 +3923,10 @@ en: latte: "Latte" summer: "Summer" dark_rose: "Dark Rose" + wcag: "WCAG Light" + wcag_theme_name: "WCAG Light" + wcag_dark: "WCAG Dark" + wcag_dark_theme_name: "WCAG Dark" default_theme_name: "Default" light_theme_name: "Light" dark_theme_name: "Dark" diff --git a/db/fixtures/600_themes.rb b/db/fixtures/600_themes.rb index 718f650c274..c5945864b5b 100644 --- a/db/fixtures/600_themes.rb +++ b/db/fixtures/600_themes.rb @@ -4,9 +4,16 @@ if !Theme.exists? STDERR.puts "> Seeding theme and color schemes" - name = I18n.t("color_schemes.dark_theme_name") - dark_scheme = ColorScheme.find_by(base_scheme_id: "Dark") - dark_scheme ||= ColorScheme.create_from_base(name: name, via_wizard: true, base_scheme_id: "Dark", user_selectable: true) + color_schemes = [ + { name: I18n.t("color_schemes.dark"), base_scheme_id: "Dark" }, + { name: I18n.t("color_schemes.wcag"), base_scheme_id: "WCAG" }, + { name: I18n.t("color_schemes.wcag_dark"), base_scheme_id: "WCAG Dark" } + ] + + color_schemes.each do |cs| + scheme = ColorScheme.find_by(base_scheme_id: cs[:base_scheme_id]) + scheme ||= ColorScheme.create_from_base(name: cs[:name], via_wizard: true, base_scheme_id: cs[:base_scheme_id], user_selectable: true) + end name = I18n.t('color_schemes.default_theme_name') default_theme = Theme.create!(name: name, user_id: -1) diff --git a/lib/stylesheet/compiler.rb b/lib/stylesheet/compiler.rb index 8596c5d8b86..23433e8f206 100644 --- a/lib/stylesheet/compiler.rb +++ b/lib/stylesheet/compiler.rb @@ -22,6 +22,7 @@ module Stylesheet if asset.to_s == Stylesheet::Manager::COLOR_SCHEME_STYLESHEET file += Stylesheet::Importer.import_color_definitions(options[:theme_id]) + file += Stylesheet::Importer.import_wcag_overrides(options[:color_scheme_id]) end end diff --git a/lib/stylesheet/importer.rb b/lib/stylesheet/importer.rb index 89572f02035..83d8875fbd2 100644 --- a/lib/stylesheet/importer.rb +++ b/lib/stylesheet/importer.rb @@ -191,6 +191,13 @@ module Stylesheet contents end + def self.import_wcag_overrides(color_scheme_id) + if color_scheme_id && ColorScheme.find_by_id(color_scheme_id)&.is_wcag? + return "@import \"wcag\";" + end + "" + end + def initialize(options) @theme = options[:theme] @theme_id = options[:theme_id] diff --git a/spec/components/stylesheet/importer_spec.rb b/spec/components/stylesheet/importer_spec.rb index 54259f131a5..bc8cc3264a8 100644 --- a/spec/components/stylesheet/importer_spec.rb +++ b/spec/components/stylesheet/importer_spec.rb @@ -187,6 +187,17 @@ describe Stylesheet::Importer do styles = Stylesheet::Importer.import_color_definitions(nil) expect(styles).to include(scss) end + end + context "#import_wcag_overrides" do + it "should do nothing on a regular scheme" do + scheme = ColorScheme.create_from_base(name: 'Regular') + expect(Stylesheet::Importer.import_wcag_overrides(scheme.id)).to eq("") + end + + it "should include WCAG overrides for WCAG based scheme" do + scheme = ColorScheme.create_from_base(name: 'WCAG New', base_scheme_id: "WCAG Dark") + expect(Stylesheet::Importer.import_wcag_overrides(scheme.id)).to eq("@import \"wcag\";") + end end end diff --git a/spec/models/color_scheme_spec.rb b/spec/models/color_scheme_spec.rb index 1add1fa77ad..8273db3206d 100644 --- a/spec/models/color_scheme_spec.rb +++ b/spec/models/color_scheme_spec.rb @@ -102,4 +102,14 @@ describe ColorScheme do expect(scheme.is_dark?).to eq(nil) end end + + describe "is_wcag?" do + it "works as expected" do + expect(ColorScheme.create_from_base(name: 'Nope').is_wcag?).to eq(nil) + expect(ColorScheme.create_from_base(name: 'Nah', base_scheme_id: "Dark").is_wcag?).to eq(false) + + expect(ColorScheme.create_from_base(name: 'Yup', base_scheme_id: "WCAG").is_wcag?).to eq(true) + expect(ColorScheme.create_from_base(name: 'Yup', base_scheme_id: "WCAG Dark").is_wcag?).to eq(true) + end + end end diff --git a/spec/serializers/site_serializer_spec.rb b/spec/serializers/site_serializer_spec.rb index bfa37936ab2..6c1783587fe 100644 --- a/spec/serializers/site_serializer_spec.rb +++ b/spec/serializers/site_serializer_spec.rb @@ -32,14 +32,19 @@ describe SiteSerializer do it "includes user-selectable color schemes" do # it includes seeded color schemes serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json - expect(serialized[:user_color_schemes].count).to eq(1) + expect(serialized[:user_color_schemes].count).to eq(3) - dark_scheme = ColorScheme.create_from_base(name: "ADarkScheme", base_scheme_id: "Dark") + scheme_names = serialized[:user_color_schemes].map { |x| x[:name] } + expect(scheme_names).to include(I18n.t("color_schemes.dark")) + expect(scheme_names).to include(I18n.t("color_schemes.wcag")) + expect(scheme_names).to include(I18n.t("color_schemes.wcag_dark")) + + dark_scheme = ColorScheme.create_from_base(name: "AnotherDarkScheme", base_scheme_id: "Dark") dark_scheme.user_selectable = true dark_scheme.save! serialized = described_class.new(Site.new(guardian), scope: guardian, root: false).as_json - expect(serialized[:user_color_schemes].count).to eq(2) + expect(serialized[:user_color_schemes].count).to eq(4) expect(serialized[:user_color_schemes][0][:is_dark]).to eq(true) end