From e5a34870f0f7154712783fb6d9c20edf4c06ad35 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sat, 28 Dec 2019 15:55:42 +0200
Subject: Accent works

---
 src/components/style_switcher/style_switcher.vue | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index ad032041..8bbdc7b7 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -114,9 +114,18 @@
               :label="$t('settings.text')"
             />
             <ContrastRatio :contrast="previewContrast.bgText" />
+            <ColorInput
+              v-model="accentColorLocal"
+              name="accentColor"
+              :fallback="previewTheme.colors.link"
+              :showOptionalTickbox="typeof linkColorLocal !== 'undefined'"
+              :label="$t('settings.accent')"
+            />
             <ColorInput
               v-model="linkColorLocal"
               name="linkColor"
+              :fallback="previewTheme.colors.accent"
+              :showOptionalTickbox="typeof accentColorLocal !== 'undefined'"
               :label="$t('settings.links')"
             />
             <ContrastRatio :contrast="previewContrast.bgLink" />
@@ -336,7 +345,7 @@
             <ColorInput
               v-model="faintColorLocal"
               name="faintColor"
-              :fallback="previewTheme.colors.faint || 1"
+              :fallback="previewTheme.colors.faint"
               :label="$t('settings.text')"
             />
             <ColorInput
-- 
cgit v1.2.3-70-g09d2


From 1a78461443e4f85461283c1921694a5fb28ea39f Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sat, 28 Dec 2019 17:02:34 +0200
Subject: fixed import-export

---
 src/components/export_import/export_import.vue   |  2 +-
 src/components/style_switcher/style_switcher.js  | 34 +++++++++++++++++++-----
 src/components/style_switcher/style_switcher.vue |  4 +--
 src/services/style_setter/style_setter.js        | 27 +++++++++++++++++--
 4 files changed, 56 insertions(+), 11 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/export_import/export_import.vue b/src/components/export_import/export_import.vue
