Refactoring, forgotten files
This commit is contained in:
parent
38f2b969e4
commit
622c9d388e
5 changed files with 577 additions and 421 deletions
|
@ -1,275 +1,13 @@
|
|||
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
|
||||
/* This is a definition of all layer combinations
|
||||
* each key is a topmost layer, each value represents layer underneath
|
||||
* this is essentially a simplified tree
|
||||
*/
|
||||
export const LAYERS = {
|
||||
undelay: null, // root
|
||||
topBar: null, // no transparency support
|
||||
badge: null, // no transparency support
|
||||
fg: null,
|
||||
bg: 'underlay',
|
||||
panel: 'bg',
|
||||
btn: 'bg',
|
||||
btnPanel: 'panel',
|
||||
btnTopBar: 'topBar',
|
||||
input: 'bg',
|
||||
inputPanel: 'panel',
|
||||
inputTopBar: 'topBar',
|
||||
alert: 'bg',
|
||||
alertPanel: 'panel'
|
||||
}
|
||||
|
||||
export const SLOT_INHERITANCE = {
|
||||
bg: null,
|
||||
fg: null,
|
||||
text: null,
|
||||
underlay: '#000000',
|
||||
link: '--accent',
|
||||
accent: '--link',
|
||||
faint: '--text',
|
||||
faintLink: '--link',
|
||||
|
||||
cBlue: '#0000ff',
|
||||
cRed: '#FF0000',
|
||||
cGreen: '#00FF00',
|
||||
cOrange: '#E3FF00',
|
||||
|
||||
lightBg: {
|
||||
depends: ['bg'],
|
||||
color: (mod, bg) => brightness(5 * mod, bg).rgb
|
||||
},
|
||||
lightText: {
|
||||
depends: ['text'],
|
||||
color: (mod, text) => brightness(20 * mod, text).rgb
|
||||
},
|
||||
|
||||
border: {
|
||||
depends: 'fg',
|
||||
color: (mod, fg) => brightness(2 * mod, fg).rgb
|
||||
},
|
||||
|
||||
linkBg: {
|
||||
depends: ['accent', 'bg'],
|
||||
color: (mod, accent, bg) => alphaBlend(accent, 0.4, bg).rgb
|
||||
},
|
||||
|
||||
icon: {
|
||||
depends: ['bg', 'text'],
|
||||
color: (mod, bg, text) => mixrgb(bg, text)
|
||||
},
|
||||
|
||||
// Foreground
|
||||
fgText: {
|
||||
depends: ['text'],
|
||||
layer: 'fg',
|
||||
textColor: true
|
||||
},
|
||||
fgLink: {
|
||||
depends: ['link'],
|
||||
layer: 'fg',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
|
||||
// Panel header
|
||||
panel: '--fg',
|
||||
panelText: {
|
||||
depends: ['fgText'],
|
||||
layer: 'panel',
|
||||
textColor: true
|
||||
},
|
||||
panelFaint: {
|
||||
depends: ['fgText'],
|
||||
layer: 'panel',
|
||||
textColor: true
|
||||
},
|
||||
panelLink: {
|
||||
depends: ['fgLink'],
|
||||
layer: 'panel',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
|
||||
// Top bar
|
||||
topBar: '--fg',
|
||||
topBarText: {
|
||||
depends: ['fgText'],
|
||||
layer: 'topBar',
|
||||
textColor: true
|
||||
},
|
||||
topBarLink: {
|
||||
depends: ['fgLink'],
|
||||
layer: 'topBar',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
|
||||
// Buttons
|
||||
btn: '--fg',
|
||||
btnText: {
|
||||
depends: ['fgText'],
|
||||
layer: 'btn'
|
||||
},
|
||||
btnPanelText: {
|
||||
depends: ['panelText'],
|
||||
layer: 'btnPanel',
|
||||
variant: 'btn',
|
||||
textColor: true
|
||||
},
|
||||
btnTopBarText: {
|
||||
depends: ['topBarText'],
|
||||
layer: 'btnTopBar',
|
||||
variant: 'btn',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
// Input fields
|
||||
input: '--fg',
|
||||
inputText: {
|
||||
depends: ['text'],
|
||||
layer: 'input',
|
||||
textColor: true
|
||||
},
|
||||
inputPanelText: {
|
||||
depends: ['panelText'],
|
||||
layer: 'inputPanel',
|
||||
variant: 'input',
|
||||
textColor: true
|
||||
},
|
||||
inputTopbarText: {
|
||||
depends: ['topBarText'],
|
||||
layer: 'inputTopBar',
|
||||
variant: 'input',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
alertError: '--cRed',
|
||||
alertErrorText: {
|
||||
depends: ['text', 'alertError'],
|
||||
layer: 'alert',
|
||||
variant: 'alertError',
|
||||
textColor: true
|
||||
},
|
||||
alertErrorPanelText: {
|
||||
depends: ['panelText', 'alertError'],
|
||||
layer: 'alertPanel',
|
||||
variant: 'alertError',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
alertWarning: '--cOrange',
|
||||
alertWarningText: {
|
||||
depends: ['text', 'alertWarning'],
|
||||
layer: 'alert',
|
||||
variant: 'alertWarning',
|
||||
textColor: true
|
||||
},
|
||||
alertWarningPanelText: {
|
||||
depends: ['panelText', 'alertWarning'],
|
||||
layer: 'alertPanel',
|
||||
variant: 'alertWarning',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
badgeNotification: '--cRed',
|
||||
badgeNotificationText: {
|
||||
depends: ['text', 'badgeNotification'],
|
||||
layer: 'badge',
|
||||
variant: 'badgeNotification',
|
||||
textColor: 'bw'
|
||||
}
|
||||
}
|
||||
|
||||
export const getLayersArray = (layer, data = LAYERS) => {
|
||||
let array = [layer]
|
||||
let parent = data[layer]
|
||||
while (parent) {
|
||||
array.unshift(parent)
|
||||
parent = data[parent]
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
export const getLayers = (layer, variant = layer, colors, opacity) => {
|
||||
return getLayersArray(layer).map((currentLayer) => ([
|
||||
currentLayer === layer
|
||||
? colors[variant]
|
||||
: colors[currentLayer],
|
||||
opacity[currentLayer]
|
||||
]))
|
||||
}
|
||||
|
||||
const getDependencies = (key, inheritance) => {
|
||||
const data = inheritance[key]
|
||||
if (typeof data === 'string' && data.startsWith('--')) {
|
||||
return [data.substring(2)]
|
||||
} else {
|
||||
if (data === null) return []
|
||||
const { depends, layer, variant } = data
|
||||
const layerDeps = layer
|
||||
? getLayersArray(layer).map(currentLayer => {
|
||||
return currentLayer === layer
|
||||
? variant || layer
|
||||
: currentLayer
|
||||
})
|
||||
: []
|
||||
if (Array.isArray(depends)) {
|
||||
return [...depends, ...layerDeps]
|
||||
} else {
|
||||
return [...layerDeps]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const topoSort = (
|
||||
inheritance = SLOT_INHERITANCE,
|
||||
getDeps = getDependencies
|
||||
) => {
|
||||
// This is an implementation of https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
|
||||
|
||||
const allKeys = Object.keys(inheritance)
|
||||
const whites = new Set(allKeys)
|
||||
const grays = new Set()
|
||||
const blacks = new Set()
|
||||
const unprocessed = [...allKeys]
|
||||
const output = []
|
||||
|
||||
const step = (node) => {
|
||||
if (whites.has(node)) {
|
||||
// Make node "gray"
|
||||
whites.delete(node)
|
||||
grays.add(node)
|
||||
// Do step for each node connected to it (one way)
|
||||
getDeps(node, inheritance).forEach(step)
|
||||
// Make node "black"
|
||||
grays.delete(node)
|
||||
blacks.add(node)
|
||||
// Put it into the output list
|
||||
output.push(node)
|
||||
} else if (grays.has(node)) {
|
||||
console.debug('Cyclic depenency in topoSort, ignoring')
|
||||
output.push(node)
|
||||
} else if (blacks.has(node)) {
|
||||
// do nothing
|
||||
} else {
|
||||
throw new Error('Unintended condition in topoSort!')
|
||||
}
|
||||
}
|
||||
while (unprocessed.length > 0) {
|
||||
step(unprocessed.pop())
|
||||
}
|
||||
return output
|
||||
}
|
||||
|
||||
export const SLOT_ORDERED = topoSort(SLOT_INHERITANCE)
|
||||
import { convert } from 'chromatism'
|
||||
import { rgb2hex, hex2rgb, rgba2css, getCssColor } from '../color_convert/color_convert.js'
|
||||
import { getColors } from '../theme_data/theme_data.service.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
|
||||
// styles as well as set their own colors in the future.
|
||||
|
||||
const setStyle = (href, commit) => {
|
||||
export const setStyle = (href, commit) => {
|
||||
/***
|
||||
What's going on here?
|
||||
I want to make it easy for admins to style this application. To have
|
||||
|
@ -315,30 +53,7 @@ const setStyle = (href, commit) => {
|
|||
cssEl.addEventListener('load', setDynamic)
|
||||
}
|
||||
|
||||
const rgb2rgba = function (rgba) {
|
||||
return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`
|
||||
}
|
||||
|
||||
const getTextColor = function (bg, text, preserve) {
|
||||
const bgIsLight = convert(bg).hsl.l > 50
|
||||
const textIsLight = convert(text).hsl.l > 50
|
||||
|
||||
console.log(bgIsLight, textIsLight)
|
||||
|
||||
if ((bgIsLight && textIsLight) || (!bgIsLight && !textIsLight)) {
|
||||
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
|
||||
}
|
||||
|
||||
const applyTheme = (input, commit) => {
|
||||
export const applyTheme = (input, commit) => {
|
||||
const { rules, theme } = generatePreset(input)
|
||||
const head = document.head
|
||||
const body = document.body
|
||||
|
@ -399,22 +114,6 @@ const getCssShadowFilter = (input) => {
|
|||
.join(' ')
|
||||
}
|
||||
|
||||
const getCssColor = (input, a) => {
|
||||
let rgb = {}
|
||||
if (typeof input === 'object') {
|
||||
rgb = input
|
||||
} else if (typeof input === 'string') {
|
||||
if (input.startsWith('#')) {
|
||||
rgb = hex2rgb(input)
|
||||
} else if (input.startsWith('--')) {
|
||||
return `var(${input})`
|
||||
} else {
|
||||
return input
|
||||
}
|
||||
}
|
||||
return rgb2rgba({ ...rgb, a })
|
||||
}
|
||||
|
||||
const generateColors = (themeData) => {
|
||||
const rawOpacity = Object.assign({
|
||||
panel: 1,
|
||||
|
@ -435,14 +134,16 @@ const generateColors = (themeData) => {
|
|||
}, {}))
|
||||
|
||||
const inputColors = themeData.colors || themeData
|
||||
const transparentsOpacity = Object.entries(inputColors).reduce((acc, [k, v]) => {
|
||||
if (v === 'transparent') {
|
||||
acc[k] = 0
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const opacity = { ...rawOpacity, ...transparentsOpacity }
|
||||
const opacity = {
|
||||
...rawOpacity,
|
||||
...Object.entries(inputColors).reduce((acc, [k, v]) => {
|
||||
if (v === 'transparent') {
|
||||
acc[k] = 0
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
// Cycle one: just whatever we have
|
||||
const sourceColors = Object.entries(inputColors).reduce((acc, [k, v]) => {
|
||||
|
@ -462,55 +163,7 @@ const generateColors = (themeData) => {
|
|||
const isLightOnDark = convert(sourceColors.bg).hsl.l < convert(sourceColors.text).hsl.l
|
||||
const mod = isLightOnDark ? 1 : -1
|
||||
|
||||
const colors = SLOT_ORDERED.reduce((acc, key) => {
|
||||
const value = SLOT_INHERITANCE[key]
|
||||
if (sourceColors[key]) {
|
||||
return { ...acc, [key]: { ...sourceColors[key] } }
|
||||
} else if (typeof value === 'string' && value.startsWith('#')) {
|
||||
return { ...acc, [key]: convert(value).rgb }
|
||||
} else {
|
||||
const isObject = typeof value === 'object'
|
||||
const defaultColorFunc = (mod, dep) => ({ ...dep })
|
||||
const deps = getDependencies(key, SLOT_INHERITANCE)
|
||||
const colorFunc = (isObject && value.color) || defaultColorFunc
|
||||
|
||||
if (value.textColor) {
|
||||
const bg = alphaBlendLayers(
|
||||
{ ...acc[deps[0]] },
|
||||
getLayers(
|
||||
value.layer,
|
||||
value.variant || value.layer,
|
||||
acc,
|
||||
opacity
|
||||
)
|
||||
)
|
||||
if (value.textColor === 'bw') {
|
||||
return {
|
||||
...acc,
|
||||
[key]: contrastRatio(bg)
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
...acc,
|
||||
[key]: getTextColor(
|
||||
bg,
|
||||
{ ...acc[deps[0]] },
|
||||
value.textColor === 'preserve'
|
||||
)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
console.log('BENIS', key, deps, deps.map((dep) => ({ ...acc[dep] })))
|
||||
return {
|
||||
...acc,
|
||||
[key]: colorFunc(
|
||||
mod,
|
||||
...deps.map((dep) => ({ ...acc[dep] }))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {})
|
||||
const colors = getColors(sourceColors, opacity, mod)
|
||||
|
||||
// Inheriting opacities
|
||||
Object.entries(opacity).forEach(([ k, v ]) => {
|
||||
|
@ -541,7 +194,7 @@ const generateColors = (themeData) => {
|
|||
.reduce((acc, [k, v]) => {
|
||||
if (!v) return acc
|
||||
acc.solid[k] = rgb2hex(v)
|
||||
acc.complete[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgb2rgba(v)
|
||||
acc.complete[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgba2css(v)
|
||||
return acc
|
||||
}, { complete: {}, solid: {} })
|
||||
return {
|
||||
|
@ -740,14 +393,12 @@ const composePreset = (colors, radii, shadows, fonts) => {
|
|||
}
|
||||
}
|
||||
|
||||
const generatePreset = (input) => {
|
||||
const shadows = generateShadows(input)
|
||||
const colors = generateColors(input)
|
||||
const radii = generateRadii(input)
|
||||
const fonts = generateFonts(input)
|
||||
|
||||
return composePreset(colors, radii, shadows, fonts)
|
||||
}
|
||||
const generatePreset = (input) => composePreset(
|
||||
generateColors(input),
|
||||
generateRadii(input),
|
||||
generateShadows(input),
|
||||
generateFonts(input)
|
||||
)
|
||||
|
||||
const getThemes = () => {
|
||||
return window.fetch('/static/styles.json')
|
||||
|
@ -779,33 +430,24 @@ const getThemes = () => {
|
|||
})
|
||||
}
|
||||
|
||||
const setPreset = (val, commit) => {
|
||||
export const setPreset = (val, commit) => {
|
||||
return getThemes().then((themes) => {
|
||||
const theme = themes[val] ? themes[val] : themes['pleroma-dark']
|
||||
const isV1 = Array.isArray(theme)
|
||||
const data = isV1 ? {} : theme.theme
|
||||
|
||||
if (isV1) {
|
||||
const bgRgb = hex2rgb(theme[1])
|
||||
const fgRgb = hex2rgb(theme[2])
|
||||
const textRgb = hex2rgb(theme[3])
|
||||
const linkRgb = hex2rgb(theme[4])
|
||||
const bg = hex2rgb(theme[1])
|
||||
const fg = hex2rgb(theme[2])
|
||||
const text = hex2rgb(theme[3])
|
||||
const link = hex2rgb(theme[4])
|
||||
|
||||
const cRedRgb = hex2rgb(theme[5] || '#FF0000')
|
||||
const cGreenRgb = hex2rgb(theme[6] || '#00FF00')
|
||||
const cBlueRgb = hex2rgb(theme[7] || '#0000FF')
|
||||
const cOrangeRgb = hex2rgb(theme[8] || '#E3FF00')
|
||||
const cRed = hex2rgb(theme[5] || '#FF0000')
|
||||
const cGreen = hex2rgb(theme[6] || '#00FF00')
|
||||
const cBlue = hex2rgb(theme[7] || '#0000FF')
|
||||
const cOrange = hex2rgb(theme[8] || '#E3FF00')
|
||||
|
||||
data.colors = {
|
||||
bg: bgRgb,
|
||||
fg: fgRgb,
|
||||
text: textRgb,
|
||||
link: linkRgb,
|
||||
cRed: cRedRgb,
|
||||
cBlue: cBlueRgb,
|
||||
cGreen: cGreenRgb,
|
||||
cOrange: cOrangeRgb
|
||||
}
|
||||
data.colors = { bg, fg, text, link, cRed, cBlue, cGreen, cOrange }
|
||||
}
|
||||
|
||||
// This is a hack, this function is only called during initial load.
|
||||
|
@ -819,19 +461,3 @@ const setPreset = (val, commit) => {
|
|||
}
|
||||
})
|
||||
}
|
||||
|
||||
export {
|
||||
setStyle,
|
||||
setPreset,
|
||||
applyTheme,
|
||||
getTextColor,
|
||||
generateColors,
|
||||
generateRadii,
|
||||
generateShadows,
|
||||
generateFonts,
|
||||
generatePreset,
|
||||
getThemes,
|
||||
composePreset,
|
||||
getCssShadow,
|
||||
getCssShadowFilter
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue