Merge branch 'themes3' into shigusegubu-themes3
This commit is contained in:
commit
08444fdd6c
12 changed files with 291 additions and 300 deletions
23
src/App.scss
23
src/App.scss
|
@ -376,6 +376,7 @@ nav {
|
||||||
position: relative;
|
position: relative;
|
||||||
border-bottom: 1px solid;
|
border-bottom: 1px solid;
|
||||||
border-color: var(--border);
|
border-color: var(--border);
|
||||||
|
width: 100%;
|
||||||
|
|
||||||
&:first-child {
|
&:first-child {
|
||||||
border-top-right-radius: var(--roundness);
|
border-top-right-radius: var(--roundness);
|
||||||
|
@ -620,22 +621,38 @@ option {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
text-overflow: ellipsis;
|
text-overflow: ellipsis;
|
||||||
|
|
||||||
|
&.-dot,
|
||||||
|
&.-counter {
|
||||||
|
margin: 0;
|
||||||
|
position: absolute;
|
||||||
|
}
|
||||||
|
|
||||||
&.-dot {
|
&.-dot {
|
||||||
border-radius: 100%;
|
|
||||||
min-height: 8px;
|
min-height: 8px;
|
||||||
max-height: 8px;
|
max-height: 8px;
|
||||||
min-width: 8px;
|
min-width: 8px;
|
||||||
max-width: 8px;
|
max-width: 8px;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
line-height: 0;
|
line-height: 0;
|
||||||
margin: 0;
|
|
||||||
font-size: 0;
|
font-size: 0;
|
||||||
position: absolute;
|
|
||||||
left: calc(50% - 4px);
|
left: calc(50% - 4px);
|
||||||
top: calc(50% - 4px);
|
top: calc(50% - 4px);
|
||||||
margin-left: 6px;
|
margin-left: 6px;
|
||||||
margin-top: -6px;
|
margin-top: -6px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.-counter {
|
||||||
|
border-radius: var(--roundness);
|
||||||
|
font-size: 0.75em;
|
||||||
|
line-height: 1;
|
||||||
|
text-align: right;
|
||||||
|
padding: 0.2em;
|
||||||
|
min-width: 0;
|
||||||
|
left: calc(50% - 0.5em);
|
||||||
|
top: calc(50% - 0.4em);
|
||||||
|
margin-left: 0.7em;
|
||||||
|
margin-top: -1em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.alert {
|
.alert {
|
||||||
|
|
|
@ -328,17 +328,14 @@ const setConfig = async ({ store }) => {
|
||||||
}
|
}
|
||||||
|
|
||||||
const checkOAuthToken = async ({ store }) => {
|
const checkOAuthToken = async ({ store }) => {
|
||||||
// eslint-disable-next-line no-async-promise-executor
|
if (store.getters.getUserToken()) {
|
||||||
return new Promise(async (resolve, reject) => {
|
try {
|
||||||
if (store.getters.getUserToken()) {
|
await store.dispatch('loginUser', store.getters.getUserToken())
|
||||||
try {
|
} catch (e) {
|
||||||
await store.dispatch('loginUser', store.getters.getUserToken())
|
console.error(e)
|
||||||
} catch (e) {
|
|
||||||
console.error(e)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
resolve()
|
}
|
||||||
})
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
const afterStoreSetup = async ({ store, i18n }) => {
|
const afterStoreSetup = async ({ store, i18n }) => {
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
@import "../../variables";
|
|
||||||
|
|
||||||
// TODO Copypaste from Status, should unify it somehow
|
// TODO Copypaste from Status, should unify it somehow
|
||||||
.Notification {
|
.Notification {
|
||||||
border-bottom: 1px solid;
|
border-bottom: 1px solid;
|
||||||
|
@ -70,28 +68,22 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-type--repeat .type-icon {
|
&.-type--repeat .type-icon {
|
||||||
color: $fallback--cGreen;
|
color: var(--cGreen);
|
||||||
color: var(--cGreen, $fallback--cGreen);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-type--follow .type-icon {
|
&.-type--follow .type-icon {
|
||||||
color: $fallback--cBlue;
|
color: var(--cBlue);
|
||||||
color: var(--cBlue, $fallback--cBlue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-type--follow-request .type-icon {
|
&.-type--follow-request .type-icon {
|
||||||
color: $fallback--cBlue;
|
color: var(--cBlue);
|
||||||
color: var(--cBlue, $fallback--cBlue);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-type--like .type-icon {
|
&.-type--like .type-icon {
|
||||||
color: orange;
|
color: var(--cOrange);
|
||||||
color: $fallback--cOrange;
|
|
||||||
color: var(--cOrange, $fallback--cOrange);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
&.-type--move .type-icon {
|
&.-type--move .type-icon {
|
||||||
color: $fallback--cBlue;
|
color: var(--cBlue);
|
||||||
color: var(--cBlue, $fallback--cBlue);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -247,7 +247,6 @@
|
||||||
/>
|
/>
|
||||||
<template v-else>
|
<template v-else>
|
||||||
<StatusContent
|
<StatusContent
|
||||||
:class="{ faint: !statusExpanded }"
|
|
||||||
:compact="!statusExpanded"
|
:compact="!statusExpanded"
|
||||||
:status="notification.status"
|
:status="notification.status"
|
||||||
/>
|
/>
|
||||||
|
|
|
@ -60,20 +60,6 @@
|
||||||
padding: 0.6em;
|
padding: 0.6em;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
||||||
.RichContent {
|
|
||||||
a {
|
|
||||||
--link: var(--linkFaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
.greentext {
|
|
||||||
--funtextGreentext: var(--funtextGreentextFaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cyantext {
|
|
||||||
--funtextCyantext: var(--funtextCyantextFaint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.avatar-container {
|
.avatar-container {
|
||||||
width: 32px;
|
width: 32px;
|
||||||
height: 32px;
|
height: 32px;
|
||||||
|
|
|
@ -79,6 +79,12 @@ export default {
|
||||||
required: false,
|
required: false,
|
||||||
type: Boolean,
|
type: Boolean,
|
||||||
default: false
|
default: false
|
||||||
|
},
|
||||||
|
// Faint style (for notifs)
|
||||||
|
faint: {
|
||||||
|
required: false,
|
||||||
|
type: Boolean,
|
||||||
|
default: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
// NEVER EVER TOUCH DATA INSIDE RENDER
|
// NEVER EVER TOUCH DATA INSIDE RENDER
|
||||||
|
@ -277,7 +283,7 @@ export default {
|
||||||
// DO NOT USE SLOTS they cause a re-render feedback loop here.
|
// DO NOT USE SLOTS they cause a re-render feedback loop here.
|
||||||
// slots updated -> rerender -> emit -> update up the tree -> rerender -> ...
|
// slots updated -> rerender -> emit -> update up the tree -> rerender -> ...
|
||||||
// at least until vue3?
|
// at least until vue3?
|
||||||
const result = <span class="RichContent">
|
const result = <span class={['RichContent', this.faint ? '-faint' : '']}>
|
||||||
{ pass2 }
|
{ pass2 }
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,15 @@
|
||||||
.RichContent {
|
.RichContent {
|
||||||
font-family: var(--font);
|
font-family: var(--font);
|
||||||
|
|
||||||
|
&.-faint {
|
||||||
|
/* stylelint-disable declaration-no-important */
|
||||||
|
--text: var(--textFaint) !important;
|
||||||
|
--link: var(--linkFaint) !important;
|
||||||
|
--funtextGreentext: var(--funtextGreentextFaint) !important;
|
||||||
|
--funtextCyantext: var(--funtextCyantextFaint) !important;
|
||||||
|
/* stylelint-enable declaration-no-important */
|
||||||
|
}
|
||||||
|
|
||||||
blockquote {
|
blockquote {
|
||||||
margin: 0.2em 0 0.2em 0.2em;
|
margin: 0.2em 0 0.2em 0.2em;
|
||||||
font-style: italic;
|
font-style: italic;
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
>
|
>
|
||||||
<RichContent
|
<RichContent
|
||||||
class="media-body summary"
|
class="media-body summary"
|
||||||
|
:faint="compact"
|
||||||
:html="status.summary_raw_html"
|
:html="status.summary_raw_html"
|
||||||
:emoji="status.emojis"
|
:emoji="status.emojis"
|
||||||
/>
|
/>
|
||||||
|
@ -48,6 +49,7 @@
|
||||||
:html="status.raw_html"
|
:html="status.raw_html"
|
||||||
:emoji="status.emojis"
|
:emoji="status.emojis"
|
||||||
:handle-links="true"
|
:handle-links="true"
|
||||||
|
:faint="compact"
|
||||||
:greentext="mergedConfig.greentext"
|
:greentext="mergedConfig.greentext"
|
||||||
:attentions="status.attentions"
|
:attentions="status.attentions"
|
||||||
@parseReady="onParseReady"
|
@parseReady="onParseReady"
|
||||||
|
|
|
@ -62,15 +62,5 @@
|
||||||
.StatusContent {
|
.StatusContent {
|
||||||
flex: 1;
|
flex: 1;
|
||||||
min-width: 0;
|
min-width: 0;
|
||||||
|
|
||||||
&.faint {
|
|
||||||
.greentext {
|
|
||||||
color: var(--funtextGreentextFaint);
|
|
||||||
}
|
|
||||||
|
|
||||||
.cyantext {
|
|
||||||
color: var(--funtextCyantextFaint);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -38,7 +38,7 @@
|
||||||
fixed-width
|
fixed-width
|
||||||
icon="circle-plus"
|
icon="circle-plus"
|
||||||
/>
|
/>
|
||||||
<div class="alert-badge">
|
<div class="badge -counter">
|
||||||
{{ mobileLoadButtonString }}
|
{{ mobileLoadButtonString }}
|
||||||
</div>
|
</div>
|
||||||
</button>
|
</button>
|
||||||
|
|
|
@ -4,24 +4,18 @@ import { init } from '../theme_data/theme_data_3.service.js'
|
||||||
import { convertTheme2To3 } from '../theme_data/theme2_to_theme3.js'
|
import { convertTheme2To3 } from '../theme_data/theme2_to_theme3.js'
|
||||||
import { getCssRules } from '../theme_data/css_utils.js'
|
import { getCssRules } from '../theme_data/css_utils.js'
|
||||||
import { defaultState } from '../../modules/config.js'
|
import { defaultState } from '../../modules/config.js'
|
||||||
|
import { chunk } from 'lodash'
|
||||||
|
|
||||||
export const applyTheme = (input) => {
|
export const applyTheme = async (input) => {
|
||||||
let extraRules
|
let extraRules
|
||||||
if (input.themeType !== 1) {
|
if (input.themeType !== 1) {
|
||||||
const t0 = performance.now()
|
|
||||||
const { theme } = generatePreset(input)
|
const { theme } = generatePreset(input)
|
||||||
const t1 = performance.now()
|
|
||||||
console.debug('Themes 2 initialization took ' + (t1 - t0) + 'ms')
|
|
||||||
extraRules = convertTheme2To3(theme)
|
extraRules = convertTheme2To3(theme)
|
||||||
} else {
|
} else {
|
||||||
console.debug(input)
|
|
||||||
extraRules = convertTheme2To3(input)
|
extraRules = convertTheme2To3(input)
|
||||||
}
|
}
|
||||||
|
|
||||||
const t1 = performance.now()
|
|
||||||
const themes3 = init(extraRules, '#FFFFFF')
|
const themes3 = init(extraRules, '#FFFFFF')
|
||||||
const t2 = performance.now()
|
|
||||||
console.debug('Themes 3 (eager) initialization took ' + (t2 - t1) + 'ms')
|
|
||||||
const head = document.head
|
const head = document.head
|
||||||
const body = document.body
|
const body = document.body
|
||||||
body.classList.add('hidden')
|
body.classList.add('hidden')
|
||||||
|
@ -47,14 +41,23 @@ export const applyTheme = (input) => {
|
||||||
styleSheet.insertRule(rule, 'index-max')
|
styleSheet.insertRule(rule, 'index-max')
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
body.classList.remove('hidden')
|
body.classList.remove('hidden')
|
||||||
themes3.lazy.then(lazyRules => {
|
|
||||||
getCssRules(lazyRules, themes3.staticVars).forEach(rule => {
|
// Optimization - instead of processing all lazy rules in one go, process them in small chunks
|
||||||
styleSheet.insertRule(rule, 'index-max')
|
// so that UI can do other things and be somewhat responsive while less important rules are being
|
||||||
})
|
// processed
|
||||||
const t3 = performance.now()
|
chunk(themes3.lazy, 5).forEach(chunk => {
|
||||||
console.debug('Themes 3 finalization (lazy) took ' + (t3 - t2) + 'ms')
|
setTimeout(() => {
|
||||||
|
Promise.all(chunk.map(x => x())).then(result => {
|
||||||
|
getCssRules(result.filter(x => x), themes3.staticVars).forEach(rule => {
|
||||||
|
styleSheet.insertRule(rule, 'index-max')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}, 50)
|
||||||
})
|
})
|
||||||
|
|
||||||
|
return Promise.resolve()
|
||||||
}
|
}
|
||||||
|
|
||||||
const configColumns = ({ sidebarColumnWidth, contentColumnWidth, notifsColumnWidth, emojiReactionsScale }) =>
|
const configColumns = ({ sidebarColumnWidth, contentColumnWidth, notifsColumnWidth, emojiReactionsScale }) =>
|
||||||
|
|
|
@ -149,9 +149,6 @@ export const init = (extraRuleset, ultimateBackgroundColor) => {
|
||||||
const stacked = {}
|
const stacked = {}
|
||||||
const computed = {}
|
const computed = {}
|
||||||
|
|
||||||
const eagerRules = []
|
|
||||||
const lazyRules = []
|
|
||||||
|
|
||||||
const rulesetUnsorted = [
|
const rulesetUnsorted = [
|
||||||
...Object.values(components)
|
...Object.values(components)
|
||||||
.map(c => (c.defaultRules || []).map(r => ({ component: c.name, ...r })))
|
.map(c => (c.defaultRules || []).map(r => ({ component: c.name, ...r })))
|
||||||
|
@ -187,25 +184,211 @@ export const init = (extraRuleset, ultimateBackgroundColor) => {
|
||||||
|
|
||||||
const virtualComponents = new Set(Object.values(components).filter(c => c.virtual).map(c => c.name))
|
const virtualComponents = new Set(Object.values(components).filter(c => c.virtual).map(c => c.name))
|
||||||
|
|
||||||
let counter = 0
|
const processCombination = (combination) => {
|
||||||
const promises = []
|
const selector = ruleToSelector(combination, true)
|
||||||
const processInnerComponent = (component, rules, parent) => {
|
const cssSelector = ruleToSelector(combination)
|
||||||
const addRule = (rule) => {
|
|
||||||
rules.push(rule)
|
const parentSelector = selector.split(/ /g).slice(0, -1).join(' ')
|
||||||
|
const soloSelector = selector.split(/ /g).slice(-1)[0]
|
||||||
|
|
||||||
|
const lowerLevelSelector = parentSelector
|
||||||
|
const lowerLevelBackground = computed[lowerLevelSelector]?.background
|
||||||
|
const lowerLevelVirtualDirectives = computed[lowerLevelSelector]?.virtualDirectives
|
||||||
|
const lowerLevelVirtualDirectivesRaw = computed[lowerLevelSelector]?.virtualDirectivesRaw
|
||||||
|
|
||||||
|
const dynamicVars = computed[selector] || {
|
||||||
|
lowerLevelBackground,
|
||||||
|
lowerLevelVirtualDirectives,
|
||||||
|
lowerLevelVirtualDirectivesRaw
|
||||||
}
|
}
|
||||||
|
|
||||||
const parentSelector = ruleToSelector(parent, true)
|
// Inheriting all of the applicable rules
|
||||||
// const parentList = parent ? unroll(parent).reverse().map(c => c.component) : []
|
const existingRules = ruleset.filter(findRules(combination))
|
||||||
// if (!component.virtual) {
|
const computedDirectives = existingRules.map(r => r.directives).reduce((acc, directives) => ({ ...acc, ...directives }), {})
|
||||||
// const path = [...parentList, component.name].join(' > ')
|
const computedRule = {
|
||||||
// console.log('Component ' + path + ' process starting')
|
...combination,
|
||||||
// }
|
directives: computedDirectives
|
||||||
// const t0 = performance.now()
|
}
|
||||||
|
|
||||||
|
computed[selector] = computed[selector] || {}
|
||||||
|
computed[selector].computedRule = computedRule
|
||||||
|
computed[selector].dynamicVars = dynamicVars
|
||||||
|
|
||||||
|
if (virtualComponents.has(combination.component)) {
|
||||||
|
const virtualName = [
|
||||||
|
'--',
|
||||||
|
combination.component.toLowerCase(),
|
||||||
|
combination.variant === 'normal'
|
||||||
|
? ''
|
||||||
|
: combination.variant[0].toUpperCase() + combination.variant.slice(1).toLowerCase(),
|
||||||
|
...combination.state.filter(x => x !== 'normal').toSorted().map(state => state[0].toUpperCase() + state.slice(1).toLowerCase())
|
||||||
|
].join('')
|
||||||
|
|
||||||
|
let inheritedTextColor = computedDirectives.textColor
|
||||||
|
let inheritedTextAuto = computedDirectives.textAuto
|
||||||
|
let inheritedTextOpacity = computedDirectives.textOpacity
|
||||||
|
let inheritedTextOpacityMode = computedDirectives.textOpacityMode
|
||||||
|
const lowerLevelTextSelector = [...selector.split(/ /g).slice(0, -1), soloSelector].join(' ')
|
||||||
|
const lowerLevelTextRule = computed[lowerLevelTextSelector]
|
||||||
|
|
||||||
|
if (inheritedTextColor == null || inheritedTextOpacity == null || inheritedTextOpacityMode == null) {
|
||||||
|
inheritedTextColor = computedDirectives.textColor ?? lowerLevelTextRule.textColor
|
||||||
|
inheritedTextAuto = computedDirectives.textAuto ?? lowerLevelTextRule.textAuto
|
||||||
|
inheritedTextOpacity = computedDirectives.textOpacity ?? lowerLevelTextRule.textOpacity
|
||||||
|
inheritedTextOpacityMode = computedDirectives.textOpacityMode ?? lowerLevelTextRule.textOpacityMode
|
||||||
|
}
|
||||||
|
|
||||||
|
const newTextRule = {
|
||||||
|
...computedRule,
|
||||||
|
directives: {
|
||||||
|
...computedRule.directives,
|
||||||
|
textColor: inheritedTextColor,
|
||||||
|
textAuto: inheritedTextAuto ?? 'preserve',
|
||||||
|
textOpacity: inheritedTextOpacity,
|
||||||
|
textOpacityMode: inheritedTextOpacityMode
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamicVars.inheritedBackground = lowerLevelBackground
|
||||||
|
dynamicVars.stacked = convert(stacked[lowerLevelSelector]).rgb
|
||||||
|
|
||||||
|
const intendedTextColor = convert(findColor(inheritedTextColor, { dynamicVars, staticVars })).rgb
|
||||||
|
const textColor = newTextRule.directives.textAuto === 'no-auto'
|
||||||
|
? intendedTextColor
|
||||||
|
: getTextColor(
|
||||||
|
convert(stacked[lowerLevelSelector]).rgb,
|
||||||
|
intendedTextColor,
|
||||||
|
newTextRule.directives.textAuto === 'preserve'
|
||||||
|
)
|
||||||
|
const virtualDirectives = computed[lowerLevelSelector].virtualDirectives || {}
|
||||||
|
const virtualDirectivesRaw = computed[lowerLevelSelector].virtualDirectivesRaw || {}
|
||||||
|
|
||||||
|
// Storing color data in lower layer to use as custom css properties
|
||||||
|
virtualDirectives[virtualName] = getTextColorAlpha(newTextRule.directives, textColor, dynamicVars)
|
||||||
|
virtualDirectivesRaw[virtualName] = textColor
|
||||||
|
|
||||||
|
computed[lowerLevelSelector].virtualDirectives = virtualDirectives
|
||||||
|
computed[lowerLevelSelector].virtualDirectivesRaw = virtualDirectivesRaw
|
||||||
|
|
||||||
|
return {
|
||||||
|
dynamicVars,
|
||||||
|
selector: cssSelector.split(/ /g).slice(0, -1).join(' '),
|
||||||
|
...combination,
|
||||||
|
directives: {},
|
||||||
|
virtualDirectives,
|
||||||
|
virtualDirectivesRaw
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
computed[selector] = computed[selector] || {}
|
||||||
|
|
||||||
|
// TODO: DEFAULT TEXT COLOR
|
||||||
|
const lowerLevelStackedBackground = stacked[lowerLevelSelector] || convert(ultimateBackgroundColor).rgb
|
||||||
|
|
||||||
|
if (computedDirectives.background) {
|
||||||
|
let inheritRule = null
|
||||||
|
const variantRules = ruleset.filter(
|
||||||
|
findRules({
|
||||||
|
component: combination.component,
|
||||||
|
variant: combination.variant,
|
||||||
|
parent: combination.parent
|
||||||
|
})
|
||||||
|
)
|
||||||
|
const lastVariantRule = variantRules[variantRules.length - 1]
|
||||||
|
if (lastVariantRule) {
|
||||||
|
inheritRule = lastVariantRule
|
||||||
|
} else {
|
||||||
|
const normalRules = ruleset.filter(findRules({
|
||||||
|
component: combination.component,
|
||||||
|
parent: combination.parent
|
||||||
|
}))
|
||||||
|
const lastNormalRule = normalRules[normalRules.length - 1]
|
||||||
|
inheritRule = lastNormalRule
|
||||||
|
}
|
||||||
|
|
||||||
|
const inheritSelector = ruleToSelector({ ...inheritRule, parent: combination.parent }, true)
|
||||||
|
const inheritedBackground = computed[inheritSelector].background
|
||||||
|
|
||||||
|
dynamicVars.inheritedBackground = inheritedBackground
|
||||||
|
|
||||||
|
const rgb = convert(findColor(computedDirectives.background, { dynamicVars, staticVars })).rgb
|
||||||
|
|
||||||
|
if (!stacked[selector]) {
|
||||||
|
let blend
|
||||||
|
const alpha = computedDirectives.opacity ?? 1
|
||||||
|
if (alpha >= 1) {
|
||||||
|
blend = rgb
|
||||||
|
} else if (alpha <= 0) {
|
||||||
|
blend = lowerLevelStackedBackground
|
||||||
|
} else {
|
||||||
|
blend = alphaBlend(rgb, computedDirectives.opacity, lowerLevelStackedBackground)
|
||||||
|
}
|
||||||
|
stacked[selector] = blend
|
||||||
|
computed[selector].background = { ...rgb, a: computedDirectives.opacity ?? 1 }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (computedDirectives.shadow) {
|
||||||
|
dynamicVars.shadow = flattenDeep(findShadow(flattenDeep(computedDirectives.shadow), { dynamicVars, staticVars }))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stacked[selector]) {
|
||||||
|
computedDirectives.background = 'transparent'
|
||||||
|
computedDirectives.opacity = 0
|
||||||
|
stacked[selector] = lowerLevelStackedBackground
|
||||||
|
computed[selector].background = { ...lowerLevelStackedBackground, a: 0 }
|
||||||
|
}
|
||||||
|
|
||||||
|
dynamicVars.stacked = stacked[selector]
|
||||||
|
dynamicVars.background = computed[selector].background
|
||||||
|
|
||||||
|
const dynamicSlots = Object.entries(computedDirectives).filter(([k, v]) => k.startsWith('--'))
|
||||||
|
|
||||||
|
dynamicSlots.forEach(([k, v]) => {
|
||||||
|
const [type, ...value] = v.split('|').map(x => x.trim()) // woah, Extreme!
|
||||||
|
switch (type) {
|
||||||
|
case 'color': {
|
||||||
|
const color = findColor(value[0], { dynamicVars, staticVars })
|
||||||
|
dynamicVars[k] = color
|
||||||
|
if (combination.component === 'Root') {
|
||||||
|
staticVars[k.substring(2)] = color
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'shadow': {
|
||||||
|
const shadow = value
|
||||||
|
dynamicVars[k] = shadow
|
||||||
|
if (combination.component === 'Root') {
|
||||||
|
staticVars[k.substring(2)] = shadow
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
case 'generic': {
|
||||||
|
dynamicVars[k] = value
|
||||||
|
if (combination.component === 'Root') {
|
||||||
|
staticVars[k.substring(2)] = value
|
||||||
|
}
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const rule = {
|
||||||
|
dynamicVars,
|
||||||
|
selector: cssSelector,
|
||||||
|
...combination,
|
||||||
|
directives: computedDirectives
|
||||||
|
}
|
||||||
|
|
||||||
|
return rule
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const processInnerComponent = (component, parent) => {
|
||||||
|
const combinations = []
|
||||||
const {
|
const {
|
||||||
validInnerComponents = [],
|
validInnerComponents = [],
|
||||||
states: originalStates = {},
|
states: originalStates = {},
|
||||||
variants: originalVariants = {},
|
variants: originalVariants = {}
|
||||||
name
|
|
||||||
} = component
|
} = component
|
||||||
|
|
||||||
// Normalizing states and variants to always include "normal"
|
// Normalizing states and variants to always include "normal"
|
||||||
|
@ -241,234 +424,41 @@ export const init = (extraRuleset, ultimateBackgroundColor) => {
|
||||||
}).reduce((acc, x) => [...acc, ...x], [])
|
}).reduce((acc, x) => [...acc, ...x], [])
|
||||||
|
|
||||||
stateVariantCombination.forEach(combination => {
|
stateVariantCombination.forEach(combination => {
|
||||||
counter++
|
|
||||||
// const tt0 = performance.now()
|
|
||||||
|
|
||||||
combination.component = component.name
|
combination.component = component.name
|
||||||
const soloSelector = ruleToSelector(combination, true)
|
combination.lazy = component.lazy || parent?.lazy
|
||||||
const soloCssSelector = ruleToSelector(combination)
|
combination.parent = parent
|
||||||
const selector = [parentSelector, soloSelector].filter(x => x).join(' ')
|
if (combination.state.indexOf('hover') >= 0) {
|
||||||
const cssSelector = [parentSelector, soloCssSelector].filter(x => x).join(' ')
|
combination.lazy = true
|
||||||
|
|
||||||
const lowerLevelSelector = parentSelector
|
|
||||||
const lowerLevelBackground = computed[lowerLevelSelector]?.background
|
|
||||||
const lowerLevelVirtualDirectives = computed[lowerLevelSelector]?.virtualDirectives
|
|
||||||
const lowerLevelVirtualDirectivesRaw = computed[lowerLevelSelector]?.virtualDirectivesRaw
|
|
||||||
|
|
||||||
const dynamicVars = computed[selector] || {
|
|
||||||
lowerLevelBackground,
|
|
||||||
lowerLevelVirtualDirectives,
|
|
||||||
lowerLevelVirtualDirectivesRaw
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Inheriting all of the applicable rules
|
combinations.push(combination)
|
||||||
const existingRules = ruleset.filter(findRules({ component: component.name, ...combination, parent }))
|
|
||||||
const computedDirectives = existingRules.map(r => r.directives).reduce((acc, directives) => ({ ...acc, ...directives }), {})
|
|
||||||
const computedRule = {
|
|
||||||
component: component.name,
|
|
||||||
...combination,
|
|
||||||
parent,
|
|
||||||
directives: computedDirectives
|
|
||||||
}
|
|
||||||
|
|
||||||
computed[selector] = computed[selector] || {}
|
|
||||||
computed[selector].computedRule = computedRule
|
|
||||||
computed[selector].dynamicVars = dynamicVars
|
|
||||||
|
|
||||||
if (virtualComponents.has(component.name)) {
|
|
||||||
const virtualName = [
|
|
||||||
'--',
|
|
||||||
component.name.toLowerCase(),
|
|
||||||
combination.variant === 'normal'
|
|
||||||
? ''
|
|
||||||
: combination.variant[0].toUpperCase() + combination.variant.slice(1).toLowerCase(),
|
|
||||||
...combination.state.filter(x => x !== 'normal').toSorted().map(state => state[0].toUpperCase() + state.slice(1).toLowerCase())
|
|
||||||
].join('')
|
|
||||||
|
|
||||||
let inheritedTextColor = computedDirectives.textColor
|
|
||||||
let inheritedTextAuto = computedDirectives.textAuto
|
|
||||||
let inheritedTextOpacity = computedDirectives.textOpacity
|
|
||||||
let inheritedTextOpacityMode = computedDirectives.textOpacityMode
|
|
||||||
const lowerLevelTextSelector = [...selector.split(/ /g).slice(0, -1), soloSelector].join(' ')
|
|
||||||
const lowerLevelTextRule = computed[lowerLevelTextSelector]
|
|
||||||
|
|
||||||
if (inheritedTextColor == null || inheritedTextOpacity == null || inheritedTextOpacityMode == null) {
|
|
||||||
inheritedTextColor = computedDirectives.textColor ?? lowerLevelTextRule.textColor
|
|
||||||
inheritedTextAuto = computedDirectives.textAuto ?? lowerLevelTextRule.textAuto
|
|
||||||
inheritedTextOpacity = computedDirectives.textOpacity ?? lowerLevelTextRule.textOpacity
|
|
||||||
inheritedTextOpacityMode = computedDirectives.textOpacityMode ?? lowerLevelTextRule.textOpacityMode
|
|
||||||
}
|
|
||||||
|
|
||||||
const newTextRule = {
|
|
||||||
...computedRule,
|
|
||||||
directives: {
|
|
||||||
...computedRule.directives,
|
|
||||||
textColor: inheritedTextColor,
|
|
||||||
textAuto: inheritedTextAuto ?? 'preserve',
|
|
||||||
textOpacity: inheritedTextOpacity,
|
|
||||||
textOpacityMode: inheritedTextOpacityMode
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamicVars.inheritedBackground = lowerLevelBackground
|
|
||||||
dynamicVars.stacked = convert(stacked[lowerLevelSelector]).rgb
|
|
||||||
|
|
||||||
const intendedTextColor = convert(findColor(inheritedTextColor, { dynamicVars, staticVars })).rgb
|
|
||||||
const textColor = newTextRule.directives.textAuto === 'no-auto'
|
|
||||||
? intendedTextColor
|
|
||||||
: getTextColor(
|
|
||||||
convert(stacked[lowerLevelSelector]).rgb,
|
|
||||||
intendedTextColor,
|
|
||||||
newTextRule.directives.textAuto === 'preserve'
|
|
||||||
)
|
|
||||||
|
|
||||||
// Updating previously added rule
|
|
||||||
const earlyLowerLevelRules = rules.filter(findRules(parent, true))
|
|
||||||
const earlyLowerLevelRule = earlyLowerLevelRules.slice(-1)[0]
|
|
||||||
|
|
||||||
const virtualDirectives = earlyLowerLevelRule.virtualDirectives || {}
|
|
||||||
const virtualDirectivesRaw = earlyLowerLevelRule.virtualDirectivesRaw || {}
|
|
||||||
|
|
||||||
// Storing color data in lower layer to use as custom css properties
|
|
||||||
virtualDirectives[virtualName] = getTextColorAlpha(newTextRule.directives, textColor, dynamicVars)
|
|
||||||
virtualDirectivesRaw[virtualName] = textColor
|
|
||||||
earlyLowerLevelRule.virtualDirectives = virtualDirectives
|
|
||||||
earlyLowerLevelRule.virtualDirectivesRaw = virtualDirectivesRaw
|
|
||||||
computed[lowerLevelSelector].virtualDirectives = virtualDirectives
|
|
||||||
computed[lowerLevelSelector].virtualDirectivesRaw = virtualDirectivesRaw
|
|
||||||
} else {
|
|
||||||
computed[selector] = computed[selector] || {}
|
|
||||||
|
|
||||||
// TODO: DEFAULT TEXT COLOR
|
|
||||||
const lowerLevelStackedBackground = stacked[lowerLevelSelector] || convert(ultimateBackgroundColor).rgb
|
|
||||||
|
|
||||||
if (computedDirectives.background) {
|
|
||||||
let inheritRule = null
|
|
||||||
const variantRules = ruleset.filter(findRules({ component: component.name, variant: combination.variant, parent }))
|
|
||||||
const lastVariantRule = variantRules[variantRules.length - 1]
|
|
||||||
if (lastVariantRule) {
|
|
||||||
inheritRule = lastVariantRule
|
|
||||||
} else {
|
|
||||||
const normalRules = ruleset.filter(findRules({ component: component.name, parent }))
|
|
||||||
const lastNormalRule = normalRules[normalRules.length - 1]
|
|
||||||
inheritRule = lastNormalRule
|
|
||||||
}
|
|
||||||
|
|
||||||
const inheritSelector = ruleToSelector({ ...inheritRule, parent }, true)
|
|
||||||
const inheritedBackground = computed[inheritSelector].background
|
|
||||||
|
|
||||||
dynamicVars.inheritedBackground = inheritedBackground
|
|
||||||
|
|
||||||
const rgb = convert(findColor(computedDirectives.background, { dynamicVars, staticVars })).rgb
|
|
||||||
|
|
||||||
if (!stacked[selector]) {
|
|
||||||
let blend
|
|
||||||
const alpha = computedDirectives.opacity ?? 1
|
|
||||||
if (alpha >= 1) {
|
|
||||||
blend = rgb
|
|
||||||
} else if (alpha <= 0) {
|
|
||||||
blend = lowerLevelStackedBackground
|
|
||||||
} else {
|
|
||||||
blend = alphaBlend(rgb, computedDirectives.opacity, lowerLevelStackedBackground)
|
|
||||||
}
|
|
||||||
stacked[selector] = blend
|
|
||||||
computed[selector].background = { ...rgb, a: computedDirectives.opacity ?? 1 }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (computedDirectives.shadow) {
|
|
||||||
dynamicVars.shadow = flattenDeep(findShadow(flattenDeep(computedDirectives.shadow), { dynamicVars, staticVars }))
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stacked[selector]) {
|
|
||||||
computedDirectives.background = 'transparent'
|
|
||||||
computedDirectives.opacity = 0
|
|
||||||
stacked[selector] = lowerLevelStackedBackground
|
|
||||||
computed[selector].background = { ...lowerLevelStackedBackground, a: 0 }
|
|
||||||
}
|
|
||||||
|
|
||||||
dynamicVars.stacked = stacked[selector]
|
|
||||||
dynamicVars.background = computed[selector].background
|
|
||||||
|
|
||||||
const dynamicSlots = Object.entries(computedDirectives).filter(([k, v]) => k.startsWith('--'))
|
|
||||||
|
|
||||||
dynamicSlots.forEach(([k, v]) => {
|
|
||||||
const [type, ...value] = v.split('|').map(x => x.trim()) // woah, Extreme!
|
|
||||||
switch (type) {
|
|
||||||
case 'color': {
|
|
||||||
const color = findColor(value[0], { dynamicVars, staticVars })
|
|
||||||
dynamicVars[k] = color
|
|
||||||
if (component.name === 'Root') {
|
|
||||||
staticVars[k.substring(2)] = color
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 'shadow': {
|
|
||||||
const shadow = value
|
|
||||||
dynamicVars[k] = shadow
|
|
||||||
if (component.name === 'Root') {
|
|
||||||
staticVars[k.substring(2)] = shadow
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
case 'generic': {
|
|
||||||
dynamicVars[k] = value
|
|
||||||
if (component.name === 'Root') {
|
|
||||||
staticVars[k.substring(2)] = value
|
|
||||||
}
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
addRule({
|
|
||||||
dynamicVars,
|
|
||||||
selector: cssSelector,
|
|
||||||
component: component.name,
|
|
||||||
...combination,
|
|
||||||
parent,
|
|
||||||
directives: computedDirectives
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
innerComponents.forEach(innerComponent => {
|
innerComponents.forEach(innerComponent => {
|
||||||
if (innerComponent.lazy) {
|
combinations.push(...processInnerComponent(innerComponent, combination))
|
||||||
promises.push(new Promise((resolve, reject) => {
|
|
||||||
setTimeout(() => {
|
|
||||||
try {
|
|
||||||
processInnerComponent(innerComponent, lazyRules, { parent, component: name, ...combination })
|
|
||||||
resolve()
|
|
||||||
} catch (e) {
|
|
||||||
reject(e)
|
|
||||||
}
|
|
||||||
}, 0)
|
|
||||||
}))
|
|
||||||
} else {
|
|
||||||
processInnerComponent(innerComponent, rules, { parent, component: name, ...combination })
|
|
||||||
}
|
|
||||||
})
|
})
|
||||||
// const tt1 = performance.now()
|
|
||||||
// if (!component.virtual) {
|
|
||||||
// console.log('State-variant ' + combination.variant + ' : ' + combination.state.join('+') + ' procession time: ' + (tt1 - tt0) + 'ms')
|
|
||||||
// }
|
|
||||||
})
|
})
|
||||||
|
|
||||||
// const t1 = performance.now()
|
return combinations
|
||||||
// if (!component.virtual) {
|
|
||||||
// const path = [...parentList, component.name].join(' > ')
|
|
||||||
// console.log('Component ' + path + ' procession time: ' + (t1 - t0) + 'ms')
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
processInnerComponent(components.Root, eagerRules)
|
const t0 = performance.now()
|
||||||
console.debug('Eager combinations processed:' + counter)
|
const combinations = processInnerComponent(components.Root)
|
||||||
const lazyExec = Promise.all(promises).then(() => {
|
const t1 = performance.now()
|
||||||
console.debug('Total combinations processed: ' + counter)
|
console.debug('Tree tranveral took ' + (t1 - t0) + ' ms')
|
||||||
}).then(() => lazyRules)
|
|
||||||
|
const result = combinations.map((combination) => {
|
||||||
|
if (combination.lazy) {
|
||||||
|
return async () => processCombination(combination)
|
||||||
|
} else {
|
||||||
|
return processCombination(combination)
|
||||||
|
}
|
||||||
|
}).filter(x => x)
|
||||||
|
const t2 = performance.now()
|
||||||
|
console.debug('Eager processing took ' + (t2 - t1) + ' ms')
|
||||||
|
|
||||||
return {
|
return {
|
||||||
lazy: lazyExec,
|
lazy: result.filter(x => typeof x === 'function'),
|
||||||
eager: eagerRules,
|
eager: result.filter(x => typeof x !== 'function'),
|
||||||
staticVars
|
staticVars
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue