From f78a5158e160fce03b333ad0aea6b2e136d42f67 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 2 Oct 2018 21:43:58 +0300 Subject: [PATCH 001/123] something works without exploding and i'm tired already --- package.json | 1 + src/App.scss | 10 +- src/components/settings/settings.vue | 2 + .../style_switcher/style_switcher.js | 141 +++++++++----- .../style_switcher/style_switcher.vue | 174 ++++++++---------- src/lib/persisted_state.js | 1 + src/services/color_convert/color_convert.js | 12 ++ src/services/style_setter/style_setter.js | 134 +++++++++----- yarn.lock | 4 + 9 files changed, 297 insertions(+), 182 deletions(-) diff --git a/package.json b/package.json index b716e7c6..1149d200 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dependencies": { "babel-plugin-add-module-exports": "^0.2.1", "babel-plugin-lodash": "^3.2.11", + "chromatism": "^3.0.0", "diff": "^3.0.1", "karma-mocha-reporter": "^2.2.1", "localforage": "^1.5.0", diff --git a/src/App.scss b/src/App.scss index 056a235e..1119caf2 100644 --- a/src/App.scss +++ b/src/App.scss @@ -51,7 +51,7 @@ a { button { user-select: none; color: $fallback--fg; - color: var(--fg, $fallback--fg); + color: var(--btnText, $fallback--fg); background-color: $fallback--btn; background-color: var(--btn, $fallback--btn); border: none; @@ -254,7 +254,7 @@ nav { mask-position: center; mask-size: contain; background-color: $fallback--fg; - background-color: var(--fg, $fallback--fg); + background-color: var(--topBarText, $fallback--fg); position: absolute; top: 0; bottom: 0; @@ -330,8 +330,9 @@ main-router { padding: .6em .6em; text-align: left; line-height: 28px; + color: var(--panelText); background-color: $fallback--btn; - background-color: var(--btn, $fallback--btn); + background-color: var(--panel, $fallback--btn); align-items: baseline; .title { @@ -387,8 +388,9 @@ main-router { nav { z-index: 1000; + color: var(--topBarText); background-color: $fallback--btn; - background-color: var(--btn, $fallback--btn); + background-color: var(--topBar, $fallback--btn); color: $fallback--faint; color: var(--faint, $fallback--faint); box-shadow: 0px 0px 4px rgba(0,0,0,.6); diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index 42c660a3..eebb2cb7 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -18,6 +18,7 @@
+
@@ -146,6 +147,7 @@
+
diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index 95c15b49..5f76c038 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -1,4 +1,7 @@ -import { rgbstr2hex } from '../../services/color_convert/color_convert.js' +import { rgb2hex } from '../../services/color_convert/color_convert.js' +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' export default { data () { @@ -7,13 +10,23 @@ export default { selected: this.$store.state.config.theme, invalidThemeImported: false, bgColorLocal: '', + bgOpacityLocal: 0, btnColorLocal: '', + btnOpacityLocal: '', + textColorLocal: '', linkColorLocal: '', + + panelColorLocal: undefined, + panelOpacityLocal: undefined, + topBarColorLocal: undefined, + topBarOpacityLocal: undefined, + redColorLocal: '', blueColorLocal: '', greenColorLocal: '', orangeColorLocal: '', + btnRadiusLocal: '', inputRadiusLocal: '', panelRadiusLocal: '', @@ -33,7 +46,48 @@ export default { }) }, mounted () { - this.normalizeLocalState(this.$store.state.config.colors, this.$store.state.config.radii) + this.normalizeLocalState(this.$store.state.config.customTheme) + }, + computed: { + currentTheme () { + return { + colors: { + bg: this.bgColorLocal, + fg: this.textColorLocal, + panel: this.panelColorLocal, + topBar: this.topBarColorLocal, + btn: this.btnColorLocal, + link: this.linkColorLocal, + cRed: this.redColorLocal, + cBlue: this.blueColorLocal, + cGreen: this.greenColorLocal, + cOrange: this.orangeColorLocal + }, + radii: { + btnRadius: this.btnRadiusLocal, + inputRadius: this.inputRadiusLocal, + panelRadius: this.panelRadiusLocal, + avatarRadius: this.avatarRadiusLocal, + avatarAltRadius: this.avatarAltRadiusLocal, + tooltipRadius: this.tooltipRadiusLocal, + attachmentRadius: this.attachmentRadiusLocal + } + } + }, + previewRules () { + try { + const generated = StyleSetter.generatePreset(this.currentTheme.colors) + return [generated.colorRules, generated.radiiRules].join(';') + } catch (e) { + console.error('CATCH') + console.error(e) + return '' + } + } + }, + components: { + ColorInput, + OpacityInput }, methods: { exportCurrentTheme () { @@ -101,57 +155,62 @@ export default { b: parseInt(result[3], 16) } : null } - const bgRgb = rgb(this.bgColorLocal) - const btnRgb = rgb(this.btnColorLocal) - const textRgb = rgb(this.textColorLocal) - const linkRgb = rgb(this.linkColorLocal) - const redRgb = rgb(this.redColorLocal) - const blueRgb = rgb(this.blueColorLocal) - const greenRgb = rgb(this.greenColorLocal) - const orangeRgb = rgb(this.orangeColorLocal) - - if (bgRgb && btnRgb && linkRgb) { - this.$store.dispatch('setOption', { - name: 'customTheme', - value: { - fg: btnRgb, - bg: bgRgb, - text: textRgb, - link: linkRgb, - cRed: redRgb, - cBlue: blueRgb, - cGreen: greenRgb, - cOrange: orangeRgb, - btnRadius: this.btnRadiusLocal, - inputRadius: this.inputRadiusLocal, - panelRadius: this.panelRadiusLocal, - avatarRadius: this.avatarRadiusLocal, - avatarAltRadius: this.avatarAltRadiusLocal, - tooltipRadius: this.tooltipRadiusLocal, - attachmentRadius: this.attachmentRadiusLocal - }}) - } + this.$store.dispatch('setOption', { + name: 'customTheme', + value: this.currentTheme + }) }, - normalizeLocalState (colors, radii) { - this.bgColorLocal = rgbstr2hex(colors.bg) - this.btnColorLocal = rgbstr2hex(colors.btn) - this.textColorLocal = rgbstr2hex(colors.fg) - this.linkColorLocal = rgbstr2hex(colors.link) + normalizeLocalState (input) { + const colors = input.colors || input + const radii = input.radii || input + let i = 0 + console.log('BENIS') + console.log(colors) - this.redColorLocal = rgbstr2hex(colors.cRed) - this.blueColorLocal = rgbstr2hex(colors.cBlue) - this.greenColorLocal = rgbstr2hex(colors.cGreen) - this.orangeColorLocal = rgbstr2hex(colors.cOrange) + console.log(i++) + this.bgColorLocal = rgb2hex(colors.bg) + console.log(i++) + this.btnColorLocal = rgb2hex(colors.btn) + console.log(i++) + this.textColorLocal = rgb2hex(colors.text || colors.fg) + console.log(i++) + this.linkColorLocal = rgb2hex(colors.link) + console.log(i++) + + this.panelColorLocal = colors.panel ? rgb2hex(colors.panel) : undefined + console.log(i++) + this.topBarColorLocal = colors.topBad ? rgb2hex(colors.topBar) : undefined + console.log(i++) + + this.redColorLocal = rgb2hex(colors.cRed) + console.log(i++) + console.log('red') + console.log(colors.cRed) + console.log(this.redColorLocal) + this.blueColorLocal = rgb2hex(colors.cBlue) + console.log(i++) + console.log('blue', this.blueColorLocal, colors.cBlue) + this.greenColorLocal = rgb2hex(colors.cGreen) + console.log(i++) + this.orangeColorLocal = rgb2hex(colors.cOrange) + console.log(i++) this.btnRadiusLocal = radii.btnRadius || 4 + console.log(i++) this.inputRadiusLocal = radii.inputRadius || 4 + console.log(i++) this.panelRadiusLocal = radii.panelRadius || 10 + console.log(i++) this.avatarRadiusLocal = radii.avatarRadius || 5 + console.log(i++) this.avatarAltRadiusLocal = radii.avatarAltRadius || 50 + console.log(i++) this.tooltipRadiusLocal = radii.tooltipRadius || 2 + console.log(i++) this.attachmentRadiusLocal = radii.attachmentRadius || 5 + console.log(i++) } }, watch: { diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 72a338bd..339d7c3d 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -24,80 +24,73 @@ -
-
-
-
Preview
-
-
- ( ͡° ͜ʖ ͡°) -
-

Content

-
- A bunch of more content and - a nice lil' link - - - - -
- +
+
+
Preview
+
+
+ ( ͡° ͜ʖ ͡°)
+

Content

+
+ A bunch of more content and + a nice lil' link + + + + +
+

{{$t('settings.theme_help')}}

-
- - - +

Basic colors!!

+
+
+ + +
+
+ + +
+
+ +
+
+ +
-
- - - + +

More customs!

+
+
+ + +
+
+ + +
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - -
-
- - - + +

Rainbows!!!

