From f78a5158e160fce03b333ad0aea6b2e136d42f67 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 2 Oct 2018 21:43:58 +0300 Subject: something works without exploding and i'm tired already --- src/components/style_switcher/style_switcher.js | 143 +++++++++++++------ src/components/style_switcher/style_switcher.vue | 174 ++++++++++------------- 2 files changed, 180 insertions(+), 137 deletions(-) (limited to 'src/components/style_switcher') 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) + + 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 = rgbstr2hex(colors.cRed) - this.blueColorLocal = rgbstr2hex(colors.cBlue) - this.greenColorLocal = rgbstr2hex(colors.cGreen) - this.orangeColorLocal = rgbstr2hex(colors.cOrange) + 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; } -- cgit v1.2.3-70-g09d2 From fb29e7c73da9520d2d08bae0757bb4ff7803ca11 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 3 Oct 2018 21:21:48 +0300 Subject: more workings and even less explosions. --- src/components/style_switcher/style_switcher.js | 110 +++++++++++++---------- src/components/style_switcher/style_switcher.vue | 60 +++++++++---- src/i18n/en.json | 1 + src/services/color_convert/color_convert.js | 7 +- src/services/style_setter/style_setter.js | 18 ++-- 5 files changed, 122 insertions(+), 74 deletions(-) (limited to 'src/components/style_switcher') 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) } }) } -- cgit v1.2.3-70-g09d2 From 0a4b07652aa24ea5fcda8f62838ea37f8e8168ef Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 4 Oct 2018 18:16:14 +0300 Subject: trying to fix transition --- src/components/style_switcher/style_switcher.js | 67 +++++++++++++++++++----- src/components/style_switcher/style_switcher.vue | 18 +++---- src/services/style_setter/style_setter.js | 44 ++++++++++++---- 3 files changed, 98 insertions(+), 31 deletions(-) (limited to 'src/components/style_switcher') 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 + + 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 // background - colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb // hilighted bg + 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 } -- cgit v1.2.3-70-g09d2 From 5441766c3cba46682227202e91e08c4fbb3e3ac3 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 4 Oct 2018 18:27:27 +0300 Subject: fix --- src/components/style_switcher/style_switcher.js | 21 ++----------------- src/services/style_setter/style_setter.js | 28 +++++-------------------- 2 files changed, 7 insertions(+), 42 deletions(-) (limited to 'src/components/style_switcher') 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) -- cgit v1.2.3-70-g09d2 From 96804d42f0f6aa6af85295933af6fd267b19e473 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 7 Oct 2018 19:59:22 +0300 Subject: 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 ++++++++++++++++ src/components/notifications/notifications.scss | 7 +- src/components/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 +- src/components/style_switcher/style_switcher.js | 107 ++++++++++++++++----- src/components/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, 343 insertions(+), 117 deletions(-) create mode 100644 src/components/color_input/color_input.vue create mode 100644 src/components/opacity_input/opacity_input.vue (limited to 'src/components/style_switcher') 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, + link: this.linkColorLocal, + + fg: this.fgColorLocal, + fgText: this.fgTextColorLocal, + fgLink: this.fgLinkColorLocal, + panel: this.panelColorLocal, + panelText: this.panelTextColorLocal, + panelFaint: this.panelFaintColorLocal, + + input: this.inputColorLocal, + inputText: this.inputTextColorLocal, + topBar: this.topBarColorLocal, + topBarText: this.topBarTextColorLocal, + topBarLink: this.topBarLinkColorLocal, + btn: this.btnColorLocal, - link: this.linkColorLocal, - cRed: this.redColorLocal, - cBlue: this.blueColorLocal, - cGreen: this.greenColorLocal, - cOrange: this.orangeColorLocal + 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 === 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 + } + } + console.log('BENIS') + console.log(version) + // Stuff that differs between V1 and V2 if (version === 1) { - this.clearV1() + console.log(colors) + this.fgColorLocal = rgb2hex(colors.btn) + this.textColorLocal = rgb2hex(colors.fg) } - this.panelColorLocal = rgb2hex(colors.panel) - this.topBarColorLocal = rgb2hex(colors.topBar) - - 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, -- cgit v1.2.3-70-g09d2 From 4d77b0c86bbd711e76e8ed23b6b227332bbea3cf Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 7 Oct 2018 22:03:34 +0300 Subject: Transparency works without exploding now. All nice. --- src/components/opacity_input/opacity_input.vue | 19 ++++++++- src/components/style_switcher/style_switcher.js | 28 +++++++----- src/components/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(-) (limited to 'src/components/style_switcher') 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 } } -- cgit v1.2.3-70-g09d2 From 87e98772b09b9b317dee020d22115517635a29c8 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 10 Oct 2018 00:07:28 +0300 Subject: initial contrast display support --- src/components/contrast_ratio/contrast_ratio.vue | 64 ++++++++++++++++++++++++ src/components/style_switcher/style_switcher.js | 37 ++++++++++++-- src/components/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 (limited to 'src/components/style_switcher') 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 } -- cgit v1.2.3-70-g09d2 From 4b7b7d9905b965c225fd42fb68682b9602254c82 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Wed, 10 Oct 2018 05:39:02 +0300 Subject: cleanup, documentation, contrast taking alpha into account. --- src/components/style_switcher/style_switcher.js | 38 +++++++++++--- src/services/color_convert/color_convert.js | 70 +++++++++++++++++++++---- 2 files changed, 91 insertions(+), 17 deletions(-) (limited to 'src/components/style_switcher') 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), + + // User Profile + tintText: getContrastRatio(worstCase(bgs.bg, 0.5, fgs.panelText), fgs.text), - panelText: getContrastRatio(hex2rgb(colors.panel), hex2rgb(colors.panelText)), + panelText: getContrastRatio(worstCase(bgs.panel, opacity.panel, fgs.panelText), fgs.panelText), - btnText: getContrastRatio(hex2rgb(colors.btn), hex2rgb(colors.btnText)), + btnText: getContrastRatio(worstCase(bgs.btn, opacity.btn, fgs.btnText), fgs.btnText), - topBarText: getContrastRatio(hex2rgb(colors.topBar), hex2rgb(colors.topBarText)), - topBarLink: getContrastRatio(hex2rgb(colors.topBar), hex2rgb(colors.topBarLink)), + 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 } -- cgit v1.2.3-70-g09d2 From 7b657fcccd3524aba552cab4ee1005057fd83d41 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 21 Oct 2018 15:25:21 +0300 Subject: added contrasts for rgbo --- src/components/style_switcher/style_switcher.js | 20 ++++++++++++++------ src/components/style_switcher/style_switcher.vue | 4 ++++ 2 files changed, 18 insertions(+), 6 deletions(-) (limited to 'src/components/style_switcher') 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

