Merge branch 'themes3-grand-finale-maybe' into shigusegubu-themes3

This commit is contained in:
Henry Jameson 2024-11-19 03:20:04 +02:00
commit 31527054c2
11 changed files with 339 additions and 120 deletions

View file

@ -89,6 +89,13 @@ export default {
shadow: ['--buttonDefaultHoverGlow', '--buttonPressedBevel'] shadow: ['--buttonDefaultHoverGlow', '--buttonPressedBevel']
} }
}, },
{
state: ['toggled', 'disabled'],
directives: {
background: '$blend(--inheritedBackground 0.25 --parent)',
shadow: ['--buttonPressedBevel']
}
},
{ {
state: ['disabled'], state: ['disabled'],
directives: { directives: {

View file

@ -16,6 +16,7 @@ import {
getCssRules, getCssRules,
getScopedVersion getScopedVersion
} from 'src/services/theme_data/css_utils.js' } from 'src/services/theme_data/css_utils.js'
import { deserialize } from 'src/services/theme_data/iss_deserializer.js'
import SharedComputedObject from '../helpers/shared_computed_object.js' import SharedComputedObject from '../helpers/shared_computed_object.js'
import ProfileSettingIndicator from '../helpers/profile_setting_indicator.vue' import ProfileSettingIndicator from '../helpers/profile_setting_indicator.vue'
@ -35,10 +36,12 @@ const AppearanceTab = {
return { return {
availableStyles: [], availableStyles: [],
bundledPalettes: [], bundledPalettes: [],
compilationCache: {},
fileImporter: newImporter({ fileImporter: newImporter({
accept: '.json, .piss', accept: '.json, .piss',
validator: this.importValidator, validator: this.importValidator,
onImport: this.onImport, onImport: this.onImport,
parser: this.importParser,
onImportFailure: this.onImportFailure onImportFailure: this.onImportFailure
}), }),
palettesKeys: [ palettesKeys: [
@ -82,6 +85,8 @@ const AppearanceTab = {
PaletteEditor PaletteEditor
}, },
mounted () { mounted () {
this.$store.dispatch('getThemeData')
const updateIndex = (resource) => { const updateIndex = (resource) => {
const capitalizedResource = resource[0].toUpperCase() + resource.slice(1) const capitalizedResource = resource[0].toUpperCase() + resource.slice(1)
const currentIndex = this.$store.state.instance[`${resource}sIndex`] const currentIndex = this.$store.state.instance[`${resource}sIndex`]
@ -100,6 +105,13 @@ const AppearanceTab = {
}) })
} }
updateIndex('style').then(styles => {
styles.forEach(([key, stylePromise]) => stylePromise.then(data => {
const meta = data.find(x => x.component === '@meta')
this.availableStyles.push({ key, data, name: meta.directives.name, version: 'v3' })
}))
})
updateIndex('theme').then(themes => { updateIndex('theme').then(themes => {
themes.forEach(([key, themePromise]) => themePromise.then(data => { themes.forEach(([key, themePromise]) => themePromise.then(data => {
this.availableStyles.push({ key, data, name: data.name, version: 'v2' }) this.availableStyles.push({ key, data, name: data.name, version: 'v2' })
@ -164,14 +176,18 @@ const AppearanceTab = {
] ]
}, },
stylePalettes () { stylePalettes () {
if (!this.mergedConfig.styleCustomData) return const ruleset = this.$store.state.interface.styleDataUsed || []
const meta = this.mergedConfig.styleCustomData console.log(
.find(x => x.component === '@meta') 'ASR',
const result = this.mergedConfig.styleCustomData this.$store.state.interface.paletteDataUsed,
.filter(x => x.component.startsWith('@palette')) this.$store.state.interface.styleDataUsed
)
if (!ruleset && ruleset.length === 0) return
const meta = ruleset.find(x => x.component === '@meta')
const result = ruleset.filter(x => x.component.startsWith('@palette'))
.map(x => { .map(x => {
const { variant, directives } = x
const { const {
variant,
bg, bg,
fg, fg,
text, text,
@ -182,10 +198,10 @@ const AppearanceTab = {
cGreen, cGreen,
cOrange, cOrange,
wallpaper wallpaper
} = x } = directives
const result = { const result = {
name: `${meta.name}: ${variant}`, name: `${meta.directives.name || this.$t('settings.style.themes3.palette.imported')}: ${variant}`,
bg, bg,
fg, fg,
text, text,
@ -238,12 +254,12 @@ const AppearanceTab = {
return themeVersion return themeVersion
}, },
isCustomThemeUsed () { isCustomThemeUsed () {
const { theme } = this.mergedConfig const { customTheme, customThemeSource } = this.mergedConfig
return theme === 'custom' return customTheme != null || customThemeSource != null
}, },
isCustomStyleUsed (name) { isCustomStyleUsed (name) {
const { style } = this.mergedConfig const { styleCustomData } = this.mergedConfig
return style === 'custom' return styleCustomData != null
}, },
...SharedComputedObject() ...SharedComputedObject()
}, },
@ -263,21 +279,33 @@ const AppearanceTab = {
importFile () { importFile () {
this.fileImporter.importData() this.fileImporter.importData()
}, },
importParser (file, filename) {
if (filename.endsWith('.json')) {
return JSON.parse(file)
} else if (filename.endsWith('.piss')) {
return deserialize(file)
}
},
onImport (parsed, filename) { onImport (parsed, filename) {
if (filename.endsWith('.json')) { if (filename.endsWith('.json')) {
this.$store.dispatch('setThemeCustom', parsed.source || parsed.theme) this.$store.dispatch('setThemeCustom', parsed.source || parsed.theme)
this.$store.dispatch('applyTheme') } else if (filename.endsWith('.piss')) {
this.$store.dispatch('setStyleCustom', parsed)
} }
// this.loadTheme(parsed, 'file', forceSource)
}, },
onImportFailure (result) { onImportFailure (result) {
console.error('Failure importing theme:', result)
this.$store.dispatch('pushGlobalNotice', { messageKey: 'settings.invalid_theme_imported', level: 'error' }) this.$store.dispatch('pushGlobalNotice', { messageKey: 'settings.invalid_theme_imported', level: 'error' })
}, },
importValidator (parsed, filename) { importValidator (parsed, filename) {
if (filename.endsWith('.json')) { if (filename.endsWith('.json')) {
const version = parsed._pleroma_theme_version const version = parsed._pleroma_theme_version
return version >= 1 || version <= 2 return version >= 1 || version <= 2
} else if (filename.endsWith('.piss')) {
if (!Array.isArray(parsed)) return false
if (parsed.length < 1) return false
if (parsed.find(x => x.component === '@meta') == null) return false
return true
} }
}, },
isThemeActive (key) { isThemeActive (key) {
@ -293,7 +321,7 @@ const AppearanceTab = {
return key === palette return key === palette
}, },
setStyle (name) { setStyle (name) {
this.$store.dispatch('setTheme', name) this.$store.dispatch('setStyle', name)
}, },
setTheme (name) { setTheme (name) {
this.$store.dispatch('setTheme', name) this.$store.dispatch('setTheme', name)
@ -309,18 +337,30 @@ const AppearanceTab = {
resetTheming (name) { resetTheming (name) {
this.$store.dispatch('setStyle', 'stock') this.$store.dispatch('setStyle', 'stock')
}, },
previewTheme (key, input) { previewTheme (key, version, input) {
let theme3 let theme3
if (input) { if (this.compilationCache[key]) {
const style = normalizeThemeData(input) theme3 = this.compilationCache[key]
const theme2 = convertTheme2To3(style) } else if (input) {
theme3 = init({ if (version === 'v2') {
inputRuleset: theme2, const style = normalizeThemeData(input)
ultimateBackgroundColor: '#000000', const theme2 = convertTheme2To3(style)
liteMode: true, theme3 = init({
debug: true, inputRuleset: theme2,
onlyNormalState: true ultimateBackgroundColor: '#000000',
}) liteMode: true,
debug: true,
onlyNormalState: true
})
} else if (version === 'v3') {
theme3 = init({
inputRuleset: input,
ultimateBackgroundColor: '#000000',
liteMode: true,
debug: true,
onlyNormalState: true
})
}
} else { } else {
theme3 = init({ theme3 = init({
inputRuleset: [], inputRuleset: [],
@ -331,6 +371,10 @@ const AppearanceTab = {
}) })
} }
if (!this.compilationCache[key]) {
this.compilationCache[key] = theme3
}
return getScopedVersion( return getScopedVersion(
getCssRules(theme3.eager), getCssRules(theme3.eager),
'#theme-preview-' + key '#theme-preview-' + key

View file

@ -18,7 +18,7 @@
<!-- eslint-disable vue/no-v-text-v-html-on-component --> <!-- eslint-disable vue/no-v-text-v-html-on-component -->
<component <component
:is="'style'" :is="'style'"
v-html="previewTheme('stock')" v-html="previewTheme('stock', 'v3')"
/> />
<!-- eslint-enable vue/no-v-text-v-html-on-component --> <!-- eslint-enable vue/no-v-text-v-html-on-component -->
<preview id="theme-preview-stock" /> <preview id="theme-preview-stock" />
@ -30,7 +30,7 @@
<button <button
v-if="isCustomThemeUsed" v-if="isCustomThemeUsed"
disabled disabled
class="button-default theme-preview" class="button-default theme-preview toggled"
> >
<preview /> <preview />
<h4 class="theme-name"> <h4 class="theme-name">
@ -38,20 +38,32 @@
<span class="alert neutral version">v2</span> <span class="alert neutral version">v2</span>
</h4> </h4>
</button> </button>
<button
v-if="isCustomStyleUsed"
disabled
class="button-default theme-preview toggled"
>
<preview />
<h4 class="theme-name">
{{ $t('settings.style.custom_style_used') }}
<span class="alert neutral version">v3</span>
</h4>
</button>
<button <button
v-for="style in availableStyles" v-for="style in availableStyles"
:key="style.key" :key="style.key"
:data-theme-key="style.key" :data-theme-key="style.key"
class="button-default theme-preview" class="button-default theme-preview"
:class="{ toggled: isThemeActive(style.key) }" :class="{ toggled: isThemeActive(style.key) }"
@click="setTheme(style.key)" @click="style.version == 'v2' ? setTheme(style.key) : setStyle(style.key)"
> >
<!-- eslint-disable vue/no-v-text-v-html-on-component --> <!-- eslint-disable vue/no-v-text-v-html-on-component -->
<component <div v-if="style.ready || noIntersectionObserver">
:is="'style'" <component
v-if="style.ready || noIntersectionObserver" :is="'style'"
v-html="previewTheme(style.key, style.data)" v-html="previewTheme(style.key, style.version, style.data)"
/> />
</div>
<!-- eslint-enable vue/no-v-text-v-html-on-component --> <!-- eslint-enable vue/no-v-text-v-html-on-component -->
<preview :id="'theme-preview-' + style.key" /> <preview :id="'theme-preview-' + style.key" />
<h4 class="theme-name"> <h4 class="theme-name">
@ -102,7 +114,7 @@
@click="() => setPaletteCustom(p)" @click="() => setPaletteCustom(p)"
> >
<label> <label>
{{ p.name }} {{ p.name ?? $t('settings.style.themes3.palette.user') }}
</label> </label>
<span <span
v-for="c in palettesKeys" v-for="c in palettesKeys"

View file

@ -86,7 +86,6 @@ export default {
exports.isActive = computed(() => { exports.isActive = computed(() => {
const tabSwitcher = getCurrentInstance().parent.ctx const tabSwitcher = getCurrentInstance().parent.ctx
console.log('TABSW', tabSwitcher)
return tabSwitcher ? tabSwitcher.isActive('style') : false return tabSwitcher ? tabSwitcher.isActive('style') : false
}) })
@ -109,10 +108,12 @@ export default {
const metaRule = computed(() => ({ const metaRule = computed(() => ({
component: '@meta', component: '@meta',
name: exports.name.value, directives: {
author: exports.author.value, name: exports.name.value,
license: exports.license.value, author: exports.author.value,
website: exports.website.value license: exports.license.value,
website: exports.website.value
}
})) }))
// ## Palette stuff // ## Palette stuff
@ -190,9 +191,9 @@ export default {
return { return {
component: '@palette', component: '@palette',
variant: name, variant: name,
...Object directives: Object
.entries(rest) .entries(rest)
.filter(([k, v]) => v) .filter(([k, v]) => v && k)
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {}) .reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {})
} }
}) })
@ -203,6 +204,7 @@ export default {
return palettes.map(({ name, ...palette }) => { return palettes.map(({ name, ...palette }) => {
const entries = Object const entries = Object
.entries(palette) .entries(palette)
.filter(([k, v]) => v && k)
.map(([slot, data]) => ` ${slot}: ${data};`) .map(([slot, data]) => ` ${slot}: ${data};`)
.join('\n') .join('\n')
@ -561,7 +563,9 @@ export default {
const virtualDirectivesOut = computed(() => { const virtualDirectivesOut = computed(() => {
return [ return [
'Root {', 'Root {',
...virtualDirectives.value.map(vd => ` --${vd.name}: ${vd.valType} | ${vd.value};`), ...virtualDirectives.value
.filter(vd => vd.name && vd.valType && vd.value)
.map(vd => ` --${vd.name}: ${vd.valType} | ${vd.value};`),
'}' '}'
].join('\n') ].join('\n')
}) })
@ -597,7 +601,11 @@ export default {
const styleImporter = newImporter({ const styleImporter = newImporter({
accept: '.piss', accept: '.piss',
parser: (string) => deserialize(string), parser (string) { return deserialize(string) },
onImportFailure (result) {
console.error('Failure importing style:', result)
this.$store.dispatch('pushGlobalNotice', { messageKey: 'settings.invalid_theme_imported', level: 'error' })
},
onImport (parsed, filename) { onImport (parsed, filename) {
const editorComponents = parsed.filter(x => x.component.startsWith('@')) const editorComponents = parsed.filter(x => x.component.startsWith('@'))
const rootComponent = parsed.find(x => x.component === 'Root') const rootComponent = parsed.find(x => x.component === 'Root')

View file

@ -750,6 +750,7 @@
"more_settings": "More settings", "more_settings": "More settings",
"style": { "style": {
"custom_theme_used": "(Custom theme)", "custom_theme_used": "(Custom theme)",
"custom_style_used": "(Custom style)",
"stock_theme_used": "(Stock theme)", "stock_theme_used": "(Stock theme)",
"themes2_outdated": "Editor for Themes V2 is being phased out and will eventually be replaced with a new one that takes advantage of new Themes V3 engine. It should still work but experience might be degraded and inconsistent.", "themes2_outdated": "Editor for Themes V2 is being phased out and will eventually be replaced with a new one that takes advantage of new Themes V3 engine. It should still work but experience might be degraded and inconsistent.",
"appearance_tab_note": "Changes on this tab do not affect the theme used, so exported theme will be different from what seen in the UI", "appearance_tab_note": "Changes on this tab do not affect the theme used, so exported theme will be different from what seen in the UI",
@ -775,7 +776,8 @@
"v2_unsupported": "Older v2 themes don't support palettes. Switch to v3 theme to make use of palettes", "v2_unsupported": "Older v2 themes don't support palettes. Switch to v3 theme to make use of palettes",
"bundled": "Bundled palettes", "bundled": "Bundled palettes",
"style": "Palettes provided by selected style", "style": "Palettes provided by selected style",
"user": "Custom palette" "user": "Custom palette",
"imported": "Imported"
}, },
"editor": { "editor": {
"title": "Style", "title": "Style",

View file

@ -48,7 +48,9 @@ export const defaultState = {
// V3 // V3
style: null, style: null,
styleCustomData: null,
palette: null, palette: null,
paletteCustomData: null,
themeDebug: false, // debug mode that uses computed backgrounds instead of real ones to debug contrast functions themeDebug: false, // debug mode that uses computed backgrounds instead of real ones to debug contrast functions
forceThemeRecompilation: false, // flag that forces recompilation on boot even if cache exists forceThemeRecompilation: false, // flag that forces recompilation on boot even if cache exists
theme3hacks: { // Hacks, user overrides that are independent of theme used theme3hacks: { // Hacks, user overrides that are independent of theme used

View file

@ -1,11 +1,18 @@
import { getResourcesIndex, applyTheme, tryLoadCache } from '../services/style_setter/style_setter.js' import { getResourcesIndex, applyTheme, tryLoadCache } from '../services/style_setter/style_setter.js'
import { CURRENT_VERSION, generatePreset } from 'src/services/theme_data/theme_data.service.js' import { CURRENT_VERSION, generatePreset } from 'src/services/theme_data/theme_data.service.js'
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js' import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
import { deserialize } from '../services/theme_data/iss_deserializer.js'
const defaultState = { const defaultState = {
localFonts: null, localFonts: null,
themeApplied: false, themeApplied: false,
themeVersion: 'v3', themeVersion: 'v3',
styleNameUsed: null,
styleDataUsed: null,
paletteNameUsed: null,
paletteDataUsed: null,
themeNameUsed: null,
themeDataUsed: null,
temporaryChangesTimeoutId: null, // used for temporary options that revert after a timeout temporaryChangesTimeoutId: null, // used for temporary options that revert after a timeout
temporaryChangesConfirm: () => {}, // used for applying temporary options temporaryChangesConfirm: () => {}, // used for applying temporary options
temporaryChangesRevert: () => {}, // used for reverting temporary options temporaryChangesRevert: () => {}, // used for reverting temporary options
@ -242,7 +249,10 @@ const interfaceMod = {
}, },
async fetchStylesIndex ({ commit, state }) { async fetchStylesIndex ({ commit, state }) {
try { try {
const value = await getResourcesIndex('/static/styles/index.json') const value = await getResourcesIndex(
'/static/styles/index.json',
deserialize
)
commit('setInstanceOption', { name: 'stylesIndex', value }) commit('setInstanceOption', { name: 'stylesIndex', value })
return value return value
} catch (e) { } catch (e) {
@ -310,17 +320,44 @@ const interfaceMod = {
commit('setOption', { name: 'customTheme', value: null }) commit('setOption', { name: 'customTheme', value: null })
commit('setOption', { name: 'customThemeSource', value: null }) commit('setOption', { name: 'customThemeSource', value: null })
}, },
async applyTheme ( async getThemeData ({ dispatch, commit, rootState, state }) {
{ dispatch, commit, rootState, state }, console.log('GET THEME DATA CALLED')
{ recompile = false } = {} const getData = async (resource, index, customData, name) => {
) { const capitalizedResource = resource[0].toUpperCase() + resource.slice(1)
// If we're not not forced to recompile try using const result = {}
// cache (tryLoadCache return true if load successful)
if (customData) {
result.nameUsed = 'custom' // custom data overrides name
result.dataUsed = customData
} else {
result.nameUsed = name
if (result.nameUsed === 'stock') {
result.dataUsed = null
return result
}
let fetchFunc = index[result.nameUsed]
// Fallbacks
if (!fetchFunc) {
const newName = Object.keys(index)[0]
fetchFunc = index[newName]
console.warn(`${capitalizedResource} with id '${state.styleNameUsed}' not found, trying back to '${newName}'`)
if (!fetchFunc) {
console.warn(`${capitalizedResource} doesn't have a fallback, defaulting to stock.`)
fetchFunc = () => Promise.resolve(null)
}
}
result.dataUsed = await fetchFunc()
}
return result
}
const { const {
style: instanceStyleName, style: instanceStyleName,
palette: instancePaletteName palette: instancePaletteName
} = rootState.instance } = rootState.instance
let { let {
theme: instanceThemeV2Name, theme: instanceThemeV2Name,
themesIndex, themesIndex,
@ -332,22 +369,15 @@ const interfaceMod = {
style: userStyleName, style: userStyleName,
styleCustomData: userStyleCustomData, styleCustomData: userStyleCustomData,
palette: userPaletteName, palette: userPaletteName,
paletteCustomData: userPaletteCustomData, paletteCustomData: userPaletteCustomData
forceThemeRecompilation,
themeDebug,
theme3hacks
} = rootState.config } = rootState.config
let { let {
theme: userThemeV2Name, theme: userThemeV2Name,
customTheme: userThemeV2Snapshot, customTheme: userThemeV2Snapshot,
customThemeSource: userThemeV2Source customThemeSource: userThemeV2Source
} = rootState.config } = rootState.config
const forceRecompile = forceThemeRecompilation || recompile
if (!forceRecompile && !themeDebug && tryLoadCache()) {
return commit('setThemeApplied')
}
let majorVersionUsed let majorVersionUsed
console.debug( console.debug(
@ -408,44 +438,6 @@ const interfaceMod = {
state.themeVersion = majorVersionUsed state.themeVersion = majorVersionUsed
let styleDataUsed = null
let styleNameUsed = null
let paletteDataUsed = null
// let paletteNameUsed = null
// let themeNameUsed = null
let themeDataUsed = null
const getData = async (resource, index, customData, name) => {
const capitalizedResource = resource[0].toUpperCase() + resource.slice(1)
const result = {}
if (customData) {
result.nameUsed = 'custom' // custom data overrides name
result.dataUsed = customData
} else {
result.nameUsed = name
if (result.nameUsed === 'stock') {
result.dataUsed = null
return result
}
let fetchFunc = index[result.nameUsed]
// Fallbacks
if (!fetchFunc) {
const newName = Object.keys(index)[0]
fetchFunc = index[newName]
console.warn(`${capitalizedResource} with id '${styleNameUsed}' not found, trying back to '${newName}'`)
if (!fetchFunc) {
console.warn(`${capitalizedResource} doesn't have a fallback, defaulting to stock.`)
fetchFunc = () => Promise.resolve(null)
}
}
result.dataUsed = await fetchFunc()
}
return result
}
console.debug('Version used', majorVersionUsed) console.debug('Version used', majorVersionUsed)
if (majorVersionUsed === 'v3') { if (majorVersionUsed === 'v3') {
@ -455,9 +447,9 @@ const interfaceMod = {
userPaletteCustomData, userPaletteCustomData,
userPaletteName || instancePaletteName userPaletteName || instancePaletteName
) )
// paletteNameUsed = palette.nameUsed state.paletteNameUsed = palette.nameUsed
paletteDataUsed = palette.dataUsed state.paletteDataUsed = palette.dataUsed
if (Array.isArray(paletteDataUsed)) { if (Array.isArray(state.paletteDataUsed)) {
const [ const [
name, name,
bg, bg,
@ -468,10 +460,10 @@ const interfaceMod = {
cGreen = '#00FF00', cGreen = '#00FF00',
cBlue = '#0000FF', cBlue = '#0000FF',
cOrange = '#E3FF00' cOrange = '#E3FF00'
] = paletteDataUsed ] = palette.dataUsed
paletteDataUsed = { name, bg, fg, text, link, cRed, cBlue, cGreen, cOrange } state.paletteDataUsed = { name, bg, fg, text, link, cRed, cBlue, cGreen, cOrange }
} }
console.debug('Palette data used', paletteDataUsed) console.debug('Palette data used', palette.dataUsed)
const style = await getData( const style = await getData(
'style', 'style',
@ -479,8 +471,14 @@ const interfaceMod = {
userStyleCustomData, userStyleCustomData,
userStyleName || instanceStyleName userStyleName || instanceStyleName
) )
styleNameUsed = style.nameUsed state.styleNameUsed = style.nameUsed
styleDataUsed = style.dataUsed state.styleDataUsed = style.dataUsed
console.log(
'GOT THEME DATA',
state.styleDataUsed,
state.paletteDataUsed
)
} else { } else {
const theme = await getData( const theme = await getData(
'theme', 'theme',
@ -489,25 +487,40 @@ const interfaceMod = {
userThemeV2Name || instanceThemeV2Name userThemeV2Name || instanceThemeV2Name
) )
// themeNameUsed = theme.nameUsed // themeNameUsed = theme.nameUsed
themeDataUsed = theme.dataUsed state.themeDataUsed = theme.dataUsed
// Themes v2 editor support
commit('setInstanceOption', { name: 'themeData', value: themeDataUsed })
} }
},
async applyTheme (
{ dispatch, commit, rootState, state },
{ recompile = false } = {}
) {
const {
forceThemeRecompilation,
themeDebug,
theme3hacks
} = rootState.config
// If we're not not forced to recompile try using
// cache (tryLoadCache return true if load successful)
const forceRecompile = forceThemeRecompilation || recompile
if (!forceRecompile && !themeDebug && await tryLoadCache()) {
return commit('setThemeApplied')
}
await dispatch('getThemeData')
// commit('setOption', { name: 'palette', value: paletteNameUsed }) // commit('setOption', { name: 'palette', value: paletteNameUsed })
// commit('setOption', { name: 'style', value: styleNameUsed }) // commit('setOption', { name: 'style', value: styleNameUsed })
// commit('setOption', { name: 'theme', value: themeNameUsed }) // commit('setOption', { name: 'theme', value: themeNameUsed })
const paletteIss = (() => { const paletteIss = (() => {
if (!paletteDataUsed) return null if (!state.paletteDataUsed) return null
const result = { const result = {
component: 'Root', component: 'Root',
directives: {} directives: {}
} }
Object Object
.entries(paletteDataUsed) .entries(state.paletteDataUsed)
.filter(([k]) => k !== 'name') .filter(([k]) => k !== 'name')
.forEach(([k, v]) => { .forEach(([k, v]) => {
let issRootDirectiveName let issRootDirectiveName
@ -526,7 +539,7 @@ const interfaceMod = {
return result return result
})() })()
const theme2ruleset = themeDataUsed && convertTheme2To3(normalizeThemeData(themeDataUsed)) const theme2ruleset = state.themeDataUsed && convertTheme2To3(normalizeThemeData(state.themeDataUsed))
const hacks = [] const hacks = []
Object.entries(theme3hacks).forEach(([key, value]) => { Object.entries(theme3hacks).forEach(([key, value]) => {
@ -593,7 +606,7 @@ const interfaceMod = {
const rulesetArray = [ const rulesetArray = [
theme2ruleset, theme2ruleset,
styleDataUsed, state.styleDataUsed,
paletteIss, paletteIss,
hacks hacks
].filter(x => x) ].filter(x => x)

View file

@ -46,7 +46,7 @@ export const newImporter = ({
const reader = new FileReader() const reader = new FileReader()
reader.onload = ({ target }) => { reader.onload = ({ target }) => {
try { try {
const parsed = parser(target.result) const parsed = parser(target.result, filename)
const validationResult = validator(parsed, filename) const validationResult = validator(parsed, filename)
if (validationResult === true) { if (validationResult === true) {
onImport(parsed, filename) onImport(parsed, filename)

View file

@ -226,7 +226,7 @@ export const applyConfig = (input, i18n) => {
} }
} }
export const getResourcesIndex = async (url) => { export const getResourcesIndex = async (url, parser = JSON.parse) => {
const cache = 'no-store' const cache = 'no-store'
try { try {
@ -243,8 +243,9 @@ export const getResourcesIndex = async (url) => {
k, k,
() => window () => window
.fetch(v, { cache }) .fetch(v, { cache })
.then((data) => data.json()) .then(data => data.text())
.catch((e) => { .then(text => parser(text))
.catch(e => {
console.error(e) console.error(e)
return null return null
}) })

View file

@ -0,0 +1,127 @@
@meta {
name: Redmond DX;
author: HJ;
license: WTFPL;
website: ebin.club;
}
@palette.Modern {
bg: #D3CFC7;
fg: #092369;
text: #000000;
link: #0000FF;
accent: #A5C9F0;
cRed: #FF3000;
cBlue: #009EFF;
cGreen: #309E00;
cOrange: #FFCE00;
}
@palette.Classic {
bg: #BFBFBF;
fg: #000180;
text: #000000;
link: #0000FF;
accent: #A5C9F0;
cRed: #FF0000;
cBlue: #2E2ECE;
cGreen: #007E00;
cOrange: #CE8F5F;
}
@palette.Vapor {
bg: #F0ADCD;
fg: #bca4ee;
text: #602040;
link: #064745;
accent: #9DF7C8;
cRed: #86004a;
cBlue: #0e5663;
cGreen: #0a8b51;
cOrange: #787424;
}
Root {
--gradientColor: color | --accent;
--inputColor: color | #FFFFFF;
--bevelLight: color | $brightness(--bg 50);
--bevelDark: color | $brightness(--bg -20);
--bevelExtraDark: color | #404040;
--buttonDefaultBevel: shadow | $borderSide(--bevelExtraDark bottom-right 1 1), $borderSide(--bevelLight top-left 1 1), $borderSide(--bevelDark bottom-right 1 2);
--buttonPressedBevel: shadow | inset 0 0 0 1 #000000 / 1 #Outer , inset 0 0 0 2 --bevelExtraDark / 1 #inner;
--defaultInputBevel: shadow | $borderSide(--bevelLight bottom-right 1), $borderSide(--bevelDark top-left 1 1), $borderSide(--bg bottom-right 1 2), $borderSide(--bevelExtraDark top-left 1 2);
}
Button:toggled {
background: --bg;
shadow: --buttonPressedBevel
}
Button:focused {
shadow: --buttonDefaultBevel, 0 0 0 1 #000000 / 1
}
Button:pressed {
shadow: --buttonPressedBevel
}
Button:hover {
shadow: --buttonDefaultBevel;
background: --bg
}
Button {
shadow: --buttonDefaultBevel;
background: --bg;
roundness: 0
}
Button:pressed:hover {
shadow: --buttonPressedBevel
}
Input {
background: $mod(--bg -80);
shadow: --defaultInputBevel;
roundness: 0
}
Panel {
shadow: --buttonDefaultBevel;
roundness: 0
}
PanelHeader {
shadow: inset -1100 0 1000 -1000 --gradientColor / 1 #Gradient ;
background: --fg
}
Tab:hover {
background: --bg;
shadow: --buttonDefaultBevel
}
Tab:active {
background: --bg
}
Tab:active:hover {
background: --bg
}
Tab:active:hover:disabled {
background: --bg
}
Tab:hover:disabled {
background: --bg
}
Tab:disabled {
background: --bg
}
Tab {
background: --bg;
shadow: --buttonDefaultBevel
}

3
static/styles/index.json Normal file
View file

@ -0,0 +1,3 @@
{
"RedmondDX": "/static/styles/Redmond DX.piss"
}