diff --git a/package.json b/package.json index b716e7c69224947957730eb69de2c275a8dcab6a..1149d200b8cc16ac649fbb9768ec4d12e17e9cee 100644 --- a/package.json +++ b/package.json @@ -16,6 +16,7 @@ "dependencies": { "babel-plugin-add-module-exports": "^0.2.1", "babel-plugin-lodash": "^3.2.11", + "chromatism": "^3.0.0", "diff": "^3.0.1", "karma-mocha-reporter": "^2.2.1", "localforage": "^1.5.0", diff --git a/src/App.scss b/src/App.scss index 056a235ef1916e3584ccb0733c554112171e2e98..1119caf27accbcc8857cec42903e82cdb3a13287 100644 --- a/src/App.scss +++ b/src/App.scss @@ -51,7 +51,7 @@ a { button { user-select: none; color: $fallback--fg; - color: var(--fg, $fallback--fg); + color: var(--btnText, $fallback--fg); background-color: $fallback--btn; background-color: var(--btn, $fallback--btn); border: none; @@ -254,7 +254,7 @@ nav { mask-position: center; mask-size: contain; background-color: $fallback--fg; - background-color: var(--fg, $fallback--fg); + background-color: var(--topBarText, $fallback--fg); position: absolute; top: 0; bottom: 0; @@ -330,8 +330,9 @@ main-router { padding: .6em .6em; text-align: left; line-height: 28px; + color: var(--panelText); background-color: $fallback--btn; - background-color: var(--btn, $fallback--btn); + background-color: var(--panel, $fallback--btn); align-items: baseline; .title { @@ -387,8 +388,9 @@ main-router { nav { z-index: 1000; + color: var(--topBarText); background-color: $fallback--btn; - background-color: var(--btn, $fallback--btn); + background-color: var(--topBar, $fallback--btn); color: $fallback--faint; color: var(--faint, $fallback--faint); box-shadow: 0px 0px 4px rgba(0,0,0,.6); diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index 42c660a3c33dcdcf078873cd3f3c8af24747f539..eebb2cb78f6c0fe7c02d83651129aa7aac7395d1 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -18,6 +18,7 @@ </transition> </div> <div class="panel-body"> +<keep-alive> <tab-switcher> <div :label="$t('settings.general')" > <div class="setting-item"> @@ -146,6 +147,7 @@ </div> </tab-switcher> +</keep-alive> </div> </div> </template> diff --git a/src/components/style_switcher/style_switcher.js b/src/components/style_switcher/style_switcher.js index 95c15b496baf67d63f2296cac856861582ead9da..5f76c038a1dfef0151e4e80e8ad9fcd5a014df8d 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 72a338bdb9cc4c3eb2f84cbf3fd43fc5c803d366..339d7c3dbe0b06c874a9dc4089c2c58bb0bc8c98 100644 --- a/src/components/style_switcher/style_switcher.vue +++ b/src/components/style_switcher/style_switcher.vue @@ -24,80 +24,73 @@ </div> </div> - <div class="preview-container"> - <div :style="{ - '--btnRadius': btnRadiusLocal + 'px', - '--inputRadius': inputRadiusLocal + 'px', - '--panelRadius': panelRadiusLocal + 'px', - '--avatarRadius': avatarRadiusLocal + 'px', - '--avatarAltRadius': avatarAltRadiusLocal + 'px', - '--tooltipRadius': tooltipRadiusLocal + 'px', - '--attachmentRadius': attachmentRadiusLocal + 'px' - }"> - <div class="panel dummy"> - <div class="panel-heading" :style="{ 'background-color': btnColorLocal, 'color': textColorLocal }">Preview</div> - <div class="panel-body theme-preview-content" :style="{ 'background-color': bgColorLocal, 'color': textColorLocal }"> - <div class="avatar" :style="{ - 'border-radius': avatarRadiusLocal + 'px' - }"> - ( 汀掳 蜏蕱 汀掳) - </div> - <h4>Content</h4> - <br> - A bunch of more content and - <a :style="{ color: linkColorLocal }">a nice lil' link</a> - <i :style="{ color: blueColorLocal }" class="icon-reply"/> - <i :style="{ color: greenColorLocal }" class="icon-retweet"/> - <i :style="{ color: redColorLocal }" class="icon-cancel"/> - <i :style="{ color: orangeColorLocal }" class="icon-star"/> - <br> - <button class="btn" :style="{ 'background-color': btnColorLocal, 'color': textColorLocal }">Button</button> + <div class="preview-container" :style="previewRules"> + <div class="panel dummy"> + <div class="panel-heading">Preview</div> + <div class="panel-body theme-preview-content"> + <div class="avatar"> + ( 汀掳 蜏蕱 汀掳) </div> + <h4>Content</h4> + <br> + A bunch of more content and + <a style="color: var(--link)">a nice lil' link</a> + <i style="color: var(--cBlue)" class="icon-reply"/> + <i style="color: var(--cGreen)" class="icon-retweet"/> + <i style="color: var(--cRed)" class="icon-cancel"/> + <i style="color: var(--cOrange)" class="icon-star"/> + <br> + <button class="btn">Button</button> </div> </div> </div> <div class="color-container"> <p>{{$t('settings.theme_help')}}</p> - <div class="color-item"> - <label for="bgcolor" class="theme-color-lb">{{$t('settings.background')}}</label> - <input id="bgcolor" class="theme-color-cl" type="color" v-model="bgColorLocal"> - <input id="bgcolor-t" class="theme-color-in" type="text" v-model="bgColorLocal"> - </div> - <div class="color-item"> - <label for="fgcolor" class="theme-color-lb">{{$t('settings.foreground')}}</label> - <input id="fgcolor" class="theme-color-cl" type="color" v-model="btnColorLocal"> - <input id="fgcolor-t" class="theme-color-in" type="text" v-model="btnColorLocal"> - </div> - <div class="color-item"> - <label for="textcolor" class="theme-color-lb">{{$t('settings.text')}}</label> - <input id="textcolor" class="theme-color-cl" type="color" v-model="textColorLocal"> - <input id="textcolor-t" class="theme-color-in" type="text" v-model="textColorLocal"> - </div> - <div class="color-item"> - <label for="linkcolor" class="theme-color-lb">{{$t('settings.links')}}</label> - <input id="linkcolor" class="theme-color-cl" type="color" v-model="linkColorLocal"> - <input id="linkcolor-t" class="theme-color-in" type="text" v-model="linkColorLocal"> - </div> - <div class="color-item"> - <label for="redcolor" class="theme-color-lb">{{$t('settings.cRed')}}</label> - <input id="redcolor" class="theme-color-cl" type="color" v-model="redColorLocal"> - <input id="redcolor-t" class="theme-color-in" type="text" v-model="redColorLocal"> - </div> - <div class="color-item"> - <label for="bluecolor" class="theme-color-lb">{{$t('settings.cBlue')}}</label> - <input id="bluecolor" class="theme-color-cl" type="color" v-model="blueColorLocal"> - <input id="bluecolor-t" class="theme-color-in" type="text" v-model="blueColorLocal"> + <h3>Basic colors!!</h3> + <div> + <div class="color-item"> + <ColorInput name="bgColor" v-model="bgColorLocal" :label="$t('settings.background')"/> + <OpacityInput name="bgOpacity" v-model="bgOpacityLocal" fallback="1"/> + </div> + <div class="color-item"> + <ColorInput name="fgColor" v-model="btnColorLocal" :label="$t('settings.foreground')"/> + <OpacityInput name="fgOpacity" v-model="btnOpacityLocal" fallback="1"/> + </div> + <div class="color-item"> + <ColorInput name="textColor" v-model="textColorLocal" :label="$t('settings.text')"/> + </div> + <div class="color-item"> + <ColorInput name="linkColor" v-model="linkColorLocal" :label="$t('settings.links')"/> + </div> </div> - <div class="color-item"> - <label for="greencolor" class="theme-color-lb">{{$t('settings.cGreen')}}</label> - <input id="greencolor" class="theme-color-cl" type="color" v-model="greenColorLocal"> - <input id="greencolor-t" class="theme-color-in" type="green" v-model="greenColorLocal"> + + <h3>More customs!</h3> + <div> + <div class="color-item"> + <ColorInput name="panelColor" v-model="panelColorLocal" :fallback="btnColorLocal" label="Panel header"/> + <OpacityInput name="panelOpacity" v-model="panelOpacityLocal" fallback="1"/> + </div> + <div class="color-item"> + <ColorInput name="topBarColor" v-model="topBarColorLocal" :fallback="btnColorLocal" label="Top bar"/> + <OpacityInput name="topBarOpacity" v-model="topBarOpacityLocal" fallback="1"/> + </div> </div> - <div class="color-item"> - <label for="orangecolor" class="theme-color-lb">{{$t('settings.cOrange')}}</label> - <input id="orangecolor" class="theme-color-cl" type="color" v-model="orangeColorLocal"> - <input id="orangecolor-t" class="theme-color-in" type="text" v-model="orangeColorLocal"> + + <h3>Rainbows!!!</h3> + <div> + <div class="color-item"> + <ColorInput name="cRedColor" v-model="redColorLocal" :label="$t('settings.cRed')"/> + </div> + <div class="color-item"> + <ColorInput name="cBlueColor" v-model="blueColorLocal" :label="$t('settings.cBlue')"/> + </div> + <div class="color-item"> + <ColorInput name="cGreenColor" v-model="greenColorLocal" :label="$t('settings.cGreen')"/> + </div> + <div class="color-item"> + <ColorInput name="cOrangeColor" v-model="orangeColorLocal" :label="$t('settings.cOrange')"/> + </div> </div> </div> @@ -161,7 +154,7 @@ .apply-container, .radius-container, -.color-container, +.color-container > div, .presets-container { display: flex; @@ -176,7 +169,7 @@ flex-direction: column; } -.color-container { +.color-container > div{ flex-wrap: wrap; justify-content: space-between; } @@ -214,14 +207,30 @@ .radius-item, .color-item { min-width: 20em; + margin: 5px 6px 0 0; display:flex; + flex-direction: column; flex: 1 1 0; - align-items: baseline; - margin: 5px 6px 5px 0; + + &:nth-child(2n+1) { + margin-right: 7px; + + } + + .color, .opacity { + display:flex; + align-items: baseline; + } label { color: var(--faint, $fallback--faint); } + .opacity-control { + margin-top: 5px; + height: 12px; + line-height: 12px; + font-size: 12px; + } } .radius-item { @@ -243,44 +252,19 @@ margin-left: 4px; } -.theme-color-in { - min-width: 4em; -} - .theme-radius-in { min-width: 1em; } -.theme-radius-in, -.theme-color-in { +.theme-radius-in { max-width: 7em; flex: 1; } -.theme-radius-lb, -.theme-color-lb { - flex: 2; - min-width: 7em; -} - .theme-radius-lb{ max-width: 50em; } -.theme-color-lb { - max-width: 10em; -} - -.theme-color-cl { - padding: 1px; - max-width: 8em; - height: 100%; - flex: 0; - min-width: 2em; - cursor: pointer; - max-height: 29px; -} - .theme-preview-content { padding: 20px; } diff --git a/src/lib/persisted_state.js b/src/lib/persisted_state.js index 006107e207ac7f6d8875b70590406e3dd4e3e0ea..e55b3b79e53f875236d238dab0aa81a833bf52a4 100644 --- a/src/lib/persisted_state.js +++ b/src/lib/persisted_state.js @@ -73,6 +73,7 @@ export default function createPersistedState ({ loaded = true } catch (e) { console.log("Couldn't load state") + console.error(e) loaded = true } }) diff --git a/src/services/color_convert/color_convert.js b/src/services/color_convert/color_convert.js index 13dd897975fe19f5eba7572cd37255567c9cc5a3..efb433276b2ec6daad7c073342a114321280e5a3 100644 --- a/src/services/color_convert/color_convert.js +++ b/src/services/color_convert/color_convert.js @@ -1,6 +1,10 @@ import { map } from 'lodash' const rgb2hex = (r, g, b) => { + console.log(r) + if (typeof r === 'object') { + ({ r, g, b } = r) + } [r, g, b] = map([r, g, b], (val) => { val = Math.ceil(val) val = val < 0 ? 0 : val @@ -27,8 +31,16 @@ const rgbstr2hex = (rgb) => { return `#${((Number(rgb[0]) << 16) + (Number(rgb[1]) << 8) + Number(rgb[2])).toString(16)}` } +const mixrgb = (a, b) => { + return Object.keys(a).reduce((acc, k) => { + acc[k] = (a[k] + b[k]) / 2 + return acc + }, {}) +} + export { rgb2hex, hex2rgb, + mixrgb, rgbstr2hex } diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 493d444eb144a024a27c5bdd307ec9229c64c96e..72782594156e2001abce42fe84f6c1c11e1cec7f 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -1,5 +1,6 @@ import { times } from 'lodash' -import { rgb2hex, hex2rgb } from '../color_convert/color_convert.js' +import { brightness, invertLightness, convert } from 'chromatism' +import { rgb2hex, hex2rgb, mixrgb } from '../color_convert/color_convert.js' // While this is not used anymore right now, I left it in if we want to do custom // styles that aren't just colors, so user can pick from a few different distinct @@ -53,7 +54,23 @@ const setStyle = (href, commit) => { cssEl.addEventListener('load', setDynamic) } -const setColors = (col, commit) => { +const rgb2rgba = function (rgba) { + return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})` +} + +const getTextColor = function (bg, text) { + const bgIsLight = convert(bg).hsl.l > 50 + const textIsLight = convert(text).hsl.l > 50 + + if ((bgIsLight && textIsLight) || (!bgIsLight && !textIsLight)) { + const base = typeof text.a !== 'undefined' ? { a: text.a } : {} + return Object.assign(base, invertLightness(text).rgb) + } + return text +} + +const setColors = (input, commit) => { + const { colorRules, radiiRules, col } = generatePreset(input) const head = document.head const body = document.body body.style.display = 'none' @@ -62,51 +79,83 @@ const setColors = (col, commit) => { head.appendChild(styleEl) const styleSheet = styleEl.sheet - const isDark = (col.text.r + col.text.g + col.text.b) > (col.bg.r + col.bg.g + col.bg.b) - let colors = {} - let radii = {} - - const mod = isDark ? -10 : 10 - - colors.bg = rgb2hex(col.bg.r, col.bg.g, col.bg.b) // background - colors.lightBg = rgb2hex((col.bg.r + col.fg.r) / 2, (col.bg.g + col.fg.g) / 2, (col.bg.b + col.fg.b) / 2) // hilighted bg - colors.btn = rgb2hex(col.fg.r, col.fg.g, col.fg.b) // panels & buttons - colors.input = `rgba(${col.fg.r}, ${col.fg.g}, ${col.fg.b}, .5)` - colors.border = rgb2hex(col.fg.r - mod, col.fg.g - mod, col.fg.b - mod) // borders - colors.faint = `rgba(${col.text.r}, ${col.text.g}, ${col.text.b}, .5)` - colors.fg = rgb2hex(col.text.r, col.text.g, col.text.b) // text - colors.lightFg = rgb2hex(col.text.r - mod * 5, col.text.g - mod * 5, col.text.b - mod * 5) // strong text - - colors['base07'] = rgb2hex(col.text.r - mod * 2, col.text.g - mod * 2, col.text.b - mod * 2) - - colors.link = rgb2hex(col.link.r, col.link.g, col.link.b) // links - colors.icon = rgb2hex((col.bg.r + col.text.r) / 2, (col.bg.g + col.text.g) / 2, (col.bg.b + col.text.b) / 2) // icons - - colors.cBlue = col.cBlue && rgb2hex(col.cBlue.r, col.cBlue.g, col.cBlue.b) - colors.cRed = col.cRed && rgb2hex(col.cRed.r, col.cRed.g, col.cRed.b) - colors.cGreen = col.cGreen && rgb2hex(col.cGreen.r, col.cGreen.g, col.cGreen.b) - colors.cOrange = col.cOrange && rgb2hex(col.cOrange.r, col.cOrange.g, col.cOrange.b) - - colors.cAlertRed = col.cRed && `rgba(${col.cRed.r}, ${col.cRed.g}, ${col.cRed.b}, .5)` - - radii.btnRadius = col.btnRadius - radii.inputRadius = col.inputRadius - radii.panelRadius = col.panelRadius - radii.avatarRadius = col.avatarRadius - radii.avatarAltRadius = col.avatarAltRadius - radii.tooltipRadius = col.tooltipRadius - radii.attachmentRadius = col.attachmentRadius - styleSheet.toString() - styleSheet.insertRule(`body { ${Object.entries(colors).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}`).join(';')} }`, 'index-max') - styleSheet.insertRule(`body { ${Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}px`).join(';')} }`, 'index-max') + styleSheet.insertRule(`body { ${colorRules} }`, 'index-max') + styleSheet.insertRule(`body { ${radiiRules} }`, 'index-max') body.style.display = 'initial' - commit('setOption', { name: 'colors', value: colors }) - commit('setOption', { name: 'radii', value: radii }) + // commit('setOption', { name: 'colors', value: htmlColors }) + // commit('setOption', { name: 'radii', value: radii }) commit('setOption', { name: 'customTheme', value: col }) } +const generatePreset = (input) => { + const radii = input.radii || { + btnRadius: input.btnRadius, + inputRadius: input.inputRadius, + panelRadius: input.panelRadius, + avatarRadius: input.avatarRadius, + avatarAltRadius: input.avatarAltRadius, + tooltipRadius: input.tooltipRadius, + attachmentRadius: input.attachmentRadius + } + const colors = {} + + const col = Object.entries(input.colors || input).reduce((acc, [k, v]) => { + if (typeof v === 'object') { + acc[k] = v + } else { + acc[k] = hex2rgb(v) + } + return acc + }, {}) + + colors.fg = col.fg || col.text // text + colors.text = col.fg || col.text // text + colors.lightFg = col.fg || col.text // text + + colors.bg = col.bg // background + colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb // hilighted bg + console.log(colors.bg) + console.log(colors.lightBg) + + colors.btn = col.btn || { r: 0, g: 0, b: 0 } + colors.btnText = getTextColor(colors.btn, colors.text) + + colors.panel = col.panel || col.btn + colors.panelText = getTextColor(colors.panel, colors.text) + + colors.topBar = col.topBar || col.btn + colors.topBarText = getTextColor(colors.topBar, colors.text) + + colors.input = col.input || Object.assign({ a: 0.5 }, col.btn) + colors.border = col.btn // borders + colors.faint = col.faint || Object.assign({ a: 0.5 }, col.text) + + colors.link = col.link // links + colors.icon = mixrgb(colors.bg, colors.text) // icons + + colors.cBlue = col.cBlue + colors.cRed = col.cRed + colors.cGreen = col.cGreen + colors.cOrange = col.cOrange + + colors.cAlertRed = col.cAlertRed || Object.assign({ a: 0.5 }, col.cRed) + + const htmlColors = Object.entries(colors) + .reduce((acc, [k, v]) => { + if (!v) return acc + acc[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgb2rgba(v) + return acc + }, {}) + + return { + colorRules: Object.entries(htmlColors).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}`).join(';'), + radiiRules: Object.entries(radii).filter(([k, v]) => v).map(([k, v]) => `--${k}: ${v}px`).join(';'), + col + } +} + const setPreset = (val, commit) => { window.fetch('/static/styles.json') .then((data) => data.json()) @@ -148,7 +197,8 @@ const setPreset = (val, commit) => { const StyleSetter = { setStyle, setPreset, - setColors + setColors, + generatePreset } export default StyleSetter diff --git a/yarn.lock b/yarn.lock index fdad8b498f0d99ea01e38d51b5497988cee99d74..0139c714c258d7258456fdbd835c91e06190616e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1205,6 +1205,10 @@ chokidar@^1.0.0, chokidar@^1.4.1: optionalDependencies: fsevents "^1.0.0" +chromatism@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/chromatism/-/chromatism-3.0.0.tgz#a7249d353c1e4f3577e444ac41171c4e2e624b12" + chromedriver@^2.21.2: version "2.35.0" resolved "https://registry.yarnpkg.com/chromedriver/-/chromedriver-2.35.0.tgz#c103ba2fb3d1671f666058159f5cbaa816902e4d"