-- cgit v1.2.3-70-g09d2 From 1723f427f59bb6bf62bb35de93c7226aef2e8727 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 13 Nov 2018 16:30:01 +0300 Subject: updates --- src/App.scss | 4 +- src/_variables.scss | 2 +- src/components/contrast_ratio/contrast_ratio.vue | 50 ++++++++--------------- src/components/notifications/notifications.scss | 8 ++-- src/components/opacity_input/opacity_input.vue | 10 ----- src/components/style_switcher/style_switcher.js | 24 ++++++++++- src/components/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(-) (limited to 'src/components/style_switcher') 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,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') 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 a7b690a7..7dfef262 100644 Binary files a/static/font/font/fontello.eot and b/static/font/font/fontello.eot differ 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 5fb1466a..1fe7c631 100644 Binary files a/static/font/font/fontello.ttf and b/static/font/font/fontello.ttf differ diff --git a/static/font/font/fontello.woff b/static/font/font/fontello.woff index ca463697..fc65e325 100644 Binary files a/static/font/font/fontello.woff and b/static/font/font/fontello.woff differ diff --git a/static/font/font/fontello.woff2 b/static/font/font/fontello.woff2 index 09fafb31..8513d894 100644 Binary files a/static/font/font/fontello.woff2 and b/static/font/font/fontello.woff2 differ -- cgit v1.2.3-70-g09d2 From a8180d03be3488aeb7cfc811a1b49f6519836ab5 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 19 Nov 2018 18:15:27 +0300 Subject: it works, now to clean it up --- src/App.scss | 1 + src/components/shadow_control/shadow_control.js | 6 +- src/components/shadow_control/shadow_control.vue | 11 +-- src/components/style_switcher/style_switcher.js | 38 ++++++-- src/components/style_switcher/style_switcher.vue | 110 +++++++++++++---------- src/services/style_setter/style_setter.js | 3 +- 6 files changed, 105 insertions(+), 64 deletions(-) (limited to 'src/components/style_switcher') 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) -- cgit v1.2.3-70-g09d2 From d64f4ab363b8fd8b6fe4542abe5f991178f4d3d4 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 26 Nov 2018 20:14:53 +0300 Subject: fix preview input text using wrong string --- src/components/style_switcher/style_switcher.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src/components/style_switcher') 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')}} -- cgit v1.2.3-70-g09d2 From 2ebc06e30f009204eb289057730f9fa4a148d499 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Mon, 26 Nov 2018 21:07:22 +0300 Subject: fixed keep checkboxes working when exporting --- src/components/style_switcher/style_switcher.js | 51 +++++++++++++++++++------ src/i18n/en.json | 2 +- 2 files changed, 40 insertions(+), 13 deletions(-) (limited to 'src/components/style_switcher') 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" -- cgit v1.2.3-70-g09d2 From b45fc6c6523b1332c6422a5dc6eff95c11a32690 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 27 Nov 2018 04:54:59 +0300 Subject: updated preview window --- src/components/style_switcher/style_switcher.scss | 120 +++++++++++++++------- src/components/style_switcher/style_switcher.vue | 98 ++++++++++-------- src/components/timeline/timeline.vue | 2 +- src/i18n/en.json | 3 +- 4 files changed, 143 insertions(+), 80 deletions(-) (limited to 'src/components/style_switcher') 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; + + .content { + flex: 1; + + h4 { + margin-bottom: .25em; + } + + .icons { + margin-top: .5em; + display: flex; + + i { + margin-right: 1em; + } + } + } + } - .panel-heading { - .badge, .alert, .btn, .faint { - margin-left: 1em; + .after-post { + margin-top: 1em; + display: flex; + align-items: center; } - .flex-spacer { - flex: 1; + + .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; } - } - .checkbox { - display: inline-flex; - align-items: baseline; - margin-right: 1em; - } - .btn { - margin-left: 0; - padding: 0 1em; - min-width: 3em; - min-height: 30px; + .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,9 +60,14 @@
- {{$t('settings.style.preview.header')}} - - 99 +
+ {{$t('settings.style.preview.header')}} + + 99 + +
+ + {{$t('settings.style.preview.header_faint')}} {{$t('settings.style.preview.error')}} @@ -70,56 +75,63 @@ - - - {{$t('settings.style.preview.header_faint')}} -
-
- ( ͡° ͜ʖ ͡°) -
-

