shit more or less works for the very basic stuff

This commit is contained in:
Henry Jameson 2024-01-23 19:18:55 +02:00
parent 0729b529d7
commit 22b32f149d
9 changed files with 132 additions and 22 deletions

View File

@ -2,10 +2,10 @@ export default {
name: 'Button', name: 'Button',
selector: '.btn', selector: '.btn',
states: { states: {
hover: ':hover',
disabled: ':disabled', disabled: ':disabled',
toggled: '.toggled',
pressed: ':active', pressed: ':active',
toggled: '.toggled' hover: ':hover'
}, },
variants: { variants: {
danger: '.danger', danger: '.danger',

View File

@ -4,6 +4,7 @@ export default {
validInnerComponents: [ validInnerComponents: [
'Text', 'Text',
'Icon', 'Icon',
'Button' 'Button',
'PanelHeader'
] ]
} }

View File

@ -0,0 +1,9 @@
export default {
name: 'PanelHeader',
selector: '.panel-heading',
validInnerComponents: [
'Text',
'Icon',
'Button'
]
}

View File

@ -1,6 +1,6 @@
export default { export default {
name: 'Text', name: 'Text',
selector: '', selector: '/*text*/',
states: { states: {
faint: '.faint' faint: '.faint'
} }

View File

@ -1,6 +1,6 @@
export default { export default {
name: 'Underlay', name: 'Underlay',
selector: '.underlay', selector: '#app',
validInnerComponents: [ validInnerComponents: [
'Panel' 'Panel'
] ]

View File

@ -188,6 +188,7 @@ export const rgba2css = function (rgba) {
*/ */
export const getTextColor = function (bg, text, preserve) { export const getTextColor = function (bg, text, preserve) {
const contrast = getContrastRatio(bg, text) const contrast = getContrastRatio(bg, text)
console.log(contrast)
if (contrast < 4.5) { if (contrast < 4.5) {
const base = typeof text.a !== 'undefined' ? { a: text.a } : {} const base = typeof text.a !== 'undefined' ? { a: text.a } : {}

View File

@ -4,7 +4,7 @@ export const sampleRules = [
// variant: 'normal', // variant: 'normal',
// state: 'normal' // state: 'normal'
directives: { directives: {
background: '#000', background: '#000000',
opacity: 0.2 opacity: 0.2
} }
}, },
@ -15,11 +15,17 @@ export const sampleRules = [
opacity: 0.9 opacity: 0.9
} }
}, },
{
component: 'PanelHeader',
directives: {
background: '#000000',
opacity: 0.9
}
},
{ {
component: 'Button', component: 'Button',
directives: { directives: {
background: '#808080', background: '#808080',
text: '#FFFFFF',
opacity: 0.5 opacity: 0.5
} }
} }

View File

@ -1,5 +1,9 @@
import { convert } from 'chromatism'
import { alphaBlend, getTextColor, rgba2css } from '../color_convert/color_convert.js'
import Underlay from 'src/components/underlay.style.js' import Underlay from 'src/components/underlay.style.js'
import Panel from 'src/components/panel.style.js' import Panel from 'src/components/panel.style.js'
import PanelHeader from 'src/components/panel_header.style.js'
import Button from 'src/components/button.style.js' import Button from 'src/components/button.style.js'
import Text from 'src/components/text.style.js' import Text from 'src/components/text.style.js'
import Icon from 'src/components/icon.style.js' import Icon from 'src/components/icon.style.js'
@ -8,6 +12,7 @@ const root = Underlay
const components = { const components = {
Underlay, Underlay,
Panel, Panel,
PanelHeader,
Button, Button,
Text, Text,
Icon Icon
@ -34,7 +39,7 @@ export const ruleToSelector = (rule) => {
const component = components[rule.component] const component = components[rule.component]
const { states, variants, selector } = component const { states, variants, selector } = component
const applicableStates = (rule.state.filter(x => x !== 'normal') || []).map(state => states[state]) const applicableStates = ((rule.state || []).filter(x => x !== 'normal')).map(state => states[state])
const applicableVariantName = (rule.variant || 'normal') const applicableVariantName = (rule.variant || 'normal')
let applicableVariant = '' let applicableVariant = ''
@ -63,12 +68,37 @@ export const init = (ruleset) => {
const addRule = (rule) => { const addRule = (rule) => {
rules.push(rule) rules.push(rule)
rulesByComponent[rule.component] = rulesByComponent[rule.component] || [] rulesByComponent[rule.component] = rulesByComponent[rule.component] || []
rulesByComponent.push(rule) rulesByComponent[rule.component].push(rule)
} }
ruleset.forEach(rule => { const findRules = (combination) => rule => {
if (combination.component !== rule.component) return false
if (Object.prototype.hasOwnProperty.call(rule, 'variant')) {
if (combination.variant !== rule.variant) return false
} else {
if (combination.variant !== 'normal') return false
}
}) if (Object.prototype.hasOwnProperty.call(rule, 'state')) {
const ruleStatesSet = new Set(['normal', ...(rule.state || [])])
return combination.state.every(state => ruleStatesSet.has(state))
} else {
if (combination.state.length !== 1 || combination.state[0] !== 'normal') return false
return true
}
}
const findLowerLevelRule = (parent, filter = () => true) => {
let lowerLevelComponent = null
let currentParent = parent
while (currentParent) {
const rulesParent = ruleset.filter(findRules(currentParent, true))
lowerLevelComponent = rulesParent[rulesParent.length - 1]
currentParent = currentParent.parent
if (lowerLevelComponent && filter(lowerLevelComponent)) currentParent = null
}
return filter(lowerLevelComponent) ? lowerLevelComponent : null
}
const processInnerComponent = (component, parent) => { const processInnerComponent = (component, parent) => {
const { const {
@ -87,18 +117,82 @@ export const init = (ruleset) => {
return stateCombinations.map(state => ({ variant, state })) return stateCombinations.map(state => ({ variant, state }))
}).reduce((acc, x) => [...acc, ...x], []) }).reduce((acc, x) => [...acc, ...x], [])
const VIRTUAL_COMPONENTS = new Set(['Text', 'Link', 'Icon'])
stateVariantCombination.forEach(combination => { stateVariantCombination.forEach(combination => {
// addRule(({ const existingRules = ruleset.filter(findRules({ component: component.name, ...combination }))
// parent, const lastRule = existingRules[existingRules.length - 1]
// component: component.name,
// state: combination.state, if (existingRules.length !== 0) {
// variant: combination.variant const { directives } = lastRule
// })) const rgb = convert(directives.background).rgb
// TODO: DEFAULT TEXT COLOR
const bg = findLowerLevelRule(parent)?.cache.background || convert('#FFFFFF').rgb
if (!lastRule.cache?.background) {
const blend = directives.opacity < 1 ? alphaBlend(rgb, directives.opacity, bg) : rgb
lastRule.cache = lastRule.cache || {}
lastRule.cache.background = blend
addRule(lastRule)
}
} else {
if (VIRTUAL_COMPONENTS.has(component.name)) {
const selector = component.name + ruleToSelector({ component: component.name, ...combination })
const lowerLevel = findLowerLevelRule(parent, (r) => {
if (components[r.component].validInnerComponents.indexOf(component.name) < 0) return false
if (r.cache?.background === undefined) return false
if (r.cache.textDefined) {
return !r.cache.textDefined[selector]
}
return true
})
if (!lowerLevel) return
lowerLevel.cache.textDefined = lowerLevel.cache.textDefined || {}
lowerLevel.cache.textDefined[selector] = true
addRule({
parent,
component: component.name,
...combination,
directives: {
// TODO: DEFAULT TEXT COLOR
textColor: getTextColor(convert(lowerLevel.cache.background).rgb, convert('#FFFFFF').rgb, component.name === 'Link'),
// Debug: lets you see what it think background color should be
background: convert(lowerLevel.cache.background).hex
}
})
}
}
innerComponents.forEach(innerComponent => processInnerComponent(innerComponent, { parent, component: name, ...combination })) innerComponents.forEach(innerComponent => processInnerComponent(innerComponent, { parent, component: name, ...combination }))
}) })
} }
processInnerComponent(components[rootName]) processInnerComponent(components[rootName])
return rules
// console.info(rules.map(x => [
// (parent?.component || 'root') + ' -> ' + x.component,
// // 'Cached background:' + convert(bg).hex,
// // 'Color: ' + convert(x.directives.background).hex + ' A:' + x.directives.opacity,
// JSON.stringify(x.directives)
// // '=> Blend: ' + convert(x.cache.background).hex
// ].join(' ')))
return {
raw: rules,
css: rules.map(rule => {
const header = ruleToSelector(rule) + ' {'
const footer = '}'
const directives = Object.entries(rule.directives).map(([k, v]) => {
switch (k) {
case 'background': return 'background-color: ' + rgba2css({ ...convert(v).rgb, a: rule.directives.opacity ?? 1 })
case 'textColor': return 'color: ' + rgba2css({ ...convert(v).rgb, a: rule.directives.opacity ?? 1 })
default: return ''
}
}).filter(x => x).map(x => ' ' + x).join(';\n')
return [header, directives, footer].join('\n')
})
}
} }

View File

@ -1,8 +1,7 @@
// import { topoSort } from 'src/services/theme_data/theme_data.service.js' // import { topoSort } from 'src/services/theme_data/theme_data.service.js'
import { import {
getAllPossibleCombinations, getAllPossibleCombinations,
init, init
ruleToSelector
} from 'src/services/theme_data/theme_data_3.service.js' } from 'src/services/theme_data/theme_data_3.service.js'
import { import {
sampleRules sampleRules
@ -19,8 +18,8 @@ describe.only('Theme Data 3', () => {
describe('init', () => { describe('init', () => {
it('test simple case', () => { it('test simple case', () => {
const out = init(sampleRules) const out = init(sampleRules)
console.log(JSON.stringify(out, null, 2)) // console.log(JSON.stringify(out, null, 2))
out.forEach(r => console.log(ruleToSelector(r))) console.log('\n' + out.css.join('\n') + '\n')
}) })
}) })
}) })