From a5b4f31c12706b7226915864c01e5508caf262f9 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 19 Nov 2018 04:40:25 +0300
Subject: shadow control initial stuff. not done yet tho

---
 src/components/shadow_control/shadow_control.vue | 249 +++++++++++++++++++++++
 1 file changed, 249 insertions(+)
 create mode 100644 src/components/shadow_control/shadow_control.vue

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

diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
new file mode 100644
index 00000000..24439449
--- /dev/null
+++ b/src/components/shadow_control/shadow_control.vue
@@ -0,0 +1,249 @@
+<template>
+<div class="shadow-control" :class="{ disabled: !present }">
+  <div class="shadow-preview-container">
+    <div :disabled="!present" class="y-shift-control">
+      <input
+        v-model="selected.y"
+        :disabled="!present"
+        class="input-number"
+        type="number">
+      <div class="wrap">
+        <input
+          v-model="selected.y"
+          :disabled="!present"
+          class="input-range"
+          type="range"
+          max="20"
+          min="-20">
+      </div>
+    </div>
+    <div class="preview-window">
+      <div class="preview-block" :style="style"></div>
+    </div>
+    <div :disabled="!present" class="x-shift-control">
+      <input
+        v-model="selected.x"
+        :disabled="!present"
+        class="input-number"
+        type="number">
+      <div class="wrap">
+        <input
+          v-model="selected.x"
+          :disabled="!present"
+          class="input-range"
+          type="range"
+          max="20"
+          min="-20">
+      </div>
+    </div>
+  </div>
+
+  <div class="shadow-tweak">
+    <div :disabled="usingFallback" class="id-control">
+      <label for="id" class="label">
+        Shadow id
+      </label>
+      <input
+        v-model="selectedId"
+        :disabled="usingFallback"
+        class="input-number"
+        type="number"
+        min="0"
+        :max="cValue.length - 1">
+      <button class="btn btn-default" :disabled="!present" @click="del">
+        <i class="icon-cancel"/>
+      </button>
+      <button class="btn btn-default" :disabled="!moveUpValid" @click="moveUp">
+        <i class="icon-up-open"/>
+      </button>
+      <button class="btn btn-default" :disabled="!moveDnValid" @click="moveDn">
+        <i class="icon-down-open"/>
+      </button>
+      <button class="btn btn-default" @click="add">
+        <i class="icon-plus"/>
+      </button>
+    </div>
+    <div :disabled="!present" class="inset-control">
+      <label for="inset" class="label">
+        Inset
+      </label>
+      <input
+        v-model="selected.inset"
+        :disabled="!present"
+        name="inset"
+        id="inset"
+        class="input-inset"
+        type="checkbox">
+      <label class="checkbox-label" for="inset"></label>
+    </div>
+    <div :disabled="!present" class="blur-control">
+      <label for="spread" class="label">
+        Blur
+      </label>
+      <input
+        v-model="selected.blur"
+        :disabled="!present"
+        name="blur"
+        id="blur"
+        class="input-range"
+        type="range"
+        max="20"
+        min="0">
+      <input
+        v-model="selected.blur"
+        :disabled="!present"
+        class="input-number"
+        type="number"
+        min="0">
+    </div>
+    <div :disabled="!present" class="spread-control">
+      <label for="spread" class="label">
+        Spread
+      </label>
+      <input
+        v-model="selected.spread"
+        :disabled="!present"
+        name="spread"
+        id="spread"
+        class="input-range"
+        type="range"
+        max="20"
+        min="-20">
+      <input
+        v-model="selected.spread"
+        :disabled="!present"
+        class="input-number"
+        type="number">
+    </div>
+    <ColorInput
+      v-model="selected.color"
+      :disabled="!present"
+      label="Color"
+      name="shadow"/>
+    <OpacityInput
+      v-model="selected.alpha"
+      :disabled="!present"/>
+  </div>
+</div>
+</template>
+
+<script src="./shadow_control.js" ></script>
+
+<style lang="scss">
+@import '../../_variables.scss';
+.shadow-control {
+  display: flex;
+  flex-wrap: wrap;
+  justify-content: center;
+
+  .shadow-preview-container {
+    flex: 0;
+    display: flex;
+    flex-wrap: wrap;
+
+    $side: 15em;
+
+    input[type=number] {
+      width: 5em;
+      min-width: 2em;
+    }
+    .x-shift-control,
+    .y-shift-control {
+      display: flex;
+      flex: 0;
+
+      &[disabled=disabled] *{
+        opacity: .5
+      }
+
+    }
+
+    .x-shift-control {
+      align-items: flex-start;
+    }
+
+    .x-shift-control .wrap,
+    input[type=range] {
+      margin: 0;
+      width: $side;
+      height: 2em;
+    }
+    .y-shift-control {
+      flex-direction: column;
+      align-items: flex-end;
+      .wrap {
+        width: 2em;
+        height: $side;
+      }
+      input[type=range] {
+        transform-origin: 1em 1em;
+        transform: rotate(90deg);
+      }
+    }
+    .preview-window {
+      flex: 1;
+      background-color: white;
+      display: flex;
+      align-items: center;
+      justify-content: center;
+      background-image:
+      linear-gradient(45deg, #808080 25%, transparent 25%),
+      linear-gradient(-45deg, #808080 25%, transparent 25%),
+      linear-gradient(45deg, transparent 75%, #808080 75%),
+      linear-gradient(-45deg, transparent 75%, #808080 75%);
+      background-size: 20px 20px;
+      background-position:0 0, 0 10px, 10px -10px, -10px 0;
+
+      border-radius: $fallback--inputRadius;
+      border-radius: var(--inputRadius, $fallback--inputRadius);
+
+      .preview-block {
+        width: 33%;
+        height: 33%;
+        background-color: $fallback--bg;
+        background-color: var(--bg, $fallback--bg);
+        border-radius: $fallback--panelRadius;
+        border-radius: var(--panelRadius, $fallback--panelRadius);
+      }
+    }
+  }
+
+  .shadow-tweak {
+    .label {
+      flex: 1;
+      min-width: 3em;
+    }
+
+    .inset-control {
+      justify-content: flex-end;
+      label {
+        flex: 0
+      }
+    }
+
+    .blur-control,
+    .id-control,
+    .inset-control,
+    .spread-control {
+      display: flex;
+      align-items: baseline;
+      max-width: 100%;
+
+      &[disabled=disabled] *{
+        opacity: .5
+      }
+
+      .input-range {
+        flex: 1;
+        align-self: center;
+      }
+
+      .input-number {
+        width: 4em;
+        min-width: 4em;
+        flex: 0;
+      }
+    }
+  }
+}
+</style>
-- 
cgit v1.2.3-70-g09d2


From a8180d03be3488aeb7cfc811a1b49f6519836ab5 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 19 Nov 2018 18:15:27 +0300
Subject: it works, now to clean it up

---
 src/App.scss                                     |   1 +
 src/components/shadow_control/shadow_control.js  |   6 +-
 src/components/shadow_control/shadow_control.vue |  11 +--
 src/components/style_switcher/style_switcher.js  |  38 ++++++--
 src/components/style_switcher/style_switcher.vue | 110 +++++++++++++----------
 src/services/style_setter/style_setter.js        |   3 +-
 6 files changed, 105 insertions(+), 64 deletions(-)

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

diff --git a/src/App.scss b/src/App.scss
index 8fb3c488..19c069ed 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -313,6 +313,7 @@ main-router {
   border-radius: $fallback--panelRadius;
   border-radius: var(--panelRadius, $fallback--panelRadius);
   box-shadow: 1px 1px 4px rgba(0,0,0,.6);
+  box-shadow: var(--panel-shadow);
 }
 
 .panel-body:empty::before {
diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js
index c357581d..a6992999 100644
--- a/src/components/shadow_control/shadow_control.js
+++ b/src/components/shadow_control/shadow_control.js
@@ -9,6 +9,8 @@ export default {
     'value', 'fallback'
   ],
   data () {
+    console.log('sdsa')
+    console.log(this.value, this.fallback)
     return {
       selectedId: 0,
       cValue: this.value || this.fallback
@@ -36,6 +38,9 @@ export default {
       const movable = this.cValue.splice(this.selectedId, 1)[0]
       this.cValue.splice(this.selectedId + 1, 0, movable)
       this.selectedId += 1
+    },
+    update () {
+      this.$emit('input', this.cValue)
     }
   },
   computed: {
@@ -67,7 +72,6 @@ export default {
       return hex2rgb(this.selected.color)
     },
     style () {
-      console.log(StyleSetter.generateShadow(this.cValue))
       return {
         boxShadow: StyleSetter.generateShadow(this.cValue)
       }
diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index 24439449..614de76a 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -5,6 +5,7 @@
       <input
         v-model="selected.y"
         :disabled="!present"
+        @input="update"
         class="input-number"
         type="number">
       <div class="wrap">
@@ -182,15 +183,15 @@
     }
     .preview-window {
       flex: 1;
-      background-color: white;
+      background-color: #999999;
       display: flex;
       align-items: center;
       justify-content: center;
       background-image:
-      linear-gradient(45deg, #808080 25%, transparent 25%),
-      linear-gradient(-45deg, #808080 25%, transparent 25%),
-      linear-gradient(45deg, transparent 75%, #808080 75%),
-      linear-gradient(-45deg, transparent 75%, #808080 75%);
+      linear-gradient(45deg, #666666 25%, transparent 25%),
+      linear-gradient(-45deg, #666666 25%, transparent 25%),
+      linear-gradient(45deg, transparent 75%, #666666 75%),
+      linear-gradient(-45deg, transparent 75%, #666666 75%);
       background-size: 20px 20px;
       background-position:0 0, 0 10px, 10px -10px, -10px 0;
 
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 8e344eb1..b40511df 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -1,4 +1,5 @@
 import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js'
+import { set, delete as del } from 'vue'
 import ColorInput from '../color_input/color_input.vue'
 import ShadowControl from '../shadow_control/shadow_control.vue'
 import ContrastRatio from '../contrast_ratio/contrast_ratio.vue'
@@ -155,7 +156,7 @@ export default {
       }
     },
     previewTheme () {
-      if (!this.preview.theme) return { colors: {}, opacity: {}, radii: {} }
+      if (!this.preview.theme) return { colors: {}, opacity: {}, radii: {}, shadows: {} }
       return this.preview.theme
     },
     previewContrast () {
@@ -231,14 +232,30 @@ export default {
       return [this.preview.colorRules, this.preview.radiiRules, 'color: var(--text)'].join(';')
     },
     shadowsAvailable () {
-      return Object.keys(this.preview.theme.shadows)
+      return Object.keys(this.previewTheme.shadows)
     },
-    currentShadow () {
-      const fallback = this.preview.theme.shadows[this.shadowSelected];
-      return fallback ? {
-        fallback,
-        value: this.shadowsLocal[this.shadowSelected]
-      } : undefined
+    currentShadowOverriden: {
+      get () {
+        return this.currentShadow
+      },
+      set (val) {
+        if (val) {
+          set(this.shadowsLocal, this.shadowSelected, Object.assign({}, this.currentShadowFallback))
+        } else {
+          del(this.shadowsLocal, this.shadowSelected)
+        }
+      }
+    },
+    currentShadowFallback () {
+      return this.previewTheme.shadows[this.shadowSelected]
+    },
+    currentShadow: {
+      get () {
+        return this.shadowsLocal[this.shadowSelected]
+      },
+      set (v) {
+        set(this.shadowsLocal, this.shadowSelected, v)
+      }
     }
   },
   components: {
@@ -305,7 +322,10 @@ export default {
     setCustomTheme () {
       this.$store.dispatch('setOption', {
         name: 'customTheme',
-        value: this.currentTheme
+        value: {
+          ...this.currentTheme,
+          shadows: this.shadowsLocal
+        }
       })
     },
 
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 0352f546..af816a23 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -1,49 +1,49 @@
 <template>
-<div>
-  <div class="presets-container">
-    <div>
-      {{$t('settings.presets')}}
-      <label for="style-switcher" class='select'>
-        <select id="style-switcher" v-model="selected" class="style-switcher">
-          <option v-for="style in availableStyles"
-                  :value="style"
-                  :style="{
-                          backgroundColor: style[1],
-                          color: style[3]
-                          }">
-            {{style[0]}}
-          </option>
-        </select>
-        <i class="icon-down-open"/>
-      </label>
-    </div>
-    <div class="import-export">
-      <button class="btn" @click="exportCurrentTheme">{{ $t('settings.export_theme') }}</button>
-      <button class="btn" @click="importTheme">{{ $t('settings.import_theme') }}</button>
-      <p v-if="invalidThemeImported" class="import-warning">{{ $t('settings.invalid_theme_imported') }}</p>
+  <div>
+    <div class="presets-container">
+      <div>
+        {{$t('settings.presets')}}
+        <label for="style-switcher" class='select'>
+          <select id="style-switcher" v-model="selected" class="style-switcher">
+            <option v-for="style in availableStyles"
+                    :value="style"
+                    :style="{
+                            backgroundColor: style[1],
+                            color: style[3]
+                            }">
+              {{style[0]}}
+            </option>
+          </select>
+          <i class="icon-down-open"/>
+        </label>
+      </div>
+      <div class="import-export">
+        <button class="btn" @click="exportCurrentTheme">{{ $t('settings.export_theme') }}</button>
+        <button class="btn" @click="importTheme">{{ $t('settings.import_theme') }}</button>
+        <p v-if="invalidThemeImported" class="import-warning">{{ $t('settings.invalid_theme_imported') }}</p>
+      </div>
     </div>
-  </div>
 
-  <div class="preview-container">
-    <div class="panel dummy" :style="previewRules">
-      <div class="panel-heading">Preview</div>
-      <div class="panel-body theme-preview-content">
-        <div class="avatar">
-          ( ͡° ͜ʖ ͡°)
+    <div class="preview-container">
+      <div class="panel dummy" :style="previewRules">
+        <div class="panel-heading">Preview</div>
+        <div class="panel-body theme-preview-content">
+          <div class="avatar">
+            ( ͡° ͜ʖ ͡°)
+          </div>
+          <h4>Content</h4>
+          <br>
+          A bunch of more content and
+          <a style="color: var(--link)">a nice lil' link</a>
+          <i style="color: var(--cBlue)" class="icon-reply"/>
+          <i style="color: var(--cGreen)" class="icon-retweet"/>
+          <i style="color: var(--cRed)" class="icon-cancel"/>
+          <i style="color: var(--cOrange)" class="icon-star"/>
+          <br>
+          <button class="btn">Button</button>
         </div>
-        <h4>Content</h4>
-        <br>
-        A bunch of more content and
-        <a style="color: var(--link)">a nice lil' link</a>
-        <i style="color: var(--cBlue)" class="icon-reply"/>
-        <i style="color: var(--cGreen)" class="icon-retweet"/>
-        <i style="color: var(--cRed)" class="icon-cancel"/>
-        <i style="color: var(--cOrange)" class="icon-star"/>
-        <br>
-        <button class="btn">Button</button>
       </div>
     </div>
-  </div>
 
     <p>{{$t('settings.theme_help')}}</p>
     <tab-switcher>
@@ -171,15 +171,29 @@
         </div>
       </div>
       <div label="Shadow Realm" class="shadow-container">
-        <div class="shadow-selector">
-          <select id="style-switcher" v-model="shadowSelected" class="style-switcher">
-            <option v-for="shadow in shadowsAvailable"
-                    :value="shadow">
-              {{shadow}}
-            </option>
-          </select>
+        <div>
+          Shadow
+          <label for="shadow-switcher" class="shadow-selector select">
+            <select id="shadow-switcher" v-model="shadowSelected" class="shadow-switcher">
+              <option v-for="shadow in shadowsAvailable"
+                      :value="shadow">
+                {{shadow}}
+              </option>
+            </select>
+            <i class="icon-down-open"/>
+          </label>
+          <label for="override" class="label">
+            Override
+          </label>
+          <input
+            v-model="currentShadowOverriden"
+            name="override"
+            id="override"
+            class="input-override"
+            type="checkbox">
+          <label class="checkbox-label" for="override"></label>
         </div>
-        <shadow-control v-if="currentShadow" :value="currentShadow.value" :fallback="currentShadow.fallback"/>
+        <shadow-control v-if="currentShadowFallback" :fallback="currentShadowFallback" v-model="currentShadow"/>
       </div>
     </tab-switcher>
 
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 3840e215..aac04055 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -72,7 +72,7 @@ const getTextColor = function (bg, text, preserve) {
 }
 
 const setColors = (input, commit) => {
-  const { colorRules, radiiRules, theme } = generatePreset(input)
+  const { colorRules, radiiRules, shadowRules, theme } = generatePreset(input)
   const head = document.head
   const body = document.body
   body.style.display = 'none'
@@ -84,6 +84,7 @@ const setColors = (input, commit) => {
   styleSheet.toString()
   styleSheet.insertRule(`body { ${colorRules} }`, 'index-max')
   styleSheet.insertRule(`body { ${radiiRules} }`, 'index-max')
+  styleSheet.insertRule(`body { ${shadowRules} }`, 'index-max')
   body.style.display = 'initial'
 
   // commit('setOption', { name: 'colors', value: htmlColors })
-- 
cgit v1.2.3-70-g09d2


From 56fec664a9bb5c1539423e396c127c4a45e8f4e9 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Mon, 19 Nov 2018 20:22:46 +0300
Subject: cleanup and optimization

---
 src/App.scss                                     |   2 +-
 src/components/shadow_control/shadow_control.js  |  10 +-
 src/components/shadow_control/shadow_control.vue |   1 -
 src/components/style_switcher/style_switcher.js  | 220 +++++++++++------------
 src/modules/config.js                            |   6 +-
 src/modules/instance.js                          |   4 +-
 src/services/style_setter/style_setter.js        | 144 +++++++++++----
 7 files changed, 224 insertions(+), 163 deletions(-)

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

diff --git a/src/App.scss b/src/App.scss
index 19c069ed..1021b64b 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -313,7 +313,7 @@ main-router {
   border-radius: $fallback--panelRadius;
   border-radius: var(--panelRadius, $fallback--panelRadius);
   box-shadow: 1px 1px 4px rgba(0,0,0,.6);
-  box-shadow: var(--panel-shadow);
+  box-shadow: var(--panelShadow);
 }
 
 .panel-body:empty::before {
diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js
index a6992999..54813685 100644
--- a/src/components/shadow_control/shadow_control.js
+++ b/src/components/shadow_control/shadow_control.js
@@ -1,16 +1,13 @@
 import ColorInput from '../color_input/color_input.vue'
 import OpacityInput from '../opacity_input/opacity_input.vue'
-import StyleSetter from '../../services/style_setter/style_setter.js'
+import { getCssShadow } from '../../services/style_setter/style_setter.js'
 import { hex2rgb } from '../../services/color_convert/color_convert.js'
-import { set } from 'vue'
 
 export default {
   props: [
     'value', 'fallback'
   ],
   data () {
-    console.log('sdsa')
-    console.log(this.value, this.fallback)
     return {
       selectedId: 0,
       cValue: this.value || this.fallback
@@ -38,9 +35,6 @@ export default {
       const movable = this.cValue.splice(this.selectedId, 1)[0]
       this.cValue.splice(this.selectedId + 1, 0, movable)
       this.selectedId += 1
-    },
-    update () {
-      this.$emit('input', this.cValue)
     }
   },
   computed: {
@@ -73,7 +67,7 @@ export default {
     },
     style () {
       return {
-        boxShadow: StyleSetter.generateShadow(this.cValue)
+        boxShadow: getCssShadow(this.cValue)
       }
     }
   }
diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index 614de76a..6847278c 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -5,7 +5,6 @@
       <input
         v-model="selected.y"
         :disabled="!present"
-        @input="update"
         class="input-number"
         type="number">
       <div class="wrap">
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index b40511df..e523cd7b 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -1,12 +1,23 @@
 import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js'
 import { set, delete as del } from 'vue'
+import { generateColors, generateShadows, generateRadii, composePreset } from '../../services/style_setter/style_setter.js'
 import ColorInput from '../color_input/color_input.vue'
 import ShadowControl from '../shadow_control/shadow_control.vue'
 import ContrastRatio from '../contrast_ratio/contrast_ratio.vue'
 import OpacityInput from '../opacity_input/opacity_input.vue'
-import StyleSetter from '../../services/style_setter/style_setter.js'
 import TabSwitcher from '../tab_switcher/tab_switcher.jsx'
 
+const v1OnlyNames = [
+  'bg',
+  'fg',
+  'text',
+  'link',
+  'cRed',
+  'cGreen',
+  'cBlue',
+  'cOrange'
+].map(_ => _ + 'ColorLocal')
+
 export default {
   data () {
     return {
@@ -53,14 +64,14 @@ export default {
       faintOpacityLocal: undefined,
       faintLinkColorLocal: undefined,
 
-      shadowSelected: undefined,
-      shadowsLocal: {},
-
       cRedColorLocal: '',
       cBlueColorLocal: '',
       cGreenColorLocal: '',
       cOrangeColorLocal: '',
 
+      shadowSelected: undefined,
+      shadowsLocal: {},
+
       btnRadiusLocal: '',
       inputRadiusLocal: '',
       panelRadiusLocal: '',
@@ -86,81 +97,90 @@ export default {
     selectedVersion () {
       return Array.isArray(this.selected) ? 1 : 2
     },
-    currentTheme () {
+    currentColors () {
       return {
-        colors: {
-          bg: this.bgColorLocal,
-          text: this.textColorLocal,
-          link: this.linkColorLocal,
-
-          fg: this.fgColorLocal,
-          fgText: this.fgTextColorLocal,
-          fgLink: this.fgLinkColorLocal,
-
-          panel: this.panelColorLocal,
-          panelText: this.panelTextColorLocal,
-          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,
-          badgeNotification: this.badgeNotificationColorLocal,
-
-          faint: this.faintColorLocal,
-          faintLink: this.faintLinkColorLocal,
-          border: this.borderColorLocal,
-
-          cRed: this.cRedColorLocal,
-          cBlue: this.cBlueColorLocal,
-          cGreen: this.cGreenColorLocal,
-          cOrange: this.cOrangeColorLocal
-        },
-        opacity: {
-          bg: this.bgOpacityLocal,
-          btn: this.btnOpacityLocal,
-          input: this.inputOpacityLocal,
-          panel: this.panelOpacityLocal,
-          topBar: this.topBarOpacityLocal,
-          border: this.borderOpacityLocal,
-          faint: this.faintOpacityLocal
-        },
-        radii: {
-          btnRadius: this.btnRadiusLocal,
-          inputRadius: this.inputRadiusLocal,
-          panelRadius: this.panelRadiusLocal,
-          avatarRadius: this.avatarRadiusLocal,
-          avatarAltRadius: this.avatarAltRadiusLocal,
-          tooltipRadius: this.tooltipRadiusLocal,
-          attachmentRadius: this.attachmentRadiusLocal
-        }
+        bg: this.bgColorLocal,
+        text: this.textColorLocal,
+        link: this.linkColorLocal,
+
+        fg: this.fgColorLocal,
+        fgText: this.fgTextColorLocal,
+        fgLink: this.fgLinkColorLocal,
+
+        panel: this.panelColorLocal,
+        panelText: this.panelTextColorLocal,
+        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,
+        badgeNotification: this.badgeNotificationColorLocal,
+
+        faint: this.faintColorLocal,
+        faintLink: this.faintLinkColorLocal,
+        border: this.borderColorLocal,
+
+        cRed: this.cRedColorLocal,
+        cBlue: this.cBlueColorLocal,
+        cGreen: this.cGreenColorLocal,
+        cOrange: this.cOrangeColorLocal
       }
     },
-    preview () {
-      try {
-        if (!this.currentTheme.colors.bg) {
-          return {}
-        }
-        return StyleSetter.generatePreset(this.currentTheme)
-      } catch (e) {
-        console.error('CATCH')
-        console.error(e)
+    currentOpacity () {
+      return {
+        bg: this.bgOpacityLocal,
+        btn: this.btnOpacityLocal,
+        input: this.inputOpacityLocal,
+        panel: this.panelOpacityLocal,
+        topBar: this.topBarOpacityLocal,
+        border: this.borderOpacityLocal,
+        faint: this.faintOpacityLocal
+      }
+    },
+    currentRadii () {
+      return {
+        btn: this.btnRadiusLocal,
+        input: this.inputRadiusLocal,
+        panel: this.panelRadiusLocal,
+        avatar: this.avatarRadiusLocal,
+        avatarAlt: this.avatarAltRadiusLocal,
+        tooltip: this.tooltipRadiusLocal,
+        attachment: this.attachmentRadiusLocal
+      }
+    },
+    previewColors () {
+      if (this.currentColors.bg) {
+        return generateColors({
+          opacity: this.currentOpacity,
+          colors: this.currentColors
+        })
+      } else {
         return {}
       }
     },
+    previewRadii () {
+      return generateRadii(this.currentRadii)
+    },
+    previewShadows () {
+      return generateShadows({ shadows: this.shadowsLocal })
+    },
+    preview () {
+      return composePreset(this.previewColors, this.previewRadii, this.previewShadows)
+    },
     previewTheme () {
-      if (!this.preview.theme) return { colors: {}, opacity: {}, radii: {}, shadows: {} }
+      if (!this.preview.theme.colors) return { colors: {}, opacity: {}, radii: {}, shadows: {} }
       return this.preview.theme
     },
     previewContrast () {
-      if (!this.previewTheme.colors) return {}
+      if (!this.previewTheme.colors.bg) return {}
       const colors = this.previewTheme.colors
       const opacity = this.previewTheme.opacity
       if (!colors.bg) return {}
@@ -228,19 +248,19 @@ export default {
       return Object.entries(ratios).reduce((acc, [k, v]) => { acc[k] = hints(v); return acc }, {})
     },
     previewRules () {
-      if (!this.preview.colorRules) return ''
-      return [this.preview.colorRules, this.preview.radiiRules, 'color: var(--text)'].join(';')
+      if (!this.preview.rules) return ''
+      return [...Object.values(this.preview.rules), 'color: var(--text)'].join(';')
     },
     shadowsAvailable () {
       return Object.keys(this.previewTheme.shadows)
     },
     currentShadowOverriden: {
       get () {
-        return this.currentShadow
+        return !!this.currentShadow
       },
       set (val) {
         if (val) {
-          set(this.shadowsLocal, this.shadowSelected, Object.assign({}, this.currentShadowFallback))
+          set(this.shadowsLocal, this.shadowSelected, this.currentShadowFallback.map(_ => Object.assign({}, _)))
         } else {
           del(this.shadowsLocal, this.shadowSelected)
         }
@@ -270,7 +290,12 @@ export default {
       const stringified = JSON.stringify({
         // To separate from other random JSON files and possible future theme formats
         _pleroma_theme_version: 2,
-        theme: this.currentTheme
+        theme: {
+          shadows: this.shadowsLocal,
+          opacity: this.currentOpacity,
+          colors: this.currentColors,
+          radii: this.currentRadii
+        }
       }, null, 2) // Pretty-print and indent with 2 spaces
 
       // Create an invisible link with a data url and simulate a click
@@ -323,47 +348,22 @@ export default {
       this.$store.dispatch('setOption', {
         name: 'customTheme',
         value: {
-          ...this.currentTheme,
-          shadows: this.shadowsLocal
+          shadows: this.shadowsLocal,
+          opacity: this.currentOpacity,
+          colors: this.currentColors,
+          radii: this.currentRadii
         }
       })
     },
 
+    // Clears all the extra stuff when loading V1 theme
     clearV1 () {
-      this.bgOpacityLocal = undefined
-      this.fgOpacityLocal = undefined
-
-      this.fgTextColorLocal = undefined
-      this.fgLinkColorLocal = undefined
-
-      this.btnColorLocal = undefined
-      this.btnTextColorLocal = undefined
-      this.btnOpacityLocal = undefined
-
-      this.inputColorLocal = undefined
-      this.inputTextColorLocal = undefined
-      this.inputOpacityLocal = undefined
-
-      this.panelColorLocal = undefined
-      this.panelTextColorLocal = undefined
-      this.panelFaintColorLocal = undefined
-      this.panelOpacityLocal = undefined
-
-      this.topBarColorLocal = undefined
-      this.topBarTextColorLocal = undefined
-      this.topBarLinkColorLocal = undefined
-      this.topBarOpacityLocal = undefined
-
-      this.borderColorLocal = undefined
-      this.borderOpacityLocal = undefined
-
-      this.faintColorLocal = undefined
-      this.faintOpacityLocal = undefined
-      this.faintLinkColorLocal = undefined
-
-      this.alertErrorColorLocal = undefined
-
-      this.badgeNotificationColorLocal = undefined
+      Object.keys(this.$data)
+        .filter(_ => _.endsWith('ColorLocal') || _.endsWith('OpacityLocal'))
+        .filter(_ => !v1OnlyNames.includes(_))
+        .forEach(key => {
+          set(this.$data, key, undefined)
+        })
     },
 
     /**
diff --git a/src/modules/config.js b/src/modules/config.js
index 375d0167..96f2fd5e 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -1,5 +1,5 @@
 import { set, delete as del } from 'vue'
-import StyleSetter from '../services/style_setter/style_setter.js'
+import { setPreset, setColors } from '../services/style_setter/style_setter.js'
 
 const browserLocale = (window.navigator.language || 'en').split('-')[0]
 
@@ -51,10 +51,10 @@ const config = {
       commit('setOption', {name, value})
       switch (name) {
         case 'theme':
-          StyleSetter.setPreset(value, commit)
+          setPreset(value, commit)
           break
         case 'customTheme':
-          StyleSetter.setColors(value, commit)
+          setColors(value, commit)
       }
     }
   }
diff --git a/src/modules/instance.js b/src/modules/instance.js
index cb724821..611212c3 100644
--- a/src/modules/instance.js
+++ b/src/modules/instance.js
@@ -1,5 +1,5 @@
 import { set } from 'vue'
-import StyleSetter from '../services/style_setter/style_setter.js'
+import { setPreset } from '../services/style_setter/style_setter.js'
 
 const defaultState = {
   // Stuff from static/config.json and apiConfig
@@ -54,7 +54,7 @@ const instance = {
           dispatch('setPageTitle')
           break
         case 'theme':
-          StyleSetter.setPreset(value, commit)
+          setPreset(value, commit)
       }
     }
   }
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index aac04055..cfff51ea 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -72,7 +72,7 @@ const getTextColor = function (bg, text, preserve) {
 }
 
 const setColors = (input, commit) => {
-  const { colorRules, radiiRules, shadowRules, theme } = generatePreset(input)
+  const { rules, theme } = generatePreset(input)
   const head = document.head
   const body = document.body
   body.style.display = 'none'
@@ -81,10 +81,11 @@ const setColors = (input, commit) => {
   head.appendChild(styleEl)
   const styleSheet = styleEl.sheet
 
+  console.log(rules)
   styleSheet.toString()
-  styleSheet.insertRule(`body { ${colorRules} }`, 'index-max')
-  styleSheet.insertRule(`body { ${radiiRules} }`, 'index-max')
-  styleSheet.insertRule(`body { ${shadowRules} }`, 'index-max')
+  styleSheet.insertRule(`body { ${rules.radii} }`, 'index-max')
+  styleSheet.insertRule(`body { ${rules.colors} }`, 'index-max')
+  styleSheet.insertRule(`body { ${rules.shadows} }`, 'index-max')
   body.style.display = 'initial'
 
   // commit('setOption', { name: 'colors', value: htmlColors })
@@ -93,7 +94,8 @@ const setColors = (input, commit) => {
   commit('setOption', { name: 'colors', value: theme.colors })
 }
 
-const generateShadow = (input) => {
+const getCssShadow = (input) => {
+  console.log(input)
   // >shad
   return input.map((shad) => [
     shad.x,
@@ -106,27 +108,8 @@ const generateShadow = (input) => {
   ]).join(' ')).join(', ')
 }
 
-const generatePreset = (input) => {
-  const radii = input.radii || {
-    btnRadius: input.btnRadius,
-    inputRadius: input.inputRadius,
-    panelRadius: input.panelRadius,
-    avatarRadius: input.avatarRadius,
-    avatarAltRadius: input.avatarAltRadius,
-    tooltipRadius: input.tooltipRadius,
-    attachmentRadius: input.attachmentRadius
-  }
-  const shadows = {
-    panel: [{
-      x: 1,
-      y: 1,
-      blur: 4,
-      spread: 0,
-      color: '#000000',
-      alpha: 0.6
-    }],
-    ...(input.shadows || {})
-  }
+const generateColors = (input) => {
+  console.log(input.opacity)
   const colors = {}
   const opacity = Object.assign({
     alert: 0.5,
@@ -138,7 +121,7 @@ const generatePreset = (input) => {
     }
     return acc
   }, {}))
-
+  console.log(colors, opacity)
   const col = Object.entries(input.colors || input).reduce((acc, [k, v]) => {
     if (typeof v === 'object') {
       acc[k] = v
@@ -205,7 +188,11 @@ const generatePreset = (input) => {
       colors[k + 'Link'].a = v
       colors['panelFaint'].a = v
     }
-    colors[k].a = v
+    if (colors[k]) {
+      colors[k].a = v
+    } else {
+      console.error('Wrong key ' + k)
+    }
   })
 
   const htmlColors = Object.entries(colors)
@@ -215,20 +202,99 @@ const generatePreset = (input) => {
           acc.complete[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgb2rgba(v)
           return acc
         }, { complete: {}, solid: {} })
-
   return {
-    colorRules: Object.entries(htmlColors.complete).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}`).join(';'),
-    radiiRules: Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}px`).join(';'),
-    shadowRules: Object.entries(shadows).filter(([k, v]) => v).map(([k, v]) => `--${k}-shadow: ${generateShadow(v)}`).join(';'),
+    rules: {
+      colors: Object.entries(htmlColors.complete)
+        .filter(([k, v]) => v)
+        .map(([k, v]) => `--${k}: ${v}`)
+        .join(';')
+    },
     theme: {
       colors: htmlColors.solid,
-      shadows,
-      opacity,
+      opacity
+    }
+  }
+}
+
+const generateRadii = (input) => {
+  const inputRadii = input.radii || {
+    btn: input.btnRadius,
+    input: input.inputRadius,
+    panel: input.panelRadius,
+    avatar: input.avatarRadius,
+    avatarAlt: input.avatarAltRadius,
+    tooltip: input.tooltipRadius,
+    attachment: input.attachmentRadius
+  }
+
+  const radii = {
+    btn: 4,
+    input: 4,
+    panel: 10,
+    avatar: 5,
+    avatarAlt: 50,
+    tooltip: 2,
+    attachment: 5,
+    ...inputRadii
+  }
+
+  return {
+    rules: {
+      radii: Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}Radius: ${v}px`).join(';')
+    },
+    theme: {
       radii
     }
   }
 }
 
+const generateShadows = (input) => {
+  const shadows = {
+    panel: [{
+      x: 1,
+      y: 1,
+      blur: 4,
+      spread: 0,
+      color: '#000000',
+      alpha: 0.6
+    }],
+    ...(input.shadows || {})
+  }
+  console.log('benis')
+
+  return {
+    rules: {
+      shadows: Object.entries(shadows).filter(([k, v]) => v).map(([k, v]) => `--${k}Shadow: ${getCssShadow(v)}`).join(';')
+    },
+    theme: {
+      shadows
+    }
+  }
+}
+
+const composePreset = (colors, radii, shadows) => {
+  return {
+    rules: {
+      ...shadows.rules,
+      ...colors.rules,
+      ...radii.rules
+    },
+    theme: {
+      ...shadows.theme,
+      ...colors.theme,
+      ...radii.theme
+    }
+  }
+}
+
+const generatePreset = (input) => {
+  const shadows = generateShadows(input)
+  const colors = generateColors(input)
+  const radii = generateRadii(input)
+
+  return composePreset(colors, radii, shadows)
+}
+
 const setPreset = (val, commit) => {
   window.fetch('/static/styles.json')
     .then((data) => data.json())
@@ -267,13 +333,15 @@ const setPreset = (val, commit) => {
     })
 }
 
-const StyleSetter = {
+export {
   setStyle,
   setPreset,
   setColors,
   getTextColor,
+  generateColors,
+  generateRadii,
+  generateShadows,
   generatePreset,
-  generateShadow
+  composePreset,
+  getCssShadow
 }
-
-export default StyleSetter
-- 
cgit v1.2.3-70-g09d2


From 32132e225c749e506285370a2a065bb71920ce59 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 20 Nov 2018 20:58:20 +0300
Subject: localization and small fixes

---
 src/components/color_input/color_input.vue       | 17 ++++-----
 src/components/opacity_input/opacity_input.vue   | 17 ++++-----
 src/components/shadow_control/shadow_control.vue | 27 +++++++-------
 src/components/style_switcher/style_switcher.js  |  1 +
 src/components/style_switcher/style_switcher.vue | 44 +++++++++++-----------
 src/i18n/en.json                                 | 47 +++++++++++++++++++++++-
 6 files changed, 99 insertions(+), 54 deletions(-)

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

diff --git a/src/components/color_input/color_input.vue b/src/components/color_input/color_input.vue
index ea9fb3c4..b756d265 100644
--- a/src/components/color_input/color_input.vue
+++ b/src/components/color_input/color_input.vue
@@ -1,17 +1,16 @@
 <template>
-<div class="color-control" :class="{ disabled: !present || disabled }">
+<div class="color-control style-control" :class="{ disabled: !present || disabled }">
   <label :for="name" class="label">
     {{label}}
   </label>
   <input
-  v-if="typeof fallback !== 'undefined'"
-  class="opt"
-  :id="name + '-o'"
-      type="checkbox"
-  :checked="present"
-           @input="$emit('input', typeof value === 'undefined' ? fallback : undefined)"
-           >
-           <label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label>
+    v-if="typeof fallback !== 'undefined'"
+    class="opt"
+    :id="name + '-o'"
+    type="checkbox"
+    :checked="present"
+    @input="$emit('input', typeof value === 'undefined' ? fallback : undefined)">
+  <label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label>
   <input
     :id="name"
     class="color-input"
diff --git a/src/components/opacity_input/opacity_input.vue b/src/components/opacity_input/opacity_input.vue
index 91c4f5e9..e0567ec7 100644
--- a/src/components/opacity_input/opacity_input.vue
+++ b/src/components/opacity_input/opacity_input.vue
@@ -1,16 +1,15 @@
 <template>
-<div class="opacity-control" :class="{ disabled: !present || disabled }">
+<div class="opacity-control style-control" :class="{ disabled: !present || disabled }">
   <label :for="name" class="label">
-    {{$t('settings.opacity')}}
+    {{$t('settings.style.common.opacity')}}
   </label>
   <input
-  v-if="typeof fallback !== 'undefined'"
-  class="opt"
-  :id="name + '-o'"
-      type="checkbox"
-  :checked="present"
-           @input="$emit('input', !present ? fallback : undefined)"
-           >
+    v-if="typeof fallback !== 'undefined'"
+    class="opt"
+    :id="name + '-o'"
+    type="checkbox"
+    :checked="present"
+    @input="$emit('input', !present ? fallback : undefined)">
   <label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label>
   <input
     :id="name"
diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index 6847278c..b99df35a 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -40,16 +40,17 @@
 
   <div class="shadow-tweak">
     <div :disabled="usingFallback" class="id-control">
-      <label for="id" class="label">
-        Shadow id
+      <label for="shadow-switcher" class="select">
+        <select
+          v-model="selectedId" class="shadow-switcher"
+          :disabled="usingFallback"
+          id="shadow-switcher">
+          <option v-for="(shadow, index) in cValue" :value="index">
+            {{$t('settings.style.shadows.shadow_id', { value: index })}}
+          </option>
+        </select>
+        <i class="icon-down-open"/>
       </label>
-      <input
-        v-model="selectedId"
-        :disabled="usingFallback"
-        class="input-number"
-        type="number"
-        min="0"
-        :max="cValue.length - 1">
       <button class="btn btn-default" :disabled="!present" @click="del">
         <i class="icon-cancel"/>
       </button>
@@ -65,7 +66,7 @@
     </div>
     <div :disabled="!present" class="inset-control">
       <label for="inset" class="label">
-        Inset
+        {{$t('settings.style.shadows.inset')}}
       </label>
       <input
         v-model="selected.inset"
@@ -78,7 +79,7 @@
     </div>
     <div :disabled="!present" class="blur-control">
       <label for="spread" class="label">
-        Blur
+        {{$t('settings.style.shadows.blur')}}
       </label>
       <input
         v-model="selected.blur"
@@ -98,7 +99,7 @@
     </div>
     <div :disabled="!present" class="spread-control">
       <label for="spread" class="label">
-        Spread
+        {{$t('settings.style.shadows.spread')}}
       </label>
       <input
         v-model="selected.spread"
@@ -118,7 +119,7 @@
     <ColorInput
       v-model="selected.color"
       :disabled="!present"
-      label="Color"
+      :label="$t('settings.style.common.color')"
       name="shadow"/>
     <OpacityInput
       v-model="selected.alpha"
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index e523cd7b..7cb6197c 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -7,6 +7,7 @@ import ContrastRatio from '../contrast_ratio/contrast_ratio.vue'
 import OpacityInput from '../opacity_input/opacity_input.vue'
 import TabSwitcher from '../tab_switcher/tab_switcher.jsx'
 
+// List of color values used in v1
 const v1OnlyNames = [
   'bg',
   'fg',
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index af816a23..fd5d830a 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -47,9 +47,9 @@
 
     <p>{{$t('settings.theme_help')}}</p>
     <tab-switcher>
-      <div label="Basic" class="color-container">
+      <div :label="$t('settings.style.basic_colors._tab_label')" class="color-container">
         <div class="color-item">
-          <h4>Main colors</h4>
+          <h4>{{ $t('settings.style.basic_colors.main') }}</h4>
           <ColorInput name="bgColor" v-model="bgColorLocal" :label="$t('settings.background')"/>
           <OpacityInput name="bgOpacity" v-model="bgOpacityLocal" :fallback="previewTheme.opacity.bg || 1"/>
           <ColorInput name="textColor" v-model="textColorLocal" :label="$t('settings.text')"/>
@@ -58,14 +58,14 @@
           <ContrastRatio :contrast="previewContrast.bgLink"/>
         </div>
         <div class="color-item">
-          <h4>Panel header, top bar, buttons, text fields</h4>
+          <h4>{{ $t('settings.style.basic_colors.foreground') }}</h4>
           <ColorInput name="fgColor" v-model="fgColorLocal" :label="$t('settings.foreground')"/>
           <ColorInput name="fgTextColor" v-model="fgTextColorLocal" :label="$t('settings.text')" :fallback="previewTheme.colors.fgText"/>
           <ColorInput name="fgLinkColor" v-model="fgLinkColorLocal" :label="$t('settings.links')" :fallback="previewTheme.colors.fgLink"/>
-          <p>See "Advanced" tab for more detailed control</p>
+          <p>{{ $t('settings.style.basic_colors.foreground_hint') }}</p>
         </div>
         <div class="color-item">
-          <h4>Icons, alerts, etc.</h4>
+          <h4>{{ $t('settings.style.basic_colors.rgbo') }}</h4>
           <ColorInput name="cRedColor" v-model="cRedColorLocal" :label="$t('settings.cRed')"/>
           <ContrastRatio :contrast="previewContrast.bgRed"/>
           <ColorInput name="cBlueColor" v-model="cBlueColorLocal" :label="$t('settings.cBlue')"/>
@@ -80,25 +80,25 @@
         </div>
       </div>
 
-      <div label="Advanced" class="color-container">
+      <div :label="$t('settings.style.advanced_colors._tab_label')" class="color-container">
         <div class="color-item">
-          <h4>Alerts</h4>
-          <ColorInput name="alertError" v-model="alertErrorColorLocal" :label="$t('settings.error')" :fallback="previewTheme.colors.alertError"/>
+          <h4>{{ $t('settings.style.advanced_colors.alert') }}</h4>
+          <ColorInput name="alertError" v-model="alertErrorColorLocal" :label="$t('settings.style.advanced_colors.alert_error')" :fallback="previewTheme.colors.alertError"/>
           <ContrastRatio :contrast="previewContrast.alertError"/>
         </div>
         <div class="color-item">
-          <h4>Badges</h4>
-          <ColorInput name="badgeNotification" v-model="badgeNotificationColorLocal" :label="$t('settings.notification')" :fallback="previewTheme.colors.badgeNotification"/>
+          <h4>{{ $t('settings.style.advanced_colors.badge') }}</h4>
+          <ColorInput name="badgeNotification" v-model="badgeNotificationColorLocal" :label="$t('settings.style.advanced_colors.badge_notification')" :fallback="previewTheme.colors.badgeNotification"/>
         </div>
         <div class="color-item">
-          <h4>Panel header</h4>
+          <h4>{{ $t('settings.style.advanced_colors.panel_header') }}</h4>
           <ColorInput name="panelColor" v-model="panelColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/>
           <OpacityInput name="panelOpacity" v-model="panelOpacityLocal" :fallback="previewTheme.opacity.panel || 1"/>
           <ColorInput name="panelTextColor" v-model="panelTextColorLocal" :fallback="previewTheme.colors.panelText" :label="$t('settings.links')"/>
           <ContrastRatio :contrast="previewContrast.panelText" large="1"/>
         </div>
         <div class="color-item">
-          <h4>Top bar</h4>
+          <h4>{{ $t('settings.style.advanced_colors.top_bar') }}</h4>
           <ColorInput name="topBarColor" v-model="topBarColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/>
           <ColorInput name="topBarTextColor" v-model="topBarTextColorLocal" :fallback="previewTheme.colors.topBarText" :label="$t('settings.text')"/>
           <ContrastRatio :contrast="previewContrast.topBarText"/>
@@ -106,33 +106,33 @@
           <ContrastRatio :contrast="previewContrast.topBarLink"/>
         </div>
         <div class="color-item">
-          <h4>Text fields</h4>
+          <h4>{{ $t('settings.style.advanced_colors.inputs') }}</h4>
           <ColorInput name="inputColor" v-model="inputColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/>
           <OpacityInput name="inputOpacity" v-model="inputOpacityLocal" :fallback="previewTheme.opacity.input || 1"/>
           <ColorInput name="inputTextColor" v-model="inputTextColorLocal" :fallback="previewTheme.colors.inputText" :label="$t('settings.text')"/>
           <ContrastRatio :contrast="previewContrast.inputText"/>
         </div>
         <div class="color-item">
-          <h4>Buttons</h4>
+          <h4>{{ $t('settings.style.advanced_colors.buttons') }}</h4>
           <ColorInput name="btnColor" v-model="btnColorLocal" :fallback="fgColorLocal" :label="$t('settings.background')"/>
           <OpacityInput name="btnOpacity" v-model="btnOpacityLocal" :fallback="previewTheme.opacity.btn || 1"/>
           <ColorInput name="btnTextColor" v-model="btnTextColorLocal" :fallback="previewTheme.colors.btnText" :label="$t('settings.text')"/>
           <ContrastRatio :contrast="previewContrast.btnText"/>
         </div>
         <div class="color-item">
-          <h4>Borders</h4>
+          <h4>{{ $t('settings.style.advanced_colors.borders') }}</h4>
           <ColorInput name="borderColor" v-model="borderColorLocal" :fallback="previewTheme.colors.border" label="Color"/>
           <OpacityInput name="borderOpacity" v-model="borderOpacityLocal" :fallback="previewTheme.opacity.border || 1"/>
         </div>
         <div class="color-item">
-          <h4>Faint text</h4>
+          <h4>{{ $t('settings.style.advanced_colors.faint_text') }}</h4>
           <ColorInput name="faintColor" v-model="faintColorLocal" :fallback="previewTheme.colors.faint || 1" :label="$t('settings.text')"/>
           <ColorInput name="faintLinkColor" v-model="faintLinkColorLocal" :fallback="previewTheme.colors.faintLink" :label="$t('settings.links')"/>
-          <ColorInput name="panelFaintColor" v-model="panelFaintColorLocal" :fallback="previewTheme.colors.panelFaint" :label="$t('settings.panel')"/>
+          <ColorInput name="panelFaintColor" v-model="panelFaintColorLocal" :fallback="previewTheme.colors.panelFaint" :label="$t('settings.style.advanced_colors.panel_header')"/>
           <OpacityInput name="faintOpacity" v-model="faintOpacityLocal" :fallback="previewTheme.opacity.faint || 0.5"/>
         </div>
       </div>
-      <div label="Roundness" class="radius-container">
+      <div :label="$t('settings.style.radii._tab_label')" class="radius-container">
         <p>{{$t('settings.radii_help')}}</p>
         <div class="radius-item">
           <label for="btnradius" class="theme-radius-lb">{{$t('settings.btnRadius')}}</label>
@@ -170,20 +170,20 @@
           <input id="tooltipradius-t" class="theme-radius-in" type="text" v-model="tooltipRadiusLocal">
         </div>
       </div>
-      <div label="Shadow Realm" class="shadow-container">
+      <div :label="$t('settings.style.shadows._tab_label')" class="shadow-container">
         <div>
-          Shadow
+          {{$t('settings.style.shadows.component')}}
           <label for="shadow-switcher" class="shadow-selector select">
             <select id="shadow-switcher" v-model="shadowSelected" class="shadow-switcher">
               <option v-for="shadow in shadowsAvailable"
                       :value="shadow">
-                {{shadow}}
+                {{$t('settings.style.shadows.components.' + shadow)}}
               </option>
             </select>
             <i class="icon-down-open"/>
           </label>
           <label for="override" class="label">
-            Override
+            {{$t('settings.style.shadows.override')}}
           </label>
           <input
             v-model="currentShadowOverriden"
diff --git a/src/i18n/en.json b/src/i18n/en.json
index d825dcc1..04e9977b 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -108,7 +108,6 @@
     "follow_import_error": "Error importing followers",
     "follows_imported": "Follows imported! Processing them will take a while.",
     "foreground": "Foreground",
-    "opacity": "Opacity",
     "general": "General",
     "hide_attachments_in_convo": "Hide attachments in conversations",
     "hide_attachments_in_tl": "Hide attachments in timeline",
@@ -162,6 +161,52 @@
     "values": {
       "false": "no",
       "true": "yes"
+    },
+    "style": {
+      "common": {
+        "color": "Color",
+        "opacity": "Opacity"
+      },
+      "basic_colors": {
+        "_tab_label": "Basic",
+        "main": "Basic colors",
+        "foreground": "Panel header, top bar, buttons, text fields",
+        "foreground_hint": "See \"Advanced\" tab for more detailed control",
+        "rgbo": "Icons, accents, badges"
+      },
+      "advanced_colors": {
+        "_tab_label": "Advanced",
+        "alert": "Alert background",
+        "alert_error": "Error",
+        "badge": "Badge background",
+        "badge_notification": "Notification",
+        "panel_header": "Panel header",
+        "top_bar": "Top bar",
+        "borders": "Borders",
+        "buttons": "Buttons",
+        "inputs": "Input fields",
+        "faint_text": "Faded text"
+      },
+      "radii": {
+        "_tab_label": "Roundness"
+      },
+      "shadows": {
+        "_tab_label": "Shadow and lighting",
+        "component": "Component",
+        "override": "Override",
+        "shadow_id": "Shadow #{value}",
+        "blur": "Blur",
+        "spread": "Spread",
+        "inset": "Inset",
+        "components": {
+          "panel": "Panel",
+          "button": "Button",
+          "button_hover": "Button (hover)",
+          "button_pressed": "Button (pressed)",
+          "button_pressed_hover": "Button (pressed+hover)",
+          "input_box": "Input field"
+        }
+      }
     }
   },
   "timeline": {
-- 
cgit v1.2.3-70-g09d2


From 2609c0d0d279031cba579d60bf94cca81544ec4f Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 20 Nov 2018 22:14:49 +0300
Subject: unification of stylings

---
 src/App.scss                                     |  13 ++
 src/components/color_input/color_input.vue       |  35 +--
 src/components/opacity_input/opacity_input.vue   |  42 +---
 src/components/shadow_control/shadow_control.vue |  52 ++---
 src/components/style_switcher/style_switcher.vue | 274 ++++++-----------------
 5 files changed, 105 insertions(+), 311 deletions(-)

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

diff --git a/src/App.scss b/src/App.scss
index 1021b64b..970a5f74 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -64,6 +64,11 @@ button {
   font-size: 14px;
   font-family: sans-serif;
 
+  i[class*=icon-] {
+    color: $fallback--text;
+    color: var(--btnText, $fallback--text);
+  }
+
   &::-moz-focus-inner {
     border: none;
   }
@@ -145,6 +150,14 @@ input, textarea, .select {
     line-height: 16px;
   }
 
+  &[type=range] {
+    background: none;
+    border: none;
+    margin: 0;
+    box-shadow: none;
+    flex: 1;
+  }
+
   &[type=radio],
   &[type=checkbox] {
     display: none;
diff --git a/src/components/color_input/color_input.vue b/src/components/color_input/color_input.vue
index b756d265..34eec248 100644
--- a/src/components/color_input/color_input.vue
+++ b/src/components/color_input/color_input.vue
@@ -5,7 +5,7 @@
   </label>
   <input
     v-if="typeof fallback !== 'undefined'"
-    class="opt"
+    class="opt exlcude-disabled"
     :id="name + '-o'"
     type="checkbox"
     :checked="present"
@@ -45,40 +45,9 @@ export default {
 
 <style lang="scss">
 .color-control {
-  display: flex;
-  align-items: baseline;
-
-  &.disabled *:not(.opt-l){
-    opacity: .5
-  }
-
-  .label {
-    flex: 2;
-    min-width: 7em;
-  }
-
-  .opt-l {
-    align-self: center;
-    flex: 0;
-    &::before {
-      width: 14px;
-      height: 14px;
-    }
-  }
-
-  .text-input {
+  input.text-input {
     max-width: 7em;
     flex: 1;
   }
-
-  .color-input {
-    flex: 0;
-    padding: 1px;
-    cursor: pointer;
-    height: 29px;
-    min-width: 2em;
-    border: none;
-    align-self: stretch;
-  }
 }
 </style>
diff --git a/src/components/opacity_input/opacity_input.vue b/src/components/opacity_input/opacity_input.vue
index e0567ec7..3926915b 100644
--- a/src/components/opacity_input/opacity_input.vue
+++ b/src/components/opacity_input/opacity_input.vue
@@ -5,7 +5,7 @@
   </label>
   <input
     v-if="typeof fallback !== 'undefined'"
-    class="opt"
+    class="opt exclude-disabled"
     :id="name + '-o'"
     type="checkbox"
     :checked="present"
@@ -36,43 +36,3 @@ export default {
   }
 }
 </script>
-
-<style lang="scss">
-.opacity-control {
-  display: flex;
-  align-items: baseline;
-
-  &.disabled *:not(.opt-l) {
-    opacity: .5
-  }
-
-  .opt-l {
-    align-self: center;
-    &::before {
-      width: 14px;
-      height: 14px;
-    }
-  }
-
-  .label {
-    flex: 2;
-    min-width: 7em;
-  }
-
-  .input-range {
-    background: none;
-    border: none;
-    margin: 0;
-    height: auto;
-    box-shadow: none;
-    min-width: 7em;
-    flex: 1;
-  }
-
-  .input-number {
-    margin: 0;
-    min-width: 4em;
-    flex: 0;
-  }
-}
-</style>
diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index b99df35a..cd774d32 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -39,7 +39,7 @@
   </div>
 
   <div class="shadow-tweak">
-    <div :disabled="usingFallback" class="id-control">
+    <div :disabled="usingFallback" class="id-control style-control">
       <label for="shadow-switcher" class="select">
         <select
           v-model="selectedId" class="shadow-switcher"
@@ -64,7 +64,7 @@
         <i class="icon-plus"/>
       </button>
     </div>
-    <div :disabled="!present" class="inset-control">
+    <div :disabled="!present" class="inset-control style-control">
       <label for="inset" class="label">
         {{$t('settings.style.shadows.inset')}}
       </label>
@@ -77,7 +77,7 @@
         type="checkbox">
       <label class="checkbox-label" for="inset"></label>
     </div>
-    <div :disabled="!present" class="blur-control">
+    <div :disabled="!present" class="blur-control style-control">
       <label for="spread" class="label">
         {{$t('settings.style.shadows.blur')}}
       </label>
@@ -97,7 +97,7 @@
         type="number"
         min="0">
     </div>
-    <div :disabled="!present" class="spread-control">
+    <div :disabled="!present" class="spread-control style-control">
       <label for="spread" class="label">
         {{$t('settings.style.shadows.spread')}}
       </label>
@@ -137,6 +137,11 @@
   flex-wrap: wrap;
   justify-content: center;
 
+
+  .shadow-preview-container,
+  .shadow-tweak {
+    margin: 5px 6px 0 0;
+  }
   .shadow-preview-container {
     flex: 0;
     display: flex;
@@ -210,39 +215,18 @@
   }
 
   .shadow-tweak {
-    .label {
-      flex: 1;
-      min-width: 3em;
-    }
+    flex: 1;
 
-    .inset-control {
-      justify-content: flex-end;
-      label {
-        flex: 0
+    .id-control {
+      align-items: stretch;
+      .select, .btn {
+        margin-right: 5px;
       }
-    }
-
-    .blur-control,
-    .id-control,
-    .inset-control,
-    .spread-control {
-      display: flex;
-      align-items: baseline;
-      max-width: 100%;
-
-      &[disabled=disabled] *{
-        opacity: .5
-      }
-
-      .input-range {
+      .select {
         flex: 1;
-        align-self: center;
-      }
-
-      .input-number {
-        width: 4em;
-        min-width: 4em;
-        flex: 0;
+        select {
+          align-self: initial;
+        }
       }
     }
   }
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index fd5d830a..5f0c2566 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -1,52 +1,53 @@
 <template>
-  <div>
-    <div class="presets-container">
-      <div>
-        {{$t('settings.presets')}}
-        <label for="style-switcher" class='select'>
-          <select id="style-switcher" v-model="selected" class="style-switcher">
-            <option v-for="style in availableStyles"
-                    :value="style"
-                    :style="{
-                            backgroundColor: style[1],
-                            color: style[3]
-                            }">
-              {{style[0]}}
-            </option>
-          </select>
-          <i class="icon-down-open"/>
-        </label>
-      </div>
-      <div class="import-export">
-        <button class="btn" @click="exportCurrentTheme">{{ $t('settings.export_theme') }}</button>
-        <button class="btn" @click="importTheme">{{ $t('settings.import_theme') }}</button>
-        <p v-if="invalidThemeImported" class="import-warning">{{ $t('settings.invalid_theme_imported') }}</p>
-      </div>
+<div class="style-switcher">
+  <div class="presets-container">
+    <div>
+      {{$t('settings.presets')}}
+      <label for="preset-switcher" class='select'>
+        <select id="preset-switcher" v-model="selected" class="preset-switcher">
+          <option v-for="style in availableStyles"
+                  :value="style"
+                  :style="{
+                          backgroundColor: style[1],
+                          color: style[3]
+                          }">
+            {{style[0]}}
+          </option>
+        </select>
+        <i class="icon-down-open"/>
+      </label>
     </div>
+    <div class="import-export">
+      <button class="btn" @click="exportCurrentTheme">{{ $t('settings.export_theme') }}</button>
+      <button class="btn" @click="importTheme">{{ $t('settings.import_theme') }}</button>
+      <p v-if="invalidThemeImported" class="import-warning">{{ $t('settings.invalid_theme_imported') }}</p>
+    </div>
+  </div>
 
-    <div class="preview-container">
-      <div class="panel dummy" :style="previewRules">
-        <div class="panel-heading">Preview</div>
-        <div class="panel-body theme-preview-content">
-          <div class="avatar">
-            ( ͡° ͜ʖ ͡°)
-          </div>
-          <h4>Content</h4>
-          <br>
-          A bunch of more content and
-          <a style="color: var(--link)">a nice lil' link</a>
-          <i style="color: var(--cBlue)" class="icon-reply"/>
-          <i style="color: var(--cGreen)" class="icon-retweet"/>
-          <i style="color: var(--cRed)" class="icon-cancel"/>
-          <i style="color: var(--cOrange)" class="icon-star"/>
-          <br>
-          <button class="btn">Button</button>
-        </div>
+  <div class="preview-container">
+    <div class="panel dummy" :style="previewRules">
+      <div class="panel-heading">Preview</div>
+      <div class="panel-body theme-preview-content">
+        <div class="avatar">
+          ( ͡° ͜ʖ ͡°)
+        </div>
+        <h4>Content</h4>
+        <br>
+        A bunch of more content and
+        <a style="color: var(--link)">a nice lil' link</a>
+        <i style="color: var(--cBlue)" class="icon-reply"/>
+        <i style="color: var(--cGreen)" class="icon-retweet"/>
+        <i style="color: var(--cRed)" class="icon-cancel"/>
+        <i style="color: var(--cOrange)" class="icon-star"/>
+        <br>
+        <button class="btn">Button</button>
       </div>
     </div>
+  </div>
 
-    <p>{{$t('settings.theme_help')}}</p>
-    <tab-switcher>
+  <p>{{$t('settings.theme_help')}}</p>
+  <keep-alive>
+    <tab-switcher key="style-tweak">
       <div :label="$t('settings.style.basic_colors._tab_label')" class="color-container">
         <div class="color-item">
           <h4>{{ $t('settings.style.basic_colors.main') }}</h4>
@@ -171,31 +172,36 @@
         </div>
       </div>
       <div :label="$t('settings.style.shadows._tab_label')" class="shadow-container">
-        <div>
-          {{$t('settings.style.shadows.component')}}
-          <label for="shadow-switcher" class="shadow-selector select">
-            <select id="shadow-switcher" v-model="shadowSelected" class="shadow-switcher">
-              <option v-for="shadow in shadowsAvailable"
-                      :value="shadow">
-                {{$t('settings.style.shadows.components.' + shadow)}}
-              </option>
-            </select>
-            <i class="icon-down-open"/>
-          </label>
-          <label for="override" class="label">
-            {{$t('settings.style.shadows.override')}}
-          </label>
-          <input
-            v-model="currentShadowOverriden"
-            name="override"
-            id="override"
-            class="input-override"
-            type="checkbox">
-          <label class="checkbox-label" for="override"></label>
+        <div class="shadow-selector">
+          <div>
+            {{$t('settings.style.shadows.component')}}
+            <label for="shadow-switcher" class="select">
+              <select id="shadow-switcher" v-model="shadowSelected" class="shadow-switcher">
+                <option v-for="shadow in shadowsAvailable"
+                        :value="shadow">
+                  {{$t('settings.style.shadows.components.' + shadow)}}
+                </option>
+              </select>
+              <i class="icon-down-open"/>
+            </label>
+          </div>
+          <div class="override">
+            <label for="override" class="label">
+              {{$t('settings.style.shadows.override')}}
+            </label>
+            <input
+              v-model="currentShadowOverriden"
+              name="override"
+              id="override"
+              class="input-override"
+              type="checkbox">
+            <label class="checkbox-label" for="override"></label>
+          </div>
         </div>
         <shadow-control v-if="currentShadowFallback" :fallback="currentShadowFallback" v-model="currentShadow"/>
       </div>
     </tab-switcher>
+  </keep-alive>
 
   <div class="apply-container">
     <button class="btn submit" @click="setCustomTheme">{{$t('general.apply')}}</button>
@@ -205,142 +211,4 @@
 
 <script src="./style_switcher.js"></script>
 
-<style lang="scss">
-@import '../../_variables.scss';
-.style-switcher {
-  margin-right: 1em;
-}
-
-.import-warning {
-  color: $fallback--cRed;
-  color: var(--cRed, $fallback--cRed);
-}
-
-.apply-container,
-.radius-container,
-.color-container,
-.presets-container {
-  display: flex;
-
-  p {
-    margin-left: 1em
-  }
-}
-
-.radius-container {
-  flex-direction: column;
-}
-
-.color-container{
-  flex-wrap: wrap;
-  justify-content: space-between;
-}
-
-.presets-container {
-  justify-content: center;
-  .import-export {
-    display: flex;
-
-    .btn {
-      margin-left: .5em;
-    }
-  }
-}
-
-.preview-container {
-  border-top: 1px dashed;
-  border-bottom: 1px dashed;
-  border-color: $fallback--border;
-  border-color: var(--border, $fallback--border);
-  margin: 1em -1em 0;
-  padding: 1em;
-  background: var(--body-background-image);
-  background-size: cover;
-  background-position: 50% 50%;
-
-  .btn {
-    margin-top: 1em;
-    min-height: 30px;
-    width: 10em;
-  }
-}
-
-.apply-container {
-  justify-content: center;
-}
-
-.radius-item,
-.color-item {
-  min-width: 20em;
-  margin: 5px 6px 0 0;
-  display:flex;
-  flex-direction: column;
-  flex: 1 1 0;
-
-  &.wide {
-    min-width: 60%
-  }
-  &:not(.wide):nth-child(2n+1) {
-    margin-right: 7px;
-
-  }
-
-  .color, .opacity {
-    display:flex;
-    align-items: baseline;
-  }
-
-  h4 {
-    margin-top: 1em;
-  }
-}
-
-.radius-item {
-  flex-basis: auto;
-}
-
-.theme-radius-rn,
-.theme-color-cl {
-  border: 0;
-  box-shadow: none;
-  background: transparent;
-  color: var(--faint, $fallback--faint);
-  align-self: stretch;
-}
-
-.theme-color-cl,
-.theme-radius-in,
-.theme-color-in {
-  margin-left: 4px;
-}
-
-.theme-radius-in {
-  min-width: 1em;
-}
-
-.theme-radius-in {
-  max-width: 7em;
-  flex: 1;
-}
-
-.theme-radius-lb{
-  max-width: 50em;
-}
-
-.theme-preview-content {
-  padding: 20px;
-}
-
-.dummy {
-  .avatar {
-    background: linear-gradient(135deg, #b8e1fc 0%,#a9d2f3 10%,#90bae4 25%,#90bcea 37%,#90bff0 50%,#6ba8e5 51%,#a2daf5 83%,#bdf3fd 100%);
-    color: black;
-    text-align: center;
-    height: 48px;
-    line-height: 48px;
-    width: 48px;
-    float: left;
-    margin-right: 1em;
-  }
-}
-</style>
+<style src="./style_switcher.scss" lang="scss"></style>
-- 
cgit v1.2.3-70-g09d2


From d7af2c8419df59d8b897bc57e94f6cc67bd60eca Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Tue, 20 Nov 2018 23:25:38 +0300
Subject: mentioned bug in tab-switcher, made shadow-control work in zero-state

---
 src/components/shadow_control/shadow_control.js  | 19 +++++++++++++------
 src/components/shadow_control/shadow_control.vue |  7 +++----
 src/components/style_switcher/style_switcher.js  |  4 ++++
 src/components/style_switcher/style_switcher.vue |  2 +-
 src/components/tab_switcher/tab_switcher.jsx     |  2 ++
 5 files changed, 23 insertions(+), 11 deletions(-)

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

diff --git a/src/components/shadow_control/shadow_control.js b/src/components/shadow_control/shadow_control.js
index 54813685..b4f48668 100644
--- a/src/components/shadow_control/shadow_control.js
+++ b/src/components/shadow_control/shadow_control.js
@@ -37,9 +37,12 @@ export default {
       this.selectedId += 1
     }
   },
+  beforeUpdate () {
+    this.cValue = this.value || this.fallback
+  },
   computed: {
     selected () {
-      return this.cValue[this.selectedId] || {
+      return this.isReady && this.cValue[this.selectedId] || {
         x: 0,
         y: 0,
         blur: 0,
@@ -50,13 +53,17 @@ export default {
       }
     },
     moveUpValid () {
-      return this.selectedId > 0
+      return this.isReady && this.selectedId > 0
     },
     moveDnValid () {
-      return this.selectedId < this.cValue.length - 1
+      return this.isReady && this.selectedId < this.cValue.length - 1
+    },
+    isReady () {
+      return typeof this.cValue !== 'undefined'
     },
     present () {
-      return typeof this.cValue[this.selectedId] !== 'undefined' &&
+      return this.isReady &&
+        typeof this.cValue[this.selectedId] !== 'undefined' &&
         !this.usingFallback
     },
     usingFallback () {
@@ -66,9 +73,9 @@ export default {
       return hex2rgb(this.selected.color)
     },
     style () {
-      return {
+      return this.isReady ? {
         boxShadow: getCssShadow(this.cValue)
-      }
+      } : {}
     }
   }
 }
diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index cd774d32..f8066947 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -43,7 +43,7 @@
       <label for="shadow-switcher" class="select">
         <select
           v-model="selectedId" class="shadow-switcher"
-          :disabled="usingFallback"
+          :disabled="!isReady || usingFallback"
           id="shadow-switcher">
           <option v-for="(shadow, index) in cValue" :value="index">
             {{$t('settings.style.shadows.shadow_id', { value: index })}}
@@ -51,7 +51,7 @@
         </select>
         <i class="icon-down-open"/>
       </label>
-      <button class="btn btn-default" :disabled="!present" @click="del">
+      <button class="btn btn-default" :disabled="!isReady || !present" @click="del">
         <i class="icon-cancel"/>
       </button>
       <button class="btn btn-default" :disabled="!moveUpValid" @click="moveUp">
@@ -60,7 +60,7 @@
       <button class="btn btn-default" :disabled="!moveDnValid" @click="moveDn">
         <i class="icon-down-open"/>
       </button>
-      <button class="btn btn-default" @click="add">
+      <button class="btn btn-default" :disabled="!isReady" @click="add">
         <i class="icon-plus"/>
       </button>
     </div>
@@ -137,7 +137,6 @@
   flex-wrap: wrap;
   justify-content: center;
 
-
   .shadow-preview-container,
   .shadow-tweak {
     margin: 5px 6px 0 0;
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 7cb6197c..acb1764d 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -93,6 +93,9 @@ export default {
   },
   mounted () {
     this.normalizeLocalState(this.$store.state.config.customTheme)
+    if (typeof this.shadowSelected === 'undefined') {
+      this.shadowSelected = this.shadowsAvailable[0]
+    }
   },
   computed: {
     selectedVersion () {
@@ -180,6 +183,7 @@ export default {
       if (!this.preview.theme.colors) return { colors: {}, opacity: {}, radii: {}, shadows: {} }
       return this.preview.theme
     },
+    // This needs optimization maybe
     previewContrast () {
       if (!this.previewTheme.colors.bg) return {}
       const colors = this.previewTheme.colors
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 5f0c2566..5cf75636 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -198,7 +198,7 @@
             <label class="checkbox-label" for="override"></label>
           </div>
         </div>
-        <shadow-control v-if="currentShadowFallback" :fallback="currentShadowFallback" v-model="currentShadow"/>
+        <shadow-control :fallback="currentShadowFallback" v-model="currentShadow"/>
       </div>
     </tab-switcher>
   </keep-alive>
diff --git a/src/components/tab_switcher/tab_switcher.jsx b/src/components/tab_switcher/tab_switcher.jsx
index 3fff38f6..ea582450 100644
--- a/src/components/tab_switcher/tab_switcher.jsx
+++ b/src/components/tab_switcher/tab_switcher.jsx
@@ -1,5 +1,7 @@
 import Vue from 'vue'
 
+// FIXME: This doesn't like v-if directly inside the tab's contents, breaks vue really bad
+
 import './tab_switcher.scss'
 
 export default Vue.component('tab-switcher', {
-- 
cgit v1.2.3-70-g09d2


From 324aadb7c180baf51e77d08058683c7e256bfcfb Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Thu, 22 Nov 2018 04:25:15 +0300
Subject: fix

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

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

diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index f8066947..2bc05cb7 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -43,7 +43,7 @@
       <label for="shadow-switcher" class="select">
         <select
           v-model="selectedId" class="shadow-switcher"
-          :disabled="!isReady || usingFallback"
+          :disabled="!ready || usingFallback"
           id="shadow-switcher">
           <option v-for="(shadow, index) in cValue" :value="index">
             {{$t('settings.style.shadows.shadow_id', { value: index })}}
@@ -51,7 +51,7 @@
         </select>
         <i class="icon-down-open"/>
       </label>
-      <button class="btn btn-default" :disabled="!isReady || !present" @click="del">
+      <button class="btn btn-default" :disabled="!ready || !present" @click="del">
         <i class="icon-cancel"/>
       </button>
       <button class="btn btn-default" :disabled="!moveUpValid" @click="moveUp">
@@ -60,7 +60,7 @@
       <button class="btn btn-default" :disabled="!moveDnValid" @click="moveDn">
         <i class="icon-down-open"/>
       </button>
-      <button class="btn btn-default" :disabled="!isReady" @click="add">
+      <button class="btn btn-default" :disabled="!ready" @click="add">
         <i class="icon-plus"/>
       </button>
     </div>
-- 
cgit v1.2.3-70-g09d2


From b07d7d7229c376a0588d86ee8a28735bdcf99b7f Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Fri, 23 Nov 2018 11:36:36 +0300
Subject: reset buttons, better disabled for shadows

---
 src/App.scss                                      |  5 +++
 src/components/settings/settings.vue              |  8 +---
 src/components/shadow_control/shadow_control.vue  |  9 +++-
 src/components/style_switcher/style_switcher.js   |  4 ++
 src/components/style_switcher/style_switcher.scss | 54 +++++++++++++++++++----
 src/components/style_switcher/style_switcher.vue  | 21 +++++++--
 src/i18n/en.json                                  |  5 ++-
 src/services/style_setter/style_setter.js         |  1 +
 8 files changed, 85 insertions(+), 22 deletions(-)

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

diff --git a/src/App.scss b/src/App.scss
index 004c6fc3..ceb0bb87 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -120,6 +120,11 @@ input, textarea, .select {
   line-height: 16px;
   hyphens: none;
 
+  &:disabled, &[disabled=disabled] {
+    cursor: not-allowed;
+    opacity: 0.5;
+  }
+
   .icon-down-open {
     position: absolute;
     top: 0;
diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue
index 990d1f0d..2097fd22 100644
--- a/src/components/settings/settings.vue
+++ b/src/components/settings/settings.vue
@@ -208,12 +208,8 @@
 
   .btn {
     min-height: 28px;
-  }
-
-  .submit {
-    margin-top: 1em;
-    min-height: 30px;
-    width: 10em;
+    min-width: 10em;
+    padding: 0 2em;
   }
 }
 .select-multiple {
diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index 2bc05cb7..b608d0ff 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -40,7 +40,7 @@
 
   <div class="shadow-tweak">
     <div :disabled="usingFallback" class="id-control style-control">
-      <label for="shadow-switcher" class="select">
+      <label for="shadow-switcher" class="select" :disabled="!ready || usingFallback">
         <select
           v-model="selectedId" class="shadow-switcher"
           :disabled="!ready || usingFallback"
@@ -60,7 +60,7 @@
       <button class="btn btn-default" :disabled="!moveDnValid" @click="moveDn">
         <i class="icon-down-open"/>
       </button>
-      <button class="btn btn-default" :disabled="!ready" @click="add">
+      <button class="btn btn-default" :disabled="usingFallback" @click="add">
         <i class="icon-plus"/>
       </button>
     </div>
@@ -219,8 +219,13 @@
     .id-control {
       align-items: stretch;
       .select, .btn {
+        min-width: 1px;
         margin-right: 5px;
       }
+      .btn {
+        padding: 0 .4em;
+        margin: 0 .1em;
+      }
       .select {
         flex: 1;
         select {
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index e1a17837..d45ce455 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -369,6 +369,10 @@ export default {
       })
     },
 
+    clearAll () {
+      this.normalizeLocalState(this.$store.state.config.customTheme)
+    },
+
     // Clears all the extra stuff when loading V1 theme
     clearV1 () {
       Object.keys(this.$data)
diff --git a/src/components/style_switcher/style_switcher.scss b/src/components/style_switcher/style_switcher.scss
index 9cdc9f33..ad203856 100644
--- a/src/components/style_switcher/style_switcher.scss
+++ b/src/components/style_switcher/style_switcher.scss
@@ -63,15 +63,16 @@
     margin: 0 -1em;
   }
 
+  .reset-container {
+    flex-wrap: wrap;
+  }
+
+  .reset-container,
   .apply-container,
   .radius-container,
   .color-container,
   {
     display: flex;
-
-    p {
-      margin-left: 1em
-    }
   }
 
   .radius-container {
@@ -93,7 +94,38 @@
     margin: 1em 1em 0;
   }
 
-  .shadow-selector,
+  .tab-header {
+    display: flex;
+    justify-content: space-between;
+    align-items: baseline;
+    width: 100%;
+    min-height: 30px;
+
+    .btn {
+      min-width: 1px;
+      flex: 0 auto;
+      padding: 0 1em;
+    }
+
+    p {
+      flex: 1;
+      margin: 0;
+    }
+
+    margin-bottom: 1em;
+  }
+
+  .shadow-selector {
+    .override {
+      flex: 1;
+      margin-left: .5em;
+    }
+    .select-container {
+      margin-top: -4px;
+      margin-bottom: -3px;
+    }
+  }
+
   .save-load,
   .save-load-options {
     display: flex;
@@ -102,11 +134,8 @@
 
     .import-export {
       display: flex;
-
-      .btn {
-        margin-left: .5em;
-      }
     }
+
     .override {
       margin-left: .5em;
     }
@@ -132,6 +161,7 @@
     background-position: 50% 50%;
 
     .btn {
+      margin-left: 0;
       margin-top: 1em;
       min-height: 30px;
       width: 10em;
@@ -153,6 +183,7 @@
     &.wide {
       min-width: 60%
     }
+
     &:not(.wide):nth-child(2n+1) {
       margin-right: 7px;
 
@@ -200,6 +231,11 @@
     padding: 20px;
   }
 
+  .btn {
+    margin-left: .25em;
+    margin-right: .25em;
+  }
+
   .dummy {
     .avatar {
       background: linear-gradient(135deg, #b8e1fc 0%,#a9d2f3 10%,#90bae4 25%,#90bcea 37%,#90bff0 50%,#6ba8e5 51%,#a2daf5 83%,#bdf3fd 100%);
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index ed0dd733..9e5cffbe 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -71,10 +71,13 @@
     </div>
   </div>
 
-  <p>{{$t('settings.theme_help')}}</p>
   <keep-alive>
     <tab-switcher key="style-tweak">
       <div :label="$t('settings.style.common_colors._tab_label')" class="color-container">
+        <div class="tab-header">
+          <p>{{$t('settings.theme_help')}}</p>
+          <button class="btn" @click="clearOpacity">{{$t('settings.style.switcher.clear_opacity')}}</button>
+        </div>
         <h4>{{ $t('settings.style.common_colors.main') }}</h4>
         <div class="color-item">
           <ColorInput name="bgColor" v-model="bgColorLocal" :label="$t('settings.background')"/>
@@ -106,6 +109,11 @@
       </div>
 
       <div :label="$t('settings.style.advanced_colors._tab_label')" class="color-container">
+        <div class="tab-header">
+          <p>{{$t('settings.theme_help')}}</p>
+          <button class="btn" @click="clearV1">{{$t('settings.style.switcher.clear_all')}}</button>
+          <button class="btn" @click="clearOpacity">{{$t('settings.style.switcher.clear_opacity')}}</button>
+        </div>
         <div class="color-item">
           <h4>{{ $t('settings.style.advanced_colors.alert') }}</h4>
           <ColorInput name="alertError" v-model="alertErrorColorLocal" :label="$t('settings.style.advanced_colors.alert_error')" :fallback="previewTheme.colors.alertError"/>
@@ -159,7 +167,10 @@
       </div>
       <div :label="$t('settings.style.radii._tab_label')" class="radius-container">
         <div>
-          <p>{{$t('settings.radii_help')}}</p>
+          <div class="tab-header">
+            <p>{{$t('settings.radii_help')}}</p>
+            <button class="btn" @click="clearRoundness">{{$t('settings.style.switcher.clear_all')}}</button>
+          </div>
           <RangeInput name="btnRadius" :label="$t('settings.btnRadius')" v-model="btnRadiusLocal" :fallback="previewTheme.radii.btn" max="16" hardMin="0"/>
           <RangeInput name="inputRadius" :label="$t('settings.inputRadius')" v-model="inputRadiusLocal" :fallback="previewTheme.radii.input" max="9" hardMin="0"/>
           <RangeInput name="checkboxRadius" :label="$t('settings.checkboxRadius')" v-model="checkboxRadiusLocal" :fallback="previewTheme.radii.checkbox" max="16" hardMin="0"/>
@@ -171,8 +182,8 @@
         </div>
       </div>
       <div :label="$t('settings.style.shadows._tab_label')" class="shadow-container">
-        <div class="shadow-selector">
-          <div>
+        <div class="tab-header shadow-selector">
+          <div class="select-container">
             {{$t('settings.style.shadows.component')}}
             <label for="shadow-switcher" class="select">
               <select id="shadow-switcher" v-model="shadowSelected" class="shadow-switcher">
@@ -196,6 +207,7 @@
               type="checkbox">
             <label class="checkbox-label" for="override"></label>
           </div>
+          <button class="btn" @click="clearShadows">{{$t('settings.style.switcher.clear_all')}}</button>
         </div>
         <shadow-control :ready="!!currentShadowFallback" :fallback="currentShadowFallback" v-model="currentShadow"/>
       </div>
@@ -204,6 +216,7 @@
 
   <div class="apply-container">
     <button class="btn submit" @click="setCustomTheme">{{$t('general.apply')}}</button>
+    <button class="btn" @click="clearAll">{{$t('settings.style.switcher.reset')}}</button>
   </div>
 </div>
 </template>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 98a91013..15d57765 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -168,7 +168,10 @@
         "keep_shadows": "Keep shadows",
         "keep_opacity": "Keep opacity",
         "keep_roundness": "Keep roundness",
-        "save_load_hint": "\"Keep\" options preserve currently set options when selecting or loading themes, it also stores said options when exporting a theme."
+        "save_load_hint": "\"Keep\" options preserve currently set options when selecting or loading themes, it also stores said options when exporting a theme.",
+        "reset": "Reset",
+        "clear_all": "Clear all",
+        "clear_opacity": "Clear opacity"
       },
       "common": {
         "color": "Color",
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 60531f28..680aadb4 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -249,6 +249,7 @@ const generateRadii = (input) => {
   }, {
     btn: 4,
     input: 4,
+    checkbox: 2,
     panel: 10,
     avatar: 5,
     avatarAlt: 50,
-- 
cgit v1.2.3-70-g09d2


From 1a8d24d649228a245e7f5b6ebf6883d8f1c6797b Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 25 Nov 2018 17:21:53 +0300
Subject: some help strings

---
 src/components/shadow_control/shadow_control.vue | 4 ++++
 src/components/style_switcher/style_switcher.vue | 7 +++++--
 src/i18n/en.json                                 | 7 +++++--
 src/services/style_setter/style_setter.js        | 1 +
 4 files changed, 15 insertions(+), 4 deletions(-)

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

diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index b608d0ff..85346e17 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -124,6 +124,9 @@
     <OpacityInput
       v-model="selected.alpha"
       :disabled="!present"/>
+    <div>
+      {{$t('settings.style.shadows.hint')}}
+    </div>
   </div>
 </div>
 </template>
@@ -215,6 +218,7 @@
 
   .shadow-tweak {
     flex: 1;
+    min-width: 280px;
 
     .id-control {
       align-items: stretch;
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 9e5cffbe..f5090321 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -75,9 +75,11 @@
     <tab-switcher key="style-tweak">
       <div :label="$t('settings.style.common_colors._tab_label')" class="color-container">
         <div class="tab-header">
-          <p>{{$t('settings.theme_help')}}</p>
+            <p>{{$t('settings.theme_help')}}</p>
           <button class="btn" @click="clearOpacity">{{$t('settings.style.switcher.clear_opacity')}}</button>
+          <button class="btn" @click="clearV1">{{$t('settings.style.switcher.clear_all')}}</button>
         </div>
+        <p>{{$t('settings.theme_help_v2_1')}}</p>
         <h4>{{ $t('settings.style.common_colors.main') }}</h4>
         <div class="color-item">
           <ColorInput name="bgColor" v-model="bgColorLocal" :label="$t('settings.background')"/>
@@ -106,13 +108,14 @@
           <ColorInput name="cOrangeColor" v-model="cOrangeColorLocal" :label="$t('settings.cOrange')"/>
           <ContrastRatio :contrast="previewContrast.bgOrange"/>
         </div>
+        <p>{{$t('settings.theme_help_v2_2')}}</p>
       </div>
 
       <div :label="$t('settings.style.advanced_colors._tab_label')" class="color-container">
         <div class="tab-header">
           <p>{{$t('settings.theme_help')}}</p>
-          <button class="btn" @click="clearV1">{{$t('settings.style.switcher.clear_all')}}</button>
           <button class="btn" @click="clearOpacity">{{$t('settings.style.switcher.clear_opacity')}}</button>
+          <button class="btn" @click="clearV1">{{$t('settings.style.switcher.clear_all')}}</button>
         </div>
         <div class="color-item">
           <h4>{{ $t('settings.style.advanced_colors.alert') }}</h4>
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 15d57765..5bd1ddbb 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -157,6 +157,8 @@
     "text": "Text",
     "theme": "Theme",
     "theme_help": "Use hex color codes (#rrggbb) to customize your color theme.",
+    "theme_help_v2_1": "You can also override certain component's colors and opacity by toggling the checkbox, use \"Clear all\" button to clear all overrides.",
+    "theme_help_v2_2": "Icons underneath some entries are background/text contrast indicators, hover over for detailed info. Please keep in mind that when using transparency contrast indicators show the worst possible case.",
     "tooltipRadius": "Tooltips/alerts",
     "user_settings": "User Settings",
     "values": {
@@ -220,12 +222,13 @@
         "blur": "Blur",
         "spread": "Spread",
         "inset": "Inset",
+        "hint": "For shadows you can also use --variable as a color value to use CSS3 variables. Please note that setting opacity won't work in this case.",
         "components": {
           "panel": "Panel",
           "panelHeader": "Panel header",
           "topBar": "Top bar",
-          "avatar": "User avatar (in post display)",
-          "avatarStatus": "User avatar (in profile view)",
+          "avatar": "User avatar (in profile view)",
+          "avatarStatus": "User avatar (in post display)",
           "popup": "Popups and tooltips",
           "button": "Button",
           "buttonHover": "Button (hover)",
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index 680aadb4..5726cd61 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -321,6 +321,7 @@ const generateShadows = (input) => {
       color: '#000000',
       alpha: 0.7
     }],
+    avatarStatus: [],
     panelHeader: [],
     button: [{
       x: 0,
-- 
cgit v1.2.3-70-g09d2


From 1a65895bfd441ea57163ee3e185785c82a81b736 Mon Sep 17 00:00:00 2001
From: Henry Jameson <me@hjkos.com>
Date: Sun, 25 Nov 2018 21:48:16 +0300
Subject: initial font support

---
 src/App.scss                                      |  3 +
 src/components/font_control/font_control.vue      | 93 +++++++++++++++++++++++
 src/components/shadow_control/shadow_control.vue  |  5 +-
 src/components/style_switcher/style_switcher.js   | 63 ++++++++++++---
 src/components/style_switcher/style_switcher.scss |  3 +
 src/components/style_switcher/style_switcher.vue  | 55 ++++++++++----
 src/i18n/en.json                                  | 13 ++++
 src/services/style_setter/style_setter.js         | 48 +++++++++++-
 8 files changed, 251 insertions(+), 32 deletions(-)
 create mode 100644 src/components/font_control/font_control.vue

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

diff --git a/src/App.scss b/src/App.scss
index ceb0bb87..45491fd2 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -34,6 +34,7 @@ h4 {
 
 body {
   font-family: sans-serif;
+  font-family: var(--interfaceFont, sans-serif);
   font-size: 14px;
   margin: 0;
   color: $fallback--text;
@@ -62,6 +63,7 @@ button {
   box-shadow: var(--buttonShadow);
   font-size: 14px;
   font-family: sans-serif;
+  font-family: var(--interfaceFont, sans-serif);
 
   i[class*=icon-] {
     color: $fallback--text;
@@ -111,6 +113,7 @@ input, textarea, .select {
   color: $fallback--lightText;
   color: var(--inputText, $fallback--lightText);
   font-family: sans-serif;
+  font-family: var(--inputFont, sans-serif);
   font-size: 14px;
   padding: 8px 7px;
   box-sizing: border-box;
diff --git a/src/components/font_control/font_control.vue b/src/components/font_control/font_control.vue
new file mode 100644
index 00000000..424f6259
--- /dev/null
+++ b/src/components/font_control/font_control.vue
@@ -0,0 +1,93 @@
+<template>
+<div class="font-control style-control">
+  <label :for="preset === 'custom' ? name : name + '-font-switcher'" class="label">
+    {{label}}
+  </label>
+  <input
+    v-if="typeof fallback !== 'undefined'"
+    class="opt exlcude-disabled"
+    type="checkbox"
+    :id="name + '-o'"
+    :checked="present"
+    @input="$emit('input', typeof value === 'undefined' ? fallback : undefined)">
+  <label v-if="typeof fallback !== 'undefined'" class="opt-l" :for="name + '-o'"></label>
+  <label :for="name + '-font-switcher'" class="select" :disabled="!present">
+    <select
+      :disabled="!present"
+      v-model="preset"
+      class="font-switcher"
+      id="name + '-font-switcher'">
+      <option v-for="option in options" :value="option">
+        {{ option }}
+      </option>
+    </select>
+    <i class="icon-down-open"/>
+  </label>
+  <input
+    v-if="preset === 'custom'"
+    class="custom-font"
+    type="text"
+    id="name"
+    v-model="family">
+</div>
+</template>
+
+<script>
+import { set } from 'vue'
+
+export default {
+  props: [
+    'name', 'label', 'value', 'fallback', 'options'
+  ],
+  data () {
+    return {
+      lValue: this.value
+    }
+  },
+  beforeUpdate () {
+    this.lValue = this.value
+  },
+  computed: {
+    present () {
+      return typeof this.lValue !== 'undefined'
+    },
+    dValue () {
+      return this.lValue || this.fallback || {}
+    },
+    family: {
+      get () {
+        return this.dValue.family
+      },
+      set (v) {
+        set(this.lValue, 'family', v)
+        this.$emit('input', this.lValue)
+      }
+    },
+    preset: {
+      get () {
+        console.log(this.family)
+        if (this.family === 'serif' ||
+            this.family === 'sans-serif' ||
+            this.family === 'monospace' ||
+            this.family === 'inherit') {
+          return this.family
+        } else {
+          return 'custom'
+        }
+      },
+      set (v) {
+        this.family = v === 'custom' ? '' : v
+      }
+    }
+  }
+}
+</script>
+
+<style lang="scss">
+@import '../../_variables.scss';
+.font-control {
+  input.custom-font {
+    min-width: 10em;
+  }
+}
+</style>
diff --git a/src/components/shadow_control/shadow_control.vue b/src/components/shadow_control/shadow_control.vue
index 85346e17..744925d4 100644
--- a/src/components/shadow_control/shadow_control.vue
+++ b/src/components/shadow_control/shadow_control.vue
@@ -124,9 +124,9 @@
     <OpacityInput
       v-model="selected.alpha"
       :disabled="!present"/>
-    <div>
+    <p>
       {{$t('settings.style.shadows.hint')}}
-    </div>
+    </p>
   </div>
 </div>
 </template>
@@ -139,6 +139,7 @@
   display: flex;
   flex-wrap: wrap;
   justify-content: center;
+  margin-bottom: 1em;
 
   .shadow-preview-container,
   .shadow-tweak {
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js
index 57faa61b..bbd28bdc 100644
--- a/src/components/style_switcher/style_switcher.js
+++ b/src/components/style_switcher/style_switcher.js
@@ -1,10 +1,11 @@
 import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js'
 import { set, delete as del } from 'vue'
-import { generateColors, generateShadows, generateRadii, composePreset } from '../../services/style_setter/style_setter.js'
+import { generateColors, generateShadows, generateRadii, generateFonts, composePreset } 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'
 import ShadowControl from '../shadow_control/shadow_control.vue'
+import FontControl from '../font_control/font_control.vue'
 import ContrastRatio from '../contrast_ratio/contrast_ratio.vue'
 import TabSwitcher from '../tab_switcher/tab_switcher.jsx'
 
@@ -30,6 +31,7 @@ export default {
       previewShadows: {},
       previewColors: {},
       previewRadii: {},
+      previewFonts: {},
 
       shadowsInvalid: true,
       colorsInvalid: true,
@@ -38,6 +40,7 @@ export default {
       keepShadows: false,
       keepOpacity: false,
       keepRoundness: false,
+      keepFonts: false,
 
       textColorLocal: '',
       linkColorLocal: '',
@@ -85,6 +88,7 @@ export default {
 
       shadowSelected: undefined,
       shadowsLocal: {},
+      fontsLocal: {},
 
       btnRadiusLocal: '',
       inputRadiusLocal: '',
@@ -176,10 +180,11 @@ export default {
       }
     },
     preview () {
-      return composePreset(this.previewColors, this.previewRadii, this.previewShadows)
+      return composePreset(this.previewColors, this.previewRadii, this.previewShadows, this.previewFonts)
     },
     previewTheme () {
-      if (!this.preview.theme.colors) return { colors: {}, opacity: {}, radii: {}, shadows: {} }
+      if (!this.preview.theme.colors) return { colors: {}, opacity: {}, radii: {}, shadows: {}, fonts: {} }
+      console.log(this.preview.theme)
       return this.preview.theme
     },
     // This needs optimization maybe
@@ -253,7 +258,11 @@ export default {
     },
     previewRules () {
       if (!this.preview.rules) return ''
-      return [...Object.values(this.preview.rules), 'color: var(--text)'].join(';')
+      return [
+        ...Object.values(this.preview.rules),
+        'color: var(--text)',
+        'font-family: var(--interfaceFont, sans-serif)'
+      ].join(';')
     },
     shadowsAvailable () {
       return Object.keys(this.previewTheme.shadows).sort()
@@ -291,6 +300,7 @@ export default {
     RangeInput,
     ContrastRatio,
     ShadowControl,
+    FontControl,
     TabSwitcher
   },
   methods: {
@@ -300,6 +310,7 @@ export default {
         _pleroma_theme_version: 2,
         theme: {
           shadows: this.shadowsLocal,
+          fonts: this.fontsLocal,
           opacity: this.currentOpacity,
           colors: this.currentColors,
           radii: this.currentRadii
@@ -357,6 +368,7 @@ export default {
         name: 'customTheme',
         value: {
           shadows: this.shadowsLocal,
+          fonts: this.fontsLocal,
           opacity: this.currentOpacity,
           colors: this.currentColors,
           radii: this.currentRadii
@@ -398,6 +410,10 @@ export default {
       this.shadowsLocal = {}
     },
 
+    clearFonts () {
+      this.fontsLocal = {}
+    },
+
     /**
      * This applies stored theme data onto form.
      * @param {Object} input - input data
@@ -408,6 +424,7 @@ export default {
       const radii = input.radii || input
       const opacity = input.opacity
       const shadows = input.shadows || {}
+      const fonts = input.fonts || {}
 
       if (version === 0) {
         if (input.version) version = input.version
@@ -458,6 +475,11 @@ export default {
         this.shadowSelected = this.shadowsAvailable[0]
       }
 
+      if (!this.keepFonts) {
+        this.clearFonts()
+        this.fontsLocal = fonts
+      }
+
       if (opacity && !this.keepOpacity) {
         this.clearOpacity()
         Object.entries(opacity).forEach(([k, v]) => {
@@ -477,14 +499,31 @@ export default {
         console.warn(e)
       }
     },
-    shadowsLocal () {
-      try {
-        this.previewShadows = generateShadows({ shadows: this.shadowsLocal })
-        this.shadowsInvalid = false
-      } catch (e) {
-        this.shadowsInvalid = true
-        console.warn(e)
-      }
+    shadowsLocal: {
+      handler () {
+        try {
+          this.previewShadows = generateShadows({ shadows: this.shadowsLocal })
+          this.shadowsInvalid = false
+        } catch (e) {
+          this.shadowsInvalid = true
+          console.warn(e)
+        }
+      },
+      deep: true
+    },
+    fontsLocal: {
+      handler () {
+        try {
+          this.previewFonts = generateFonts({ fonts: this.fontsLocal })
+          console.log('BENIS')
+          console.log(this.previewFonts)
+          this.fontsInvalid = false
+        } catch (e) {
+          this.fontsInvalid = true
+          console.warn(e)
+        }
+      },
+      deep: true
     },
     currentColors () {
       try {
diff --git a/src/components/style_switcher/style_switcher.scss b/src/components/style_switcher/style_switcher.scss
index ad203856..9c4f4ecd 100644
--- a/src/components/style_switcher/style_switcher.scss
+++ b/src/components/style_switcher/style_switcher.scss
@@ -67,6 +67,7 @@
     flex-wrap: wrap;
   }
 
+  .fonts-container,
   .reset-container,
   .apply-container,
   .radius-container,
@@ -75,6 +76,7 @@
     display: flex;
   }
 
+  .fonts-container,
   .radius-container {
     flex-direction: column;
   }
@@ -87,6 +89,7 @@
     justify-content: space-between;
   }
 
+  .fonts-container,
   .color-container,
   .shadow-container,
   .radius-container,
diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue
index 5e9af19e..f64bda3f 100644
--- a/src/components/style_switcher/style_switcher.vue
+++ b/src/components/style_switcher/style_switcher.vue
@@ -75,7 +75,7 @@
     <tab-switcher key="style-tweak">
       <div :label="$t('settings.style.common_colors._tab_label')" class="color-container">
         <div class="tab-header">
-            <p>{{$t('settings.theme_help')}}</p>
+          <p>{{$t('settings.theme_help')}}</p>
           <button class="btn" @click="clearOpacity">{{$t('settings.style.switcher.clear_opacity')}}</button>
           <button class="btn" @click="clearV1">{{$t('settings.style.switcher.clear_all')}}</button>
         </div>
@@ -169,20 +169,18 @@
         </div>
       </div>
       <div :label="$t('settings.style.radii._tab_label')" class="radius-container">
-        <div>
-          <div class="tab-header">
-            <p>{{$t('settings.radii_help')}}</p>
-            <button class="btn" @click="clearRoundness">{{$t('settings.style.switcher.clear_all')}}</button>
-          </div>
-          <RangeInput name="btnRadius" :label="$t('settings.btnRadius')" v-model="btnRadiusLocal" :fallback="previewTheme.radii.btn" max="16" hardMin="0"/>
-          <RangeInput name="inputRadius" :label="$t('settings.inputRadius')" v-model="inputRadiusLocal" :fallback="previewTheme.radii.input" max="9" hardMin="0"/>
-          <RangeInput name="checkboxRadius" :label="$t('settings.checkboxRadius')" v-model="checkboxRadiusLocal" :fallback="previewTheme.radii.checkbox" max="16" hardMin="0"/>
-          <RangeInput name="panelRadius" :label="$t('settings.panelRadius')" v-model="panelRadiusLocal" :fallback="previewTheme.radii.panel" max="50" hardMin="0"/>
-          <RangeInput name="avatarRadius" :label="$t('settings.avatarRadius')" v-model="avatarRadiusLocal" :fallback="previewTheme.radii.avatar" max="28" hardMin="0"/>
-          <RangeInput name="avatarAltRadius" :label="$t('settings.avatarAltRadius')" v-model="avatarAltRadiusLocal" :fallback="previewTheme.radii.avatarAlt" max="28" hardMin="0"/>
-          <RangeInput name="attachmentRadius" :label="$t('settings.attachmentRadius')" v-model="attachmentRadiusLocal" :fallback="previewTheme.radii.attachment" max="50" hardMin="0"/>
-          <RangeInput name="tooltipRadius" :label="$t('settings.tooltipRadius')" v-model="tooltipRadiusLocal" :fallback="previewTheme.radii.tooltip" max="50" hardMin="0"/>
+        <div class="tab-header">
+          <p>{{$t('settings.radii_help')}}</p>
+          <button class="btn" @click="clearRoundness">{{$t('settings.style.switcher.clear_all')}}</button>
         </div>
+        <RangeInput name="btnRadius" :label="$t('settings.btnRadius')" v-model="btnRadiusLocal" :fallback="previewTheme.radii.btn" max="16" hardMin="0"/>
+        <RangeInput name="inputRadius" :label="$t('settings.inputRadius')" v-model="inputRadiusLocal" :fallback="previewTheme.radii.input" max="9" hardMin="0"/>
+        <RangeInput name="checkboxRadius" :label="$t('settings.checkboxRadius')" v-model="checkboxRadiusLocal" :fallback="previewTheme.radii.checkbox" max="16" hardMin="0"/>
+        <RangeInput name="panelRadius" :label="$t('settings.panelRadius')" v-model="panelRadiusLocal" :fallback="previewTheme.radii.panel" max="50" hardMin="0"/>
+        <RangeInput name="avatarRadius" :label="$t('settings.avatarRadius')" v-model="avatarRadiusLocal" :fallback="previewTheme.radii.avatar" max="28" hardMin="0"/>
+        <RangeInput name="avatarAltRadius" :label="$t('settings.avatarAltRadius')" v-model="avatarAltRadiusLocal" :fallback="previewTheme.radii.avatarAlt" max="28" hardMin="0"/>
+        <RangeInput name="attachmentRadius" :label="$t('settings.attachmentRadius')" v-model="attachmentRadiusLocal" :fallback="previewTheme.radii.attachment" max="50" hardMin="0"/>
+        <RangeInput name="tooltipRadius" :label="$t('settings.tooltipRadius')" v-model="tooltipRadiusLocal" :fallback="previewTheme.radii.tooltip" max="50" hardMin="0"/>
       </div>
       <div :label="$t('settings.style.shadows._tab_label')" class="shadow-container">
         <div class="tab-header shadow-selector">
@@ -214,6 +212,35 @@
         </div>
         <shadow-control :ready="!!currentShadowFallback" :fallback="currentShadowFallback" v-model="currentShadow"/>
       </div>
+      <div :label="$t('settings.style.fonts._tab_label')" class="fonts-container">
+        <div class="tab-header">
+          <p>{{$t('settings.style.fonts.help')}}</p>
+        </div>
+        <FontControl
+          name="ui"
+          v-model="fontsLocal.interface"
+          :label="$t('settings.style.fonts.components.interface')"
+          :fallback="previewTheme.fonts.interface"
+          :options="['serif', 'sans-serif', 'monospace', 'custom']" />
+        <FontControl
+          name="input"
+          v-model="fontsLocal.input"
+          :label="$t('settings.style.fonts.components.input')"
+          :fallback="previewTheme.fonts.input"
+          :options="['serif', 'sans-serif', 'monospace', 'inherit', 'custom']" />
+        <FontControl
+          name="post"
+          v-model="fontsLocal.post"
+          :label="$t('settings.style.fonts.components.post')"
+          :fallback="previewTheme.fonts.post"
+          :options="['serif', 'sans-serif', 'monospace', 'inherit', 'custom']" />
+        <FontControl
+          name="postCode"
+          v-model="fontsLocal.postCode"
+          :label="$t('settings.style.fonts.components.postCode')"
+          :fallback="previewTheme.fonts.postCode"
+          :options="['serif', 'sans-serif', 'monospace', 'inherit', 'custom']" />
+      </div>
     </tab-switcher>
   </keep-alive>
 
diff --git a/src/i18n/en.json b/src/i18n/en.json
index 5bd1ddbb..6f439f65 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -236,6 +236,19 @@
           "buttonPressedHover": "Button (pressed+hover)",
           "input": "Input field"
         }
+      },
+      "fonts": {
+        "_tab_label": "Fonts",
+        "help": "Select font to use for elements of UI. For \"custom\" you have to enter exact font name as it appears in system.",
+        "components": {
+          "interface": "Interface",
+          "input": "Input fields",
+          "post": "Post text",
+          "postCode": "Monospaced text in a post (rich text)"
+        },
+        "family": "Font name",
+        "size": "Size (in px)",
+        "weight": "Weight (boldness)"
       }
     }
   },
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js
index e11ee90c..f2c9c13e 100644
--- a/src/services/style_setter/style_setter.js
+++ b/src/services/style_setter/style_setter.js
@@ -85,6 +85,7 @@ const setColors = (input, commit) => {
   styleSheet.insertRule(`body { ${rules.radii} }`, 'index-max')
   styleSheet.insertRule(`body { ${rules.colors} }`, 'index-max')
   styleSheet.insertRule(`body { ${rules.shadows} }`, 'index-max')
+  styleSheet.insertRule(`body { ${rules.fonts} }`, 'index-max')
   body.style.display = 'initial'
 
   // commit('setOption', { name: 'colors', value: htmlColors })
@@ -267,6 +268,41 @@ const generateRadii = (input) => {
   }
 }
 
+const generateFonts = (input) => {
+  const fonts = Object.entries(input.fonts || {}).filter(([k, v]) => v).reduce((acc, [k, v]) => {
+    acc[k] = Object.entries(v).filter(([k, v]) => v).reduce((acc, [k, v]) => {
+      acc[k] = v
+      return acc
+    }, acc[k])
+    return acc
+  }, {
+    interface: {
+      family: 'sans-serif'
+    },
+    input: {
+      family: 'inherit'
+    },
+    post: {
+      family: 'inherit'
+    },
+    postCode: {
+      family: 'monospace'
+    }
+  })
+
+  return {
+    rules: {
+      fonts: Object
+        .entries(fonts)
+        .filter(([k, v]) => v)
+        .map(([k, v]) => `--${k}Font: ${v.family}`).join(';')
+    },
+    theme: {
+      fonts
+    }
+  }
+}
+
 const generateShadows = (input) => {
   const border = (top, shadow) => ({
     x: 0,
@@ -355,17 +391,19 @@ const generateShadows = (input) => {
   }
 }
 
-const composePreset = (colors, radii, shadows) => {
+const composePreset = (colors, radii, shadows, fonts) => {
   return {
     rules: {
       ...shadows.rules,
       ...colors.rules,
-      ...radii.rules
+      ...radii.rules,
+      ...fonts.rules
     },
     theme: {
       ...shadows.theme,
       ...colors.theme,
-      ...radii.theme
+      ...radii.theme,
+      ...fonts.theme
     }
   }
 }
@@ -374,8 +412,9 @@ const generatePreset = (input) => {
   const shadows = generateShadows(input)
   const colors = generateColors(input)
   const radii = generateRadii(input)
+  const fonts = generateFonts(input)
 
-  return composePreset(colors, radii, shadows)
+  return composePreset(colors, radii, shadows, fonts)
 }
 
 const setPreset = (val, commit) => {
@@ -424,6 +463,7 @@ export {
   generateColors,
   generateRadii,
   generateShadows,
+  generateFonts,
   generatePreset,
   composePreset,
   getCssShadow
-- 
cgit v1.2.3-70-g09d2

