From e5a34870f0f7154712783fb6d9c20edf4c06ad35 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sat, 28 Dec 2019 15:55:42 +0200 Subject: Accent works --- src/components/style_switcher/style_switcher.vue | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) (limited to 'src/components/style_switcher/style_switcher.vue') diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index ad032041..8bbdc7b7 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -114,9 +114,18 @@ :label="$t('settings.text')" /> + @@ -336,7 +345,7 @@ Date: Sat, 28 Dec 2019 17:02:34 +0200 Subject: fixed import-export --- src/components/export_import/export_import.vue | 2 +- src/components/style_switcher/style_switcher.js | 34 +++++++++++++++++++----- src/components/style_switcher/style_switcher.vue | 4 +-- src/services/style_setter/style_setter.js | 27 +++++++++++++++++-- 4 files changed, 56 insertions(+), 11 deletions(-) (limited to 'src/components/style_switcher/style_switcher.vue') diff --git a/src/components/export_import/export_import.vue b/src/components/export_import/export_import.vue index 20c6f569..ae00487f 100644 --- a/src/components/export_import/export_import.vue +++ b/src/components/export_import/export_import.vue @@ -42,7 +42,7 @@ export default { }, methods: { exportData () { - const stringified = JSON.stringify(this.exportObject) // Pretty-print and indent with 2 spaces + const stringified = JSON.stringify(this.exportObject, null, 2) // Pretty-print and indent with 2 spaces // Create an invisible link with a data url and simulate a click const e = document.createElement('a') diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index 1e512407..b450dc8e 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -1,6 +1,7 @@ import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js' import { set, delete as del } from 'vue' -import { generateColors, generateShadows, generateRadii, generateFonts, composePreset, getThemes } from '../../services/style_setter/style_setter.js' +import { merge } from 'lodash' +import { generateCompat, generateColors, generateShadows, generateRadii, generateFonts, composePreset, getThemes } from '../../services/style_setter/style_setter.js' import ColorInput from '../color_input/color_input.vue' import RangeInput from '../range_input/range_input.vue' import OpacityInput from '../opacity_input/opacity_input.vue' @@ -123,6 +124,15 @@ export default { selectedVersion () { return Array.isArray(this.selected) ? 1 : 2 }, + currentCompat () { + return generateCompat({ + shadows: this.shadowsLocal, + fonts: this.fontsLocal, + opacity: this.currentOpacity, + colors: this.currentColors, + radii: this.currentRadii + }) + }, currentColors () { return { bg: this.bgColorLocal, @@ -332,7 +342,7 @@ export default { return { // To separate from other random JSON files and possible future theme formats - _pleroma_theme_version: 2, theme + _pleroma_theme_version: 2, theme: merge(theme, this.currentCompat) } } }, @@ -364,7 +374,7 @@ export default { onImport (parsed) { if (parsed._pleroma_theme_version === 1) { this.normalizeLocalState(parsed, 1) - } else if (parsed._pleroma_theme_version === 2) { + } else if (parsed._pleroma_theme_version >= 2) { this.normalizeLocalState(parsed.theme, 2) } }, @@ -414,6 +424,7 @@ export default { /** * This applies stored theme data onto form. Supports three versions of data: + * v3 (version = 3) - same as 2 but with some incompatible changes * v2 (version = 2) - newer version of themes. * v1 (version = 1) - older version of themes (import from file) * v1l (version = l1) - older version of theme (load from local storage) @@ -421,12 +432,21 @@ export default { * @param {Object} input - input data * @param {Number} version - version of data. 0 means try to guess based on data. "l1" means v1, locastorage type */ - normalizeLocalState (input, version = 0) { - const colors = input.colors || input + normalizeLocalState (originalInput, version = 0) { + let input + if (typeof originalInput.v3compat !== undefined) { + version = 3 + input = merge(originalInput, originalInput.v3compat) + } else { + input = originalInput + } + + const compat = input.v3compat const radii = input.radii || input const opacity = input.opacity const shadows = input.shadows || {} const fonts = input.fonts || {} + const colors = input.colors || input if (version === 0) { if (input.version) version = input.version @@ -530,6 +550,7 @@ export default { currentColors () { try { this.previewColors = generateColors({ + v3compat: this.currentCompat, opacity: this.currentOpacity, colors: this.currentColors }) @@ -542,8 +563,9 @@ export default { currentOpacity () { try { this.previewColors = generateColors({ + v3compat: this.currentCompat, opacity: this.currentOpacity, - colors: this.currentColors + colors: this.currentColors, }) } catch (e) { console.warn(e) diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 8bbdc7b7..2ecd275a 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -2,7 +2,7 @@
-
- +
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 1e4bc59e..19a06587 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -148,6 +148,26 @@ const getCssColor = (input, a) => { return rgb2rgba({ ...rgb, a }) } +// Generates a "patch" for theme to make it compatible with v2 +export const generateCompat = (input) => { + const { colors } = input + const v3compat = { + colors: {} + } + const v2colorsPatch = {} + + // # Link became optional in v3 + if (typeof colors.link === 'undefined') { + v2colorsPatch.link = colors.accent + v3compat.colors.link = null + } + + return { + v3compat, + colors: v2colorsPatch + } +} + const generateColors = (input) => { const colors = {} const opacity = Object.assign({ @@ -164,7 +184,10 @@ const generateColors = (input) => { const inputColors = input.colors || input const compat = input.v3compat || {} - const compatColors = compat.colors || {} + const compatColors = Object.entries(compat.colors || {}).reduce((acc, [key, value]) => { + const newVal = value === null ? undefined : value + return { ...acc, [key]: newVal } + }, {}) const col = Object.entries({ ...inputColors, ...compatColors }).reduce((acc, [k, v]) => { if (typeof v === 'object') { @@ -210,7 +233,7 @@ const generateColors = (input) => { colors.topBarText = col.topBarText || getTextColor(colors.topBar, colors.fgText) colors.topBarLink = col.topBarLink || getTextColor(colors.topBar, colors.fgLink) - colors.faintLink = col.faintLink || Object.assign({}, col.link) + colors.faintLink = col.faintLink || Object.assign({}, col.link || col.accent) colors.linkBg = alphaBlend(colors.link, 0.4, colors.bg) colors.icon = mixrgb(colors.bg, colors.text) -- cgit v1.2.3-70-g09d2 From 6e11924c27288e590de8f5b675fb53704581bcc8 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Sat, 28 Dec 2019 18:49:35 +0200 Subject: underlay customization, updated contrast calculations to account for alpha blending --- src/App.scss | 1 + src/components/style_switcher/style_switcher.js | 47 ++++++++++++++---------- src/components/style_switcher/style_switcher.vue | 14 +++++++ src/services/color_convert/color_convert.js | 23 ++++++++++++ src/services/style_setter/style_setter.js | 37 +++++++++++++------ 5 files changed, 91 insertions(+), 31 deletions(-) (limited to 'src/components/style_switcher/style_switcher.vue') diff --git a/src/App.scss b/src/App.scss index 3b03a761..b6d4943a 100644 --- a/src/App.scss +++ b/src/App.scss @@ -32,6 +32,7 @@ h4 { min-height: 100vh; max-width: 980px; background-color: rgba(0,0,0,0.15); + background-color: var(--underlay, rgba(0,0,0,0.15)); align-content: flex-start; } diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index b450dc8e..602a635e 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -1,4 +1,4 @@ -import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js' +import { rgb2hex, hex2rgb, getContrastRatio, getContrastRatioLayers, alphaBlend } from '../../services/color_convert/color_convert.js' import { set, delete as del } from 'vue' import { merge } from 'lodash' import { generateCompat, generateColors, generateShadows, generateRadii, generateFonts, composePreset, getThemes } from '../../services/style_setter/style_setter.js' @@ -53,6 +53,9 @@ export default { bgColorLocal: '', bgOpacityLocal: undefined, + underlayColorLocal: '', + underlayOpacityLocal: undefined, + fgColorLocal: '', fgTextColorLocal: undefined, fgLinkColorLocal: undefined, @@ -145,6 +148,8 @@ export default { accent: this.accentColorLocal, + underlay: this.underlayColorLocal, + panel: this.panelColorLocal, panelText: this.panelTextColorLocal, panelLink: this.panelLinkColorLocal, @@ -182,7 +187,8 @@ export default { panel: this.panelOpacityLocal, topBar: this.topBarOpacityLocal, border: this.borderOpacityLocal, - faint: this.faintOpacityLocal + faint: this.faintOpacityLocal, + underlay: this.underlayOpacityLocal } }, currentRadii () { @@ -240,6 +246,7 @@ export default { const bgs = { bg: hex2rgb(colors.bg), + underlay: hex2rgb(colors.underlay), btn: hex2rgb(colors.btn), panel: hex2rgb(colors.panel), topBar: hex2rgb(colors.topBar), @@ -249,29 +256,31 @@ export default { badgeNotification: hex2rgb(colors.badgeNotification) } - /* This is a bit confusing because "bottom layer" used is text color - * This is done to get worst case scenario when background below transparent - * layer matches text color, making it harder to read the lower alpha is. - */ - const ratios = { - bgText: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.text), fgs.text), - bgLink: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.link), fgs.link), - bgRed: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.red), fgs.red), - bgGreen: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.green), fgs.green), - bgBlue: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.blue), fgs.blue), - bgOrange: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.orange), fgs.orange), + const bg = [bgs.bg, opacity.bg] + const underlay = [bgs.underlay, opacity.underlay] + const panel = [underlay, bg] + + const ratios = { + bgText: getContrastRatioLayers(fgs.text, panel, fgs.text), + bgLink: getContrastRatioLayers(fgs.link, panel, fgs.link), + bgRed: getContrastRatioLayers(fgs.red, panel, fgs.red), + bgGreen: getContrastRatioLayers(fgs.green, panel, fgs.green), + bgBlue: getContrastRatioLayers(fgs.blue, panel, fgs.blue), + bgOrange: getContrastRatioLayers(fgs.orange, panel, fgs.orange), + + // TODO what's this? tintText: getContrastRatio(alphaBlend(bgs.bg, 0.5, fgs.panelText), fgs.text), - panelText: getContrastRatio(alphaBlend(bgs.panel, opacity.panel, fgs.panelText), fgs.panelText), - panelLink: getContrastRatio(alphaBlend(bgs.panel, opacity.panel, fgs.panelLink), fgs.panelLink), + panelText: getContrastRatioLayers(fgs.text, [...panel, [bgs.panel, opacity.panel]], fgs.panelText), + panelLink: getContrastRatioLayers(fgs.link, [...panel, [bgs.panel, opacity.panel]], fgs.panelLink), - btnText: getContrastRatio(alphaBlend(bgs.btn, opacity.btn, fgs.btnText), fgs.btnText), + btnText: getContrastRatioLayers(fgs.text, [...panel, [bgs.btn, opacity.btn]], fgs.btnText), - inputText: getContrastRatio(alphaBlend(bgs.input, opacity.input, fgs.inputText), fgs.inputText), + inputText: getContrastRatioLayers(fgs.text, [...panel, [bgs.input, opacity.input]], fgs.inputText), - topBarText: getContrastRatio(alphaBlend(bgs.topBar, opacity.topBar, fgs.topBarText), fgs.topBarText), - topBarLink: getContrastRatio(alphaBlend(bgs.topBar, opacity.topBar, fgs.topBarLink), fgs.topBarLink) + topBarText: getContrastRatioLayers(fgs.text, [...panel, [bgs.topBar, opacity.topBar]], fgs.topBarText), + topBarLink: getContrastRatioLayers(fgs.link, [...panel, [bgs.topBar, opacity.topBar]], fgs.topBarLink) } return Object.entries(ratios).reduce((acc, [k, v]) => { acc[k] = hints(v); return acc }, {}) diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 2ecd275a..38ca2017 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -366,6 +366,20 @@ :fallback="previewTheme.opacity.faint || 0.5" />
+
+

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

+ + +
console.log('%c##########', 'background: ' + color + '; color: ' + color) + const rgb2hex = (r, g, b) => { if (r === null || typeof r === 'undefined') { return undefined @@ -78,6 +81,16 @@ const getContrastRatio = (a, b) => { return (l1 + 0.05) / (l2 + 0.05) } +/** + * Same as `getContrastRatio` but for multiple layers in-between + * + * @param {Object} text - text color (topmost layer) + * @param {[Object, Number]} layers[] - layers between text and bedrock + * @param {Object} bedrock - layer at the very bottom + */ +export const getContrastRatioLayers = (text, layers, bedrock) => { + return getContrastRatio(alphaBlendLayers(bedrock, layers), text) +} /** * This performs alpha blending between solid background and semi-transparent foreground @@ -97,6 +110,16 @@ const alphaBlend = (fg, fga, bg) => { }, {}) } +/** + * Same as `alphaBlend` but for multiple layers in-between + * + * @param {Object} bedrock - layer at the very bottom + * @param {[Object, Number]} layers[] - layers between text and bedrock + */ +export const alphaBlendLayers = (bedrock, layers) => layers.reduce((acc, [color, opacity]) => { + return alphaBlend(color, opacity, acc) +}, bedrock) + const invert = (rgb) => { return 'rgb'.split('').reduce((acc, c) => { acc[c] = 255 - rgb[c] diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 19a06587..8740fc55 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -1,6 +1,6 @@ import { times } from 'lodash' import { brightness, invertLightness, convert, contrastRatio } from 'chromatism' -import { rgb2hex, hex2rgb, mixrgb, getContrastRatio, alphaBlend } from '../color_convert/color_convert.js' +import { rgb2hex, hex2rgb, mixrgb, getContrastRatio, alphaBlend, alphaBlendLayers } from '../color_convert/color_convert.js' // While this is not used anymore right now, I left it in if we want to do custom // styles that aren't just colors, so user can pick from a few different distinct @@ -64,8 +64,10 @@ const getTextColor = function (bg, text, preserve) { const base = typeof text.a !== 'undefined' ? { a: text.a } : {} const result = Object.assign(base, invertLightness(text).rgb) if (!preserve && getContrastRatio(bg, result) < 4.5) { + // B&W return contrastRatio(bg, text).rgb } + // Inverted color return result } return text @@ -173,7 +175,8 @@ const generateColors = (input) => { const opacity = Object.assign({ alert: 0.5, input: 0.5, - faint: 0.5 + faint: 0.5, + underlay: 0.15 }, Object.entries(input.opacity || {}).reduce((acc, [k, v]) => { if (typeof v !== 'undefined') { acc[k] = v @@ -210,28 +213,37 @@ const generateColors = (input) => { colors.faint = col.faint || Object.assign({}, col.text) colors.bg = col.bg - colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb + colors.lightBg = col.lightBg || brightness(5 * mod, colors.bg).rgb + + const underlay = [col.underlay, opacity.underlay] + const fg = [col.fg, opacity.fg] + const bg = [col.bg, opacity.bg] colors.fg = col.fg - colors.fgText = col.fgText || getTextColor(colors.fg, colors.text) - colors.fgLink = col.fgLink || getTextColor(colors.fg, colors.link, true) + colors.fgText = col.fgText || getTextColor(alphaBlendLayers(colors.text, [underlay, bg, fg]), colors.text) + colors.fgLink = col.fgLink || getTextColor(alphaBlendLayers(colors.link, [underlay, bg, fg]), colors.link, true) + colors.underlay = col.underlay || hex2rgb('#000000') colors.border = col.border || brightness(2 * mod, colors.fg).rgb colors.btn = col.btn || Object.assign({}, col.fg) - colors.btnText = col.btnText || getTextColor(colors.btn, colors.fgText) + const btn = [colors.btn, opacity.btn || 1] + colors.btnText = col.btnText || getTextColor(alphaBlendLayers(colors.fgText, [underlay, bg, fg, btn]), colors.fgText) colors.input = col.input || Object.assign({}, col.fg) - colors.inputText = col.inputText || getTextColor(colors.input, colors.lightText) + const inputCol = [colors.input, opacity.input] + colors.inputText = col.inputText || getTextColor(alphaBlendLayers(colors.lightText, [underlay, bg, fg, inputCol]), colors.lightText) colors.panel = col.panel || Object.assign({}, col.fg) - colors.panelText = col.panelText || getTextColor(colors.panel, colors.fgText) - colors.panelLink = col.panelLink || getTextColor(colors.panel, colors.fgLink) - colors.panelFaint = col.panelFaint || getTextColor(colors.panel, colors.faint) + const panel = [colors.panel, opacity.panel] + colors.panelText = col.panelText || getTextColor(alphaBlendLayers(colors.fgText, [underlay, bg, panel]), colors.fgText) + colors.panelLink = col.panelLink || getTextColor(alphaBlendLayers(colors.fgLink, [underlay, bg, panel]), colors.fgLink) + colors.panelFaint = col.panelFaint || getTextColor(alphaBlendLayers(colors.faint, [underlay, bg, panel]), colors.faint) colors.topBar = col.topBar || Object.assign({}, col.fg) - colors.topBarText = col.topBarText || getTextColor(colors.topBar, colors.fgText) - colors.topBarLink = col.topBarLink || getTextColor(colors.topBar, colors.fgLink) + const topBar = [colors.topBar, opacity.topBar] + colors.topBarText = col.topBarText || getTextColor(alphaBlendLayers(colors.fgText, [topBar]), colors.fgText) + colors.topBarLink = col.topBarLink || getTextColor(alphaBlendLayers(colors.fgLink, [topBar]), colors.fgLink) colors.faintLink = col.faintLink || Object.assign({}, col.link || col.accent) colors.linkBg = alphaBlend(colors.link, 0.4, colors.bg) @@ -255,6 +267,7 @@ const generateColors = (input) => { colors.badgeNotificationText = contrastRatio(colors.badgeNotification).rgb Object.entries(opacity).forEach(([ k, v ]) => { + console.log(k) if (typeof v === 'undefined') return if (k === 'alert') { colors.alertError.a = v -- cgit v1.2.3-70-g09d2 From 4bb1c98e0f28bcf1d0dff2d90d01013cd5487522 Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 2 Jan 2020 20:36:10 +0200 Subject: Replaced `v3compat` with `source` to reduce code complexity. Made more slots customizable. `theme` now contains a snapshot of theme generated for better compatiblity and future-proofing --- src/components/style_switcher/style_switcher.js | 68 ++++--- src/components/style_switcher/style_switcher.vue | 14 +- src/services/style_setter/style_setter.js | 42 ++--- static/themes/breezy-dark.json | 224 ++++++++++++++++++++++- static/themes/breezy-light.json | 220 +++++++++++++++++++++- 5 files changed, 488 insertions(+), 80 deletions(-) (limited to 'src/components/style_switcher/style_switcher.vue') diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index 9fe1bf59..f751260a 100644 --- a/src/components/style_switcher/style_switcher.js +++ b/src/components/style_switcher/style_switcher.js @@ -1,7 +1,15 @@ import { rgb2hex, hex2rgb, getContrastRatio, getContrastRatioLayers, alphaBlend } from '../../services/color_convert/color_convert.js' import { set, delete as del } from 'vue' import { merge } from 'lodash' -import { generateCompat, generateColors, generateShadows, generateRadii, generateFonts, composePreset, getThemes } from '../../services/style_setter/style_setter.js' +import { + generateColors, + generateShadows, + generateRadii, + generateFonts, + composePreset, + getThemes, + CURRENT_VERSION +} from '../../services/style_setter/style_setter.js' import ColorInput from '../color_input/color_input.vue' import RangeInput from '../range_input/range_input.vue' import OpacityInput from '../opacity_input/opacity_input.vue' @@ -135,15 +143,6 @@ export default { selectedVersion () { return Array.isArray(this.selected) ? 1 : 2 }, - currentCompat () { - return generateCompat({ - shadows: this.shadowsLocal, - fonts: this.fontsLocal, - opacity: this.currentOpacity, - colors: this.currentColors, - radii: this.currentRadii - }) - }, currentColors () { return { bg: this.bgColorLocal, @@ -339,27 +338,32 @@ export default { !this.keepColor ) - const theme = {} + const source = { + themeEngineVersion: CURRENT_VERSION + } if (this.keepFonts || saveEverything) { - theme.fonts = this.fontsLocal + source.fonts = this.fontsLocal } if (this.keepShadows || saveEverything) { - theme.shadows = this.shadowsLocal + source.shadows = this.shadowsLocal } if (this.keepOpacity || saveEverything) { - theme.opacity = this.currentOpacity + source.opacity = this.currentOpacity } if (this.keepColor || saveEverything) { - theme.colors = this.currentColors + source.colors = this.currentColors } if (this.keepRoundness || saveEverything) { - theme.radii = this.currentRadii + source.radii = this.currentRadii } + const theme = this.previewTheme + + console.log(source) return { - // To separate from other random JSON files and possible future theme formats - _pleroma_theme_version: 2, theme: merge(theme, this.currentCompat) + // To separate from other random JSON files and possible future source formats + _pleroma_theme_version: 2, theme, source } } }, @@ -392,7 +396,7 @@ export default { if (parsed._pleroma_theme_version === 1) { this.normalizeLocalState(parsed, 1) } else if (parsed._pleroma_theme_version >= 2) { - this.normalizeLocalState(parsed.theme, 2) + this.normalizeLocalState(parsed.theme, 2, parsed.source) } }, importValidator (parsed) { @@ -402,7 +406,7 @@ export default { clearAll () { const state = this.$store.getters.mergedConfig.customTheme const version = state.colors ? 2 : 'l1' - this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme, version) + this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme, version, this.$store.getters.mergedConfig.customThemeSource) }, // Clears all the extra stuff when loading V1 theme @@ -441,24 +445,30 @@ export default { /** * This applies stored theme data onto form. Supports three versions of data: - * v3 (version = 3) - same as 2 but with some incompatible changes + * v3 (version >= 3) - newest version of themes which supports snapshots for better compatiblity * v2 (version = 2) - newer version of themes. * v1 (version = 1) - older version of themes (import from file) * v1l (version = l1) - older version of theme (load from local storage) * v1 and v1l differ because of way themes were stored/exported. - * @param {Object} input - input data + * @param {Object} theme - theme data (snapshot) * @param {Number} version - version of data. 0 means try to guess based on data. "l1" means v1, locastorage type + * @param {Object} source - theme source - this will be used if compatible + * @param {Boolean} source - by default source won't be used if version doesn't match since it might render differently + * this allows importing source anyway */ - normalizeLocalState (originalInput, version = 0) { + normalizeLocalState (theme, version = 0, source, forceSource = false) { let input - if (typeof originalInput.v3compat !== 'undefined') { - version = 3 - input = merge(originalInput, originalInput.v3compat) + if (typeof source !== 'undefined') { + if (forceSource || source.themeEngineVersion === CURRENT_VERSION) { + input = source + version = source.themeEngineVersion + } else { + input = theme + } } else { - input = originalInput + input = theme } - const compat = input.v3compat const radii = input.radii || input const opacity = input.opacity const shadows = input.shadows || {} @@ -615,7 +625,7 @@ export default { this.cOrangeColorLocal = this.selected[8] } } else if (this.selectedVersion >= 2) { - this.normalizeLocalState(this.selected.theme, 2) + this.normalizeLocalState(this.selected.theme, 2, this.selected.source) } } } diff --git a/src/components/style_switcher/style_switcher.vue b/src/components/style_switcher/style_switcher.vue index 38ca2017..2eadbe25 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -106,7 +106,7 @@
@@ -363,7 +363,7 @@
@@ -377,7 +377,7 @@
diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index df22f94f..e8a64517 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -2,6 +2,8 @@ import { times } from 'lodash' import { brightness, invertLightness, convert, contrastRatio } from 'chromatism' import { rgb2hex, hex2rgb, mixrgb, getContrastRatio, alphaBlend, alphaBlendLayers } from '../color_convert/color_convert.js' +export const CURRENT_VERSION = 3 + // While this is not used anymore right now, I left it in if we want to do custom // styles that aren't just colors, so user can pick from a few different distinct // styles as well as set their own colors in the future. @@ -150,29 +152,13 @@ const getCssColor = (input, a) => { return rgb2rgba({ ...rgb, a }) } -// Generates a "patch" for theme to make it compatible with v2 -export const generateCompat = (input) => { - const { colors } = input - const v3compat = { - colors: {} - } - const v2colorsPatch = {} - - // # Link became optional in v3 - if (typeof colors.link === 'undefined') { - v2colorsPatch.link = colors.accent - v3compat.colors.link = null - } - - return { - v3compat, - colors: v2colorsPatch - } -} - const generateColors = (themeData) => { const colors = {} const rawOpacity = Object.assign({ + panel: 1, + btn: 1, + border: 1, + bg: 1, alert: 0.5, input: 0.5, faint: 0.5, @@ -207,6 +193,7 @@ const generateColors = (themeData) => { } else { let value = v if (v === 'transparent') { + // TODO: hack to keep rest of the code from complaining value = '#FF00FF' } acc[k] = hex2rgb(value) @@ -221,7 +208,7 @@ const generateColors = (themeData) => { const isLightOnDark = convert(colors.bg).hsl.l < convert(colors.text).hsl.l const mod = isLightOnDark ? 1 : -1 - colors.lightText = brightness(20 * mod, colors.text).rgb + colors.lightText = col.lightText || brightness(20 * mod, colors.text).rgb colors.accent = col.accent || col.link colors.link = col.link || col.accent @@ -231,7 +218,8 @@ const generateColors = (themeData) => { colors.lightBg = col.lightBg || brightness(5 * mod, colors.bg).rgb const underlay = [colors.underlay, opacity.underlay] - const fg = [col.fg, opacity.fg] + // Technically, foreground can't be transparent (descendants can) but let's keep it just in case + const fg = [col.fg, opacity.fg || 1] const bg = [col.bg, opacity.bg] colors.fg = col.fg @@ -271,16 +259,16 @@ const generateColors = (themeData) => { colors.alertError = col.alertError || Object.assign({}, colors.cRed) const alertError = [colors.alertError, opacity.alert] - colors.alertErrorText = getTextColor(alphaBlendLayers(colors.text, [underlay, bg, alertError]), colors.text) - colors.alertErrorPanelText = getTextColor(alphaBlendLayers(colors.panelText, [underlay, bg, panel, panel, alertError]), colors.panelText) + colors.alertErrorText = col.alertErrorText || getTextColor(alphaBlendLayers(colors.text, [underlay, bg, alertError]), colors.text) + colors.alertErrorPanelText = col.alertErrorPanelText || getTextColor(alphaBlendLayers(colors.panelText, [underlay, bg, panel, panel, alertError]), colors.panelText) colors.alertWarning = col.alertWarning || Object.assign({}, colors.cOrange) const alertWarning = [colors.alertWarning, opacity.alert] - colors.alertWarningText = getTextColor(alphaBlendLayers(colors.text, [underlay, bg, alertWarning]), colors.text) - colors.alertWarningPanelText = getTextColor(alphaBlendLayers(colors.panelText, [underlay, bg, panel, panel, alertWarning]), colors.panelText) + colors.alertWarningText = col.alertWarningText || getTextColor(alphaBlendLayers(colors.text, [underlay, bg, alertWarning]), colors.text) + colors.alertWarningPanelText = col.alertWarningPanelText || getTextColor(alphaBlendLayers(colors.panelText, [underlay, bg, panel, panel, alertWarning]), colors.panelText) colors.badgeNotification = col.badgeNotification || Object.assign({}, colors.cRed) - colors.badgeNotificationText = contrastRatio(colors.badgeNotification).rgb + colors.badgeNotificationText = colors.badgeNotificationText || contrastRatio(colors.badgeNotification).rgb Object.entries(opacity).forEach(([ k, v ]) => { console.log(k) diff --git a/static/themes/breezy-dark.json b/static/themes/breezy-dark.json index 0ed55184..d447005f 100644 --- a/static/themes/breezy-dark.json +++ b/static/themes/breezy-dark.json @@ -2,6 +2,218 @@ "_pleroma_theme_version": 2, "name": "Breezy Dark (beta)", "theme": { + "shadows": { + "panel": [ + { + "x": "1", + "y": "2", + "blur": "6", + "spread": 0, + "color": "#000000", + "alpha": 0.6 + } + ], + "topBar": [ + { + "x": 0, + "y": 0, + "blur": 4, + "spread": 0, + "color": "#000000", + "alpha": 0.6 + } + ], + "popup": [ + { + "x": 2, + "y": 2, + "blur": 3, + "spread": 0, + "color": "#000000", + "alpha": 0.5 + } + ], + "avatar": [ + { + "x": 0, + "y": 1, + "blur": 8, + "spread": 0, + "color": "#000000", + "alpha": 0.7 + } + ], + "avatarStatus": [], + "panelHeader": [ + { + "x": 0, + "y": "40", + "blur": "40", + "spread": "-40", + "inset": true, + "color": "#ffffff", + "alpha": "0.1" + } + ], + "button": [ + { + "x": 0, + "y": "0", + "blur": "0", + "spread": "1", + "color": "#ffffff", + "alpha": "0.15", + "inset": true + }, + { + "x": "1", + "y": "1", + "blur": "1", + "spread": 0, + "color": "#000000", + "alpha": "0.3", + "inset": false + } + ], + "buttonHover": [ + { + "x": 0, + "y": "0", + "blur": 0, + "spread": "1", + "color": "--accent", + "alpha": "0.3", + "inset": true + }, + { + "x": "1", + "y": "1", + "blur": "1", + "spread": 0, + "color": "#000000", + "alpha": "0.3", + "inset": false + } + ], + "buttonPressed": [ + { + "x": 0, + "y": 0, + "blur": "0", + "spread": "50", + "color": "--faint", + "alpha": 1, + "inset": true + }, + { + "x": 0, + "y": "0", + "blur": 0, + "spread": "1", + "color": "#ffffff", + "alpha": 0.2, + "inset": true + }, + { + "x": "1", + "y": "1", + "blur": 0, + "spread": 0, + "color": "#000000", + "alpha": "0.3", + "inset": false + } + ], + "input": [ + { + "x": 0, + "y": "0", + "blur": 0, + "spread": "1", + "color": "#FFFFFF", + "alpha": "0.2", + "inset": true + } + ] + }, + "colors": { + "bg": "#31363b", + "underlay": "#000000", + "text": "#eff0f1", + "lightText": "#ffffff", + "accent": "#3daee9", + "link": "#3daee9", + "faint": "#eff0f1", + "lightBg": "#3d4349", + "fg": "#31363b", + "fgText": "#eff0f1", + "fgLink": "#3daee9", + "border": "#4c545b", + "btn": "#31363b", + "btnText": "#eff0f1", + "input": "#232629", + "inputText": "#ffffff", + "panel": "#ff00ff", + "panelText": "#eff0f1", + "panelLink": "#3daee9", + "panelFaint": "#eff0f1", + "topBar": "#31363b", + "topBarText": "#eff0f1", + "topBarLink": "#eff0f1", + "faintLink": "#3daee9", + "linkBg": "#366681", + "icon": "#909396", + "cBlue": "#3daee9", + "cRed": "#da4453", + "cGreen": "#27ae60", + "cOrange": "#f67400", + "alertError": "#da4453", + "alertErrorText": "#eff0f1", + "alertErrorPanelText": "#eff0f1", + "alertWarning": "#f67400", + "alertWarningText": "#eff0f1", + "alertWarningPanelText": "#eff0f1", + "badgeNotification": "#da4453", + "badgeNotificationText": "#ffffff" + }, + "opacity": { + "panel": 0, + "btn": 1, + "border": 1, + "bg": 1, + "alert": 0.5, + "input": 0.5, + "faint": 0.5, + "underlay": 0.15 + }, + "radii": { + "btn": "2", + "input": "2", + "checkbox": "1", + "panel": "2", + "avatar": "2", + "avatarAlt": "2", + "tooltip": "2", + "attachment": "2" + }, + "fonts": { + "interface": { + "family": "sans-serif" + }, + "input": { + "family": "inherit" + }, + "post": { + "family": "inherit" + }, + "postCode": { + "family": "monospace" + } + } + }, + "source": { + "themeEngineVersion": 3, + "fonts": {}, "shadows": { "panel": [ { @@ -105,21 +317,13 @@ } ] }, - "fonts": {}, - "opacity": { - "input": "1" - }, - "v3compat": { - "colors": { - "panel": "transparent" - } - }, + "opacity": {}, "colors": { "bg": "#31363b", "text": "#eff0f1", "link": "#3daee9", "fg": "#31363b", - "panel": "#31363b", + "panel": "transparent", "input": "#232629", "topBarLink": "#eff0f1", "btn": "#31363b", diff --git a/static/themes/breezy-light.json b/static/themes/breezy-light.json index 5db185dd..243b8593 100644 --- a/static/themes/breezy-light.json +++ b/static/themes/breezy-light.json @@ -2,6 +2,218 @@ "_pleroma_theme_version": 2, "name": "Breezy Light (beta)", "theme": { + "shadows": { + "panel": [ + { + "x": "1", + "y": "2", + "blur": "6", + "spread": 0, + "color": "#000000", + "alpha": 0.6 + } + ], + "topBar": [ + { + "x": 0, + "y": 0, + "blur": 4, + "spread": 0, + "color": "#000000", + "alpha": 0.6 + } + ], + "popup": [ + { + "x": 2, + "y": 2, + "blur": 3, + "spread": 0, + "color": "#000000", + "alpha": 0.5 + } + ], + "avatar": [ + { + "x": 0, + "y": 1, + "blur": 8, + "spread": 0, + "color": "#000000", + "alpha": 0.7 + } + ], + "avatarStatus": [], + "panelHeader": [ + { + "x": 0, + "y": "40", + "blur": "40", + "spread": "-40", + "inset": true, + "color": "#ffffff", + "alpha": "0.1" + } + ], + "button": [ + { + "x": 0, + "y": "0", + "blur": "0", + "spread": "1", + "color": "#000000", + "alpha": "0.3", + "inset": true + }, + { + "x": "1", + "y": "1", + "blur": "1", + "spread": 0, + "color": "#000000", + "alpha": "0.3", + "inset": false + } + ], + "buttonHover": [ + { + "x": 0, + "y": "0", + "blur": 0, + "spread": "1", + "color": "--accent", + "alpha": "0.3", + "inset": true + }, + { + "x": "1", + "y": "1", + "blur": "1", + "spread": 0, + "color": "#000000", + "alpha": "0.3", + "inset": false + } + ], + "buttonPressed": [ + { + "x": 0, + "y": 0, + "blur": "0", + "spread": "50", + "color": "--faint", + "alpha": 1, + "inset": true + }, + { + "x": 0, + "y": "0", + "blur": 0, + "spread": "1", + "color": "#ffffff", + "alpha": 0.2, + "inset": true + }, + { + "x": "1", + "y": "1", + "blur": 0, + "spread": 0, + "color": "#000000", + "alpha": "0.3", + "inset": false + } + ], + "input": [ + { + "x": 0, + "y": "0", + "blur": 0, + "spread": "1", + "color": "#000000", + "alpha": "0.2", + "inset": true + } + ] + }, + "colors": { + "bg": "#eff0f1", + "underlay": "#000000", + "text": "#232627", + "lightText": "#000000", + "accent": "#2980b9", + "link": "#2980b9", + "faint": "#232627", + "lightBg": "#e2e4e6", + "fg": "#bcc2c7", + "fgText": "#232627", + "fgLink": "#2980b9", + "border": "#b7bdc3", + "btn": "#eff0f1", + "btnText": "#232627", + "input": "#fcfcfc", + "inputText": "#000000", + "panel": "#475057", + "panelText": "#fcfcfc", + "panelLink": "#ffffff", + "panelFaint": "#d8dbdc", + "topBar": "#475057", + "topBarText": "#d8dbdc", + "topBarLink": "#eff0f1", + "faintLink": "#2980b9", + "linkBg": "#a0c4db", + "icon": "#898b8c", + "cBlue": "#2980b9", + "cRed": "#da4453", + "cGreen": "#27ae60", + "cOrange": "#f67400", + "alertError": "#da4453", + "alertErrorText": "#232627", + "alertErrorPanelText": "#fcfcfc", + "alertWarning": "#f67400", + "alertWarningText": "#232627", + "alertWarningPanelText": "#fcfcfc", + "badgeNotification": "#da4453", + "badgeNotificationText": "#ffffff" + }, + "opacity": { + "panel": 1, + "btn": 1, + "border": 1, + "bg": 1, + "alert": 0.5, + "input": "1", + "faint": 0.5, + "underlay": 0.15 + }, + "radii": { + "btn": "2", + "input": "2", + "checkbox": "1", + "panel": "2", + "avatar": "2", + "avatarAlt": "2", + "tooltip": "2", + "attachment": "2" + }, + "fonts": { + "interface": { + "family": "sans-serif" + }, + "input": { + "family": "inherit" + }, + "post": { + "family": "inherit" + }, + "postCode": { + "family": "monospace" + } + } + }, + "source": { + "themeEngineVersion": 3, + "fonts": {}, "shadows": { "panel": [ { @@ -105,20 +317,14 @@ } ] }, - "fonts": {}, "opacity": { "input": "1" }, - "v3compat": { - "colors": { - "panel": "transparent" - } - }, "colors": { "bg": "#eff0f1", "text": "#232627", - "link": "#2980b9", "fg": "#bcc2c7", + "accent": "#2980b9", "panel": "#475057", "panelText": "#fcfcfc", "input": "#fcfcfc", -- cgit v1.2.3-70-g09d2 From adbab6ad2a413357b24edbd5b9beec3baae695fa Mon Sep 17 00:00:00 2001 From: Henry Jameson Date: Thu, 2 Jan 2020 21:36:01 +0200 Subject: added optional checkbox for opacity, similar to color input --- src/components/opacity_input/opacity_input.vue | 37 +++++++++++++++++++++--- src/components/style_switcher/style_switcher.vue | 9 ++++-- 2 files changed, 40 insertions(+), 6 deletions(-) (limited to 'src/components/style_switcher/style_switcher.vue') diff --git a/src/components/opacity_input/opacity_input.vue b/src/components/opacity_input/opacity_input.vue index c677f18c..f7b10d30 100644 --- a/src/components/opacity_input/opacity_input.vue +++ b/src/components/opacity_input/opacity_input.vue @@ -18,7 +18,7 @@ @input="$emit('input', !present ? fallback : undefined)" >