Content

- -
+
+
+ ( ͡° ͜ʖ ͡°) +
+
+

+ Content +

- - - {{$t('settings.style.preview.link')}} - - + + + {{$t('settings.style.preview.mono')}} + + + {{$t('settings.style.preview.link')}} + + - - - - +
+ + + + +
+
+
-
-
+
+
+ :^) +
+ +
+
- {{$t('settings.style.preview.error')}} + -
-
- - - - - - - -
- - - - {{$t('settings.style.preview.faint_link')}} - - +
+ + + + + +
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!", -- cgit v1.2.3-70-g09d2 From 406df4399b630268c1028664f3b818571d6f8e4f Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Fri, 30 Nov 2018 16:39:07 +0300 Subject: avatars shadows, also allows drop-shadow use --- src/components/notification/notification.js | 3 ++- src/components/notification/notification.vue | 2 +- src/components/notifications/notifications.scss | 6 +++++ src/components/status/status.js | 3 ++- src/components/status/status.vue | 13 +++++++++- src/components/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(-) (limited to 'src/components/style_switcher') 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 } -- cgit v1.2.3-70-g09d2 From bee738c815f287c4605eafd52c5565cdb07d5721 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 2 Dec 2018 08:47:55 +0300 Subject: making inset shadows work on avatars again --- src/components/notifications/notifications.scss | 4 +-- src/components/status/status.vue | 8 +++--- src/components/style_switcher/style_switcher.vue | 7 +++-- .../user_card_content/user_card_content.vue | 4 +-- src/i18n/en.json | 6 ++-- src/services/style_setter/style_setter.js | 32 ++++++++++++++-------- 6 files changed, 36 insertions(+), 25 deletions(-) (limited to 'src/components/style_switcher') diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index d17ae25d..a6468e01 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -56,8 +56,8 @@ line-height: 0; &.better-shadow { - box-shadow: none; - filter: drop-shadow(var(--avatarStatusShadowFilter)) + box-shadow: var(--avatarStatusShadowInset); + filter: var(--avatarStatusShadowFilter) } &.animated::before { diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 6597d56b..428383e3 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -469,8 +469,8 @@ border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); &.better-shadow { - box-shadow: none; - filter: drop-shadow(var(--avatarStatusShadowFilter)) + box-shadow: var(--avatarStatusShadowInset); + filter: var(--avatarStatusShadowFilter) } } @@ -484,8 +484,8 @@ position: relative; &.better-shadow { - box-shadow: none; - filter: drop-shadow(var(--avatarStatusShadowFilter)) + box-shadow: var(--avatarStatusShadowInset); + filter: var(--avatarStatusShadowFilter) } img { diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 66fe0f6b..c0a7da69 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -282,12 +282,15 @@ filter: drop-shadow() - +

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