index 20c6f569..ae00487f 100644
--- a/src/components/export_import/export_import.vue
+++ b/src/components/export_import/export_import.vue
@@ -42,7 +42,7 @@ export default {
   },
   methods: {
     exportData () {
-      const stringified = JSON.stringify(this.exportObject) // Pretty-print and indent with 2 spaces
+      const stringified = JSON.stringify(this.exportObject, null, 2) // Pretty-print and indent with 2 spaces
 
       // Create an invisible link with a data url and simulate a click
       const e = document.createElement('a')
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 1e512407..b450dc8e 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -1,6 +1,7 @@
 import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js'
 import { set, delete as del } from 'vue'
-import { generateColors, generateShadows, generateRadii, generateFonts, composePreset, getThemes } from '../../services/style_setter/style_setter.js'
+import { merge } from 'lodash'
+import { generateCompat, generateColors, generateShadows, generateRadii, generateFonts, composePreset, getThemes } from '../../services/style_setter/style_setter.js'
 import ColorInput from '../color_input/color_input.vue'
 import RangeInput from '../range_input/range_input.vue'
 import OpacityInput from '../opacity_input/opacity_input.vue'
@@ -123,6 +124,15 @@ export default {
     selectedVersion () {
       return Array.isArray(this.selected) ? 1 : 2
     },
+    currentCompat () {
+      return generateCompat({
+        shadows: this.shadowsLocal,
+        fonts: this.fontsLocal,
+        opacity: this.currentOpacity,
+        colors: this.currentColors,
+        radii: this.currentRadii
+      })
+    },
     currentColors () {
       return {
         bg: this.bgColorLocal,
@@ -332,7 +342,7 @@ export default {
 
       return {
         // To separate from other random JSON files and possible future theme formats
-        _pleroma_theme_version: 2, theme
+        _pleroma_theme_version: 2, theme: merge(theme, this.currentCompat)
       }
     }
   },
@@ -364,7 +374,7 @@ export default {
     onImport (parsed) {
       if (parsed._pleroma_theme_version === 1) {
         this.normalizeLocalState(parsed, 1)
-      } else if (parsed._pleroma_theme_version === 2) {
+      } else if (parsed._pleroma_theme_version >= 2) {
         this.normalizeLocalState(parsed.theme, 2)
       }
     },
@@ -414,6 +424,7 @@ export default {
 
     /**
      * This applies stored theme data onto form. Supports three versions of data:
+     * v3 (version = 3) - same as 2 but with some incompatible changes
      * v2 (version = 2) - newer version of themes.
      * v1 (version = 1) - older version of themes (import from file)
      * v1l (version = l1) - older version of theme (load from local storage)
@@ -421,12 +432,21 @@ export default {
      * @param {Object} input - input data
      * @param {Number} version - version of data. 0 means try to guess based on data. "l1" means v1, locastorage type
      */
-    normalizeLocalState (input, version = 0) {
-      const colors = input.colors || input
+    normalizeLocalState (originalInput, version = 0) {
+      let input
+      if (typeof originalInput.v3compat !== undefined) {
+        version = 3
+        input = merge(originalInput, originalInput.v3compat)
+      } else {
+        input = originalInput
+      }
+
+      const compat = input.v3compat
       const radii = input.radii || input
       const opacity = input.opacity
       const shadows = input.shadows || {}
       const fonts = input.fonts || {}
+      const colors = input.colors || input
 
       if (version === 0) {
         if (input.version) version = input.version
@@ -530,6 +550,7 @@ export default {
     currentColors () {
       try {
         this.previewColors = generateColors({
+          v3compat: this.currentCompat,
           opacity: this.currentOpacity,
           colors: this.currentColors
         })
@@ -542,8 +563,9 @@ export default {
     currentOpacity () {
       try {
         this.previewColors = generateColors({
+          v3compat: this.currentCompat,
           opacity: this.currentOpacity,
-          colors: this.currentColors
+          colors: this.currentColors,
         })
       } catch (e) {
         console.warn(e)
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 8bbdc7b7..2ecd275a 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -2,7 +2,7 @@
   <div class="style-switcher">
     <div class="presets-container">
       <div class="save-load">
-        <export-import
+        <ExportImport
           :export-object="exportedTheme"
           :export-label="$t(&quot;settings.export_theme&quot;)"
           :import-label="$t(&quot;settings.import_theme&quot;)"
@@ -38,7 +38,7 @@
               </label>
             </div>
           </template>
-        </export-import>
+        </ExportImport>
       </div>
       <div class="save-load-options">
         <span class="keep-option">
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 1e4bc59e..19a06587 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -148,6 +148,26 @@ const getCssColor = (input, a) => {
   return rgb2rgba({ ...rgb, a })
 }
 
+// Generates a "patch" for theme to make it compatible with v2
+export const generateCompat = (input) => {
+  const { colors } = input
+  const v3compat = {
+    colors: {}
+  }
+  const v2colorsPatch = {}
+
+  // # Link became optional in v3
+  if (typeof colors.link === 'undefined') {
+    v2colorsPatch.link = colors.accent
+    v3compat.colors.link = null
+  }
+
+  return {
+    v3compat,
+    colors: v2colorsPatch
+  }
+}
+
 const generateColors = (input) => {
   const colors = {}
   const opacity = Object.assign({
@@ -164,7 +184,10 @@ const generateColors = (input) => {
   const inputColors = input.colors || input
 
   const compat = input.v3compat || {}
-  const compatColors = compat.colors || {}
+  const compatColors = Object.entries(compat.colors || {}).reduce((acc, [key, value]) => {
+    const newVal = value === null ? undefined : value
+    return { ...acc, [key]: newVal }
+  }, {})
 
   const col = Object.entries({ ...inputColors, ...compatColors }).reduce((acc, [k, v]) => {
     if (typeof v === 'object') {
@@ -210,7 +233,7 @@ const generateColors = (input) => {
   colors.topBarText = col.topBarText || getTextColor(colors.topBar, colors.fgText)
   colors.topBarLink = col.topBarLink || getTextColor(colors.topBar, colors.fgLink)
 
-  colors.faintLink = col.faintLink || Object.assign({}, col.link)
+  colors.faintLink = col.faintLink || Object.assign({}, col.link || col.accent)
   colors.linkBg = alphaBlend(colors.link, 0.4, colors.bg)
 
   colors.icon = mixrgb(colors.bg, colors.text)
-- 
cgit v1.2.3-70-g09d2


From 6e11924c27288e590de8f5b675fb53704581bcc8 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sat, 28 Dec 2019 18:49:35 +0200
Subject: underlay customization, updated contrast calculations to account for
 alpha blending

---
 src/App.scss                                     |  1 +
 src/components/style_switcher/style_switcher.js  | 47 ++++++++++++++----------
 src/components/style_switcher/style_switcher.vue | 14 +++++++
 src/services/color_convert/color_convert.js      | 23 ++++++++++++
 src/services/style_setter/style_setter.js        | 37 +++++++++++++------
 5 files changed, 91 insertions(+), 31 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/App.scss b/src/App.scss
index 3b03a761..b6d4943a 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -32,6 +32,7 @@ h4 {
   min-height: 100vh;
   max-width: 980px;
   background-color: rgba(0,0,0,0.15);
+  background-color: var(--underlay, rgba(0,0,0,0.15));
   align-content: flex-start;
 }
 
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index b450dc8e..602a635e 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -1,4 +1,4 @@
-import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js'
+import { rgb2hex, hex2rgb, getContrastRatio, getContrastRatioLayers, alphaBlend } from '../../services/color_convert/color_convert.js'
 import { set, delete as del } from 'vue'
 import { merge } from 'lodash'
 import { generateCompat, generateColors, generateShadows, generateRadii, generateFonts, composePreset, getThemes } from '../../services/style_setter/style_setter.js'
@@ -53,6 +53,9 @@ export default {
       bgColorLocal: '',
       bgOpacityLocal: undefined,
 
+      underlayColorLocal: '',
+      underlayOpacityLocal: undefined,
+
       fgColorLocal: '',
       fgTextColorLocal: undefined,
       fgLinkColorLocal: undefined,
@@ -145,6 +148,8 @@ export default {
 
         accent: this.accentColorLocal,
 
+        underlay: this.underlayColorLocal,
+
         panel: this.panelColorLocal,
         panelText: this.panelTextColorLocal,
         panelLink: this.panelLinkColorLocal,
@@ -182,7 +187,8 @@ export default {
         panel: this.panelOpacityLocal,
         topBar: this.topBarOpacityLocal,
         border: this.borderOpacityLocal,
-        faint: this.faintOpacityLocal
+        faint: this.faintOpacityLocal,
+        underlay: this.underlayOpacityLocal
       }
     },
     currentRadii () {
@@ -240,6 +246,7 @@ export default {
 
       const bgs = {
         bg: hex2rgb(colors.bg),
+        underlay: hex2rgb(colors.underlay),
         btn: hex2rgb(colors.btn),
         panel: hex2rgb(colors.panel),
         topBar: hex2rgb(colors.topBar),
@@ -249,29 +256,31 @@ export default {
         badgeNotification: hex2rgb(colors.badgeNotification)
       }
 
-      /* This is a bit confusing because "bottom layer" used is text color
-       * This is done to get worst case scenario when background below transparent
-       * layer matches text color, making it harder to read the lower alpha is.
-       */
-      const ratios = {
-        bgText: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.text), fgs.text),
-        bgLink: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.link), fgs.link),
-        bgRed: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.red), fgs.red),
-        bgGreen: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.green), fgs.green),
-        bgBlue: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.blue), fgs.blue),
-        bgOrange: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.orange), fgs.orange),
+      const bg = [bgs.bg, opacity.bg]
+      const underlay = [bgs.underlay, opacity.underlay]
 
+      const panel = [underlay, bg]
+
+      const ratios = {
+        bgText: getContrastRatioLayers(fgs.text, panel, fgs.text),
+        bgLink: getContrastRatioLayers(fgs.link, panel, fgs.link),
+        bgRed: getContrastRatioLayers(fgs.red, panel, fgs.red),
+        bgGreen: getContrastRatioLayers(fgs.green, panel, fgs.green),
+        bgBlue: getContrastRatioLayers(fgs.blue, panel, fgs.blue),
+        bgOrange: getContrastRatioLayers(fgs.orange, panel, fgs.orange),
+
+        // TODO what's this?
         tintText: getContrastRatio(alphaBlend(bgs.bg, 0.5, fgs.panelText), fgs.text),
 
-        panelText: getContrastRatio(alphaBlend(bgs.panel, opacity.panel, fgs.panelText), fgs.panelText),
-        panelLink: getContrastRatio(alphaBlend(bgs.panel, opacity.panel, fgs.panelLink), fgs.panelLink),
+        panelText: getContrastRatioLayers(fgs.text, [...panel, [bgs.panel, opacity.panel]], fgs.panelText),
+        panelLink: getContrastRatioLayers(fgs.link, [...panel, [bgs.panel, opacity.panel]], fgs.panelLink),
 
-        btnText: getContrastRatio(alphaBlend(bgs.btn, opacity.btn, fgs.btnText), fgs.btnText),
+        btnText: getContrastRatioLayers(fgs.text, [...panel, [bgs.btn, opacity.btn]], fgs.btnText),
 
-        inputText: getContrastRatio(alphaBlend(bgs.input, opacity.input, fgs.inputText), fgs.inputText),
+        inputText: getContrastRatioLayers(fgs.text, [...panel, [bgs.input, opacity.input]], fgs.inputText),
 
-        topBarText: getContrastRatio(alphaBlend(bgs.topBar, opacity.topBar, fgs.topBarText), fgs.topBarText),
-        topBarLink: getContrastRatio(alphaBlend(bgs.topBar, opacity.topBar, fgs.topBarLink), fgs.topBarLink)
+        topBarText: getContrastRatioLayers(fgs.text, [...panel, [bgs.topBar, opacity.topBar]], fgs.topBarText),
+        topBarLink: getContrastRatioLayers(fgs.link, [...panel, [bgs.topBar, opacity.topBar]], fgs.topBarLink)
       }
 
       return Object.entries(ratios).reduce((acc, [k, v]) => { acc[k] = hints(v); return acc }, {})
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 2ecd275a..38ca2017 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -366,6 +366,20 @@
               :fallback="previewTheme.opacity.faint || 0.5"
             />
           </div>
+          <div class="color-item">
+            <h4>{{ $t('settings.style.advanced_colors.underlay') }}</h4>
+            <ColorInput
+              v-model="underlayColorLocal"
+              name="underlay"
+              :label="$t('settings.style.advanced_colors.underlay')"
+              fallback='#000000'
+            />
+            <OpacityInput
+              v-model="underlayOpacityLocal"
+              name="underlayOpacity"
+              :fallback="previewTheme.opacity.underlay || 0.15"
+            />
+          </div>
         </div>
 
         <div
diff --git a/src/services/color_convert/color_convert.js b/src/services/color_convert/color_convert.js
index d1b17c61..757a36bd 100644
--- a/src/services/color_convert/color_convert.js
+++ b/src/services/color_convert/color_convert.js
@@ -1,5 +1,8 @@
 import { map } from 'lodash'
 
+// useful for visualizing color when debugging
+export const consoleColor = (color) => console.log('%c##########', 'background: ' + color + '; color: ' + color)
+
 const rgb2hex = (r, g, b) => {
   if (r === null || typeof r === 'undefined') {
     return undefined
@@ -78,6 +81,16 @@ const getContrastRatio = (a, b) => {
 
   return (l1 + 0.05) / (l2 + 0.05)
 }
+/**
+ * Same as `getContrastRatio` but for multiple layers in-between
+ *
+ * @param {Object} text - text color (topmost layer)
+ * @param {[Object, Number]} layers[] - layers between text and bedrock
+ * @param {Object} bedrock - layer at the very bottom
+ */
+export const getContrastRatioLayers = (text, layers, bedrock) => {
+  return getContrastRatio(alphaBlendLayers(bedrock, layers), text)
+}
 
 /**
  * This performs alpha blending between solid background and semi-transparent foreground
@@ -97,6 +110,16 @@ const alphaBlend = (fg, fga, bg) => {
   }, {})
 }
 
+/**
+ * Same as `alphaBlend` but for multiple layers in-between
+ *
+ * @param {Object} bedrock - layer at the very bottom
+ * @param {[Object, Number]} layers[] - layers between text and bedrock
+ */
+export const alphaBlendLayers = (bedrock, layers) => layers.reduce((acc, [color, opacity]) => {
+  return alphaBlend(color, opacity, acc)
+}, bedrock)
+
 const invert = (rgb) => {
   return 'rgb'.split('').reduce((acc, c) => {
     acc[c] = 255 - rgb[c]
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 19a06587..8740fc55 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -1,6 +1,6 @@
 import { times } from 'lodash'
 import { brightness, invertLightness, convert, contrastRatio } from 'chromatism'
-import { rgb2hex, hex2rgb, mixrgb, getContrastRatio, alphaBlend } from '../color_convert/color_convert.js'
+import { rgb2hex, hex2rgb, mixrgb, getContrastRatio, alphaBlend, alphaBlendLayers } from '../color_convert/color_convert.js'
 
 // While this is not used anymore right now, I left it in if we want to do custom
 // styles that aren't just colors, so user can pick from a few different distinct
@@ -64,8 +64,10 @@ const getTextColor = function (bg, text, preserve) {
     const base = typeof text.a !== 'undefined' ? { a: text.a } : {}
     const result = Object.assign(base, invertLightness(text).rgb)
     if (!preserve && getContrastRatio(bg, result) < 4.5) {
+      // B&W
       return contrastRatio(bg, text).rgb
     }
+    // Inverted color
     return result
   }
   return text
@@ -173,7 +175,8 @@ const generateColors = (input) => {
   const opacity = Object.assign({
     alert: 0.5,
     input: 0.5,
-    faint: 0.5
+    faint: 0.5,
+    underlay: 0.15
   }, Object.entries(input.opacity || {}).reduce((acc, [k, v]) => {
     if (typeof v !== 'undefined') {
       acc[k] = v
@@ -210,28 +213,37 @@ const generateColors = (input) => {
   colors.faint = col.faint || Object.assign({}, col.text)
 
   colors.bg = col.bg
-  colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb
+  colors.lightBg = col.lightBg || brightness(5 * mod, colors.bg).rgb
+
+  const underlay = [col.underlay, opacity.underlay]
+  const fg = [col.fg, opacity.fg]
+  const bg = [col.bg, opacity.bg]
 
   colors.fg = col.fg
-  colors.fgText = col.fgText || getTextColor(colors.fg, colors.text)
-  colors.fgLink = col.fgLink || getTextColor(colors.fg, colors.link, true)
+  colors.fgText = col.fgText || getTextColor(alphaBlendLayers(colors.text, [underlay, bg, fg]), colors.text)
+  colors.fgLink = col.fgLink || getTextColor(alphaBlendLayers(colors.link, [underlay, bg, fg]), colors.link, true)
+  colors.underlay = col.underlay || hex2rgb('#000000')
 
   colors.border = col.border || brightness(2 * mod, colors.fg).rgb
 
   colors.btn = col.btn || Object.assign({}, col.fg)
-  colors.btnText = col.btnText || getTextColor(colors.btn, colors.fgText)
+  const btn = [colors.btn, opacity.btn || 1]
+  colors.btnText = col.btnText || getTextColor(alphaBlendLayers(colors.fgText, [underlay, bg, fg, btn]), colors.fgText)
 
   colors.input = col.input || Object.assign({}, col.fg)
-  colors.inputText = col.inputText || getTextColor(colors.input, colors.lightText)
+  const inputCol = [colors.input, opacity.input]
+  colors.inputText = col.inputText || getTextColor(alphaBlendLayers(colors.lightText, [underlay, bg, fg, inputCol]), colors.lightText)
 
   colors.panel = col.panel || Object.assign({}, col.fg)
-  colors.panelText = col.panelText || getTextColor(colors.panel, colors.fgText)
-  colors.panelLink = col.panelLink || getTextColor(colors.panel, colors.fgLink)
-  colors.panelFaint = col.panelFaint || getTextColor(colors.panel, colors.faint)
+  const panel = [colors.panel, opacity.panel]
+  colors.panelText = col.panelText || getTextColor(alphaBlendLayers(colors.fgText, [underlay, bg, panel]), colors.fgText)
+  colors.panelLink = col.panelLink || getTextColor(alphaBlendLayers(colors.fgLink, [underlay, bg, panel]), colors.fgLink)
+  colors.panelFaint = col.panelFaint || getTextColor(alphaBlendLayers(colors.faint, [underlay, bg, panel]), colors.faint)
 
   colors.topBar = col.topBar || Object.assign({}, col.fg)
-  colors.topBarText = col.topBarText || getTextColor(colors.topBar, colors.fgText)
-  colors.topBarLink = col.topBarLink || getTextColor(colors.topBar, colors.fgLink)
+  const topBar = [colors.topBar, opacity.topBar]
+  colors.topBarText = col.topBarText || getTextColor(alphaBlendLayers(colors.fgText, [topBar]), colors.fgText)
+  colors.topBarLink = col.topBarLink || getTextColor(alphaBlendLayers(colors.fgLink, [topBar]), colors.fgLink)
 
   colors.faintLink = col.faintLink || Object.assign({}, col.link || col.accent)
   colors.linkBg = alphaBlend(colors.link, 0.4, colors.bg)
@@ -255,6 +267,7 @@ const generateColors = (input) => {
   colors.badgeNotificationText = contrastRatio(colors.badgeNotification).rgb
 
   Object.entries(opacity).forEach(([ k, v ]) => {
+    console.log(k)
     if (typeof v === 'undefined') return
     if (k === 'alert') {
       colors.alertError.a = v
-- 
cgit v1.2.3-70-g09d2


From 4bb1c98e0f28bcf1d0dff2d90d01013cd5487522 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Thu, 2 Jan 2020 20:36:10 +0200
Subject: Replaced `v3compat` with `source` to reduce code complexity. Made
 more slots customizable. `theme` now contains a snapshot of theme generated
 for better compatiblity and future-proofing

---
 src/components/style_switcher/style_switcher.js  |  68 ++++---
 src/components/style_switcher/style_switcher.vue |  14 +-
 src/services/style_setter/style_setter.js        |  42 ++---
 static/themes/breezy-dark.json                   | 224 ++++++++++++++++++++++-
 static/themes/breezy-light.json                  | 220 +++++++++++++++++++++-
 5 files changed, 488 insertions(+), 80 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 9fe1bf59..f751260a 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -1,7 +1,15 @@
 import { rgb2hex, hex2rgb, getContrastRatio, getContrastRatioLayers, alphaBlend } from '../../services/color_convert/color_convert.js'
 import { set, delete as del } from 'vue'
 import { merge } from 'lodash'
-import { generateCompat, generateColors, generateShadows, generateRadii, generateFonts, composePreset, getThemes } from '../../services/style_setter/style_setter.js'
+import {
+  generateColors,
+  generateShadows,
+  generateRadii,
+  generateFonts,
+  composePreset,
+  getThemes,
+  CURRENT_VERSION
+} from '../../services/style_setter/style_setter.js'
 import ColorInput from '../color_input/color_input.vue'
 import RangeInput from '../range_input/range_input.vue'
 import OpacityInput from '../opacity_input/opacity_input.vue'
@@ -135,15 +143,6 @@ export default {
     selectedVersion () {
       return Array.isArray(this.selected) ? 1 : 2
     },
-    currentCompat () {
-      return generateCompat({
-        shadows: this.shadowsLocal,
-        fonts: this.fontsLocal,
-        opacity: this.currentOpacity,
-        colors: this.currentColors,
-        radii: this.currentRadii
-      })
-    },
     currentColors () {
       return {
         bg: this.bgColorLocal,
@@ -339,27 +338,32 @@ export default {
         !this.keepColor
       )
 
-      const theme = {}
+      const source = {
+        themeEngineVersion: CURRENT_VERSION
+      }
 
       if (this.keepFonts || saveEverything) {
-        theme.fonts = this.fontsLocal
+        source.fonts = this.fontsLocal
       }
       if (this.keepShadows || saveEverything) {
-        theme.shadows = this.shadowsLocal
+        source.shadows = this.shadowsLocal
       }
       if (this.keepOpacity || saveEverything) {
-        theme.opacity = this.currentOpacity
+        source.opacity = this.currentOpacity
       }
       if (this.keepColor || saveEverything) {
-        theme.colors = this.currentColors
+        source.colors = this.currentColors
       }
       if (this.keepRoundness || saveEverything) {
-        theme.radii = this.currentRadii
+        source.radii = this.currentRadii
       }
 
+      const theme = this.previewTheme
+
+      console.log(source)
       return {
-        // To separate from other random JSON files and possible future theme formats
-        _pleroma_theme_version: 2, theme: merge(theme, this.currentCompat)
+        // To separate from other random JSON files and possible future source formats
+        _pleroma_theme_version: 2, theme, source
       }
     }
   },
@@ -392,7 +396,7 @@ export default {
       if (parsed._pleroma_theme_version === 1) {
         this.normalizeLocalState(parsed, 1)
       } else if (parsed._pleroma_theme_version >= 2) {
-        this.normalizeLocalState(parsed.theme, 2)
+        this.normalizeLocalState(parsed.theme, 2, parsed.source)
       }
     },
     importValidator (parsed) {
@@ -402,7 +406,7 @@ export default {
     clearAll () {
       const state = this.$store.getters.mergedConfig.customTheme
       const version = state.colors ? 2 : 'l1'
-      this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme, version)
+      this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme, version, this.$store.getters.mergedConfig.customThemeSource)
     },
 
     // Clears all the extra stuff when loading V1 theme
@@ -441,24 +445,30 @@ export default {
 
     /**
      * This applies stored theme data onto form. Supports three versions of data:
-     * v3 (version = 3) - same as 2 but with some incompatible changes
+     * v3 (version >= 3) - newest version of themes which supports snapshots for better compatiblity
      * v2 (version = 2) - newer version of themes.
      * v1 (version = 1) - older version of themes (import from file)
      * v1l (version = l1) - older version of theme (load from local storage)
      * v1 and v1l differ because of way themes were stored/exported.
-     * @param {Object} input - input data
+     * @param {Object} theme - theme data (snapshot)
      * @param {Number} version - version of data. 0 means try to guess based on data. "l1" means v1, locastorage type
+     * @param {Object} source - theme source - this will be used if compatible
+     * @param {Boolean} source - by default source won't be used if version doesn't match since it might render differently
+     *                           this allows importing source anyway
      */
-    normalizeLocalState (originalInput, version = 0) {
+    normalizeLocalState (theme, version = 0, source, forceSource = false) {
       let input
-      if (typeof originalInput.v3compat !== 'undefined') {
-        version = 3
-        input = merge(originalInput, originalInput.v3compat)
+      if (typeof source !== 'undefined') {
+        if (forceSource || source.themeEngineVersion === CURRENT_VERSION) {
+          input = source
+          version = source.themeEngineVersion
+        } else {
+          input = theme
+        }
       } else {
-        input = originalInput
+        input = theme
       }
 
-      const compat = input.v3compat
       const radii = input.radii || input
       const opacity = input.opacity
       const shadows = input.shadows || {}
@@ -615,7 +625,7 @@ export default {
           this.cOrangeColorLocal = this.selected[8]
         }
       } else if (this.selectedVersion >= 2) {
-        this.normalizeLocalState(this.selected.theme, 2)
+        this.normalizeLocalState(this.selected.theme, 2, this.selected.source)
       }
     }
   }
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 38ca2017..2eadbe25 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -106,7 +106,7 @@
             <OpacityInput
               v-model="bgOpacityLocal"
               name="bgOpacity"
-              :fallback="previewTheme.opacity.bg || 1"
+              :fallback="previewTheme.opacity.bg"
             />
             <ColorInput
               v-model="textColorLocal"
@@ -238,7 +238,7 @@
             <OpacityInput
               v-model="panelOpacityLocal"
               name="panelOpacity"
-              :fallback="previewTheme.opacity.panel || 1"
+              :fallback="previewTheme.opacity.panel"
             />
             <ColorInput
               v-model="panelTextColorLocal"
@@ -295,7 +295,7 @@
             <OpacityInput
               v-model="inputOpacityLocal"
               name="inputOpacity"
-              :fallback="previewTheme.opacity.input || 1"
+              :fallback="previewTheme.opacity.input"
             />
             <ColorInput
               v-model="inputTextColorLocal"
@@ -316,7 +316,7 @@
             <OpacityInput
               v-model="btnOpacityLocal"
               name="btnOpacity"
-              :fallback="previewTheme.opacity.btn || 1"
+              :fallback="previewTheme.opacity.btn"
             />
             <ColorInput
               v-model="btnTextColorLocal"
@@ -337,7 +337,7 @@
             <OpacityInput
               v-model="borderOpacityLocal"
               name="borderOpacity"
-              :fallback="previewTheme.opacity.border || 1"
+              :fallback="previewTheme.opacity.border"
             />
           </div>
           <div class="color-item">
@@ -363,7 +363,7 @@
             <OpacityInput
               v-model="faintOpacityLocal"
               name="faintOpacity"
-              :fallback="previewTheme.opacity.faint || 0.5"
+              :fallback="previewTheme.opacity.faint"
             />
           </div>
           <div class="color-item">
@@ -377,7 +377,7 @@
             <OpacityInput
               v-model="underlayOpacityLocal"
               name="underlayOpacity"
-              :fallback="previewTheme.opacity.underlay || 0.15"
+              :fallback="previewTheme.opacity.underlay"
             />
           </div>
         </div>
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index df22f94f..e8a64517 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -2,6 +2,8 @@ import { times } from 'lodash'
 import { brightness, invertLightness, convert, contrastRatio } from 'chromatism'
 import { rgb2hex, hex2rgb, mixrgb, getContrastRatio, alphaBlend, alphaBlendLayers } from '../color_convert/color_convert.js'
 
+export const CURRENT_VERSION = 3
+
 // While this is not used anymore right now, I left it in if we want to do custom
 // styles that aren't just colors, so user can pick from a few different distinct
 // styles as well as set their own colors in the future.
@@ -150,29 +152,13 @@ const getCssColor = (input, a) => {
   return rgb2rgba({ ...rgb, a })
 }
 
-// Generates a "patch" for theme to make it compatible with v2
-export const generateCompat = (input) => {
-  const { colors } = input
-  const v3compat = {
-    colors: {}
-  }
-  const v2colorsPatch = {}
-
-  // # Link became optional in v3
-  if (typeof colors.link === 'undefined') {
-    v2colorsPatch.link = colors.accent
-    v3compat.colors.link = null
-  }
-
-  return {
-    v3compat,
-    colors: v2colorsPatch
-  }
-}
-
 const generateColors = (themeData) => {
   const colors = {}
   const rawOpacity = Object.assign({
+    panel: 1,
+    btn: 1,
+    border: 1,
+    bg: 1,
     alert: 0.5,
     input: 0.5,
     faint: 0.5,
@@ -207,6 +193,7 @@ const generateColors = (themeData) => {
     } else {
       let value = v
       if (v === 'transparent') {
+        // TODO: hack to keep rest of the code from complaining
         value = '#FF00FF'
       }
       acc[k] = hex2rgb(value)
@@ -221,7 +208,7 @@ const generateColors = (themeData) => {
   const isLightOnDark = convert(colors.bg).hsl.l < convert(colors.text).hsl.l
   const mod = isLightOnDark ? 1 : -1
 
-  colors.lightText = brightness(20 * mod, colors.text).rgb
+  colors.lightText = col.lightText || brightness(20 * mod, colors.text).rgb
 
   colors.accent = col.accent || col.link
   colors.link = col.link || col.accent
@@ -231,7 +218,8 @@ const generateColors = (themeData) => {
   colors.lightBg = col.lightBg || brightness(5 * mod, colors.bg).rgb
 
   const underlay = [colors.underlay, opacity.underlay]
-  const fg = [col.fg, opacity.fg]
+  // Technically, foreground can't be transparent (descendants can) but let's keep it just in case
+  const fg = [col.fg, opacity.fg || 1]
   const bg = [col.bg, opacity.bg]
 
   colors.fg = col.fg
@@ -271,16 +259,16 @@ const generateColors = (themeData) => {
 
   colors.alertError = col.alertError || Object.assign({}, colors.cRed)
   const alertError = [colors.alertError, opacity.alert]
-  colors.alertErrorText = getTextColor(alphaBlendLayers(colors.text, [underlay, bg, alertError]), colors.text)
-  colors.alertErrorPanelText = getTextColor(alphaBlendLayers(colors.panelText, [underlay, bg, panel, panel, alertError]), colors.panelText)
+  colors.alertErrorText = col.alertErrorText || getTextColor(alphaBlendLayers(colors.text, [underlay, bg, alertError]), colors.text)
+  colors.alertErrorPanelText = col.alertErrorPanelText || getTextColor(alphaBlendLayers(colors.panelText, [underlay, bg, panel, panel, alertError]), colors.panelText)
 
   colors.alertWarning = col.alertWarning || Object.assign({}, colors.cOrange)
   const alertWarning = [colors.alertWarning, opacity.alert]
-  colors.alertWarningText = getTextColor(alphaBlendLayers(colors.text, [underlay, bg, alertWarning]), colors.text)
-  colors.alertWarningPanelText = getTextColor(alphaBlendLayers(colors.panelText, [underlay, bg, panel, panel, alertWarning]), colors.panelText)
+  colors.alertWarningText = col.alertWarningText || getTextColor(alphaBlendLayers(colors.text, [underlay, bg, alertWarning]), colors.text)
+  colors.alertWarningPanelText = col.alertWarningPanelText || getTextColor(alphaBlendLayers(colors.panelText, [underlay, bg, panel, panel, alertWarning]), colors.panelText)
 
   colors.badgeNotification = col.badgeNotification || Object.assign({}, colors.cRed)
-  colors.badgeNotificationText = contrastRatio(colors.badgeNotification).rgb
+  colors.badgeNotificationText = colors.badgeNotificationText || contrastRatio(colors.badgeNotification).rgb
 
   Object.entries(opacity).forEach(([ k, v ]) => {
     console.log(k)
diff --git a/static/themes/breezy-dark.json b/static/themes/breezy-dark.json
index 0ed55184..d447005f 100644
--- a/static/themes/breezy-dark.json
+++ b/static/themes/breezy-dark.json
@@ -2,6 +2,218 @@
   "_pleroma_theme_version": 2,
   "name": "Breezy Dark (beta)",
   "theme": {
+    "shadows": {
+      "panel": [
+        {
+          "x": "1",
+          "y": "2",
+          "blur": "6",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": 0.6
+        }
+      ],
+      "topBar": [
+        {
+          "x": 0,
+          "y": 0,
+          "blur": 4,
+          "spread": 0,
+          "color": "#000000",
+          "alpha": 0.6
+        }
+      ],
+      "popup": [
+        {
+          "x": 2,
+          "y": 2,
+          "blur": 3,
+          "spread": 0,
+          "color": "#000000",
+          "alpha": 0.5
+        }
+      ],
+      "avatar": [
+        {
+          "x": 0,
+          "y": 1,
+          "blur": 8,
+          "spread": 0,
+          "color": "#000000",
+          "alpha": 0.7
+        }
+      ],
+      "avatarStatus": [],
+      "panelHeader": [
+        {
+          "x": 0,
+          "y": "40",
+          "blur": "40",
+          "spread": "-40",
+          "inset": true,
+          "color": "#ffffff",
+          "alpha": "0.1"
+        }
+      ],
+      "button": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": "0",
+          "spread": "1",
+          "color": "#ffffff",
+          "alpha": "0.15",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "1",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "buttonHover": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "--accent",
+          "alpha": "0.3",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "1",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "buttonPressed": [
+        {
+          "x": 0,
+          "y": 0,
+          "blur": "0",
+          "spread": "50",
+          "color": "--faint",
+          "alpha": 1,
+          "inset": true
+        },
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "#ffffff",
+          "alpha": 0.2,
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": 0,
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "input": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "#FFFFFF",
+          "alpha": "0.2",
+          "inset": true
+        }
+      ]
+    },
+    "colors": {
+      "bg": "#31363b",
+      "underlay": "#000000",
+      "text": "#eff0f1",
+      "lightText": "#ffffff",
+      "accent": "#3daee9",
+      "link": "#3daee9",
+      "faint": "#eff0f1",
+      "lightBg": "#3d4349",
+      "fg": "#31363b",
+      "fgText": "#eff0f1",
+      "fgLink": "#3daee9",
+      "border": "#4c545b",
+      "btn": "#31363b",
+      "btnText": "#eff0f1",
+      "input": "#232629",
+      "inputText": "#ffffff",
+      "panel": "#ff00ff",
+      "panelText": "#eff0f1",
+      "panelLink": "#3daee9",
+      "panelFaint": "#eff0f1",
+      "topBar": "#31363b",
+      "topBarText": "#eff0f1",
+      "topBarLink": "#eff0f1",
+      "faintLink": "#3daee9",
+      "linkBg": "#366681",
+      "icon": "#909396",
+      "cBlue": "#3daee9",
+      "cRed": "#da4453",
+      "cGreen": "#27ae60",
+      "cOrange": "#f67400",
+      "alertError": "#da4453",
+      "alertErrorText": "#eff0f1",
+      "alertErrorPanelText": "#eff0f1",
+      "alertWarning": "#f67400",
+      "alertWarningText": "#eff0f1",
+      "alertWarningPanelText": "#eff0f1",
+      "badgeNotification": "#da4453",
+      "badgeNotificationText": "#ffffff"
+    },
+    "opacity": {
+      "panel": 0,
+      "btn": 1,
+      "border": 1,
+      "bg": 1,
+      "alert": 0.5,
+      "input": 0.5,
+      "faint": 0.5,
+      "underlay": 0.15
+    },
+    "radii": {
+      "btn": "2",
+      "input": "2",
+      "checkbox": "1",
+      "panel": "2",
+      "avatar": "2",
+      "avatarAlt": "2",
+      "tooltip": "2",
+      "attachment": "2"
+    },
+    "fonts": {
+      "interface": {
+        "family": "sans-serif"
+      },
+      "input": {
+        "family": "inherit"
+      },
+      "post": {
+        "family": "inherit"
+      },
+      "postCode": {
+        "family": "monospace"
+      }
+    }
+  },
+  "source": {
+    "themeEngineVersion": 3,
+    "fonts": {},
     "shadows": {
       "panel": [
         {
@@ -105,21 +317,13 @@
         }
       ]
     },
-    "fonts": {},
-    "opacity": {
-      "input": "1"
-    },
-    "v3compat": {
-      "colors": {
-        "panel": "transparent"
-      }
-    },
+    "opacity": {},
     "colors": {
       "bg": "#31363b",
       "text": "#eff0f1",
       "link": "#3daee9",
       "fg": "#31363b",
-      "panel": "#31363b",
+      "panel": "transparent",
       "input": "#232629",
       "topBarLink": "#eff0f1",
       "btn": "#31363b",
diff --git a/static/themes/breezy-light.json b/static/themes/breezy-light.json
index 5db185dd..243b8593 100644
--- a/static/themes/breezy-light.json
+++ b/static/themes/breezy-light.json
@@ -2,6 +2,218 @@
   "_pleroma_theme_version": 2,
   "name": "Breezy Light (beta)",
   "theme": {
+    "shadows": {
+      "panel": [
+        {
+          "x": "1",
+          "y": "2",
+          "blur": "6",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": 0.6
+        }
+      ],
+      "topBar": [
+        {
+          "x": 0,
+          "y": 0,
+          "blur": 4,
+          "spread": 0,
+          "color": "#000000",
+          "alpha": 0.6
+        }
+      ],
+      "popup": [
+        {
+          "x": 2,
+          "y": 2,
+          "blur": 3,
+          "spread": 0,
+          "color": "#000000",
+          "alpha": 0.5
+        }
+      ],
+      "avatar": [
+        {
+          "x": 0,
+          "y": 1,
+          "blur": 8,
+          "spread": 0,
+          "color": "#000000",
+          "alpha": 0.7
+        }
+      ],
+      "avatarStatus": [],
+      "panelHeader": [
+        {
+          "x": 0,
+          "y": "40",
+          "blur": "40",
+          "spread": "-40",
+          "inset": true,
+          "color": "#ffffff",
+          "alpha": "0.1"
+        }
+      ],
+      "button": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": "0",
+          "spread": "1",
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "1",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "buttonHover": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "--accent",
+          "alpha": "0.3",
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": "1",
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "buttonPressed": [
+        {
+          "x": 0,
+          "y": 0,
+          "blur": "0",
+          "spread": "50",
+          "color": "--faint",
+          "alpha": 1,
+          "inset": true
+        },
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "#ffffff",
+          "alpha": 0.2,
+          "inset": true
+        },
+        {
+          "x": "1",
+          "y": "1",
+          "blur": 0,
+          "spread": 0,
+          "color": "#000000",
+          "alpha": "0.3",
+          "inset": false
+        }
+      ],
+      "input": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "#000000",
+          "alpha": "0.2",
+          "inset": true
+        }
+      ]
+    },
+    "colors": {
+      "bg": "#eff0f1",
+      "underlay": "#000000",
+      "text": "#232627",
+      "lightText": "#000000",
+      "accent": "#2980b9",
+      "link": "#2980b9",
+      "faint": "#232627",
+      "lightBg": "#e2e4e6",
+      "fg": "#bcc2c7",
+      "fgText": "#232627",
+      "fgLink": "#2980b9",
+      "border": "#b7bdc3",
+      "btn": "#eff0f1",
+      "btnText": "#232627",
+      "input": "#fcfcfc",
+      "inputText": "#000000",
+      "panel": "#475057",
+      "panelText": "#fcfcfc",
+      "panelLink": "#ffffff",
+      "panelFaint": "#d8dbdc",
+      "topBar": "#475057",
+      "topBarText": "#d8dbdc",
+      "topBarLink": "#eff0f1",
+      "faintLink": "#2980b9",
+      "linkBg": "#a0c4db",
+      "icon": "#898b8c",
+      "cBlue": "#2980b9",
+      "cRed": "#da4453",
+      "cGreen": "#27ae60",
+      "cOrange": "#f67400",
+      "alertError": "#da4453",
+      "alertErrorText": "#232627",
+      "alertErrorPanelText": "#fcfcfc",
+      "alertWarning": "#f67400",
+      "alertWarningText": "#232627",
+      "alertWarningPanelText": "#fcfcfc",
+      "badgeNotification": "#da4453",
+      "badgeNotificationText": "#ffffff"
+    },
+    "opacity": {
+      "panel": 1,
+      "btn": 1,
+      "border": 1,
+      "bg": 1,
+      "alert": 0.5,
+      "input": "1",
+      "faint": 0.5,
+      "underlay": 0.15
+    },
+    "radii": {
+      "btn": "2",
+      "input": "2",
+      "checkbox": "1",
+      "panel": "2",
+      "avatar": "2",
+      "avatarAlt": "2",
+      "tooltip": "2",
+      "attachment": "2"
+    },
+    "fonts": {
+      "interface": {
+        "family": "sans-serif"
+      },
+      "input": {
+        "family": "inherit"
+      },
+      "post": {
+        "family": "inherit"
+      },
+      "postCode": {
+        "family": "monospace"
+      }
+    }
+  },
+  "source": {
+    "themeEngineVersion": 3,
+    "fonts": {},
     "shadows": {
       "panel": [
         {
@@ -105,20 +317,14 @@
         }
       ]
     },
-    "fonts": {},
     "opacity": {
       "input": "1"
     },
-    "v3compat": {
-      "colors": {
-        "panel": "transparent"
-      }
-    },
     "colors": {
       "bg": "#eff0f1",
       "text": "#232627",
-      "link": "#2980b9",
       "fg": "#bcc2c7",
+      "accent": "#2980b9",
       "panel": "#475057",
       "panelText": "#fcfcfc",
       "input": "#fcfcfc",
-- 
cgit v1.2.3-70-g09d2


From adbab6ad2a413357b24edbd5b9beec3baae695fa Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Thu, 2 Jan 2020 21:36:01 +0200
Subject: added optional checkbox for opacity, similar to color input

---
 src/components/opacity_input/opacity_input.vue   | 37 +++++++++++++++++++++---
 src/components/style_switcher/style_switcher.vue |  9 ++++--
 2 files changed, 40 insertions(+), 6 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/opacity_input/opacity_input.vue b/src/components/opacity_input/opacity_input.vue
index c677f18c..f7b10d30 100644
--- a/src/components/opacity_input/opacity_input.vue
+++ b/src/components/opacity_input/opacity_input.vue
@@ -18,7 +18,7 @@
       @input="$emit('input', !present ? fallback : undefined)"
     >
     <label
-      v-if="typeof fallback !== 'undefined'"
+      v-if="typeof fallback !== 'undefined' && showOptionalTickbox"
       class="opt-l"
       :for="name + '-o'"
     />
@@ -38,9 +38,38 @@
 
 <script>
 export default {
-  props: [
-    'name', 'value', 'fallback', 'disabled'
-  ],
+  props: {
+    // Name of opacity, used for identifying
+    name: {
+      required: true,
+      type: String
+    },
+    // Opacity value, should be required but vue cannot tell the difference
+    // between "property missing" and "property set to undefined"
+    value: {
+      required: false,
+      type: Number,
+      default: undefined
+    },
+    // Opacity fallback to use when value is not defeind
+    fallback: {
+      required: false,
+      type: Number,
+      default: undefined
+    },
+    // Disable the control
+    disabled: {
+      required: false,
+      type: Boolean,
+      default: false
+    },
+    // Show "optional" tickbox, for when value might become mandatory
+    showOptionalTickbox: {
+      required: false,
+      type: Boolean,
+      default: true
+    }
+  },
   computed: {
     present () {
       return typeof this.value !== 'undefined'
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 2eadbe25..f5b12e7e 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -118,15 +118,15 @@
               v-model="accentColorLocal"
               name="accentColor"
               :fallback="previewTheme.colors.link"
-              :showOptionalTickbox="typeof linkColorLocal !== 'undefined'"
               :label="$t('settings.accent')"
+              :showOptionalTickbox="typeof linkColorLocal !== 'undefined'"
             />
             <ColorInput
               v-model="linkColorLocal"
               name="linkColor"
               :fallback="previewTheme.colors.accent"
-              :showOptionalTickbox="typeof accentColorLocal !== 'undefined'"
               :label="$t('settings.links')"
+              :showOptionalTickbox="typeof accentColorLocal !== 'undefined'"
             />
             <ContrastRatio :contrast="previewContrast.bgLink" />
           </div>
@@ -239,6 +239,7 @@
               v-model="panelOpacityLocal"
               name="panelOpacity"
               :fallback="previewTheme.opacity.panel"
+              :showOptionalTickbox="panelColorLocal !== 'transparent'"
             />
             <ColorInput
               v-model="panelTextColorLocal"
@@ -296,6 +297,7 @@
               v-model="inputOpacityLocal"
               name="inputOpacity"
               :fallback="previewTheme.opacity.input"
+              :showOptionalTickbox="inputColorLocal !== 'transparent'"
             />
             <ColorInput
               v-model="inputTextColorLocal"
@@ -317,6 +319,7 @@
               v-model="btnOpacityLocal"
               name="btnOpacity"
               :fallback="previewTheme.opacity.btn"
+              :showOptionalTickbox="btnColorLocal !== 'transparent'"
             />
             <ColorInput
               v-model="btnTextColorLocal"
@@ -338,6 +341,7 @@
               v-model="borderOpacityLocal"
               name="borderOpacity"
               :fallback="previewTheme.opacity.border"
+              :showOptionalTickbox="borderColorLocal !== 'transparent'"
             />
           </div>
           <div class="color-item">
@@ -378,6 +382,7 @@
               v-model="underlayOpacityLocal"
               name="underlayOpacity"
               :fallback="previewTheme.opacity.underlay"
+              :showOptionalTickbox="underlayOpacityLocal !== 'transparent'"
             />
           </div>
         </div>
-- 
cgit v1.2.3-70-g09d2


From c7e9f21da0eb035b73a165e16f77a9cd18036305 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Thu, 2 Jan 2020 22:44:54 +0200
Subject: color input and opacity input now use Checkbox component. Cleanup.

---
 src/components/color_input/color_input.vue        | 20 ++++-----
 src/components/opacity_input/opacity_input.vue    | 51 +++++------------------
 src/components/range_input/range_input.vue        |  2 +-
 src/components/style_switcher/style_switcher.scss | 12 +++---
 src/components/style_switcher/style_switcher.vue  | 10 ++---
 5 files changed, 30 insertions(+), 65 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/color_input/color_input.vue b/src/components/color_input/color_input.vue
index fa26d079..aa289288 100644
--- a/src/components/color_input/color_input.vue
+++ b/src/components/color_input/color_input.vue
@@ -9,18 +9,12 @@
     >
       {{ label }}
     </label>
-    <input
-      v-if="typeof fallback !== 'undefined'"
-      :id="name + '-o'"
-      class="opt exlcude-disabled"
-      type="checkbox"
-      :checked="present"
-      @input="$emit('input', typeof value === 'undefined' ? fallback : undefined)"
-    >
-    <label
+    <Checkbox
       v-if="typeof fallback !== 'undefined' && showOptionalTickbox"
-      class="opt-l"
-      :for="name + '-o'"
+      :checked="present"
+      :disabled="disabled"
+      @change="$emit('input', typeof value === 'undefined' ? fallback : undefined)"
+      class="opt"
     />
     <input
       :id="name"
@@ -42,6 +36,7 @@
 </template>
 
 <script>
+import Checkbox from '../checkbox/checkbox.vue'
 export default {
   props: {
     // Name of color, used for identifying
@@ -80,6 +75,9 @@ export default {
       default: true
     }
   },
+  components: {
+    Checkbox
+  },
   computed: {
     present () {
       return typeof this.value !== 'undefined'
diff --git a/src/components/opacity_input/opacity_input.vue b/src/components/opacity_input/opacity_input.vue
index f7b10d30..cfda9926 100644
--- a/src/components/opacity_input/opacity_input.vue
+++ b/src/components/opacity_input/opacity_input.vue
@@ -9,18 +9,12 @@
     >
       {{ $t('settings.style.common.opacity') }}
     </label>
-    <input
+    <Checkbox
       v-if="typeof fallback !== 'undefined'"
-      :id="name + '-o'"
-      class="opt exclude-disabled"
-      type="checkbox"
       :checked="present"
-      @input="$emit('input', !present ? fallback : undefined)"
-    >
-    <label
-      v-if="typeof fallback !== 'undefined' && showOptionalTickbox"
-      class="opt-l"
-      :for="name + '-o'"
+      :disabled="disabled"
+      @change="$emit('input', !present ? fallback : undefined)"
+      class="opt"
     />
     <input
       :id="name"
@@ -37,38 +31,13 @@
 </template>
 
 <script>
+import Checkbox from '../checkbox/checkbox.vue'
 export default {
-  props: {
-    // Name of opacity, used for identifying
-    name: {
-      required: true,
-      type: String
-    },
-    // Opacity value, should be required but vue cannot tell the difference
-    // between "property missing" and "property set to undefined"
-    value: {
-      required: false,
-      type: Number,
-      default: undefined
-    },
-    // Opacity fallback to use when value is not defeind
-    fallback: {
-      required: false,
-      type: Number,
-      default: undefined
-    },
-    // Disable the control
-    disabled: {
-      required: false,
-      type: Boolean,
-      default: false
-    },
-    // Show "optional" tickbox, for when value might become mandatory
-    showOptionalTickbox: {
-      required: false,
-      type: Boolean,
-      default: true
-    }
+  props: [
+    'name', 'value', 'fallback', 'disabled'
+  ],
+  components: {
+    Checkbox
   },
   computed: {
     present () {
diff --git a/src/components/range_input/range_input.vue b/src/components/range_input/range_input.vue
index aaa2ed26..5857a5c1 100644
--- a/src/components/range_input/range_input.vue
+++ b/src/components/range_input/range_input.vue
@@ -12,7 +12,7 @@
     <input
       v-if="typeof fallback !== 'undefined'"
       :id="name + '-o'"
-      class="opt exclude-disabled"
+      class="opt"
       type="checkbox"
       :checked="present"
       @input="$emit('input', !present ? fallback : undefined)"
diff --git a/src/components/style_switcher/style_switcher.scss b/src/components/style_switcher/style_switcher.scss
index 135c113a..7291a884 100644
--- a/src/components/style_switcher/style_switcher.scss
+++ b/src/components/style_switcher/style_switcher.scss
@@ -15,12 +15,14 @@
 
     &.disabled {
       input, select {
-        &:not(.exclude-disabled) {
-          opacity: .5
-        }
+        opacity: .5
       }
     }
 
+    .opt {
+      margin: .5em;
+    }
+
     input, select {
       min-width: 3em;
       margin: 0;
@@ -44,10 +46,6 @@
         min-width: 3em;
       }
 
-      &[type=checkbox] + label {
-        margin: 6px 0;
-      }
-
       &:not([type=number]):not([type=text]) {
         align-self: flex-start;
       }
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index f5b12e7e..f993e070 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -239,7 +239,7 @@
               v-model="panelOpacityLocal"
               name="panelOpacity"
               :fallback="previewTheme.opacity.panel"
-              :showOptionalTickbox="panelColorLocal !== 'transparent'"
+              :disabled="panelColorLocal === 'transparent'"
             />
             <ColorInput
               v-model="panelTextColorLocal"
@@ -297,7 +297,7 @@
               v-model="inputOpacityLocal"
               name="inputOpacity"
               :fallback="previewTheme.opacity.input"
-              :showOptionalTickbox="inputColorLocal !== 'transparent'"
+              :disabled="inputColorLocal === 'transparent'"
             />
             <ColorInput
               v-model="inputTextColorLocal"
@@ -319,7 +319,7 @@
               v-model="btnOpacityLocal"
               name="btnOpacity"
               :fallback="previewTheme.opacity.btn"
-              :showOptionalTickbox="btnColorLocal !== 'transparent'"
+              :disabled="btnColorLocal === 'transparent'"
             />
             <ColorInput
               v-model="btnTextColorLocal"
@@ -341,7 +341,7 @@
               v-model="borderOpacityLocal"
               name="borderOpacity"
               :fallback="previewTheme.opacity.border"
-              :showOptionalTickbox="borderColorLocal !== 'transparent'"
+              :disabled="borderColorLocal === 'transparent'"
             />
           </div>
           <div class="color-item">
@@ -382,7 +382,7 @@
               v-model="underlayOpacityLocal"
               name="underlayOpacity"
               :fallback="previewTheme.opacity.underlay"
-              :showOptionalTickbox="underlayOpacityLocal !== 'transparent'"
+              :disabled="underlayOpacityLocal === 'transparent'"
             />
           </div>
         </div>
-- 
cgit v1.2.3-70-g09d2


From 4418baf62aa7a8bef05568e7590b9b4303c29dc7 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 12 Jan 2020 04:16:04 +0200
Subject: fix

---
 src/components/style_switcher/style_switcher.vue | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index f993e070..82b85bd5 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -27,8 +27,8 @@
                     :key="style.name"
                     :value="style"
                     :style="{
-                      backgroundColor: style[1] || style.theme.colors.bg,
-                      color: style[3] || style.theme.colors.text
+                      backgroundColor: style[1] || (style.theme || style.source).colors.bg,
+                      color: style[3] || (style.theme || style.source).colors.text
                     }"
                   >
                     {{ style[0] || style.name }}
-- 
cgit v1.2.3-70-g09d2


From 88f83fc9fa3652efdbe6aa622d3e0089883e8057 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 12 Jan 2020 17:46:07 +0200
Subject: overhaul how style-switcher makes state, removed tons of copy-paste

---
 src/components/style_switcher/style_switcher.js  | 214 ++++++-----------------
 src/components/style_switcher/style_switcher.vue |  12 ++
 src/services/style_setter/style_setter.js        |  15 +-
 src/services/theme_data/theme_data.service.js    |  15 +-
 4 files changed, 85 insertions(+), 171 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 4749d3f7..9c6f3266 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -14,7 +14,12 @@ import {
   composePreset,
   getThemes
 } from '../../services/style_setter/style_setter.js'
-import { CURRENT_VERSION } from '../../services/theme_data/theme_data.service.js'
+import {
+  CURRENT_VERSION,
+  SLOT_INHERITANCE,
+  DEFAULT_OPACITY,
+  getLayers
+} from '../../services/theme_data/theme_data.service.js'
 import ColorInput from '../color_input/color_input.vue'
 import RangeInput from '../range_input/range_input.vue'
 import OpacityInput from '../opacity_input/opacity_input.vue'
@@ -67,55 +72,13 @@ export default {
       keepRoundness: false,
       keepFonts: false,
 
-      textColorLocal: '',
-      accentColorLocal: undefined,
-      linkColorLocal: undefined,
-
-      bgColorLocal: '',
-      bgOpacityLocal: undefined,
-
-      underlayColorLocal: '',
-      underlayOpacityLocal: undefined,
-
-      fgColorLocal: '',
-      fgTextColorLocal: undefined,
-      fgLinkColorLocal: undefined,
-
-      btnColorLocal: undefined,
-      btnTextColorLocal: undefined,
-      btnOpacityLocal: undefined,
-
-      inputColorLocal: undefined,
-      inputTextColorLocal: undefined,
-      inputOpacityLocal: undefined,
-
-      panelColorLocal: undefined,
-      panelTextColorLocal: undefined,
-      panelLinkColorLocal: undefined,
-      panelFaintColorLocal: undefined,
-      panelOpacityLocal: undefined,
-
-      topBarColorLocal: undefined,
-      topBarTextColorLocal: undefined,
-      topBarLinkColorLocal: undefined,
-
-      alertErrorColorLocal: undefined,
-      alertWarningColorLocal: undefined,
-
-      badgeOpacityLocal: undefined,
-      badgeNotificationColorLocal: undefined,
+      ...Object.keys(SLOT_INHERITANCE)
+        .map(key => [key, ''])
+        .reduce((acc, [key, val]) => ({ ...acc, [ key + 'ColorLocal' ]: val }), {}),
 
-      borderColorLocal: undefined,
-      borderOpacityLocal: undefined,
-
-      faintColorLocal: undefined,
-      faintOpacityLocal: undefined,
-      faintLinkColorLocal: undefined,
-
-      cRedColorLocal: '',
-      cBlueColorLocal: '',
-      cGreenColorLocal: '',
-      cOrangeColorLocal: '',
+      ...Object.keys(DEFAULT_OPACITY)
+        .map(key => [key, undefined])
+        .reduce((acc, [key, val]) => ({ ...acc, [ key + 'OpacityLocal' ]: val }), {}),
 
       shadowSelected: undefined,
       shadowsLocal: {},
@@ -149,59 +112,14 @@ export default {
       return Array.isArray(this.selected) ? 1 : 2
     },
     currentColors () {
-      return {
-        bg: this.bgColorLocal,
-        text: this.textColorLocal,
-        link: this.linkColorLocal,
-
-        fg: this.fgColorLocal,
-        fgText: this.fgTextColorLocal,
-        fgLink: this.fgLinkColorLocal,
-
-        accent: this.accentColorLocal,
-
-        underlay: this.underlayColorLocal,
-
-        panel: this.panelColorLocal,
-        panelText: this.panelTextColorLocal,
-        panelLink: this.panelLinkColorLocal,
-        panelFaint: this.panelFaintColorLocal,
-
-        input: this.inputColorLocal,
-        inputText: this.inputTextColorLocal,
-
-        topBar: this.topBarColorLocal,
-        topBarText: this.topBarTextColorLocal,
-        topBarLink: this.topBarLinkColorLocal,
-
-        btn: this.btnColorLocal,
-        btnText: this.btnTextColorLocal,
-
-        alertError: this.alertErrorColorLocal,
-        alertWarning: this.alertWarningColorLocal,
-        badgeNotification: this.badgeNotificationColorLocal,
-
-        faint: this.faintColorLocal,
-        faintLink: this.faintLinkColorLocal,
-        border: this.borderColorLocal,
-
-        cRed: this.cRedColorLocal,
-        cBlue: this.cBlueColorLocal,
-        cGreen: this.cGreenColorLocal,
-        cOrange: this.cOrangeColorLocal
-      }
+      return Object.keys(SLOT_INHERITANCE)
+        .map(key => [key, this[key + 'ColorLocal']])
+        .reduce((acc, [key, val]) => ({ ...acc, [ key ]: val }), {})
     },
     currentOpacity () {
-      return {
-        bg: this.bgOpacityLocal,
-        btn: this.btnOpacityLocal,
-        input: this.inputOpacityLocal,
-        panel: this.panelOpacityLocal,
-        topBar: this.topBarOpacityLocal,
-        border: this.borderOpacityLocal,
-        faint: this.faintOpacityLocal,
-        underlay: this.underlayOpacityLocal
-      }
+      return Object.keys(DEFAULT_OPACITY)
+        .map(key => [key, this[key + 'OpacityLocal']])
+        .reduce((acc, [key, val]) => ({ ...acc, [ key + 'OpacityLocal' ]: val }), {})
     },
     currentRadii () {
       return {
@@ -237,63 +155,45 @@ export default {
         laa: ratio >= 3,
         laaa: ratio >= 4.5
       })
-
-      // fgsfds :DDDD
-      const fgs = {
-        text: colorConvert(colors.text),
-        panelText: colorConvert(colors.panelText),
-        panelLink: colorConvert(colors.panelLink),
-        btnText: colorConvert(colors.btnText),
-        topBarText: colorConvert(colors.topBarText),
-        inputText: colorConvert(colors.inputText),
-
-        link: colorConvert(colors.link),
-        topBarLink: colorConvert(colors.topBarLink),
-
-        red: colorConvert(colors.cRed),
-        green: colorConvert(colors.cGreen),
-        blue: colorConvert(colors.cBlue),
-        orange: colorConvert(colors.cOrange)
-      }
-
-      const bgs = {
-        bg: colorConvert(colors.bg),
-        underlay: colorConvert(colors.underlay),
-        btn: colorConvert(colors.btn),
-        panel: colorConvert(colors.panel),
-        topBar: colorConvert(colors.topBar),
-        input: colorConvert(colors.input),
-        alertError: colorConvert(colors.alertError),
-        alertWarning: colorConvert(colors.alertWarning),
-        badgeNotification: colorConvert(colors.badgeNotification)
-      }
-
-      const bg = [bgs.bg, opacity.bg]
-      const underlay = [bgs.underlay || colorConvert('#000000'), opacity.underlay]
-
-      const panel = [underlay, bg]
-
-      const ratios = {
-        bgText: getContrastRatioLayers(fgs.text, panel, fgs.text),
-        bgLink: getContrastRatioLayers(fgs.link, panel, fgs.link),
-        bgRed: getContrastRatioLayers(fgs.red, panel, fgs.red),
-        bgGreen: getContrastRatioLayers(fgs.green, panel, fgs.green),
-        bgBlue: getContrastRatioLayers(fgs.blue, panel, fgs.blue),
-        bgOrange: getContrastRatioLayers(fgs.orange, panel, fgs.orange),
-
-        // TODO what's this?
-        tintText: getContrastRatio(alphaBlend(bgs.bg, 0.5, fgs.panelText), fgs.text),
-
-        panelText: getContrastRatioLayers(fgs.text, [...panel, [bgs.panel, opacity.panel]], fgs.panelText),
-        panelLink: getContrastRatioLayers(fgs.link, [...panel, [bgs.panel, opacity.panel]], fgs.panelLink),
-
-        btnText: getContrastRatioLayers(fgs.text, [...panel, [bgs.btn, opacity.btn]], fgs.btnText),
-
-        inputText: getContrastRatioLayers(fgs.text, [...panel, [bgs.input, opacity.input]], fgs.inputText),
-
-        topBarText: getContrastRatioLayers(fgs.text, [...panel, [bgs.topBar, opacity.topBar]], fgs.topBarText),
-        topBarLink: getContrastRatioLayers(fgs.link, [...panel, [bgs.topBar, opacity.topBar]], fgs.topBarLink)
-      }
+      const colorsConverted = Object.entries(colors).reduce((acc, [key, value]) => ({ ...acc, [key]: colorConvert(value) }), {})
+
+      const ratios = Object.entries(SLOT_INHERITANCE).reduce((acc, [key, value]) => {
+        const slotIsBaseText = key === 'text' || key === 'link'
+        const slotIsText = slotIsBaseText || (
+          typeof value === 'object' && value !== null && value.textColor
+        )
+        if (!slotIsText) return acc
+        const { layer, variant } = slotIsBaseText ? { layer: 'bg' } : value
+        const background = variant || layer
+        const textColors = [
+          key,
+          ...(background === 'bg' ? ['cRed', 'cGreen', 'cBlue', 'cOrange'] : [])
+        ]
+
+        const layers = getLayers(
+          layer,
+          variant || layer,
+          colorsConverted,
+          opacity
+        )
+
+        return {
+          ...acc,
+          ...textColors.reduce((acc, textColorKey) => {
+            const newKey = slotIsBaseText
+              ? 'bg' + textColorKey[0].toUpperCase() + textColorKey.slice(1)
+              : textColorKey
+            return {
+              ...acc,
+              [newKey]: getContrastRatioLayers(
+                colorsConverted[textColorKey],
+                layers,
+                colorsConverted[textColorKey]
+              )
+            }
+          }, {})
+        }
+      }, {})
 
       return Object.entries(ratios).reduce((acc, [k, v]) => { acc[k] = hints(v); return acc }, {})
     },
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 82b85bd5..b059eb8a 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -209,6 +209,12 @@
               :label="$t('settings.style.advanced_colors.alert_error')"
               :fallback="previewTheme.colors.alertError"
             />
+            <ColorInput
+              v-model="alertErrorTextColorLocal"
+              name="alertErrorText"
+              :label="$t('settings.text')"
+              :fallback="previewTheme.colors.alertErrorText"
+            />
             <ContrastRatio :contrast="previewContrast.alertError" />
             <ColorInput
               v-model="alertWarningColorLocal"
@@ -217,6 +223,12 @@
               :fallback="previewTheme.colors.alertWarning"
             />
             <ContrastRatio :contrast="previewContrast.alertWarning" />
+            <ColorInput
+              v-model="alertWarningTextColorLocal"
+              name="alertWarningText"
+              :label="$t('settings.text')"
+              :fallback="previewTheme.colors.alertWarningText"
+            />
           </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.badge') }}</h4>
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 516fb5f6..e11516c0 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -1,7 +1,7 @@
 import { times } from 'lodash'
 import { convert } from 'chromatism'
 import { rgb2hex, hex2rgb, rgba2css, getCssColor } from '../color_convert/color_convert.js'
-import { getColors } from '../theme_data/theme_data.service.js'
+import { getColors, DEFAULT_OPACITY } from '../theme_data/theme_data.service.js'
 
 // While this is not used anymore right now, I left it in if we want to do custom
 // styles that aren't just colors, so user can pick from a few different distinct
@@ -115,18 +115,7 @@ const getCssShadowFilter = (input) => {
 }
 
 export const generateColors = (themeData) => {
-  const rawOpacity = Object.assign({
-    panel: 1,
-    btn: 1,
-    border: 1,
-    bg: 1,
-    badge: 1,
-    text: 1,
-    alert: 0.5,
-    input: 0.5,
-    faint: 0.5,
-    underlay: 0.15
-  }, Object.entries(themeData.opacity || {}).reduce((acc, [k, v]) => {
+  const rawOpacity = Object.assign({ ...DEFAULT_OPACITY }, Object.entries(themeData.opacity || {}).reduce((acc, [k, v]) => {
     if (typeof v !== 'undefined') {
       acc[k] = v
     }
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index 1117ab05..297d0223 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -23,6 +23,19 @@ export const LAYERS = {
   alertPanel: 'panel'
 }
 
+export const DEFAULT_OPACITY = {
+  panel: 1,
+  btn: 1,
+  border: 1,
+  bg: 1,
+  badge: 1,
+  text: 1,
+  alert: 0.5,
+  input: 0.5,
+  faint: 0.5,
+  underlay: 0.15
+}
+
 export const SLOT_INHERITANCE = {
   bg: null,
   fg: null,
@@ -289,7 +302,7 @@ export const getColors = (sourceColors, sourceOpacity, mod) => SLOT_ORDERED.redu
       if (value.textColor === 'bw') {
         return {
           ...acc,
-          [key]: contrastRatio(bg)
+          [key]: contrastRatio(bg).rgb
         }
       } else {
         return {
-- 
cgit v1.2.3-70-g09d2


From 3492d7f81ec3f99c4f15f9ab75f658b3d1db7799 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 12 Jan 2020 17:59:41 +0200
Subject: eslint

---
 src/components/color_input/color_input.vue       | 8 ++++----
 src/components/opacity_input/opacity_input.vue   | 8 ++++----
 src/components/settings/settings.vue             | 4 ++--
 src/components/style_switcher/style_switcher.vue | 6 +++---
 4 files changed, 13 insertions(+), 13 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/color_input/color_input.vue b/src/components/color_input/color_input.vue
index 7fe04433..e54409fe 100644
--- a/src/components/color_input/color_input.vue
+++ b/src/components/color_input/color_input.vue
@@ -13,8 +13,8 @@
       v-if="typeof fallback !== 'undefined' && showOptionalTickbox"
       :checked="present"
       :disabled="disabled"
-      @change="$emit('input', typeof value === 'undefined' ? fallback : undefined)"
       class="opt"
+      @change="$emit('input', typeof value === 'undefined' ? fallback : undefined)"
     />
     <div class="input color-input-field">
       <input
@@ -46,6 +46,9 @@
 import Checkbox from '../checkbox/checkbox.vue'
 import { hex2rgb } from '../../services/color_convert/color_convert.js'
 export default {
+  components: {
+    Checkbox
+  },
   props: {
     // Name of color, used for identifying
     name: {
@@ -83,9 +86,6 @@ export default {
       default: true
     }
   },
-  components: {
-    Checkbox
-  },
   computed: {
     present () {
       return typeof this.value !== 'undefined'
diff --git a/src/components/opacity_input/opacity_input.vue b/src/components/opacity_input/opacity_input.vue
index cfda9926..3cc3942b 100644
--- a/src/components/opacity_input/opacity_input.vue
+++ b/src/components/opacity_input/opacity_input.vue
@@ -13,8 +13,8 @@
       v-if="typeof fallback !== 'undefined'"
       :checked="present"
       :disabled="disabled"
-      @change="$emit('input', !present ? fallback : undefined)"
       class="opt"
+      @change="$emit('input', !present ? fallback : undefined)"
     />
     <input
       :id="name"
@@ -33,12 +33,12 @@
 <script>
 import Checkbox from '../checkbox/checkbox.vue'
 export default {
-  props: [
-    'name', 'value', 'fallback', 'disabled'
-  ],
   components: {
     Checkbox
   },
+  props: [
+    'name', 'value', 'fallback', 'disabled'
+  ],
   computed: {
     present () {
       return typeof this.value !== 'undefined'
diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue
index b40c85dd..e118dbcc 100644
--- a/src/components/settings/settings.vue
+++ b/src/components/settings/settings.vue
@@ -76,9 +76,9 @@
                 <li>
                   <Checkbox v-model="useStreamingApi">
                     {{ $t('settings.useStreamingApi') }}
-                    <br/>
+                    <br>
                     <small>
-                    {{ $t('settings.useStreamingApiWarning') }}
+                      {{ $t('settings.useStreamingApiWarning') }}
                     </small>
                   </Checkbox>
                 </li>
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index b059eb8a..ff6a8264 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -119,14 +119,14 @@
               name="accentColor"
               :fallback="previewTheme.colors.link"
               :label="$t('settings.accent')"
-              :showOptionalTickbox="typeof linkColorLocal !== 'undefined'"
+              :show-optional-tickbox="typeof linkColorLocal !== 'undefined'"
             />
             <ColorInput
               v-model="linkColorLocal"
               name="linkColor"
               :fallback="previewTheme.colors.accent"
               :label="$t('settings.links')"
-              :showOptionalTickbox="typeof accentColorLocal !== 'undefined'"
+              :show-optional-tickbox="typeof accentColorLocal !== 'undefined'"
             />
             <ContrastRatio :contrast="previewContrast.bgLink" />
           </div>
@@ -388,7 +388,7 @@
               v-model="underlayColorLocal"
               name="underlay"
               :label="$t('settings.style.advanced_colors.underlay')"
-              fallback='#000000'
+              fallback="#000000"
             />
             <OpacityInput
               v-model="underlayOpacityLocal"
-- 
cgit v1.2.3-70-g09d2


From 40ba3e225209539639b65c2f636fa1b5af9861ff Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 12 Jan 2020 23:41:11 +0200
Subject: added more slots to UI

---
 src/components/poll/poll.vue                     |  4 ++-
 src/components/style_switcher/style_switcher.vue | 37 ++++++++++++++++++++++--
 src/i18n/en.json                                 |  4 ++-
 src/services/theme_data/theme_data.service.js    | 15 +++++++---
 4 files changed, 51 insertions(+), 9 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/poll/poll.vue b/src/components/poll/poll.vue
index db8e33b3..56e91cca 100644
--- a/src/components/poll/poll.vue
+++ b/src/components/poll/poll.vue
@@ -104,8 +104,10 @@
   .result-fill {
     height: 100%;
     position: absolute;
+    color: $fallback--text;
+    color: var(--pollText, $fallback--text);
     background-color: $fallback--lightBg;
-    background-color: var(--linkBg, $fallback--lightBg);
+    background-color: var(--poll, $fallback--lightBg);
     border-radius: $fallback--panelRadius;
     border-radius: var(--panelRadius, $fallback--panelRadius);
     top: 0;
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index ff6a8264..e0894b6d 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -215,20 +215,20 @@
               :label="$t('settings.text')"
               :fallback="previewTheme.colors.alertErrorText"
             />
-            <ContrastRatio :contrast="previewContrast.alertError" />
+            <ContrastRatio :contrast="previewContrast.alertErrorText" large="1"/>
             <ColorInput
               v-model="alertWarningColorLocal"
               name="alertWarning"
               :label="$t('settings.style.advanced_colors.alert_warning')"
               :fallback="previewTheme.colors.alertWarning"
             />
-            <ContrastRatio :contrast="previewContrast.alertWarning" />
             <ColorInput
               v-model="alertWarningTextColorLocal"
               name="alertWarningText"
               :label="$t('settings.text')"
               :fallback="previewTheme.colors.alertWarningText"
             />
+            <ContrastRatio :contrast="previewContrast.alertWarningText" large="1"/>
           </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.badge') }}</h4>
@@ -238,6 +238,13 @@
               :label="$t('settings.style.advanced_colors.badge_notification')"
               :fallback="previewTheme.colors.badgeNotification"
             />
+            <ColorInput
+              v-model="badgeNotificationTextColorLocal"
+              name="badgeNotificationText"
+              :label="$t('settings.text')"
+              :fallback="previewTheme.colors.badgeNotificationText"
+            />
+            <ContrastRatio :contrast="previewContrast.badgeNotificationText" large="1" />
           </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.panel_header') }}</h4>
@@ -388,7 +395,7 @@
               v-model="underlayColorLocal"
               name="underlay"
               :label="$t('settings.style.advanced_colors.underlay')"
-              fallback="#000000"
+              :fallback="previewTheme.colors.underlay"
             />
             <OpacityInput
               v-model="underlayOpacityLocal"
@@ -397,6 +404,30 @@
               :disabled="underlayOpacityLocal === 'transparent'"
             />
           </div>
+          <div class="color-item">
+            <h4>{{ $t('settings.style.advanced_colors.poll') }}</h4>
+            <ColorInput
+              v-model="pollColorLocal"
+              name="poll"
+              :label="$t('settings.background')"
+              :fallback="previewTheme.colors.poll"
+            />
+            <ColorInput
+              v-model="pollTextColorLocal"
+              name="poll"
+              :label="$t('settings.text')"
+              :fallback="previewTheme.colors.pollText"
+            />
+          </div>
+          <div class="color-item">
+            <h4>{{ $t('settings.style.advanced_colors.icons') }}</h4>
+            <ColorInput
+              v-model="iconColorLocal"
+              name="poll"
+              :label="$t('settings.style.advanced_colors.icons')"
+              :fallback="previewTheme.colors.icon"
+            />
+          </div>
         </div>
 
         <div
diff --git a/src/i18n/en.json b/src/i18n/en.json
index d97b4909..bd3d7413 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -431,7 +431,9 @@
         "buttons": "Buttons",
         "inputs": "Input fields",
         "faint_text": "Faded text",
-        "underlay": "Underlay"
+        "underlay": "Underlay",
+        "poll": "Poll graph",
+        "icons": "Icons"
       },
       "radii": {
         "_tab_label": "Roundness"
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index e2e9331c..21bab1a2 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -20,7 +20,8 @@ export const LAYERS = {
   inputPanel: 'panel',
   inputTopBar: 'topBar',
   alert: 'bg',
-  alertPanel: 'panel'
+  alertPanel: 'panel',
+  poll: 'bg'
 }
 
 export const DEFAULT_OPACITY = {
@@ -33,7 +34,8 @@ export const DEFAULT_OPACITY = {
   alert: 0.5,
   input: 0.5,
   faint: 0.5,
-  underlay: 0.15
+  underlay: 0.15,
+  poll: 1
 }
 
 export const SLOT_INHERITANCE = {
@@ -65,9 +67,14 @@ export const SLOT_INHERITANCE = {
     color: (mod, fg) => brightness(2 * mod, fg).rgb
   },
 
-  linkBg: {
+  poll: {
     depends: ['accent', 'bg'],
-    color: (mod, accent, bg) => alphaBlend(accent, 0.4, bg).rgb
+    color: (mod, accent, bg) => alphaBlend(accent, 0.4, bg)
+  },
+  pollText: {
+    depends: ['text'],
+    layer: 'poll',
+    textColor: true
   },
 
   icon: {
-- 
cgit v1.2.3-70-g09d2


From 8f63bbb64fa2860e73d8562de9d6c62629a8668f Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 13 Jan 2020 00:33:04 +0200
Subject: poll slot renamed, lightBg customization implemented

---
 src/App.scss                                       |  4 ++++
 src/components/autosuggest/autosuggest.vue         |  4 ++--
 src/components/dialog_modal/dialog_modal.vue       | 12 +++++-----
 src/components/emoji_input/emoji_input.vue         |  4 ++++
 src/components/nav_panel/nav_panel.vue             | 10 ++++++++
 src/components/selectable_list/selectable_list.vue |  4 ++++
 src/components/side_drawer/side_drawer.vue         |  5 ++++
 src/components/status/status.vue                   |  7 ++++--
 src/components/style_switcher/style_switcher.vue   | 27 ++++++++++++++++++++--
 src/services/style_setter/style_setter.js          |  4 +++-
 src/services/theme_data/theme_data.service.js      | 26 +++++++++++++++++++++
 11 files changed, 94 insertions(+), 13 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/App.scss b/src/App.scss
index 7c9c91af..7da3688a 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -495,6 +495,10 @@ main-router {
     color: $fallback--faint;
     color: var(--panelFaint, $fallback--faint);
   }
+  .faint-link {
+    color: $fallback--faint;
+    color: var(--faintLink, $fallback--faint);
+  }
 
   .alert {
     white-space: nowrap;
diff --git a/src/components/autosuggest/autosuggest.vue b/src/components/autosuggest/autosuggest.vue
index 1f86e996..f283ab82 100644
--- a/src/components/autosuggest/autosuggest.vue
+++ b/src/components/autosuggest/autosuggest.vue
@@ -40,8 +40,8 @@
     top: 100%;
     right: 0;
     max-height: 400px;
-    background-color: $fallback--lightBg;
-    background-color: var(--lightBg, $fallback--lightBg);
+    background-color: $fallback--bg;
+    background-color: var(--bg, $fallback--bg);
     border-style: solid;
     border-width: 1px;
     border-color: $fallback--border;
diff --git a/src/components/dialog_modal/dialog_modal.vue b/src/components/dialog_modal/dialog_modal.vue
index 55d7a7d2..3241ce3e 100644
--- a/src/components/dialog_modal/dialog_modal.vue
+++ b/src/components/dialog_modal/dialog_modal.vue
@@ -75,18 +75,18 @@
   .dialog-modal-content {
     margin: 0;
     padding: 1rem 1rem;
-    background-color: $fallback--lightBg;
-    background-color: var(--lightBg, $fallback--lightBg);
+    background-color: $fallback--bg;
+    background-color: var(--bg, $fallback--bg);
     white-space: normal;
   }
 
   .dialog-modal-footer {
     margin: 0;
     padding: .5em .5em;
-    background-color: $fallback--lightBg;
-    background-color: var(--lightBg, $fallback--lightBg);
-    border-top: 1px solid $fallback--bg;
-    border-top: 1px solid var(--bg, $fallback--bg);
+    background-color: $fallback--bg;
+    background-color: var(--bg, $fallback--bg);
+    border-top: 1px solid $fallback--border;
+    border-top: 1px solid var(--border, $fallback--border);
     display: flex;
     justify-content: flex-end;
 
diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue
index a7215670..dcf51ff9 100644
--- a/src/components/emoji_input/emoji_input.vue
+++ b/src/components/emoji_input/emoji_input.vue
@@ -158,6 +158,10 @@
       &.highlighted {
         background-color: $fallback--fg;
         background-color: var(--lightBg, $fallback--fg);
+        color: var(--lightBgText, $fallback--text);
+        --faint: var(--lightBgFaintText, $fallback--faint);
+        --faintLink: var(--lightBgFaintLink, $fallback--faint);
+        --icon: var(--lightBgIcon, $fallback--icon);
       }
     }
   }
diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue
index 034259d9..0886bf8c 100644
--- a/src/components/nav_panel/nav_panel.vue
+++ b/src/components/nav_panel/nav_panel.vue
@@ -101,12 +101,22 @@
   &:hover {
     background-color: $fallback--lightBg;
     background-color: var(--lightBg, $fallback--lightBg);
+    color: $fallback--link;
+    color: var(--lightBgText, $fallback--link);
+    --faint: var(--lightBgFaintText, $fallback--faint);
+    --faintLink: var(--lightBgFaintLink, $fallback--faint);
+    --icon: var(--lightBgIcon, $fallback--icon);
   }
 
   &.router-link-active {
     font-weight: bolder;
     background-color: $fallback--lightBg;
     background-color: var(--lightBg, $fallback--lightBg);
+    color: $fallback--text;
+    color: var(--lightBgText, $fallback--text);
+    --faint: var(--lightBgFaintText, $fallback--faint);
+    --faintLink: var(--lightBgFaintLink, $fallback--faint);
+    --icon: var(--lightBgIcon, $fallback--icon);
 
     &:hover {
       text-decoration: underline;
diff --git a/src/components/selectable_list/selectable_list.vue b/src/components/selectable_list/selectable_list.vue
index d9ec7ece..416c9b6a 100644
--- a/src/components/selectable_list/selectable_list.vue
+++ b/src/components/selectable_list/selectable_list.vue
@@ -69,6 +69,10 @@
   &-item-selected-inner {
     background-color: $fallback--lightBg;
     background-color: var(--lightBg, $fallback--lightBg);
+    color: var(--lightBgText, $fallback--text);
+    --faint: var(--lightBgFaintText, $fallback--faint);
+    --faintLink: var(--lightBgFaintLink, $fallback--faint);
+    --icon: var(--lightBgIcon, $fallback--icon);
   }
 
   &-header {
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index 3fba9058..6d75221f 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -290,6 +290,11 @@
     &:hover {
       background-color: $fallback--lightBg;
       background-color: var(--lightBg, $fallback--lightBg);
+      color: $fallback--text;
+      color: var(--lightBgText, $fallback--text);
+      --faint: var(--lightBgFaintText, $fallback--faint);
+      --faintLink: var(--lightBgFaintLink, $fallback--faint);
+      --icon: var(--lightBgIcon, $fallback--icon);
     }
   }
 }
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index d291e762..72e9b25a 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -446,6 +446,11 @@ $status-margin: 0.75em;
   &_focused {
     background-color: $fallback--lightBg;
     background-color: var(--lightBg, $fallback--lightBg);
+    color: $fallback--text;
+    color: var(--lightBgText, $fallback--text);
+    --faint: var(--lightBgFaintText, $fallback--faint);
+    --faintLink: var(--lightBgFaintLink, $fallback--faint);
+    --icon: var(--lightBgIcon, $fallback--icon);
   }
 
   .timeline & {
@@ -573,8 +578,6 @@ $status-margin: 0.75em;
       overflow: hidden;
       text-overflow: ellipsis;
       margin: 0 0.4em 0 0.2em;
-      color: $fallback--faint;
-      color: var(--faint, $fallback--faint);
     }
 
     .replies-separator {
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index e0894b6d..1381f1fb 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -414,7 +414,7 @@
             />
             <ColorInput
               v-model="pollTextColorLocal"
-              name="poll"
+              name="pollText"
               :label="$t('settings.text')"
               :fallback="previewTheme.colors.pollText"
             />
@@ -423,11 +423,34 @@
             <h4>{{ $t('settings.style.advanced_colors.icons') }}</h4>
             <ColorInput
               v-model="iconColorLocal"
-              name="poll"
+              name="icon"
               :label="$t('settings.style.advanced_colors.icons')"
               :fallback="previewTheme.colors.icon"
             />
           </div>
+          <div class="color-item">
+            <h4>{{ $t('settings.style.advanced_colors.lightBg') }}</h4>
+            <ColorInput
+              v-model="lightBgColorLocal"
+              name="lightBg"
+              :label="$t('settings.style.advanced_colors.lightBg')"
+              :fallback="previewTheme.colors.lightBg"
+            />
+            <ColorInput
+              v-model="lightBgTextColorLocal"
+              name="lightBgText"
+              :label="$t('settings.text')"
+              :fallback="previewTheme.colors.lightBgText"
+            />
+            <ContrastRatio :contrast="previewContrast.lightBgText" />
+            <ColorInput
+              v-model="lightBgLinkColorLocal"
+              name="lightBgLink"
+              :label="$t('settings.links')"
+              :fallback="previewTheme.colors.lightBgLink"
+            />
+            <ContrastRatio :contrast="previewContrast.lightBgLink" />
+          </div>
         </div>
 
         <div
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index e11516c0..204c162b 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -163,8 +163,10 @@ export const generateColors = (themeData) => {
       return
     }
     if (k === 'faint') {
-      colors[k + 'Link'].a = v
+      colors['faintLink'].a = v
       colors['panelFaint'].a = v
+      colors['lightBgFaintText'].a = v
+      colors['lightBgFaintLink'].a = v
     }
     if (k === 'bg') {
       colors['lightBg'].a = v
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index 21bab1a2..808f67d5 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -12,6 +12,7 @@ export const LAYERS = {
   badge: null, //  no transparency support
   fg: null,
   bg: 'underlay',
+  lightBg: 'bg',
   panel: 'bg',
   btn: 'bg',
   btnPanel: 'panel',
@@ -57,6 +58,31 @@ export const SLOT_INHERITANCE = {
     depends: ['bg'],
     color: (mod, bg) => brightness(5 * mod, bg).rgb
   },
+  lightBgFaintText: {
+    depends: ['faint'],
+    layer: 'lightBg',
+    textColor: true
+  },
+  lightBgFaintLink: {
+    depends: ['faintLink'],
+    layer: 'lightBg',
+    textColor: 'preserve'
+  },
+  lightBgText: {
+    depends: ['text'],
+    layer: 'lightBg',
+    textColor: true
+  },
+  lightBgLink: {
+    depends: ['link'],
+    layer: 'lightBg',
+    textColor: 'preserve'
+  },
+  lightBgIcon: {
+    depends: ['lightBg', 'lightBgText'],
+    color: (mod, bg, text) => mixrgb(bg, text)
+  },
+
   lightText: {
     depends: ['text'],
     color: (mod, text) => brightness(20 * mod, text).rgb
-- 
cgit v1.2.3-70-g09d2


From fa2fcc882737c8c057fd12d4cc1a85d67f3b672e Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 13 Jan 2020 01:54:56 +0200
Subject: better fallbacks in UI

---
 src/components/style_switcher/style_switcher.vue | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 1381f1fb..c1ec7c9a 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -251,7 +251,7 @@
             <ColorInput
               v-model="panelColorLocal"
               name="panelColor"
-              :fallback="fgColorLocal"
+              :fallback="previewTheme.colors.panel"
               :label="$t('settings.background')"
             />
             <OpacityInput
@@ -286,7 +286,7 @@
             <ColorInput
               v-model="topBarColorLocal"
               name="topBarColor"
-              :fallback="fgColorLocal"
+              :fallback="previewTheme.colors.topBar"
               :label="$t('settings.background')"
             />
             <ColorInput
@@ -309,7 +309,7 @@
             <ColorInput
               v-model="inputColorLocal"
               name="inputColor"
-              :fallback="fgColorLocal"
+              :fallback="previewTheme.colors.input"
               :label="$t('settings.background')"
             />
             <OpacityInput
@@ -331,7 +331,7 @@
             <ColorInput
               v-model="btnColorLocal"
               name="btnColor"
-              :fallback="fgColorLocal"
+              :fallback="previewTheme.colors.btn"
               :label="$t('settings.background')"
             />
             <OpacityInput
-- 
cgit v1.2.3-70-g09d2


From 8d2f2866f6d32b4ada155d76e07910b92c218146 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 13 Jan 2020 01:56:29 +0200
Subject: computed colors support

---
 src/App.scss                                     |  4 ++
 src/components/style_switcher/style_switcher.js  |  6 ++-
 src/components/style_switcher/style_switcher.vue | 16 +++++-
 src/i18n/en.json                                 |  4 +-
 src/services/style_setter/style_setter.js        |  6 ++-
 src/services/theme_data/theme_data.service.js    | 69 +++++++++++++++++++++---
 6 files changed, 92 insertions(+), 13 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/App.scss b/src/App.scss
index 7da3688a..ef139e88 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -99,6 +99,10 @@ button {
   &:active {
     box-shadow: 0px 0px 4px 0px rgba(255, 255, 255, 0.3), 0px 1px 0px 0px rgba(0, 0, 0, 0.2) inset, 0px -1px 0px 0px rgba(255, 255, 255, 0.2) inset;
     box-shadow: var(--buttonPressedShadow);
+    color: $fallback--text;
+    color: var(--btnPressedText, $fallback--text);
+    background-color: $fallback--fg;
+    background-color: var(--btnPressed, $fallback--fg)
   }
 
   &:disabled {
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 49b34405..b84d2489 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -42,7 +42,7 @@ const v1OnlyNames = [
 ].map(_ => _ + 'ColorLocal')
 
 const colorConvert = (color) => {
-  if (color === 'transparent') {
+  if (color.startsWith('--') || color === 'transparent') {
     return color
   } else {
     return hex2rgb(color)
@@ -409,7 +409,9 @@ export default {
         }
 
         keys.forEach(key => {
-          this[key + 'ColorLocal'] = rgb2hex(colors[key])
+          const color = colors[key]
+          const hex = rgb2hex(colors[key])
+          this[key + 'ColorLocal'] = hex === '#aN' ? color : hex
         })
       }
 
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index c1ec7c9a..f2fdfea2 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -347,6 +347,20 @@
               :label="$t('settings.text')"
             />
             <ContrastRatio :contrast="previewContrast.btnText" />
+            <h4>{{ $t('settings.style.advanced_colors.pressed') }}</h4>
+            <ColorInput
+              v-model="btnPressedColorLocal"
+              name="btnPressedColor"
+              :fallback="previewTheme.colors.btnPressed"
+              :label="$t('settings.background')"
+            />
+            <ColorInput
+              v-model="btnPressedTextColorLocal"
+              name="btnPressedTextColor"
+              :fallback="previewTheme.colors.btnPressedText"
+              :label="$t('settings.text')"
+            />
+            <ContrastRatio :contrast="previewContrast.btnText" />
           </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.borders') }}</h4>
@@ -433,7 +447,7 @@
             <ColorInput
               v-model="lightBgColorLocal"
               name="lightBg"
-              :label="$t('settings.style.advanced_colors.lightBg')"
+              :label="$t('settings.background')"
               :fallback="previewTheme.colors.lightBg"
             />
             <ColorInput
diff --git a/src/i18n/en.json b/src/i18n/en.json
index bd3d7413..544bc2ba 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -433,7 +433,9 @@
         "faint_text": "Faded text",
         "underlay": "Underlay",
         "poll": "Poll graph",
-        "icons": "Icons"
+        "icons": "Icons",
+        "lightBg": "Highlighted elements",
+        "pressed": "Pressed"
       },
       "radii": {
         "_tab_label": "Roundness"
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 204c162b..61612cf4 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -144,7 +144,11 @@ export const generateColors = (themeData) => {
         // TODO: hack to keep rest of the code from complaining
         value = '#FF00FF'
       }
-      acc[k] = hex2rgb(value)
+      if (!value || value.startsWith('--')) {
+        acc[k] = value
+      } else {
+        acc[k] = hex2rgb(value)
+      }
     }
     return acc
   }, {})
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index 808f67d5..221c3b48 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -40,12 +40,27 @@ export const DEFAULT_OPACITY = {
 }
 
 export const SLOT_INHERITANCE = {
-  bg: null,
-  fg: null,
-  text: null,
+  bg: {
+    depends: [],
+    priority: 1
+  },
+  fg: {
+    depends: [],
+    priority: 1
+  },
+  text: {
+    depends: [],
+    priority: 1
+  },
   underlay: '#000000',
-  link: '--accent',
-  accent: '--link',
+  link: {
+    depends: ['accent'],
+    priority: 1
+  },
+  accent: {
+    depends: ['link'],
+    priority: 1
+  },
   faint: '--text',
   faintLink: '--link',
 
@@ -170,6 +185,26 @@ export const SLOT_INHERITANCE = {
     textColor: true
   },
 
+  btnPressed: '--btn',
+  btnPressedText: {
+    depends: ['btnText'],
+    layer: 'btn',
+    variant: 'btnPressed',
+    textColor: true
+  },
+  btnPressedPanelText: {
+    depends: ['btnPanelText'],
+    layer: 'btnPanel',
+    variant: 'btnPressed',
+    textColor: true
+  },
+  btnPressedTopBarText: {
+    depends: ['btnTopBarText'],
+    layer: 'btnTopBar',
+    variant: 'btnPressed',
+    textColor: true
+  },
+
   // Input fields
   input: '--fg',
   inputText: {
@@ -308,12 +343,30 @@ export const topoSort = (
   return output
 }
 
-export const SLOT_ORDERED = topoSort(SLOT_INHERITANCE)
+export const SLOT_ORDERED = topoSort(
+  Object.entries(SLOT_INHERITANCE)
+    .sort(([aK, aV], [bK, bV]) => ((aV && aV.priority) || 0) - ((bV && bV.priority) || 0))
+    .reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {})
+)
+
+console.log(SLOT_ORDERED)
 
 export const getColors = (sourceColors, sourceOpacity, mod) => SLOT_ORDERED.reduce((acc, key) => {
   const value = SLOT_INHERITANCE[key]
-  if (sourceColors[key]) {
-    return { ...acc, [key]: { ...sourceColors[key] } }
+  const sourceColor = sourceColors[key]
+  if (sourceColor) {
+    let targetColor = sourceColor
+    if (typeof sourceColor === 'string' && sourceColor.startsWith('--')) {
+      const [variable, modifier] = sourceColor.split(/,/g).map(str => str.trim())
+      const variableSlot = variable.substring(2)
+      targetColor = acc[variableSlot] || sourceColors[variableSlot]
+      if (modifier) {
+        console.log(targetColor, acc, variableSlot)
+        targetColor = brightness(Number.parseFloat(modifier) * mod, targetColor).rgb
+      }
+      console.log(targetColor, acc, variableSlot)
+    }
+    return { ...acc, [key]: { ...targetColor } }
   } else if (typeof value === 'string' && value.startsWith('#')) {
     return { ...acc, [key]: convert(value).rgb }
   } else {
-- 
cgit v1.2.3-70-g09d2


From 8a7f3fc16a511e6c5917c0e25cba1f6163659264 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 13 Jan 2020 20:40:16 +0200
Subject: selectedPost and selectedMenu support

---
 src/components/emoji_input/emoji_input.vue         | 10 ++---
 src/components/nav_panel/nav_panel.vue             | 20 ++++-----
 src/components/selectable_list/selectable_list.vue | 10 ++---
 src/components/side_drawer/side_drawer.vue         | 10 ++---
 src/components/status/status.vue                   | 10 ++---
 src/components/style_switcher/style_switcher.vue   | 46 +++++++++++++++++++
 src/services/theme_data/theme_data.service.js      | 52 ++++++++++++++++++++++
 7 files changed, 128 insertions(+), 30 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue
index dcf51ff9..46ed6f25 100644
--- a/src/components/emoji_input/emoji_input.vue
+++ b/src/components/emoji_input/emoji_input.vue
@@ -157,11 +157,11 @@
 
       &.highlighted {
         background-color: $fallback--fg;
-        background-color: var(--lightBg, $fallback--fg);
-        color: var(--lightBgText, $fallback--text);
-        --faint: var(--lightBgFaintText, $fallback--faint);
-        --faintLink: var(--lightBgFaintLink, $fallback--faint);
-        --icon: var(--lightBgIcon, $fallback--icon);
+        background-color: var(--selectedMenu, $fallback--fg);
+        color: var(--selectedMenuText, $fallback--text);
+        --faint: var(--selectedMenuFaintText, $fallback--faint);
+        --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
+        --icon: var(--selectedMenuIcon, $fallback--icon);
       }
     }
   }
diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue
index 0886bf8c..afc611ea 100644
--- a/src/components/nav_panel/nav_panel.vue
+++ b/src/components/nav_panel/nav_panel.vue
@@ -100,23 +100,23 @@
 
   &:hover {
     background-color: $fallback--lightBg;
-    background-color: var(--lightBg, $fallback--lightBg);
+    background-color: var(--selectedMenu, $fallback--lightBg);
     color: $fallback--link;
-    color: var(--lightBgText, $fallback--link);
-    --faint: var(--lightBgFaintText, $fallback--faint);
-    --faintLink: var(--lightBgFaintLink, $fallback--faint);
-    --icon: var(--lightBgIcon, $fallback--icon);
+    color: var(--selectedMenuText, $fallback--link);
+    --faint: var(--selectedMenuFaintText, $fallback--faint);
+    --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
+    --icon: var(--selectedMenuIcon, $fallback--icon);
   }
 
   &.router-link-active {
     font-weight: bolder;
     background-color: $fallback--lightBg;
-    background-color: var(--lightBg, $fallback--lightBg);
+    background-color: var(--selectedMenu, $fallback--lightBg);
     color: $fallback--text;
-    color: var(--lightBgText, $fallback--text);
-    --faint: var(--lightBgFaintText, $fallback--faint);
-    --faintLink: var(--lightBgFaintLink, $fallback--faint);
-    --icon: var(--lightBgIcon, $fallback--icon);
+    color: var(--selectedMenuText, $fallback--text);
+    --faint: var(--selectedMenuFaintText, $fallback--faint);
+    --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
+    --icon: var(--selectedMenuIcon, $fallback--icon);
 
     &:hover {
       text-decoration: underline;
diff --git a/src/components/selectable_list/selectable_list.vue b/src/components/selectable_list/selectable_list.vue
index 416c9b6a..2d1e44a3 100644
--- a/src/components/selectable_list/selectable_list.vue
+++ b/src/components/selectable_list/selectable_list.vue
@@ -68,11 +68,11 @@
 
   &-item-selected-inner {
     background-color: $fallback--lightBg;
-    background-color: var(--lightBg, $fallback--lightBg);
-    color: var(--lightBgText, $fallback--text);
-    --faint: var(--lightBgFaintText, $fallback--faint);
-    --faintLink: var(--lightBgFaintLink, $fallback--faint);
-    --icon: var(--lightBgIcon, $fallback--icon);
+    background-color: var(--selectedMenu, $fallback--lightBg);
+    color: var(--selectedMenuText, $fallback--text);
+    --faint: var(--selectedMenuFaintText, $fallback--faint);
+    --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
+    --icon: var(--selectedMenuIcon, $fallback--icon);
   }
 
   &-header {
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index 6d75221f..3188fd59 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -289,12 +289,12 @@
 
     &:hover {
       background-color: $fallback--lightBg;
-      background-color: var(--lightBg, $fallback--lightBg);
+      background-color: var(--selectedMenu, $fallback--lightBg);
       color: $fallback--text;
-      color: var(--lightBgText, $fallback--text);
-      --faint: var(--lightBgFaintText, $fallback--faint);
-      --faintLink: var(--lightBgFaintLink, $fallback--faint);
-      --icon: var(--lightBgIcon, $fallback--icon);
+      color: var(--selectedMenuText, $fallback--text);
+      --faint: var(--selectedMenuFaintText, $fallback--faint);
+      --faintLink: var(--selectedMenuFaintLink, $fallback--faint);
+      --icon: var(--selectedMenuIcon, $fallback--icon);
     }
   }
 }
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 72e9b25a..38d091ed 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -445,12 +445,12 @@ $status-margin: 0.75em;
 
   &_focused {
     background-color: $fallback--lightBg;
-    background-color: var(--lightBg, $fallback--lightBg);
+    background-color: var(--selectedPost, $fallback--lightBg);
     color: $fallback--text;
-    color: var(--lightBgText, $fallback--text);
-    --faint: var(--lightBgFaintText, $fallback--faint);
-    --faintLink: var(--lightBgFaintLink, $fallback--faint);
-    --icon: var(--lightBgIcon, $fallback--icon);
+    color: var(--selectedPostText, $fallback--text);
+    --faint: var(--selectedPostFaintText, $fallback--faint);
+    --faintLink: var(--selectedPostFaintLink, $fallback--faint);
+    --icon: var(--selectedPostIcon, $fallback--icon);
   }
 
   .timeline & {
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index f2fdfea2..613abd1f 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -465,6 +465,52 @@
             />
             <ContrastRatio :contrast="previewContrast.lightBgLink" />
           </div>
+          <div class="color-item">
+            <h4>{{ $t('settings.style.advanced_colors.selectedPost') }}</h4>
+            <ColorInput
+              v-model="selectedPostColorLocal"
+              name="selectedPost"
+              :label="$t('settings.background')"
+              :fallback="previewTheme.colors.selectedPost"
+            />
+            <ColorInput
+              v-model="selectedPostTextColorLocal"
+              name="selectedPostText"
+              :label="$t('settings.text')"
+              :fallback="previewTheme.colors.selectedPostText"
+            />
+            <ContrastRatio :contrast="previewContrast.selectedPostText" />
+            <ColorInput
+              v-model="selectedPostLinkColorLocal"
+              name="selectedPostLink"
+              :label="$t('settings.links')"
+              :fallback="previewTheme.colors.selectedPostLink"
+            />
+            <ContrastRatio :contrast="previewContrast.selectedPostLink" />
+          </div>
+          <div class="color-item">
+            <h4>{{ $t('settings.style.advanced_colors.selectedMenu') }}</h4>
+            <ColorInput
+              v-model="selectedMenuColorLocal"
+              name="selectedMenu"
+              :label="$t('settings.background')"
+              :fallback="previewTheme.colors.selectedMenu"
+            />
+            <ColorInput
+              v-model="selectedMenuTextColorLocal"
+              name="selectedMenuText"
+              :label="$t('settings.text')"
+              :fallback="previewTheme.colors.selectedMenuText"
+            />
+            <ContrastRatio :contrast="previewContrast.selectedMenuText" />
+            <ColorInput
+              v-model="selectedMenuLinkColorLocal"
+              name="selectedMenuLink"
+              :label="$t('settings.links')"
+              :fallback="previewTheme.colors.selectedMenuLink"
+            />
+            <ContrastRatio :contrast="previewContrast.selectedMenuLink" />
+          </div>
         </div>
 
         <div
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index 221c3b48..dd5f8fd0 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -98,6 +98,58 @@ export const SLOT_INHERITANCE = {
     color: (mod, bg, text) => mixrgb(bg, text)
   },
 
+  selectedPost: '--lightBg',
+  selectedPostFaintText: {
+    depends: ['lightBgFaintText'],
+    layer: 'lightBg',
+    textColor: true
+  },
+  selectedPostFaintLink: {
+    depends: ['lightBgFaintLink'],
+    layer: 'lightBg',
+    textColor: 'preserve'
+  },
+  selectedPostText: {
+    depends: ['lightBgText'],
+    layer: 'lightBg',
+    textColor: true
+  },
+  selectedPostLink: {
+    depends: ['lightBgLink'],
+    layer: 'lightBg',
+    textColor: 'preserve'
+  },
+  selectedPostIcon: {
+    depends: ['selectedPost', 'selectedPostText'],
+    color: (mod, bg, text) => mixrgb(bg, text)
+  },
+
+  selectedMenu: '--lightBg',
+  selectedMenuFaintText: {
+    depends: ['lightBgFaintText'],
+    layer: 'lightBg',
+    textColor: true
+  },
+  selectedMenuFaintLink: {
+    depends: ['lightBgFaintLink'],
+    layer: 'lightBg',
+    textColor: 'preserve'
+  },
+  selectedMenuText: {
+    depends: ['lightBgText'],
+    layer: 'lightBg',
+    textColor: true
+  },
+  selectedMenuLink: {
+    depends: ['lightBgLink'],
+    layer: 'lightBg',
+    textColor: 'preserve'
+  },
+  selectedMenuIcon: {
+    depends: ['selectedMenu', 'selectedMenuText'],
+    color: (mod, bg, text) => mixrgb(bg, text)
+  },
+
   lightText: {
     depends: ['text'],
     color: (mod, text) => brightness(20 * mod, text).rgb
-- 
cgit v1.2.3-70-g09d2


From 4b8e0f0afa2c7f1d0f4f0c2f39f289b75b3cae08 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 13 Jan 2020 21:30:55 +0200
Subject: buttonPressed & buttonDisabled slots

---
 src/App.scss                                     | 44 ++++++++++++++++++++++-
 src/components/style_switcher/style_switcher.vue | 16 ++++++++-
 src/services/theme_data/theme_data.service.js    | 46 +++++++++++++++++++++---
 3 files changed, 100 insertions(+), 6 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/App.scss b/src/App.scss
index ef139e88..7f404bc6 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -107,7 +107,10 @@ button {
 
   &:disabled {
     cursor: not-allowed;
-    opacity: 0.5;
+    color: $fallback--text;
+    color: var(--btnDisabledText, $fallback--text);
+    background-color: $fallback--fg;
+    background-color: var(--btnDisabled, $fallback--fg)
   }
 
   &.pressed {
@@ -365,6 +368,26 @@ i[class*=icon-] {
   height: 50px;
   box-sizing: border-box;
 
+  button {
+    &, i[class*=icon-] {
+      color: $fallback--text;
+      color: var(--btnTopBarText, $fallback--text);
+    }
+
+    &:active {
+      background-color: $fallback--fg;
+      background-color: var(--btnTopBarPressed, $fallback--fg);
+      color: $fallback--text;
+      color: var(--btnTopBarPressedText, $fallback--text);
+    }
+
+    &:disabled {
+      color: $fallback--text;
+      color: var(--btnTopBarDisabledText, $fallback--text);
+    }
+  }
+
+
   .logo {
     display: flex;
     position: absolute;
@@ -525,6 +548,25 @@ main-router {
     align-self: stretch;
   }
 
+  button {
+    &, i[class*=icon-] {
+      color: $fallback--text;
+      color: var(--btnPanelText, $fallback--text);
+    }
+
+    &:active {
+      background-color: $fallback--fg;
+      background-color: var(--btnPanelPressed, $fallback--fg);
+      color: $fallback--text;
+      color: var(--btnPanelPressedText, $fallback--text);
+    }
+
+    &:disabled {
+      color: $fallback--text;
+      color: var(--btnPanelDisabledText, $fallback--text);
+    }
+  }
+
   a {
     color: $fallback--link;
     color: var(--panelLink, $fallback--link)
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 613abd1f..3921c953 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -360,7 +360,21 @@
               :fallback="previewTheme.colors.btnPressedText"
               :label="$t('settings.text')"
             />
-            <ContrastRatio :contrast="previewContrast.btnText" />
+            <ContrastRatio :contrast="previewContrast.btnPressedText" />
+            <h4>{{ $t('settings.style.advanced_colors.disabled') }}</h4>
+            <ColorInput
+              v-model="btnDisabledColorLocal"
+              name="btnDisabledColor"
+              :fallback="previewTheme.colors.btnDisabled"
+              :label="$t('settings.background')"
+            />
+            <ColorInput
+              v-model="btnDisabledTextColorLocal"
+              name="btnDisabledTextColor"
+              :fallback="previewTheme.colors.btnDisabledText"
+              :label="$t('settings.text')"
+            />
+            <ContrastRatio :contrast="previewContrast.btnDisabledText" />
           </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.borders') }}</h4>
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index dd5f8fd0..c5dd8047 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -36,7 +36,8 @@ export const DEFAULT_OPACITY = {
   input: 0.5,
   faint: 0.5,
   underlay: 0.15,
-  poll: 1
+  poll: 1,
+  topBar: 1
 }
 
 export const SLOT_INHERITANCE = {
@@ -222,7 +223,8 @@ export const SLOT_INHERITANCE = {
   btn: '--fg',
   btnText: {
     depends: ['fgText'],
-    layer: 'btn'
+    layer: 'btn',
+    textColor: true
   },
   btnPanelText: {
     depends: ['panelText'],
@@ -257,6 +259,32 @@ export const SLOT_INHERITANCE = {
     textColor: true
   },
 
+  btnDisabled: {
+    depends: ['btn', 'bg'],
+    color: (mod, btn, bg) => alphaBlend(btn, 0.5, bg)
+  },
+  btnDisabledText: {
+    depends: ['btnText'],
+    layer: 'btn',
+    variant: 'btnDisabled',
+    textColor: true,
+    color: (mod, text) => brightness(mod * -60, text).rgb
+  },
+  btnDisabledPanelText: {
+    depends: ['btnPanelText'],
+    layer: 'btnPanel',
+    variant: 'btnDisabled',
+    textColor: true,
+    color: (mod, text) => brightness(mod * -60, text).rgb
+  },
+  btnDisabledTopBarText: {
+    depends: ['btnTopBarText'],
+    layer: 'btnTopBar',
+    variant: 'btnDisabled',
+    textColor: true,
+    color: (mod, text) => brightness(mod * -60, text).rgb
+  },
+
   // Input fields
   input: '--fg',
   inputText: {
@@ -329,7 +357,10 @@ export const getLayers = (layer, variant = layer, colors, opacity) => {
     currentLayer === layer
       ? colors[variant]
       : colors[currentLayer],
-    opacity[currentLayer]
+    // TODO: Remove this hack when opacities/layers system is improved
+    currentLayer.startsWith('btn')
+      ? opacity.btn
+      : opacity[currentLayer]
   ]))
 }
 
@@ -443,11 +474,18 @@ export const getColors = (sourceColors, sourceOpacity, mod) => SLOT_ORDERED.redu
           [key]: contrastRatio(bg).rgb
         }
       } else {
+        let color = { ...acc[deps[0]] }
+        if (value.color) {
+          const isLightOnDark = convert(bg).hsl.l < convert(color).hsl.l
+          const mod = isLightOnDark ? 1 : -1
+          color = value.color(mod, ...deps.map((dep) => ({ ...acc[dep] })))
+        }
+
         return {
           ...acc,
           [key]: getTextColor(
             bg,
-            { ...acc[deps[0]] },
+            { ...color },
             value.textColor === 'preserve'
           )
         }
-- 
cgit v1.2.3-70-g09d2


From 9f7af191e8a77a0c5620c8698cc7b26dde02868b Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 13 Jan 2020 22:19:19 +0200
Subject: tabs & toggled (ex pressed) buttons

---
 src/App.scss                                       | 22 +++++++++---
 src/components/follow_button/follow_button.vue     |  2 +-
 .../moderation_tools/moderation_tools.vue          |  2 +-
 src/components/style_switcher/style_switcher.vue   | 23 +++++++++++++
 src/components/tab_switcher/tab_switcher.scss      |  7 ++++
 src/components/user_card/user_card.vue             | 10 ++----
 src/services/theme_data/theme_data.service.js      | 39 ++++++++++++++++++++++
 7 files changed, 90 insertions(+), 15 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/App.scss b/src/App.scss
index 7f404bc6..70983fe2 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -113,11 +113,11 @@ button {
     background-color: var(--btnDisabled, $fallback--fg)
   }
 
-  &.pressed {
-    color: $fallback--faint;
-    color: var(--faint, $fallback--faint);
-    background-color: $fallback--bg;
-    background-color: var(--bg, $fallback--bg)
+  &.toggled {
+    color: $fallback--text;
+    color: var(--btnToggledText, $fallback--text);
+    background-color: $fallback--fg;
+    background-color: var(--btnToggled, $fallback--fg)
   }
 
   &.danger {
@@ -385,6 +385,13 @@ i[class*=icon-] {
       color: $fallback--text;
       color: var(--btnTopBarDisabledText, $fallback--text);
     }
+
+    &.toggled {
+      color: $fallback--text;
+      color: var(--btnTopBarToggledText, $fallback--text);
+      background-color: $fallback--fg;
+      background-color: var(--btnTopBarToggled, $fallback--fg)
+    }
   }
 
 
@@ -565,6 +572,11 @@ main-router {
       color: $fallback--text;
       color: var(--btnPanelDisabledText, $fallback--text);
     }
+
+    &.toggled {
+      color: $fallback--text;
+      color: var(--btnPanelToggledText, $fallback--text);
+    }
   }
 
   a {
diff --git a/src/components/follow_button/follow_button.vue b/src/components/follow_button/follow_button.vue
index f0cbb94b..bfdc137b 100644
--- a/src/components/follow_button/follow_button.vue
+++ b/src/components/follow_button/follow_button.vue
@@ -1,7 +1,7 @@
 <template>
   <button
     class="btn btn-default follow-button"
-    :class="{ pressed: isPressed }"
+    :class="{ toggled: isPressed }"
     :disabled="inProgress"
     :title="title"
     @click="onClick"
diff --git a/src/components/moderation_tools/moderation_tools.vue b/src/components/moderation_tools/moderation_tools.vue
index 006d6373..e78e05f1 100644
--- a/src/components/moderation_tools/moderation_tools.vue
+++ b/src/components/moderation_tools/moderation_tools.vue
@@ -123,7 +123,7 @@
       </div>
       <button
         class="btn btn-default btn-block"
-        :class="{ pressed: showDropDown }"
+        :class="{ toggled: showDropDown }"
       >
         {{ $t('user_card.admin_menu.moderation') }}
       </button>
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 3921c953..2fca5570 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -376,6 +376,29 @@
             />
             <ContrastRatio :contrast="previewContrast.btnDisabledText" />
           </div>
+          <div class="color-item">
+            <h4>{{ $t('settings.style.advanced_colors.tabs') }}</h4>
+            <ColorInput
+              v-model="tabColorLocal"
+              name="tabColor"
+              :fallback="previewTheme.colors.tab"
+              :label="$t('settings.background')"
+            />
+            <ColorInput
+              v-model="tabTextColorLocal"
+              name="tabTextColor"
+              :fallback="previewTheme.colors.tabText"
+              :label="$t('settings.text')"
+            />
+            <ContrastRatio :contrast="previewContrast.tabText" />
+            <ColorInput
+              v-model="tabActiveTextColorLocal"
+              name="tabActiveTextColor"
+              :fallback="previewTheme.colors.tabActiveText"
+              :label="$t('settings.text')"
+            />
+            <ContrastRatio :contrast="previewContrast.tabActiveText" />
+          </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.borders') }}</h4>
             <ColorInput
diff --git a/src/components/tab_switcher/tab_switcher.scss b/src/components/tab_switcher/tab_switcher.scss
index 3e5eacd5..df585faa 100644
--- a/src/components/tab_switcher/tab_switcher.scss
+++ b/src/components/tab_switcher/tab_switcher.scss
@@ -52,6 +52,11 @@
         margin-bottom: 6px - 99px;
         white-space: nowrap;
 
+        color: $fallback--text;
+        color: var(--tabText, $fallback--text);
+        background-color: $fallback--fg;
+        background-color: var(--tab, $fallback--fg);
+
         &:not(.active) {
           z-index: 4;
 
@@ -63,6 +68,8 @@
         &.active {
           background: transparent;
           z-index: 5;
+          color: $fallback--text;
+          color: var(--tabActiveText, $fallback--text);
         }
 
         img {
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 93d55fff..e286ceea 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -151,7 +151,7 @@
               </ProgressButton>
               <ProgressButton
                 v-else
-                class="btn btn-default pressed"
+                class="btn btn-default toggled"
                 :click="unsubscribeUser"
                 :title="$t('user_card.unsubscribe')"
               >
@@ -162,7 +162,7 @@
           <div>
             <button
               v-if="user.muted"
-              class="btn btn-default btn-block pressed"
+              class="btn btn-default btn-block toggled"
               @click="unmuteUser"
             >
               {{ $t('user_card.muted') }}
@@ -538,12 +538,6 @@
 
     button {
       margin: 0;
-
-      &.pressed {
-        // TODO: This should be themed.
-        border-bottom-color: rgba(255, 255, 255, 0.2);
-        border-top-color: rgba(0, 0, 0, 0.2);
-      }
     }
   }
 }
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index c5dd8047..a345d996 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -219,6 +219,19 @@ export const SLOT_INHERITANCE = {
     textColor: 'preserve'
   },
 
+  // Tabs
+  tab: '--btn',
+  tabText: {
+    depends: ['btnText'],
+    layer: 'btn',
+    textColor: true
+  },
+  tabActiveText: {
+    depends: ['text'],
+    layer: 'bg',
+    textColor: true
+  },
+
   // Buttons
   btn: '--fg',
   btnText: {
@@ -239,6 +252,7 @@ export const SLOT_INHERITANCE = {
     textColor: true
   },
 
+  // Buttons: pressed
   btnPressed: '--btn',
   btnPressedText: {
     depends: ['btnText'],
@@ -259,6 +273,31 @@ export const SLOT_INHERITANCE = {
     textColor: true
   },
 
+  // Buttons: toggled
+  btnToggled: {
+    depends: ['btn'],
+    color: (mod, btn) => brightness(mod * 20, btn).rgb
+  },
+  btnToggledText: {
+    depends: ['btnText'],
+    layer: 'btn',
+    variant: 'btnToggled',
+    textColor: true
+  },
+  btnToggledPanelText: {
+    depends: ['btnPanelText'],
+    layer: 'btnPanel',
+    variant: 'btnToggled',
+    textColor: true
+  },
+  btnToggledTopBarText: {
+    depends: ['btnTopBarText'],
+    layer: 'btnTopBar',
+    variant: 'btnToggled',
+    textColor: true
+  },
+
+  // Buttons: disabled
   btnDisabled: {
     depends: ['btn', 'bg'],
     color: (mod, btn, bg) => alphaBlend(btn, 0.5, bg)
-- 
cgit v1.2.3-70-g09d2


From 24a7a9bfd8dbdaae8b5a2e5dde5cb754a122905b Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Thu, 16 Jan 2020 23:30:13 +0200
Subject: lint

---
 src/components/style_switcher/style_switcher.vue | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 2fca5570..e3b899f0 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -215,7 +215,10 @@
               :label="$t('settings.text')"
               :fallback="previewTheme.colors.alertErrorText"
             />
-            <ContrastRatio :contrast="previewContrast.alertErrorText" large="1"/>
+            <ContrastRatio
+              :contrast="previewContrast.alertErrorText"
+              large="1"
+            />
             <ColorInput
               v-model="alertWarningColorLocal"
               name="alertWarning"
@@ -228,7 +231,10 @@
               :label="$t('settings.text')"
               :fallback="previewTheme.colors.alertWarningText"
             />
-            <ContrastRatio :contrast="previewContrast.alertWarningText" large="1"/>
+            <ContrastRatio
+              :contrast="previewContrast.alertWarningText"
+              large="1"
+            />
           </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.badge') }}</h4>
@@ -244,7 +250,10 @@
               :label="$t('settings.text')"
               :fallback="previewTheme.colors.badgeNotificationText"
             />
-            <ContrastRatio :contrast="previewContrast.badgeNotificationText" large="1" />
+            <ContrastRatio
+              :contrast="previewContrast.badgeNotificationText"
+              large="1"
+            />
           </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.panel_header') }}</h4>
-- 
cgit v1.2.3-70-g09d2


From 7d7ccf729855283ad0f5b9d6943b8d86ed1f180d Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 19 Jan 2020 22:44:35 +0200
Subject: fix some contrast ratios not displaying

---
 src/components/contrast_ratio/contrast_ratio.vue | 12 +++++++++---
 src/components/style_switcher/style_switcher.vue | 18 +++++++++---------
 2 files changed, 18 insertions(+), 12 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/contrast_ratio/contrast_ratio.vue b/src/components/contrast_ratio/contrast_ratio.vue
index 15a450a2..5e79ef41 100644
--- a/src/components/contrast_ratio/contrast_ratio.vue
+++ b/src/components/contrast_ratio/contrast_ratio.vue
@@ -37,9 +37,15 @@
 
 <script>
 export default {
-  props: [
-    'large', 'contrast'
-  ],
+  props: {
+    large: {
+      required: false
+    },
+    contrast: {
+      required: true,
+      type: Object
+    }
+  },
   computed: {
     hint () {
       const levelVal = this.contrast.aaa ? 'aaa' : (this.contrast.aa ? 'aa' : 'bad')
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index e3b899f0..c8c02b8d 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -157,13 +157,13 @@
               name="cRedColor"
               :label="$t('settings.cRed')"
             />
-            <ContrastRatio :contrast="previewContrast.bgRed" />
+            <ContrastRatio :contrast="previewContrast.bgCRed" />
             <ColorInput
               v-model="cBlueColorLocal"
               name="cBlueColor"
               :label="$t('settings.cBlue')"
             />
-            <ContrastRatio :contrast="previewContrast.bgBlue" />
+            <ContrastRatio :contrast="previewContrast.bgCBlue" />
           </div>
           <div class="color-item">
             <ColorInput
@@ -171,13 +171,13 @@
               name="cGreenColor"
               :label="$t('settings.cGreen')"
             />
-            <ContrastRatio :contrast="previewContrast.bgGreen" />
+            <ContrastRatio :contrast="previewContrast.bgCGreen" />
             <ColorInput
               v-model="cOrangeColorLocal"
               name="cOrangeColor"
               :label="$t('settings.cOrange')"
             />
-            <ContrastRatio :contrast="previewContrast.bgOrange" />
+            <ContrastRatio :contrast="previewContrast.bgCOrange" />
           </div>
           <p>{{ $t('settings.theme_help_v2_2') }}</p>
         </div>
@@ -217,7 +217,7 @@
             />
             <ContrastRatio
               :contrast="previewContrast.alertErrorText"
-              large="1"
+              large="true"
             />
             <ColorInput
               v-model="alertWarningColorLocal"
@@ -233,7 +233,7 @@
             />
             <ContrastRatio
               :contrast="previewContrast.alertWarningText"
-              large="1"
+              large="true"
             />
           </div>
           <div class="color-item">
@@ -252,7 +252,7 @@
             />
             <ContrastRatio
               :contrast="previewContrast.badgeNotificationText"
-              large="1"
+              large="true"
             />
           </div>
           <div class="color-item">
@@ -277,7 +277,7 @@
             />
             <ContrastRatio
               :contrast="previewContrast.panelText"
-              large="1"
+              large="true"
             />
             <ColorInput
               v-model="panelLinkColorLocal"
@@ -287,7 +287,7 @@
             />
             <ContrastRatio
               :contrast="previewContrast.panelLink"
-              large="1"
+              large="true"
             />
           </div>
           <div class="color-item">
-- 
cgit v1.2.3-70-g09d2


From e4033c85e2066d8a575a1cd8e5a59bb685a3adf0 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 20 Jan 2020 00:34:49 +0200
Subject: removed console logs

---
 src/components/shadow_control/shadow_control.js  |  15 ++
 src/components/shadow_control/shadow_control.vue |   2 +
 src/components/style_switcher/style_switcher.js  |  49 ++++---
 src/components/style_switcher/style_switcher.vue |   2 +-
 src/services/style_setter/style_setter.js        | 178 +++++++++++++----------
 src/services/theme_data/theme_data.service.js    |  28 +++-
 6 files changed, 166 insertions(+), 108 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js
index 44e4a22f..653d5a9b 100644
--- a/src/components/shadow_control/shadow_control.js
+++ b/src/components/shadow_control/shadow_control.js
@@ -61,6 +61,21 @@ export default {
         }
       }
     },
+    currentFallback () {
+      if (this.ready && this.fallback.length > 0) {
+        return this.fallback[this.selectedId]
+      } else {
+        return {
+          x: 0,
+          y: 0,
+          blur: 0,
+          spread: 0,
+          inset: false,
+          color: '#000000',
+          alpha: 1
+        }
+      }
+    },
     moveUpValid () {
       return this.ready && this.selectedId > 0
     },
diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index de8a42d1..efbb980e 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -191,6 +191,8 @@
         v-model="selected.color"
         :disabled="!present"
         :label="$t('settings.style.common.color')"
+        :fallback="currentFallback.color"
+        :showOptionalTickbox="false"
         name="shadow"
       />
       <OpacityInput
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 52ece3a1..2984873f 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -5,6 +5,7 @@ import {
   getContrastRatioLayers
 } from '../../services/color_convert/color_convert.js'
 import {
+  DEFAULT_SHADOWS,
   generateColors,
   generateShadows,
   generateRadii,
@@ -76,7 +77,7 @@ export default {
         .reduce((acc, [key, val]) => ({ ...acc, [ key + 'ColorLocal' ]: val }), {}),
 
       ...Object.keys(OPACITIES)
-        .map(key => console.log(key) || [key, ''])
+        .map(key => [key, ''])
         .reduce((acc, [key, val]) => ({ ...acc, [ key + 'OpacityLocal' ]: val }), {}),
 
       shadowSelected: undefined,
@@ -134,7 +135,7 @@ export default {
     },
     currentOpacity () {
       return Object.keys(OPACITIES)
-        .map(key => console.log(key) || [key, this[key + 'OpacityLocal']])
+        .map(key => [key, this[key + 'OpacityLocal']])
         .reduce((acc, [key, val]) => ({ ...acc, [ key ]: val }), {})
     },
     currentRadii () {
@@ -224,7 +225,7 @@ export default {
       ].join(';')
     },
     shadowsAvailable () {
-      return Object.keys(this.previewTheme.shadows).sort()
+      return Object.keys(DEFAULT_SHADOWS).sort()
     },
     currentShadowOverriden: {
       get () {
@@ -239,7 +240,7 @@ export default {
       }
     },
     currentShadowFallback () {
-      return this.previewTheme.shadows[this.shadowSelected]
+      return (this.previewTheme.shadows || {})[this.shadowSelected]
     },
     currentShadow: {
       get () {
@@ -314,6 +315,17 @@ export default {
         }
       })
     },
+    updatePreviewColorsAndShadows () {
+      this.previewColors = generateColors({
+        opacity: this.currentOpacity,
+        colors: this.currentColors
+      })
+      this.previewShadows = generateShadows(
+        { shadows: this.shadowsLocal },
+        this.previewColors.theme.colors,
+        this.previewColors.mod
+      )
+    },
     onImport (parsed) {
       if (parsed._pleroma_theme_version === 1) {
         this.normalizeLocalState(parsed, 1)
@@ -435,6 +447,14 @@ export default {
         })
       }
 
+      if (opacity && !this.keepOpacity) {
+        this.clearOpacity()
+        Object.entries(opacity).forEach(([k, v]) => {
+          if (typeof v === 'undefined' || v === null || Number.isNaN(v)) return
+          this[k + 'OpacityLocal'] = v
+        })
+      }
+
       if (!this.keepRoundness) {
         this.clearRoundness()
         Object.entries(radii).forEach(([k, v]) => {
@@ -454,14 +474,6 @@ export default {
         this.clearFonts()
         this.fontsLocal = fonts
       }
-
-      if (opacity && !this.keepOpacity) {
-        this.clearOpacity()
-        Object.entries(opacity).forEach(([k, v]) => {
-          if (typeof v === 'undefined' || v === null || Number.isNaN(v)) return
-          this[k + 'OpacityLocal'] = v
-        })
-      }
     }
   },
   watch: {
@@ -476,8 +488,9 @@ export default {
     },
     shadowsLocal: {
       handler () {
+        if (Object.getOwnPropertyNames(this.previewColors).length === 1) return
         try {
-          this.previewShadows = generateShadows({ shadows: this.shadowsLocal })
+          this.updatePreviewColorsAndShadows()
           this.shadowsInvalid = false
         } catch (e) {
           this.shadowsInvalid = true
@@ -500,10 +513,7 @@ export default {
     },
     currentColors () {
       try {
-        this.previewColors = generateColors({
-          opacity: this.currentOpacity,
-          colors: this.currentColors
-        })
+        this.updatePreviewColorsAndShadows()
         this.colorsInvalid = false
       } catch (e) {
         this.colorsInvalid = true
@@ -512,10 +522,7 @@ export default {
     },
     currentOpacity () {
       try {
-        this.previewColors = generateColors({
-          opacity: this.currentOpacity,
-          colors: this.currentColors
-        })
+        this.updatePreviewColorsAndShadows()
       } catch (e) {
         console.warn(e)
       }
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index c8c02b8d..287d31b7 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -691,7 +691,7 @@
               {{ $t('settings.style.switcher.clear_all') }}
             </button>
           </div>
-          <shadow-control
+          <ShadowControl
             v-model="currentShadow"
             :ready="!!currentShadowFallback"
             :fallback="currentShadowFallback"
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 872dd393..74af190c 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -1,7 +1,7 @@
 import { times } from 'lodash'
 import { convert } from 'chromatism'
 import { rgb2hex, hex2rgb, rgba2css, getCssColor } from '../color_convert/color_convert.js'
-import { getColors } from '../theme_data/theme_data.service.js'
+import { getColors, computeDynamicColor } from '../theme_data/theme_data.service.js'
 
 // While this is not used anymore right now, I left it in if we want to do custom
 // styles that aren't just colors, so user can pick from a few different distinct
@@ -139,7 +139,8 @@ export const generateColors = (themeData) => {
     theme: {
       colors: htmlColors.solid,
       opacity
-    }
+    },
+    mod
   }
 }
 
@@ -211,83 +212,99 @@ export const generateFonts = (input) => {
   }
 }
 
-export const generateShadows = (input) => {
-  const border = (top, shadow) => ({
-    x: 0,
-    y: top ? 1 : -1,
-    blur: 0,
+const border = (top, shadow) => ({
+  x: 0,
+  y: top ? 1 : -1,
+  blur: 0,
+  spread: 0,
+  color: shadow ? '#000000' : '#FFFFFF',
+  alpha: 0.2,
+  inset: true
+})
+const buttonInsetFakeBorders = [border(true, false), border(false, true)]
+const inputInsetFakeBorders = [border(true, true), border(false, false)]
+const hoverGlow = {
+  x: 0,
+  y: 0,
+  blur: 4,
+  spread: 0,
+  color: '--faint',
+  alpha: 1
+}
+
+export const DEFAULT_SHADOWS = {
+  panel: [{
+    x: 1,
+    y: 1,
+    blur: 4,
     spread: 0,
-    color: shadow ? '#000000' : '#FFFFFF',
-    alpha: 0.2,
-    inset: true
-  })
-  const buttonInsetFakeBorders = [border(true, false), border(false, true)]
-  const inputInsetFakeBorders = [border(true, true), border(false, false)]
-  const hoverGlow = {
+    color: '#000000',
+    alpha: 0.6
+  }],
+  topBar: [{
     x: 0,
     y: 0,
     blur: 4,
     spread: 0,
-    color: '--faint',
+    color: '#000000',
+    alpha: 0.6
+  }],
+  popup: [{
+    x: 2,
+    y: 2,
+    blur: 3,
+    spread: 0,
+    color: '#000000',
+    alpha: 0.5
+  }],
+  avatar: [{
+    x: 0,
+    y: 1,
+    blur: 8,
+    spread: 0,
+    color: '#000000',
+    alpha: 0.7
+  }],
+  avatarStatus: [],
+  panelHeader: [],
+  button: [{
+    x: 0,
+    y: 0,
+    blur: 2,
+    spread: 0,
+    color: '#000000',
     alpha: 1
-  }
-
-  const shadows = {
-    panel: [{
-      x: 1,
-      y: 1,
-      blur: 4,
-      spread: 0,
-      color: '#000000',
-      alpha: 0.6
-    }],
-    topBar: [{
-      x: 0,
-      y: 0,
-      blur: 4,
-      spread: 0,
-      color: '#000000',
-      alpha: 0.6
-    }],
-    popup: [{
-      x: 2,
-      y: 2,
-      blur: 3,
-      spread: 0,
-      color: '#000000',
-      alpha: 0.5
-    }],
-    avatar: [{
-      x: 0,
-      y: 1,
-      blur: 8,
-      spread: 0,
-      color: '#000000',
-      alpha: 0.7
-    }],
-    avatarStatus: [],
-    panelHeader: [],
-    button: [{
-      x: 0,
-      y: 0,
-      blur: 2,
-      spread: 0,
-      color: '#000000',
-      alpha: 1
-    }, ...buttonInsetFakeBorders],
-    buttonHover: [hoverGlow, ...buttonInsetFakeBorders],
-    buttonPressed: [hoverGlow, ...inputInsetFakeBorders],
-    input: [...inputInsetFakeBorders, {
-      x: 0,
-      y: 0,
-      blur: 2,
-      inset: true,
-      spread: 0,
-      color: '#000000',
-      alpha: 1
-    }],
+  }, ...buttonInsetFakeBorders],
+  buttonHover: [hoverGlow, ...buttonInsetFakeBorders],
+  buttonPressed: [hoverGlow, ...inputInsetFakeBorders],
+  input: [...inputInsetFakeBorders, {
+    x: 0,
+    y: 0,
+    blur: 2,
+    inset: true,
+    spread: 0,
+    color: '#000000',
+    alpha: 1
+  }]
+}
+export const generateShadows = (input, colors, mod) => {
+  const shadows = Object.entries({
+    ...DEFAULT_SHADOWS,
     ...(input.shadows || {})
-  }
+  }).reduce((shadowsAcc, [slotName, shadowdefs]) => {
+    const newShadow = shadowdefs.reduce((shadowAcc, def) => [
+      ...shadowAcc,
+      {
+        ...def,
+        color: rgb2hex(computeDynamicColor(
+          def.color,
+          (variableSlot) => convert(colors[variableSlot]).rgb,
+          mod
+        ))
+      }
+    ], [])
+    return { ...shadowsAcc, [slotName]: newShadow }
+  }, {})
 
   return {
     rules: {
@@ -325,12 +342,15 @@ export const composePreset = (colors, radii, shadows, fonts) => {
   }
 }
 
-export const generatePreset = (input) => composePreset(
-  generateColors(input),
-  generateRadii(input),
-  generateShadows(input),
-  generateFonts(input)
-)
+export const generatePreset = (input) => {
+  const colors = generateColors(input)
+  return composePreset(
+    colors,
+    generateRadii(input),
+    generateShadows(input, colors.theme.colors, colors.mod),
+    generateFonts(input)
+  )
+}
 
 export const getThemes = () => {
   return window.fetch('/static/styles.json')
@@ -362,7 +382,7 @@ export const getThemes = () => {
 
 export const setPreset = (val, commit) => {
   return getThemes()
-    .then((themes) => console.log(themes) || themes[val] ? themes[val] : themes['pleroma-dark'])
+    .then((themes) => themes[val] ? themes[val] : themes['pleroma-dark'])
     .then((theme) => {
       const isV1 = Array.isArray(theme)
       const data = isV1 ? {} : theme.theme
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index 9f010fdf..e4456b29 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -697,6 +697,22 @@ export const OPACITIES = Object.entries(SLOT_INHERITANCE).reduce((acc, [k, v]) =
   }
 }, {})
 
+/**
+ * Handle dynamic color
+ */
+export const computeDynamicColor = (sourceColor, getColor, mod) => {
+  if (typeof sourceColor !== 'string' || !sourceColor.startsWith('--')) return sourceColor
+  let targetColor = null
+  // Color references other color
+  const [variable, modifier] = sourceColor.split(/,/g).map(str => str.trim())
+  const variableSlot = variable.substring(2)
+  targetColor = getColor(variableSlot)
+  if (modifier) {
+    targetColor = brightness(Number.parseFloat(modifier) * mod, targetColor).rgb
+  }
+  return targetColor
+}
+
 /**
  * THE function you want to use. Takes provided colors and opacities, mod
  * value and uses inheritance data to figure out color needed for the slot.
@@ -728,13 +744,11 @@ export const getColors = (sourceColors, sourceOpacity, mod) => SLOT_ORDERED.redu
         a: 0
       }
     } else if (typeof sourceColor === 'string' && sourceColor.startsWith('--')) {
-      // Color references other color
-      const [variable, modifier] = sourceColor.split(/,/g).map(str => str.trim())
-      const variableSlot = variable.substring(2)
-      targetColor = colors[variableSlot] || sourceColors[variableSlot]
-      if (modifier) {
-        targetColor = brightness(Number.parseFloat(modifier) * mod, targetColor).rgb
-      }
+      targetColor = computeDynamicColor(
+        sourceColor,
+        variableSlot => colors[variableSlot] || sourceColors[variableSlot],
+        mod
+      )
     } else if (typeof sourceColor === 'string' && sourceColor.startsWith('#')) {
       targetColor = convert(targetColor).rgb
     }
-- 
cgit v1.2.3-70-g09d2


From 9336140486f50159b935001b7ebadf3d9bda89ec Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Wed, 22 Jan 2020 00:37:19 +0200
Subject: massively improved initial theme loading code, added checks and
 warnings when loading theme files (import/localStorage/defaults)

---
 src/boot/after_store.js                           |  32 +++--
 src/components/style_switcher/style_switcher.js   | 153 ++++++++++++++++++++--
 src/components/style_switcher/style_switcher.scss |   4 +
 src/components/style_switcher/style_switcher.vue  |  79 +++++++----
 src/i18n/en.json                                  |  12 +-
 src/modules/config.js                             |   7 +-
 src/modules/instance.js                           |  17 ++-
 src/services/style_setter/style_setter.js         |  27 ++--
 8 files changed, 259 insertions(+), 72 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/boot/after_store.js b/src/boot/after_store.js
index 228a0497..6c4f0e1b 100644
--- a/src/boot/after_store.js
+++ b/src/boot/after_store.js
@@ -5,6 +5,8 @@ import App from '../App.vue'
 import { windowWidth } from '../services/window_utils/window_utils'
 import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
 import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
+import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
+import { applyTheme } from '../services/style_setter/style_setter.js'
 
 const getStatusnetConfig = async ({ store }) => {
   try {
@@ -261,7 +263,7 @@ const checkOAuthToken = async ({ store }) => {
       try {
         await store.dispatch('loginUser', store.getters.getUserToken())
       } catch (e) {
-        console.log(e)
+        console.error(e)
       }
     }
     resolve()
@@ -269,23 +271,29 @@ const checkOAuthToken = async ({ store }) => {
 }
 
 const afterStoreSetup = async ({ store, i18n }) => {
-  if (store.state.config.customTheme) {
-    // This is a hack to deal with async loading of config.json and themes
-    // See: style_setter.js, setPreset()
-    window.themeLoaded = true
-    store.dispatch('setOption', {
-      name: 'customTheme',
-      value: store.state.config.customTheme
-    })
-  }
-
   const width = windowWidth()
   store.dispatch('setMobileLayout', width <= 800)
+  await setConfig({ store })
+
+  const { customTheme, customThemeSource } = store.state.config
+  const { theme } = store.state.instance
+  const customThemePresent = customThemeSource || customTheme
+
+  if (customThemePresent) {
+    if (customThemeSource && customThemeSource.version === CURRENT_VERSION) {
+      applyTheme(customThemeSource)
+    } else {
+      applyTheme(customTheme)
+    }
+  } else if (theme) {
+    // do nothing, it will load asynchronously
+  } else {
+    console.error('Failed to load any theme!')
+  }
 
   // Now we can try getting the server settings and logging in
   await Promise.all([
     checkOAuthToken({ store }),
-    setConfig({ store }),
     getTOS({ store }),
     getInstancePanel({ store }),
     getStickers({ store }),
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 799646b1..0ef02f39 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -57,6 +57,8 @@ export default {
     return {
       availableStyles: [],
       selected: this.$store.getters.mergedConfig.theme,
+      themeWarning: undefined,
+      tempImportFile: undefined,
 
       previewShadows: {},
       previewColors: {},
@@ -120,12 +122,62 @@ export default {
       })
   },
   mounted () {
-    this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme)
+    this.loadThemeFromLocalStorage()
     if (typeof this.shadowSelected === 'undefined') {
       this.shadowSelected = this.shadowsAvailable[0]
     }
   },
   computed: {
+    themeWarningHelp () {
+      if (!this.themeWarning) return
+      const t = this.$t
+      const pre = 'settings.style.switcher.help.'
+      const {
+        origin,
+        themeEngineVersion,
+        type,
+        noActionsPossible
+      } = this.themeWarning
+      if (origin === 'file') {
+        // Loaded v2 theme from file
+        if (themeEngineVersion === 2 && type === 'wrong_version') {
+          return t(pre + 'v2_imported')
+        }
+        if (themeEngineVersion > CURRENT_VERSION) {
+          return t(pre + 'future_version_imported') + ' ' +
+            (
+              noActionsPossible
+                ? t(pre + 'snapshot_missing')
+                : t(pre + 'snapshot_present')
+            )
+        }
+        if (themeEngineVersion < CURRENT_VERSION) {
+          return t(pre + 'future_version_imported') + ' ' +
+            (
+              noActionsPossible
+                ? t(pre + 'snapshot_missing')
+                : t(pre + 'snapshot_present')
+            )
+        }
+      } else if (origin === 'localStorage') {
+        // FE upgraded from v2
+        if (themeEngineVersion === 2) {
+          return 'upgraded_from_v2'
+        }
+        // Admin downgraded FE
+        if (themeEngineVersion > CURRENT_VERSION) {
+          return noActionsPossible
+            ? 'downgraded_theme'
+            : 'downgraded_theme_missing_snapshot'
+        }
+        // Admin upgraded FE
+        if (themeEngineVersion < CURRENT_VERSION) {
+          return noActionsPossible
+            ? 'upgraded_theme'
+            : 'upgraded_theme_missing_snapshot'
+        }
+      }
+    },
     selectedVersion () {
       return Array.isArray(this.selected) ? 1 : 2
     },
@@ -308,10 +360,96 @@ export default {
     Checkbox
   },
   methods: {
+    loadTheme (
+      {
+        theme,
+        source,
+        _pleroma_theme_version: fileVersion
+      },
+      origin,
+      forceUseSource = false
+    ) {
+      if (!source && !theme) {
+        throw new Error('Can\'t load theme: empty')
+      }
+      const version = (origin === 'localstorage' && !theme.colors)
+        ? 'l1'
+        : fileVersion
+      const themeEngineVersion = (source || {}).themeEngineVersion || 2
+      const versionsMatch = themeEngineVersion === CURRENT_VERSION
+      // Force loading of source if user requested it or if snapshot
+      // is unavailable
+      const forcedSourceLoad = (source && forceUseSource) || !theme
+      if (!versionsMatch &&
+          !forcedSourceLoad &&
+          version !== 'l1' &&
+          origin !== 'defaults'
+      ) {
+        if (!theme) {
+          this.themeWarning = {
+            origin,
+            noActionsPossible: true,
+            themeEngineVersion,
+            type: 'no_snapshot_old_version'
+          }
+        } else if (!versionsMatch) {
+          this.themeWarning = {
+            origin,
+            noActionsPossible: !source,
+            themeEngineVersion,
+            type: 'wrong_version'
+          }
+        }
+      }
+      this.normalizeLocalState(theme, version, source, forcedSourceLoad)
+    },
+    forceLoadLocalStorage () {
+      this.loadThemeFromLocalStorage(true)
+    },
+    dismissWarning () {
+      this.themeWarning = undefined
+      this.tempImportFile = undefined
+    },
+    forceLoad () {
+      const { origin } = this.themeWarning
+      switch (origin) {
+        case 'localstorage':
+          this.loadThemeFromLocalStorage(true)
+          break
+        case 'file':
+          this.onImport(this.tempImportFile, true)
+          break
+      }
+    },
+    loadThemeFromLocalStorage (confirmLoadSource = false) {
+      const {
+        customTheme: theme,
+        customThemeSource: source
+      } = this.$store.getters.mergedConfig
+      if (!theme && !source) {
+        // Anon user or never touched themes
+        this.loadTheme(
+          this.$store.state.instance.themeData,
+          'defaults',
+          confirmLoadSource
+        )
+      } else {
+        this.loadTheme(
+          { theme, source },
+          'localStorage',
+          confirmLoadSource
+        )
+      }
+    },
     setCustomTheme () {
       this.$store.dispatch('setOption', {
         name: 'customTheme',
+        value: this.previewTheme
+      })
+      this.$store.dispatch('setOption', {
+        name: 'customThemeSource',
         value: {
+          themeEngineVersion: CURRENT_VERSION,
           shadows: this.shadowsLocal,
           fonts: this.fontsLocal,
           opacity: this.currentOpacity,
@@ -331,21 +469,16 @@ export default {
         this.previewColors.mod
       )
     },
-    onImport (parsed) {
-      if (parsed._pleroma_theme_version === 1) {
-        this.normalizeLocalState(parsed, 1)
-      } else if (parsed._pleroma_theme_version >= 2) {
-        this.normalizeLocalState(parsed.theme, 2, parsed.source)
-      }
+    onImport (parsed, forceSource = false) {
+      this.tempImportFile = parsed
+      this.loadTheme(parsed, 'file', forceSource)
     },
     importValidator (parsed) {
       const version = parsed._pleroma_theme_version
       return version >= 1 || version <= 2
     },
     clearAll () {
-      const state = this.$store.getters.mergedConfig.customTheme
-      const version = state.colors ? 2 : 'l1'
-      this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme, version, this.$store.getters.mergedConfig.customThemeSource)
+      this.loadThemeFromLocalStorage()
     },
 
     // Clears all the extra stuff when loading V1 theme
diff --git a/src/components/style_switcher/style_switcher.scss b/src/components/style_switcher/style_switcher.scss
index 987245a2..71d0f05e 100644
--- a/src/components/style_switcher/style_switcher.scss
+++ b/src/components/style_switcher/style_switcher.scss
@@ -1,5 +1,9 @@
 @import '../../_variables.scss';
 .style-switcher {
+  .theme-warning {
+    display: flex;
+    align-items: baseline;
+  }
   .preset-switcher {
     margin-right: 1em;
   }
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 287d31b7..61f8800a 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -1,31 +1,60 @@
 <template>
-  <div class="style-switcher">
-    <div class="presets-container">
-      <div class="save-load">
-        <ExportImport
-          :export-object="exportedTheme"
-          :export-label="$t(&quot;settings.export_theme&quot;)"
-          :import-label="$t(&quot;settings.import_theme&quot;)"
-          :import-failed-text="$t(&quot;settings.invalid_theme_imported&quot;)"
-          :on-import="onImport"
-          :validator="importValidator"
-        >
-          <template slot="before">
-            <div class="presets">
-              {{ $t('settings.presets') }}
-              <label
-                for="preset-switcher"
-                class="select"
+<div class="style-switcher">
+  <div class="presets-container">
+    <div class="save-load">
+      <div class="theme-warning" v-if="themeWarning">
+        <div class="alert warning">
+        {{ themeWarningHelp }}
+        </div>
+        <div class="buttons">
+          <template v-if="themeWarning.noActionsPossible">
+            <button
+              class="btn"
+              @click="dismissWarning"
+            >
+              {{ $t('general.dismiss') }}
+            </button>
+          </template>
+          <template v-else>
+            <button
+              class="btn"
+              @click="forceLoad"
+            >
+              {{ $t('settings.style.switcher.load_theme') }}
+            </button>
+            <button
+              class="btn"
+              @click="dismissWarning"
+            >
+              {{ $t('settings.style.switcher.use_snapshot') }}
+            </button>
+          </template>
+        </div>
+      </div>
+      <ExportImport
+        :export-object="exportedTheme"
+        :export-label="$t(&quot;settings.export_theme&quot;)"
+        :import-label="$t(&quot;settings.import_theme&quot;)"
+        :import-failed-text="$t(&quot;settings.invalid_theme_imported&quot;)"
+        :on-import="onImport"
+        :validator="importValidator"
+      >
+        <template slot="before">
+          <div class="presets">
+            {{ $t('settings.presets') }}
+            <label
+              for="preset-switcher"
+              class="select"
               >
-                <select
-                  id="preset-switcher"
-                  v-model="selected"
-                  class="preset-switcher"
+              <select
+                id="preset-switcher"
+                v-model="selected"
+                class="preset-switcher"
                 >
-                  <option
-                    v-for="style in availableStyles"
-                    :key="style.name"
-                    :value="style"
+                <option
+                  v-for="style in availableStyles"
+                  :key="style.name"
+                  :value="style"
                     :style="{
                       backgroundColor: style[1] || (style.theme || style.source).colors.bg,
                       color: style[3] || (style.theme || style.source).colors.text
diff --git a/src/i18n/en.json b/src/i18n/en.json
index f624a1c5..6994d62f 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -46,6 +46,7 @@
     "optional": "optional",
     "show_more": "Show more",
     "show_less": "Show less",
+    "dismiss": "Dismiss",
     "cancel": "Cancel",
     "disable": "Disable",
     "enable": "Enable",
@@ -394,7 +395,16 @@
         "save_load_hint": "\"Keep\" options preserve currently set options when selecting or loading themes, it also stores said options when exporting a theme. When all checkboxes unset, exporting theme will save everything.",
         "reset": "Reset",
         "clear_all": "Clear all",
-        "clear_opacity": "Clear opacity"
+        "clear_opacity": "Clear opacity",
+        "load_theme": "Load theme",
+        "use_snapshot": "Keep as is",
+        "help": {
+          "v2_imported": "File you imported was made for older FE. We try to maximize compatibility but there still could be inconsitencies.",
+          "snapshot_present": "Theme snapshot is loaded, so all values are overriden. You can load theme's actual data instead.",
+          "snapshot_missing": "No theme snapshot was in the file so it could look different than originally envisioned.",
+          "future_version_imported": "File you imported was made in newer version of FE.",
+          "older_version_imported": "File you imported was made in older version of FE."
+        }
       },
       "common": {
         "color": "Color",
diff --git a/src/modules/config.js b/src/modules/config.js
index 74025db1..ee474b16 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -5,6 +5,9 @@ const browserLocale = (window.navigator.language || 'en').split('-')[0]
 
 export const defaultState = {
   colors: {},
+  theme: undefined,
+  customTheme: undefined,
+  customThemeSource: undefined,
   hideISP: false,
   // bad name: actually hides posts of muted USERS
   hideMutedPosts: undefined, // instance default
@@ -93,10 +96,10 @@ const config = {
       commit('setOption', { name, value })
       switch (name) {
         case 'theme':
-          setPreset(value, commit)
+          setPreset(value)
           break
         case 'customTheme':
-          applyTheme(value, commit)
+          applyTheme(value)
       }
     }
   }
diff --git a/src/modules/instance.js b/src/modules/instance.js
index 625323b9..8781646d 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -1,5 +1,5 @@
 import { set } from 'vue'
-import { setPreset } from '../services/style_setter/style_setter.js'
+import { getPreset, applyTheme } from '../services/style_setter/style_setter.js'
 import { instanceDefaultProperties } from './config.js'
 
 const defaultState = {
@@ -10,6 +10,7 @@ const defaultState = {
   textlimit: 5000,
   server: 'http://localhost:4040/',
   theme: 'pleroma-dark',
+  themeData: undefined,
   background: '/static/aurora_borealis.jpg',
   logo: '/static/logo.png',
   logoMask: true,
@@ -96,6 +97,9 @@ const instance = {
             dispatch('initializeSocket')
           }
           break
+        case 'theme':
+          dispatch('setTheme', value)
+          break
       }
     },
     async getStaticEmoji ({ commit }) {
@@ -147,9 +151,16 @@ const instance = {
       }
     },
 
-    setTheme ({ commit }, themeName) {
+    setTheme ({ commit, rootState }, themeName) {
       commit('setInstanceOption', { name: 'theme', value: themeName })
-      return setPreset(themeName, commit)
+      getPreset(themeName)
+        .then(themeData => {
+          commit('setInstanceOption', { name: 'themeData', value: themeData })
+          // No need to apply theme if there's user theme already
+          const { customTheme } = rootState.config
+          if (customTheme) return
+          applyTheme(themeData.theme)
+        })
     },
     fetchEmoji ({ dispatch, state }) {
       if (!state.customEmojiFetched) {
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index ee264c49..9610d799 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -7,7 +7,7 @@ import { getColors, computeDynamicColor } from '../theme_data/theme_data.service
 // styles that aren't just colors, so user can pick from a few different distinct
 // styles as well as set their own colors in the future.
 
-export const setStyle = (href, commit) => {
+export const setStyle = (href) => {
   /***
       What's going on here?
       I want to make it easy for admins to style this application. To have
@@ -53,8 +53,8 @@ export const setStyle = (href, commit) => {
   cssEl.addEventListener('load', setDynamic)
 }
 
-export const applyTheme = (input, commit) => {
-  const { rules, theme } = generatePreset(input)
+export const applyTheme = (input) => {
+  const { rules } = generatePreset(input)
   const head = document.head
   const body = document.body
   body.classList.add('hidden')
@@ -69,11 +69,6 @@ export const applyTheme = (input, commit) => {
   styleSheet.insertRule(`body { ${rules.shadows} }`, 'index-max')
   styleSheet.insertRule(`body { ${rules.fonts} }`, 'index-max')
   body.classList.remove('hidden')
-
-  // commit('setOption', { name: 'colors', value: htmlColors })
-  // commit('setOption', { name: 'radii', value: radii })
-  commit('setOption', { name: 'customTheme', value: input })
-  commit('setOption', { name: 'colors', value: theme.colors })
 }
 
 export const getCssShadow = (input, usesDropShadow) => {
@@ -387,7 +382,7 @@ export const getThemes = () => {
  */
 export const shadows2to3 = (shadows) => {
   return Object.entries(shadows).reduce((shadowsAcc, [slotName, shadowDefs]) => {
-    const isDynamic = ({ color }) => console.log(color) || color.startsWith('--')
+    const isDynamic = ({ color }) => color.startsWith('--')
     const newShadow = shadowDefs.reduce((shadowAcc, def) => [
       ...shadowAcc,
       {
@@ -399,7 +394,7 @@ export const shadows2to3 = (shadows) => {
   }, {})
 }
 
-export const setPreset = (val, commit) => {
+export const getPreset = (val) => {
   return getThemes()
     .then((themes) => themes[val] ? themes[val] : themes['pleroma-dark'])
     .then((theme) => {
@@ -420,14 +415,8 @@ export const setPreset = (val, commit) => {
         data.colors = { bg, fg, text, link, cRed, cBlue, cGreen, cOrange }
       }
 
-      // This is a hack, this function is only called during initial load.
-      // We want to cancel loading the theme from config.json if we're already
-      // loading a theme from the persisted state.
-      // Needed some way of dealing with the async way of things.
-      // load config -> set preset -> wait for styles.json to load ->
-      // load persisted state -> set colors -> styles.json loaded -> set colors
-      if (!window.themeLoaded) {
-        applyTheme(data, commit)
-      }
+      return { theme: data, source: theme.source }
     })
 }
+
+export const setPreset = (val) => getPreset(val).then(data => applyTheme(data.theme))
-- 
cgit v1.2.3-70-g09d2


From 644ce497a0f118b2e5050a2e45b67450915c53f0 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Wed, 22 Jan 2020 01:28:46 +0200
Subject: lightBg -> highlight because it causes issues with v2

---
 src/components/style_switcher/style_switcher.vue | 24 +++++-----
 src/i18n/en.json                                 |  2 +-
 src/services/theme_data/theme_data.service.js    | 60 ++++++++++++------------
 static/themes/breezy-dark.json                   |  2 +-
 static/themes/breezy-light.json                  |  2 +-
 static/themes/redmond-xx-se.json                 |  2 +-
 static/themes/redmond-xx.json                    |  2 +-
 static/themes/redmond-xxi.json                   |  2 +-
 8 files changed, 48 insertions(+), 48 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 61f8800a..79c2fcd3 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -518,27 +518,27 @@
             />
           </div>
           <div class="color-item">
-            <h4>{{ $t('settings.style.advanced_colors.lightBg') }}</h4>
+            <h4>{{ $t('settings.style.advanced_colors.highlight') }}</h4>
             <ColorInput
-              v-model="lightBgColorLocal"
-              name="lightBg"
+              v-model="highlightColorLocal"
+              name="highlight"
               :label="$t('settings.background')"
-              :fallback="previewTheme.colors.lightBg"
+              :fallback="previewTheme.colors.highlight"
             />
             <ColorInput
-              v-model="lightBgTextColorLocal"
-              name="lightBgText"
+              v-model="highlightTextColorLocal"
+              name="highlightText"
               :label="$t('settings.text')"
-              :fallback="previewTheme.colors.lightBgText"
+              :fallback="previewTheme.colors.highlightText"
             />
-            <ContrastRatio :contrast="previewContrast.lightBgText" />
+            <ContrastRatio :contrast="previewContrast.highlightText" />
             <ColorInput
-              v-model="lightBgLinkColorLocal"
-              name="lightBgLink"
+              v-model="highlightLinkColorLocal"
+              name="highlightLink"
               :label="$t('settings.links')"
-              :fallback="previewTheme.colors.lightBgLink"
+              :fallback="previewTheme.colors.highlightLink"
             />
-            <ContrastRatio :contrast="previewContrast.lightBgLink" />
+            <ContrastRatio :contrast="previewContrast.highlightLink" />
           </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.selectedPost') }}</h4>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 815c11b1..2622157a 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -449,7 +449,7 @@
         "underlay": "Underlay",
         "poll": "Poll graph",
         "icons": "Icons",
-        "lightBg": "Highlighted elements",
+        "highlight": "Highlighted elements",
         "pressed": "Pressed",
         "selectedPost": "Selected post",
         "selectedMenu": "Selected menu item",
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index 63bfb5af..8c114004 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -47,7 +47,7 @@ export const LAYERS = {
   badge: null, //  no transparency support
   fg: null,
   bg: 'underlay',
-  lightBg: 'bg',
+  highlight: 'bg',
   panel: 'bg',
   btn: 'bg',
   btnPanel: 'panel',
@@ -148,57 +148,57 @@ export const SLOT_INHERITANCE = {
   cGreen: '#00FF00',
   cOrange: '#E3FF00',
 
-  lightBg: {
+  highlight: {
     depends: ['bg'],
     color: (mod, bg) => brightness(5 * mod, bg).rgb
   },
-  lightBgFaintText: {
+  highlightFaintText: {
     depends: ['faint'],
-    layer: 'lightBg',
+    layer: 'highlight',
     textColor: true
   },
-  lightBgFaintLink: {
+  highlightFaintLink: {
     depends: ['faintLink'],
-    layer: 'lightBg',
+    layer: 'highlight',
     textColor: 'preserve'
   },
-  lightBgText: {
+  highlightText: {
     depends: ['text'],
-    layer: 'lightBg',
+    layer: 'highlight',
     textColor: true
   },
-  lightBgLink: {
+  highlightLink: {
     depends: ['link'],
-    layer: 'lightBg',
+    layer: 'highlight',
     textColor: 'preserve'
   },
-  lightBgIcon: {
-    depends: ['lightBg', 'lightBgText'],
+  highlightIcon: {
+    depends: ['highlight', 'highlightText'],
     color: (mod, bg, text) => mixrgb(bg, text)
   },
 
-  selectedPost: '--lightBg',
+  selectedPost: '--highlight',
   selectedPostFaintText: {
-    depends: ['lightBgFaintText'],
-    layer: 'lightBg',
+    depends: ['highlightFaintText'],
+    layer: 'highlight',
     variant: 'selectedPost',
     textColor: true
   },
   selectedPostFaintLink: {
-    depends: ['lightBgFaintLink'],
-    layer: 'lightBg',
+    depends: ['highlightFaintLink'],
+    layer: 'highlight',
     variant: 'selectedPost',
     textColor: 'preserve'
   },
   selectedPostText: {
-    depends: ['lightBgText'],
-    layer: 'lightBg',
+    depends: ['highlightText'],
+    layer: 'highlight',
     variant: 'selectedPost',
     textColor: true
   },
   selectedPostLink: {
-    depends: ['lightBgLink'],
-    layer: 'lightBg',
+    depends: ['highlightLink'],
+    layer: 'highlight',
     variant: 'selectedPost',
     textColor: 'preserve'
   },
@@ -207,28 +207,28 @@ export const SLOT_INHERITANCE = {
     color: (mod, bg, text) => mixrgb(bg, text)
   },
 
-  selectedMenu: '--lightBg',
+  selectedMenu: '--highlight',
   selectedMenuFaintText: {
-    depends: ['lightBgFaintText'],
-    layer: 'lightBg',
+    depends: ['highlightFaintText'],
+    layer: 'highlight',
     variant: 'selectedMenu',
     textColor: true
   },
   selectedMenuFaintLink: {
-    depends: ['lightBgFaintLink'],
-    layer: 'lightBg',
+    depends: ['highlightFaintLink'],
+    layer: 'highlight',
     variant: 'selectedMenu',
     textColor: 'preserve'
   },
   selectedMenuText: {
-    depends: ['lightBgText'],
-    layer: 'lightBg',
+    depends: ['highlightText'],
+    layer: 'highlight',
     variant: 'selectedMenu',
     textColor: true
   },
   selectedMenuLink: {
-    depends: ['lightBgLink'],
-    layer: 'lightBg',
+    depends: ['highlightLink'],
+    layer: 'highlight',
     variant: 'selectedMenu',
     textColor: 'preserve'
   },
diff --git a/static/themes/breezy-dark.json b/static/themes/breezy-dark.json
index 3aafda52..c3bdcf65 100644
--- a/static/themes/breezy-dark.json
+++ b/static/themes/breezy-dark.json
@@ -114,7 +114,7 @@
       "cGreen": "#27ae60",
       "cOrange": "#f67400",
       "btnPressed": "--accent",
-      "lightBg": "--accent",
+      "highlight": "--accent",
       "selectedPost": "--bg,10"
     },
     "radii": {
diff --git a/static/themes/breezy-light.json b/static/themes/breezy-light.json
index df6e1a66..478407c9 100644
--- a/static/themes/breezy-light.json
+++ b/static/themes/breezy-light.json
@@ -117,7 +117,7 @@
       "cGreen": "#27ae60",
       "cOrange": "#f67400",
       "btnPressed": "--accent",
-      "lightBg": "--accent",
+      "highlight": "--accent",
       "selectedPost": "--bg,10"
     },
     "radii": {
diff --git a/static/themes/redmond-xx-se.json b/static/themes/redmond-xx-se.json
index 13ed3b0e..1a867fcc 100644
--- a/static/themes/redmond-xx-se.json
+++ b/static/themes/redmond-xx-se.json
@@ -283,7 +283,7 @@
       "cBlue": "#008080",
       "cGreen": "#008000",
       "cOrange": "#808000",
-      "lightBg": "--accent",
+      "highlight": "--accent",
       "selectedPost": "--bg,-10"
     },
     "radii": {
diff --git a/static/themes/redmond-xx.json b/static/themes/redmond-xx.json
index 7c687ae0..78c92f10 100644
--- a/static/themes/redmond-xx.json
+++ b/static/themes/redmond-xx.json
@@ -274,7 +274,7 @@
       "cBlue": "#008080",
       "cGreen": "#008000",
       "cOrange": "#808000",
-      "lightBg": "--accent",
+      "highlight": "--accent",
       "selectedPost": "--bg,-10"
     },
     "radii": {
diff --git a/static/themes/redmond-xxi.json b/static/themes/redmond-xxi.json
index 5371ee64..28f68351 100644
--- a/static/themes/redmond-xxi.json
+++ b/static/themes/redmond-xxi.json
@@ -256,7 +256,7 @@
       "cBlue": "#6699cc",
       "cGreen": "#669966",
       "cOrange": "#cc6633",
-      "lightBg": "--accent",
+      "highlight": "--accent",
       "selectedPost": "--bg,-10"
     },
     "radii": {
-- 
cgit v1.2.3-70-g09d2


From d98e31af458ed42e678072879265267e8148c627 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Wed, 22 Jan 2020 02:44:39 +0200
Subject: snapshot/source mismatch case

---
 src/components/style_switcher/style_switcher.js  | 53 +++++++++++++++++++++---
 src/components/style_switcher/style_switcher.vue | 18 +++++++-
 src/i18n/en.json                                 |  7 +++-
 3 files changed, 68 insertions(+), 10 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 195c6b35..3b538ac7 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -160,6 +160,9 @@ export default {
             )
         }
       } else if (origin === 'localStorage') {
+        if (type === 'snapshot_source_mismatch') {
+          return t(pre + 'snapshot_source_mismatch')
+        }
         // FE upgraded from v2
         if (themeEngineVersion === 2) {
           return t(pre + 'upgraded_from_v2')
@@ -345,7 +348,10 @@ export default {
         source.radii = this.currentRadii
       }
 
-      const theme = this.previewTheme
+      const theme = {
+        themeEngineVersion: CURRENT_VERSION,
+        ...this.previewTheme
+      }
 
       return {
         // To separate from other random JSON files and possible future source formats
@@ -381,17 +387,34 @@ export default {
       const version = (origin === 'localstorage' && !theme.colors)
         ? 'l1'
         : fileVersion
+      const snapshotEngineVersion = (theme || {}).themeEngineVersion
       const themeEngineVersion = (source || {}).themeEngineVersion || 2
       const versionsMatch = themeEngineVersion === CURRENT_VERSION
+      console.log(
+        theme !== undefined,
+        source !== undefined,
+        themeEngineVersion !== snapshotEngineVersion
+      )
+      const sourceSnapshotMismatch = (
+        theme !== undefined &&
+          source !== undefined &&
+          themeEngineVersion !== snapshotEngineVersion
+      )
       // Force loading of source if user requested it or if snapshot
       // is unavailable
       const forcedSourceLoad = (source && forceUseSource) || !theme
-      if (!versionsMatch &&
+      if (!(versionsMatch && !sourceSnapshotMismatch) &&
           !forcedSourceLoad &&
           version !== 'l1' &&
           origin !== 'defaults'
       ) {
-        if (!theme) {
+        if (sourceSnapshotMismatch) {
+          this.themeWarning = {
+            origin,
+            themeEngineVersion,
+            type: 'snapshot_source_mismatch'
+          }
+        } else if (!theme) {
           this.themeWarning = {
             origin,
             noActionsPossible: true,
@@ -428,7 +451,19 @@ export default {
       }
       this.dismissWarning()
     },
-    loadThemeFromLocalStorage (confirmLoadSource = false) {
+    forceSnapshot() {
+      const { origin } = this.themeWarning
+      switch (origin) {
+        case 'localstorage':
+          this.loadThemeFromLocalStorage(false, true)
+          break
+        case 'file':
+          console.err('Forcing snapshout from file is not supported yet')
+          break
+      }
+      this.dismissWarning()
+    },
+    loadThemeFromLocalStorage (confirmLoadSource = false, forceSnapshot = false) {
       const {
         customTheme: theme,
         customThemeSource: source
@@ -442,7 +477,10 @@ export default {
         )
       } else {
         this.loadTheme(
-          { theme, source },
+          {
+            theme,
+            source: forceSnapshot ? theme : source
+          },
           'localStorage',
           confirmLoadSource
         )
@@ -451,7 +489,10 @@ export default {
     setCustomTheme () {
       this.$store.dispatch('setOption', {
         name: 'customTheme',
-        value: this.previewTheme
+        value: {
+          themeEngineVersion: CURRENT_VERSION,
+          ...this.previewTheme
+        }
       })
       this.$store.dispatch('setOption', {
         name: 'customThemeSource',
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 79c2fcd3..793d68f1 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -7,7 +7,21 @@
         {{ themeWarningHelp }}
         </div>
         <div class="buttons">
-          <template v-if="themeWarning.noActionsPossible">
+          <template v-if="themeWarning.type === 'snapshot_source_mismatch'">
+            <button
+              class="btn"
+              @click="forceLoad"
+            >
+              {{ $t('settings.style.switcher.use_source') }}
+            </button>
+            <button
+              class="btn"
+              @click="dismissWarning"
+            >
+              {{ $t('settings.style.switcher.use_snapshot') }}
+            </button>
+          </template>
+          <template v-else-if="themeWarning.noActionsPossible">
             <button
               class="btn"
               @click="dismissWarning"
@@ -26,7 +40,7 @@
               class="btn"
               @click="dismissWarning"
             >
-              {{ $t('settings.style.switcher.use_snapshot') }}
+              {{ $t('settings.style.switcher.keep_as_is') }}
             </button>
           </template>
         </div>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 2622157a..81dde663 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -397,7 +397,9 @@
         "clear_all": "Clear all",
         "clear_opacity": "Clear opacity",
         "load_theme": "Load theme",
-        "use_snapshot": "Keep as is",
+        "keep_as_is": "Keep as is",
+        "use_snapshot": "Old version",
+        "use_source": "New version",
         "help": {
           "upgraded_from_v2": "PleromaFE has been upgraded, theme could look a little bit different than you remember.",
           "v2_imported": "File you imported was made for older FE. We try to maximize compatibility but there still could be inconsitencies.",
@@ -408,7 +410,8 @@
           "fe_upgraded": "PleromaFE's theme engine upgraded after version update.",
           "fe_downgraded": "PleromaFE's version rolled back.",
           "migration_snapshot_ok": "Just to be safe, theme snapshot loaded. You can try loading theme data.",
-          "migration_napshot_gone": "For whatever reason snapshot was missing, some stuff could look different than you remember."
+          "migration_napshot_gone": "For whatever reason snapshot was missing, some stuff could look different than you remember.",
+          "snapshot_source_mismatch": "Versions conflict: most likely FE was rolled back and updated again, if you changed theme using older version of FE you most likely want to use old version, otherwise use new version."
         }
       },
       "common": {
-- 
cgit v1.2.3-70-g09d2


From c7f42b7799d4a0484f7d40ac0a7377021caf9cb6 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Wed, 22 Jan 2020 02:53:40 +0200
Subject: made it actually work, the forceSnapshot

---
 src/components/style_switcher/style_switcher.js  | 11 +++--------
 src/components/style_switcher/style_switcher.vue |  2 +-
 2 files changed, 4 insertions(+), 9 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 3b538ac7..27df0d10 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -390,11 +390,6 @@ export default {
       const snapshotEngineVersion = (theme || {}).themeEngineVersion
       const themeEngineVersion = (source || {}).themeEngineVersion || 2
       const versionsMatch = themeEngineVersion === CURRENT_VERSION
-      console.log(
-        theme !== undefined,
-        source !== undefined,
-        themeEngineVersion !== snapshotEngineVersion
-      )
       const sourceSnapshotMismatch = (
         theme !== undefined &&
           source !== undefined &&
@@ -442,7 +437,7 @@ export default {
     forceLoad () {
       const { origin } = this.themeWarning
       switch (origin) {
-        case 'localstorage':
+        case 'localStorage':
           this.loadThemeFromLocalStorage(true)
           break
         case 'file':
@@ -451,10 +446,10 @@ export default {
       }
       this.dismissWarning()
     },
-    forceSnapshot() {
+    forceSnapshot () {
       const { origin } = this.themeWarning
       switch (origin) {
-        case 'localstorage':
+        case 'localStorage':
           this.loadThemeFromLocalStorage(false, true)
           break
         case 'file':
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 793d68f1..ff7f4710 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -16,7 +16,7 @@
             </button>
             <button
               class="btn"
-              @click="dismissWarning"
+              @click="forceSnapshot"
             >
               {{ $t('settings.style.switcher.use_snapshot') }}
             </button>
-- 
cgit v1.2.3-70-g09d2


From 53576df72aff5405ab30764e5cfcf2162bde37bc Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Fri, 24 Jan 2020 00:02:16 +0200
Subject: popover/selected menu improvements

---
 src/components/emoji_input/emoji_input.vue       | 11 +++---
 src/components/popper/popper.scss                |  7 +++-
 src/components/side_drawer/side_drawer.vue       |  7 +++-
 src/components/style_switcher/style_switcher.vue | 29 ++++++++++++++++
 src/services/theme_data/pleromafe.js             | 44 +++++++++++++++++++++---
 5 files changed, 87 insertions(+), 11 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue
index 46ed6f25..9c2501a9 100644
--- a/src/components/emoji_input/emoji_input.vue
+++ b/src/components/emoji_input/emoji_input.vue
@@ -109,10 +109,13 @@
         box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5);
         box-shadow: var(--popupShadow);
         min-width: 75%;
-        background: $fallback--bg;
-        background: var(--bg, $fallback--bg);
-        color: $fallback--lightText;
-        color: var(--lightText, $fallback--lightText);
+        background-color: $fallback--bg;
+        background-color: var(--popover, $fallback--bg);
+        color: $fallback--link;
+        color: var(--popoverText, $fallback--link);
+        --faint: var(--popoverFaintText, $fallback--faint);
+        --faintLink: var(--popoverFaintLink, $fallback--faint);
+        --icon: var(--popoverIcon, $fallback--icon);
       }
     }
 
diff --git a/src/components/popper/popper.scss b/src/components/popper/popper.scss
index 9c2ce25f..e70b277d 100644
--- a/src/components/popper/popper.scss
+++ b/src/components/popper/popper.scss
@@ -9,7 +9,12 @@
     border-radius: $fallback--btnRadius;
     border-radius: var(--btnRadius, $fallback--btnRadius);
     background-color: $fallback--bg;
-    background-color: var(--bg, $fallback--bg);
+    background-color: var(--popover, $fallback--bg);
+    color: $fallback--text;
+    color: var(--popoverText, $fallback--text);
+    --faint: var(--popoverFaintText, $fallback--faint);
+    --faintLink: var(--popoverFaintLink, $fallback--faint);
+    --icon: var(--popoverIcon, $fallback--icon);
   }
 
   .popover-arrow {
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index 3188fd59..a5b754d7 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -223,7 +223,12 @@
   box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);
   box-shadow: var(--panelShadow);
   background-color: $fallback--bg;
-  background-color: var(--bg, $fallback--bg);
+  background-color: var(--popover, $fallback--bg);
+  color: $fallback--link;
+  color: var(--popoverText, $fallback--link);
+  --faint: var(--popoverFaintText, $fallback--faint);
+  --faintLink: var(--popoverFaintLink, $fallback--faint);
+  --icon: var(--popoverIcon, $fallback--icon);
 
   .button-icon:before {
     width: 1.1em;
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index ff7f4710..1c39a806 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -554,6 +554,35 @@
             />
             <ContrastRatio :contrast="previewContrast.highlightLink" />
           </div>
+          <div class="color-item">
+            <h4>{{ $t('settings.style.advanced_colors.popover') }}</h4>
+            <ColorInput
+              v-model="popoverColorLocal"
+              name="popover"
+              :label="$t('settings.background')"
+              :fallback="previewTheme.colors.popover"
+            />
+            <OpacityInput
+              v-model="popoverOpacityLocal"
+              name="popoverOpacity"
+              :fallback="previewTheme.opacity.popover"
+              :disabled="popoverOpacityLocal === 'transparent'"
+            />
+            <ColorInput
+              v-model="popoverTextColorLocal"
+              name="popoverText"
+              :label="$t('settings.text')"
+              :fallback="previewTheme.colors.popoverText"
+            />
+            <ContrastRatio :contrast="previewContrast.popoverText" />
+            <ColorInput
+              v-model="popoverLinkColorLocal"
+              name="popoverLink"
+              :label="$t('settings.links')"
+              :fallback="previewTheme.colors.popoverLink"
+            />
+            <ContrastRatio :contrast="previewContrast.popoverLink" />
+          </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.selectedPost') }}</h4>
             <ColorInput
diff --git a/src/services/theme_data/pleromafe.js b/src/services/theme_data/pleromafe.js
index 0deb829f..484874d7 100644
--- a/src/services/theme_data/pleromafe.js
+++ b/src/services/theme_data/pleromafe.js
@@ -12,6 +12,8 @@ export const LAYERS = {
   bg: 'underlay',
   highlight: 'bg',
   panel: 'bg',
+  popover: 'bg',
+  selectedMenu: 'popover',
   btn: 'bg',
   btnPanel: 'panel',
   btnTopBar: 'topBar',
@@ -140,6 +142,35 @@ export const SLOT_INHERITANCE = {
     color: (mod, bg, text) => mixrgb(bg, text)
   },
 
+  popover: {
+    depends: ['bg'],
+    opacity: 'popover'
+  },
+  popoverFaintText: {
+    depends: ['faint'],
+    layer: 'popover',
+    textColor: true
+  },
+  popoverFaintLink: {
+    depends: ['faintLink'],
+    layer: 'popover',
+    textColor: 'preserve'
+  },
+  popoverText: {
+    depends: ['text'],
+    layer: 'popover',
+    textColor: true
+  },
+  popoverLink: {
+    depends: ['link'],
+    layer: 'popover',
+    textColor: 'preserve'
+  },
+  popoverIcon: {
+    depends: ['popover', 'popoverText'],
+    color: (mod, bg, text) => mixrgb(bg, text)
+  },
+
   selectedPost: '--highlight',
   selectedPostFaintText: {
     depends: ['highlightFaintText'],
@@ -170,28 +201,31 @@ export const SLOT_INHERITANCE = {
     color: (mod, bg, text) => mixrgb(bg, text)
   },
 
-  selectedMenu: '--highlight',
+  selectedMenu: {
+    depends: ['popover'],
+    color: (mod, bg) => brightness(5 * mod, bg).rgb
+  },
   selectedMenuFaintText: {
     depends: ['highlightFaintText'],
-    layer: 'highlight',
+    layer: 'selectedMenu',
     variant: 'selectedMenu',
     textColor: true
   },
   selectedMenuFaintLink: {
     depends: ['highlightFaintLink'],
-    layer: 'highlight',
+    layer: 'selectedMenu',
     variant: 'selectedMenu',
     textColor: 'preserve'
   },
   selectedMenuText: {
     depends: ['highlightText'],
-    layer: 'highlight',
+    layer: 'selectedMenu',
     variant: 'selectedMenu',
     textColor: true
   },
   selectedMenuLink: {
     depends: ['highlightLink'],
-    layer: 'highlight',
+    layer: 'selectedMenu',
     variant: 'selectedMenu',
     textColor: 'preserve'
   },
-- 
cgit v1.2.3-70-g09d2


From 5313833d80221bbad667aeda39ca9e7321489e30 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 27 Jan 2020 04:24:00 +0200
Subject: lint

---
 src/components/style_switcher/style_switcher.vue   | 137 +++++++++++----------
 .../specs/services/theme_data/theme_data.spec.js   |   1 -
 2 files changed, 70 insertions(+), 68 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 1c39a806..6e38bd8e 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -1,74 +1,77 @@
 <template>
-<div class="style-switcher">
-  <div class="presets-container">
-    <div class="save-load">
-      <div class="theme-warning" v-if="themeWarning">
-        <div class="alert warning">
-        {{ themeWarningHelp }}
-        </div>
-        <div class="buttons">
-          <template v-if="themeWarning.type === 'snapshot_source_mismatch'">
-            <button
-              class="btn"
-              @click="forceLoad"
-            >
-              {{ $t('settings.style.switcher.use_source') }}
-            </button>
-            <button
-              class="btn"
-              @click="forceSnapshot"
-            >
-              {{ $t('settings.style.switcher.use_snapshot') }}
-            </button>
-          </template>
-          <template v-else-if="themeWarning.noActionsPossible">
-            <button
-              class="btn"
-              @click="dismissWarning"
-            >
-              {{ $t('general.dismiss') }}
-            </button>
-          </template>
-          <template v-else>
-            <button
-              class="btn"
-              @click="forceLoad"
-            >
-              {{ $t('settings.style.switcher.load_theme') }}
-            </button>
-            <button
-              class="btn"
-              @click="dismissWarning"
-            >
-              {{ $t('settings.style.switcher.keep_as_is') }}
-            </button>
-          </template>
+  <div class="style-switcher">
+    <div class="presets-container">
+      <div class="save-load">
+        <div
+          v-if="themeWarning"
+          class="theme-warning"
+        >
+          <div class="alert warning">
+            {{ themeWarningHelp }}
+          </div>
+          <div class="buttons">
+            <template v-if="themeWarning.type === 'snapshot_source_mismatch'">
+              <button
+                class="btn"
+                @click="forceLoad"
+              >
+                {{ $t('settings.style.switcher.use_source') }}
+              </button>
+              <button
+                class="btn"
+                @click="forceSnapshot"
+              >
+                {{ $t('settings.style.switcher.use_snapshot') }}
+              </button>
+            </template>
+            <template v-else-if="themeWarning.noActionsPossible">
+              <button
+                class="btn"
+                @click="dismissWarning"
+              >
+                {{ $t('general.dismiss') }}
+              </button>
+            </template>
+            <template v-else>
+              <button
+                class="btn"
+                @click="forceLoad"
+              >
+                {{ $t('settings.style.switcher.load_theme') }}
+              </button>
+              <button
+                class="btn"
+                @click="dismissWarning"
+              >
+                {{ $t('settings.style.switcher.keep_as_is') }}
+              </button>
+            </template>
+          </div>
         </div>
-      </div>
-      <ExportImport
-        :export-object="exportedTheme"
-        :export-label="$t(&quot;settings.export_theme&quot;)"
-        :import-label="$t(&quot;settings.import_theme&quot;)"
-        :import-failed-text="$t(&quot;settings.invalid_theme_imported&quot;)"
-        :on-import="onImport"
-        :validator="importValidator"
-      >
-        <template slot="before">
-          <div class="presets">
-            {{ $t('settings.presets') }}
-            <label
-              for="preset-switcher"
-              class="select"
+        <ExportImport
+          :export-object="exportedTheme"
+          :export-label="$t(&quot;settings.export_theme&quot;)"
+          :import-label="$t(&quot;settings.import_theme&quot;)"
+          :import-failed-text="$t(&quot;settings.invalid_theme_imported&quot;)"
+          :on-import="onImport"
+          :validator="importValidator"
+        >
+          <template slot="before">
+            <div class="presets">
+              {{ $t('settings.presets') }}
+              <label
+                for="preset-switcher"
+                class="select"
               >
-              <select
-                id="preset-switcher"
-                v-model="selected"
-                class="preset-switcher"
+                <select
+                  id="preset-switcher"
+                  v-model="selected"
+                  class="preset-switcher"
                 >
-                <option
-                  v-for="style in availableStyles"
-                  :key="style.name"
-                  :value="style"
+                  <option
+                    v-for="style in availableStyles"
+                    :key="style.name"
+                    :value="style"
                     :style="{
                       backgroundColor: style[1] || (style.theme || style.source).colors.bg,
                       color: style[3] || (style.theme || style.source).colors.text
diff --git a/test/unit/specs/services/theme_data/theme_data.spec.js b/test/unit/specs/services/theme_data/theme_data.spec.js
index 67f4fd5a..c634cade 100644
--- a/test/unit/specs/services/theme_data/theme_data.spec.js
+++ b/test/unit/specs/services/theme_data/theme_data.spec.js
@@ -86,5 +86,4 @@ describe('Theme Data utility functions', () => {
       expect(out.indexOf('a')).to.be.below(out.indexOf('c'))
     })
   })
-
 })
-- 
cgit v1.2.3-70-g09d2


From 526b43eba66c597c78857da6ded3c7f672f96e49 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 28 Jan 2020 01:29:20 +0200
Subject: Kenomo (see: #624) theme. Ability to define link color for post
 contents. Fixes

---
 src/components/emoji_input/emoji_input.vue       |  2 +
 src/components/notifications/notifications.scss  |  3 +
 src/components/popper/popper.scss                |  2 +
 src/components/status/status.vue                 |  7 +++
 src/components/style_switcher/style_switcher.vue | 17 ++++++
 src/components/user_card/user_card.vue           |  5 ++
 src/services/theme_data/pleromafe.js             | 34 ++++++++++++
 static/themes/kenomo.json                        | 71 ++++++++++++++++++++++++
 8 files changed, 141 insertions(+)
 create mode 100644 static/themes/kenomo.json

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/emoji_input/emoji_input.vue b/src/components/emoji_input/emoji_input.vue
index 94eae560..e9ac09c3 100644
--- a/src/components/emoji_input/emoji_input.vue
+++ b/src/components/emoji_input/emoji_input.vue
@@ -116,6 +116,8 @@
         --faint: var(--popoverFaintText, $fallback--faint);
         --faintLink: var(--popoverFaintLink, $fallback--faint);
         --lightText: var(--popoverLightText, $fallback--lightText);
+        --postLink: var(--popoverPostLink, $fallback--link);
+        --postFaintLink: var(--popoverPostFaintLink, $fallback--link);
         --icon: var(--popoverIcon, $fallback--icon);
       }
     }
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss
index 71876b14..ca762432 100644
--- a/src/components/notifications/notifications.scss
+++ b/src/components/notifications/notifications.scss
@@ -68,6 +68,9 @@
         a {
           color: var(--faintLink);
         }
+        .status-content a {
+          color: var(--postFaintLink);
+        }
       }
       padding: 0;
       .media-body {
diff --git a/src/components/popper/popper.scss b/src/components/popper/popper.scss
index 341416c1..8e2dcd55 100644
--- a/src/components/popper/popper.scss
+++ b/src/components/popper/popper.scss
@@ -15,6 +15,8 @@
     --faint: var(--popoverFaintText, $fallback--faint);
     --faintLink: var(--popoverFaintLink, $fallback--faint);
     --lightText: var(--popoverLightText, $fallback--lightText);
+    --postLink: var(--popoverPostLink, $fallback--link);
+    --postFaintLink: var(--popoverPostFaintLink, $fallback--link);
     --icon: var(--popoverIcon, $fallback--icon);
   }
 
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 1997e187..b1048832 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -451,6 +451,8 @@ $status-margin: 0.75em;
     --lightText: var(--selectedPostLightText, $fallback--light);
     --faint: var(--selectedPostFaintText, $fallback--faint);
     --faintLink: var(--selectedPostFaintLink, $fallback--faint);
+    --postLink: var(--selectedPostPostLink, $fallback--faint);
+    --postFaintLink: var(--selectedPostFaintPostLink, $fallback--faint);
     --icon: var(--selectedPostIcon, $fallback--icon);
   }
 
@@ -640,6 +642,11 @@ $status-margin: 0.75em;
     line-height: 1.4em;
     white-space: pre-wrap;
 
+    a {
+      color: $fallback--link;
+      color: var(--postLink, $fallback--link);
+    }
+
     img, video {
       max-width: 100%;
       max-height: 400px;
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 6e38bd8e..0b3b0fbf 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -248,6 +248,23 @@
             </button>
           </div>
           <div class="color-item">
+            <h4>{{ $t('settings.style.advanced_colors.post') }}</h4>
+            <ColorInput
+              v-model="postLinkColorLocal"
+              name="postLinkColor"
+              :fallback="previewTheme.colors.accent"
+              :label="$t('settings.links')"
+              :show-optional-tickbox="typeof accentColorLocal !== 'undefined'"
+            />
+            <ContrastRatio :contrast="previewContrast.bgPostLink" />
+            <ColorInput
+              v-model="iconColorLocal"
+              name="iconColor"
+              :fallback="previewTheme.colors.accent"
+              :label="$t('settings.links')"
+              :show-optional-tickbox="typeof accentColorLocal !== 'undefined'"
+            />
+            <ContrastRatio :contrast="previewContrast.bgIcon" />
             <h4>{{ $t('settings.style.advanced_colors.alert') }}</h4>
             <ColorInput
               v-model="alertErrorColorLocal"
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index e286ceea..72656435 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -299,6 +299,11 @@
   &-bio {
     text-align: center;
 
+    a {
+      color: $fallback--link;
+      color: var(--postLink, $fallback--link);
+    }
+
     img {
       object-fit: contain;
       vertical-align: middle;
diff --git a/src/services/theme_data/pleromafe.js b/src/services/theme_data/pleromafe.js
index a40d08a6..74e6fc1c 100644
--- a/src/services/theme_data/pleromafe.js
+++ b/src/services/theme_data/pleromafe.js
@@ -107,6 +107,10 @@ export const SLOT_INHERITANCE = {
     depends: ['link'],
     opacity: 'faint'
   },
+  postFaintLink: {
+    depends: ['postLink'],
+    opacity: 'faint'
+  },
 
   cBlue: '#0000ff',
   cRed: '#FF0000',
@@ -122,6 +126,11 @@ export const SLOT_INHERITANCE = {
     layer: 'highlight',
     textColor: true
   },
+  highlightPostLink: {
+    depends: ['postLink'],
+    layer: 'highlight',
+    textColor: 'preserve'
+  },
   highlightFaintText: {
     depends: ['faint'],
     layer: 'highlight',
@@ -132,6 +141,11 @@ export const SLOT_INHERITANCE = {
     layer: 'highlight',
     textColor: 'preserve'
   },
+  highlightPostFaintLink: {
+    depends: ['postFaintLink'],
+    layer: 'highlight',
+    textColor: 'preserve'
+  },
   highlightText: {
     depends: ['text'],
     layer: 'highlight',
@@ -156,6 +170,11 @@ export const SLOT_INHERITANCE = {
     layer: 'popover',
     textColor: true
   },
+  popoverPostLink: {
+    depends: ['postLink'],
+    layer: 'popover',
+    textColor: 'preserve'
+  },
   popoverFaintText: {
     depends: ['faint'],
     layer: 'popover',
@@ -166,6 +185,11 @@ export const SLOT_INHERITANCE = {
     layer: 'popover',
     textColor: 'preserve'
   },
+  popoverPostFaintLink: {
+    depends: ['postFaintLink'],
+    layer: 'popover',
+    textColor: 'preserve'
+  },
   popoverText: {
     depends: ['text'],
     layer: 'popover',
@@ -194,6 +218,12 @@ export const SLOT_INHERITANCE = {
     variant: 'selectedPost',
     textColor: true
   },
+  selectedPostPostLink: {
+    depends: ['highlightPostLink'],
+    layer: 'highlight',
+    variant: 'selectedPost',
+    textColor: 'preserve'
+  },
   selectedPostFaintLink: {
     depends: ['highlightFaintLink'],
     layer: 'highlight',
@@ -300,6 +330,10 @@ export const SLOT_INHERITANCE = {
     color: (mod, text) => brightness(20 * mod, text).rgb
   },
 
+  postLink: {
+    depends: ['link']
+  },
+
   border: {
     depends: ['fg'],
     opacity: 'border',
diff --git a/static/themes/kenomo.json b/static/themes/kenomo.json
new file mode 100644
index 00000000..98ddf974
--- /dev/null
+++ b/static/themes/kenomo.json
@@ -0,0 +1,71 @@
+{
+  "_pleroma_theme_version": 2,
+  "name": "Kenomo",
+  "source": {
+    "themeEngineVersion": 3,
+    "fonts": {},
+    "shadows": {
+      "panel": [],
+      "topBar": [],
+      "button": [
+        {
+          "x": 0,
+          "y": 1,
+          "blur": 0,
+          "spread": 0,
+          "color": "#FFFFFF",
+          "alpha": 0.2,
+          "inset": true
+        },
+        {
+          "x": 0,
+          "y": -1,
+          "blur": 0,
+          "spread": 0,
+          "color": "#000000",
+          "alpha": 0.2,
+          "inset": true
+        }
+      ],
+      "input": [
+        {
+          "x": 0,
+          "y": "0",
+          "blur": 0,
+          "spread": "1",
+          "color": "#576574",
+          "alpha": "1",
+          "inset": true
+        }
+      ]
+    },
+    "opacity": {
+      "underlay": "1",
+      "border": "0"
+    },
+    "colors": {
+      "bg": "#ffffff",
+      "fg": "#f6f6f6",
+      "text": "#494949",
+      "underlay": "#ffffff",
+      "link": "#818181",
+      "accent": "#818181",
+      "cBlue": "#2e86de",
+      "cRed": "#c96248",
+      "cGreen": "#0fa00f",
+      "cOrange": "#aa7623",
+      "postLink": "#2e86de",
+      "border": "#ffffff",
+      "icon": "#8a8a8a",
+      "panel": "transparent",
+      "topBarText": "#4b4b4b",
+      "tab": "--btn,-30",
+      "btn": "#576574"
+    },
+    "radii": {
+      "panel": "0",
+      "avatar": "6",
+      "avatarAlt": "6"
+    }
+  }
+}
-- 
cgit v1.2.3-70-g09d2


From b63e679a31a573c30868477f17322d6ed040af58 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 28 Jan 2020 02:03:21 +0200
Subject: removed one color TODO

---
 src/components/popper/popper.scss                |  2 ++
 src/components/style_switcher/style_switcher.vue | 29 +++++++++++++++++-------
 src/components/user_card/user_card.vue           |  5 ++--
 src/i18n/en.json                                 |  3 +++
 src/services/theme_data/pleromafe.js             | 20 +++++++++++++++-
 5 files changed, 47 insertions(+), 12 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/popper/popper.scss b/src/components/popper/popper.scss
index 8e2dcd55..99b7e6fc 100644
--- a/src/components/popper/popper.scss
+++ b/src/components/popper/popper.scss
@@ -137,6 +137,8 @@
     width: 100%;
     height: 100%;
 
+    --btnText: var(--popoverText, $fallback--text);
+
     &-icon {
       padding-left: 0.5rem;
 
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 0b3b0fbf..9de3a96c 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -257,14 +257,6 @@
               :show-optional-tickbox="typeof accentColorLocal !== 'undefined'"
             />
             <ContrastRatio :contrast="previewContrast.bgPostLink" />
-            <ColorInput
-              v-model="iconColorLocal"
-              name="iconColor"
-              :fallback="previewTheme.colors.accent"
-              :label="$t('settings.links')"
-              :show-optional-tickbox="typeof accentColorLocal !== 'undefined'"
-            />
-            <ContrastRatio :contrast="previewContrast.bgIcon" />
             <h4>{{ $t('settings.style.advanced_colors.alert') }}</h4>
             <ColorInput
               v-model="alertErrorColorLocal"
@@ -298,6 +290,27 @@
               :contrast="previewContrast.alertWarningText"
               large="true"
             />
+            <ColorInput
+              v-model="alertNeutralColorLocal"
+              name="alertNeutral"
+              :label="$t('settings.style.advanced_colors.alert_neutral')"
+              :fallback="previewTheme.colors.alertNeutral"
+            />
+            <ColorInput
+              v-model="alertNeutralTextColorLocal"
+              name="alertNeutralText"
+              :label="$t('settings.text')"
+              :fallback="previewTheme.colors.alertNeutralText"
+            />
+            <ContrastRatio
+              :contrast="previewContrast.alertNeutralText"
+              large="true"
+            />
+            <OpacityInput
+              v-model="alertOpacityLocal"
+              name="alertOpacity"
+              :fallback="previewTheme.opacity.alert"
+            />
           </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.badge') }}</h4>
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 72656435..3988ff1c 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -465,14 +465,13 @@
       color: var(--text, $fallback--text);
     }
 
-    // TODO use proper colors
     .staff {
       flex: none;
       text-transform: capitalize;
       color: $fallback--text;
-      color: var(--btnText, $fallback--text);
+      color: var(--alertNeutralText, $fallback--text);
       background-color: $fallback--fg;
-      background-color: var(--btn, $fallback--fg);
+      background-color: var(--alertNeutral, $fallback--fg);
     }
   }
 
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 81dde663..06cc12f0 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -441,7 +441,10 @@
         "alert": "Alert background",
         "alert_error": "Error",
         "alert_warning": "Warning",
+        "alert_neutral": "Neutral",
+        "post": "Posts/User bios",
         "badge": "Badge background",
+        "popover": "Tooltips, menus, popovers",
         "badge_notification": "Notification",
         "panel_header": "Panel header",
         "top_bar": "Top bar",
diff --git a/src/services/theme_data/pleromafe.js b/src/services/theme_data/pleromafe.js
index 74e6fc1c..354009ee 100644
--- a/src/services/theme_data/pleromafe.js
+++ b/src/services/theme_data/pleromafe.js
@@ -1,4 +1,4 @@
-import { brightness } from 'chromatism'
+import { invertLightness, brightness } from 'chromatism'
 import { alphaBlend, mixrgb } from '../color_convert/color_convert.js'
 /* This is a definition of all layer combinations
  * each key is a topmost layer, each value represents layer underneath
@@ -574,6 +574,24 @@ export const SLOT_INHERITANCE = {
     textColor: true
   },
 
+  alertNeutral: {
+    depends: ['text'],
+    opacity: 'alert'
+  },
+  alertNeutralText: {
+    depends: ['text'],
+    layer: 'alert',
+    variant: 'alertNeutral',
+    color: (mod, text) => invertLightness(text).rgb,
+    textColor: true
+  },
+  alertNeutralPanelText: {
+    depends: ['panelText'],
+    layer: 'alertPanel',
+    variant: 'alertNeutral',
+    textColor: true
+  },
+
   badgeNotification: '--cRed',
   badgeNotificationText: {
     depends: ['text', 'badgeNotification'],
-- 
cgit v1.2.3-70-g09d2


From 846285326900a497c68dc994ce06dcb1d5d1ca9c Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 28 Jan 2020 22:40:15 +0200
Subject: update button toggled state, apply it to emoji reactions

---
 src/App.scss                                       |  4 +++-
 src/components/emoji_reactions/emoji_reactions.vue |  8 +-------
 src/components/style_switcher/style_switcher.vue   | 13 +++++++++++++
 static/themes/redmond-xx-se.json                   |  2 ++
 static/themes/redmond-xx.json                      |  2 ++
 static/themes/redmond-xxi.json                     |  2 ++
 6 files changed, 23 insertions(+), 8 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/App.scss b/src/App.scss
index dd994a38..1fabaaa9 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -117,7 +117,9 @@ button {
     color: $fallback--text;
     color: var(--btnToggledText, $fallback--text);
     background-color: $fallback--fg;
-    background-color: var(--btnToggled, $fallback--fg)
+    background-color: var(--btnToggled, $fallback--fg);
+    box-shadow: 0px 0px 4px 0px rgba(255, 255, 255, 0.3), 0px 1px 0px 0px rgba(0, 0, 0, 0.2) inset, 0px -1px 0px 0px rgba(255, 255, 255, 0.2) inset;
+    box-shadow: var(--buttonPressedShadow);
   }
 
   &.danger {
diff --git a/src/components/emoji_reactions/emoji_reactions.vue b/src/components/emoji_reactions/emoji_reactions.vue
index 00d6d2b7..f5d2e79a 100644
--- a/src/components/emoji_reactions/emoji_reactions.vue
+++ b/src/components/emoji_reactions/emoji_reactions.vue
@@ -4,7 +4,7 @@
       v-for="(reaction) in emojiReactions"
       :key="reaction.emoji"
       class="emoji-reaction btn btn-default"
-      :class="{ 'picked-reaction': reactedWith(reaction.emoji) }"
+      :class="{ 'toggled': reactedWith(reaction.emoji) }"
       @click="emojiOnClick(reaction.emoji, $event)"
     >
       <span class="reaction-emoji">{{ reaction.emoji }}</span>
@@ -40,10 +40,4 @@
   }
 }
 
-.picked-reaction {
-  border: 1px solid var(--link, $fallback--link);
-  margin-left: -1px; // offset the border, can't use inset shadows either
-  margin-right: calc(0.5em - 1px);
-}
-
 </style>
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 9de3a96c..5a42bba7 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -460,6 +460,19 @@
               :label="$t('settings.text')"
             />
             <ContrastRatio :contrast="previewContrast.btnDisabledText" />
+            <h4>{{ $t('settings.style.advanced_colors.toggled') }}</h4>
+            <ColorInput
+              v-model="btnToggledColorLocal"
+              name="btnToggledColor"
+              :fallback="previewTheme.colors.btnToggled"
+              :label="$t('settings.background')"
+            />
+            <ColorInput
+              v-model="btnToggledTextColorLocal"
+              name="btnToggledTextColor"
+              :fallback="previewTheme.colors.btnToggledText"
+              :label="$t('settings.text')"
+            />
           </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.tabs') }}</h4>
diff --git a/static/themes/redmond-xx-se.json b/static/themes/redmond-xx-se.json
index 8deab7b7..7a4a29da 100644
--- a/static/themes/redmond-xx-se.json
+++ b/static/themes/redmond-xx-se.json
@@ -2,6 +2,7 @@
   "_pleroma_theme_version": 2,
   "name": "Redmond XX SE",
   "source": {
+    "themeEngineVersion": 3,
     "shadows": {
       "panel": [
         {
@@ -276,6 +277,7 @@
       "topBar": "#000080",
       "topBarLink": "#ffffff",
       "btn": "#c0c0c0",
+      "btnToggled": "--btn",
       "faint": "#3f3f3f",
       "faintLink": "#404080",
       "border": "#808080",
diff --git a/static/themes/redmond-xx.json b/static/themes/redmond-xx.json
index cdb89fe3..ff95b1e0 100644
--- a/static/themes/redmond-xx.json
+++ b/static/themes/redmond-xx.json
@@ -2,6 +2,7 @@
   "_pleroma_theme_version": 2,
   "name": "Redmond XX",
   "source": {
+    "themeEngineVersion": 3,
     "shadows": {
       "panel": [
         {
@@ -267,6 +268,7 @@
       "topBar": "#000080",
       "topBarLink": "#ffffff",
       "btn": "#c0c0c0",
+      "btnToggled": "--btn",
       "faint": "#3f3f3f",
       "faintLink": "#404080",
       "border": "#808080",
diff --git a/static/themes/redmond-xxi.json b/static/themes/redmond-xxi.json
index 79a2cb26..f788bdb8 100644
--- a/static/themes/redmond-xxi.json
+++ b/static/themes/redmond-xxi.json
@@ -2,6 +2,7 @@
   "_pleroma_theme_version": 2,
   "name": "Redmond XXI",
   "source": {
+    "themeEngineVersion": 3,
     "shadows": {
       "panel": [
         {
@@ -249,6 +250,7 @@
       "topBar": "#042967",
       "topBarLink": "#ffffff",
       "btn": "#d6d6ce",
+      "btnToggled": "--btn",
       "faint": "#3f3f3f",
       "faintLink": "#404080",
       "border": "#808080",
-- 
cgit v1.2.3-70-g09d2


From e46bb942260d192beb601727519ed90df5c62494 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 28 Jan 2020 23:45:14 +0200
Subject: updated preview to account for underlay

---
 src/App.scss                                     |   4 +-
 src/App.vue                                      |   2 +-
 src/components/style_switcher/preview.vue        | 188 ++++++++++++-----------
 src/components/style_switcher/style_switcher.vue |   4 +-
 4 files changed, 107 insertions(+), 91 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/App.scss b/src/App.scss
index 1fabaaa9..85fd0b47 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -31,9 +31,11 @@ h4 {
   margin: auto;
   min-height: 100vh;
   max-width: 980px;
+  align-content: flex-start;
+}
+.underlay {
   background-color: rgba(0,0,0,0.15);
   background-color: var(--underlay, rgba(0,0,0,0.15));
-  align-content: flex-start;
 }
 
 .text-center {
diff --git a/src/App.vue b/src/App.vue
index 1b1c2648..ff62fc51 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -78,7 +78,7 @@
     </nav>
     <div
       id="content"
-      class="container"
+      class="container underlay"
     >
       <div class="sidebar-flexer mobile-hidden">
         <div class="sidebar-bounds">
diff --git a/src/components/style_switcher/preview.vue b/src/components/style_switcher/preview.vue
index 101a32bd..5b8c3839 100644
--- a/src/components/style_switcher/preview.vue
+++ b/src/components/style_switcher/preview.vue
@@ -1,101 +1,117 @@
 <template>
-  <div class="panel dummy">
-    <div class="panel-heading">
-      <div class="title">
-        {{ $t('settings.style.preview.header') }}
-        <span class="badge badge-notification">
-          99
+  <div class="preview-container">
+    <div class="underlay underlay-preview"/>
+    <div class="panel dummy">
+      <div class="panel-heading">
+        <div class="title">
+          {{ $t('settings.style.preview.header') }}
+          <span class="badge badge-notification">
+            99
+          </span>
+        </div>
+        <span class="faint">
+          {{ $t('settings.style.preview.header_faint') }}
+        </span>
+        <span class="alert error">
+          {{ $t('settings.style.preview.error') }}
         </span>
+        <button class="btn">
+          {{ $t('settings.style.preview.button') }}
+        </button>
       </div>
-      <span class="faint">
-        {{ $t('settings.style.preview.header_faint') }}
-      </span>
-      <span class="alert error">
-        {{ $t('settings.style.preview.error') }}
-      </span>
-      <button class="btn">
-        {{ $t('settings.style.preview.button') }}
-      </button>
-    </div>
-    <div class="panel-body theme-preview-content">
-      <div class="post">
-        <div class="avatar">
-          ( ͡° ͜ʖ ͡°)
-        </div>
-        <div class="content">
-          <h4>
-            {{ $t('settings.style.preview.content') }}
-          </h4>
+      <div class="panel-body theme-preview-content">
+        <div class="post">
+          <div class="avatar">
+            ( ͡° ͜ʖ ͡°)
+          </div>
+          <div class="content">
+            <h4>
+              {{ $t('settings.style.preview.content') }}
+            </h4>
 
-          <i18n path="settings.style.preview.text">
-            <code style="font-family: var(--postCodeFont)">
-              {{ $t('settings.style.preview.mono') }}
-            </code>
-            <a style="color: var(--link)">
-              {{ $t('settings.style.preview.link') }}
-            </a>
-          </i18n>
+            <i18n path="settings.style.preview.text">
+              <code style="font-family: var(--postCodeFont)">
+                {{ $t('settings.style.preview.mono') }}
+              </code>
+              <a style="color: var(--link)">
+                {{ $t('settings.style.preview.link') }}
+              </a>
+            </i18n>
 
-          <div class="icons">
-            <i
-              style="color: var(--cBlue)"
-              class="button-icon icon-reply"
-            />
-            <i
-              style="color: var(--cGreen)"
-              class="button-icon icon-retweet"
-            />
-            <i
-              style="color: var(--cOrange)"
-              class="button-icon icon-star"
-            />
-            <i
-              style="color: var(--cRed)"
-              class="button-icon icon-cancel"
-            />
+            <div class="icons">
+              <i
+                style="color: var(--cBlue)"
+                class="button-icon icon-reply"
+              />
+              <i
+                style="color: var(--cGreen)"
+                class="button-icon icon-retweet"
+              />
+              <i
+                style="color: var(--cOrange)"
+                class="button-icon icon-star"
+              />
+              <i
+                style="color: var(--cRed)"
+                class="button-icon icon-cancel"
+              />
+            </div>
           </div>
         </div>
-      </div>
 
-      <div class="after-post">
-        <div class="avatar-alt">
-          :^)
-        </div>
-        <div class="content">
-          <i18n
-            path="settings.style.preview.fine_print"
-            tag="span"
-            class="faint"
-          >
-            <a style="color: var(--faintLink)">
-              {{ $t('settings.style.preview.faint_link') }}
-            </a>
-          </i18n>
+        <div class="after-post">
+          <div class="avatar-alt">
+            :^)
+          </div>
+          <div class="content">
+            <i18n
+              path="settings.style.preview.fine_print"
+              tag="span"
+              class="faint"
+            >
+              <a style="color: var(--faintLink)">
+                {{ $t('settings.style.preview.faint_link') }}
+              </a>
+            </i18n>
+          </div>
         </div>
-      </div>
-      <div class="separator" />
+        <div class="separator" />
 
-      <span class="alert error">
-        {{ $t('settings.style.preview.error') }}
-      </span>
-      <input
-        :value="$t('settings.style.preview.input')"
-        type="text"
-      >
-
-      <div class="actions">
-        <span class="checkbox">
-          <input
-            id="preview_checkbox"
-            checked="very yes"
-            type="checkbox"
-          >
-          <label for="preview_checkbox">{{ $t('settings.style.preview.checkbox') }}</label>
+        <span class="alert error">
+          {{ $t('settings.style.preview.error') }}
         </span>
-        <button class="btn">
-          {{ $t('settings.style.preview.button') }}
-        </button>
+        <input
+          :value="$t('settings.style.preview.input')"
+          type="text"
+        >
+
+        <div class="actions">
+          <span class="checkbox">
+            <input
+              id="preview_checkbox"
+              checked="very yes"
+              type="checkbox"
+            >
+            <label for="preview_checkbox">{{ $t('settings.style.preview.checkbox') }}</label>
+          </span>
+          <button class="btn">
+            {{ $t('settings.style.preview.button') }}
+          </button>
+        </div>
       </div>
     </div>
   </div>
 </template>
+
+<style lang="scss">
+.preview-container {
+  position: relative;
+}
+.underlay-preview {
+  position: absolute;
+  top: 0;
+  bottom: 0;
+  left: 10px;
+  right: 10px;
+}
+</style>
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 5a42bba7..a3f9b488 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -116,9 +116,7 @@
       </div>
     </div>
 
-    <div class="preview-container">
-      <preview :style="previewRules" />
-    </div>
+    <preview :style="previewRules" />
 
     <keep-alive>
       <tab-switcher key="style-tweak">
-- 
cgit v1.2.3-70-g09d2


From 611da13a4b252c10f1613d70d877e2d039ba64b7 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Fri, 7 Feb 2020 01:25:26 +0200
Subject: Better Disabled buttons support. Mammal theme fixes. Implemented
 proper context-aware `mod` argument - now checks lightness of "variant"
 color. needs retesting tho

---
 src/App.scss                                     |  4 +-
 src/components/checkbox/checkbox.vue             |  4 +-
 src/components/style_switcher/style_switcher.vue | 57 ++++++++++++++++++++++++
 src/i18n/en.json                                 |  1 +
 src/services/style_setter/style_setter.js        | 17 ++-----
 src/services/theme_data/pleromafe.js             | 31 +++++++------
 src/services/theme_data/theme_data.service.js    |  9 ++--
 7 files changed, 89 insertions(+), 34 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/App.scss b/src/App.scss
index 85fd0b47..9f37ff12 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -179,7 +179,7 @@ input, textarea, .select, .input {
     right: 5px;
     height: 100%;
     color: $fallback--text;
-    color: var(--text, $fallback--text);
+    color: var(--inputText, $fallback--text);
     line-height: 28px;
     z-index: 0;
     pointer-events: none;
@@ -254,7 +254,7 @@ input, textarea, .select, .input {
     display: none;
     &:checked + label::before {
       color: $fallback--text;
-      color: var(--text, $fallback--text);
+      color: var(--inputText, $fallback--text);
     }
     &:disabled {
       &,
diff --git a/src/components/checkbox/checkbox.vue b/src/components/checkbox/checkbox.vue
index 1113f81d..03375b2f 100644
--- a/src/components/checkbox/checkbox.vue
+++ b/src/components/checkbox/checkbox.vue
@@ -87,13 +87,13 @@ export default {
 
     &:checked + .checkbox-indicator::before {
       color: $fallback--text;
-      color: var(--text, $fallback--text);
+      color: var(--inputText, $fallback--text);
     }
 
     &:indeterminate + .checkbox-indicator::before {
       content: '–';
       color: $fallback--text;
-      color: var(--text, $fallback--text);
+      color: var(--inputText, $fallback--text);
     }
 
   }
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index a3f9b488..705a60a2 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -430,6 +430,20 @@
               :label="$t('settings.text')"
             />
             <ContrastRatio :contrast="previewContrast.btnText" />
+            <ColorInput
+              v-model="btnPanelTextColorLocal"
+              name="btnPanelTextColor"
+              :fallback="previewTheme.colors.btnPanelText"
+              :label="$t('settings.style.advanced_colors.panel_header')"
+            />
+            <ContrastRatio :contrast="previewContrast.btnPanelText" />
+            <ColorInput
+              v-model="btnTopBarTextColorLocal"
+              name="btnTopBarTextColor"
+              :fallback="previewTheme.colors.btnTopBarText"
+              :label="$t('settings.style.advanced_colors.top_bar')"
+            />
+            <ContrastRatio :contrast="previewContrast.btnTopBarText" />
             <h4>{{ $t('settings.style.advanced_colors.pressed') }}</h4>
             <ColorInput
               v-model="btnPressedColorLocal"
@@ -444,6 +458,20 @@
               :label="$t('settings.text')"
             />
             <ContrastRatio :contrast="previewContrast.btnPressedText" />
+            <ColorInput
+              v-model="btnPressedPanelTextColorLocal"
+              name="btnPressedPanelTextColor"
+              :fallback="previewTheme.colors.btnPressedPanelText"
+              :label="$t('settings.style.advanced_colors.panel_header')"
+            />
+            <ContrastRatio :contrast="previewContrast.btnPressedPanelText" />
+            <ColorInput
+              v-model="btnPressedTopBarTextColorLocal"
+              name="btnPressedTopBarTextColor"
+              :fallback="previewTheme.colors.btnPressedTopBarText"
+              :label="$t('settings.style.advanced_colors.top_bar')"
+            />
+            <ContrastRatio :contrast="previewContrast.btnPressedTopBarText" />
             <h4>{{ $t('settings.style.advanced_colors.disabled') }}</h4>
             <ColorInput
               v-model="btnDisabledColorLocal"
@@ -458,6 +486,20 @@
               :label="$t('settings.text')"
             />
             <ContrastRatio :contrast="previewContrast.btnDisabledText" />
+            <ColorInput
+              v-model="btnDisabledPanelTextColorLocal"
+              name="btnDisabledPanelTextColor"
+              :fallback="previewTheme.colors.btnDisabledPanelText"
+              :label="$t('settings.style.advanced_colors.panel_header')"
+            />
+            <ContrastRatio :contrast="previewContrast.btnDisabledPanelText" />
+            <ColorInput
+              v-model="btnDisabledTopBarTextColorLocal"
+              name="btnDisabledTopBarTextColor"
+              :fallback="previewTheme.colors.btnDisabledTopBarText"
+              :label="$t('settings.style.advanced_colors.top_bar')"
+            />
+            <ContrastRatio :contrast="previewContrast.btnDisabledTopBarText" />
             <h4>{{ $t('settings.style.advanced_colors.toggled') }}</h4>
             <ColorInput
               v-model="btnToggledColorLocal"
@@ -471,6 +513,21 @@
               :fallback="previewTheme.colors.btnToggledText"
               :label="$t('settings.text')"
             />
+            <ContrastRatio :contrast="previewContrast.btnToggledText" />
+            <ColorInput
+              v-model="btnToggledPanelTextColorLocal"
+              name="btnToggledPanelTextColor"
+              :fallback="previewTheme.colors.btnToggledPanelText"
+              :label="$t('settings.style.advanced_colors.panel_header')"
+            />
+            <ContrastRatio :contrast="previewContrast.btnToggledPanelText" />
+            <ColorInput
+              v-model="btnToggledTopBarTextColorLocal"
+              name="btnToggledTopBarTextColor"
+              :fallback="previewTheme.colors.btnToggledTopBarText"
+              :label="$t('settings.style.advanced_colors.top_bar')"
+            />
+            <ContrastRatio :contrast="previewContrast.btnToggledTopBarText" />
           </div>
           <div class="color-item">
             <h4>{{ $t('settings.style.advanced_colors.tabs') }}</h4>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 4efa41c3..771805e9 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -472,6 +472,7 @@
         "selectedPost": "Selected post",
         "selectedMenu": "Selected menu item",
         "disabled": "Disabled",
+        "toggled": "Toggled",
         "tabs": "Tabs"
       },
       "radii": {
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 533145d4..b9a23ad7 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -114,10 +114,7 @@ export const generateColors = (themeData) => {
     ? colors2to3(themeData.colors || themeData)
     : themeData.colors || themeData
 
-  const isLightOnDark = convert(sourceColors.bg).hsl.l < convert(sourceColors.text).hsl.l
-  const mod = isLightOnDark ? 1 : -1
-
-  const { colors, opacity } = getColors(sourceColors, themeData.opacity || {}, mod)
+  const { colors, opacity } = getColors(sourceColors, themeData.opacity || {})
 
   const htmlColors = Object.entries(colors)
     .reduce((acc, [k, v]) => {
@@ -381,25 +378,17 @@ export const getThemes = () => {
 }
 export const colors2to3 = (colors) => {
   return Object.entries(colors).reduce((acc, [slotName, color]) => {
-    const btnStates = ['', 'Pressed', 'Disabled', 'Toggled']
     const btnPositions = ['', 'Panel', 'TopBar']
     switch (slotName) {
       case 'lightBg':
         return { ...acc, highlight: color }
-      case 'btn':
-        return {
-          ...acc,
-          ...btnStates.reduce((stateAcc, state) => ({ ...stateAcc, ['btn' + state]: color }), {})
-        }
       case 'btnText':
         return {
           ...acc,
           ...btnPositions
-            .map(position => btnStates.map(state => state + position))
-            .flat()
             .reduce(
-              (statePositionAcc, statePosition) =>
-                ({ ...statePositionAcc, ['btn' + statePosition + 'Text']: color })
+              (statePositionAcc, position) =>
+                ({ ...statePositionAcc, ['btn' + position + 'Text']: color })
               , {}
             )
         }
diff --git a/src/services/theme_data/pleromafe.js b/src/services/theme_data/pleromafe.js
index 354009ee..98fba5ef 100644
--- a/src/services/theme_data/pleromafe.js
+++ b/src/services/theme_data/pleromafe.js
@@ -85,6 +85,8 @@ export const SLOT_INHERITANCE = {
   },
   text: {
     depends: [],
+    layer: 'bg',
+    opacity: null,
     priority: 1
   },
   underlay: {
@@ -422,6 +424,7 @@ export const SLOT_INHERITANCE = {
   // Buttons
   btn: {
     depends: ['fg'],
+    variant: 'btn',
     opacity: 'btn'
   },
   btnText: {
@@ -430,20 +433,23 @@ export const SLOT_INHERITANCE = {
     textColor: true
   },
   btnPanelText: {
-    depends: ['panelText'],
+    depends: ['btnText'],
     layer: 'btnPanel',
     variant: 'btn',
     textColor: true
   },
   btnTopBarText: {
-    depends: ['topBarText'],
+    depends: ['btnText'],
     layer: 'btnTopBar',
     variant: 'btn',
     textColor: true
   },
 
   // Buttons: pressed
-  btnPressed: '--btn',
+  btnPressed: {
+    depends: ['btn'],
+    layer: 'btn'
+  },
   btnPressedText: {
     depends: ['btnText'],
     layer: 'btn',
@@ -451,7 +457,8 @@ export const SLOT_INHERITANCE = {
     textColor: true
   },
   btnPressedPanel: {
-    depends: ['btnPressed']
+    depends: ['btnPressed'],
+    layer: 'btn'
   },
   btnPressedPanelText: {
     depends: ['btnPanelText'],
@@ -469,6 +476,7 @@ export const SLOT_INHERITANCE = {
   // Buttons: toggled
   btnToggled: {
     depends: ['btn'],
+    layer: 'btn',
     color: (mod, btn) => brightness(mod * 20, btn).rgb
   },
   btnToggledText: {
@@ -496,25 +504,22 @@ export const SLOT_INHERITANCE = {
     color: (mod, btn, bg) => alphaBlend(btn, 0.5, bg)
   },
   btnDisabledText: {
-    depends: ['btnText'],
+    depends: ['btnText', 'btnDisabled'],
     layer: 'btn',
     variant: 'btnDisabled',
-    textColor: true,
-    color: (mod, text) => brightness(mod * -60, text).rgb
+    color: (mod, text, btn) => alphaBlend(text, 0.5, btn)
   },
   btnDisabledPanelText: {
-    depends: ['btnPanelText'],
+    depends: ['btnPanelText', 'btnDisabled'],
     layer: 'btnPanel',
     variant: 'btnDisabled',
-    textColor: true,
-    color: (mod, text) => brightness(mod * -60, text).rgb
+    color: (mod, text, btn) => alphaBlend(text, 0.5, btn)
   },
   btnDisabledTopBarText: {
-    depends: ['btnTopBarText'],
+    depends: ['btnTopBarText', 'btnDisabled'],
     layer: 'btnTopBar',
     variant: 'btnDisabled',
-    textColor: true,
-    color: (mod, text) => brightness(mod * -60, text).rgb
+    color: (mod, text, btn) => alphaBlend(text, 0.5, btn)
   },
 
   // Input fields
diff --git a/src/services/theme_data/theme_data.service.js b/src/services/theme_data/theme_data.service.js
index 49b99148..e9ed3781 100644
--- a/src/services/theme_data/theme_data.service.js
+++ b/src/services/theme_data/theme_data.service.js
@@ -255,14 +255,17 @@ export const computeDynamicColor = (sourceColor, getColor, mod) => {
 }
 
 /**
- * THE function you want to use. Takes provided colors and opacities, mod
+ * THE function you want to use. Takes provided colors and opacities
  * value and uses inheritance data to figure out color needed for the slot.
  */
-export const getColors = (sourceColors, sourceOpacity, mod) => SLOT_ORDERED.reduce(({ colors, opacity }, key) => {
+export const getColors = (sourceColors, sourceOpacity) => SLOT_ORDERED.reduce(({ colors, opacity }, key) => {
   const value = SLOT_INHERITANCE[key]
   const isObject = typeof value === 'object'
   const isString = typeof value === 'string'
   const sourceColor = sourceColors[key]
+  const variant = value.variant || value.layer || 'bg'
+  const isLightOnDark = relativeLuminance(colors[variant] || sourceColors[variant]) < 0.5
+  const mod = isLightOnDark ? 1 : -1
   let outputColor = null
   if (sourceColor) {
     // Color is defined in source color
@@ -318,7 +321,7 @@ export const getColors = (sourceColors, sourceOpacity, mod) => SLOT_ORDERED.redu
           opacity
         )
       )
-      const isLightOnDark = relativeLuminance(bg) > 127
+      const isLightOnDark = relativeLuminance(bg) > 0.5
       const mod = isLightOnDark ? 1 : -1
 
       if (value.textColor === 'bw') {
-- 
cgit v1.2.3-70-g09d2


From 43bddc79e0abc35fd310d9a92051bb2d5b529984 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 11 Feb 2020 01:13:59 +0200
Subject: fix/remove contrast ratios

---
 src/components/style_switcher/style_switcher.vue | 6 +-----
 src/services/theme_data/pleromafe.js             | 6 +++++-
 2 files changed, 6 insertions(+), 6 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 705a60a2..205f325c 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -252,9 +252,8 @@
               name="postLinkColor"
               :fallback="previewTheme.colors.accent"
               :label="$t('settings.links')"
-              :show-optional-tickbox="typeof accentColorLocal !== 'undefined'"
             />
-            <ContrastRatio :contrast="previewContrast.bgPostLink" />
+            <ContrastRatio :contrast="previewContrast.postLink" />
             <h4>{{ $t('settings.style.advanced_colors.alert') }}</h4>
             <ColorInput
               v-model="alertErrorColorLocal"
@@ -485,21 +484,18 @@
               :fallback="previewTheme.colors.btnDisabledText"
               :label="$t('settings.text')"
             />
-            <ContrastRatio :contrast="previewContrast.btnDisabledText" />
             <ColorInput
               v-model="btnDisabledPanelTextColorLocal"
               name="btnDisabledPanelTextColor"
               :fallback="previewTheme.colors.btnDisabledPanelText"
               :label="$t('settings.style.advanced_colors.panel_header')"
             />
-            <ContrastRatio :contrast="previewContrast.btnDisabledPanelText" />
             <ColorInput
               v-model="btnDisabledTopBarTextColorLocal"
               name="btnDisabledTopBarTextColor"
               :fallback="previewTheme.colors.btnDisabledTopBarText"
               :label="$t('settings.style.advanced_colors.top_bar')"
             />
-            <ContrastRatio :contrast="previewContrast.btnDisabledTopBarText" />
             <h4>{{ $t('settings.style.advanced_colors.toggled') }}</h4>
             <ColorInput
               v-model="btnToggledColorLocal"
diff --git a/src/services/theme_data/pleromafe.js b/src/services/theme_data/pleromafe.js
index 98fba5ef..9b33e4a9 100644
--- a/src/services/theme_data/pleromafe.js
+++ b/src/services/theme_data/pleromafe.js
@@ -329,11 +329,15 @@ export const SLOT_INHERITANCE = {
 
   lightText: {
     depends: ['text'],
+    layer: 'bg',
+    textColor: 'preserve',
     color: (mod, text) => brightness(20 * mod, text).rgb
   },
 
   postLink: {
-    depends: ['link']
+    depends: ['link'],
+    layer: 'bg',
+    textColor: 'preserve'
   },
 
   border: {
-- 
cgit v1.2.3-70-g09d2


From 171f4c7ddbc2f55136ff57742470ea9752e4da05 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 18 Feb 2020 00:01:48 +0200
Subject: update headers in switcher to better separate the subsections

---
 src/components/style_switcher/style_switcher.vue | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

(limited to 'src/components/style_switcher/style_switcher.vue')

diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 205f325c..62c8e634 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -443,7 +443,7 @@
               :label="$t('settings.style.advanced_colors.top_bar')"
             />
             <ContrastRatio :contrast="previewContrast.btnTopBarText" />
-            <h4>{{ $t('settings.style.advanced_colors.pressed') }}</h4>
+            <h5>{{ $t('settings.style.advanced_colors.pressed') }}</h5>
             <ColorInput
               v-model="btnPressedColorLocal"
               name="btnPressedColor"
@@ -471,7 +471,7 @@
               :label="$t('settings.style.advanced_colors.top_bar')"
             />
             <ContrastRatio :contrast="previewContrast.btnPressedTopBarText" />
-            <h4>{{ $t('settings.style.advanced_colors.disabled') }}</h4>
+            <h5>{{ $t('settings.style.advanced_colors.disabled') }}</h5>
             <ColorInput
               v-model="btnDisabledColorLocal"
               name="btnDisabledColor"
@@ -496,7 +496,7 @@
               :fallback="previewTheme.colors.btnDisabledTopBarText"
               :label="$t('settings.style.advanced_colors.top_bar')"
             />
-            <h4>{{ $t('settings.style.advanced_colors.toggled') }}</h4>
+            <h5>{{ $t('settings.style.advanced_colors.toggled') }}</h5>
             <ColorInput
               v-model="btnToggledColorLocal"
               name="btnToggledColor"
-- 
cgit v1.2.3-70-g09d2

