palettes that actually work
This commit is contained in:
parent
07a48315a1
commit
f0957bdb4f
|
@ -63,11 +63,17 @@ export default {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
state: ['hover', 'pressed'],
|
state: ['pressed', 'hover'],
|
||||||
directives: {
|
directives: {
|
||||||
shadow: ['--defaultButtonHoverGlow', '--pressedButtonBevel']
|
shadow: ['--defaultButtonHoverGlow', '--pressedButtonBevel']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
state: ['pressed', 'hover', 'focused'],
|
||||||
|
directives: {
|
||||||
|
shadow: ['--pressedButtonBevel']
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
state: ['toggled'],
|
state: ['toggled'],
|
||||||
directives: {
|
directives: {
|
||||||
|
|
|
@ -1,21 +1,73 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="PaletteEditor">
|
<div class="PaletteEditor">
|
||||||
|
<div class="colors">
|
||||||
<ColorInput
|
<ColorInput
|
||||||
v-for="key in paletteKeys"
|
v-for="key in paletteKeys"
|
||||||
:key="key"
|
:key="key"
|
||||||
:model-value="props.modelValue[key]"
|
:model-value="props.modelValue[key]"
|
||||||
:fallback="fallback(key)"
|
:fallback="fallback(key)"
|
||||||
:label="$t('settings.style.themes3.editor.palette.' + key)"
|
:label="$t('settings.style.themes3.palette.' + key)"
|
||||||
@update:modelValue="value => updatePalette(key, value)"
|
@update:modelValue="value => updatePalette(key, value)"
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="controls">
|
||||||
|
<button
|
||||||
|
class="btn button-default"
|
||||||
|
@click="importPalette"
|
||||||
|
>
|
||||||
|
<FAIcon icon="file-import"/>
|
||||||
|
{{ $t('settings.style.themes3.palette.import') }}
|
||||||
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn button-default"
|
||||||
|
@click="exportPalette"
|
||||||
|
>
|
||||||
|
<FAIcon icon="file-export"/>
|
||||||
|
{{ $t('settings.style.themes3.palette.export') }}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
import ColorInput from 'src/components/color_input/color_input.vue'
|
import ColorInput from 'src/components/color_input/color_input.vue'
|
||||||
|
import {
|
||||||
|
// newImporter,
|
||||||
|
newExporter
|
||||||
|
} from 'src/services/export_import/export_import.js'
|
||||||
|
|
||||||
|
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
|
import {
|
||||||
|
faFileImport,
|
||||||
|
faFileExport
|
||||||
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
|
||||||
|
library.add(
|
||||||
|
faFileImport,
|
||||||
|
faFileExport
|
||||||
|
)
|
||||||
|
|
||||||
const props = defineProps(['modelValue'])
|
const props = defineProps(['modelValue'])
|
||||||
const emit = defineEmits(['update:modelValue'])
|
const emit = defineEmits(['update:modelValue'])
|
||||||
|
const paletteExporter = newExporter({
|
||||||
|
filename: 'pleroma.palette.json',
|
||||||
|
getExportedObject: () => props.modelValue
|
||||||
|
})
|
||||||
|
/*
|
||||||
|
const themeImporter = newImporter({
|
||||||
|
validator: importValidator,
|
||||||
|
onImport,
|
||||||
|
onImportFailure,
|
||||||
|
})
|
||||||
|
*/
|
||||||
|
|
||||||
|
const exportPalette = () => {
|
||||||
|
paletteExporter.exportData()
|
||||||
|
}
|
||||||
|
|
||||||
|
const importPalette = () => {
|
||||||
|
// TODO
|
||||||
|
}
|
||||||
|
|
||||||
const paletteKeys = [
|
const paletteKeys = [
|
||||||
'bg',
|
'bg',
|
||||||
|
@ -40,7 +92,7 @@ const fallback = (key) => {
|
||||||
return props.modelValue.accent
|
return props.modelValue.accent
|
||||||
}
|
}
|
||||||
if (key.startsWith('extra')) {
|
if (key.startsWith('extra')) {
|
||||||
return '#000000'
|
return '#008080'
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -54,10 +106,18 @@ const updatePalette = (paletteKey, value) => {
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss">
|
||||||
.PaletteEditor {
|
.PaletteEditor {
|
||||||
|
.colors {
|
||||||
display: grid;
|
display: grid;
|
||||||
justify-content: space-around;
|
justify-content: space-around;
|
||||||
grid-template-columns: repeat(4, min-content);
|
grid-template-columns: repeat(4, min-content);
|
||||||
grid-template-rows: repeat(auto-fit, min-content);
|
grid-template-rows: repeat(auto-fit, min-content);
|
||||||
grid-gap: 0.5em;
|
grid-gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-gap: 0.5em;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -9,7 +9,7 @@ import FontControl from 'src/components/font_control/font_control.vue'
|
||||||
import { normalizeThemeData } from 'src/modules/interface'
|
import { normalizeThemeData } from 'src/modules/interface'
|
||||||
|
|
||||||
import {
|
import {
|
||||||
getThemes
|
getThemeResources
|
||||||
} from 'src/services/style_setter/style_setter.js'
|
} from 'src/services/style_setter/style_setter.js'
|
||||||
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
import { convertTheme2To3 } from 'src/services/theme_data/theme2_to_theme3.js'
|
||||||
import { init } from 'src/services/theme_data/theme_data_3.service.js'
|
import { init } from 'src/services/theme_data/theme_data_3.service.js'
|
||||||
|
@ -35,6 +35,17 @@ const AppearanceTab = {
|
||||||
data () {
|
data () {
|
||||||
return {
|
return {
|
||||||
availableStyles: [],
|
availableStyles: [],
|
||||||
|
availablePalettes: [],
|
||||||
|
palettesKeys: [
|
||||||
|
'background',
|
||||||
|
'foreground',
|
||||||
|
'link',
|
||||||
|
'text',
|
||||||
|
'cRed',
|
||||||
|
'cBlue',
|
||||||
|
'cGreen',
|
||||||
|
'cOrange'
|
||||||
|
],
|
||||||
intersectionObserver: null,
|
intersectionObserver: null,
|
||||||
thirdColumnModeOptions: ['none', 'notifications', 'postform'].map(mode => ({
|
thirdColumnModeOptions: ['none', 'notifications', 'postform'].map(mode => ({
|
||||||
key: mode,
|
key: mode,
|
||||||
|
@ -64,29 +75,36 @@ const AppearanceTab = {
|
||||||
Preview
|
Preview
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
getThemes()
|
getThemeResources('/static/styles.json')
|
||||||
.then((promises) => {
|
.then((themes) => {
|
||||||
return Promise.all(
|
this.availableStyles = Object
|
||||||
Object.entries(promises)
|
.entries(themes)
|
||||||
.map(([k, v]) => v.then(res => [k, res]))
|
.map(([key, data]) => ({ key, data, name: data.name || data[0], version: 'v2' }))
|
||||||
)
|
|
||||||
})
|
})
|
||||||
.then(themes => themes.reduce((acc, [k, v]) => {
|
|
||||||
if (v) {
|
getThemeResources('/static/palettes/index.json')
|
||||||
return [
|
.then((palettes) => {
|
||||||
...acc,
|
const result = {}
|
||||||
{
|
console.log(palettes)
|
||||||
name: v.name || v[0],
|
Object.entries(palettes).forEach(([k, v]) => {
|
||||||
key: k,
|
if (Array.isArray(v)) {
|
||||||
data: v
|
const [
|
||||||
}
|
name,
|
||||||
]
|
background,
|
||||||
|
foreground,
|
||||||
|
text,
|
||||||
|
link,
|
||||||
|
cRed = '#FF0000',
|
||||||
|
cBlue = '#0000FF',
|
||||||
|
cGreen = '#00FF00',
|
||||||
|
cOrange = '#E3FF00'
|
||||||
|
] = v
|
||||||
|
result[k] = { name, background, foreground, text, link, cRed, cBlue, cGreen, cOrange }
|
||||||
} else {
|
} else {
|
||||||
return acc
|
result[k] = v
|
||||||
}
|
}
|
||||||
}, []))
|
})
|
||||||
.then((themesComplete) => {
|
this.availablePalettes = result
|
||||||
this.availableStyles = themesComplete
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (window.IntersectionObserver) {
|
if (window.IntersectionObserver) {
|
||||||
|
@ -171,18 +189,30 @@ const AppearanceTab = {
|
||||||
setTheme (name) {
|
setTheme (name) {
|
||||||
this.$store.dispatch('setTheme', { themeName: name, saveData: true, recompile: true })
|
this.$store.dispatch('setTheme', { themeName: name, saveData: true, recompile: true })
|
||||||
},
|
},
|
||||||
|
setPalette (name) {
|
||||||
|
this.$store.dispatch('setPalette', { paletteData: name })
|
||||||
|
},
|
||||||
previewTheme (key, input) {
|
previewTheme (key, input) {
|
||||||
|
let theme3
|
||||||
|
if (input) {
|
||||||
const style = normalizeThemeData(input)
|
const style = normalizeThemeData(input)
|
||||||
const x = 2
|
|
||||||
if (x === 1) return
|
|
||||||
const theme2 = convertTheme2To3(style)
|
const theme2 = convertTheme2To3(style)
|
||||||
const theme3 = init({
|
theme3 = init({
|
||||||
inputRuleset: theme2,
|
inputRuleset: theme2,
|
||||||
ultimateBackgroundColor: '#000000',
|
ultimateBackgroundColor: '#000000',
|
||||||
liteMode: true,
|
liteMode: true,
|
||||||
debug: true,
|
debug: true,
|
||||||
onlyNormalState: true
|
onlyNormalState: true
|
||||||
})
|
})
|
||||||
|
} else {
|
||||||
|
theme3 = init({
|
||||||
|
inputRuleset: [],
|
||||||
|
ultimateBackgroundColor: '#000000',
|
||||||
|
liteMode: true,
|
||||||
|
debug: true,
|
||||||
|
onlyNormalState: true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return getScopedVersion(
|
return getScopedVersion(
|
||||||
getCssRules(theme3.eager),
|
getCssRules(theme3.eager),
|
||||||
|
|
76
src/components/settings_modal/tabs/appearance_tab.scss
Normal file
76
src/components/settings_modal/tabs/appearance_tab.scss
Normal file
|
@ -0,0 +1,76 @@
|
||||||
|
.appearance-tab {
|
||||||
|
.palette,
|
||||||
|
.theme-notice {
|
||||||
|
padding: 0.5em;
|
||||||
|
margin: 1em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palettes {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 1fr 1fr;
|
||||||
|
grid-gap: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palette-entry {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
|
||||||
|
> label {
|
||||||
|
flex: 1 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.palette-square {
|
||||||
|
flex: 0 0 auto;
|
||||||
|
display: inline-block;
|
||||||
|
min-width: 1em;
|
||||||
|
min-height: 1em;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-settings {
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-evenly;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.column-settings .size-label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5em;
|
||||||
|
margin-top: 0.5em;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-list {
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
margin: -0.5em 0;
|
||||||
|
height: 25em;
|
||||||
|
overflow-x: hidden;
|
||||||
|
overflow-y: auto;
|
||||||
|
scrollbar-gutter: stable;
|
||||||
|
border-radius: var(--roundness);
|
||||||
|
border: 1px solid var(--border);
|
||||||
|
padding: 0;
|
||||||
|
|
||||||
|
.theme-preview {
|
||||||
|
font-size: 1rem; // fix for firefox
|
||||||
|
width: 19rem;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
margin: 0.5em;
|
||||||
|
|
||||||
|
&.placeholder {
|
||||||
|
opacity: 0.2;
|
||||||
|
}
|
||||||
|
|
||||||
|
.theme-preview-container {
|
||||||
|
pointer-events: none;
|
||||||
|
zoom: 0.5;
|
||||||
|
border: none;
|
||||||
|
border-radius: var(--roundness);
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -6,13 +6,33 @@
|
||||||
class="theme-list"
|
class="theme-list"
|
||||||
ref="themeList"
|
ref="themeList"
|
||||||
>
|
>
|
||||||
|
<button
|
||||||
|
class="button-default theme-preview"
|
||||||
|
data-theme-key="stock"
|
||||||
|
@click="setTheme(null)"
|
||||||
|
>
|
||||||
|
<!-- eslint-disable vue/no-v-text-v-html-on-component -->
|
||||||
|
<component
|
||||||
|
:is="'style'"
|
||||||
|
v-html="previewTheme('stock')"
|
||||||
|
/>
|
||||||
|
<!-- eslint-enable vue/no-v-text-v-html-on-component -->
|
||||||
|
<preview />
|
||||||
|
<h4 class="theme-name">
|
||||||
|
{{ $t('settings.style.stock_theme_used') }}
|
||||||
|
<span class="alert neutral version">v3</span>
|
||||||
|
</h4>
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="isCustomThemeUsed"
|
v-if="isCustomThemeUsed"
|
||||||
disabled
|
disabled
|
||||||
class="button-default theme-preview"
|
class="button-default theme-preview"
|
||||||
>
|
>
|
||||||
<preview />
|
<preview />
|
||||||
<h4 class="theme-name">{{ $t('settings.style.custom_theme_used') }}</h4>
|
<h4 class="theme-name">
|
||||||
|
{{ $t('settings.style.custom_theme_used') }}
|
||||||
|
<span class="alert neutral version">v2</span>
|
||||||
|
</h4>
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-for="style in availableStyles"
|
v-for="style in availableStyles"
|
||||||
|
@ -30,9 +50,31 @@
|
||||||
/>
|
/>
|
||||||
<!-- eslint-enable vue/no-v-text-v-html-on-component -->
|
<!-- eslint-enable vue/no-v-text-v-html-on-component -->
|
||||||
<preview :class="{ placeholder: ready }" :id="'theme-preview-' + style.key"/>
|
<preview :class="{ placeholder: ready }" :id="'theme-preview-' + style.key"/>
|
||||||
<h4 class="theme-name">{{ style.name }}</h4>
|
<h4 class="theme-name">
|
||||||
|
{{ style.name }}
|
||||||
|
<span class="alert neutral version">{{ style.version }}</span>
|
||||||
|
</h4>
|
||||||
</button>
|
</button>
|
||||||
</ul>
|
</ul>
|
||||||
|
<h3>{{ $t('settings.style.themes3.palette.label') }}</h3>
|
||||||
|
<div class="palettes">
|
||||||
|
<button
|
||||||
|
v-for="p in availablePalettes"
|
||||||
|
class="btn button-default palette-entry"
|
||||||
|
:key="p.name"
|
||||||
|
@click="() => setPalette(p)"
|
||||||
|
>
|
||||||
|
<label>
|
||||||
|
{{ p.name }}
|
||||||
|
</label>
|
||||||
|
<span
|
||||||
|
v-for="c in palettesKeys"
|
||||||
|
:key="c"
|
||||||
|
class="palette-square"
|
||||||
|
:style="{ backgroundColor: p[c], border: '1px solid ' + (p[c] ?? 'var(--text)') }"
|
||||||
|
/>
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="alert neutral theme-notice">
|
<div class="alert neutral theme-notice">
|
||||||
{{ $t("settings.style.appearance_tab_note") }}
|
{{ $t("settings.style.appearance_tab_note") }}
|
||||||
|
@ -256,58 +298,4 @@
|
||||||
|
|
||||||
<script src="./appearance_tab.js"></script>
|
<script src="./appearance_tab.js"></script>
|
||||||
|
|
||||||
<style lang="scss">
|
<style lang="scss" src="./appearance_tab.scss"></style>
|
||||||
.appearance-tab {
|
|
||||||
.theme-notice {
|
|
||||||
padding: 0.5em;
|
|
||||||
margin: 1em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.column-settings {
|
|
||||||
display: flex;
|
|
||||||
justify-content: space-evenly;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
}
|
|
||||||
|
|
||||||
.column-settings .size-label {
|
|
||||||
display: block;
|
|
||||||
margin-bottom: 0.5em;
|
|
||||||
margin-top: 0.5em;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-list {
|
|
||||||
list-style: none;
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: wrap;
|
|
||||||
margin: -0.5em 0;
|
|
||||||
height: 25em;
|
|
||||||
overflow-x: hidden;
|
|
||||||
overflow-y: auto;
|
|
||||||
scrollbar-gutter: stable;
|
|
||||||
border-radius: var(--roundness);
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
padding: 0;
|
|
||||||
|
|
||||||
.theme-preview {
|
|
||||||
font-size: 1rem; // fix for firefox
|
|
||||||
width: 19rem;
|
|
||||||
display: flex;
|
|
||||||
flex-direction: column;
|
|
||||||
align-items: center;
|
|
||||||
margin: 0.5em;
|
|
||||||
|
|
||||||
&.placeholder {
|
|
||||||
opacity: 0.2;
|
|
||||||
}
|
|
||||||
|
|
||||||
.theme-preview-container {
|
|
||||||
pointer-events: none;
|
|
||||||
zoom: 0.5;
|
|
||||||
border: none;
|
|
||||||
border-radius: var(--roundness);
|
|
||||||
text-align: left;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
|
@ -54,7 +54,7 @@
|
||||||
<div class="setting-item palette-editor">
|
<div class="setting-item palette-editor">
|
||||||
<div class="label">
|
<div class="label">
|
||||||
<label for="palette-selector">
|
<label for="palette-selector">
|
||||||
{{ $t('settings.style.themes3.editor.palette.label') }}
|
{{ $t('settings.style.themes3.palette.label') }}
|
||||||
{{ ' ' }}
|
{{ ' ' }}
|
||||||
</label>
|
</label>
|
||||||
<Select
|
<Select
|
||||||
|
@ -62,10 +62,10 @@
|
||||||
id="palette-selector"
|
id="palette-selector"
|
||||||
>
|
>
|
||||||
<option key="dark" value="dark">
|
<option key="dark" value="dark">
|
||||||
{{ $t('settings.style.themes3.editor.palette.dark') }}
|
{{ $t('settings.style.themes3.palette.dark') }}
|
||||||
</option>
|
</option>
|
||||||
<option key="light" value="light">
|
<option key="light" value="light">
|
||||||
{{ $t('settings.style.themes3.editor.palette.light') }}
|
{{ $t('settings.style.themes3.palette.light') }}
|
||||||
</option>
|
</option>
|
||||||
</Select>
|
</Select>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -5,7 +5,7 @@ import {
|
||||||
relativeLuminance
|
relativeLuminance
|
||||||
} from 'src/services/color_convert/color_convert.js'
|
} from 'src/services/color_convert/color_convert.js'
|
||||||
import {
|
import {
|
||||||
getThemes
|
getThemeResources
|
||||||
} from 'src/services/style_setter/style_setter.js'
|
} from 'src/services/style_setter/style_setter.js'
|
||||||
import {
|
import {
|
||||||
newImporter,
|
newImporter,
|
||||||
|
@ -125,25 +125,9 @@ export default {
|
||||||
created () {
|
created () {
|
||||||
const self = this
|
const self = this
|
||||||
|
|
||||||
getThemes()
|
getThemeResources('/static/styles.json')
|
||||||
.then((promises) => {
|
|
||||||
return Promise.all(
|
|
||||||
Object.entries(promises)
|
|
||||||
.map(([k, v]) => v.then(res => [k, res]))
|
|
||||||
)
|
|
||||||
})
|
|
||||||
.then(themes => themes.reduce((acc, [k, v]) => {
|
|
||||||
if (v) {
|
|
||||||
return {
|
|
||||||
...acc,
|
|
||||||
[k]: v
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return acc
|
|
||||||
}
|
|
||||||
}, {}))
|
|
||||||
.then((themesComplete) => {
|
.then((themesComplete) => {
|
||||||
self.availableStyles = themesComplete
|
self.availableStyles = Object.values(themesComplete)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
@ -412,9 +396,6 @@ export default {
|
||||||
forceUseSource = false
|
forceUseSource = false
|
||||||
) {
|
) {
|
||||||
this.dismissWarning()
|
this.dismissWarning()
|
||||||
if (!source && !theme) {
|
|
||||||
throw new Error('Can\'t load theme: empty')
|
|
||||||
}
|
|
||||||
const version = (origin === 'localStorage' && !theme.colors)
|
const version = (origin === 'localStorage' && !theme.colors)
|
||||||
? 'l1'
|
? 'l1'
|
||||||
: fileVersion
|
: fileVersion
|
||||||
|
@ -494,14 +475,7 @@ export default {
|
||||||
customTheme: theme,
|
customTheme: theme,
|
||||||
customThemeSource: source
|
customThemeSource: source
|
||||||
} = this.$store.getters.mergedConfig
|
} = this.$store.getters.mergedConfig
|
||||||
if (!theme && !source) {
|
if (theme || source) {
|
||||||
// Anon user or never touched themes
|
|
||||||
this.loadTheme(
|
|
||||||
this.$store.state.instance.themeData,
|
|
||||||
'defaults',
|
|
||||||
confirmLoadSource
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
this.loadTheme(
|
this.loadTheme(
|
||||||
{
|
{
|
||||||
theme,
|
theme,
|
||||||
|
|
|
@ -748,11 +748,31 @@
|
||||||
"more_settings": "More settings",
|
"more_settings": "More settings",
|
||||||
"style": {
|
"style": {
|
||||||
"custom_theme_used": "(Custom theme)",
|
"custom_theme_used": "(Custom 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",
|
||||||
"update_preview": "Update preview",
|
"update_preview": "Update preview",
|
||||||
"themes3": {
|
"themes3": {
|
||||||
"define": "Override",
|
"define": "Override",
|
||||||
|
"palette": {
|
||||||
|
"label": "Palette",
|
||||||
|
"import": "Import",
|
||||||
|
"export": "Export",
|
||||||
|
"dark": "Dark mode",
|
||||||
|
"light": "Light mode",
|
||||||
|
"bg": "Panel background",
|
||||||
|
"fg": "Buttons etc.",
|
||||||
|
"text": "Text",
|
||||||
|
"link": "Links",
|
||||||
|
"accent": "Accent color",
|
||||||
|
"cRed": "Red color",
|
||||||
|
"cBlue": "Blue color",
|
||||||
|
"cGreen": "Green color",
|
||||||
|
"cOrange": "Orange color",
|
||||||
|
"extra1": "Extra 1",
|
||||||
|
"extra2": "Extra 2",
|
||||||
|
"extra3": "Extra 3"
|
||||||
|
},
|
||||||
"editor": {
|
"editor": {
|
||||||
"title": "Style",
|
"title": "Style",
|
||||||
"new_style": "New",
|
"new_style": "New",
|
||||||
|
@ -778,23 +798,6 @@
|
||||||
"preserve": "Keep color",
|
"preserve": "Keep color",
|
||||||
"no-auto": "Disabled"
|
"no-auto": "Disabled"
|
||||||
},
|
},
|
||||||
"palette": {
|
|
||||||
"label": "Palette",
|
|
||||||
"dark": "Dark mode",
|
|
||||||
"light": "Light mode",
|
|
||||||
"bg": "Panel background",
|
|
||||||
"fg": "Buttons etc.",
|
|
||||||
"text": "Text",
|
|
||||||
"link": "Links",
|
|
||||||
"accent": "Accent color",
|
|
||||||
"cRed": "Red color",
|
|
||||||
"cBlue": "Blue color",
|
|
||||||
"cGreen": "Green color",
|
|
||||||
"cOrange": "Orange color",
|
|
||||||
"extra1": "Extra 1",
|
|
||||||
"extra2": "Extra 2",
|
|
||||||
"extra3": "Extra 3"
|
|
||||||
},
|
|
||||||
"components": {
|
"components": {
|
||||||
"normal": {
|
"normal": {
|
||||||
"state": "Normal",
|
"state": "Normal",
|
||||||
|
|
|
@ -212,6 +212,11 @@ const interfaceMod = {
|
||||||
setLastTimeline ({ commit }, value) {
|
setLastTimeline ({ commit }, value) {
|
||||||
commit('setLastTimeline', value)
|
commit('setLastTimeline', value)
|
||||||
},
|
},
|
||||||
|
setPalette ({ dispatch, commit }, { paletteData }) {
|
||||||
|
console.log('PAL', paletteData)
|
||||||
|
commit('setOption', { name: 'userPalette', value: paletteData })
|
||||||
|
dispatch('setTheme', { themeName: null, recompile: true })
|
||||||
|
},
|
||||||
setTheme ({ commit, rootState }, { themeName, themeData, recompile, saveData } = {}) {
|
setTheme ({ commit, rootState }, { themeName, themeData, recompile, saveData } = {}) {
|
||||||
const {
|
const {
|
||||||
theme: instanceThemeName
|
theme: instanceThemeName
|
||||||
|
@ -221,21 +226,52 @@ const interfaceMod = {
|
||||||
theme: userThemeName,
|
theme: userThemeName,
|
||||||
customTheme: userThemeSnapshot,
|
customTheme: userThemeSnapshot,
|
||||||
customThemeSource: userThemeSource,
|
customThemeSource: userThemeSource,
|
||||||
|
userPalette,
|
||||||
forceThemeRecompilation,
|
forceThemeRecompilation,
|
||||||
themeDebug,
|
themeDebug,
|
||||||
theme3hacks
|
theme3hacks
|
||||||
} = rootState.config
|
} = rootState.config
|
||||||
|
|
||||||
|
const userPaletteIss = (() => {
|
||||||
|
if (!userPalette) return null
|
||||||
|
const result = {
|
||||||
|
component: 'Root',
|
||||||
|
directives: {}
|
||||||
|
}
|
||||||
|
|
||||||
|
Object
|
||||||
|
.entries(userPalette)
|
||||||
|
.filter(([k]) => k !== 'name')
|
||||||
|
.forEach(([k, v]) => {
|
||||||
|
let issRootDirectiveName
|
||||||
|
switch (k) {
|
||||||
|
case 'background':
|
||||||
|
issRootDirectiveName = 'bg'
|
||||||
|
break
|
||||||
|
case 'foreground':
|
||||||
|
issRootDirectiveName = 'fg'
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
issRootDirectiveName = k
|
||||||
|
}
|
||||||
|
result.directives['--' + issRootDirectiveName] = 'color | ' + v
|
||||||
|
})
|
||||||
|
return result
|
||||||
|
})()
|
||||||
const actualThemeName = userThemeName || instanceThemeName
|
const actualThemeName = userThemeName || instanceThemeName
|
||||||
|
|
||||||
const forceRecompile = forceThemeRecompilation || recompile
|
const forceRecompile = forceThemeRecompilation || recompile
|
||||||
|
|
||||||
let promise = null
|
let promise = null
|
||||||
|
|
||||||
|
console.log('TEST', actualThemeName, themeData)
|
||||||
|
|
||||||
if (themeData) {
|
if (themeData) {
|
||||||
promise = Promise.resolve(normalizeThemeData(themeData))
|
promise = Promise.resolve(normalizeThemeData(themeData))
|
||||||
} else if (themeName) {
|
} else if (themeName) {
|
||||||
promise = getPreset(themeName).then(themeData => normalizeThemeData(themeData))
|
promise = getPreset(themeName).then(themeData => normalizeThemeData(themeData))
|
||||||
|
} else if (themeName === null) {
|
||||||
|
promise = Promise.resolve(null)
|
||||||
} else if (userThemeSource || userThemeSnapshot) {
|
} else if (userThemeSource || userThemeSnapshot) {
|
||||||
promise = Promise.resolve(normalizeThemeData({
|
promise = Promise.resolve(normalizeThemeData({
|
||||||
_pleroma_theme_version: 2,
|
_pleroma_theme_version: 2,
|
||||||
|
@ -264,13 +300,14 @@ const interfaceMod = {
|
||||||
|
|
||||||
promise
|
promise
|
||||||
.then(realThemeData => {
|
.then(realThemeData => {
|
||||||
const theme2ruleset = convertTheme2To3(realThemeData)
|
const theme2ruleset = realThemeData ? convertTheme2To3(realThemeData) : null
|
||||||
|
|
||||||
if (saveData) {
|
if (saveData) {
|
||||||
commit('setOption', { name: 'theme', value: themeName || actualThemeName })
|
commit('setOption', { name: 'theme', value: themeName || actualThemeName })
|
||||||
commit('setOption', { name: 'customTheme', value: realThemeData })
|
commit('setOption', { name: 'customTheme', value: realThemeData })
|
||||||
commit('setOption', { name: 'customThemeSource', value: realThemeData })
|
commit('setOption', { name: 'customThemeSource', value: realThemeData })
|
||||||
}
|
}
|
||||||
|
|
||||||
const hacks = []
|
const hacks = []
|
||||||
|
|
||||||
Object.entries(theme3hacks).forEach(([key, value]) => {
|
Object.entries(theme3hacks).forEach(([key, value]) => {
|
||||||
|
@ -336,9 +373,15 @@ const interfaceMod = {
|
||||||
})
|
})
|
||||||
|
|
||||||
const ruleset = [
|
const ruleset = [
|
||||||
...theme2ruleset,
|
|
||||||
...hacks
|
...hacks
|
||||||
]
|
]
|
||||||
|
if (!theme2ruleset && userPaletteIss) {
|
||||||
|
ruleset.unshift(userPaletteIss)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (theme2ruleset) {
|
||||||
|
ruleset.unshift(...theme2ruleset)
|
||||||
|
}
|
||||||
|
|
||||||
applyTheme(
|
applyTheme(
|
||||||
ruleset,
|
ruleset,
|
||||||
|
@ -355,6 +398,7 @@ const interfaceMod = {
|
||||||
export default interfaceMod
|
export default interfaceMod
|
||||||
|
|
||||||
export const normalizeThemeData = (input) => {
|
export const normalizeThemeData = (input) => {
|
||||||
|
console.log(input)
|
||||||
if (Array.isArray(input)) {
|
if (Array.isArray(input)) {
|
||||||
const themeData = { colors: {} }
|
const themeData = { colors: {} }
|
||||||
themeData.colors.bg = input[1]
|
themeData.colors.bg = input[1]
|
||||||
|
@ -365,7 +409,7 @@ export const normalizeThemeData = (input) => {
|
||||||
themeData.colors.cGreen = input[6]
|
themeData.colors.cGreen = input[6]
|
||||||
themeData.colors.cBlue = input[7]
|
themeData.colors.cBlue = input[7]
|
||||||
themeData.colors.cOrange = input[8]
|
themeData.colors.cOrange = input[8]
|
||||||
return generatePreset(themeData).theme
|
return generatePreset(themeData).source || generatePreset(themeData).theme
|
||||||
}
|
}
|
||||||
|
|
||||||
let themeData, themeSource
|
let themeData, themeSource
|
||||||
|
|
|
@ -256,13 +256,13 @@ export const applyConfig = (input) => {
|
||||||
body.classList.remove('hidden')
|
body.classList.remove('hidden')
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getThemes = () => {
|
export const getThemeResources = (url) => {
|
||||||
const cache = 'no-store'
|
const cache = 'no-store'
|
||||||
|
|
||||||
return window.fetch('/static/styles.json', { cache })
|
return window.fetch(url, { cache })
|
||||||
.then((data) => data.json())
|
.then((data) => data.json())
|
||||||
.then((themes) => {
|
.then((resources) => {
|
||||||
return Object.entries(themes).map(([k, v]) => {
|
return Object.entries(resources).map(([k, v]) => {
|
||||||
let promise = null
|
let promise = null
|
||||||
if (typeof v === 'object') {
|
if (typeof v === 'object') {
|
||||||
promise = Promise.resolve(v)
|
promise = Promise.resolve(v)
|
||||||
|
@ -284,10 +284,26 @@ export const getThemes = () => {
|
||||||
return acc
|
return acc
|
||||||
}, {})
|
}, {})
|
||||||
})
|
})
|
||||||
|
.then((promises) => {
|
||||||
|
return Promise.all(
|
||||||
|
Object.entries(promises)
|
||||||
|
.map(([k, v]) => v.then(res => [k, res]))
|
||||||
|
)
|
||||||
|
})
|
||||||
|
.then(themes => themes.reduce((acc, [k, v]) => {
|
||||||
|
if (v) {
|
||||||
|
return {
|
||||||
|
...acc,
|
||||||
|
[k]: v
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return acc
|
||||||
|
}
|
||||||
|
}, {}))
|
||||||
}
|
}
|
||||||
|
|
||||||
export const getPreset = (val) => {
|
export const getPreset = (val) => {
|
||||||
return getThemes()
|
return getThemeResources('/static/styles.json')
|
||||||
.then((themes) => themes[val] ? themes[val] : themes['pleroma-dark'])
|
.then((themes) => themes[val] ? themes[val] : themes['pleroma-dark'])
|
||||||
.then((theme) => {
|
.then((theme) => {
|
||||||
const isV1 = Array.isArray(theme)
|
const isV1 = Array.isArray(theme)
|
||||||
|
|
32
static/palettes/index.json
Normal file
32
static/palettes/index.json
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
{
|
||||||
|
"pleroma-light": [ "Pleroma Light", "#f2f4f6", "#dbe0e8", "#304055", "#f86f0f", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
|
||||||
|
"pleroma-dark": [ "Pleroma Dark", "#121a24", "#182230", "#b9b9ba", "#d8a070", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
|
||||||
|
"classic-dark": {
|
||||||
|
"name": "Classic Dark",
|
||||||
|
"background": "#161c20",
|
||||||
|
"foreground": "#282e32",
|
||||||
|
"text": "#b9b9b9",
|
||||||
|
"link": "#baaa9c",
|
||||||
|
"cRed": "#d31014",
|
||||||
|
"cBlue": "#0fa00f",
|
||||||
|
"cGreen": "#0095ff",
|
||||||
|
"cOrange": "#ffa500"
|
||||||
|
},
|
||||||
|
"pleroma-amoled": [ "Pleroma Dark AMOLED", "#000000", "#111111", "#b0b0b1", "#d8a070", "#aa0000", "#0fa00f", "#0095ff", "#d59500"],
|
||||||
|
"tomorrow-night": {
|
||||||
|
"name": "Tomorrow Night",
|
||||||
|
"background": "#1d1f21",
|
||||||
|
"foreground": "#373b41",
|
||||||
|
"link": "#81a2be",
|
||||||
|
"text": "#c5c8c6",
|
||||||
|
"cRed": "#cc6666",
|
||||||
|
"cBlue": "#8abeb7",
|
||||||
|
"cGreen": "#b5bd68",
|
||||||
|
"cOrange": "#de935f",
|
||||||
|
"_cYellow": "#f0c674",
|
||||||
|
"_cPurple": "#b294bb"
|
||||||
|
},
|
||||||
|
"bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"],
|
||||||
|
"ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ],
|
||||||
|
"monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672", "#F92672", "#a6e22e", "#66d9ef", "#f4bf75" ]
|
||||||
|
}
|
|
@ -1,12 +1,6 @@
|
||||||
{
|
{
|
||||||
"pleroma-dark": "/static/themes/pleroma-dark.json",
|
"pleroma-dark": "/static/themes/pleroma-dark.json",
|
||||||
"pleroma-light": "/static/themes/pleroma-light.json",
|
"pleroma-light": "/static/themes/pleroma-light.json",
|
||||||
"pleroma-amoled": [ "Pleroma Dark AMOLED", "#000000", "#111111", "#b0b0b1", "#d8a070", "#aa0000", "#0fa00f", "#0095ff", "#d59500"],
|
|
||||||
"classic-dark": [ "Classic Dark", "#161c20", "#282e32", "#b9b9b9", "#baaa9c", "#d31014", "#0fa00f", "#0095ff", "#ffa500" ],
|
|
||||||
"bird": [ "Bird", "#f8fafd", "#e6ecf0", "#14171a", "#0084b8", "#e0245e", "#17bf63", "#1b95e0", "#fab81e"],
|
|
||||||
"ir-black": [ "Ir Black", "#000000", "#242422", "#b5b3aa", "#ff6c60", "#FF6C60", "#A8FF60", "#96CBFE", "#FFFFB6" ],
|
|
||||||
"monokai": [ "Monokai", "#272822", "#383830", "#f8f8f2", "#f92672", "#F92672", "#a6e22e", "#66d9ef", "#f4bf75" ],
|
|
||||||
|
|
||||||
"redmond-xx": "/static/themes/redmond-xx.json",
|
"redmond-xx": "/static/themes/redmond-xx.json",
|
||||||
"redmond-xx-se": "/static/themes/redmond-xx-se.json",
|
"redmond-xx-se": "/static/themes/redmond-xx-se.json",
|
||||||
"redmond-xxi": "/static/themes/redmond-xxi.json",
|
"redmond-xxi": "/static/themes/redmond-xxi.json",
|
||||||
|
|
Loading…
Reference in a new issue