+ drop-shadow spread-radius inset -

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

+ + box-shadow +

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

diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue index cca418ff..e8b0ebf9 100644 --- a/src/components/user_card_content/user_card_content.vue +++ b/src/components/user_card_content/user_card_content.vue @@ -160,8 +160,8 @@ object-fit: cover; &.better-shadow { - box-shadow: none; - filter: drop-shadow(var(--avatarStatusShadowFilter)) + box-shadow: var(--avatarShadowInset); + filter: var(--avatarShadowFilter) } &.animated::before { diff --git a/src/i18n/en.json b/src/i18n/en.json index 7f5a2a4f..39da04d8 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -238,10 +238,10 @@ "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.", + "drop_shadow_syntax": "{0} does not support {1} parameter and {2} keyword.", + "avatar_inset": "Please note that combining both inset and non-inset shadows on avatars might give unexpected results with transparent avatars.", "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" + "inset_classic": "Inset shadows will be using {0}" }, "components": { "panel": "Panel", diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index cff81c40..44a36c88 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -94,20 +94,22 @@ const setColors = (input, commit) => { commit('setOption', { name: 'colors', value: theme.colors }) } -const getCssShadow = (input) => { +const getCssShadow = (input, usesDropShadow) => { if (input.length === 0) { return 'none' } - return input.map((shad) => [ - shad.x, - shad.y, - shad.blur, - shad.spread - ].map(_ => _ + 'px').concat([ - getCssColor(shad.color, shad.alpha), - shad.inset ? 'inset' : '' - ]).join(' ')).join(', ') + return input + .filter(_ => usesDropShadow ? _.inset : _) + .map((shad) => [ + shad.x, + shad.y, + shad.blur, + shad.spread + ].map(_ => _ + 'px').concat([ + getCssColor(shad.color, shad.alpha), + shad.inset ? 'inset' : '' + ]).join(' ')).join(', ') } const getCssShadowFilter = (input) => { @@ -125,7 +127,9 @@ const getCssShadowFilter = (input) => { shad.blur / 2 ].map(_ => _ + 'px').concat([ getCssColor(shad.color, shad.alpha) - ]).join(' ')).join(', ') + ]).join(' ')) + .map(_ => `drop-shadow(${_})`) + .join(' ') } const getCssColor = (input, a) => { @@ -406,7 +410,11 @@ const generateShadows = (input) => { .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)}`) + .map(([k, v]) => [ + `--${k}Shadow: ${getCssShadow(v)}`, + `--${k}ShadowFilter: ${getCssShadowFilter(v)}`, + `--${k}ShadowInset: ${getCssShadow(v, true)}` + ].join(';')) .join(';') }, theme: { -- cgit v1.2.3-70-g09d2 From 67ca21b2e6c5f76d1db3e7cfdd1c0ef019156172 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 2 Dec 2018 09:38:40 +0300 Subject: localization strings, fixes --- src/components/style_switcher/style_switcher.scss | 9 +- src/components/style_switcher/style_switcher.vue | 4 +- src/i18n/en.json | 2 +- src/i18n/ru.json | 112 +++++++++++++++++++++- 4 files changed, 119 insertions(+), 8 deletions(-) (limited to 'src/components/style_switcher') diff --git a/src/components/style_switcher/style_switcher.scss b/src/components/style_switcher/style_switcher.scss index baf2b73a..4db1a295 100644 --- a/src/components/style_switcher/style_switcher.scss +++ b/src/components/style_switcher/style_switcher.scss @@ -49,7 +49,7 @@ } &:not([type=number]):not([type=text]) { - align-self: center; + align-self: flex-start; } } } @@ -113,6 +113,7 @@ p { flex: 1; margin: 0; + margin-right: .5em; } margin-bottom: 1em; @@ -148,7 +149,7 @@ flex-wrap: wrap; margin-top: .5em; span { - margin: 0 .5em; + margin: 0 .5em .5em; } } @@ -204,8 +205,8 @@ flex: 0 auto; margin-left: 28px; font-size: 12px; - width: 20px; - height: 20px; + min-width: 20px; + min-height: 20px; line-height: 20px; border-radius: $fallback--avatarAltRadius; border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius); diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index c0a7da69..814a6f17 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -83,7 +83,7 @@

- Content + {{$t('settings.style.preview.content')}}

@@ -224,7 +224,7 @@

{{ $t('settings.style.advanced_colors.borders') }}

- +
diff --git a/src/i18n/en.json b/src/i18n/en.json index 39da04d8..56179868 100644 --- a/src/i18n/en.json +++ b/src/i18n/en.json @@ -207,7 +207,6 @@ "common_colors": { "_tab_label": "Common", "main": "Common colors", - "foreground": "Panel header, top bar, buttons, text fields", "foreground_hint": "See \"Advanced\" tab for more detailed control", "rgbo": "Icons, accents, badges" }, @@ -273,6 +272,7 @@ }, "preview": { "header": "Preview of header", + "content": "Content", "error": "Example error", "button": "Button", "text": "A bunch of more {0} and {1}", diff --git a/src/i18n/ru.json b/src/i18n/ru.json index 921bf67e..63c0bd2a 100644 --- a/src/i18n/ru.json +++ b/src/i18n/ru.json @@ -138,8 +138,118 @@ "text": "Текст", "theme": "Тема", "theme_help": "Используйте шестнадцатеричные коды цветов (#rrggbb) для настройки темы.", + "theme_help_v2_1": "Вы так же можете перепоределить цвета определенных компонентов нажав соотв. галочку. Используйте кнопку \"Очистить всё\" чтобы снять все переопределения", + "theme_help_v2_2": "Под некоторыми полями ввода это идикаторы контрастности, наведите на них мышью чтобы узнать больше. Приспользовании прозрачности контраст расчитывается для наихудшего варианта.", "tooltipRadius": "Всплывающие подсказки/уведомления", - "user_settings": "Настройки пользователя" + "user_settings": "Настройки пользователя", + "style": { + "switcher": { + "keep_shadows": "Оставить тени", + "keep_opacity": "Оставить прозрачность", + "keep_roundness": "Оставить скругление", + "keep_fonts": "Оставить шрифты", + "save_load_hint": "Опции \"оставить...\" позволяют сохранить текущие настройки при выборе другой темы или импорта её из файла. Так же они влияют на то какие компоненты будут сохранены при экспорте темы. Когда все галочки сняты все компоненты будут экспортированы.", + "reset": "Сбросить", + "clear_all": "Очистить всё", + "clear_opacity": "Очистить прозрачность" + }, + "common": { + "color": "Цвет", + "opacity": "Прозрачность", + "contrast": { + "hint": "Уровень контраста: {ratio}, что {level} {context}", + "level": { + "aa": "соответствует гайдлайну Level AA (минимальный)", + "aaa": "соответствует гайдлайну Level AAA (рекомендуемый)", + "bad": "не соответствует каким либо гайдлайнам" + }, + "context": { + "18pt": "для крупного (18pt+) текста", + "text": "для текста" + } + } + }, + "common_colors": { + "_tab_label": "Общие", + "main": "Общие цвета", + "foreground_hint": "См. вкладку \"Дополнительно\" для более детального контроля", + "rgbo": "Иконки, акценты, ярылки" + }, + "advanced_colors": { + "_tab_label": "Дополнительно", + "alert": "Фон уведомлений", + "alert_error": "Ошибки", + "badge": "Фон значков", + "badge_notification": "Уведомления", + "panel_header": "Заголовок панели", + "top_bar": "Верняя полоска", + "borders": "Границы", + "buttons": "Кнопки", + "inputs": "Поля ввода", + "faint_text": "Маловажный текст" + }, + "radii": { + "_tab_label": "Скругление" + }, + "shadows": { + "_tab_label": "Светотень", + "component": "Компонент", + "override": "Переопределить", + "shadow_id": "Тень №{value}", + "blur": "Размытие", + "spread": "Разброс", + "inset": "Внутренняя", + "hint": "Для теней вы так же можете использовать --variable в качестве цвета чтобы использовать CSS3-переменные. В таком случае прозрачность работать не будет.", + "filter_hint": { + "always_drop_shadow": "Внимание, эта тень всегда использует {0} когда браузер поддерживает это", + "drop_shadow_syntax": "{0} не поддерживает параметр {1} и ключевое слово {2}", + "avatar_inset": "Одновременное использование внутренних и внешних теней на (прозрачных) аватарках может дать не те результаты что вы ожидаете", + "spread_zero": "Тени с разбросом > 0 будут выглядеть как если бы разброс установлен в 0", + "inset_classic": "Внутренние тени будут использовать {0}" + }, + "components": { + "panel": "Панель", + "panelHeader": "Заголовок панели", + "topBar": "Верхняя полоска", + "avatar": "Аватарка (профиль)", + "avatarStatus": "Аватарка (в ленте)", + "popup": "Всплывающие подсказки", + "button": "Кнопки", + "buttonHover": "Кнопки (наведен курсор)", + "buttonPressed": "Кнопки (нажата)", + "buttonPressedHover": "Кнопки (нажата+наведен курсор)", + "input": "Поля ввода" + } + }, + "fonts": { + "_tab_label": "Шрифты", + "help": "Выберите тип шрифта для использования в интерфейсе. При выборе варианта \"другой\" надо ввести название шрифта в точности как он называется в системе.", + "components": { + "interface": "Интерфейс", + "input": "Поля ввода", + "post": "Текст постов", + "postCode": "Моноширинный текст в посте (форматирование)" + }, + "family": "Шрифт", + "size": "Размер (в пикселях)", + "weight": "Ширина", + "custom": "Другой" + }, + "preview": { + "header": "Пример", + "content": "Контент", + "error": "Ошибка стоп 000", + "button": "Кнопка", + "text": "Еще немного {0} и масенькая {1}", + "mono": "контента", + "input": "Что нового?", + "faint_link": "Его придется убрать", + "fine_print": "Если проблемы остались — ваш гуртовщик мыши плохо стоит. {0}.", + "header_faint": "Все идет по плану", + "checkbox": "Я подтверждаю что не было ни единого разрыва", + "link": "ссылка" + } + } }, "timeline": { "collapse": "Свернуть", -- cgit v1.2.3-70-g09d2 From 80c0745558cd5dc69364bc19ee5dc1b8b3ddc3e2 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sun, 2 Dec 2018 10:22:25 +0300 Subject: some more themes, fixes --- src/components/style_switcher/style_switcher.js | 3 +- src/components/style_switcher/style_switcher.scss | 6 + src/components/style_switcher/style_switcher.vue | 2 +- static/styles.json | 4 +- static/themes/breezy-dark.json | 139 ++++++++++++++++++++++ static/themes/breezy-light.json | 139 ++++++++++++++++++++++ 6 files changed, 289 insertions(+), 4 deletions(-) create mode 100644 static/themes/breezy-dark.json create mode 100644 static/themes/breezy-light.json (limited to 'src/components/style_switcher') diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index ccdb4c4f..d09185fa 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -497,10 +497,9 @@ export default { this.textColorLocal = rgb2hex(colors.fg) } + this.clearV1() const keys = new Set(version !== 1 ? Object.keys(colors) : []) if (version === 1 || version === 'l1') { - // V1 ignores the rest - this.clearV1() keys .add('bg') .add('link') diff --git a/src/components/style_switcher/style_switcher.scss b/src/components/style_switcher/style_switcher.scss index 4db1a295..c8c5d9dd 100644 --- a/src/components/style_switcher/style_switcher.scss +++ b/src/components/style_switcher/style_switcher.scss @@ -135,6 +135,12 @@ display: flex; justify-content: center; align-items: baseline; + flex-wrap: wrap; + + .presets, + .import-export { + margin-bottom: .5em; + } .import-export { display: flex; diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 814a6f17..9de60f7b 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -2,7 +2,7 @@
-
+
{{$t('settings.presets')}}
-
+
@@ -235,6 +163,7 @@
+

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

@@ -249,6 +178,7 @@
+
@@ -294,6 +224,7 @@

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

+

{{$t('settings.style.fonts.help')}}

diff --git a/src/modules/config.js b/src/modules/config.js index fb9b3ca6..45ac8f65 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -1,5 +1,5 @@ import { set, delete as del } from 'vue' -import { setPreset, setColors } from '../services/style_setter/style_setter.js' +import { setPreset, applyTheme } from '../services/style_setter/style_setter.js' const browserLocale = (window.navigator.language || 'en').split('-')[0] @@ -57,7 +57,7 @@ const config = { setPreset(value, commit) break case 'customTheme': - setColors(value, commit) + applyTheme(value, commit) } } } -- cgit v1.2.3-70-g09d2 From c189a08dffd2373172d9fd34af5954af146c2f36 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Tue, 11 Dec 2018 16:36:06 +0300 Subject: added keep-colors option --- src/components/style_switcher/style_switcher.js | 94 ++++++++++++----------- src/components/style_switcher/style_switcher.scss | 9 +-- src/components/style_switcher/style_switcher.vue | 15 +++- src/i18n/en.json | 1 + src/i18n/ru.json | 1 + 5 files changed, 65 insertions(+), 55 deletions(-) (limited to 'src/components/style_switcher') diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index 50cd1e6f..6a4e1cba 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -38,6 +38,7 @@ export default { colorsInvalid: true, radiiInvalid: true, + keepColor: false, keepShadows: false, keepOpacity: false, keepRoundness: false, @@ -296,31 +297,30 @@ export default { return !this.shadowsInvalid && !this.colorsInvalid && !this.radiiInvalid }, exportedTheme () { - const saveEverything = !this.keepFonts && !this.keepShadows && !this.keepColors && !this.keepOpacity && !this.keepRoundness - - // TODO change into delete-less version. - const theme = { - shadows: this.shadowsLocal, - fonts: this.fontsLocal, - opacity: this.currentOpacity, - colors: this.currentColors, - radii: this.currentRadii + const saveEverything = ( + !this.keepFonts && + !this.keepShadows && + !this.keepOpacity && + !this.keepRoundness && + !this.keepColor + ) + + const theme = {} + + if (this.keepFonts || saveEverything) { + theme.fonts = this.fontsLocal } - - if (!this.keepFonts && !saveEverything) { - delete theme.fonts - } - if (!this.keepShadows && !saveEverything) { - delete theme.shadows + if (this.keepShadows || saveEverything) { + theme.shadows = this.shadowsLocal } - if (!this.keepOpacity && !saveEverything) { - delete theme.opacity + if (this.keepOpacity || saveEverything) { + theme.opacity = this.currentOpacity } - if (!this.keepColors && !saveEverything) { - delete theme.colors + if (this.keepColor || saveEverything) { + theme.colors = this.currentColors } - if (!this.keepRoundness && !saveEverything) { - delete theme.radii + if (this.keepRoundness || saveEverything) { + theme.radii = this.currentRadii } return { @@ -438,21 +438,23 @@ export default { this.textColorLocal = rgb2hex(colors.fg) } - this.clearV1() - const keys = new Set(version !== 1 ? Object.keys(colors) : []) - if (version === 1 || version === 'l1') { - keys - .add('bg') - .add('link') - .add('cRed') - .add('cBlue') - .add('cGreen') - .add('cOrange') - } + if (!this.keepColor) { + this.clearV1() + const keys = new Set(version !== 1 ? Object.keys(colors) : []) + if (version === 1 || version === 'l1') { + keys + .add('bg') + .add('link') + .add('cRed') + .add('cBlue') + .add('cGreen') + .add('cOrange') + } - keys.forEach(key => { - this[key + 'ColorLocal'] = rgb2hex(colors[key]) - }) + keys.forEach(key => { + this[key + 'ColorLocal'] = rgb2hex(colors[key]) + }) + } if (!this.keepRoundness) { this.clearRoundness() @@ -553,16 +555,18 @@ export default { this.clearOpacity() } - this.clearV1() - - this.bgColorLocal = this.selected[1] - this.fgColorLocal = this.selected[2] - this.textColorLocal = this.selected[3] - this.linkColorLocal = this.selected[4] - this.cRedColorLocal = this.selected[5] - this.cGreenColorLocal = this.selected[6] - this.cBlueColorLocal = this.selected[7] - this.cOrangeColorLocal = this.selected[8] + if (!this.keepColor) { + this.clearV1() + + this.bgColorLocal = this.selected[1] + this.fgColorLocal = this.selected[2] + this.textColorLocal = this.selected[3] + this.linkColorLocal = this.selected[4] + this.cRedColorLocal = this.selected[5] + this.cGreenColorLocal = this.selected[6] + this.cBlueColorLocal = this.selected[7] + this.cOrangeColorLocal = this.selected[8] + } } else if (this.selectedVersion >= 2) { this.normalizeLocalState(this.selected.theme, 2) } diff --git a/src/components/style_switcher/style_switcher.scss b/src/components/style_switcher/style_switcher.scss index f53f00a0..135c113a 100644 --- a/src/components/style_switcher/style_switcher.scss +++ b/src/components/style_switcher/style_switcher.scss @@ -54,11 +54,6 @@ } } - .import-warning { - color: $fallback--cRed; - color: var(--cRed, $fallback--cRed); - } - .tab-switcher { margin: 0 -1em; } @@ -154,8 +149,10 @@ .save-load-options { flex-wrap: wrap; margin-top: .5em; - span { + justify-content: center; + .keep-option { margin: 0 .5em .5em; + min-width: 25%; } } diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 730bfef0..6acb7755 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -28,28 +28,35 @@ />
- + + + + + - + - + - + Date: Tue, 11 Dec 2018 16:36:27 +0300 Subject: better layouting for import-export, error display fixes --- src/components/export_import/export_import.vue | 16 ++++++++-- src/components/style_switcher/style_switcher.vue | 38 +++++++++++++----------- 2 files changed, 34 insertions(+), 20 deletions(-) (limited to 'src/components/style_switcher') diff --git a/src/components/export_import/export_import.vue b/src/components/export_import/export_import.vue index 9914d54a..451a2668 100644 --- a/src/components/export_import/export_import.vue +++ b/src/components/export_import/export_import.vue @@ -1,8 +1,11 @@ @@ -73,3 +76,12 @@ export default { } } + + diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 6acb7755..84963c81 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -2,30 +2,32 @@
-
- {{$t('settings.presets')}} - -
+ :validator='importValidator'> + +
-- cgit v1.2.3-70-g09d2