+
+
+ +
+
+ +
+
+ +
+
+ +
@@ -161,7 +154,7 @@ .apply-container, .radius-container, -.color-container, +.color-container > div, .presets-container { display: flex; @@ -176,7 +169,7 @@ flex-direction: column; } -.color-container { +.color-container > div{ flex-wrap: wrap; justify-content: space-between; } @@ -214,14 +207,30 @@ .radius-item, .color-item { min-width: 20em; + margin: 5px 6px 0 0; display:flex; + flex-direction: column; flex: 1 1 0; - align-items: baseline; - margin: 5px 6px 5px 0; + + &:nth-child(2n+1) { + margin-right: 7px; + + } + + .color, .opacity { + display:flex; + align-items: baseline; + } label { color: var(--faint, $fallback--faint); } + .opacity-control { + margin-top: 5px; + height: 12px; + line-height: 12px; + font-size: 12px; + } } .radius-item { @@ -243,44 +252,19 @@ margin-left: 4px; } -.theme-color-in { - min-width: 4em; -} - .theme-radius-in { min-width: 1em; } -.theme-radius-in, -.theme-color-in { +.theme-radius-in { max-width: 7em; flex: 1; } -.theme-radius-lb, -.theme-color-lb { - flex: 2; - min-width: 7em; -} - .theme-radius-lb{ max-width: 50em; } -.theme-color-lb { - max-width: 10em; -} - -.theme-color-cl { - padding: 1px; - max-width: 8em; - height: 100%; - flex: 0; - min-width: 2em; - cursor: pointer; - max-height: 29px; -} - .theme-preview-content { padding: 20px; } diff --git a/src/lib/persisted_state.js b/src/lib/persisted_state.js index 006107e2..e55b3b79 100644 --- a/src/lib/persisted_state.js +++ b/src/lib/persisted_state.js @@ -73,6 +73,7 @@ export default function createPersistedState ({ loaded = true } catch (e) { console.log("Couldn't load state") + console.error(e) loaded = true } }) diff --git a/src/services/color_convert/color_convert.js b/src/services/color_convert/color_convert.js index 13dd8979..efb43327 100644 --- a/src/services/color_convert/color_convert.js +++ b/src/services/color_convert/color_convert.js @@ -1,6 +1,10 @@ import { map } from 'lodash' const rgb2hex = (r, g, b) => { + console.log(r) + if (typeof r === 'object') { + ({ r, g, b } = r) + } [r, g, b] = map([r, g, b], (val) => { val = Math.ceil(val) val = val < 0 ? 0 : val @@ -27,8 +31,16 @@ const rgbstr2hex = (rgb) => { return `#${((Number(rgb[0]) << 16) + (Number(rgb[1]) << 8) + Number(rgb[2])).toString(16)}` } +const mixrgb = (a, b) => { + return Object.keys(a).reduce((acc, k) => { + acc[k] = (a[k] + b[k]) / 2 + return acc + }, {}) +} + export { rgb2hex, hex2rgb, + mixrgb, rgbstr2hex } diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 493d444e..72782594 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -1,5 +1,6 @@ import { times } from 'lodash' -import { rgb2hex, hex2rgb } from '../color_convert/color_convert.js' +import { brightness, invertLightness, convert } from 'chromatism' +import { rgb2hex, hex2rgb, mixrgb } from '../color_convert/color_convert.js' // While this is not used anymore right now, I left it in if we want to do custom // styles that aren't just colors, so user can pick from a few different distinct @@ -53,7 +54,23 @@ const setStyle = (href, commit) => { cssEl.addEventListener('load', setDynamic) } -const setColors = (col, commit) => { +const rgb2rgba = function (rgba) { + return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})` +} + +const getTextColor = function (bg, text) { + const bgIsLight = convert(bg).hsl.l > 50 + const textIsLight = convert(text).hsl.l > 50 + + if ((bgIsLight && textIsLight) || (!bgIsLight && !textIsLight)) { + const base = typeof text.a !== 'undefined' ? { a: text.a } : {} + return Object.assign(base, invertLightness(text).rgb) + } + return text +} + +const setColors = (input, commit) => { + const { colorRules, radiiRules, col } = generatePreset(input) const head = document.head const body = document.body body.style.display = 'none' @@ -62,51 +79,83 @@ const setColors = (col, commit) => { head.appendChild(styleEl) const styleSheet = styleEl.sheet - const isDark = (col.text.r + col.text.g + col.text.b) > (col.bg.r + col.bg.g + col.bg.b) - let colors = {} - let radii = {} - - const mod = isDark ? -10 : 10 - - colors.bg = rgb2hex(col.bg.r, col.bg.g, col.bg.b) // background - colors.lightBg = rgb2hex((col.bg.r + col.fg.r) / 2, (col.bg.g + col.fg.g) / 2, (col.bg.b + col.fg.b) / 2) // hilighted bg - colors.btn = rgb2hex(col.fg.r, col.fg.g, col.fg.b) // panels & buttons - colors.input = `rgba(${col.fg.r}, ${col.fg.g}, ${col.fg.b}, .5)` - colors.border = rgb2hex(col.fg.r - mod, col.fg.g - mod, col.fg.b - mod) // borders - colors.faint = `rgba(${col.text.r}, ${col.text.g}, ${col.text.b}, .5)` - colors.fg = rgb2hex(col.text.r, col.text.g, col.text.b) // text - colors.lightFg = rgb2hex(col.text.r - mod * 5, col.text.g - mod * 5, col.text.b - mod * 5) // strong text - - colors['base07'] = rgb2hex(col.text.r - mod * 2, col.text.g - mod * 2, col.text.b - mod * 2) - - colors.link = rgb2hex(col.link.r, col.link.g, col.link.b) // links - colors.icon = rgb2hex((col.bg.r + col.text.r) / 2, (col.bg.g + col.text.g) / 2, (col.bg.b + col.text.b) / 2) // icons - - colors.cBlue = col.cBlue && rgb2hex(col.cBlue.r, col.cBlue.g, col.cBlue.b) - colors.cRed = col.cRed && rgb2hex(col.cRed.r, col.cRed.g, col.cRed.b) - colors.cGreen = col.cGreen && rgb2hex(col.cGreen.r, col.cGreen.g, col.cGreen.b) - colors.cOrange = col.cOrange && rgb2hex(col.cOrange.r, col.cOrange.g, col.cOrange.b) - - colors.cAlertRed = col.cRed && `rgba(${col.cRed.r}, ${col.cRed.g}, ${col.cRed.b}, .5)` - - radii.btnRadius = col.btnRadius - radii.inputRadius = col.inputRadius - radii.panelRadius = col.panelRadius - radii.avatarRadius = col.avatarRadius - radii.avatarAltRadius = col.avatarAltRadius - radii.tooltipRadius = col.tooltipRadius - radii.attachmentRadius = col.attachmentRadius - styleSheet.toString() - styleSheet.insertRule(`body { ${Object.entries(colors).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}`).join(';')} }`, 'index-max') - styleSheet.insertRule(`body { ${Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}px`).join(';')} }`, 'index-max') + styleSheet.insertRule(`body { ${colorRules} }`, 'index-max') + styleSheet.insertRule(`body { ${radiiRules} }`, 'index-max') body.style.display = 'initial' - commit('setOption', { name: 'colors', value: colors }) - commit('setOption', { name: 'radii', value: radii }) + // commit('setOption', { name: 'colors', value: htmlColors }) + // commit('setOption', { name: 'radii', value: radii }) commit('setOption', { name: 'customTheme', value: col }) } +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 colors = {} + + const col = Object.entries(input.colors || input).reduce((acc, [k, v]) => { + if (typeof v === 'object') { + acc[k] = v + } else { + acc[k] = hex2rgb(v) + } + return acc + }, {}) + + colors.fg = col.fg || col.text // text + colors.text = col.fg || col.text // text + colors.lightFg = col.fg || col.text // text + + colors.bg = col.bg // background + colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb // hilighted bg + console.log(colors.bg) + console.log(colors.lightBg) + + colors.btn = col.btn || { r: 0, g: 0, b: 0 } + colors.btnText = getTextColor(colors.btn, colors.text) + + colors.panel = col.panel || col.btn + colors.panelText = getTextColor(colors.panel, colors.text) + + colors.topBar = col.topBar || col.btn + colors.topBarText = getTextColor(colors.topBar, colors.text) + + colors.input = col.input || Object.assign({ a: 0.5 }, col.btn) + colors.border = col.btn // borders + colors.faint = col.faint || Object.assign({ a: 0.5 }, col.text) + + colors.link = col.link // links + colors.icon = mixrgb(colors.bg, colors.text) // icons + + colors.cBlue = col.cBlue + colors.cRed = col.cRed + colors.cGreen = col.cGreen + colors.cOrange = col.cOrange + + colors.cAlertRed = col.cAlertRed || Object.assign({ a: 0.5 }, col.cRed) + + const htmlColors = Object.entries(colors) + .reduce((acc, [k, v]) => { + if (!v) return acc + acc[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgb2rgba(v) + return acc + }, {}) + + return { + colorRules: Object.entries(htmlColors).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(';'), + col + } +} + const setPreset = (val, commit) => { window.fetch('/static/styles.json') .then((data) => data.json()) @@ -148,7 +197,8 @@ const setPreset = (val, commit) => { const StyleSetter = { setStyle, setPreset, - setColors + setColors, + generatePreset } export default StyleSetter diff --git a/yarn.lock b/yarn.lock index fdad8b49..0139c714 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1205,6 +1205,10 @@ chokidar@^1.0.0, chokidar@^1.4.1: optionalDependencies: fsevents "^1.0.0" +chromatism@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chromatism/-/chromatism-3.0.0.tgz#a7249d353c1e4f3577e444ac41171c4e2e624b12" + chromedriver@^2.21.2: version "2.35.0" resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-2.35.0.tgz#c103ba2fb3d1671f666058159f5cbaa816902e4d" From fb29e7c73da9520d2d08bae0757bb4ff7803ca11 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 3 Oct 2018 21:21:48 +0300 Subject: [PATCH 002/123] more workings and even less explosions. --- .../style_switcher/style_switcher.js | 110 ++++++++++-------- .../style_switcher/style_switcher.vue | 64 +++++++--- src/i18n/en.json | 1 + src/services/color_convert/color_convert.js | 7 +- src/services/style_setter/style_setter.js | 18 ++- 5 files changed, 124 insertions(+), 76 deletions(-) diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index 5f76c038..f74337fd 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -9,17 +9,27 @@ export default { availableStyles: [], selected: this.$store.state.config.theme, invalidThemeImported: false, - bgColorLocal: '', - bgOpacityLocal: 0, - btnColorLocal: '', - btnOpacityLocal: '', textColorLocal: '', linkColorLocal: '', + bgColorLocal: '', + bgOpacityLocal: undefined, + + btnColorLocal: '', + btnTextColorLocal: undefined, + btnOpacityLocal: undefined, + + inputColorLocal: undefined, + inputTextColorLocal: undefined, + inputOpacityLocal: undefined, + panelColorLocal: undefined, + panelTextColorLocal: undefined, panelOpacityLocal: undefined, + topBarColorLocal: undefined, + topBarTextColorLocal: undefined, topBarOpacityLocal: undefined, redColorLocal: '', @@ -49,6 +59,9 @@ export default { this.normalizeLocalState(this.$store.state.config.customTheme) }, computed: { + selectedVersion () { + return Array.isArray(this.selected) ? 1 : 2 + }, currentTheme () { return { colors: { @@ -76,8 +89,11 @@ export default { }, previewRules () { try { - const generated = StyleSetter.generatePreset(this.currentTheme.colors) - return [generated.colorRules, generated.radiiRules].join(';') + if (!this.currentTheme.colors.bg) { + return '' + } + const generated = StyleSetter.generatePreset(this.currentTheme) + return [generated.colorRules, generated.radiiRules, 'color: var(--text)'].join(';') } catch (e) { console.error('CATCH') console.error(e) @@ -93,9 +109,8 @@ export default { exportCurrentTheme () { const stringified = JSON.stringify({ // To separate from other random JSON files and possible future theme formats - _pleroma_theme_version: 1, - colors: this.$store.state.config.colors, - radii: this.$store.state.config.radii + _pleroma_theme_version: 2, + theme: this.currentTheme }, null, 2) // Pretty-print and indent with 2 spaces // Create an invisible link with a data url and simulate a click @@ -123,7 +138,9 @@ export default { try { const parsed = JSON.parse(target.result) if (parsed._pleroma_theme_version === 1) { - this.normalizeLocalState(parsed.colors, parsed.radii) + this.normalizeLocalState(parsed, 1) + } else if (parsed._pleroma_theme_version === 2) { + this.normalizeLocalState(parsed.theme) } else { // A theme from the future, spooky this.invalidThemeImported = true @@ -162,67 +179,68 @@ export default { }) }, - normalizeLocalState (input) { + clearV1 () { + this.panelColorLocal = undefined + this.topBarColorLocal = undefined + this.btnTextColorLocal = undefined + this.btnOpacityLocal = undefined + + this.inputColorLocal = undefined + this.inputTextColorLocal = undefined + this.inputOpacityLocal = undefined + + this.panelColorLocal = undefined + this.panelTextColorLocal = undefined + this.panelOpacityLocal = undefined + + this.topBarColorLocal = undefined + this.topBarTextColorLocal = undefined + this.topBarOpacityLocal = undefined + }, + + normalizeLocalState (input, version = 2) { const colors = input.colors || input const radii = input.radii || input - let i = 0 - console.log('BENIS') - console.log(colors) - console.log(i++) this.bgColorLocal = rgb2hex(colors.bg) - console.log(i++) this.btnColorLocal = rgb2hex(colors.btn) - console.log(i++) this.textColorLocal = rgb2hex(colors.text || colors.fg) - console.log(i++) this.linkColorLocal = rgb2hex(colors.link) - console.log(i++) - this.panelColorLocal = colors.panel ? rgb2hex(colors.panel) : undefined - console.log(i++) - this.topBarColorLocal = colors.topBad ? rgb2hex(colors.topBar) : undefined - console.log(i++) + if (version === 1) { + this.clearV1() + } + + this.panelColorLocal = rgb2hex(colors.panel) + this.topBarColorLocal = rgb2hex(colors.topBar) this.redColorLocal = rgb2hex(colors.cRed) - console.log(i++) - console.log('red') - console.log(colors.cRed) - console.log(this.redColorLocal) this.blueColorLocal = rgb2hex(colors.cBlue) - console.log(i++) - console.log('blue', this.blueColorLocal, colors.cBlue) this.greenColorLocal = rgb2hex(colors.cGreen) - console.log(i++) this.orangeColorLocal = rgb2hex(colors.cOrange) - console.log(i++) this.btnRadiusLocal = radii.btnRadius || 4 - console.log(i++) this.inputRadiusLocal = radii.inputRadius || 4 - console.log(i++) this.panelRadiusLocal = radii.panelRadius || 10 - console.log(i++) this.avatarRadiusLocal = radii.avatarRadius || 5 - console.log(i++) this.avatarAltRadiusLocal = radii.avatarAltRadius || 50 - console.log(i++) this.tooltipRadiusLocal = radii.tooltipRadius || 2 - console.log(i++) this.attachmentRadiusLocal = radii.attachmentRadius || 5 - console.log(i++) } }, watch: { selected () { - this.bgColorLocal = this.selected[1] - this.btnColorLocal = this.selected[2] - this.textColorLocal = this.selected[3] - this.linkColorLocal = this.selected[4] - this.redColorLocal = this.selected[5] - this.greenColorLocal = this.selected[6] - this.blueColorLocal = this.selected[7] - this.orangeColorLocal = this.selected[8] + if (this.selectedVersion === 1) { + this.clearV1(); + this.bgColorLocal = this.selected[1] + this.btnColorLocal = this.selected[2] + this.textColorLocal = this.selected[3] + this.linkColorLocal = this.selected[4] + this.redColorLocal = this.selected[5] + this.greenColorLocal = this.selected[6] + this.blueColorLocal = this.selected[7] + this.orangeColorLocal = this.selected[8] + } } } } diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 339d7c3d..521683be 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -52,44 +52,65 @@
+ +
- + + +
- + +
- + + +
+
+

Alert opacity

+

More customs!

- +

Panel header

+ +
- +

Top bar

+ -
-
- -

Rainbows!!!

-
-
- + +
- +

Inputs

+ + +
- +

Buttons

+ + +
- +

Borders

+ + +
+
+

Faint text

+ +
@@ -212,7 +233,10 @@ flex-direction: column; flex: 1 1 0; - &:nth-child(2n+1) { + &.wide { + min-width: 60% + } + &:not(.wide):nth-child(2n+1) { margin-right: 7px; } @@ -222,14 +246,16 @@ align-items: baseline; } + h4 { + margin-top: 1em; + } + label { color: var(--faint, $fallback--faint); } .opacity-control { margin-top: 5px; - height: 12px; - line-height: 12px; - font-size: 12px; + margin-bottom: 5px; } } diff --git a/src/i18n/en.json b/src/i18n/en.json index 8c7360e9..d825dcc1 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -108,6 +108,7 @@ "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", diff --git a/src/services/color_convert/color_convert.js b/src/services/color_convert/color_convert.js index efb43327..ae5d5a31 100644 --- a/src/services/color_convert/color_convert.js +++ b/src/services/color_convert/color_convert.js @@ -1,7 +1,12 @@ import { map } from 'lodash' const rgb2hex = (r, g, b) => { - console.log(r) + if (r === null || typeof r === 'undefined') { + return undefined + } + if (r[0] === '#') { + return r + } if (typeof r === 'object') { ({ r, g, b } = r) } diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 72782594..2a803a4f 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -70,7 +70,7 @@ const getTextColor = function (bg, text) { } const setColors = (input, commit) => { - const { colorRules, radiiRules, col } = generatePreset(input) + const { colorRules, radiiRules } = generatePreset(input) const head = document.head const body = document.body body.style.display = 'none' @@ -86,10 +86,11 @@ const setColors = (input, commit) => { // commit('setOption', { name: 'colors', value: htmlColors }) // commit('setOption', { name: 'radii', value: radii }) - commit('setOption', { name: 'customTheme', value: col }) + commit('setOption', { name: 'customTheme', value: input }) } const generatePreset = (input) => { + console.log(input) const radii = input.radii || { btnRadius: input.btnRadius, inputRadius: input.inputRadius, @@ -116,8 +117,6 @@ const generatePreset = (input) => { colors.bg = col.bg // background colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb // hilighted bg - console.log(colors.bg) - console.log(colors.lightBg) colors.btn = col.btn || { r: 0, g: 0, b: 0 } colors.btnText = getTextColor(colors.btn, colors.text) @@ -151,8 +150,7 @@ const generatePreset = (input) => { return { colorRules: Object.entries(htmlColors).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(';'), - col + radiiRules: Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}px`).join(';') } } @@ -162,7 +160,7 @@ const setPreset = (val, commit) => { .then((themes) => { const theme = themes[val] ? themes[val] : themes['pleroma-dark'] const bgRgb = hex2rgb(theme[1]) - const fgRgb = hex2rgb(theme[2]) + const btnRgb = hex2rgb(theme[2]) const textRgb = hex2rgb(theme[3]) const linkRgb = hex2rgb(theme[4]) @@ -171,9 +169,9 @@ const setPreset = (val, commit) => { const cBlueRgb = hex2rgb(theme[7] || '#0000FF') const cOrangeRgb = hex2rgb(theme[8] || '#E3FF00') - const col = { + const colors = { bg: bgRgb, - fg: fgRgb, + btn: btnRgb, text: textRgb, link: linkRgb, cRed: cRedRgb, @@ -189,7 +187,7 @@ const setPreset = (val, commit) => { // load config -> set preset -> wait for styles.json to load -> // load persisted state -> set colors -> styles.json loaded -> set colors if (!window.themeLoaded) { - setColors(col, commit) + setColors({ colors }, commit) } }) } From 0a4b07652aa24ea5fcda8f62838ea37f8e8168ef Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 4 Oct 2018 18:16:14 +0300 Subject: [PATCH 003/123] trying to fix transition --- .../style_switcher/style_switcher.js | 67 +++++++++++++++---- .../style_switcher/style_switcher.vue | 18 ++--- src/services/style_setter/style_setter.js | 44 +++++++++--- 3 files changed, 98 insertions(+), 31 deletions(-) diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index f74337fd..7c204bdb 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -16,7 +16,12 @@ export default { bgColorLocal: '', bgOpacityLocal: undefined, - btnColorLocal: '', + fgColorLocal: '', + fgOpacityLocal: undefined, + fgTextColorLocal: undefined, + fgLinkColorLocal: undefined, + + btnColorLocal: undefined, btnTextColorLocal: undefined, btnOpacityLocal: undefined, @@ -30,8 +35,11 @@ export default { topBarColorLocal: undefined, topBarTextColorLocal: undefined, + topBarLinkColorLocal: undefined, topBarOpacityLocal: undefined, + alertOpacityLocal: undefined, + redColorLocal: '', blueColorLocal: '', greenColorLocal: '', @@ -66,7 +74,8 @@ export default { return { colors: { bg: this.bgColorLocal, - fg: this.textColorLocal, + fg: this.fgColorLocal, + text: this.textColorLocal, panel: this.panelColorLocal, topBar: this.topBarColorLocal, btn: this.btnColorLocal, @@ -87,18 +96,26 @@ export default { } } }, - previewRules () { + preview () { try { if (!this.currentTheme.colors.bg) { - return '' + return {} } - const generated = StyleSetter.generatePreset(this.currentTheme) - return [generated.colorRules, generated.radiiRules, 'color: var(--text)'].join(';') + return StyleSetter.generatePreset(this.currentTheme) } catch (e) { console.error('CATCH') console.error(e) - return '' + return {} } + }, + previewTheme () { + if (!this.preview.theme) return { colors: {}, radii: {} } + console.log(this.preview.theme) + return this.preview.theme + }, + previewRules () { + if (!this.preview.colorRules) return '' + return [this.preview.colorRules, this.preview.radiiRules, 'color: var(--text)'].join(';') } }, components: { @@ -140,7 +157,7 @@ export default { if (parsed._pleroma_theme_version === 1) { this.normalizeLocalState(parsed, 1) } else if (parsed._pleroma_theme_version === 2) { - this.normalizeLocalState(parsed.theme) + this.normalizeLocalState(parsed.theme, 2) } else { // A theme from the future, spooky this.invalidThemeImported = true @@ -180,6 +197,10 @@ export default { }, clearV1 () { + this.fgOpacityLocal = undefined + this.fgTextColorLocal = undefined + this.fgLinkColorLocal = undefined + this.panelColorLocal = undefined this.topBarColorLocal = undefined this.btnTextColorLocal = undefined @@ -198,13 +219,35 @@ export default { this.topBarOpacityLocal = undefined }, - normalizeLocalState (input, version = 2) { + /** + * This applies stored theme data onto form. + * @param {Object} input - input data + * @param {Number} version - version of data. 0 means try to guess based on data. + */ + normalizeLocalState (input, version = 0) { const colors = input.colors || input const radii = input.radii || input + if (version === 0) { + if (input.version) version = input.version + // Old v1 naming: fg is text, btn is foreground + if (typeof input.text === 'undefined' && typeof input.fg !== 'undefined') { + version = 1 + } + // New v2 naming: text is text, fg is foreground + if (typeof input.text !== 'undefined' && typeof input.fg !== 'undefined') { + version = 2 + } + } + this.bgColorLocal = rgb2hex(colors.bg) - this.btnColorLocal = rgb2hex(colors.btn) - this.textColorLocal = rgb2hex(colors.text || colors.fg) + if (version === 1) { + this.fgColorLocal = rgb2hex(colors.btn) + this.textColorLocal = rgb2hex(colors.fg) + } else { + this.fgColorLocal = rgb2hex(colors.fg) + this.textColorLocal = rgb2hex(colors.text) + } this.linkColorLocal = rgb2hex(colors.link) if (version === 1) { @@ -231,7 +274,7 @@ export default { watch: { selected () { if (this.selectedVersion === 1) { - this.clearV1(); + this.clearV1() this.bgColorLocal = this.selected[1] this.btnColorLocal = this.selected[2] this.textColorLocal = this.selected[3] diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 521683be..cf1fac92 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -56,9 +56,9 @@
- + - +
@@ -98,19 +98,19 @@

Buttons

- - - + + +

Borders

- - + +

Faint text

- - + +
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 2a803a4f..54f54b4e 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -101,7 +101,6 @@ const generatePreset = (input) => { attachmentRadius: input.attachmentRadius } const colors = {} - const col = Object.entries(input.colors || input).reduce((acc, [k, v]) => { if (typeof v === 'object') { acc[k] = v @@ -111,12 +110,32 @@ const generatePreset = (input) => { return acc }, {}) - colors.fg = col.fg || col.text // text - colors.text = col.fg || col.text // text - colors.lightFg = col.fg || col.text // text + let version = 0 - colors.bg = col.bg // background - colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb // hilighted bg + if (input.version) { + version = input.version + } + // Old v1 naming: fg is text, btn is foreground + if (typeof col.text === 'undefined' && typeof col.fg !== 'undefined') { + version = 1 + } + // New v2 naming: text is text, fg is foreground + if (typeof col.text !== 'undefined' && typeof col.fg !== 'undefined') { + version = 2 + } + + colors.text = version === 1 ? col.fg : col.text + colors.lightText = colors.text + + colors.bg = col.bg + colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb + + colors.fg = version === 1 ? col.btn : col.fg + console.log('BENIN') + console.log(version) + console.log(col) + console.log(colors.text) + colors.fgText = getTextColor(colors.fg, colors.text) colors.btn = col.btn || { r: 0, g: 0, b: 0 } colors.btnText = getTextColor(colors.btn, colors.text) @@ -128,11 +147,11 @@ const generatePreset = (input) => { colors.topBarText = getTextColor(colors.topBar, colors.text) colors.input = col.input || Object.assign({ a: 0.5 }, col.btn) - colors.border = col.btn // borders + colors.border = col.btn colors.faint = col.faint || Object.assign({ a: 0.5 }, col.text) - colors.link = col.link // links - colors.icon = mixrgb(colors.bg, colors.text) // icons + colors.link = col.link + colors.icon = mixrgb(colors.bg, colors.text) colors.cBlue = col.cBlue colors.cRed = col.cRed @@ -150,7 +169,11 @@ const generatePreset = (input) => { return { colorRules: Object.entries(htmlColors).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(';') + radiiRules: Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}px`).join(';'), + theme: { + colors, + radii + } } } @@ -196,6 +219,7 @@ const StyleSetter = { setStyle, setPreset, setColors, + getTextColor, generatePreset } From 5441766c3cba46682227202e91e08c4fbb3e3ac3 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 4 Oct 2018 18:27:27 +0300 Subject: [PATCH 004/123] fix --- .../style_switcher/style_switcher.js | 21 ++------------ src/services/style_setter/style_setter.js | 28 ++++--------------- 2 files changed, 7 insertions(+), 42 deletions(-) diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index 7c204bdb..a1c44be3 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -228,26 +228,9 @@ export default { const colors = input.colors || input const radii = input.radii || input - if (version === 0) { - if (input.version) version = input.version - // Old v1 naming: fg is text, btn is foreground - if (typeof input.text === 'undefined' && typeof input.fg !== 'undefined') { - version = 1 - } - // New v2 naming: text is text, fg is foreground - if (typeof input.text !== 'undefined' && typeof input.fg !== 'undefined') { - version = 2 - } - } - this.bgColorLocal = rgb2hex(colors.bg) - if (version === 1) { - this.fgColorLocal = rgb2hex(colors.btn) - this.textColorLocal = rgb2hex(colors.fg) - } else { - this.fgColorLocal = rgb2hex(colors.fg) - this.textColorLocal = rgb2hex(colors.text) - } + this.fgColorLocal = rgb2hex(colors.fg) + this.textColorLocal = rgb2hex(colors.text) this.linkColorLocal = rgb2hex(colors.link) if (version === 1) { diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 54f54b4e..cfa41b11 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -110,40 +110,22 @@ const generatePreset = (input) => { return acc }, {}) - let version = 0 - - if (input.version) { - version = input.version - } - // Old v1 naming: fg is text, btn is foreground - if (typeof col.text === 'undefined' && typeof col.fg !== 'undefined') { - version = 1 - } - // New v2 naming: text is text, fg is foreground - if (typeof col.text !== 'undefined' && typeof col.fg !== 'undefined') { - version = 2 - } - - colors.text = version === 1 ? col.fg : col.text + colors.text = col.text colors.lightText = colors.text colors.bg = col.bg colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb - colors.fg = version === 1 ? col.btn : col.fg - console.log('BENIN') - console.log(version) - console.log(col) - console.log(colors.text) + colors.fg = col.fg colors.fgText = getTextColor(colors.fg, colors.text) - colors.btn = col.btn || { r: 0, g: 0, b: 0 } + colors.btn = col.btn || col.fg colors.btnText = getTextColor(colors.btn, colors.text) - colors.panel = col.panel || col.btn + colors.panel = col.panel || col.fg colors.panelText = getTextColor(colors.panel, colors.text) - colors.topBar = col.topBar || col.btn + colors.topBar = col.topBar || col.fg colors.topBarText = getTextColor(colors.topBar, colors.text) colors.input = col.input || Object.assign({ a: 0.5 }, col.btn) From 96804d42f0f6aa6af85295933af6fd267b19e473 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 7 Oct 2018 19:59:22 +0300 Subject: [PATCH 005/123] Some themeing is working!! --- src/App.scss | 56 ++++----- src/_variables.scss | 7 +- src/components/chat_panel/chat_panel.vue | 4 +- src/components/color_input/color_input.vue | 84 +++++++++++++ .../notifications/notifications.scss | 7 +- .../opacity_input/opacity_input.vue | 75 ++++++++++++ .../post_status_form/post_status_form.vue | 12 +- src/components/settings/settings.vue | 2 +- src/components/status/status.vue | 4 +- .../style_switcher/style_switcher.js | 113 +++++++++++++----- .../style_switcher/style_switcher.vue | 40 ++++--- src/components/tab_switcher/tab_switcher.scss | 8 +- src/components/timeline/timeline.vue | 10 +- .../user_card_content/user_card_content.vue | 16 +-- src/services/style_setter/style_setter.js | 28 +++-- 15 files changed, 346 insertions(+), 120 deletions(-) create mode 100644 src/components/color_input/color_input.vue create mode 100644 src/components/opacity_input/opacity_input.vue diff --git a/src/App.scss b/src/App.scss index 1119caf2..c91b6a61 100644 --- a/src/App.scss +++ b/src/App.scss @@ -36,8 +36,8 @@ body { font-family: sans-serif; font-size: 14px; margin: 0; - color: $fallback--fg; - color: var(--fg, $fallback--fg); + color: $fallback--text; + color: var(--text, $fallback--text); max-width: 100vw; overflow-x: hidden; } @@ -50,10 +50,10 @@ a { button { user-select: none; - color: $fallback--fg; - color: var(--btnText, $fallback--fg); - background-color: $fallback--btn; - background-color: var(--btn, $fallback--btn); + color: $fallback--text; + color: var(--btnText, $fallback--text); + background-color: $fallback--fg; + background-color: var(--btn, $fallback--fg); border: none; border-radius: $fallback--btnRadius; border-radius: var(--btnRadius, $fallback--btnRadius); @@ -102,10 +102,10 @@ input, textarea, .select { border-bottom: 1px solid rgba(255, 255, 255, 0.2); border-top: 1px solid rgba(0, 0, 0, 0.2); box-shadow: 0px 0px 2px black inset; - background-color: $fallback--input; - background-color: var(--input, $fallback--input); - color: $fallback--lightFg; - color: var(--lightFg, $fallback--lightFg); + background-color: $fallback--fg; + background-color: var(--input, $fallback--fg); + color: $fallback--lightText; + color: var(--inputText, $fallback--lightText); font-family: sans-serif; font-size: 14px; padding: 8px 7px; @@ -122,8 +122,8 @@ input, textarea, .select { bottom: 0; right: 5px; height: 100%; - color: $fallback--fg; - color: var(--fg, $fallback--fg); + color: $fallback--text; + color: var(--text, $fallback--text); line-height: 29px; z-index: 0; pointer-events: none; @@ -136,8 +136,8 @@ input, textarea, .select { background: transparent; border: none; margin: 0; - color: $fallback--fg; - color: var(--fg, $fallback--fg); + color: $fallback--text; + color: var(--text, $fallback--text); padding: 4px 2em 3px 3px; width: 100%; z-index: 1; @@ -149,8 +149,8 @@ input, textarea, .select { &[type=checkbox] { display: none; &:checked + label::before { - color: $fallback--fg; - color: var(--fg, $fallback--fg); + color: $fallback--text; + color: var(--text, $fallback--text); } &:disabled, { @@ -172,8 +172,8 @@ input, textarea, .select { border-top: 1px solid rgba(0, 0, 0, 0.2); box-shadow: 0px 0px 2px black inset; margin-right: .5em; - background-color: $fallback--input; - background-color: var(--input, $fallback--input); + background-color: $fallback--fg; + background-color: var(--input, $fallback--fg); vertical-align: top; text-align: center; line-height: 1.1em; @@ -187,8 +187,8 @@ input, textarea, .select { } option { - color: $fallback--fg; - color: var(--fg, $fallback--fg); + color: $fallback--text; + color: var(--text, $fallback--text); background-color: $fallback--bg; background-color: var(--bg, $fallback--bg); } @@ -279,9 +279,9 @@ nav { margin: auto; height: 50px; - a i { + a, a i { color: $fallback--link; - color: var(--link, $fallback--link); + color: var(--topBarLink, $fallback--link); } } } @@ -331,8 +331,8 @@ main-router { text-align: left; line-height: 28px; color: var(--panelText); - background-color: $fallback--btn; - background-color: var(--panel, $fallback--btn); + background-color: $fallback--fg; + background-color: var(--panel, $fallback--fg); align-items: baseline; .title { @@ -389,8 +389,8 @@ main-router { nav { z-index: 1000; color: var(--topBarText); - background-color: $fallback--btn; - background-color: var(--topBar, $fallback--btn); + background-color: $fallback--fg; + background-color: var(--topBar, $fallback--fg); color: $fallback--faint; color: var(--faint, $fallback--faint); box-shadow: 0px 0px 4px rgba(0,0,0,.6); @@ -518,8 +518,8 @@ nav { cursor: pointer; .selected { - color: $fallback--lightFg; - color: var(--lightFg, $fallback--lightFg); + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); } .text-format { diff --git a/src/_variables.scss b/src/_variables.scss index b5222a6a..0f73e929 100644 --- a/src/_variables.scss +++ b/src/_variables.scss @@ -3,14 +3,13 @@ $main-background: white; $darkened-background: whitesmoke; $fallback--bg: #121a24; -$fallback--btn: #182230; -$fallback--input: #182230; +$fallback--fg: #182230; $fallback--faint: rgba(185, 185, 186, .5); -$fallback--fg: #b9b9ba; +$fallback--text: #b9b9ba; $fallback--link: #d8a070; $fallback--icon: #666; $fallback--lightBg: rgb(21, 30, 42); -$fallback--lightFg: #b9b9ba; +$fallback--lightText: #b9b9ba; $fallback--border: #222; $fallback--cRed: #ff0000; $fallback--cBlue: #0095ff; diff --git a/src/components/chat_panel/chat_panel.vue b/src/components/chat_panel/chat_panel.vue index 30070d3e..f174319a 100644 --- a/src/components/chat_panel/chat_panel.vue +++ b/src/components/chat_panel/chat_panel.vue @@ -55,8 +55,8 @@ .chat-heading { cursor: pointer; .icon-comment-empty { - color: $fallback--fg; - color: var(--fg, $fallback--fg); + color: $fallback--text; + color: var(--text, $fallback--text); } } diff --git a/src/components/color_input/color_input.vue b/src/components/color_input/color_input.vue new file mode 100644 index 00000000..49d9bed7 --- /dev/null +++ b/src/components/color_input/color_input.vue @@ -0,0 +1,84 @@ + + + + + diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index a137ccd5..a98c2549 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -22,8 +22,8 @@ } .loadmore-error { - color: $fallback--fg; - color: var(--fg, $fallback--fg); + color: $fallback--text; + color: var(--text, $fallback--text); } .unseen { @@ -90,6 +90,9 @@ padding: 0.25em 0; color: $fallback--faint; color: var(--faint, $fallback--faint); + a { + color: var(--faintLink); + } } padding: 0; .media-body { diff --git a/src/components/opacity_input/opacity_input.vue b/src/components/opacity_input/opacity_input.vue new file mode 100644 index 00000000..cfe6de21 --- /dev/null +++ b/src/components/opacity_input/opacity_input.vue @@ -0,0 +1,75 @@ + + + + + diff --git a/src/components/post_status_form/post_status_form.vue b/src/components/post_status_form/post_status_form.vue index 42e9c65c..4514e79f 100644 --- a/src/components/post_status_form/post_status_form.vue +++ b/src/components/post_status_form/post_status_form.vue @@ -153,8 +153,8 @@ padding-bottom: 0; margin-left: $fallback--attachmentRadius; margin-left: var(--attachmentRadius, $fallback--attachmentRadius); - background-color: $fallback--btn; - background-color: var(--btn, $fallback--btn); + background-color: $fallback--fg; + background-color: var(--fg, $fallback--fg); border-bottom-left-radius: 0; border-bottom-right-radius: 0; } @@ -261,8 +261,8 @@ min-width: 75%; background: $fallback--bg; background: var(--bg, $fallback--bg); - color: $fallback--lightFg; - color: var(--lightFg, $fallback--lightFg); + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); } .autocomplete { @@ -291,8 +291,8 @@ } &.highlighted { - background-color: $fallback--btn; - background-color: var(--btn, $fallback--btn); + background-color: $fallback--fg; + background-color: var(--fg, $fallback--fg); } } } diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index eebb2cb7..990d1f0d 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -159,7 +159,7 @@ @import '../../_variables.scss'; .setting-item { - border-bottom: 2px solid var(--btn, $fallback--btn); + border-bottom: 2px solid var(--fg, $fallback--fg); margin: 1em 1em 1.4em; padding-bottom: 1.4em; diff --git a/src/components/status/status.vue b/src/components/status/status.vue index eb521280..57a007d9 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -284,8 +284,8 @@ margin-left: 0.2em; } a:hover i { - color: $fallback--fg; - color: var(--fg, $fallback--fg); + color: $fallback--text; + color: var(--text, $fallback--text); } } diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index a1c44be3..203ca18a 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -31,6 +31,7 @@ export default { panelColorLocal: undefined, panelTextColorLocal: undefined, + panelFaintColorLocal: undefined, panelOpacityLocal: undefined, topBarColorLocal: undefined, @@ -40,10 +41,17 @@ export default { alertOpacityLocal: undefined, - redColorLocal: '', - blueColorLocal: '', - greenColorLocal: '', - orangeColorLocal: '', + borderColorLocal: undefined, + borderOpacityLocal: undefined, + + faintColorLocal: undefined, + faintOpacityLocal: undefined, + faintLinkColorLocal: undefined, + + cRedColorLocal: '', + cBlueColorLocal: '', + cGreenColorLocal: '', + cOrangeColorLocal: '', btnRadiusLocal: '', inputRadiusLocal: '', @@ -74,16 +82,35 @@ export default { return { colors: { bg: this.bgColorLocal, - fg: this.fgColorLocal, text: this.textColorLocal, - panel: this.panelColorLocal, - topBar: this.topBarColorLocal, - btn: this.btnColorLocal, link: this.linkColorLocal, - cRed: this.redColorLocal, - cBlue: this.blueColorLocal, - cGreen: this.greenColorLocal, - cOrange: this.orangeColorLocal + + 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, + + faint: this.faintColorLocal, + faintLink: this.faintLinkColorLocal, + border: this.borderColorLocal, + + cRed: this.cRedColorLocal, + cBlue: this.cBlueColorLocal, + cGreen: this.cGreenColorLocal, + cOrange: this.cOrangeColorLocal }, radii: { btnRadius: this.btnRadiusLocal, @@ -197,12 +224,12 @@ export default { }, clearV1 () { + this.bgOpacityLocal = undefined this.fgOpacityLocal = undefined this.fgTextColorLocal = undefined this.fgLinkColorLocal = undefined - this.panelColorLocal = undefined - this.topBarColorLocal = undefined + this.btnColorLocal = undefined this.btnTextColorLocal = undefined this.btnOpacityLocal = undefined @@ -216,7 +243,17 @@ export default { this.topBarColorLocal = undefined this.topBarTextColorLocal = undefined + this.topBarLinkColorLocal = undefined this.topBarOpacityLocal = undefined + + this.alertOpacityLocal = undefined + + this.borderColorLocal = undefined + this.borderOpacityLocal = undefined + + this.faintColorLocal = undefined + this.faintOpacityLocal = undefined + this.faintLinkColorLocal = undefined }, /** @@ -228,22 +265,42 @@ export default { const colors = input.colors || input const radii = input.radii || input - this.bgColorLocal = rgb2hex(colors.bg) - this.fgColorLocal = rgb2hex(colors.fg) - this.textColorLocal = rgb2hex(colors.text) - this.linkColorLocal = rgb2hex(colors.link) - - if (version === 1) { - this.clearV1() + if (version === 0) { + if (input.version) version = input.version + // Old v1 naming: fg is text, btn is foreground + if (typeof colors.text === 'undefined' && typeof colors.fg !== 'undefined') { + version = 1 + } + // New v2 naming: text is text, fg is foreground + if (typeof colors.text !== 'undefined' && typeof colors.fg !== 'undefined') { + version = 2 + } } - this.panelColorLocal = rgb2hex(colors.panel) - this.topBarColorLocal = rgb2hex(colors.topBar) + console.log('BENIS') + console.log(version) + // Stuff that differs between V1 and V2 + if (version === 1) { + console.log(colors) + this.fgColorLocal = rgb2hex(colors.btn) + this.textColorLocal = rgb2hex(colors.fg) + } - this.redColorLocal = rgb2hex(colors.cRed) - this.blueColorLocal = rgb2hex(colors.cBlue) - this.greenColorLocal = rgb2hex(colors.cGreen) - this.orangeColorLocal = rgb2hex(colors.cOrange) + const keys = new Set(version !== 1 ? Object.keys(colors) : []) + if (version === 1) { + // V1 ignores the rest + this.clearV1() + keys + .add('bg') + .add('link') + .add('cRed') + .add('cBlue') + .add('cGreen') + .add('cOrange') + } + keys.forEach(key => { + this[key + 'ColorLocal'] = rgb2hex(colors[key]) + }) this.btnRadiusLocal = radii.btnRadius || 4 this.inputRadiusLocal = radii.inputRadius || 4 @@ -259,7 +316,7 @@ export default { if (this.selectedVersion === 1) { this.clearV1() this.bgColorLocal = this.selected[1] - this.btnColorLocal = this.selected[2] + this.fgColorLocal = this.selected[2] this.textColorLocal = this.selected[3] this.linkColorLocal = this.selected[4] this.redColorLocal = this.selected[5] diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index cf1fac92..7ddc2d1c 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -58,16 +58,16 @@
- - + +
- - + +
- - + +

Alert opacity

@@ -79,38 +79,40 @@

Panel header

- + - + +

Top bar

- + - - + +

Inputs

- + - +

Buttons

- + - +

Borders

- - + +

Faint text

- - + + +
diff --git a/src/components/tab_switcher/tab_switcher.scss b/src/components/tab_switcher/tab_switcher.scss index 374a19c5..578caec2 100644 --- a/src/components/tab_switcher/tab_switcher.scss +++ b/src/components/tab_switcher/tab_switcher.scss @@ -17,8 +17,8 @@ .tab, &::after, &::before { border-bottom: 1px solid; - border-bottom-color: $fallback--btn; - border-bottom-color: var(--btn, $fallback--btn); + border-bottom-color: $fallback--fg; + border-bottom-color: var(--fg, $fallback--fg); } .tab { @@ -28,8 +28,8 @@ &:not(.active) { border-bottom: 1px solid; - border-bottom-color: $fallback--btn; - border-bottom-color: var(--btn, $fallback--btn); + border-bottom-color: $fallback--fg; + border-bottom-color: var(--fg, $fallback--fg); z-index: 4; } diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue index 2dd4376a..77a9a2af 100644 --- a/src/components/timeline/timeline.vue +++ b/src/components/timeline/timeline.vue @@ -61,12 +61,12 @@ opacity: 0.8; background-color: transparent; color: $fallback--faint; - color: var(--faint, $fallback--faint); + color: var(--panelFaint, $fallback--faint); } .loadmore-error { - color: $fallback--fg; - color: var(--fg, $fallback--fg); + color: $fallback--text; + color: var(--text, $fallback--text); } } @@ -79,7 +79,7 @@ border-color: var(--border, $fallback--border); padding: 10px; z-index: 1; - background-color: $fallback--btn; - background-color: var(--btn, $fallback--btn); + background-color: $fallback--fg; + background-color: var(--fg, $fallback--fg); } diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue index 59358040..f1b54fad 100644 --- a/src/components/user_card_content/user_card_content.vue +++ b/src/components/user_card_content/user_card_content.vue @@ -138,8 +138,8 @@ } .user-info { - color: $fallback--lightFg; - color: var(--lightFg, $fallback--lightFg); + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); padding: 0 16px; .container { @@ -173,8 +173,8 @@ } .usersettings { - color: $fallback--lightFg; - color: var(--lightFg, $fallback--lightFg); + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); opacity: .8; } @@ -193,8 +193,8 @@ } .user-screen-name { - color: $fallback--lightFg; - color: var(--lightFg, $fallback--lightFg); + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); display: inline-block; font-weight: light; font-size: 15px; @@ -269,8 +269,8 @@ padding: .5em 1.5em 0em 1.5em; text-align: center; justify-content: space-between; - color: $fallback--lightFg; - color: var(--lightFg, $fallback--lightFg); + color: $fallback--lightText; + color: var(--lightText, $fallback--lightText); &.clickable { .user-count { diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index cfa41b11..cc408933 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -112,27 +112,33 @@ const generatePreset = (input) => { colors.text = col.text colors.lightText = colors.text + colors.link = col.link + colors.border = col.border || col.fg + colors.faint = col.faint || col.text colors.bg = col.bg colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb colors.fg = col.fg - colors.fgText = getTextColor(colors.fg, colors.text) + colors.fgText = col.fgText || getTextColor(colors.fg, colors.text) + colors.fgLink = col.fgLink || getTextColor(colors.fg, colors.link) colors.btn = col.btn || col.fg - colors.btnText = getTextColor(colors.btn, colors.text) + colors.btnText = col.btnText || getTextColor(colors.btn, colors.fgText) + + colors.input = col.input || col.fg + colors.inputText = col.inputText || getTextColor(colors.input, colors.fgText) colors.panel = col.panel || col.fg - colors.panelText = getTextColor(colors.panel, colors.text) + colors.panelText = col.panelText || getTextColor(colors.panel, colors.fgText) + colors.panelFaint = col.panelFaint || getTextColor(colors.panel, colors.faint) colors.topBar = col.topBar || col.fg - colors.topBarText = getTextColor(colors.topBar, colors.text) + colors.topBarText = col.topBarText || getTextColor(colors.topBar, colors.fgText) + colors.topBarLink = col.topBarLink || getTextColor(colors.topBar, colors.fgLink) - colors.input = col.input || Object.assign({ a: 0.5 }, col.btn) - colors.border = col.btn - colors.faint = col.faint || Object.assign({ a: 0.5 }, col.text) + colors.faintLink = col.faintLink || col.link - colors.link = col.link colors.icon = mixrgb(colors.bg, colors.text) colors.cBlue = col.cBlue @@ -153,7 +159,7 @@ const generatePreset = (input) => { colorRules: Object.entries(htmlColors).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(';'), theme: { - colors, + colors: htmlColors, radii } } @@ -165,7 +171,7 @@ const setPreset = (val, commit) => { .then((themes) => { const theme = themes[val] ? themes[val] : themes['pleroma-dark'] const bgRgb = hex2rgb(theme[1]) - const btnRgb = hex2rgb(theme[2]) + const fgRgb = hex2rgb(theme[2]) const textRgb = hex2rgb(theme[3]) const linkRgb = hex2rgb(theme[4]) @@ -176,7 +182,7 @@ const setPreset = (val, commit) => { const colors = { bg: bgRgb, - btn: btnRgb, + fg: fgRgb, text: textRgb, link: linkRgb, cRed: cRedRgb, From 4d77b0c86bbd711e76e8ed23b6b227332bbea3cf Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 7 Oct 2018 22:03:34 +0300 Subject: [PATCH 006/123] Transparency works without exploding now. All nice. --- .../opacity_input/opacity_input.vue | 19 ++++++- .../style_switcher/style_switcher.js | 28 ++++++---- .../style_switcher/style_switcher.vue | 24 ++++----- src/components/tab_switcher/tab_switcher.scss | 8 +-- src/services/style_setter/style_setter.js | 54 +++++++++++++------ 5 files changed, 87 insertions(+), 46 deletions(-) diff --git a/src/components/opacity_input/opacity_input.vue b/src/components/opacity_input/opacity_input.vue index cfe6de21..09972868 100644 --- a/src/components/opacity_input/opacity_input.vue +++ b/src/components/opacity_input/opacity_input.vue @@ -22,6 +22,16 @@ max="1" min="0" step=".05"> +
@@ -64,12 +74,17 @@ export default { align-self: center; background: none; border: none; - padding: 0; margin: 0; height: auto; box-shadow: none; - min-width: 9em; + min-width: 7em; flex: 1; } + .input-number { + align-self: center; + margin: 0; + min-width: 4em; + flex: 0; + } } diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index 203ca18a..c419a9ce 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -17,7 +17,6 @@ export default { bgOpacityLocal: undefined, fgColorLocal: '', - fgOpacityLocal: undefined, fgTextColorLocal: undefined, fgLinkColorLocal: undefined, @@ -37,7 +36,6 @@ export default { topBarColorLocal: undefined, topBarTextColorLocal: undefined, topBarLinkColorLocal: undefined, - topBarOpacityLocal: undefined, alertOpacityLocal: undefined, @@ -112,6 +110,15 @@ export default { 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, @@ -136,8 +143,7 @@ export default { } }, previewTheme () { - if (!this.preview.theme) return { colors: {}, radii: {} } - console.log(this.preview.theme) + if (!this.preview.theme) return { colors: {}, opacity: {}, radii: {} } return this.preview.theme }, previewRules () { @@ -226,7 +232,6 @@ export default { clearV1 () { this.bgOpacityLocal = undefined this.fgOpacityLocal = undefined - this.fgTextColorLocal = undefined this.fgLinkColorLocal = undefined this.btnColorLocal = undefined @@ -239,6 +244,7 @@ export default { this.panelColorLocal = undefined this.panelTextColorLocal = undefined + this.panelFaintColorLocal = undefined this.panelOpacityLocal = undefined this.topBarColorLocal = undefined @@ -246,8 +252,6 @@ export default { this.topBarLinkColorLocal = undefined this.topBarOpacityLocal = undefined - this.alertOpacityLocal = undefined - this.borderColorLocal = undefined this.borderOpacityLocal = undefined @@ -264,6 +268,7 @@ export default { normalizeLocalState (input, version = 0) { const colors = input.colors || input const radii = input.radii || input + const opacity = input.opacity || input if (version === 0) { if (input.version) version = input.version @@ -277,11 +282,8 @@ export default { } } - console.log('BENIS') - console.log(version) // Stuff that differs between V1 and V2 if (version === 1) { - console.log(colors) this.fgColorLocal = rgb2hex(colors.btn) this.textColorLocal = rgb2hex(colors.fg) } @@ -302,6 +304,7 @@ export default { this[key + 'ColorLocal'] = rgb2hex(colors[key]) }) + // TODO optimize this this.btnRadiusLocal = radii.btnRadius || 4 this.inputRadiusLocal = radii.inputRadius || 4 this.panelRadiusLocal = radii.panelRadius || 10 @@ -309,6 +312,11 @@ export default { this.avatarAltRadiusLocal = radii.avatarAltRadius || 50 this.tooltipRadiusLocal = radii.tooltipRadius || 2 this.attachmentRadiusLocal = radii.attachmentRadius || 5 + + Object.entries(opacity).forEach(([k, v]) => { + if (typeof v === 'undefined' || v === null || Number.isNaN(v)) return + this[k + 'OpacityLocal'] = v + }) } }, watch: { diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 7ddc2d1c..1b00603c 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -51,13 +51,12 @@
- +
-
@@ -71,7 +70,7 @@

Alert opacity

- +
@@ -80,39 +79,38 @@

Panel header

- +

Top bar

-

Inputs

- +

Buttons

- +

Borders

- +

Faint text

- - - + + +
@@ -255,10 +253,6 @@ label { color: var(--faint, $fallback--faint); } - .opacity-control { - margin-top: 5px; - margin-bottom: 5px; - } } .radius-item { diff --git a/src/components/tab_switcher/tab_switcher.scss b/src/components/tab_switcher/tab_switcher.scss index 578caec2..6f3f9f27 100644 --- a/src/components/tab_switcher/tab_switcher.scss +++ b/src/components/tab_switcher/tab_switcher.scss @@ -17,8 +17,8 @@ .tab, &::after, &::before { border-bottom: 1px solid; - border-bottom-color: $fallback--fg; - border-bottom-color: var(--fg, $fallback--fg); + border-bottom-color: $fallback--border; + border-bottom-color: var(--border, $fallback--border); } .tab { @@ -28,8 +28,8 @@ &:not(.active) { border-bottom: 1px solid; - border-bottom-color: $fallback--fg; - border-bottom-color: var(--fg, $fallback--fg); + border-bottom-color: $fallback--border; + border-bottom-color: var(--border, $fallback--border); z-index: 4; } diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index cc408933..4de39f79 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -90,7 +90,6 @@ const setColors = (input, commit) => { } const generatePreset = (input) => { - console.log(input) const radii = input.radii || { btnRadius: input.btnRadius, inputRadius: input.inputRadius, @@ -101,6 +100,12 @@ const generatePreset = (input) => { attachmentRadius: input.attachmentRadius } const colors = {} + const opacity = Object.assign({ + alert: 0.5, + input: 0.5, + faint: 0.5 + }, input.opacity) + const col = Object.entries(input.colors || input).reduce((acc, [k, v]) => { if (typeof v === 'object') { acc[k] = v @@ -110,11 +115,13 @@ const generatePreset = (input) => { return acc }, {}) + const isLightOnDark = convert(col.bg).hsl.l < convert(col.text).hsl.l + const mod = isLightOnDark ? 1 : -1 + colors.text = col.text - colors.lightText = colors.text + colors.lightText = brightness(20 * mod, colors.text).rgb colors.link = col.link - colors.border = col.border || col.fg - colors.faint = col.faint || col.text + colors.faint = col.faint || Object.assign({}, col.text) colors.bg = col.bg colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb @@ -123,21 +130,23 @@ const generatePreset = (input) => { colors.fgText = col.fgText || getTextColor(colors.fg, colors.text) colors.fgLink = col.fgLink || getTextColor(colors.fg, colors.link) - colors.btn = col.btn || col.fg + colors.border = col.border || brightness(20 * mod, colors.fg).rgb + + colors.btn = col.btn || Object.assign({}, col.fg) colors.btnText = col.btnText || getTextColor(colors.btn, colors.fgText) - colors.input = col.input || col.fg - colors.inputText = col.inputText || getTextColor(colors.input, colors.fgText) + colors.input = col.input || Object.assign({}, col.fg) + colors.inputText = col.inputText || getTextColor(colors.input, colors.lightText) - colors.panel = col.panel || col.fg + colors.panel = col.panel || Object.assign({}, col.fg) colors.panelText = col.panelText || getTextColor(colors.panel, colors.fgText) colors.panelFaint = col.panelFaint || getTextColor(colors.panel, colors.faint) - colors.topBar = col.topBar || col.fg + colors.topBar = col.topBar || Object.assign({}, col.fg) colors.topBarText = col.topBarText || getTextColor(colors.topBar, colors.fgText) colors.topBarLink = col.topBarLink || getTextColor(colors.topBar, colors.fgLink) - colors.faintLink = col.faintLink || col.link + colors.faintLink = col.faintLink || Object.assign({}, col.link) colors.icon = mixrgb(colors.bg, colors.text) @@ -146,20 +155,35 @@ const generatePreset = (input) => { colors.cGreen = col.cGreen colors.cOrange = col.cOrange - colors.cAlertRed = col.cAlertRed || Object.assign({ a: 0.5 }, col.cRed) + colors.cAlertRed = col.cAlertRed || Object.assign({}, col.cRed) + + Object.entries(opacity).forEach(([ k, v ]) => { + if (typeof v === 'undefined') return + if (k === 'alert') { + colors.cAlertRed.a = v + return + } + if (k === 'faint') { + colors[k + 'Link'].a = v + colors['panelFaint'].a = v + } + colors[k].a = v + }) const htmlColors = Object.entries(colors) .reduce((acc, [k, v]) => { if (!v) return acc - acc[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgb2rgba(v) + acc.solid[k] = rgb2hex(v) + acc.complete[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgb2rgba(v) return acc - }, {}) + }, { complete: {}, solid: {} }) return { - colorRules: Object.entries(htmlColors).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}`).join(';'), + 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(';'), theme: { - colors: htmlColors, + colors: htmlColors.solid, + opacity, radii } } From 87e98772b09b9b317dee020d22115517635a29c8 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 10 Oct 2018 00:07:28 +0300 Subject: [PATCH 007/123] initial contrast display support --- .../contrast_ratio/contrast_ratio.vue | 64 +++++++++++++++++++ .../style_switcher/style_switcher.js | 37 +++++++++-- .../style_switcher/style_switcher.vue | 6 ++ src/services/color_convert/color_convert.js | 39 ++++++++++- 4 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 src/components/contrast_ratio/contrast_ratio.vue diff --git a/src/components/contrast_ratio/contrast_ratio.vue b/src/components/contrast_ratio/contrast_ratio.vue new file mode 100644 index 00000000..6c4a59b6 --- /dev/null +++ b/src/components/contrast_ratio/contrast_ratio.vue @@ -0,0 +1,64 @@ + + + + + diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index c419a9ce..27efa230 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -1,5 +1,6 @@ -import { rgb2hex } from '../../services/color_convert/color_convert.js' +import { rgb2hex, hex2rgb, getContrastRatio } from '../../services/color_convert/color_convert.js' import ColorInput from '../color_input/color_input.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' @@ -127,7 +128,7 @@ export default { avatarAltRadius: this.avatarAltRadiusLocal, tooltipRadius: this.tooltipRadiusLocal, attachmentRadius: this.attachmentRadiusLocal - } + }, } }, preview () { @@ -143,9 +144,36 @@ export default { } }, previewTheme () { - if (!this.preview.theme) return { colors: {}, opacity: {}, radii: {} } + if (!this.preview.theme) return { colors: {}, opacity: {}, radii: {}, contrast: {} } return this.preview.theme }, + previewContrast () { + if (!this.previewTheme.colors) return {} + const colors = this.previewTheme.colors + const hints = (ratio) => ({ + text: ratio.toPrecision(3) + ':1', + // AA level, AAA level + aa: ratio >= 4.5, + aaa: ratio >= 7, + // same but for 18pt+ texts + laa: ratio >= 3, + laaa: ratio >= 4.5 + }) + + const ratios = { + bgText: getContrastRatio(hex2rgb(colors.bg), hex2rgb(colors.text)), + bgLink: getContrastRatio(hex2rgb(colors.bg), hex2rgb(colors.link)), + + panelText: getContrastRatio(hex2rgb(colors.panel), hex2rgb(colors.panelText)), + + btnText: getContrastRatio(hex2rgb(colors.btn), hex2rgb(colors.btnText)), + + topBarText: getContrastRatio(hex2rgb(colors.topBar), hex2rgb(colors.topBarText)), + topBarLink: getContrastRatio(hex2rgb(colors.topBar), hex2rgb(colors.topBarLink)), + } + + 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(';') @@ -153,7 +181,8 @@ export default { }, components: { ColorInput, - OpacityInput + OpacityInput, + ContrastRatio }, methods: { exportCurrentTheme () { diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 1b00603c..4235d65c 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -53,7 +53,9 @@ + +
@@ -81,13 +83,16 @@ +

Top bar

+ +

Inputs

@@ -100,6 +105,7 @@ +

Borders

diff --git a/src/services/color_convert/color_convert.js b/src/services/color_convert/color_convert.js index ae5d5a31..31ee3a6b 100644 --- a/src/services/color_convert/color_convert.js +++ b/src/services/color_convert/color_convert.js @@ -19,6 +19,42 @@ const rgb2hex = (r, g, b) => { return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}` } +// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef +// https://www.w3.org/TR/2008/REC-WCAG20-20081211/relative-luminance.xml +// https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation +const c2linear = (b) => { + // W3C gives 0.03928 while wikipedia states 0.04045 + // what those magical numbers mean - I don't know. + // something about gamma-correction, i suppose. + // Sticking with W3C example. + const c = b / 255 + if (c < 0.03928) { + return c / 12.92 + } else { + return Math.pow((c + 0.055) / 1.055, 2.4) + } +} + +const srgbToLinear = (srgb) => { + return 'rgb'.split('').reduce((acc, c) => { acc[c] = c2linear(srgb[c]); return acc }, {}) +} + +// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef +// https://www.w3.org/TR/2008/REC-WCAG20-20081211/relative-luminance.xml +const relativeLuminance = (srgb) => { + const {r, g, b} = srgbToLinear(srgb) + return 0.2126 * r + 0.7152 * g + 0.0722 * b +} + +// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef +const getContrastRatio = (a, b) => { + const la = relativeLuminance(a) + const lb = relativeLuminance(b) + const [l1, l2] = la > lb ? [la, lb] : [lb, la] + + return (l1 + 0.05) / (l2 + 0.05) +} + const hex2rgb = (hex) => { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) return result ? { @@ -47,5 +83,6 @@ export { rgb2hex, hex2rgb, mixrgb, - rgbstr2hex + rgbstr2hex, + getContrastRatio } From 4b7b7d9905b965c225fd42fb68682b9602254c82 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 10 Oct 2018 05:39:02 +0300 Subject: [PATCH 008/123] cleanup, documentation, contrast taking alpha into account. --- .../style_switcher/style_switcher.js | 38 +++++++--- src/services/color_convert/color_convert.js | 70 ++++++++++++++++--- 2 files changed, 91 insertions(+), 17 deletions(-) diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index 27efa230..d4381202 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -1,4 +1,4 @@ -import { rgb2hex, hex2rgb, getContrastRatio } from '../../services/color_convert/color_convert.js' +import { rgb2hex, hex2rgb, getContrastRatio, worstCase } from '../../services/color_convert/color_convert.js' import ColorInput from '../color_input/color_input.vue' import ContrastRatio from '../contrast_ratio/contrast_ratio.vue' import OpacityInput from '../opacity_input/opacity_input.vue' @@ -144,12 +144,13 @@ export default { } }, previewTheme () { - if (!this.preview.theme) return { colors: {}, opacity: {}, radii: {}, contrast: {} } + if (!this.preview.theme) return { colors: {}, opacity: {}, radii: {} } return this.preview.theme }, previewContrast () { if (!this.previewTheme.colors) return {} const colors = this.previewTheme.colors + const opacity = this.previewTheme.opacity const hints = (ratio) => ({ text: ratio.toPrecision(3) + ':1', // AA level, AAA level @@ -160,16 +161,37 @@ export default { laaa: ratio >= 4.5 }) + // fgsfds :DDDD + const fgs = { + text: hex2rgb(colors.text), + panelText: hex2rgb(colors.panelText), + btnText: hex2rgb(colors.btnText), + topBarText: hex2rgb(colors.topBarText), + + link: hex2rgb(colors.link), + topBarLink: hex2rgb(colors.topBarLink), + } + + const bgs = { + bg: hex2rgb(colors.bg), + btn: hex2rgb(colors.btn), + panel: hex2rgb(colors.panel), + topBar: hex2rgb(colors.topBar) + } + const ratios = { - bgText: getContrastRatio(hex2rgb(colors.bg), hex2rgb(colors.text)), - bgLink: getContrastRatio(hex2rgb(colors.bg), hex2rgb(colors.link)), + bgText: getContrastRatio(worstCase(bgs.bg, opacity.bg, fgs.text), fgs.text), + bgLink: getContrastRatio(worstCase(bgs.bg, opacity.bg, fgs.link), fgs.link), - panelText: getContrastRatio(hex2rgb(colors.panel), hex2rgb(colors.panelText)), + // User Profile + tintText: getContrastRatio(worstCase(bgs.bg, 0.5, fgs.panelText), fgs.text), - btnText: getContrastRatio(hex2rgb(colors.btn), hex2rgb(colors.btnText)), + panelText: getContrastRatio(worstCase(bgs.panel, opacity.panel, fgs.panelText), fgs.panelText), - topBarText: getContrastRatio(hex2rgb(colors.topBar), hex2rgb(colors.topBarText)), - topBarLink: getContrastRatio(hex2rgb(colors.topBar), hex2rgb(colors.topBarLink)), + btnText: getContrastRatio(worstCase(bgs.btn, opacity.btn, fgs.btnText), fgs.btnText), + + topBarText: getContrastRatio(worstCase(bgs.topBar, opacity.topBar, fgs.topBarText), fgs.topBarText), + topBarLink: getContrastRatio(worstCase(bgs.topBar, opacity.topBar, fgs.topBarLink), fgs.topBarLink) } return Object.entries(ratios).reduce((acc, [k, v]) => { acc[k] = hints(v); return acc }, {}) diff --git a/src/services/color_convert/color_convert.js b/src/services/color_convert/color_convert.js index 31ee3a6b..0acc7e7c 100644 --- a/src/services/color_convert/color_convert.js +++ b/src/services/color_convert/color_convert.js @@ -19,15 +19,21 @@ const rgb2hex = (r, g, b) => { return `#${((1 << 24) + (r << 16) + (g << 8) + b).toString(16).slice(1)}` } -// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef -// https://www.w3.org/TR/2008/REC-WCAG20-20081211/relative-luminance.xml -// https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation -const c2linear = (b) => { +/** + * Converts 8-bit RGB component into linear component + * https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef + * https://www.w3.org/TR/2008/REC-WCAG20-20081211/relative-luminance.xml + * https://en.wikipedia.org/wiki/SRGB#The_reverse_transformation + * + * @param {Number} bit - color component [0..255] + * @returns {Number} linear component [0..1] + */ +const c2linear = (bit) => { // W3C gives 0.03928 while wikipedia states 0.04045 // what those magical numbers mean - I don't know. // something about gamma-correction, i suppose. // Sticking with W3C example. - const c = b / 255 + const c = bit / 255 if (c < 0.03928) { return c / 12.92 } else { @@ -35,18 +41,36 @@ const c2linear = (b) => { } } +/** + * Converts sRGB into linear RGB + * @param {Object} srgb - sRGB color + * @returns {Object} linear rgb color + */ const srgbToLinear = (srgb) => { return 'rgb'.split('').reduce((acc, c) => { acc[c] = c2linear(srgb[c]); return acc }, {}) } -// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef -// https://www.w3.org/TR/2008/REC-WCAG20-20081211/relative-luminance.xml +/** + * Calculates relative luminance for given color + * https://www.w3.org/TR/2008/REC-WCAG20-20081211/#relativeluminancedef + * https://www.w3.org/TR/2008/REC-WCAG20-20081211/relative-luminance.xml + * + * @param {Object} srgb - sRGB color + * @returns {Number} relative luminance + */ const relativeLuminance = (srgb) => { const {r, g, b} = srgbToLinear(srgb) return 0.2126 * r + 0.7152 * g + 0.0722 * b } -// https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef +/** + * Generates color ratio between two colors. Order is unimporant + * https://www.w3.org/TR/2008/REC-WCAG20-20081211/#contrast-ratiodef + * + * @param {Object} a - sRGB color + * @param {Object} b - sRGB color + * @returns {Number} color ratio + */ const getContrastRatio = (a, b) => { const la = relativeLuminance(a) const lb = relativeLuminance(b) @@ -55,6 +79,33 @@ const getContrastRatio = (a, b) => { return (l1 + 0.05) / (l2 + 0.05) } +/** + * This generates what "worst case" color would look like for transparent + * segments. I.e. black with .2 alpha and pure-white background image + * could make white text unreadable + * + * @param {Object} srgb - transparent color + * @param {Number} alpha - color's opacity/alpha channel + * @param {Boolean} white - use white "background" if true, black otherwise + * @returns {Object} sRGB of resulting color + */ +const transparentWorstCase = (srgb, alpha, white = false) => { + const bg = 'rgb'.split('').reduce((acc, c) => { acc[c] = Number(white) * 255; return acc }, {}) + return 'rgb'.split('').reduce((acc, c) => { + // Simplified https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending + // for opaque bg and transparent fg + acc[c] = (srgb[c] * alpha + bg[c] * (1 - alpha)) + return acc + }, {}) +} + +const worstCase = (bg, bga, text) => { + if (bga === 1 || typeof bga === 'undefined') return bg + // taken from https://github.com/toish/chromatism/blob/master/src/operations/contrastRatio.js + const blackWorse = ((text.r * 299) + (text.g * 587) + (text.b * 114)) / 1000 <= 128 + return transparentWorstCase(bg, bga, !blackWorse) +} + const hex2rgb = (hex) => { const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex) return result ? { @@ -84,5 +135,6 @@ export { hex2rgb, mixrgb, rgbstr2hex, - getContrastRatio + getContrastRatio, + worstCase } From 7b657fcccd3524aba552cab4ee1005057fd83d41 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 21 Oct 2018 15:25:21 +0300 Subject: [PATCH 009/123] added contrasts for rgbo --- .../style_switcher/style_switcher.js | 20 +++++++++++++------ .../style_switcher/style_switcher.vue | 4 ++++ 2 files changed, 18 insertions(+), 6 deletions(-) diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index d4381202..7f794608 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -128,7 +128,7 @@ export default { avatarAltRadius: this.avatarAltRadiusLocal, tooltipRadius: this.tooltipRadiusLocal, attachmentRadius: this.attachmentRadiusLocal - }, + } } }, preview () { @@ -170,6 +170,11 @@ export default { link: hex2rgb(colors.link), topBarLink: hex2rgb(colors.topBarLink), + + red: hex2rgb(colors.cRed), + green: hex2rgb(colors.cGreen), + blue: hex2rgb(colors.cBlue), + orange: hex2rgb(colors.cOrange) } const bgs = { @@ -182,8 +187,11 @@ export default { const ratios = { bgText: getContrastRatio(worstCase(bgs.bg, opacity.bg, fgs.text), fgs.text), bgLink: getContrastRatio(worstCase(bgs.bg, opacity.bg, fgs.link), fgs.link), + bgRed: getContrastRatio(worstCase(bgs.bg, opacity.bg, fgs.red), fgs.red), + bgGreen: getContrastRatio(worstCase(bgs.bg, opacity.bg, fgs.green), fgs.green), + bgBlue: getContrastRatio(worstCase(bgs.bg, opacity.bg, fgs.blue), fgs.blue), + bgOrange: getContrastRatio(worstCase(bgs.bg, opacity.bg, fgs.orange), fgs.orange), - // User Profile tintText: getContrastRatio(worstCase(bgs.bg, 0.5, fgs.panelText), fgs.text), panelText: getContrastRatio(worstCase(bgs.panel, opacity.panel, fgs.panelText), fgs.panelText), @@ -378,10 +386,10 @@ export default { this.fgColorLocal = this.selected[2] this.textColorLocal = this.selected[3] this.linkColorLocal = this.selected[4] - this.redColorLocal = this.selected[5] - this.greenColorLocal = this.selected[6] - this.blueColorLocal = this.selected[7] - this.orangeColorLocal = this.selected[8] + this.cRedColorLocal = this.selected[5] + this.cGreenColorLocal = this.selected[6] + this.cBlueColorLocal = this.selected[7] + this.cOrangeColorLocal = this.selected[8] } } } diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 4235d65c..cecd6bc0 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -64,11 +64,15 @@
+ +
+ +

Alert opacity

From 1723f427f59bb6bf62bb35de93c7226aef2e8727 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 13 Nov 2018 16:30:01 +0300 Subject: [PATCH 010/123] updates --- src/App.scss | 4 +- src/_variables.scss | 2 +- .../contrast_ratio/contrast_ratio.vue | 50 +++++++----------- .../notifications/notifications.scss | 8 +-- .../opacity_input/opacity_input.vue | 10 ---- .../style_switcher/style_switcher.js | 24 ++++++++- .../style_switcher/style_switcher.vue | 26 +++++---- src/services/color_convert/color_convert.js | 16 +++--- src/services/style_setter/style_setter.js | 6 ++- static/font/config.json | 26 ++++++--- static/font/css/fontello-codes.css | 6 ++- static/font/css/fontello-embedded.css | 18 ++++--- static/font/css/fontello-ie7-codes.css | 6 ++- static/font/css/fontello-ie7.css | 6 ++- static/font/css/fontello.css | 20 +++---- static/font/demo.html | 22 ++++---- static/font/font/fontello.eot | Bin 15552 -> 16124 bytes static/font/font/fontello.svg | 8 ++- static/font/font/fontello.ttf | Bin 15384 -> 15956 bytes static/font/font/fontello.woff | Bin 9432 -> 9848 bytes static/font/font/fontello.woff2 | Bin 8020 -> 8372 bytes 21 files changed, 145 insertions(+), 113 deletions(-) diff --git a/src/App.scss b/src/App.scss index c91b6a61..0a2ff5cc 100644 --- a/src/App.scss +++ b/src/App.scss @@ -479,8 +479,8 @@ nav { line-height: 28px; &.error { - background-color: $fallback--cAlertRed; - background-color: var(--cAlertRed, $fallback--cAlertRed); + background-color: $fallback--alertError; + background-color: var(--alertError, $fallback--alertError); } } diff --git a/src/_variables.scss b/src/_variables.scss index 0f73e929..d0d91efe 100644 --- a/src/_variables.scss +++ b/src/_variables.scss @@ -16,7 +16,7 @@ $fallback--cBlue: #0095ff; $fallback--cGreen: #0fa00f; $fallback--cOrange: orange; -$fallback--cAlertRed: rgba(211,16,20,.5); +$fallback--alertError: rgba(211,16,20,.5); $fallback--panelRadius: 10px; $fallback--checkBoxRadius: 2px; diff --git a/src/components/contrast_ratio/contrast_ratio.vue b/src/components/contrast_ratio/contrast_ratio.vue index 6c4a59b6..a428e75f 100644 --- a/src/components/contrast_ratio/contrast_ratio.vue +++ b/src/components/contrast_ratio/contrast_ratio.vue @@ -1,41 +1,28 @@ + + diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index f4f9331f..8e344eb1 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -1,5 +1,6 @@ import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.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' @@ -51,6 +52,9 @@ export default { faintOpacityLocal: undefined, faintLinkColorLocal: undefined, + shadowSelected: undefined, + shadowsLocal: {}, + cRedColorLocal: '', cBlueColorLocal: '', cGreenColorLocal: '', @@ -225,12 +229,23 @@ export default { previewRules () { if (!this.preview.colorRules) return '' return [this.preview.colorRules, this.preview.radiiRules, 'color: var(--text)'].join(';') + }, + shadowsAvailable () { + return Object.keys(this.preview.theme.shadows) + }, + currentShadow () { + const fallback = this.preview.theme.shadows[this.shadowSelected]; + return fallback ? { + fallback, + value: this.shadowsLocal[this.shadowSelected] + } : undefined } }, components: { ColorInput, OpacityInput, ContrastRatio, + ShadowControl, TabSwitcher }, methods: { @@ -340,6 +355,7 @@ export default { const colors = input.colors || input const radii = input.radii || input const opacity = input.opacity || input + const shadows = input.shadows || {} if (version === 0) { if (input.version) version = input.version @@ -384,6 +400,8 @@ export default { this.tooltipRadiusLocal = radii.tooltipRadius || 2 this.attachmentRadiusLocal = radii.attachmentRadius || 5 + this.shadowsLocal = shadows + Object.entries(opacity).forEach(([k, v]) => { if (typeof v === 'undefined' || v === null || Number.isNaN(v)) return this[k + 'OpacityLocal'] = v diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 5bc38318..0352f546 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -170,6 +170,17 @@
+
+
+ +
+ +
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 907de586..3840e215 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -92,6 +92,19 @@ const setColors = (input, commit) => { commit('setOption', { name: 'colors', value: theme.colors }) } +const generateShadow = (input) => { + // >shad + return input.map((shad) => [ + shad.x, + shad.y, + shad.blur, + shad.spread + ].map(_ => _ + 'px').concat([ + rgb2rgba({...(hex2rgb(shad.color)), a: shad.alpha}), + shad.inset ? 'inset' : '' + ]).join(' ')).join(', ') +} + const generatePreset = (input) => { const radii = input.radii || { btnRadius: input.btnRadius, @@ -102,6 +115,17 @@ const generatePreset = (input) => { 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 colors = {} const opacity = Object.assign({ alert: 0.5, @@ -194,8 +218,10 @@ const generatePreset = (input) => { 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(';'), theme: { colors: htmlColors.solid, + shadows, opacity, radii } @@ -245,7 +271,8 @@ const StyleSetter = { setPreset, setColors, getTextColor, - generatePreset + generatePreset, + generateShadow } export default StyleSetter diff --git a/static/font/config.json b/static/font/config.json index 1d1317d7..3abeffe9 100644 --- a/static/font/config.json +++ b/static/font/config.json @@ -1,5 +1,4 @@ { - "name": "", "css_prefix_text": "icon-", "css_use_suffix": false, "hinting": true, @@ -209,6 +208,12 @@ "css": "plus-squared", "code": 61694, "src": "fontawesome" + }, + { + "uid": "44e04715aecbca7f266a17d5a7863c68", + "css": "plus", + "code": 59413, + "src": "fontawesome" } ] } \ No newline at end of file diff --git a/static/font/css/fontello-codes.css b/static/font/css/fontello-codes.css index 66a240cd..5cfcbf6a 100644 --- a/static/font/css/fontello-codes.css +++ b/static/font/css/fontello-codes.css @@ -20,6 +20,7 @@ .icon-globe:before { content: '\e812'; } /* '' */ .icon-brush:before { content: '\e813'; } /* '' */ .icon-attention:before { content: '\e814'; } /* '' */ +.icon-plus:before { content: '\e815'; } /* '' */ .icon-spin3:before { content: '\e832'; } /* '' */ .icon-spin4:before { content: '\e834'; } /* '' */ .icon-link-ext:before { content: '\f08e'; } /* '' */ diff --git a/static/font/css/fontello-embedded.css b/static/font/css/fontello-embedded.css index 65875bde..58a57456 100644 --- a/static/font/css/fontello-embedded.css +++ b/static/font/css/fontello-embedded.css @@ -1,15 +1,15 @@ @font-face { font-family: 'fontello'; - src: url('../font/fontello.eot?92539127'); - src: url('../font/fontello.eot?92539127#iefix') format('embedded-opentype'), - url('../font/fontello.svg?92539127#fontello') format('svg'); + src: url('../font/fontello.eot?4112743'); + src: url('../font/fontello.eot?4112743#iefix') format('embedded-opentype'), + url('../font/fontello.svg?4112743#fontello') format('svg'); font-weight: normal; font-style: normal; } @font-face { font-family: 'fontello'; - src: url('data:application/octet-stream;base64,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') format('woff'), - url('data:application/octet-stream;base64,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') format('truetype'); + src: url('data:application/octet-stream;base64,d09GRgABAAAAACdYAA8AAAAAQAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABHU1VCAAABWAAAADsAAABUIIslek9TLzIAAAGUAAAAQwAAAFY+L1N8Y21hcAAAAdgAAAEyAAADrCjhbUljdnQgAAADDAAAABMAAAAgBv/+9GZwZ20AAAMgAAAFkAAAC3CKkZBZZ2FzcAAACLAAAAAIAAAACAAAABBnbHlmAAAIuAAAGoEAACjSSnDq5WhlYWQAACM8AAAAMwAAADYTu6FIaGhlYQAAI3AAAAAgAAAAJAfJA/9obXR4AAAjkAAAAFIAAACQgg//5mxvY2EAACPkAAAASgAAAEq11aikbWF4cAAAJDAAAAAgAAAAIAF5DaZuYW1lAAAkUAAAAXcAAALNzJ0eIHBvc3QAACXIAAABFAAAAZCo9e7HcHJlcAAAJtwAAAB6AAAAhuVBK7x4nGNgZGBg4GIwYLBjYHJx8wlh4MtJLMljkGJgYYAAkDwymzEnMz2RgQPGA8qxgGkOIGaDiAIAJjsFSAB4nGNgZJ7LOIGBlYGBqYppDwMDQw+EZnzAYMjIBBRlYGVmwAoC0lxTGBxeMHwyYY78X8gQxZzOMA8ozAiSAwD4wAwzAHic5dI5bsJAFIfxz4GQjWwkZN9pU0WuKaMchPPAZXKGSNyCxtIrZ6hSQf7j97osF4itH5LH0njE+4BNoCPP0oXqk4pyLbVatesddtv1Lh96vuFIK30b2ovVaZbmaZGatMqDPM6T3Czr9RqM9u3057e/XpV2f23vt293ebuhL3d14h5bbLOjc+3RZ58DDnWqYwaccMqQM8654JIrrrXjLXfc88AjT4y0Te+PE/yXq19+qvd4GpWJuTJzC/q/sVAasVA6sVD6saC5YEETwoJmhQVNDQulKwuaJBbK6SxouljQnLGgiWNBs8eCKsCCesCCysCCGsGCasGCulG3TgVhtVNLpKlTVaSZU1+kuVNppIVTc6TGqT7SyqlD8sCpSPLYqU3yxKlScuPUK8vaMfoC3OeGSAAAeJxjYEADEhDInP4/CYQBEw4D9wB4nK1WaXfTRhQdeUmchCwlCy1qYcTEabBGJmzBgAlBsmMgXZytlaCLFDvpvvGJ3+Bf82Tac+g3flrvGy8kkLTncJqTo3fnzdXM22USWpLYC+uRlJsvxdTWJo3sPAnphk3LUXwoO3shZYrJ3wVREK2W2rcdh0REIlC1rrBEEPseWZpkfOhRRsu2pFdNyi096S5b40G9Vd9+GjrKsTuhpGYzdGg9siVVGFWiSKY9UtKmZaj6K0krvL/CzFfNUMKITiJpvBnG0EjeG2e0ymg1tuMoimyy3ChSJJrhQRR5lNUS5+SKCQzKB82Q8sqnEeXD/Iis2KOcVrBLttP8vi95p3c5P7Ffb1G25EAfyI7s4Ox0JV+EW1th3LST7ShUEXbXd0Js2exU/2aP8ppGA7crMr3QjGCpfIUQKz+hzP4hWS2cT/mSR6NaspETQetlTuxLPoHW44gpcc0YWdDd0QkR1P2SMwz2mD4e/PHeKZYLEwJ4HMt6RyWcCBMpYXM0SdowcmAlZYsqqfWumDjldVrEW8J+7drRl85o41B3YjxbDx1bOVHJ8WhSp5lMndpJzaMpDaKUdCZ4zK8DKD+iSV5tYzWJlUfTOGbGhEQiAi3cS1NBLDuxpCkEzaMZvbkbprl2LVqkyQP13KP39OZWuLnTU9oO9LNGf1anYjrYC9PpaeQv8Wna5SJF6frpGX5M4kHWAjKRLTbDlIMHb/0O0svXlhyF1wbY7u3zK6h91kTwpAH7G9AeT9UpCUyFmFWIVkBirWtZlsnVrBapyNR3Q5pWvqzTBIpyHBfHvoxx/V8zM5aYEr7fidOzIy49c+1LCNMcfJt1PZrXqcVyAXFmeU6nWZbv6zTH8gOd5lme1+kIS1unoyw/1GmB5Uc6HWN5QQuadN/BkIsw5AIOkDCEpQNDWF6CISwVDGG5CENYFmEIyyUYwvJjGMJyGYawvKxl1dRTSePamVgGbEJgYo4eucxF5WoquVRCu2hUakOeEm6VVBTPqn9loF488oY5sBZIl8iaXzHOlY9G5fjWFS1vGjtXwLHqbx+O9jnxUtaLhT8F/9XWVCW9Ys3Dk6vwG4aebCeqNql4dE2Xz1U9uv5fVFRYC/QbSIVYKMqybHBnIoSPOp2GaqCVQ8xszDy063XLmp/D/TcxQhZQ/fg3FBoL3INOWUlZ7eCs1dfbstw7g3I4EyxJMTfz+lb4IiOz0n6RWcqej3wecAWMSmXYagOtFbzZJzEPmd4kzwRxW1E2SNrYzgSJDRzzgHnznQQmYeqqDeRO4YYN+AVhbsF5J1yieqMsh+5F7PMopPxbp+JE9qhojMCz2Rthr+9Cym9xDCQ0+aV+DFQVoakYNRXQNFJuqAZfxtm6bULGDvQjKnbDsqziw8cW95WSbRmEfKSI1aOjn9Zeok6q3H5mFJfvnb4FwSA1MX9733RxkMq7WskyR20DU7calVPXmkPjVYfq5lH1vePsEzlrmm66Jx56X9Oq28HFXCyw9m0O0lImF9T1YYUNosvFpVDqZTRJ77gHGBYY0O9Qio3/q/rYfJ4rVYXRcSTfTtS30edgDPwP2H9H9QPQ92Pocg0uz/eaE59u9OFsma6iF+un6Dcwa625WboG3NB0A+IhR62OuMoNfKcGcXqkuRzpIeBj3RXiAcAmgMXgE921jOZTAKP5jDk+wOfMYdBkDoMt5jDYZs4awA5zGOwyh8Eecxh8wZx1gC+ZwyBkDoOIOQyeMCcAeMocBl8xh8HXzGHwDXPuA3zLHAYxcxgkzGGwr+nWMMwtXtBdoLZBVaADU09Y3MPiUFNlyP6OF4b9vUHM/sEgpv6o6faQ+hMvDPVng5j6i0FM/VXTnSH1N14Y6u8GMfUPg5j6TL8Yy2UGv4x8lwoHlF1sPufvifcP28VAuQABAAH//wAPeJzFegtwXNd53vnPue979+7r7r0LYLFY7GJ38RIILvZBkRS4fFMiRIIkRAEURUMUSUWESEiKbDGyqKgWo5FqRVQcRfWMJ3I0lTVpbbkK6TpsXdsZR7JTup2R65jSOO1MY2c8lN2ynlZpOiy57HfuLkDq1Uw70+kCuHvPPY97zn/+//u//z9gxNi1/87/kv8uG2DZZk++K6YrjNNWQZzxRUL1ES/jeYqaHil6UdLyK0iXl1J1HZXlpV7po4a8+KgOfP6X0anYaOzVV3GZisnv2PVyNPrqq9FHfXnzla9EP9owOiYbMAVzOideETVmsDgbYk22pbmxhveajGNWW5mpmYsGabq2yHShL6IDV2ZUEpguF2yeKQqfxSM+dcvawkQhXynenE5Yau9IsVpyeZbqjaXvlKcV+vOlcq1aDyaytIYq9cZExRfaCKFKL8gqXNqr9Pl5L+vxdHf6d71cgvuZ9Jacf+WHQZZy/iWnXjidr0cu+blvmunTXvR01KPTQTJ+2cpalxMDrs8TuYTS7SzdPHvWz+V8XKhvcLAvS7v9y+jhu5dH0cW6HGf4yL35EeSwlfWx3mZ3ImopQpWbw5b3ptcLhBqMEGSfTHkuhbtTqlUbybK8FsOdUX3xSvT8uJNy/udlx3do/IduH6WfsHPOSUrn6NdO9K3We44dI/3UKT1hKQYFb0WdlDrYCoLWIN64PA8Tu1FuDmS6PDdiGrqmCnI+OKHiQOAnYkL1RqixgqAReiNItmdXyH/C7Phn/+mvjt7/n7469OMftzDPwPr4eQ69lv/JT/Kv/Wpxkc60p5z5hAnjw69dhQ59SiSYzjw20hxkAgKFcihEnNMMvkgqCfEpxhJxx0Y7Pa6qqZFiPC+VgyDN/BifpAruX9/z3DSfeYbTw9+/+BfHtcf+1fv/8okan9/93KvP7abxT7/5yCNv/lJeGMPLr50XF/k5yKqbTbJN7E52Z3Om2sOZskeD+u7eiHdObxgqQ4E1UrYyVVEXIT+oLh1jpOF3gWkCvwtMiOPSGJQZaDSbxQ2bmtqeHOsa8Hp1tXuk2BijRrWh6T5VS3peS3l+pQ5VnoAWeymNw1wL+VDSY9JWG5M0UQkaqPahzLqfhIYn/cDTNd2lAmobpXIjCxum+sj4Kso/eccBOhqztxyK+bFN43bs/Jpfrsmolr7J7Jp+umLbe6/8o0qlT7WEaw/YZKZmb/1D5bLtl2f+/eNDj/7F5vV3F2oHc/aDOwtHb9m4ev2pF+g+qNihzXYsZo9vin1aoftb++6vmGXN0ocHTtweH0489UWrbmqap5HaurrjyR5Kdx1IJgdumj96m3Xq/kPNdQMH60kW6uM1ZZw/xfrZRrahuS5PiiYhC+qlk3bMJE3RNWXBAIbpxPX5G4SokpTihqbfX0z3+6nBZIgLnlYGDKygMZqIF/Jj1DF4CQGpfnm3hH2lan0N1frbd41+KckspeIQKT9vGVffUzUO5KQF2LJxFop7xvTdBVpvqnMKHTbOODn7rIEnre/IJ5bB00rYYcH1E7pDXCjk0E6/x7rgOBesjEcXtAfUn0WsC5HIBavHv6AvqBELzVRuiNYZn7VlcU7sg54b7Cjb3NxweG5qvcKUNRYnVh3siSmCRFvJoG1MWZSwsghLoEUmuIDm8SP779qz69ZtI8P5XDKhq/4ItCnvEnSpCBDEunU/8D3oSBnLBujqQEdYcblUhjXjGmpWI5SeBFLIrlFaUrc+FPADYJU6B+WrBJ3B9FB0fM3uE7v53kf2UsbQf8Oyk4OaGp2O6PrtXd2mrsQeN5xYT7BTi2lbfEU1Bq2ocUQ3yFJ/w3CDYrutcXu62zRE/HFIMJoJdqpRfZunKGa7sUWH18zMfGZm5oSsj2VTPRXN1VLTpK6NGFOZmKXfZzprVa2ZVV3NqUQzPVFy9LBtV3fuJt3RvekbmtprVHVjptO0Owb4C/eAMbHAz7MyfBX00YMKABQ1rnJNPcZUwVVYsyKYUNgxaeka8XlZEDOwcWnZgk35ha7icLGsqz3QRz9KEBFcTy1eDaWXCsJH5UJe0+OeH0xUspw8aHu+dAsV5AX6OAHx+wH5dBgYQ4ZxZuOBAxvPGJbEOlksVqk+8A2NA4c0u/UjO+Nfdn34HD9j0wq7xhOqa3JxYCM9s/GAZdimBuFCGVon0FHhBo26dutty4u+4rsXoOGvwJmZeLDkqy6Jb/JxoG1X048QgwQgBQY9kxwiSEg/BcvMl6lNGwKzY2Tiq62D8JKtg7Z9N75pkAbtjLPfppda99o2/aGdtfbbdutdPLb32xm861rr2mfFOXEfW8n6mhn5bprB+9gsdJ7YFLHhIbaSVkovFOTLAEmqBxLYdCnBUh1F3GqB35C30FUUsrzz9P0jm7Ype+nX0wdGtzjd063S4Hwuq43SVLra3frGaNpx0j79tJJbW6+3EhuUQ0/fRr+WVbHdv7Nty58dQMduZ8vovOxo5dKHhmlHdzWNjt0GV2THz8TcSisx9fRBpUmX0mOyo5Sfcu3atXPKitCOo/D3K9gdzd29HicRxZrciGMqnGVSIDWK9LaS8RxjQDtBmpiXEsDSgXOqGuKcOistfioeGxspFbqCWF+8L5lMGCFTcCV0wael+muNgIr9bYUCltXL8WopiAP0gIWNeBvf6PDkvkn88rVXLp3ZR72UvfIUbMrRxEmYiLWrWrzy1ECdqkVxsljl6Zsm+Ya9G5TVrcuXF87OUe8rAMV9sqHBXzOsxNV9oQry1+QXs7Hmh8I1t1e8ju1knwI4/TY7zb7M/hl7s9n1QpObxjNPzucUVTmxigs+Pc4EIHzr9jf6p2ebDZZKONwwU8Z8kswYKaqpzMcjHPbJJUrOR0lYFPp9W4c2erPM8yLerT3Nyf+znp5HM8sjkDc11yx9/auv/eOXv/TSi88/9/SpJx7/zG8eXzhy6MBde2d2bK/VaiX81CZ8+JagBt8Mq+0lz5f8EhBZAn6GZXDNsFzu1MOq64RNACfVsBH+BDaFPtR/qayn2mWB9nqnfYD2QWd8WS/Hb3TGl+WgU76xfyPe5sBLG37Bi26ToIALfewtX+O7rT3hI3o96l1963qViPvu1pDG4vqTDzR754aaT7pu+4AyDVx/7d9cn8YvbujTuoeysqL1M1z5722Noj62FfdXP3+9L32LesOK1s9ln3/98UP9zfXO911NFKvVIr8U6qjEtR/wR8R24FrQ9MwQ19gSrGUSHP7S7FCDhrkEbUA1fhSAlrHvBoINtt7tQNvLFj3Yusey7kYNDUmckw1kwyUM/QH/4tK76IPvCoLwXdwPqYhE0UYHQPnzrXdoqD2qRFG8JmvdbfE/ab3beie8tejL4evDacj3wON8k9/exmqVPkjhAy/E6qL07stL66xKfHU/4BjjvttZ28tyJS/bD+/HO4bwNkvWYwJWZ1Fg3dceEm+KfcwBH97A3ms6DLSMtg72gPhs2f6GCzMe0QmTIPVwCGP3ohMhspBxnDHLDMPZBpaizTJNi2i39rQtf/QDXfjC39dnAH2GPqkPh6vW9i93VYAPKz7c1oD/NpT56300jc903sG1qbm5uabTl08M+vFCMmHC8NUq3HKjmpd2WCn2l+LVMY7IIhVTPRAoTwZC0r9PKg0YHkj6JPkpT4eb8rKCrpr945RYPWi2nuMX/qC7uvuB3dVu/tpw72VQmcu9w5mx8YEEP3W/mhvNqUc/R35+fHzOGO83zaHV9E/+mIYya1fl86vWZlrv/HHvMAjQmuHedGXmwDO3z3whZtlBludTthX7wsyOp+d3V5c4DH8qjJf62HCzDNKCjcLSj2GRCEOIQs9Cs4wUmioki/VkTEMQkuwHoLgUqB3HASeCWBpEpOLrKfDis9SLKRO9nfOvvhfGyvEX/81LPIHbrz2wZoZP3/JK6zs+nqdoA6LhB468+OKRB7JMhPHbHObj0Lfp7/ij298wp2fXr2XfZt9i5+AeXmLPME2qF5wFZom7n7Ifg13NsV1Qs0k2wXKsi1lYDqeX6Yv0Ej1Hn6fH6NN0mO4FrP81+49QSQ0Bwh66nWR4aDCN3qe/oh/RD+nP6Du0iibwjORzthUqZOH9GztvfwYeWMaZ30a9wN3/+znobCvWTHgXsS09//8EMTcX7kSzxrjQBdePMV0TuoxZDaEZsBMSBi0AuY4DK0FuZ/DFxKyqcNDfqbYYm6sVgo9VxWHGdZXrCxhDbY+htsdQr4+hqu0x1L1Yu3pbz//lm+fm1neFTPFdukD/gv6U7qS97AfsLfbP2TfYn7Cvs99in4GMNMgRCIU/C6/zRmT4v5QJkJS8Mkk1RDv1oCQDnXWklWqeXi1ptTFF4qTMcHjD5OW1vF4vlwpglxNjHBQUjwHVWhY3gG8ZA2l53JRk/KTLv0pJn6SCHLTsyxAK9jPhV8uVsIEWyMZ4QRnDYtRySZazhGgKcX9e83XEXr508wjIGtWgrOkVOVTQCNBZ93XMAF01Pcu9hq+HQZheLmn+hBynDxNqaH0iywNNjldDK3Dj8hivyQgO3HgC865klT7hVzAqOjfyYeALtKrXMAoucvWlelCpY7lYlqelCnXpDPFcz+uuKGEKslyW8wLxqGIdfh0jYcJ+I8shnXrDBypMEmLL2pjM0oXSqKBFHrNBOOnLa8OvlyYp1agX5BylgCs1CEQAROGq6ohD5W+UsLIU5DWGXYtSqV6Scq9rKZdSCAjCaACRbOBpPr3+yPcfXkrsUBKhNXFFxFNJ0FxuaAJbpiiWqilkABCFUPDRSAN5VBG9I742HFIziuCIsfAyrptogngJHS2uqBEhPDepGIj5iKsmp6SpKVzVLLgTKL/QTIwG9qkKhIkKubodVWICoyoGGfILAwvQ/oQqHAev505Xj9BUNakKW4nYeJGmGIqp7KooMtwUlLYwB1WR85RxKHFL1xOKbkr/xV2Z/nIRRvCoITC0UEmB68YIqqNzYQhT9zVNNYyY4mEcDC5coSDgNuIWx4dUjhIXjkA8KEUFQ7TxHm54AoEml+tWISX8kpIWpsAERIS7UhwKajTMAXJSFN1QdUdBAcGwGk7EUXgC3bkMQrllQFSapqumY93/m9PkUAT9UxI2pKBVBzaPD8mZW9ghDlGjESai2FHipkUi0UnK4dL6D2RwmW4zhGqjGYZATKKHciWuOaoGucLFifAB7rkhxUpYOfZaF4Zu6YqqqY5UDSzNMSEUFUsQcS5cQz4XJrZVaOQqFoZUsSxL0XWdTNXQDQhJSFlCHSwhXFmtKggnLCPKhQQzFwJQNPxgEjftVOSuK1rUwhwQx7mmZ3PSujm8rKIhqhUiBhkrhmooZKcjqoNVK47hKi5ZtoeYXYXIsRcJYSmKKXNSVihgHjMSUn8xD0t3w62EvGNqVGIxt7FoFJW0a7qqKVNqEDWEDjNReRQ6QjJVJRBFKtyAIF1uWarMWdmmKlUDe4A1KzAIiEAjLA8d5b7j0oqk7pBrlklJaQcQNbcEQi0V0kXIJdtIfZLjqBkjbrqmw5WYHua3viJOiwEgcsDyzT7QYh5XJTfZKrO3i8v8uMfPh7TV08p5wERZMhAwVl2mpcBe6e2vf3bXpk27afaxWXo519/6nrd7FU3mDvzo8TdosPwPd98yO0t/mzuQa32vMeOhAr7j2t+Cg/w3MYf4tB9+9FDT6cF+czPkRVvbpLKXQXZQymNLCWZMCGLdD7/lqCCSeQbhLsJlYarLLbDNMmGhzMqmCCbNYFUZ3kLyqeIN8aGM18rJalk+0LVU0I7oBPkyfya5VqkBuKwgJLP0B3QrvMBUdf0xOFLT0e8zHIO+5qXMfOLKa4m8mfLodTNfyu87aliWgQs57xBB7YAg1+ByNR67cqlQiCcQChUKIhH3vE5cAmEkwMUKbKhZAhFWQrE/qGI1TMiTFxHmXgSbKkwUCxPhQuQJSrnQOUZp1ArtY5YwRyUTWoEkhyKR8y/m/AUQv4shN7yYDRZwIwvfkU/fC5nhe52n8sjkYi7M7T8kfoV9KbNp9kbTHfCB0nxqQ1UiWic1UGKh+opjOqwYSrogz45mNawFoUE7Q6JG1KXQoPCR1orMoOy/3oljL4c+3EprJ174RzIviAaCoUFiWzevXDE4PTTtJRyLlalsyIMR6Yg13fP7SLoumR+FKAJdkynSSZJ5VDisconyqTDbKnP45Ubo2FySbncdwQNPVGTHRhWP6dJTDx3buBkzUGaSam1iz5337ny+utrkzt/ZnqWs5glz/aZ9+2kirNx77/S2zbU1Brf/R6fWam7ad/eRzz10fEM4hphrTi4c/wcGXFXi4J5dK1ZOrrrZTIqKMP3Yzw1bW7ulNNhS2lW57EfrZO/PGQan9jnMtWsHxS+xV31sPbu1KcER0d9Kok1tySevn33QcSElzSDpqJBUdrFj4XRkrhkh1p/zkqyP+pQlIa6EBCSVCXzpyrMk89B1STSk8EIha367HpJaiVI55Ft12ahE//XOXTOb9j5w9L6jOzf092tFtzs2ERcWL1Cx9MKBu1pqOiod/QAfKG2767OP/tbJe2TjBTTOqUVDcxNirjd78+aUl83t3LB3z9ldQz0xiouotu/P5+5+oVRsXYopmhGWtt01kE937bqhbarfTbDl3PHFUJfXsZPN5CAMMg6AaYzBYfQDF5UO0AwwsAY4kOV8MiSkhHlkGWXvR6TrINJtjoK8a4v/u7Y35JznmtbqnmKtXpyQaWfqHIfWOqkgQJAstxPO/ZW6zDFL003Gw5PG5dRAuVStT/RLaz6wsTUuc870rESj1qNhto/eLlYtY8CwLvgZ+2DrRTWmNOGLHzho+y71Rj3aE+ap6e0NByhsVy22xsOeZwBT9FOZuOEOOmpaU3XDjhn/+tmHjBHTbJBVmisSIA4sTGW0NUpBG0XiLeiUxFsxy+Cop2oNr2tCVbtGZK6tjAX2YS2Snlca1DasZCeYXZIEP+9FW++nk4np1gXbvlnmPIZ3WVHNSJ0+sPHqe3L6PNh4ABGUg/XcFJPNstbNmP3wtC0sql29iMXNr+dp+cXaeRFc9vEfdnKfjWZ1kBTVYG3PpgJk1TDbILnU/A0pbgnHUzK9WJoI3UWqE3bX2jMVqfZZVnik3SkXbizPebEr/yVMfIl4mPP6xNLCDfkxii1n1MgjV+bJ3DBltmTj58R7/DzizFXspuawPKcX2If2AVPbSX9g/oCtgdUTijxrWs43SzvNcjg4acT4wXNQdpcjqgnPlmT0MybdeqhqF6vFK+cH6tTVd34qV9rUwzMbBvs+9ae5dH3o31VrTj4b4U42no3ktd+fTxTW0tiIqKP5v21tbuvkt3r8Zxvp7gx1Z4JNj/vfHZ3u/UKhbCZAC62EkRGHN7jB7oGR1Z3cCPzNRawvYLewg02nKsGtZEsm2vE2ARwAPGKobEzSJGydiAjYY1ZK4cEbquXpM1s+fJ5rxomtWT2Q7+1JxFhAgRaCG/y79A9AMMRAUicn+Vh4JA1nIHEt9KYIasIYdJKvkySnOkm5LNH7D3//EZq+dTwa6b5jczpXyqPMT3yPnnz6F8+Uh4//fs+AMFzQPHB4JeLpXkyPzh6ip39BsV88zZ/acWpq8uGhTG1ibGBtSqg7Tn3x1I7Wz+55dV65p2QoDqgPqGlUdX0jk0kOV74wg6r5V2+0xQKY0vrmpDwB6iPpj+WhDOBcHFMln5a+VYeQdJmrA/GQTlPm0BRtqlYrTPiFgYKhZkbaae7l3HVhKaG9lLVGZPqxVnq2rbBnQtU90y6cdf3nP2Cm66Uanw2bnG3r9Fmp0Gc9WvdhQ6VwXRdFjY1I7lPCiqRiK1BsULdFmSJbDFOnkoIWguQtgQSWoqe7vP2/DlDlWnVMDcF1OWsrU2O5AFq8lSzEEQitSHj5VZN79zZOejmz9XPbpl47k+Yn6fl92Yt3f1lJxBTLAXsQpb5V+5rj2YR22vVtysq0btbyoqf/enubp/GnxD7swZG208hB8UBI2DGwc0Yqa+dHQH0kFIqQoBY/volAG+kpJKERIDTNJLFcX0/aS8ZcU2MFKuhSU0FcPpz4y0J320fE1VJeC1L89pDa3Zj986IDrh+mBb+WDW5M/52970X+wv1yM2TO8mw7f3xOnAzPxdLsDrajuf02MvS+HpnoAp6sjMOelK1MN/RFZghjUQMnFZ1TbgRzD95gcKqMPKZWjKYG1pVq7SRtoyrzA1lq61JhaRUVX/V0P+Xrfpg9kTWSVJTD+kkOdMJlUkxUsooWwCrlbqPTab8XOtXr7fNifxRq1x9Fff5in0ldpmn6am7gtm3FvZXhzUlUej2rM6WE5SJE0mKpaNdw2jMQDzmGI4O/L4005f8QhOPRaOtL4Wh0OMTg8UJXYjjfV+hLTZZHKOFG00t1zcLKhJX30n467zuJ7nQuEUmN+p7iuFqTtf835aGQa8SYx4rwOjezv2oGE0NcN8A0eG8q4oD2iq0KqTI1L4HtJs0RiO91rpPMBKs6VxcwkK6yBZN03Zi1SCbbFehehC2x6dFP7iQbHr+hpw4NrPw9zdEQ7Wdke30v+hr6beDXuXicsUatsvKmkcHyQL4v29MV9+JeMoHVRRsRNdX2LcvamYTjiBfitPxA/k1UgmKq0AlJ1OU7etZ3OydGn1ci9OXnw0MvWcTvf44orcm3LOMVxE+Ptr/5a60Z1LS+296nXrrotE7QMy2nfejk0nr8fc15/eRJGXiF187ZyDnlhEhCt0fZTvZo85HRIrf0XJ8rBK8kuWKIrYx0IIxu6YsuMStiscgxZkd4xObH4KtYxLYi84jUga0GF/MMIbwxwwxDmTVlamSK2O3bb9u2edP6dfWJlSuGBgfymZ4glYhZJkzeICMaupvSJGW5pk5IYPKu//Nb+J8Fy1GbNIsgPLVMtWlidVINKjDqShjBBMDoFD079wR/7JsntFP052+G575vOtqCYb0VnhlDWAu4aR0e7j1durmV3rhbcRLZ0up+2x6dOTQzatu3jp/sHabDT7zxJH/8G4/d+tG+7UFb3+0dpd/J7NiYXbWhvirfza08PlZ9uJf9L9DM7WYAAAB4nGNgZGBgAOKp1/Oa4/ltvjJwM78AijDcEF93Fkb///o/iaWCOR3I5WBgAokCAIVoDg4AeJxjYGRgYI78X8jAwFL2/+v/zywVDEARFKACAKM8Bs94nGN+wcDALAjEC5Bw5P+/zEBxFn0QGyoGUrf6/z8W/f//QZjpFAMDCIPFgZipCaoPrPb/V7CZL4D8l///g9VEQvELJD5MH9R8ljIGBgAslihRAAAAAAAAAEoAzgESAWwBqAJaAuADogQkBFoExAU+BpAGxgb6BzAIBAhMDFAMjg0SDVoOMA7AD14PvBAiEJIRJBGQEeYSUBL2E74UaQAAAAEAAAAkAfgACwAAAAAAAgAsADwAcwAAAKoLcAAAAAB4nHWQ3WrCMBiG38yfbQrb2GCny9FQxuoPDEQQBIeebCcyPB211rZSG0mj4G3sHnYxu4ldy17bOIayljTP9+TLl68BcI1vCOTPE0fOAmeMcj7BKXqWC/TPlovkF8slVPFmuUz/brmCBwSWq7jBByuI4jmjBT4tC1yJS8snuBB3lgv0j5aL5J7lEm7Fq+UyvWe5golILVdxL74GarXVURAaWRvUZbvZ6sjpViqqKHFj6a5NqHQq+3KuEuPHsXI8tdzz2A/Wsav34X6e+DqNVCJbTnOvRn7ia9f4s131dBO0jZnLuVZLObQZcqXVwveMExqz6jYaf8/DAAorbKER8apCGEjUaOuc22iihQ5pygzJzDwrQgIXMY2LNXeE2UrKuM8xZ5TQ+syIyQ48fpdHfkwKuD9mFX20ehhPSLszosxL9uWwu8OsESnJMt3Mzn57T7HhaW1aw127LnXWlcTwoIbkfezWFjQevZPdiqHtosH3n//7AelzhFMAeJxtT8dWwzAQ9BCX2CT03ks46gQ/JMsbW0SWhAohf0/sPG7sYXZm+yZ7yc6q5H9bYA8TpMiQo8AUJSrsY4Y5DnCIIxzjBKc4wzkucIkrXOMGt7jDPR7wiCc84wWvWOAtyQXXglQerTK8SX3grhqAUW/DJufNZ/ShoA0xs1wWjsKaKEyEaXNlWhND2Zi1ZsaSznkIXHSFlSJER9m3bMhUTrZdGPOlouWOFdGOPq1JqVQZscpaZWrKahd9V27nkA7S6NSq6DNvpX4f8WOqpF4x+gmzP8K4CmlPOk57LtWg5sL020DYPTAbRjD/FbmjJnNk1WY+LBz3j+Whi33t2fakrapqqY2IijtfRk+ODe1J8gsCHmwDeJxj8N7BcCIoYiMjY1/kBsadHAwcDMkFGxlYnTYxMDJogRibuZgYOSAsPgYwi81pF9MBoDQnkM3utIvBAcJmZnDZqMLYERixwaEjYiNzistGNRBvF0cDAyOLQ0dySARISSQQbOZhYuTR2sH4v3UDS+9GJgYXAAx2I/QAAA==') format('woff'), + url('data:application/octet-stream;base64,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') format('truetype'); } /* Chrome hack: SVG is rendered more smooth in Windozze. 100% magic, uncomment if you need it. */ /* Note, that will break hinting! In other OS-es font will be not as sharp as it could be */ @@ -17,7 +17,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'fontello'; - src: url('../font/fontello.svg?92539127#fontello') format('svg'); + src: url('../font/fontello.svg?4112743#fontello') format('svg'); } } */ @@ -73,6 +73,7 @@ .icon-globe:before { content: '\e812'; } /* '' */ .icon-brush:before { content: '\e813'; } /* '' */ .icon-attention:before { content: '\e814'; } /* '' */ +.icon-plus:before { content: '\e815'; } /* '' */ .icon-spin3:before { content: '\e832'; } /* '' */ .icon-spin4:before { content: '\e834'; } /* '' */ .icon-link-ext:before { content: '\f08e'; } /* '' */ diff --git a/static/font/css/fontello-ie7-codes.css b/static/font/css/fontello-ie7-codes.css index 689c8e43..fa7c1002 100644 --- a/static/font/css/fontello-ie7-codes.css +++ b/static/font/css/fontello-ie7-codes.css @@ -20,6 +20,7 @@ .icon-globe { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-brush { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-attention { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-spin3 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-spin4 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } diff --git a/static/font/css/fontello-ie7.css b/static/font/css/fontello-ie7.css index 23ecfa3c..b37a63cd 100644 --- a/static/font/css/fontello-ie7.css +++ b/static/font/css/fontello-ie7.css @@ -31,6 +31,7 @@ .icon-globe { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-brush { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-attention { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } +.icon-plus { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-spin3 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-spin4 { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } .icon-link-ext { *zoom: expression( this.runtimeStyle['zoom'] = '1', this.innerHTML = ' '); } diff --git a/static/font/css/fontello.css b/static/font/css/fontello.css index 0181fa62..38caec46 100644 --- a/static/font/css/fontello.css +++ b/static/font/css/fontello.css @@ -1,11 +1,11 @@ @font-face { font-family: 'fontello'; - src: url('../font/fontello.eot?13201279'); - src: url('../font/fontello.eot?13201279#iefix') format('embedded-opentype'), - url('../font/fontello.woff2?13201279') format('woff2'), - url('../font/fontello.woff?13201279') format('woff'), - url('../font/fontello.ttf?13201279') format('truetype'), - url('../font/fontello.svg?13201279#fontello') format('svg'); + src: url('../font/fontello.eot?3996201'); + src: url('../font/fontello.eot?3996201#iefix') format('embedded-opentype'), + url('../font/fontello.woff2?3996201') format('woff2'), + url('../font/fontello.woff?3996201') format('woff'), + url('../font/fontello.ttf?3996201') format('truetype'), + url('../font/fontello.svg?3996201#fontello') format('svg'); font-weight: normal; font-style: normal; } @@ -15,7 +15,7 @@ @media screen and (-webkit-min-device-pixel-ratio:0) { @font-face { font-family: 'fontello'; - src: url('../font/fontello.svg?13201279#fontello') format('svg'); + src: url('../font/fontello.svg?3996201#fontello') format('svg'); } } */ @@ -76,6 +76,7 @@ .icon-globe:before { content: '\e812'; } /* '' */ .icon-brush:before { content: '\e813'; } /* '' */ .icon-attention:before { content: '\e814'; } /* '' */ +.icon-plus:before { content: '\e815'; } /* '' */ .icon-spin3:before { content: '\e832'; } /* '' */ .icon-spin4:before { content: '\e834'; } /* '' */ .icon-link-ext:before { content: '\f08e'; } /* '' */ diff --git a/static/font/demo.html b/static/font/demo.html index 6e4d3eb0..cb1aa970 100644 --- a/static/font/demo.html +++ b/static/font/demo.html @@ -229,11 +229,11 @@ body { } @font-face { font-family: 'fontello'; - src: url('./font/fontello.eot?97354950'); - src: url('./font/fontello.eot?97354950#iefix') format('embedded-opentype'), - url('./font/fontello.woff?97354950') format('woff'), - url('./font/fontello.ttf?97354950') format('truetype'), - url('./font/fontello.svg?97354950#fontello') format('svg'); + src: url('./font/fontello.eot?15755415'); + src: url('./font/fontello.eot?15755415#iefix') format('embedded-opentype'), + url('./font/fontello.woff?15755415') format('woff'), + url('./font/fontello.ttf?15755415') format('truetype'), + url('./font/fontello.svg?15755415#fontello') format('svg'); font-weight: normal; font-style: normal; } @@ -329,23 +329,24 @@ body {
icon-attention0xe814
+
icon-plus0xe815
icon-spin30xe832
icon-spin40xe834
-
icon-link-ext0xf08e
+
icon-link-ext0xf08e
icon-link-ext-alt0xf08f
icon-menu0xf0c9
icon-mail-alt0xf0e0
-
icon-comment-empty0xf0e5
+
icon-comment-empty0xf0e5
icon-plus-squared0xf0fe
icon-reply0xf112
icon-lock-open-alt0xf13e
-
icon-thumbs-up-alt0xf164
+
icon-thumbs-up-alt0xf164
icon-binoculars0xf1e5
icon-user-plus0xf234
diff --git a/static/font/font/fontello.eot b/static/font/font/fontello.eot index a7b690a7d7864f9799f11e78da248e8dea1a1fbc..7dfef262db9c104276310ad6c8aeeb45ad3f33a5 100644 GIT binary patch delta 782 zcmZ9KPfQa*7{%Xo+JYA7AKI-Vwkz9~5==2&C7Z|2*~e7n=rtazJQ zi*W$)8Eee!?_HUli9eXS1+YE}2a*{@4XFvVW!4Te!6u5IF;9)vWsj^`_0lVJ781|dHh!GewofNsTAk6Y~Sm>*8!3?V6IGgfHDDrG-?1ZX}bXq09%g?aFFz| z0UAh`3~-2a)qswJE$X2T4wLR0zz2MD8Ng3^(jWwpCPM}|LP~`?Xre3AA#@;>wk*Mh zsl7&U7k5EIOFRTKH)p9QOtmmhpS+)hW6;E?ALk@FD9Mu5($LC0ZfmndLzUDN>g=GQ zxuZSSDbsMAMFp=%jtbl*3T06k6+~9{`WP9Xca$c&S=7@_!N(k;XY+3?i2DALTMXAV z&aU+OFWXOS!^ZU=4WGTQmj9_X80lmItq@6YC!m!hN$En}vAVbROZEjvljDgq;4C;d tTz#&e^^5MSRHa`rP`cJ;<5V^g?J}{Twh*1OnANeHIV~aIE3L`?nm@V`zIOls delta 621 zcmZ9IF=!J}7{~vYOJgxHNt4oQJlkuks8~}qAv#E{A~iVGrM5WOYnoh!o;^$`aj|hw zs0KAWaBGPUQlu!F#X)d!DJnW@>EKey;1EMCA|>&EIb6KQkN^9B@B7~S?pwYk6$+9I z!@&5Nk}K|1jJjSLzBgY0q)`B4NkcOqeT`)4mjQVxIhRvi&Bi7WWf9c0sT+4o4=3m+ z0k^4ZS(9-;{V8g@K64|TUU^Xl+7iH_bD5Mj9eh;|0Y{5Gk7pRzu_`y{-_h^S7`gn- z##r+^162l!GqXwU$?Iotfk=)%VQ6_%%I|tg|At<@rWvUZi#;m+I^g(d&SrD(f2@51 zj<2xk1@n5!+&FuLxkH~tS-K)U7Tc13cncD%fg0r2Zh*Rz`CD+pYDD2L$naDHT^^Z|7?VSzAE*={=!s=QPW zdKJBHC|7-_f59zVbH|rpB>qpuX5^&QF9rrD#KPcIZ`GUkb@_6>HUCBbdPkyTDbOBx g9-Qm!YfZAh;yvb;nI4Lch^gqJaK>&|?!>~Lzh+jVrT_o{ diff --git a/static/font/font/fontello.svg b/static/font/font/fontello.svg index fed9129e..6e5616a1 100644 --- a/static/font/font/fontello.svg +++ b/static/font/font/fontello.svg @@ -48,6 +48,8 @@ + + diff --git a/static/font/font/fontello.ttf b/static/font/font/fontello.ttf index 5fb1466a2af114268066dcb77a0963f9449eaf3e..1fe7c631348c3a8f9d12ba8b15e70de95907627a 100644 GIT binary patch delta 775 zcmZ9KUr19?9LK+BXLnkf`{Q<3X4`Fdn-g={HXTuvz1XrIB!*={HRjyHtzFVWA#y~$ z^iZ=)j}k(J4iC~l$s zWzyPoc6_K;`L+TGaUk$9lS&LWzM75!!2s=dWhhXyz$@f0k@seDqhq(s{gqV;+@?S= zn@=WQewuj`6O599pWxNiKGN-Ud=o~zrFb({z)@dzs9)I`XAiUy`+umX z4aWtUvP|l$ClC poVQ=5EUiRu=}oYXQ`(0EJqG4e?V%~bsAR8=sLw-pN(aO4`ah*^yn+A# delta 602 zcmZ9IL1+^}6o&uF+FDI)(xkLnW4lch6?Mf#ss|}5QiFI9DV3t2Ynp5hUAr_(iI+A9 zJt#$62E4Vj3L;We%tb`-;-#qQv6dnVR&wwVixy9b|77vv4j=#gZ{C}E`-(-eG(Hud zC<5XffPu7aI`=*qdHP3yHk%%E^~PHD7mz&8b3N-=_U-AZLHa9z-?7ZR!+41PD7DEN zzMjo4Je>m?Qox>*xr{j!c|O+x9GK*JPmY0&i&~Zb4gJoX?H0zX1GVoAlo^;D9!Z<` zUp#&d7%qLvHVcj@Y_&AOHXZ3;+NC6951JAO`>b^k#5pZ2$lRAOHXbkN^M+aEg(TS!ZE$Z~y=Z zumAu62mk;82mk;85NB+8W&i*PxBvhefdBv~(n@gZpoJOBUyGXMYpHWRy{ zNN8wfVE_PsBX9r!03ZMW03-*=1OI4kba(&&Bai?908#(|0FZ(Y|K@COV_^UQBjf-8 z07?J=07|vhsHAOScyIs!BrpH~03ZMW03ZQ*4W@2kZDjxeBv1eV0e1iZ0?o{w9w2aU zb94XzCCC5(0TciL0g$Nm?#FO)WpDrhCfoo30D1tEQ2|H-p39S)0XTp7zzj10c%0?Z zIc~y06o>K8fsl=CBxK)dQ$?;Rqa1|uz-4lVNZf+P(ko}EQbGRX_qr?>h^-%z$I^Jj z`+!ZLBhS)>>XV9cEwx&;>m7F6^)4TJzTrqKeH+?~)oGUIX_1<=%7Z-4liV!p^%{)! z?eyojzh0Gge{Ju#Z+CxryP+?4b>bddY_p?t?a^nS0}genV+NdX%8)b8x!{s3uC?PW zcii*9BTtO9P4ABr{Fkd=eyaC)8kLE;GII<1zp+pnu~0g(Q2Mc;xnMyP!h&Xn1x*bL zr7H`XBo@l)ENHq|(44WLiDN;t$AT)rf_lJ$%D{pe!GdbRg1R|Tw@w9NwNp!^sZ&*? znNwe+xl?JRg;R5+#;HEi%Be&0z^O>`*r`qO#HmtpGX*={js(+Zji)Q@Wjz z>zL9w?M!25Je1wCo>pl(EV=A=?k+&;)l56n=>oWW&pnTO&VT;@`@jD`V8qz9|IYuC z|1KL~*=A3^E2b-q(^f&8@kK)Q5q~e^d5W4IDSA=T@+(M}mr`{dmF1;g>7$0c_^1wi z{+H3I*l6t4S8zlUJ*5Bus9oHO}3@E zv4;1WjAK??nW>qJ25Gvs$aJAEq61fER1%mj7i^v>3ZKOzK6T65!bBloDSzIaPFQO1 zNU>USd6w#prSFud75ej~a;;hqCbG1KD)q)h#TVKLp-L~vDqPyD^!a%&>+y7V`ggrt zg8P~DmYjd(he4Kd{w1egIGwLYF8R4{n(5PC^mNpt(?K$R*~(g%69cZ#6S;)a?JV6q zd)Ck8d|aq+aIh~+yZy`P;eWfAN72Q)9B25*z4;O3u$A?(-ez|qYAHgMo5Pm(rq>IE z8jKKRpGzVj8-p3V(7wIHBS|;3r~2 z^+u?%f}jz4BS^MqSIB?D?D%K@>93C7|DV1(^y445FwemH_<0V!mjB65@~{1Bagoln zr=0nO3FE`BU4;&PN+g)hJT}rCWC8+(awtTc(+s{yDhcr^#u9PIMms&Os;QA;JTH}l zAkF+3pQH-zU*GfGG=HCYhSS5}zxWr&wa5O|`~UKZ8lT_&+^f&+rtwd|`N$)0{!(5T z!^^Lo7Z>?C$f}!7vQ6wxc4u>@+QXT$M}zwA-iUWjZx|{=fi+ULGF4F*AwQ@t9b=^7 zcY$dFzY9!=T-K7F*8>Mn13mc~T$oMMCKY7Oi zIvTUL9E$m|P2+a#{F+~`$*7jT$?Tebx?07`q@Ud zp}8)TunZi3hNjm47te`QPh!^r>)G>Go0jYj@w}gGAYJCmW`rCJn zeksW;rQ#4NKW`aV-%~XXX!P83E zVZrqix(*@} z!}(k?p{xD~v?=crbg2js#JY7q@IB~A8OsLf>OeB zJ{0hO17MXp2j!~-ox$`_bbQV36TA7|NA^<2(0{|SlY^QXosQ`G?OolbuEZWUoLEn= zQ;TU^d_^?|t*CKCH^@?d!*GLQyRC71y4y5F{BcMynhAEQQGJ`IC}z8{MTghS%zS2M z=7g+|Wm7#B&DB!Vq^^w^Q<<2h-)A~&RjrwSRb9=gL^C~6a`domS9k6v-O;`28=Bf{ zRCQyf)3iGV_zU-dF|okUvod@Y^wEO~02DQ@a!ozPRKZnPvm%&K*fDA88u58q5HqlG zY1x8J`Gv0HaIvhbJzrI!lAN996Z)8n2WOjNR*JZO8qbPE;a1^PID z0rC3*`E(cILK#{o&{5$Ajks>sy_uCn~>sssDXT>>jA6v=#ni=_Sn!)?nEOegO6tUqUwvtv#FBIg<07aI?tTd%hg8}ciEhlXiKcQuWU-3C`= z$IryvN-Ht-^g*Rbm(pXhqm-X=?b@|-%8JmAqwx1D*d5K?y&fkK#hToRV=A0wQXn;o z^tO`m9AiK`L7JGC62Q`dbE+DD;+#4wEq*E<8yhJVx`J3=yf2wd7$H+|C3L~3rTS}) zfQtQXg#wn<%kgR{hy(P1g^hR{-{|n6<3`hP@k<)ve2y7tYR6?<)YseX^m!Uo))4)qSA~^4H{l7qhYEhr%_t zSG-IPLr)QfDmP$C> zFjK~SlFS$>s;SJ!BOLb0B}&dmNmvy6eOre%db7;)BHpb%&B_0>o}NcD%Oj9CHPbO_w=cMCm#RIZysMba_GQaduMiRuhnWL{M06V_?Dms-wdnmCC``q z5)fGeeuiam&9GeV)WfRlgiQb^)vyu%1U7{})PJe0r`lzK_Ijs%fc8OWd|5BYZ*<0& z<)Bl(v411p=DRo;7dXWt{ zhMG^hZu@{T4P1Zi-&~)@FK+15x`(o|qV+Re`R{FwqCU12_g6oEy)S)>dc%s=&t;!~ z{qaNn&GpXrT}>3L)gr$X>ZruEAMi)ScHmmj^vn>~*b=N|5*+^0>`;S-xdd%MHGUL; zma*>!f(^Fb?Lgaq%N9M@y2rBaMhy)~oRbY?!zB#;0srFCyXb@O3WD%m+z+XUMA1eE zK>72ncW9_Rszgz|CTrbo@jq$3+j=Lwwdl*?>%(ct_rT+Pli%LPYLz}n;R7$k>Z0`S z%S-F5N_=%c;27h++gaPoawRX@5AVl2hVV8^)?)%zXHj5(-PaxxZ;E})0UzGL-fKDx zw2Zb6_JH_o+5UzLGak_ilOXkQ2xIr66CtvYahx&B48z$5mZHrvO^ax^_Ova3^aEY^ z!r#|t0DXo&sSk&%*7h%VRe%pGKHS!T|2CBQ>wPqh&vf3wwW+zexu(;XPYn9;LNZ~( z@YO2Za-*7mmv&ew_Lt(-F^<-PLaX+Hmh>P?^iU!&KU1E&7sxw zPyU#OGHX}m^Q+coTJQXE?=T3^n&IAbW#+&$x6gckA!gY@mgiHp75l=>j;H5$SC=>p ze=3ZZ`q*%@4AO#)!qSgnkqASGLeE08j1-zGB#ZTAOhXWo><6H@6sR4?0Vjf38bqYx z>nZT!v($?z6TO}Duf7+?%JCQf%}YFi+pj&aW`@QmbhwiPO5;r$ysZ+`|JSjL&(M!mp)-T(VJ=xi(2On4WuEj|DL1Ti-k?nJZ3 zxX=aHk1<^nx{O&3p&76f5(X^*xsC%XL2hU8#l)vdNl<8>E_RrZj*q^X} zue0A`pMi`t$PoyIKMSw(Mr8QElnIcOyfR5OL_77MBmK zffmTdctIJ%V$^a;ma~Lt3UPm4^L503UcPkm2*?`MpseW?IaJUH&{_9&%m7_AJu4I)y;a4y!IydrR;0v^> z*Dwk$a`mNpP^n|NSeB=y3U%oW@m$aAt|(y&vRsz)0`aI~9ey1nVZweR%ORbAdcy}Q zOcG+t+L+AJh0>^?MIN(3IO)r4!>^YnDb=VKVp207T)c>WD+-Z&6Iws-tsZ2vhep zO*M>|;$a*NE?l7?;5OnG$A?so5*Lm@JSas4L$vW8Zg>KLCYS40Atn5hk`|`G1Vn_p zQXC3uG|T~VQWV`#bw@z~!LS-m#8G$x-MI`xxn)39nx?C!W8MFo)8tSD{ZkS)q@Yy? zHjfXFuw7cGsp& zyJ_~ZS$a9w-};`ndlgOQ4*clxH)yc@4|m@(J4=6?JCJLCeXlX&p#r|++TVhM{5LU& z__QB>^ib33!G3cy>~~%`#!3 z%*v(+Ce2_~8Qwzjsp1Xsp^Vqc$!b|X(6v<1j_3sWGJhtyR;dBFtRN(_^ape+yueg- z{V_OF)6wsLGaQ4y=B3Ph;>v4@yqWUobu(Ye?>lN(mVpa7?+`)lfFRf4ay1^ia;Z>= zClCr13L+8ryiQyKVI;uC3T&uZ0ufe1u|KF{HB88p7ZK)O1e+>M6blpKLgWcbxzIUA zY19hsW0o*SB@< z){4xa?7!ZLV=sq3+)8UFUie2cFNg+$p+RC>H?LeVI6XA&B^-;DscguD5$T9E-ShiM zx-OZ2AB89aU6U!&Ns@U~IIMDs@~JS}Ds%YdM(EgFl5Te$!2?fJWXDDokLl7=4;|aM z88c93l4@;Y&z<+~e7?Hcfm}^ch9RCLfTvg)Wo?Rvfw7Zxv2vGl@$yIN{GDjod*A1H0R>$8vk*2#Nh;{`O%sYOF` z6JoA6d-LX$m(A_muy@bdT|+%Fii@bW@6YG%exX!sU5Y815tg>yHIPqt?Yg0Ds^3kp z<=pYbP?y)Slg;EH3^ERYX^g>P^aB@vl@8DhFt7$VkmY>Yie)UYw9=XX+e>);g&mK#(lA6VCmWy38?4(@n<1lg8!LK)F<{ zPxMP`KCrPhE_2TGtVE;MqhYp>-Y!-xW5BR3_!;|P>qRxDG~tUMIB5GW^+r8^+7srf z>Fo^%C~Q|Pw#LJrX8=?5Q<=Eo4mxUDQ+30R8UOm(hl~-^Y>-u&D-s|MEKFszHA+Dn zMdB^!l*C&x%iyS|Y7MVzLRGs)WUj4@1@>VrlAc!@)HbYSCzxH51V8UZTkofniRsn_ z+rC-mJcf5!QO!u5KCtoXdvf}JJlJ>u5tM`V+!T||vewO*{qVFcEUI0-h{esX=V|%H z+IbON_VFKfa-WT6b&wR*U~SK)0%X-N+aS5r{0%8?3CB}1y;zzE-9@SscGuc76{+@F zR(Pb{DHm=m&v~&c|0PU(iFlav`oz-04f!#OEoaooBUk3h+%RRfWaH<5#C!Za;>=a- zrsl9brx)0V_5oAdNq=DefUSYm6N)@*TFy61JI!)9IBCTA!E;b{mm{hP&z5BLGbY`7 zsA?Ch#Vh9r>eSVDekxbm)Wb6y2Kzqsr@3@}=-*XqPCgsqPBxy6Fx}Fb!UQ2kNe*po$mcYp=>5V3$28a5r;Rp!R~>P)t%f3{LMwI zFJQN@gH5L@!L4LVCfe~f0UQ84VyJ9P(j;u1hzQtYR!ZT)8>;2$Gh04U5tyw*g z@9jy%SU`amf*bt1^bbHV#6VIfC;3=-Bn@XEaV_+w2x`I@bds-slO(4)Nx3Z1`wxHr z5t_brJR0e~V{CF1E`OpneUqNjgBv0psR zpW1P1YVzTsOl@LpU~NjMJ5GJ^)Q;BA?s;`yxu;|(4yX^PX;gK6Ba=xESH3WVs`*!M zw8a9L()#A4JOS!|Bk7Ojp$y<$98)EqmcCVokaU@=1M!efQ|8bVZK_r)O!$R?f}v(c z+G+0P+;w3op}mx~Mr8W2R(iIruxCQmJ<~3nb^Yf*V5aM(8lMfDoNep$S*g%xJzDo+ zL#1$C7e$SYNbXa@ilkyIP;5}QMVTU73{$6)f);}0ErA4omZGP-y#2opP~}>6Obx+x zIcqCZW4QoYyp=4(5eThFc==V6d-pa@dO5T8bK9m~JCo)o>G^%xi+6unNyHS(0ecXo zzE%60MgGG5ax-Mk@@zYQd`_GU&&AU04z{DY{Wdc6z8;zA z0-mgl!=99_OgHpJW(Z?Z11A-oQ*H!v58hyKs*F5;rdEum2G*5o?IdlZD)R$bYU@&A zX%!V;^>jbw>wcI$ku{Q3l*9T-4s^n0QcP5`iWa~sNG97A=w5^^vFXuI?j#$39>1Zd4h^jQJ+{)%GpR+L?soh!^6t{6PLqRDxov&$jgFImLze~u`v$+s-y6~s@Ew!isntr^s`zT4iXUb^VCPS7(p zEvJ3x5~ z-XJ3yx|`A@Wx1wKNMQ1=|MOe;p9RZNn>33cJhe=C z?3*XFQ}pL=hUdO-I@*F^y%nArLs$#AX&oN!J%3%gxs~3yTX7QE(&~QO9-TQfGiuwn zj-Tuuro&IX@g#rz8;{-k(Z20LTi@*+rQgZy*qB|lp}s2L&8<8>R(-ga{V&kW?PdS~ z0C=2ZU}Rum0OG0F^P1!NZN4&aGrs_eFx(JdcNRwf|N1|PrGhyf$mL*Q0*L|ug=h{A z03djrV_;-pV2=D>$iTo-_W$eu&ny)TKoJz60sx~t2G5f;BQ+hcnJ<9+m;e8R)kH$^ z3nV^FAJlx7G6n_!ES4xylZGQPBU%nH4!{py54;c}5Rwrj5s(q)5>OKM6TTE_00001 z0000av(_V(0e?@&R>Lq5^bnWWB=p`(IO+sHB+DCHM3#gKA%9QoJZ|h^c4qq~d&$nK z(;-6GPdUwPwbW&Upx2 zbcK~7L`T`TY{*njwp|$WrK07I71549tx2g=8L`S*WopW57kyW5=a3H4=+vs{GjFAS zAMs~qb74?)n+~{9QTjqp^JU( g+4iKZsuOCdjfjdnUq(-k4ed$t3j!W&1Cw|rd~S+7#{d8T delta 7738 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 AZU6uP diff --git a/static/font/font/fontello.woff2 b/static/font/font/fontello.woff2 index 09fafb310e4891a3337176a229ae0fdb5fb56f55..8513d894effdd5926975a2c9987741e1a01fcf3a 100644 GIT binary patch literal 8564 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 literal 8456 zcmV+jA@|;QPew8T0RR9103iqf4*&oF06$m&03fgc0RR9100000000000000000000 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 From a8180d03be3488aeb7cfc811a1b49f6519836ab5 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 19 Nov 2018 18:15:27 +0300 Subject: [PATCH 017/123] it works, now to clean it up --- src/App.scss | 1 + .../shadow_control/shadow_control.js | 6 +- .../shadow_control/shadow_control.vue | 11 +- .../style_switcher/style_switcher.js | 38 ++++-- .../style_switcher/style_switcher.vue | 116 ++++++++++-------- src/services/style_setter/style_setter.js | 3 +- 6 files changed, 108 insertions(+), 67 deletions(-) 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 @@
@@ -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 @@ diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index f2c9c13e..7c375206 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -172,6 +172,7 @@ const generateColors = (input) => { colors.panel = col.panel || Object.assign({}, col.fg) colors.panelText = col.panelText || getTextColor(colors.panel, colors.fgText) + colors.panelLink = col.panelLink || getTextColor(colors.panel, colors.fgLink) colors.panelFaint = col.panelFaint || getTextColor(colors.panel, colors.faint) colors.topBar = col.topBar || Object.assign({}, col.fg) From d64f4ab363b8fd8b6fe4542abe5f991178f4d3d4 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 26 Nov 2018 20:14:53 +0300 Subject: [PATCH 070/123] fix preview input text using wrong string --- src/components/style_switcher/style_switcher.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 157a8534..655e0589 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -97,7 +97,7 @@

- + {{$t('settings.style.preview.error')}} From f039b79e5ac7da33c3664241e0d20d3c6964872f Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 26 Nov 2018 20:25:14 +0300 Subject: [PATCH 071/123] unbreak user profiles --- src/components/user_card_content/user_card_content.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js index 064c984d..e7ca21c7 100644 --- a/src/components/user_card_content/user_card_content.js +++ b/src/components/user_card_content/user_card_content.js @@ -12,7 +12,10 @@ export default { }, computed: { headingStyle () { - const color = this.$store.state.config.customTheme.colors.bg + const color = this.$store.state.config.customTheme.colors ? + this.$store.state.config.customTheme.colors.bg : // v2 + this.$store.state.config.colors.bg // v1 + if (color) { const rgb = (typeof color === 'string') ? hex2rgb(color) : color const tintColor = `rgba(${Math.floor(rgb.r)}, ${Math.floor(rgb.g)}, ${Math.floor(rgb.b)}, .5)` From 2ebc06e30f009204eb289057730f9fa4a148d499 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 26 Nov 2018 21:07:22 +0300 Subject: [PATCH 072/123] fixed keep checkboxes working when exporting --- .../style_switcher/style_switcher.js | 51 ++++++++++++++----- src/i18n/en.json | 2 +- 2 files changed, 40 insertions(+), 13 deletions(-) diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index 0cceee4c..ccdb4c4f 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -332,16 +332,34 @@ export default { }, methods: { exportCurrentTheme () { + const saveEverything = !this.keepFonts && !this.keepShadows && !this.keepColors && !this.keepOpacity && !this.keepRoundness + const theme = { + shadows: this.shadowsLocal, + fonts: this.fontsLocal, + opacity: this.currentOpacity, + colors: this.currentColors, + radii: this.currentRadii + } + + if (!this.keepFonts && !saveEverything) { + delete theme.fonts + } + if (!this.keepShadows && !saveEverything) { + delete theme.shadows + } + if (!this.keepOpacity && !saveEverything) { + delete theme.opacity + } + if (!this.keepColors && !saveEverything) { + delete theme.colors + } + if (!this.keepRoundness && !saveEverything) { + delete theme.radii + } + const stringified = JSON.stringify({ // To separate from other random JSON files and possible future theme formats - _pleroma_theme_version: 2, - theme: { - shadows: this.shadowsLocal, - fonts: this.fontsLocal, - opacity: this.currentOpacity, - colors: this.currentColors, - radii: this.currentRadii - } + _pleroma_theme_version: 2, theme }, null, 2) // Pretty-print and indent with 2 spaces // Create an invisible link with a data url and simulate a click @@ -404,7 +422,9 @@ export default { }, clearAll () { - this.normalizeLocalState(this.$store.state.config.customTheme) + const state = this.$store.state.config.customTheme + const version = state.colors ? 2 : 'l1' + this.normalizeLocalState(this.$store.state.config.customTheme, version) }, // Clears all the extra stuff when loading V1 theme @@ -442,9 +462,13 @@ export default { }, /** - * This applies stored theme data onto form. + * This applies stored theme data onto form. Supports three versions of data: + * v2 (version = 2) - newer version of themes. + * v1 (version = 1) - older version of themes (import from file) + * v1l (version = l1) - older version of theme (load from local storage) + * v1 and v1l differ because of way themes were stored/exported. * @param {Object} input - input data - * @param {Number} version - version of data. 0 means try to guess based on data. + * @param {Number} version - version of data. 0 means try to guess based on data. "l1" means v1, locastorage type */ normalizeLocalState (input, version = 0) { const colors = input.colors || input @@ -465,6 +489,8 @@ export default { } } + console.log(version) + // Stuff that differs between V1 and V2 if (version === 1) { this.fgColorLocal = rgb2hex(colors.btn) @@ -472,7 +498,7 @@ export default { } const keys = new Set(version !== 1 ? Object.keys(colors) : []) - if (version === 1) { + if (version === 1 || version === 'l1') { // V1 ignores the rest this.clearV1() keys @@ -483,6 +509,7 @@ export default { .add('cGreen') .add('cOrange') } + keys.forEach(key => { this[key + 'ColorLocal'] = rgb2hex(colors[key]) }) diff --git a/src/i18n/en.json b/src/i18n/en.json index ab7b954a..74e7a556 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -183,7 +183,7 @@ "keep_opacity": "Keep opacity", "keep_roundness": "Keep roundness", "keep_fonts": "Keep fonts", - "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. When all checkboxes unset, exporting theme will save everything.", "reset": "Reset", "clear_all": "Clear all", "clear_opacity": "Clear opacity" From f8e17cbdc58651b17a4f5639d3719a7e533b0d8b Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 26 Nov 2018 21:22:44 +0300 Subject: [PATCH 073/123] lint fix --- src/components/user_card_content/user_card_content.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js index e7ca21c7..254d1666 100644 --- a/src/components/user_card_content/user_card_content.js +++ b/src/components/user_card_content/user_card_content.js @@ -12,9 +12,9 @@ export default { }, computed: { headingStyle () { - const color = this.$store.state.config.customTheme.colors ? - this.$store.state.config.customTheme.colors.bg : // v2 - this.$store.state.config.colors.bg // v1 + const color = this.$store.state.config.customTheme.colors + ? this.$store.state.config.customTheme.colors.bg // v2 + : this.$store.state.config.colors.bg // v1 if (color) { const rgb = (typeof color === 'string') ? hex2rgb(color) : color From b45fc6c6523b1332c6422a5dc6eff95c11a32690 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 27 Nov 2018 04:54:59 +0300 Subject: [PATCH 074/123] updated preview window --- .../style_switcher/style_switcher.scss | 124 ++++++++++++------ .../style_switcher/style_switcher.vue | 108 ++++++++------- src/components/timeline/timeline.vue | 2 +- src/i18n/en.json | 3 +- 4 files changed, 150 insertions(+), 87 deletions(-) diff --git a/src/components/style_switcher/style_switcher.scss b/src/components/style_switcher/style_switcher.scss index 2c33224b..baf2b73a 100644 --- a/src/components/style_switcher/style_switcher.scss +++ b/src/components/style_switcher/style_switcher.scss @@ -163,32 +163,95 @@ background-size: cover; background-position: 50% 50%; - .separator { - margin: 1em; - border-bottom: 1px solid; - border-color: $fallback--border; - border-color: var(--border, $fallback--border); - } + .dummy { + .post { + font-family: var(--postFont); + display: flex; - .panel-heading { - .badge, .alert, .btn, .faint { - margin-left: 1em; - } - .flex-spacer { - flex: 1; - } - } - .checkbox { - display: inline-flex; - align-items: baseline; - margin-right: 1em; - } + .content { + flex: 1; - .btn { - margin-left: 0; - padding: 0 1em; - min-width: 3em; - min-height: 30px; + h4 { + margin-bottom: .25em; + } + + .icons { + margin-top: .5em; + display: flex; + + i { + margin-right: 1em; + } + } + } + } + + .after-post { + margin-top: 1em; + display: flex; + align-items: center; + } + + .avatar, .avatar-alt{ + background: linear-gradient(135deg, #b8e1fc 0%,#a9d2f3 10%,#90bae4 25%,#90bcea 37%,#90bff0 50%,#6ba8e5 51%,#a2daf5 83%,#bdf3fd 100%); + color: black; + font-family: sans-serif; + text-align: center; + margin-right: 1em; + } + + .avatar-alt { + flex: 0 auto; + margin-left: 28px; + font-size: 12px; + width: 20px; + height: 20px; + line-height: 20px; + border-radius: $fallback--avatarAltRadius; + border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); + } + + .avatar { + flex: 0 auto; + width: 48px; + height: 48px; + font-size: 14px; + line-height: 48px; + } + + .actions { + display: flex; + align-items: baseline; + + .checkbox { + display: inline-flex; + align-items: baseline; + margin-right: 1em; + flex: 1; + } + } + + .separator { + margin: 1em; + border-bottom: 1px solid; + border-color: $fallback--border; + border-color: var(--border, $fallback--border); + } + + .panel-heading { + .badge, .alert, .btn, .faint { + margin-left: 1em; + } + .flex-spacer { + flex: 1; + } + } + .btn { + margin-left: 0; + padding: 0 1em; + min-width: 3em; + min-height: 30px; + } } } @@ -259,17 +322,4 @@ 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%); - color: black; - text-align: center; - height: 48px; - line-height: 48px; - width: 48px; - float: left; - margin-right: 1em; - } - } } diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 655e0589..fa173b98 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -60,66 +60,78 @@
- {{$t('settings.style.preview.header')}} - - 99 - - - {{$t('settings.style.preview.error')}} - - - +
+ {{$t('settings.style.preview.header')}} + + 99 + +
{{$t('settings.style.preview.header_faint')}} -
-
-
- ( ͡° ͜ʖ ͡°) -
-

Content

- -
- - - - {{$t('settings.style.preview.link')}} - - - - - - - - -
-
- - {{$t('settings.style.preview.error')}} - -
-
- - - - - +
+
+
+
+ ( ͡° ͜ʖ ͡°) +
+
+

+ Content +

+ + + {{$t('settings.style.preview.mono')}} + + + {{$t('settings.style.preview.link')}} + + + +
+ + + + +
+
+
+ +
+
+ :^) +
+ +
- - - {{$t('settings.style.preview.faint_link')}} - - + + {{$t('settings.style.preview.error')}} + + + +
+ + + + + +
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue index b69a09fd..bc7f74c2 100644 --- a/src/components/timeline/timeline.vue +++ b/src/components/timeline/timeline.vue @@ -10,7 +10,7 @@ -
+
{{$t('timeline.up_to_date')}}
diff --git a/src/i18n/en.json b/src/i18n/en.json index 74e7a556..8847b11e 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -268,7 +268,8 @@ "header": "Preview of header", "error": "Example error", "button": "Button", - "text": "A bunch of more content and {0}", + "text": "A bunch of more {0} and {1}", + "mono": "content", "input": "Just landed in L.A.", "faint_link": "helpful manual", "fine_print": "Read our {0} to learn nothing useful!", From 406df4399b630268c1028664f3b818571d6f8e4f Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 30 Nov 2018 16:39:07 +0300 Subject: [PATCH 075/123] avatars shadows, also allows drop-shadow use --- src/components/notification/notification.js | 3 +- src/components/notification/notification.vue | 2 +- .../notifications/notifications.scss | 6 ++++ src/components/status/status.js | 3 +- src/components/status/status.vue | 13 ++++++++- .../style_switcher/style_switcher.vue | 12 ++++++++ .../user_card_content/user_card_content.js | 3 +- .../user_card_content/user_card_content.vue | 7 ++++- src/i18n/en.json | 7 +++++ src/modules/interface.js | 6 ++++ src/services/style_setter/style_setter.js | 28 +++++++++++++++++-- 11 files changed, 82 insertions(+), 8 deletions(-) diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index c786f2cc..4dea63bb 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -6,7 +6,8 @@ import { highlightClass, highlightStyle } from '../../services/user_highlighter/ const Notification = { data () { return { - userExpanded: false + userExpanded: false, + betterShadow: this.$store.state.interface.browserSupport.cssFilter } }, props: [ diff --git a/src/components/notification/notification.vue b/src/components/notification/notification.vue index 72c1ca69..f98afbe0 100644 --- a/src/components/notification/notification.vue +++ b/src/components/notification/notification.vue @@ -2,7 +2,7 @@
- +
diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 87c89f6a..d17ae25d 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -49,11 +49,17 @@ .avatar-compact { width: 32px; height: 32px; + box-shadow: var(--avatarStatusShadow); border-radius: $fallback--avatarAltRadius; border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); overflow: hidden; line-height: 0; + &.better-shadow { + box-shadow: none; + filter: drop-shadow(var(--avatarStatusShadowFilter)) + } + &.animated::before { display: none; } diff --git a/src/components/status/status.js b/src/components/status/status.js index 10716583..725bc3f8 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -33,7 +33,8 @@ const Status = { showingTall: false, expandingSubject: typeof this.$store.state.config.collapseMessageWithSubject === 'undefined' ? !this.$store.state.instance.collapseMessageWithSubject - : !this.$store.state.config.collapseMessageWithSubject + : !this.$store.state.config.collapseMessageWithSubject, + betterShadow: this.$store.state.interface.browserSupport.cssFilter } }, computed: { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 4541c560..26be335c 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -21,7 +21,7 @@
@@ -464,8 +464,14 @@ .status .avatar-compact { width: 32px; height: 32px; + box-shadow: var(--avatarStatusShadow); border-radius: $fallback--avatarAltRadius; border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); + + &.better-shadow { + box-shadow: none; + filter: drop-shadow(var(--avatarStatusShadowFilter)) + } } .avatar { @@ -477,6 +483,11 @@ overflow: hidden; position: relative; + &.better-shadow { + box-shadow: none; + filter: drop-shadow(var(--avatarStatusShadowFilter)) + } + img { width: 100%; height: 100%; diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index fa173b98..66fe0f6b 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -278,6 +278,18 @@
+
+ + filter: drop-shadow() + + + drop-shadow + spread-radius + inset + +

{{$t('settings.style.shadows.filter_hint.inset_ignored')}}

+

{{$t('settings.style.shadows.filter_hint.spread_zero')}}

+
diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js index 254d1666..97cd4983 100644 --- a/src/components/user_card_content/user_card_content.js +++ b/src/components/user_card_content/user_card_content.js @@ -7,7 +7,8 @@ export default { return { hideUserStatsLocal: typeof this.$store.state.config.hideUserStats === 'undefined' ? this.$store.state.instance.hideUserStats - : this.$store.state.config.hideUserStats + : this.$store.state.config.hideUserStats, + betterShadow: this.$store.state.interface.browserSupport.cssFilter } }, computed: { diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue index 5529948e..cca418ff 100644 --- a/src/components/user_card_content/user_card_content.vue +++ b/src/components/user_card_content/user_card_content.vue @@ -10,7 +10,7 @@
- +
@@ -159,6 +159,11 @@ box-shadow: var(--avatarShadow); object-fit: cover; + &.better-shadow { + box-shadow: none; + filter: drop-shadow(var(--avatarStatusShadowFilter)) + } + &.animated::before { display: none; } diff --git a/src/i18n/en.json b/src/i18n/en.json index 8847b11e..7f5a2a4f 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -236,6 +236,13 @@ "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.", + "filter_hint": { + "always_drop_shadow": "Warning, this shadow always uses {0} when browser supports it.", + "text": "Please note that {0} does not support {1} parameter and {2} keyword.", + "spread_zero": "Shadows with spread > 0 will appear as if it was set to zero", + "inset_ignored": "Inset shadows using will be ignored", + "inset_substituted": "Inset shadows will be substituted with {1} equivalent" + }, "components": { "panel": "Panel", "panelHeader": "Panel header", diff --git a/src/modules/interface.js b/src/modules/interface.js index 07489685..132fb08d 100644 --- a/src/modules/interface.js +++ b/src/modules/interface.js @@ -4,6 +4,12 @@ const defaultState = { settings: { currentSaveStateNotice: null, noticeClearTimeout: null + }, + browserSupport: { + cssFilter: window.CSS && window.CSS.supports && ( + window.CSS.supports('filter', 'drop-shadow(0 0)') || + window.CSS.supports('-webkit-filter', 'drop-shadow(0 0)') + ) } } diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 7c375206..cff81c40 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -110,6 +110,24 @@ const getCssShadow = (input) => { ]).join(' ')).join(', ') } +const getCssShadowFilter = (input) => { + if (input.length === 0) { + return 'none' + } + + return input + // drop-shadow doesn't support inset or spread + .filter((shad) => console.log(shad) || !shad.inset && Number(shad.spread) === 0) + .map((shad) => [ + shad.x, + shad.y, + // drop-shadow's blur is twice as strong compared to box-shadow + shad.blur / 2 + ].map(_ => _ + 'px').concat([ + getCssColor(shad.color, shad.alpha) + ]).join(' ')).join(', ') +} + const getCssColor = (input, a) => { let rgb = {} if (typeof input === 'object') { @@ -384,7 +402,12 @@ const generateShadows = (input) => { return { rules: { - shadows: Object.entries(shadows).map(([k, v]) => `--${k}Shadow: ${getCssShadow(v)}`).join(';') + shadows: Object + .entries(shadows) + // TODO for v2.1: if shadow doesn't have non-inset shadows with spread > 0 - optionally + // convert all non-inset shadows into filter: drop-shadow() to boost performance + .map(([k, v]) => `--${k}Shadow: ${getCssShadow(v)}; --${k}ShadowFilter: ${getCssShadowFilter(v)}`) + .join(';') }, theme: { shadows @@ -467,5 +490,6 @@ export { generateFonts, generatePreset, composePreset, - getCssShadow + getCssShadow, + getCssShadowFilter } From 77ac42d9190934c8e4f1fa7dfef087c58ccd3990 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sat, 1 Dec 2018 14:47:42 +0300 Subject: [PATCH 076/123] fix retweeter avatar not getting proper shadow --- src/components/status/status.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 26be335c..6597d56b 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -9,7 +9,7 @@