mirror of
https://git.pleroma.social/sjw/pleroma-fe.git
synced 2024-12-22 18:49:41 +01:00
Merge branch 'themes-accent' into 'develop'
Themes v3 Part 1 "2.1" codenamed "One step for themes, a giant burder for code reviewers" Closes #750 and #774 See merge request pleroma/pleroma-fe!1037
This commit is contained in:
commit
3ddf7ebe2c
@ -5,6 +5,9 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
|
||||
## [Unreleased]
|
||||
### Added
|
||||
- Tons of color slots including ones for hover/pressed/toggled buttons
|
||||
- Experimental `--variable[,mod]` syntax support for color slots in themes. the `mod` makes color brighter/darker depending on background color (makes darker color brighter/darker depending on background color)
|
||||
- Paper theme by Shpuld
|
||||
- Icons in nav panel
|
||||
- Private mode support
|
||||
- Support for 'Move' type notifications
|
||||
@ -13,10 +16,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
|
||||
- Emoji reactions for statuses
|
||||
- MRF keyword policy disclosure
|
||||
### Changed
|
||||
- theme engine update to 3 (themes v2.1 introduction)
|
||||
- massive internal changes in theme engine - slowly away from "generate things separately with spaghetti code" towards "feed all data into single 'generateTheme' function and declare slot inheritance and all in a separate file"
|
||||
- Breezy theme updates to make it closer to actual Breeze in some aspects
|
||||
- when using `--variable` in shadows it no longer uses the actual CSS3 variable, instead it generates color from other slots
|
||||
- theme doesn't get saved to local storage when opening FE anonymously
|
||||
- Captcha now resets on failed registrations
|
||||
- Notifications column now cleans itself up to optimize performance when tab is left open for a long time
|
||||
- 403 messaging
|
||||
### Fixed
|
||||
- anon viewers won't get theme data saved to local storage, so admin changing default theme will have an effect for users coming back to instance.
|
||||
- Single notifications left unread when hitting read on another device/tab
|
||||
- Registration fixed
|
||||
- Deactivation of remote accounts from frontend
|
||||
|
@ -35,6 +35,7 @@ module.exports = {
|
||||
],
|
||||
alias: {
|
||||
'vue$': 'vue/dist/vue.runtime.common',
|
||||
'static': path.resolve(__dirname, '../static'),
|
||||
'src': path.resolve(__dirname, '../src'),
|
||||
'assets': path.resolve(__dirname, '../src/assets'),
|
||||
'components': path.resolve(__dirname, '../src/components')
|
||||
|
116
src/App.scss
116
src/App.scss
@ -31,9 +31,12 @@ h4 {
|
||||
margin: auto;
|
||||
min-height: 100vh;
|
||||
max-width: 980px;
|
||||
background-color: rgba(0,0,0,0.15);
|
||||
align-content: flex-start;
|
||||
}
|
||||
.underlay {
|
||||
background-color: rgba(0,0,0,0.15);
|
||||
background-color: var(--underlay, rgba(0,0,0,0.15));
|
||||
}
|
||||
|
||||
.text-center {
|
||||
text-align: center;
|
||||
@ -98,18 +101,39 @@ button {
|
||||
&:active {
|
||||
box-shadow: 0px 0px 4px 0px rgba(255, 255, 255, 0.3), 0px 1px 0px 0px rgba(0, 0, 0, 0.2) inset, 0px -1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||
box-shadow: var(--buttonPressedShadow);
|
||||
color: $fallback--text;
|
||||
color: var(--btnPressedText, $fallback--text);
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--btnPressed, $fallback--fg);
|
||||
i {
|
||||
color: $fallback--text;
|
||||
color: var(--btnPressedText, $fallback--text);
|
||||
}
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
cursor: not-allowed;
|
||||
opacity: 0.5;
|
||||
color: $fallback--text;
|
||||
color: var(--btnDisabledText, $fallback--text);
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--btnDisabled, $fallback--fg);
|
||||
i {
|
||||
color: $fallback--text;
|
||||
color: var(--btnDisabledText, $fallback--text);
|
||||
}
|
||||
}
|
||||
|
||||
&.pressed {
|
||||
color: $fallback--faint;
|
||||
color: var(--faint, $fallback--faint);
|
||||
background-color: $fallback--bg;
|
||||
background-color: var(--bg, $fallback--bg)
|
||||
&.toggled {
|
||||
color: $fallback--text;
|
||||
color: var(--btnToggledText, $fallback--text);
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--btnToggled, $fallback--fg);
|
||||
box-shadow: 0px 0px 4px 0px rgba(255, 255, 255, 0.3), 0px 1px 0px 0px rgba(0, 0, 0, 0.2) inset, 0px -1px 0px 0px rgba(255, 255, 255, 0.2) inset;
|
||||
box-shadow: var(--buttonPressedShadow);
|
||||
i {
|
||||
color: $fallback--text;
|
||||
color: var(--btnToggledText, $fallback--text);
|
||||
}
|
||||
}
|
||||
|
||||
&.danger {
|
||||
@ -121,12 +145,15 @@ button {
|
||||
}
|
||||
}
|
||||
|
||||
label.select {
|
||||
padding: 0;
|
||||
input, textarea, .select, .input {
|
||||
|
||||
}
|
||||
&.unstyled {
|
||||
border-radius: 0;
|
||||
background: none;
|
||||
box-shadow: none;
|
||||
height: unset;
|
||||
}
|
||||
|
||||
input, textarea, .select {
|
||||
border: none;
|
||||
border-radius: $fallback--inputRadius;
|
||||
border-radius: var(--inputRadius, $fallback--inputRadius);
|
||||
@ -140,13 +167,17 @@ input, textarea, .select {
|
||||
font-family: var(--inputFont, sans-serif);
|
||||
font-size: 14px;
|
||||
margin: 0;
|
||||
padding: 8px .5em;
|
||||
box-sizing: border-box;
|
||||
display: inline-block;
|
||||
position: relative;
|
||||
height: 28px;
|
||||
line-height: 16px;
|
||||
hyphens: none;
|
||||
padding: 8px .5em;
|
||||
|
||||
&.select {
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&:disabled, &[disabled=disabled] {
|
||||
cursor: not-allowed;
|
||||
@ -160,7 +191,7 @@ input, textarea, .select {
|
||||
right: 5px;
|
||||
height: 100%;
|
||||
color: $fallback--text;
|
||||
color: var(--text, $fallback--text);
|
||||
color: var(--inputText, $fallback--text);
|
||||
line-height: 28px;
|
||||
z-index: 0;
|
||||
pointer-events: none;
|
||||
@ -198,7 +229,7 @@ input, textarea, .select {
|
||||
&:checked + label::before {
|
||||
box-shadow: 0px 0px 2px black inset, 0px 0px 0px 4px $fallback--fg inset;
|
||||
box-shadow: var(--inputShadow), 0px 0px 0px 4px var(--fg, $fallback--fg) inset;
|
||||
background-color: var(--link, $fallback--link);
|
||||
background-color: var(--accent, $fallback--link);
|
||||
}
|
||||
&:disabled {
|
||||
&,
|
||||
@ -235,7 +266,7 @@ input, textarea, .select {
|
||||
display: none;
|
||||
&:checked + label::before {
|
||||
color: $fallback--text;
|
||||
color: var(--text, $fallback--text);
|
||||
color: var(--inputText, $fallback--text);
|
||||
}
|
||||
&:disabled {
|
||||
&,
|
||||
@ -353,6 +384,33 @@ i[class*=icon-] {
|
||||
height: 50px;
|
||||
box-sizing: border-box;
|
||||
|
||||
button {
|
||||
&, i[class*=icon-] {
|
||||
color: $fallback--text;
|
||||
color: var(--btnTopBarText, $fallback--text);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--btnPressedTopBar, $fallback--fg);
|
||||
color: $fallback--text;
|
||||
color: var(--btnPressedTopBarText, $fallback--text);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
color: $fallback--text;
|
||||
color: var(--btnDisabledTopBarText, $fallback--text);
|
||||
}
|
||||
|
||||
&.toggled {
|
||||
color: $fallback--text;
|
||||
color: var(--btnToggledTopBarText, $fallback--text);
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--btnToggledTopBar, $fallback--fg)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
.logo {
|
||||
display: flex;
|
||||
position: absolute;
|
||||
@ -487,6 +545,10 @@ main-router {
|
||||
color: $fallback--faint;
|
||||
color: var(--panelFaint, $fallback--faint);
|
||||
}
|
||||
.faint-link {
|
||||
color: $fallback--faint;
|
||||
color: var(--faintLink, $fallback--faint);
|
||||
}
|
||||
|
||||
.alert {
|
||||
white-space: nowrap;
|
||||
@ -509,6 +571,30 @@ main-router {
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
button {
|
||||
&, i[class*=icon-] {
|
||||
color: $fallback--text;
|
||||
color: var(--btnPanelText, $fallback--text);
|
||||
}
|
||||
|
||||
&:active {
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--btnPressedPanel, $fallback--fg);
|
||||
color: $fallback--text;
|
||||
color: var(--btnPressedPanelText, $fallback--text);
|
||||
}
|
||||
|
||||
&:disabled {
|
||||
color: $fallback--text;
|
||||
color: var(--btnDisabledPanelText, $fallback--text);
|
||||
}
|
||||
|
||||
&.toggled {
|
||||
color: $fallback--text;
|
||||
color: var(--btnToggledPanelText, $fallback--text);
|
||||
}
|
||||
}
|
||||
|
||||
a {
|
||||
color: $fallback--link;
|
||||
color: var(--panelLink, $fallback--link)
|
||||
|
@ -78,7 +78,7 @@
|
||||
</nav>
|
||||
<div
|
||||
id="content"
|
||||
class="container"
|
||||
class="container underlay"
|
||||
>
|
||||
<div class="sidebar-flexer mobile-hidden">
|
||||
<div class="sidebar-bounds">
|
||||
|
@ -5,6 +5,8 @@ import App from '../App.vue'
|
||||
import { windowWidth } from '../services/window_utils/window_utils'
|
||||
import { getOrCreateApp, getClientToken } from '../services/new_api/oauth.js'
|
||||
import backendInteractorService from '../services/backend_interactor_service/backend_interactor_service.js'
|
||||
import { CURRENT_VERSION } from '../services/theme_data/theme_data.service.js'
|
||||
import { applyTheme } from '../services/style_setter/style_setter.js'
|
||||
|
||||
const getStatusnetConfig = async ({ store }) => {
|
||||
try {
|
||||
@ -265,7 +267,7 @@ const checkOAuthToken = async ({ store }) => {
|
||||
try {
|
||||
await store.dispatch('loginUser', store.getters.getUserToken())
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
console.error(e)
|
||||
}
|
||||
}
|
||||
resolve()
|
||||
@ -273,23 +275,29 @@ const checkOAuthToken = async ({ store }) => {
|
||||
}
|
||||
|
||||
const afterStoreSetup = async ({ store, i18n }) => {
|
||||
if (store.state.config.customTheme) {
|
||||
// This is a hack to deal with async loading of config.json and themes
|
||||
// See: style_setter.js, setPreset()
|
||||
window.themeLoaded = true
|
||||
store.dispatch('setOption', {
|
||||
name: 'customTheme',
|
||||
value: store.state.config.customTheme
|
||||
})
|
||||
}
|
||||
|
||||
const width = windowWidth()
|
||||
store.dispatch('setMobileLayout', width <= 800)
|
||||
await setConfig({ store })
|
||||
|
||||
const { customTheme, customThemeSource } = store.state.config
|
||||
const { theme } = store.state.instance
|
||||
const customThemePresent = customThemeSource || customTheme
|
||||
|
||||
if (customThemePresent) {
|
||||
if (customThemeSource && customThemeSource.themeEngineVersion === CURRENT_VERSION) {
|
||||
applyTheme(customThemeSource)
|
||||
} else {
|
||||
applyTheme(customTheme)
|
||||
}
|
||||
} else if (theme) {
|
||||
// do nothing, it will load asynchronously
|
||||
} else {
|
||||
console.error('Failed to load any theme!')
|
||||
}
|
||||
|
||||
// Now we can try getting the server settings and logging in
|
||||
await Promise.all([
|
||||
checkOAuthToken({ store }),
|
||||
setConfig({ store }),
|
||||
getTOS({ store }),
|
||||
getInstancePanel({ store }),
|
||||
getStickers({ store }),
|
||||
|
@ -130,6 +130,8 @@
|
||||
.placeholder {
|
||||
margin-right: 8px;
|
||||
margin-bottom: 4px;
|
||||
color: $fallback--link;
|
||||
color: var(--postLink, $fallback--link);
|
||||
}
|
||||
|
||||
.nsfw-placeholder {
|
||||
|
@ -40,8 +40,8 @@
|
||||
top: 100%;
|
||||
right: 0;
|
||||
max-height: 400px;
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--lightBg, $fallback--lightBg);
|
||||
background-color: $fallback--bg;
|
||||
background-color: var(--bg, $fallback--bg);
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
border-color: $fallback--border;
|
||||
|
@ -87,13 +87,13 @@ export default {
|
||||
|
||||
&:checked + .checkbox-indicator::before {
|
||||
color: $fallback--text;
|
||||
color: var(--text, $fallback--text);
|
||||
color: var(--inputText, $fallback--text);
|
||||
}
|
||||
|
||||
&:indeterminate + .checkbox-indicator::before {
|
||||
content: '–';
|
||||
color: $fallback--text;
|
||||
color: var(--text, $fallback--text);
|
||||
color: var(--inputText, $fallback--text);
|
||||
}
|
||||
|
||||
}
|
||||
|
68
src/components/color_input/color_input.scss
Normal file
68
src/components/color_input/color_input.scss
Normal file
@ -0,0 +1,68 @@
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.color-input {
|
||||
display: inline-flex;
|
||||
|
||||
&-field.input {
|
||||
display: inline-flex;
|
||||
flex: 0 0 0;
|
||||
max-width: 9em;
|
||||
align-items: stretch;
|
||||
padding: .2em 8px;
|
||||
|
||||
input {
|
||||
background: none;
|
||||
color: $fallback--lightText;
|
||||
color: var(--inputText, $fallback--lightText);
|
||||
border: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
&.textColor {
|
||||
flex: 1 0 3em;
|
||||
min-width: 3em;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
&.nativeColor {
|
||||
flex: 0 0 2em;
|
||||
min-width: 2em;
|
||||
align-self: center;
|
||||
height: 100%;
|
||||
}
|
||||
}
|
||||
.computedIndicator,
|
||||
.transparentIndicator {
|
||||
flex: 0 0 2em;
|
||||
min-width: 2em;
|
||||
align-self: center;
|
||||
height: 100%;
|
||||
}
|
||||
.transparentIndicator {
|
||||
// forgot to install counter-strike source, ooops
|
||||
background-color: #FF00FF;
|
||||
position: relative;
|
||||
&::before, &::after {
|
||||
display: block;
|
||||
content: '';
|
||||
background-color: #000000;
|
||||
position: absolute;
|
||||
height: 50%;
|
||||
width: 50%;
|
||||
}
|
||||
&::after {
|
||||
top: 0;
|
||||
left: 0;
|
||||
}
|
||||
&::before {
|
||||
bottom: 0;
|
||||
right: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.label {
|
||||
flex: 1 1 auto;
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
<template>
|
||||
<div
|
||||
class="color-control style-control"
|
||||
class="color-input style-control"
|
||||
:class="{ disabled: !present || disabled }"
|
||||
>
|
||||
<label
|
||||
@ -9,46 +9,100 @@
|
||||
>
|
||||
{{ label }}
|
||||
</label>
|
||||
<input
|
||||
v-if="typeof fallback !== 'undefined'"
|
||||
:id="name + '-o'"
|
||||
class="opt exlcude-disabled"
|
||||
type="checkbox"
|
||||
<Checkbox
|
||||
v-if="typeof fallback !== 'undefined' && showOptionalTickbox"
|
||||
:checked="present"
|
||||
@input="$emit('input', typeof value === 'undefined' ? fallback : undefined)"
|
||||
>
|
||||
<label
|
||||
v-if="typeof fallback !== 'undefined'"
|
||||
class="opt-l"
|
||||
:for="name + '-o'"
|
||||
:disabled="disabled"
|
||||
class="opt"
|
||||
@change="$emit('input', typeof value === 'undefined' ? fallback : undefined)"
|
||||
/>
|
||||
<input
|
||||
:id="name"
|
||||
class="color-input"
|
||||
type="color"
|
||||
:value="value || fallback"
|
||||
:disabled="!present || disabled"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
>
|
||||
<input
|
||||
:id="name + '-t'"
|
||||
class="text-input"
|
||||
type="text"
|
||||
:value="value || fallback"
|
||||
:disabled="!present || disabled"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
>
|
||||
<div class="input color-input-field">
|
||||
<input
|
||||
:id="name + '-t'"
|
||||
class="textColor unstyled"
|
||||
type="text"
|
||||
:value="value || fallback"
|
||||
:disabled="!present || disabled"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
>
|
||||
<input
|
||||
v-if="validColor"
|
||||
:id="name"
|
||||
class="nativeColor unstyled"
|
||||
type="color"
|
||||
:value="value || fallback"
|
||||
:disabled="!present || disabled"
|
||||
@input="$emit('input', $event.target.value)"
|
||||
>
|
||||
<div
|
||||
v-if="transparentColor"
|
||||
class="transparentIndicator"
|
||||
/>
|
||||
<div
|
||||
v-if="computedColor"
|
||||
class="computedIndicator"
|
||||
:style="{backgroundColor: fallback}"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss" src="./color_input.scss"></style>
|
||||
<script>
|
||||
import Checkbox from '../checkbox/checkbox.vue'
|
||||
import { hex2rgb } from '../../services/color_convert/color_convert.js'
|
||||
export default {
|
||||
props: [
|
||||
'name', 'label', 'value', 'fallback', 'disabled'
|
||||
],
|
||||
components: {
|
||||
Checkbox
|
||||
},
|
||||
props: {
|
||||
// Name of color, used for identifying
|
||||
name: {
|
||||
required: true,
|
||||
type: String
|
||||
},
|
||||
// Readable label
|
||||
label: {
|
||||
required: true,
|
||||
type: String
|
||||
},
|
||||
// Color value, should be required but vue cannot tell the difference
|
||||
// between "property missing" and "property set to undefined"
|
||||
value: {
|
||||
required: false,
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
// Color fallback to use when value is not defeind
|
||||
fallback: {
|
||||
required: false,
|
||||
type: String,
|
||||
default: undefined
|
||||
},
|
||||
// Disable the control
|
||||
disabled: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: false
|
||||
},
|
||||
// Show "optional" tickbox, for when value might become mandatory
|
||||
showOptionalTickbox: {
|
||||
required: false,
|
||||
type: Boolean,
|
||||
default: true
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
present () {
|
||||
return typeof this.value !== 'undefined'
|
||||
},
|
||||
validColor () {
|
||||
return hex2rgb(this.value || this.fallback)
|
||||
},
|
||||
transparentColor () {
|
||||
return this.value === 'transparent'
|
||||
},
|
||||
computedColor () {
|
||||
return this.value && this.value.startsWith('--')
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -37,9 +37,17 @@
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: [
|
||||
'large', 'contrast'
|
||||
],
|
||||
props: {
|
||||
large: {
|
||||
required: false
|
||||
},
|
||||
// TODO: Make theme switcher compute theme initially so that contrast
|
||||
// component won't be called without contrast data
|
||||
contrast: {
|
||||
required: false,
|
||||
type: Object
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
hint () {
|
||||
const levelVal = this.contrast.aaa ? 'aaa' : (this.contrast.aa ? 'aa' : 'bad')
|
||||
|
@ -75,18 +75,18 @@
|
||||
.dialog-modal-content {
|
||||
margin: 0;
|
||||
padding: 1rem 1rem;
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--lightBg, $fallback--lightBg);
|
||||
background-color: $fallback--bg;
|
||||
background-color: var(--bg, $fallback--bg);
|
||||
white-space: normal;
|
||||
}
|
||||
|
||||
.dialog-modal-footer {
|
||||
margin: 0;
|
||||
padding: .5em .5em;
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--lightBg, $fallback--lightBg);
|
||||
border-top: 1px solid $fallback--bg;
|
||||
border-top: 1px solid var(--bg, $fallback--bg);
|
||||
background-color: $fallback--bg;
|
||||
background-color: var(--bg, $fallback--bg);
|
||||
border-top: 1px solid $fallback--border;
|
||||
border-top: 1px solid var(--border, $fallback--border);
|
||||
display: flex;
|
||||
justify-content: flex-end;
|
||||
|
||||
|
@ -109,10 +109,16 @@
|
||||
box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5);
|
||||
box-shadow: var(--popupShadow);
|
||||
min-width: 75%;
|
||||
background: $fallback--bg;
|
||||
background: var(--bg, $fallback--bg);
|
||||
color: $fallback--lightText;
|
||||
color: var(--lightText, $fallback--lightText);
|
||||
background-color: $fallback--bg;
|
||||
background-color: var(--popover, $fallback--bg);
|
||||
color: $fallback--link;
|
||||
color: var(--popoverText, $fallback--link);
|
||||
--faint: var(--popoverFaintText, $fallback--faint);
|
||||
--faintLink: var(--popoverFaintLink, $fallback--faint);
|
||||
--lightText: var(--popoverLightText, $fallback--lightText);
|
||||
--postLink: var(--popoverPostLink, $fallback--link);
|
||||
--postFaintLink: var(--popoverPostFaintLink, $fallback--link);
|
||||
--icon: var(--popoverIcon, $fallback--icon);
|
||||
}
|
||||
}
|
||||
|
||||
@ -157,7 +163,12 @@
|
||||
|
||||
&.highlighted {
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--lightBg, $fallback--fg);
|
||||
background-color: var(--selectedMenuPopover, $fallback--fg);
|
||||
color: var(--selectedMenuPopoverText, $fallback--text);
|
||||
--faint: var(--selectedMenuPopoverFaintText, $fallback--faint);
|
||||
--faintLink: var(--selectedMenuPopoverFaintLink, $fallback--faint);
|
||||
--lightText: var(--selectedMenuPopoverLightText, $fallback--lightText);
|
||||
--icon: var(--selectedMenuPopoverIcon, $fallback--icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -8,6 +8,15 @@
|
||||
left: 0;
|
||||
margin: 0 !important;
|
||||
z-index: 1;
|
||||
background-color: $fallback--bg;
|
||||
background-color: var(--popover, $fallback--bg);
|
||||
color: $fallback--link;
|
||||
color: var(--popoverText, $fallback--link);
|
||||
--lightText: var(--popoverLightText, $fallback--faint);
|
||||
--faint: var(--popoverFaintText, $fallback--faint);
|
||||
--faintLink: var(--popoverFaintLink, $fallback--faint);
|
||||
--lightText: var(--popoverLightText, $fallback--lightText);
|
||||
--icon: var(--popoverIcon, $fallback--icon);
|
||||
|
||||
.keep-open,
|
||||
.too-many-emoji {
|
||||
|
@ -128,7 +128,7 @@
|
||||
}
|
||||
|
||||
.picked-reaction {
|
||||
border: 1px solid var(--link, $fallback--link);
|
||||
border: 1px solid var(--accent, $fallback--link);
|
||||
margin-left: -1px; // offset the border, can't use inset shadows either
|
||||
margin-right: calc(0.5em - 1px);
|
||||
}
|
||||
|
@ -42,7 +42,7 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
exportData () {
|
||||
const stringified = JSON.stringify(this.exportObject) // Pretty-print and indent with 2 spaces
|
||||
const stringified = JSON.stringify(this.exportObject, null, 2) // Pretty-print and indent with 2 spaces
|
||||
|
||||
// Create an invisible link with a data url and simulate a click
|
||||
const e = document.createElement('a')
|
||||
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<button
|
||||
class="btn btn-default follow-button"
|
||||
:class="{ pressed: isPressed }"
|
||||
:class="{ toggled: isPressed }"
|
||||
:disabled="inProgress"
|
||||
:title="title"
|
||||
@click="onClick"
|
||||
|
@ -123,7 +123,7 @@
|
||||
</div>
|
||||
<button
|
||||
class="btn btn-default btn-block"
|
||||
:class="{ pressed: showDropDown }"
|
||||
:class="{ toggled: showDropDown }"
|
||||
>
|
||||
{{ $t('user_card.admin_menu.moderation') }}
|
||||
</button>
|
||||
|
@ -100,13 +100,25 @@
|
||||
|
||||
&:hover {
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--lightBg, $fallback--lightBg);
|
||||
background-color: var(--selectedMenu, $fallback--lightBg);
|
||||
color: $fallback--link;
|
||||
color: var(--selectedMenuText, $fallback--link);
|
||||
--faint: var(--selectedMenuFaintText, $fallback--faint);
|
||||
--faintLink: var(--selectedMenuFaintLink, $fallback--faint);
|
||||
--lightText: var(--selectedMenuLightText, $fallback--lightText);
|
||||
--icon: var(--selectedMenuIcon, $fallback--icon);
|
||||
}
|
||||
|
||||
&.router-link-active {
|
||||
font-weight: bolder;
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--lightBg, $fallback--lightBg);
|
||||
background-color: var(--selectedMenu, $fallback--lightBg);
|
||||
color: $fallback--text;
|
||||
color: var(--selectedMenuText, $fallback--text);
|
||||
--faint: var(--selectedMenuFaintText, $fallback--faint);
|
||||
--faintLink: var(--selectedMenuFaintLink, $fallback--faint);
|
||||
--lightText: var(--selectedMenuLightText, $fallback--lightText);
|
||||
--icon: var(--selectedMenuIcon, $fallback--icon);
|
||||
|
||||
&:hover {
|
||||
text-decoration: underline;
|
||||
|
@ -68,6 +68,9 @@
|
||||
a {
|
||||
color: var(--faintLink);
|
||||
}
|
||||
.status-content a {
|
||||
color: var(--postFaintLink);
|
||||
}
|
||||
}
|
||||
padding: 0;
|
||||
.media-body {
|
||||
|
@ -9,18 +9,12 @@
|
||||
>
|
||||
{{ $t('settings.style.common.opacity') }}
|
||||
</label>
|
||||
<input
|
||||
<Checkbox
|
||||
v-if="typeof fallback !== 'undefined'"
|
||||
:id="name + '-o'"
|
||||
class="opt exclude-disabled"
|
||||
type="checkbox"
|
||||
:checked="present"
|
||||
@input="$emit('input', !present ? fallback : undefined)"
|
||||
>
|
||||
<label
|
||||
v-if="typeof fallback !== 'undefined'"
|
||||
class="opt-l"
|
||||
:for="name + '-o'"
|
||||
:disabled="disabled"
|
||||
class="opt"
|
||||
@change="$emit('input', !present ? fallback : undefined)"
|
||||
/>
|
||||
<input
|
||||
:id="name"
|
||||
@ -37,7 +31,11 @@
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import Checkbox from '../checkbox/checkbox.vue'
|
||||
export default {
|
||||
components: {
|
||||
Checkbox
|
||||
},
|
||||
props: [
|
||||
'name', 'value', 'fallback', 'disabled'
|
||||
],
|
||||
|
@ -104,8 +104,10 @@
|
||||
.result-fill {
|
||||
height: 100%;
|
||||
position: absolute;
|
||||
color: $fallback--text;
|
||||
color: var(--pollText, $fallback--text);
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--linkBg, $fallback--lightBg);
|
||||
background-color: var(--poll, $fallback--lightBg);
|
||||
border-radius: $fallback--panelRadius;
|
||||
border-radius: var(--panelRadius, $fallback--panelRadius);
|
||||
top: 0;
|
||||
|
@ -9,7 +9,15 @@
|
||||
border-radius: $fallback--btnRadius;
|
||||
border-radius: var(--btnRadius, $fallback--btnRadius);
|
||||
background-color: $fallback--bg;
|
||||
background-color: var(--bg, $fallback--bg);
|
||||
background-color: var(--popover, $fallback--bg);
|
||||
color: $fallback--text;
|
||||
color: var(--popoverText, $fallback--text);
|
||||
--faint: var(--popoverFaintText, $fallback--faint);
|
||||
--faintLink: var(--popoverFaintLink, $fallback--faint);
|
||||
--lightText: var(--popoverLightText, $fallback--lightText);
|
||||
--postLink: var(--popoverPostLink, $fallback--link);
|
||||
--postFaintLink: var(--popoverPostFaintLink, $fallback--link);
|
||||
--icon: var(--popoverIcon, $fallback--icon);
|
||||
}
|
||||
|
||||
.popover-arrow {
|
||||
@ -129,6 +137,8 @@
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
--btnText: var(--popoverText, $fallback--text);
|
||||
|
||||
&-icon {
|
||||
padding-left: 0.5rem;
|
||||
|
||||
@ -137,11 +147,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
&:hover {
|
||||
// TODO: improve the look on breeze themes
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--btn, $fallback--fg);
|
||||
box-shadow: none;
|
||||
&:active, &:hover {
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--selectedMenuPopover, $fallback--lightBg);
|
||||
color: $fallback--link;
|
||||
color: var(--selectedMenuPopoverText, $fallback--link);
|
||||
--faint: var(--selectedMenuPopoverFaintText, $fallback--faint);
|
||||
--faintLink: var(--selectedMenuPopoverFaintLink, $fallback--faint);
|
||||
--lightText: var(--selectedMenuPopoverLightText, $fallback--lightText);
|
||||
--icon: var(--selectedMenuPopoverIcon, $fallback--icon);
|
||||
i {
|
||||
color: var(--selectedMenuPopoverIcon, $fallback--icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,7 @@
|
||||
<input
|
||||
v-if="typeof fallback !== 'undefined'"
|
||||
:id="name + '-o'"
|
||||
class="opt exclude-disabled"
|
||||
class="opt"
|
||||
type="checkbox"
|
||||
:checked="present"
|
||||
@input="$emit('input', !present ? fallback : undefined)"
|
||||
|
@ -68,7 +68,12 @@
|
||||
|
||||
&-item-selected-inner {
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--lightBg, $fallback--lightBg);
|
||||
background-color: var(--selectedMenu, $fallback--lightBg);
|
||||
color: var(--selectedMenuText, $fallback--text);
|
||||
--faint: var(--selectedMenuFaintText, $fallback--faint);
|
||||
--faintLink: var(--selectedMenuFaintLink, $fallback--faint);
|
||||
--lightText: var(--selectedMenuLightText, $fallback--lightText);
|
||||
--icon: var(--selectedMenuIcon, $fallback--icon);
|
||||
}
|
||||
|
||||
&-header {
|
||||
|
@ -76,9 +76,9 @@
|
||||
<li>
|
||||
<Checkbox v-model="useStreamingApi">
|
||||
{{ $t('settings.useStreamingApi') }}
|
||||
<br/>
|
||||
<br>
|
||||
<small>
|
||||
{{ $t('settings.useStreamingApiWarning') }}
|
||||
{{ $t('settings.useStreamingApiWarning') }}
|
||||
</small>
|
||||
</Checkbox>
|
||||
</li>
|
||||
|
@ -3,6 +3,17 @@ import OpacityInput from '../opacity_input/opacity_input.vue'
|
||||
import { getCssShadow } from '../../services/style_setter/style_setter.js'
|
||||
import { hex2rgb } from '../../services/color_convert/color_convert.js'
|
||||
|
||||
const toModel = (object = {}) => ({
|
||||
x: 0,
|
||||
y: 0,
|
||||
blur: 0,
|
||||
spread: 0,
|
||||
inset: false,
|
||||
color: '#000000',
|
||||
alpha: 1,
|
||||
...object
|
||||
})
|
||||
|
||||
export default {
|
||||
// 'Value' and 'Fallback' can be undefined, but if they are
|
||||
// initially vue won't detect it when they become something else
|
||||
@ -15,7 +26,7 @@ export default {
|
||||
return {
|
||||
selectedId: 0,
|
||||
// TODO there are some bugs regarding display of array (it's not getting updated when deleting for some reason)
|
||||
cValue: this.value || this.fallback || []
|
||||
cValue: (this.value || this.fallback || []).map(toModel)
|
||||
}
|
||||
},
|
||||
components: {
|
||||
@ -24,12 +35,12 @@ export default {
|
||||
},
|
||||
methods: {
|
||||
add () {
|
||||
this.cValue.push(Object.assign({}, this.selected))
|
||||
this.cValue.push(toModel(this.selected))
|
||||
this.selectedId = this.cValue.length - 1
|
||||
},
|
||||
del () {
|
||||
this.cValue.splice(this.selectedId, 1)
|
||||
this.selectedId = this.cValue.length === 0 ? undefined : this.selectedId - 1
|
||||
this.selectedId = this.cValue.length === 0 ? undefined : Math.max(this.selectedId - 1, 0)
|
||||
},
|
||||
moveUp () {
|
||||
const movable = this.cValue.splice(this.selectedId, 1)[0]
|
||||
@ -46,19 +57,24 @@ export default {
|
||||
this.cValue = this.value || this.fallback
|
||||
},
|
||||
computed: {
|
||||
anyShadows () {
|
||||
return this.cValue.length > 0
|
||||
},
|
||||
anyShadowsFallback () {
|
||||
return this.fallback.length > 0
|
||||
},
|
||||
selected () {
|
||||
if (this.ready && this.cValue.length > 0) {
|
||||
if (this.ready && this.anyShadows) {
|
||||
return this.cValue[this.selectedId]
|
||||
} else {
|
||||
return {
|
||||
x: 0,
|
||||
y: 0,
|
||||
blur: 0,
|
||||
spread: 0,
|
||||
inset: false,
|
||||
color: '#000000',
|
||||
alpha: 1
|
||||
}
|
||||
return toModel({})
|
||||
}
|
||||
},
|
||||
currentFallback () {
|
||||
if (this.ready && this.anyShadowsFallback) {
|
||||
return this.fallback[this.selectedId]
|
||||
} else {
|
||||
return toModel({})
|
||||
}
|
||||
},
|
||||
moveUpValid () {
|
||||
@ -80,7 +96,7 @@ export default {
|
||||
},
|
||||
style () {
|
||||
return this.ready ? {
|
||||
boxShadow: getCssShadow(this.cValue)
|
||||
boxShadow: getCssShadow(this.fallback)
|
||||
} : {}
|
||||
}
|
||||
}
|
||||
|
@ -191,15 +191,20 @@
|
||||
v-model="selected.color"
|
||||
:disabled="!present"
|
||||
:label="$t('settings.style.common.color')"
|
||||
:fallback="currentFallback.color"
|
||||
:show-optional-tickbox="false"
|
||||
name="shadow"
|
||||
/>
|
||||
<OpacityInput
|
||||
v-model="selected.alpha"
|
||||
:disabled="!present"
|
||||
/>
|
||||
<p>
|
||||
{{ $t('settings.style.shadows.hint') }}
|
||||
</p>
|
||||
<i18n
|
||||
path="settings.style.shadows.hintV3"
|
||||
tag="p"
|
||||
>
|
||||
<code>--variable,mod</code>
|
||||
</i18n>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -223,7 +223,13 @@
|
||||
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);
|
||||
box-shadow: var(--panelShadow);
|
||||
background-color: $fallback--bg;
|
||||
background-color: var(--bg, $fallback--bg);
|
||||
background-color: var(--popover, $fallback--bg);
|
||||
color: $fallback--link;
|
||||
color: var(--popoverText, $fallback--link);
|
||||
--faint: var(--popoverFaintText, $fallback--faint);
|
||||
--faintLink: var(--popoverFaintLink, $fallback--faint);
|
||||
--lightText: var(--popoverLightText, $fallback--lightText);
|
||||
--icon: var(--popoverIcon, $fallback--icon);
|
||||
|
||||
.button-icon:before {
|
||||
width: 1.1em;
|
||||
@ -289,7 +295,13 @@
|
||||
|
||||
&:hover {
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--lightBg, $fallback--lightBg);
|
||||
background-color: var(--selectedMenuPopover, $fallback--lightBg);
|
||||
color: $fallback--text;
|
||||
color: var(--selectedMenuPopoverText, $fallback--text);
|
||||
--faint: var(--selectedMenuPopoverFaintText, $fallback--faint);
|
||||
--faintLink: var(--selectedMenuPopoverFaintLink, $fallback--faint);
|
||||
--lightText: var(--selectedMenuPopoverLightText, $fallback--lightText);
|
||||
--icon: var(--selectedMenuPopoverIcon, $fallback--icon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -468,7 +468,15 @@ $status-margin: 0.75em;
|
||||
|
||||
&_focused {
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--lightBg, $fallback--lightBg);
|
||||
background-color: var(--selectedPost, $fallback--lightBg);
|
||||
color: $fallback--text;
|
||||
color: var(--selectedPostText, $fallback--text);
|
||||
--lightText: var(--selectedPostLightText, $fallback--light);
|
||||
--faint: var(--selectedPostFaintText, $fallback--faint);
|
||||
--faintLink: var(--selectedPostFaintLink, $fallback--faint);
|
||||
--postLink: var(--selectedPostPostLink, $fallback--faint);
|
||||
--postFaintLink: var(--selectedPostFaintPostLink, $fallback--faint);
|
||||
--icon: var(--selectedPostIcon, $fallback--icon);
|
||||
}
|
||||
|
||||
.timeline & {
|
||||
@ -596,8 +604,6 @@ $status-margin: 0.75em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
margin: 0 0.4em 0 0.2em;
|
||||
color: $fallback--faint;
|
||||
color: var(--faint, $fallback--faint);
|
||||
}
|
||||
|
||||
.replies-separator {
|
||||
@ -659,6 +665,11 @@ $status-margin: 0.75em;
|
||||
line-height: 1.4em;
|
||||
white-space: pre-wrap;
|
||||
|
||||
a {
|
||||
color: $fallback--link;
|
||||
color: var(--postLink, $fallback--link);
|
||||
}
|
||||
|
||||
img, video {
|
||||
max-width: 100%;
|
||||
max-height: 400px;
|
||||
|
@ -51,7 +51,7 @@
|
||||
img {
|
||||
height: 100%;
|
||||
&:hover {
|
||||
filter: drop-shadow(0 0 5px var(--link, $fallback--link));
|
||||
filter: drop-shadow(0 0 5px var(--accent, $fallback--link));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,101 +1,117 @@
|
||||
<template>
|
||||
<div class="panel dummy">
|
||||
<div class="panel-heading">
|
||||
<div class="title">
|
||||
{{ $t('settings.style.preview.header') }}
|
||||
<span class="badge badge-notification">
|
||||
99
|
||||
<div class="preview-container">
|
||||
<div class="underlay underlay-preview" />
|
||||
<div class="panel dummy">
|
||||
<div class="panel-heading">
|
||||
<div class="title">
|
||||
{{ $t('settings.style.preview.header') }}
|
||||
<span class="badge badge-notification">
|
||||
99
|
||||
</span>
|
||||
</div>
|
||||
<span class="faint">
|
||||
{{ $t('settings.style.preview.header_faint') }}
|
||||
</span>
|
||||
</div>
|
||||
<span class="faint">
|
||||
{{ $t('settings.style.preview.header_faint') }}
|
||||
</span>
|
||||
<span class="alert error">
|
||||
{{ $t('settings.style.preview.error') }}
|
||||
</span>
|
||||
<button class="btn">
|
||||
{{ $t('settings.style.preview.button') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="panel-body theme-preview-content">
|
||||
<div class="post">
|
||||
<div class="avatar">
|
||||
( ͡° ͜ʖ ͡°)
|
||||
</div>
|
||||
<div class="content">
|
||||
<h4>
|
||||
{{ $t('settings.style.preview.content') }}
|
||||
</h4>
|
||||
|
||||
<i18n path="settings.style.preview.text">
|
||||
<code style="font-family: var(--postCodeFont)">
|
||||
{{ $t('settings.style.preview.mono') }}
|
||||
</code>
|
||||
<a style="color: var(--link)">
|
||||
{{ $t('settings.style.preview.link') }}
|
||||
</a>
|
||||
</i18n>
|
||||
|
||||
<div class="icons">
|
||||
<i
|
||||
style="color: var(--cBlue)"
|
||||
class="button-icon icon-reply"
|
||||
/>
|
||||
<i
|
||||
style="color: var(--cGreen)"
|
||||
class="button-icon icon-retweet"
|
||||
/>
|
||||
<i
|
||||
style="color: var(--cOrange)"
|
||||
class="button-icon icon-star"
|
||||
/>
|
||||
<i
|
||||
style="color: var(--cRed)"
|
||||
class="button-icon icon-cancel"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="after-post">
|
||||
<div class="avatar-alt">
|
||||
:^)
|
||||
</div>
|
||||
<div class="content">
|
||||
<i18n
|
||||
path="settings.style.preview.fine_print"
|
||||
tag="span"
|
||||
class="faint"
|
||||
>
|
||||
<a style="color: var(--faintLink)">
|
||||
{{ $t('settings.style.preview.faint_link') }}
|
||||
</a>
|
||||
</i18n>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator" />
|
||||
|
||||
<span class="alert error">
|
||||
{{ $t('settings.style.preview.error') }}
|
||||
</span>
|
||||
<input
|
||||
:value="$t('settings.style.preview.input')"
|
||||
type="text"
|
||||
>
|
||||
|
||||
<div class="actions">
|
||||
<span class="checkbox">
|
||||
<input
|
||||
id="preview_checkbox"
|
||||
checked="very yes"
|
||||
type="checkbox"
|
||||
>
|
||||
<label for="preview_checkbox">{{ $t('settings.style.preview.checkbox') }}</label>
|
||||
<span class="alert error">
|
||||
{{ $t('settings.style.preview.error') }}
|
||||
</span>
|
||||
<button class="btn">
|
||||
{{ $t('settings.style.preview.button') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="panel-body theme-preview-content">
|
||||
<div class="post">
|
||||
<div class="avatar still-image">
|
||||
( ͡° ͜ʖ ͡°)
|
||||
</div>
|
||||
<div class="content">
|
||||
<h4>
|
||||
{{ $t('settings.style.preview.content') }}
|
||||
</h4>
|
||||
|
||||
<i18n path="settings.style.preview.text">
|
||||
<code style="font-family: var(--postCodeFont)">
|
||||
{{ $t('settings.style.preview.mono') }}
|
||||
</code>
|
||||
<a style="color: var(--link)">
|
||||
{{ $t('settings.style.preview.link') }}
|
||||
</a>
|
||||
</i18n>
|
||||
|
||||
<div class="icons">
|
||||
<i
|
||||
style="color: var(--cBlue)"
|
||||
class="button-icon icon-reply"
|
||||
/>
|
||||
<i
|
||||
style="color: var(--cGreen)"
|
||||
class="button-icon icon-retweet"
|
||||
/>
|
||||
<i
|
||||
style="color: var(--cOrange)"
|
||||
class="button-icon icon-star"
|
||||
/>
|
||||
<i
|
||||
style="color: var(--cRed)"
|
||||
class="button-icon icon-cancel"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="after-post">
|
||||
<div class="avatar-alt">
|
||||
:^)
|
||||
</div>
|
||||
<div class="content">
|
||||
<i18n
|
||||
path="settings.style.preview.fine_print"
|
||||
tag="span"
|
||||
class="faint"
|
||||
>
|
||||
<a style="color: var(--faintLink)">
|
||||
{{ $t('settings.style.preview.faint_link') }}
|
||||
</a>
|
||||
</i18n>
|
||||
</div>
|
||||
</div>
|
||||
<div class="separator" />
|
||||
|
||||
<span class="alert error">
|
||||
{{ $t('settings.style.preview.error') }}
|
||||
</span>
|
||||
<input
|
||||
:value="$t('settings.style.preview.input')"
|
||||
type="text"
|
||||
>
|
||||
|
||||
<div class="actions">
|
||||
<span class="checkbox">
|
||||
<input
|
||||
id="preview_checkbox"
|
||||
checked="very yes"
|
||||
type="checkbox"
|
||||
>
|
||||
<label for="preview_checkbox">{{ $t('settings.style.preview.checkbox') }}</label>
|
||||
</span>
|
||||
<button class="btn">
|
||||
{{ $t('settings.style.preview.button') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style lang="scss">
|
||||
.preview-container {
|
||||
position: relative;
|
||||
}
|
||||
.underlay-preview {
|
||||
position: absolute;
|
||||
top: 0;
|
||||
bottom: 0;
|
||||
left: 10px;
|
||||
right: 10px;
|
||||
}
|
||||
</style>
|
||||
|
@ -1,6 +1,29 @@
|
||||
import { rgb2hex, hex2rgb, getContrastRatio, alphaBlend } from '../../services/color_convert/color_convert.js'
|
||||
import { set, delete as del } from 'vue'
|
||||
import { generateColors, generateShadows, generateRadii, generateFonts, composePreset, getThemes } from '../../services/style_setter/style_setter.js'
|
||||
import {
|
||||
rgb2hex,
|
||||
hex2rgb,
|
||||
getContrastRatioLayers
|
||||
} from '../../services/color_convert/color_convert.js'
|
||||
import {
|
||||
DEFAULT_SHADOWS,
|
||||
generateColors,
|
||||
generateShadows,
|
||||
generateRadii,
|
||||
generateFonts,
|
||||
composePreset,
|
||||
getThemes,
|
||||
shadows2to3,
|
||||
colors2to3
|
||||
} from '../../services/style_setter/style_setter.js'
|
||||
import {
|
||||
SLOT_INHERITANCE
|
||||
} from '../../services/theme_data/pleromafe.js'
|
||||
import {
|
||||
CURRENT_VERSION,
|
||||
OPACITIES,
|
||||
getLayers,
|
||||
getOpacitySlot
|
||||
} from '../../services/theme_data/theme_data.service.js'
|
||||
import ColorInput from '../color_input/color_input.vue'
|
||||
import RangeInput from '../range_input/range_input.vue'
|
||||
import OpacityInput from '../opacity_input/opacity_input.vue'
|
||||
@ -24,11 +47,22 @@ const v1OnlyNames = [
|
||||
'cOrange'
|
||||
].map(_ => _ + 'ColorLocal')
|
||||
|
||||
const colorConvert = (color) => {
|
||||
if (color.startsWith('--') || color === 'transparent') {
|
||||
return color
|
||||
} else {
|
||||
return hex2rgb(color)
|
||||
}
|
||||
}
|
||||
|
||||
export default {
|
||||
data () {
|
||||
return {
|
||||
availableStyles: [],
|
||||
selected: this.$store.getters.mergedConfig.theme,
|
||||
themeWarning: undefined,
|
||||
tempImportFile: undefined,
|
||||
engineVersion: 0,
|
||||
|
||||
previewShadows: {},
|
||||
previewColors: {},
|
||||
@ -45,51 +79,13 @@ export default {
|
||||
keepRoundness: false,
|
||||
keepFonts: false,
|
||||
|
||||
textColorLocal: '',
|
||||
linkColorLocal: '',
|
||||
...Object.keys(SLOT_INHERITANCE)
|
||||
.map(key => [key, ''])
|
||||
.reduce((acc, [key, val]) => ({ ...acc, [ key + 'ColorLocal' ]: val }), {}),
|
||||
|
||||
bgColorLocal: '',
|
||||
bgOpacityLocal: undefined,
|
||||
|
||||
fgColorLocal: '',
|
||||
fgTextColorLocal: undefined,
|
||||
fgLinkColorLocal: undefined,
|
||||
|
||||
btnColorLocal: undefined,
|
||||
btnTextColorLocal: undefined,
|
||||
btnOpacityLocal: undefined,
|
||||
|
||||
inputColorLocal: undefined,
|
||||
inputTextColorLocal: undefined,
|
||||
inputOpacityLocal: undefined,
|
||||
|
||||
panelColorLocal: undefined,
|
||||
panelTextColorLocal: undefined,
|
||||
panelLinkColorLocal: undefined,
|
||||
panelFaintColorLocal: undefined,
|
||||
panelOpacityLocal: undefined,
|
||||
|
||||
topBarColorLocal: undefined,
|
||||
topBarTextColorLocal: undefined,
|
||||
topBarLinkColorLocal: undefined,
|
||||
|
||||
alertErrorColorLocal: undefined,
|
||||
alertWarningColorLocal: undefined,
|
||||
|
||||
badgeOpacityLocal: undefined,
|
||||
badgeNotificationColorLocal: undefined,
|
||||
|
||||
borderColorLocal: undefined,
|
||||
borderOpacityLocal: undefined,
|
||||
|
||||
faintColorLocal: undefined,
|
||||
faintOpacityLocal: undefined,
|
||||
faintLinkColorLocal: undefined,
|
||||
|
||||
cRedColorLocal: '',
|
||||
cBlueColorLocal: '',
|
||||
cGreenColorLocal: '',
|
||||
cOrangeColorLocal: '',
|
||||
...Object.keys(OPACITIES)
|
||||
.map(key => [key, ''])
|
||||
.reduce((acc, [key, val]) => ({ ...acc, [ key + 'OpacityLocal' ]: val }), {}),
|
||||
|
||||
shadowSelected: undefined,
|
||||
shadowsLocal: {},
|
||||
@ -108,69 +104,105 @@ export default {
|
||||
created () {
|
||||
const self = this
|
||||
|
||||
getThemes().then((themesComplete) => {
|
||||
self.availableStyles = themesComplete
|
||||
})
|
||||
getThemes()
|
||||
.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) => {
|
||||
self.availableStyles = themesComplete
|
||||
})
|
||||
},
|
||||
mounted () {
|
||||
this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme)
|
||||
this.loadThemeFromLocalStorage()
|
||||
if (typeof this.shadowSelected === 'undefined') {
|
||||
this.shadowSelected = this.shadowsAvailable[0]
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
themeWarningHelp () {
|
||||
if (!this.themeWarning) return
|
||||
const t = this.$t
|
||||
const pre = 'settings.style.switcher.help.'
|
||||
const {
|
||||
origin,
|
||||
themeEngineVersion,
|
||||
type,
|
||||
noActionsPossible
|
||||
} = this.themeWarning
|
||||
if (origin === 'file') {
|
||||
// Loaded v2 theme from file
|
||||
if (themeEngineVersion === 2 && type === 'wrong_version') {
|
||||
return t(pre + 'v2_imported')
|
||||
}
|
||||
if (themeEngineVersion > CURRENT_VERSION) {
|
||||
return t(pre + 'future_version_imported') + ' ' +
|
||||
(
|
||||
noActionsPossible
|
||||
? t(pre + 'snapshot_missing')
|
||||
: t(pre + 'snapshot_present')
|
||||
)
|
||||
}
|
||||
if (themeEngineVersion < CURRENT_VERSION) {
|
||||
return t(pre + 'future_version_imported') + ' ' +
|
||||
(
|
||||
noActionsPossible
|
||||
? t(pre + 'snapshot_missing')
|
||||
: t(pre + 'snapshot_present')
|
||||
)
|
||||
}
|
||||
} else if (origin === 'localStorage') {
|
||||
if (type === 'snapshot_source_mismatch') {
|
||||
return t(pre + 'snapshot_source_mismatch')
|
||||
}
|
||||
// FE upgraded from v2
|
||||
if (themeEngineVersion === 2) {
|
||||
return t(pre + 'upgraded_from_v2')
|
||||
}
|
||||
// Admin downgraded FE
|
||||
if (themeEngineVersion > CURRENT_VERSION) {
|
||||
return t(pre + 'fe_downgraded') + ' ' +
|
||||
(
|
||||
noActionsPossible
|
||||
? t(pre + 'migration_snapshot_ok')
|
||||
: t(pre + 'migration_snapshot_gone')
|
||||
)
|
||||
}
|
||||
// Admin upgraded FE
|
||||
if (themeEngineVersion < CURRENT_VERSION) {
|
||||
return t(pre + 'fe_upgraded') + ' ' +
|
||||
(
|
||||
noActionsPossible
|
||||
? t(pre + 'migration_snapshot_ok')
|
||||
: t(pre + 'migration_snapshot_gone')
|
||||
)
|
||||
}
|
||||
}
|
||||
},
|
||||
selectedVersion () {
|
||||
return Array.isArray(this.selected) ? 1 : 2
|
||||
},
|
||||
currentColors () {
|
||||
return {
|
||||
bg: this.bgColorLocal,
|
||||
text: this.textColorLocal,
|
||||
link: this.linkColorLocal,
|
||||
|
||||
fg: this.fgColorLocal,
|
||||
fgText: this.fgTextColorLocal,
|
||||
fgLink: this.fgLinkColorLocal,
|
||||
|
||||
panel: this.panelColorLocal,
|
||||
panelText: this.panelTextColorLocal,
|
||||
panelLink: this.panelLinkColorLocal,
|
||||
panelFaint: this.panelFaintColorLocal,
|
||||
|
||||
input: this.inputColorLocal,
|
||||
inputText: this.inputTextColorLocal,
|
||||
|
||||
topBar: this.topBarColorLocal,
|
||||
topBarText: this.topBarTextColorLocal,
|
||||
topBarLink: this.topBarLinkColorLocal,
|
||||
|
||||
btn: this.btnColorLocal,
|
||||
btnText: this.btnTextColorLocal,
|
||||
|
||||
alertError: this.alertErrorColorLocal,
|
||||
alertWarning: this.alertWarningColorLocal,
|
||||
badgeNotification: this.badgeNotificationColorLocal,
|
||||
|
||||
faint: this.faintColorLocal,
|
||||
faintLink: this.faintLinkColorLocal,
|
||||
border: this.borderColorLocal,
|
||||
|
||||
cRed: this.cRedColorLocal,
|
||||
cBlue: this.cBlueColorLocal,
|
||||
cGreen: this.cGreenColorLocal,
|
||||
cOrange: this.cOrangeColorLocal
|
||||
}
|
||||
return Object.keys(SLOT_INHERITANCE)
|
||||
.map(key => [key, this[key + 'ColorLocal']])
|
||||
.reduce((acc, [key, val]) => ({ ...acc, [ key ]: val }), {})
|
||||
},
|
||||
currentOpacity () {
|
||||
return {
|
||||
bg: this.bgOpacityLocal,
|
||||
btn: this.btnOpacityLocal,
|
||||
input: this.inputOpacityLocal,
|
||||
panel: this.panelOpacityLocal,
|
||||
topBar: this.topBarOpacityLocal,
|
||||
border: this.borderOpacityLocal,
|
||||
faint: this.faintOpacityLocal
|
||||
}
|
||||
return Object.keys(OPACITIES)
|
||||
.map(key => [key, this[key + 'OpacityLocal']])
|
||||
.reduce((acc, [key, val]) => ({ ...acc, [ key ]: val }), {})
|
||||
},
|
||||
currentRadii () {
|
||||
return {
|
||||
@ -193,75 +225,66 @@ export default {
|
||||
},
|
||||
// This needs optimization maybe
|
||||
previewContrast () {
|
||||
if (!this.previewTheme.colors.bg) return {}
|
||||
const colors = this.previewTheme.colors
|
||||
const opacity = this.previewTheme.opacity
|
||||
if (!colors.bg) return {}
|
||||
const hints = (ratio) => ({
|
||||
text: ratio.toPrecision(3) + ':1',
|
||||
// AA level, AAA level
|
||||
aa: ratio >= 4.5,
|
||||
aaa: ratio >= 7,
|
||||
// same but for 18pt+ texts
|
||||
laa: ratio >= 3,
|
||||
laaa: ratio >= 4.5
|
||||
})
|
||||
try {
|
||||
if (!this.previewTheme.colors.bg) return {}
|
||||
const colors = this.previewTheme.colors
|
||||
const opacity = this.previewTheme.opacity
|
||||
if (!colors.bg) return {}
|
||||
const hints = (ratio) => ({
|
||||
text: ratio.toPrecision(3) + ':1',
|
||||
// AA level, AAA level
|
||||
aa: ratio >= 4.5,
|
||||
aaa: ratio >= 7,
|
||||
// same but for 18pt+ texts
|
||||
laa: ratio >= 3,
|
||||
laaa: ratio >= 4.5
|
||||
})
|
||||
const colorsConverted = Object.entries(colors).reduce((acc, [key, value]) => ({ ...acc, [key]: colorConvert(value) }), {})
|
||||
|
||||
// fgsfds :DDDD
|
||||
const fgs = {
|
||||
text: hex2rgb(colors.text),
|
||||
panelText: hex2rgb(colors.panelText),
|
||||
panelLink: hex2rgb(colors.panelLink),
|
||||
btnText: hex2rgb(colors.btnText),
|
||||
topBarText: hex2rgb(colors.topBarText),
|
||||
inputText: hex2rgb(colors.inputText),
|
||||
const ratios = Object.entries(SLOT_INHERITANCE).reduce((acc, [key, value]) => {
|
||||
const slotIsBaseText = key === 'text' || key === 'link'
|
||||
const slotIsText = slotIsBaseText || (
|
||||
typeof value === 'object' && value !== null && value.textColor
|
||||
)
|
||||
if (!slotIsText) return acc
|
||||
const { layer, variant } = slotIsBaseText ? { layer: 'bg' } : value
|
||||
const background = variant || layer
|
||||
const opacitySlot = getOpacitySlot(background)
|
||||
const textColors = [
|
||||
key,
|
||||
...(background === 'bg' ? ['cRed', 'cGreen', 'cBlue', 'cOrange'] : [])
|
||||
]
|
||||
|
||||
link: hex2rgb(colors.link),
|
||||
topBarLink: hex2rgb(colors.topBarLink),
|
||||
const layers = getLayers(
|
||||
layer,
|
||||
variant || layer,
|
||||
opacitySlot,
|
||||
colorsConverted,
|
||||
opacity
|
||||
)
|
||||
|
||||
red: hex2rgb(colors.cRed),
|
||||
green: hex2rgb(colors.cGreen),
|
||||
blue: hex2rgb(colors.cBlue),
|
||||
orange: hex2rgb(colors.cOrange)
|
||||
return {
|
||||
...acc,
|
||||
...textColors.reduce((acc, textColorKey) => {
|
||||
const newKey = slotIsBaseText
|
||||
? 'bg' + textColorKey[0].toUpperCase() + textColorKey.slice(1)
|
||||
: textColorKey
|
||||
return {
|
||||
...acc,
|
||||
[newKey]: getContrastRatioLayers(
|
||||
colorsConverted[textColorKey],
|
||||
layers,
|
||||
colorsConverted[textColorKey]
|
||||
)
|
||||
}
|
||||
}, {})
|
||||
}
|
||||
}, {})
|
||||
|
||||
return Object.entries(ratios).reduce((acc, [k, v]) => { acc[k] = hints(v); return acc }, {})
|
||||
} catch (e) {
|
||||
console.warn('Failure computing contrasts', e)
|
||||
}
|
||||
|
||||
const bgs = {
|
||||
bg: hex2rgb(colors.bg),
|
||||
btn: hex2rgb(colors.btn),
|
||||
panel: hex2rgb(colors.panel),
|
||||
topBar: hex2rgb(colors.topBar),
|
||||
input: hex2rgb(colors.input),
|
||||
alertError: hex2rgb(colors.alertError),
|
||||
alertWarning: hex2rgb(colors.alertWarning),
|
||||
badgeNotification: hex2rgb(colors.badgeNotification)
|
||||
}
|
||||
|
||||
/* This is a bit confusing because "bottom layer" used is text color
|
||||
* This is done to get worst case scenario when background below transparent
|
||||
* layer matches text color, making it harder to read the lower alpha is.
|
||||
*/
|
||||
const ratios = {
|
||||
bgText: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.text), fgs.text),
|
||||
bgLink: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.link), fgs.link),
|
||||
bgRed: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.red), fgs.red),
|
||||
bgGreen: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.green), fgs.green),
|
||||
bgBlue: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.blue), fgs.blue),
|
||||
bgOrange: getContrastRatio(alphaBlend(bgs.bg, opacity.bg, fgs.orange), fgs.orange),
|
||||
|
||||
tintText: getContrastRatio(alphaBlend(bgs.bg, 0.5, fgs.panelText), fgs.text),
|
||||
|
||||
panelText: getContrastRatio(alphaBlend(bgs.panel, opacity.panel, fgs.panelText), fgs.panelText),
|
||||
panelLink: getContrastRatio(alphaBlend(bgs.panel, opacity.panel, fgs.panelLink), fgs.panelLink),
|
||||
|
||||
btnText: getContrastRatio(alphaBlend(bgs.btn, opacity.btn, fgs.btnText), fgs.btnText),
|
||||
|
||||
inputText: getContrastRatio(alphaBlend(bgs.input, opacity.input, fgs.inputText), fgs.inputText),
|
||||
|
||||
topBarText: getContrastRatio(alphaBlend(bgs.topBar, opacity.topBar, fgs.topBarText), fgs.topBarText),
|
||||
topBarLink: getContrastRatio(alphaBlend(bgs.topBar, opacity.topBar, fgs.topBarLink), fgs.topBarLink)
|
||||
}
|
||||
|
||||
return Object.entries(ratios).reduce((acc, [k, v]) => { acc[k] = hints(v); return acc }, {})
|
||||
},
|
||||
previewRules () {
|
||||
if (!this.preview.rules) return ''
|
||||
@ -272,7 +295,7 @@ export default {
|
||||
].join(';')
|
||||
},
|
||||
shadowsAvailable () {
|
||||
return Object.keys(this.previewTheme.shadows).sort()
|
||||
return Object.keys(DEFAULT_SHADOWS).sort()
|
||||
},
|
||||
currentShadowOverriden: {
|
||||
get () {
|
||||
@ -287,7 +310,7 @@ export default {
|
||||
}
|
||||
},
|
||||
currentShadowFallback () {
|
||||
return this.previewTheme.shadows[this.shadowSelected]
|
||||
return (this.previewTheme.shadows || {})[this.shadowSelected]
|
||||
},
|
||||
currentShadow: {
|
||||
get () {
|
||||
@ -309,27 +332,34 @@ export default {
|
||||
!this.keepColor
|
||||
)
|
||||
|
||||
const theme = {}
|
||||
const source = {
|
||||
themeEngineVersion: CURRENT_VERSION
|
||||
}
|
||||
|
||||
if (this.keepFonts || saveEverything) {
|
||||
theme.fonts = this.fontsLocal
|
||||
source.fonts = this.fontsLocal
|
||||
}
|
||||
if (this.keepShadows || saveEverything) {
|
||||
theme.shadows = this.shadowsLocal
|
||||
source.shadows = this.shadowsLocal
|
||||
}
|
||||
if (this.keepOpacity || saveEverything) {
|
||||
theme.opacity = this.currentOpacity
|
||||
source.opacity = this.currentOpacity
|
||||
}
|
||||
if (this.keepColor || saveEverything) {
|
||||
theme.colors = this.currentColors
|
||||
source.colors = this.currentColors
|
||||
}
|
||||
if (this.keepRoundness || saveEverything) {
|
||||
theme.radii = this.currentRadii
|
||||
source.radii = this.currentRadii
|
||||
}
|
||||
|
||||
const theme = {
|
||||
themeEngineVersion: CURRENT_VERSION,
|
||||
...this.previewTheme
|
||||
}
|
||||
|
||||
return {
|
||||
// To separate from other random JSON files and possible future theme formats
|
||||
_pleroma_theme_version: 2, theme
|
||||
// To separate from other random JSON files and possible future source formats
|
||||
_pleroma_theme_version: 2, theme, source
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -346,10 +376,128 @@ export default {
|
||||
Checkbox
|
||||
},
|
||||
methods: {
|
||||
loadTheme (
|
||||
{
|
||||
theme,
|
||||
source,
|
||||
_pleroma_theme_version: fileVersion
|
||||
},
|
||||
origin,
|
||||
forceUseSource = false
|
||||
) {
|
||||
this.dismissWarning()
|
||||
if (!source && !theme) {
|
||||
throw new Error('Can\'t load theme: empty')
|
||||
}
|
||||
const version = (origin === 'localStorage' && !theme.colors)
|
||||
? 'l1'
|
||||
: fileVersion
|
||||
const snapshotEngineVersion = (theme || {}).themeEngineVersion
|
||||
const themeEngineVersion = (source || {}).themeEngineVersion || 2
|
||||
const versionsMatch = themeEngineVersion === CURRENT_VERSION
|
||||
const sourceSnapshotMismatch = (
|
||||
theme !== undefined &&
|
||||
source !== undefined &&
|
||||
themeEngineVersion !== snapshotEngineVersion
|
||||
)
|
||||
// Force loading of source if user requested it or if snapshot
|
||||
// is unavailable
|
||||
const forcedSourceLoad = (source && forceUseSource) || !theme
|
||||
if (!(versionsMatch && !sourceSnapshotMismatch) &&
|
||||
!forcedSourceLoad &&
|
||||
version !== 'l1' &&
|
||||
origin !== 'defaults'
|
||||
) {
|
||||
if (sourceSnapshotMismatch && origin === 'localStorage') {
|
||||
this.themeWarning = {
|
||||
origin,
|
||||
themeEngineVersion,
|
||||
type: 'snapshot_source_mismatch'
|
||||
}
|
||||
} else if (!theme) {
|
||||
this.themeWarning = {
|
||||
origin,
|
||||
noActionsPossible: true,
|
||||
themeEngineVersion,
|
||||
type: 'no_snapshot_old_version'
|
||||
}
|
||||
} else if (!versionsMatch) {
|
||||
this.themeWarning = {
|
||||
origin,
|
||||
noActionsPossible: !source,
|
||||
themeEngineVersion,
|
||||
type: 'wrong_version'
|
||||
}
|
||||
}
|
||||
}
|
||||
this.normalizeLocalState(theme, version, source, forcedSourceLoad)
|
||||
},
|
||||
forceLoadLocalStorage () {
|
||||
this.loadThemeFromLocalStorage(true)
|
||||
},
|
||||
dismissWarning () {
|
||||
this.themeWarning = undefined
|
||||
this.tempImportFile = undefined
|
||||
},
|
||||
forceLoad () {
|
||||
const { origin } = this.themeWarning
|
||||
switch (origin) {
|
||||
case 'localStorage':
|
||||
this.loadThemeFromLocalStorage(true)
|
||||
break
|
||||
case 'file':
|
||||
this.onImport(this.tempImportFile, true)
|
||||
break
|
||||
}
|
||||
this.dismissWarning()
|
||||
},
|
||||
forceSnapshot () {
|
||||
const { origin } = this.themeWarning
|
||||
switch (origin) {
|
||||
case 'localStorage':
|
||||
this.loadThemeFromLocalStorage(false, true)
|
||||
break
|
||||
case 'file':
|
||||
console.err('Forcing snapshout from file is not supported yet')
|
||||
break
|
||||
}
|
||||
this.dismissWarning()
|
||||
},
|
||||
loadThemeFromLocalStorage (confirmLoadSource = false, forceSnapshot = false) {
|
||||
const {
|
||||
customTheme: theme,
|
||||
customThemeSource: source
|
||||
} = this.$store.getters.mergedConfig
|
||||
if (!theme && !source) {
|
||||
// Anon user or never touched themes
|
||||
this.loadTheme(
|
||||
this.$store.state.instance.themeData,
|
||||
'defaults',
|
||||
confirmLoadSource
|
||||
)
|
||||
} else {
|
||||
this.loadTheme(
|
||||
{
|
||||
theme,
|
||||
source: forceSnapshot ? theme : source
|
||||
},
|
||||
'localStorage',
|
||||
confirmLoadSource
|
||||
)
|
||||
}
|
||||
},
|
||||
setCustomTheme () {
|
||||
this.$store.dispatch('setOption', {
|
||||
name: 'customTheme',
|
||||
value: {
|
||||
themeEngineVersion: CURRENT_VERSION,
|
||||
...this.previewTheme
|
||||
}
|
||||
})
|
||||
this.$store.dispatch('setOption', {
|
||||
name: 'customThemeSource',
|
||||
value: {
|
||||
themeEngineVersion: CURRENT_VERSION,
|
||||
shadows: this.shadowsLocal,
|
||||
fonts: this.fontsLocal,
|
||||
opacity: this.currentOpacity,
|
||||
@ -358,21 +506,27 @@ export default {
|
||||
}
|
||||
})
|
||||
},
|
||||
onImport (parsed) {
|
||||
if (parsed._pleroma_theme_version === 1) {
|
||||
this.normalizeLocalState(parsed, 1)
|
||||
} else if (parsed._pleroma_theme_version === 2) {
|
||||
this.normalizeLocalState(parsed.theme, 2)
|
||||
}
|
||||
updatePreviewColorsAndShadows () {
|
||||
this.previewColors = generateColors({
|
||||
opacity: this.currentOpacity,
|
||||
colors: this.currentColors
|
||||
})
|
||||
this.previewShadows = generateShadows(
|
||||
{ shadows: this.shadowsLocal, opacity: this.previewTheme.opacity, themeEngineVersion: this.engineVersion },
|
||||
this.previewColors.theme.colors,
|
||||
this.previewColors.mod
|
||||
)
|
||||
},
|
||||
onImport (parsed, forceSource = false) {
|
||||
this.tempImportFile = parsed
|
||||
this.loadTheme(parsed, 'file', forceSource)
|
||||
},
|
||||
importValidator (parsed) {
|
||||
const version = parsed._pleroma_theme_version
|
||||
return version >= 1 || version <= 2
|
||||
},
|
||||
clearAll () {
|
||||
const state = this.$store.getters.mergedConfig.customTheme
|
||||
const version = state.colors ? 2 : 'l1'
|
||||
this.normalizeLocalState(this.$store.getters.mergedConfig.customTheme, version)
|
||||
this.loadThemeFromLocalStorage()
|
||||
},
|
||||
|
||||
// Clears all the extra stuff when loading V1 theme
|
||||
@ -411,19 +565,37 @@ export default {
|
||||
|
||||
/**
|
||||
* This applies stored theme data onto form. Supports three versions of data:
|
||||
* v3 (version >= 3) - newest version of themes which supports snapshots for better compatiblity
|
||||
* v2 (version = 2) - newer version of themes.
|
||||
* v1 (version = 1) - older version of themes (import from file)
|
||||
* v1l (version = l1) - older version of theme (load from local storage)
|
||||
* v1 and v1l differ because of way themes were stored/exported.
|
||||
* @param {Object} input - input data
|
||||
* @param {Object} theme - theme data (snapshot)
|
||||
* @param {Number} version - version of data. 0 means try to guess based on data. "l1" means v1, locastorage type
|
||||
* @param {Object} source - theme source - this will be used if compatible
|
||||
* @param {Boolean} source - by default source won't be used if version doesn't match since it might render differently
|
||||
* this allows importing source anyway
|
||||
*/
|
||||
normalizeLocalState (input, version = 0) {
|
||||
const colors = input.colors || input
|
||||
normalizeLocalState (theme, version = 0, source, forceSource = false) {
|
||||
let input
|
||||
if (typeof source !== 'undefined') {
|
||||
if (forceSource || source.themeEngineVersion === CURRENT_VERSION) {
|
||||
input = source
|
||||
version = source.themeEngineVersion
|
||||
} else {
|
||||
input = theme
|
||||
}
|
||||
} else {
|
||||
input = theme
|
||||
}
|
||||
|
||||
const radii = input.radii || input
|
||||
const opacity = input.opacity
|
||||
const shadows = input.shadows || {}
|
||||
const fonts = input.fonts || {}
|
||||
const colors = !input.themeEngineVersion
|
||||
? colors2to3(input.colors || input)
|
||||
: input.colors || input
|
||||
|
||||
if (version === 0) {
|
||||
if (input.version) version = input.version
|
||||
@ -437,6 +609,8 @@ export default {
|
||||
}
|
||||
}
|
||||
|
||||
this.engineVersion = version
|
||||
|
||||
// Stuff that differs between V1 and V2
|
||||
if (version === 1) {
|
||||
this.fgColorLocal = rgb2hex(colors.btn)
|
||||
@ -445,7 +619,7 @@ export default {
|
||||
|
||||
if (!this.keepColor) {
|
||||
this.clearV1()
|
||||
const keys = new Set(version !== 1 ? Object.keys(colors) : [])
|
||||
const keys = new Set(version !== 1 ? Object.keys(SLOT_INHERITANCE) : [])
|
||||
if (version === 1 || version === 'l1') {
|
||||
keys
|
||||
.add('bg')
|
||||
@ -457,7 +631,17 @@ export default {
|
||||
}
|
||||
|
||||
keys.forEach(key => {
|
||||
this[key + 'ColorLocal'] = rgb2hex(colors[key])
|
||||
const color = colors[key]
|
||||
const hex = rgb2hex(colors[key])
|
||||
this[key + 'ColorLocal'] = hex === '#aN' ? color : hex
|
||||
})
|
||||
}
|
||||
|
||||
if (opacity && !this.keepOpacity) {
|
||||
this.clearOpacity()
|
||||
Object.entries(opacity).forEach(([k, v]) => {
|
||||
if (typeof v === 'undefined' || v === null || Number.isNaN(v)) return
|
||||
this[k + 'OpacityLocal'] = v
|
||||
})
|
||||
}
|
||||
|
||||
@ -472,7 +656,11 @@ export default {
|
||||
|
||||
if (!this.keepShadows) {
|
||||
this.clearShadows()
|
||||
this.shadowsLocal = shadows
|
||||
if (version === 2) {
|
||||
this.shadowsLocal = shadows2to3(shadows, this.previewTheme.opacity)
|
||||
} else {
|
||||
this.shadowsLocal = shadows
|
||||
}
|
||||
this.shadowSelected = this.shadowsAvailable[0]
|
||||
}
|
||||
|
||||
@ -480,14 +668,6 @@ export default {
|
||||
this.clearFonts()
|
||||
this.fontsLocal = fonts
|
||||
}
|
||||
|
||||
if (opacity && !this.keepOpacity) {
|
||||
this.clearOpacity()
|
||||
Object.entries(opacity).forEach(([k, v]) => {
|
||||
if (typeof v === 'undefined' || v === null || Number.isNaN(v)) return
|
||||
this[k + 'OpacityLocal'] = v
|
||||
})
|
||||
}
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
@ -502,8 +682,9 @@ export default {
|
||||
},
|
||||
shadowsLocal: {
|
||||
handler () {
|
||||
if (Object.getOwnPropertyNames(this.previewColors).length === 1) return
|
||||
try {
|
||||
this.previewShadows = generateShadows({ shadows: this.shadowsLocal })
|
||||
this.updatePreviewColorsAndShadows()
|
||||
this.shadowsInvalid = false
|
||||
} catch (e) {
|
||||
this.shadowsInvalid = true
|
||||
@ -526,27 +707,24 @@ export default {
|
||||
},
|
||||
currentColors () {
|
||||
try {
|
||||
this.previewColors = generateColors({
|
||||
opacity: this.currentOpacity,
|
||||
colors: this.currentColors
|
||||
})
|
||||
this.updatePreviewColorsAndShadows()
|
||||
this.colorsInvalid = false
|
||||
this.shadowsInvalid = false
|
||||
} catch (e) {
|
||||
this.colorsInvalid = true
|
||||
this.shadowsInvalid = true
|
||||
console.warn(e)
|
||||
}
|
||||
},
|
||||
currentOpacity () {
|
||||
try {
|
||||
this.previewColors = generateColors({
|
||||
opacity: this.currentOpacity,
|
||||
colors: this.currentColors
|
||||
})
|
||||
this.updatePreviewColorsAndShadows()
|
||||
} catch (e) {
|
||||
console.warn(e)
|
||||
}
|
||||
},
|
||||
selected () {
|
||||
this.dismissWarning()
|
||||
if (this.selectedVersion === 1) {
|
||||
if (!this.keepRoundness) {
|
||||
this.clearRoundness()
|
||||
@ -573,7 +751,7 @@ export default {
|
||||
this.cOrangeColorLocal = this.selected[8]
|
||||
}
|
||||
} else if (this.selectedVersion >= 2) {
|
||||
this.normalizeLocalState(this.selected.theme, 2)
|
||||
this.normalizeLocalState(this.selected.theme, 2, this.selected.source)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,15 @@
|
||||
@import '../../_variables.scss';
|
||||
.style-switcher {
|
||||
.theme-warning {
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
margin-bottom: .5em;
|
||||
.buttons {
|
||||
.btn {
|
||||
margin-bottom: .5em;
|
||||
}
|
||||
}
|
||||
}
|
||||
.preset-switcher {
|
||||
margin-right: 1em;
|
||||
}
|
||||
@ -15,26 +25,23 @@
|
||||
|
||||
&.disabled {
|
||||
input, select {
|
||||
&:not(.exclude-disabled) {
|
||||
opacity: .5
|
||||
}
|
||||
opacity: .5
|
||||
}
|
||||
}
|
||||
|
||||
.opt {
|
||||
margin: .5em;
|
||||
}
|
||||
|
||||
.color-input {
|
||||
flex: 0 0 0;
|
||||
}
|
||||
|
||||
input, select {
|
||||
min-width: 3em;
|
||||
margin: 0;
|
||||
flex: 0;
|
||||
|
||||
&[type=color] {
|
||||
padding: 1px;
|
||||
cursor: pointer;
|
||||
height: 29px;
|
||||
min-width: 2em;
|
||||
border: none;
|
||||
align-self: stretch;
|
||||
}
|
||||
|
||||
&[type=number] {
|
||||
min-width: 5em;
|
||||
}
|
||||
@ -42,13 +49,6 @@
|
||||
&[type=range] {
|
||||
flex: 1;
|
||||
min-width: 3em;
|
||||
}
|
||||
|
||||
&[type=checkbox] + label {
|
||||
margin: 6px 0;
|
||||
}
|
||||
|
||||
&:not([type=number]):not([type=text]) {
|
||||
align-self: flex-start;
|
||||
}
|
||||
}
|
||||
|
@ -2,7 +2,53 @@
|
||||
<div class="style-switcher">
|
||||
<div class="presets-container">
|
||||
<div class="save-load">
|
||||
<export-import
|
||||
<div
|
||||
v-if="themeWarning"
|
||||
class="theme-warning"
|
||||
>
|
||||
<div class="alert warning">
|
||||
{{ themeWarningHelp }}
|
||||
</div>
|
||||
<div class="buttons">
|
||||
<template v-if="themeWarning.type === 'snapshot_source_mismatch'">
|
||||
<button
|
||||
class="btn"
|
||||
@click="forceLoad"
|
||||
>
|
||||
{{ $t('settings.style.switcher.use_source') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
@click="forceSnapshot"
|
||||
>
|
||||
{{ $t('settings.style.switcher.use_snapshot') }}
|
||||
</button>
|
||||
</template>
|
||||
<template v-else-if="themeWarning.noActionsPossible">
|
||||
<button
|
||||
class="btn"
|
||||
@click="dismissWarning"
|
||||
>
|
||||
{{ $t('general.dismiss') }}
|
||||
</button>
|
||||
</template>
|
||||
<template v-else>
|
||||
<button
|
||||
class="btn"
|
||||
@click="forceLoad"
|
||||
>
|
||||
{{ $t('settings.style.switcher.load_theme') }}
|
||||
</button>
|
||||
<button
|
||||
class="btn"
|
||||
@click="dismissWarning"
|
||||
>
|
||||
{{ $t('settings.style.switcher.keep_as_is') }}
|
||||
</button>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
<ExportImport
|
||||
:export-object="exportedTheme"
|
||||
:export-label="$t("settings.export_theme")"
|
||||
:import-label="$t("settings.import_theme")"
|
||||
@ -27,8 +73,8 @@
|
||||
:key="style.name"
|
||||
:value="style"
|
||||
:style="{
|
||||
backgroundColor: style[1] || style.theme.colors.bg,
|
||||
color: style[3] || style.theme.colors.text
|
||||
backgroundColor: style[1] || (style.theme || style.source).colors.bg,
|
||||
color: style[3] || (style.theme || style.source).colors.text
|
||||
}"
|
||||
>
|
||||
{{ style[0] || style.name }}
|
||||
@ -38,7 +84,7 @@
|
||||
</label>
|
||||
</div>
|
||||
</template>
|
||||
</export-import>
|
||||
</ExportImport>
|
||||
</div>
|
||||
<div class="save-load-options">
|
||||
<span class="keep-option">
|
||||
@ -70,9 +116,7 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="preview-container">
|
||||
<preview :style="previewRules" />
|
||||
</div>
|
||||
<preview :style="previewRules" />
|
||||
|
||||
<keep-alive>
|
||||
<tab-switcher key="style-tweak">
|
||||
@ -106,7 +150,7 @@
|
||||
<OpacityInput
|
||||
v-model="bgOpacityLocal"
|
||||
name="bgOpacity"
|
||||
:fallback="previewTheme.opacity.bg || 1"
|
||||
:fallback="previewTheme.opacity.bg"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="textColorLocal"
|
||||
@ -114,10 +158,19 @@
|
||||
:label="$t('settings.text')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.bgText" />
|
||||
<ColorInput
|
||||
v-model="accentColorLocal"
|
||||
name="accentColor"
|
||||
:fallback="previewTheme.colors.link"
|
||||
:label="$t('settings.accent')"
|
||||
:show-optional-tickbox="typeof linkColorLocal !== 'undefined'"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="linkColorLocal"
|
||||
name="linkColor"
|
||||
:fallback="previewTheme.colors.accent"
|
||||
:label="$t('settings.links')"
|
||||
:show-optional-tickbox="typeof accentColorLocal !== 'undefined'"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.bgLink" />
|
||||
</div>
|
||||
@ -148,13 +201,13 @@
|
||||
name="cRedColor"
|
||||
:label="$t('settings.cRed')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.bgRed" />
|
||||
<ContrastRatio :contrast="previewContrast.bgCRed" />
|
||||
<ColorInput
|
||||
v-model="cBlueColorLocal"
|
||||
name="cBlueColor"
|
||||
:label="$t('settings.cBlue')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.bgBlue" />
|
||||
<ContrastRatio :contrast="previewContrast.bgCBlue" />
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<ColorInput
|
||||
@ -162,13 +215,13 @@
|
||||
name="cGreenColor"
|
||||
:label="$t('settings.cGreen')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.bgGreen" />
|
||||
<ContrastRatio :contrast="previewContrast.bgCGreen" />
|
||||
<ColorInput
|
||||
v-model="cOrangeColorLocal"
|
||||
name="cOrangeColor"
|
||||
:label="$t('settings.cOrange')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.bgOrange" />
|
||||
<ContrastRatio :contrast="previewContrast.bgCOrange" />
|
||||
</div>
|
||||
<p>{{ $t('settings.theme_help_v2_2') }}</p>
|
||||
</div>
|
||||
@ -193,6 +246,14 @@
|
||||
</button>
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.post') }}</h4>
|
||||
<ColorInput
|
||||
v-model="postLinkColorLocal"
|
||||
name="postLinkColor"
|
||||
:fallback="previewTheme.colors.accent"
|
||||
:label="$t('settings.links')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.postLink" />
|
||||
<h4>{{ $t('settings.style.advanced_colors.alert') }}</h4>
|
||||
<ColorInput
|
||||
v-model="alertErrorColorLocal"
|
||||
@ -200,14 +261,53 @@
|
||||
:label="$t('settings.style.advanced_colors.alert_error')"
|
||||
:fallback="previewTheme.colors.alertError"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.alertError" />
|
||||
<ColorInput
|
||||
v-model="alertErrorTextColorLocal"
|
||||
name="alertErrorText"
|
||||
:label="$t('settings.text')"
|
||||
:fallback="previewTheme.colors.alertErrorText"
|
||||
/>
|
||||
<ContrastRatio
|
||||
:contrast="previewContrast.alertErrorText"
|
||||
large="true"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="alertWarningColorLocal"
|
||||
name="alertWarning"
|
||||
:label="$t('settings.style.advanced_colors.alert_warning')"
|
||||
:fallback="previewTheme.colors.alertWarning"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.alertWarning" />
|
||||
<ColorInput
|
||||
v-model="alertWarningTextColorLocal"
|
||||
name="alertWarningText"
|
||||
:label="$t('settings.text')"
|
||||
:fallback="previewTheme.colors.alertWarningText"
|
||||
/>
|
||||
<ContrastRatio
|
||||
:contrast="previewContrast.alertWarningText"
|
||||
large="true"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="alertNeutralColorLocal"
|
||||
name="alertNeutral"
|
||||
:label="$t('settings.style.advanced_colors.alert_neutral')"
|
||||
:fallback="previewTheme.colors.alertNeutral"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="alertNeutralTextColorLocal"
|
||||
name="alertNeutralText"
|
||||
:label="$t('settings.text')"
|
||||
:fallback="previewTheme.colors.alertNeutralText"
|
||||
/>
|
||||
<ContrastRatio
|
||||
:contrast="previewContrast.alertNeutralText"
|
||||
large="true"
|
||||
/>
|
||||
<OpacityInput
|
||||
v-model="alertOpacityLocal"
|
||||
name="alertOpacity"
|
||||
:fallback="previewTheme.opacity.alert"
|
||||
/>
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.badge') }}</h4>
|
||||
@ -217,19 +317,30 @@
|
||||
:label="$t('settings.style.advanced_colors.badge_notification')"
|
||||
:fallback="previewTheme.colors.badgeNotification"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="badgeNotificationTextColorLocal"
|
||||
name="badgeNotificationText"
|
||||
:label="$t('settings.text')"
|
||||
:fallback="previewTheme.colors.badgeNotificationText"
|
||||
/>
|
||||
<ContrastRatio
|
||||
:contrast="previewContrast.badgeNotificationText"
|
||||
large="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.panel_header') }}</h4>
|
||||
<ColorInput
|
||||
v-model="panelColorLocal"
|
||||
name="panelColor"
|
||||
:fallback="fgColorLocal"
|
||||
:fallback="previewTheme.colors.panel"
|
||||
:label="$t('settings.background')"
|
||||
/>
|
||||
<OpacityInput
|
||||
v-model="panelOpacityLocal"
|
||||
name="panelOpacity"
|
||||
:fallback="previewTheme.opacity.panel || 1"
|
||||
:fallback="previewTheme.opacity.panel"
|
||||
:disabled="panelColorLocal === 'transparent'"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="panelTextColorLocal"
|
||||
@ -239,7 +350,7 @@
|
||||
/>
|
||||
<ContrastRatio
|
||||
:contrast="previewContrast.panelText"
|
||||
large="1"
|
||||
large="true"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="panelLinkColorLocal"
|
||||
@ -249,7 +360,7 @@
|
||||
/>
|
||||
<ContrastRatio
|
||||
:contrast="previewContrast.panelLink"
|
||||
large="1"
|
||||
large="true"
|
||||
/>
|
||||
</div>
|
||||
<div class="color-item">
|
||||
@ -257,7 +368,7 @@
|
||||
<ColorInput
|
||||
v-model="topBarColorLocal"
|
||||
name="topBarColor"
|
||||
:fallback="fgColorLocal"
|
||||
:fallback="previewTheme.colors.topBar"
|
||||
:label="$t('settings.background')"
|
||||
/>
|
||||
<ColorInput
|
||||
@ -280,13 +391,14 @@
|
||||
<ColorInput
|
||||
v-model="inputColorLocal"
|
||||
name="inputColor"
|
||||
:fallback="fgColorLocal"
|
||||
:fallback="previewTheme.colors.input"
|
||||
:label="$t('settings.background')"
|
||||
/>
|
||||
<OpacityInput
|
||||
v-model="inputOpacityLocal"
|
||||
name="inputOpacity"
|
||||
:fallback="previewTheme.opacity.input || 1"
|
||||
:fallback="previewTheme.opacity.input"
|
||||
:disabled="inputColorLocal === 'transparent'"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="inputTextColorLocal"
|
||||
@ -301,13 +413,14 @@
|
||||
<ColorInput
|
||||
v-model="btnColorLocal"
|
||||
name="btnColor"
|
||||
:fallback="fgColorLocal"
|
||||
:fallback="previewTheme.colors.btn"
|
||||
:label="$t('settings.background')"
|
||||
/>
|
||||
<OpacityInput
|
||||
v-model="btnOpacityLocal"
|
||||
name="btnOpacity"
|
||||
:fallback="previewTheme.opacity.btn || 1"
|
||||
:fallback="previewTheme.opacity.btn"
|
||||
:disabled="btnColorLocal === 'transparent'"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="btnTextColorLocal"
|
||||
@ -316,6 +429,124 @@
|
||||
:label="$t('settings.text')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.btnText" />
|
||||
<ColorInput
|
||||
v-model="btnPanelTextColorLocal"
|
||||
name="btnPanelTextColor"
|
||||
:fallback="previewTheme.colors.btnPanelText"
|
||||
:label="$t('settings.style.advanced_colors.panel_header')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.btnPanelText" />
|
||||
<ColorInput
|
||||
v-model="btnTopBarTextColorLocal"
|
||||
name="btnTopBarTextColor"
|
||||
:fallback="previewTheme.colors.btnTopBarText"
|
||||
:label="$t('settings.style.advanced_colors.top_bar')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.btnTopBarText" />
|
||||
<h5>{{ $t('settings.style.advanced_colors.pressed') }}</h5>
|
||||
<ColorInput
|
||||
v-model="btnPressedColorLocal"
|
||||
name="btnPressedColor"
|
||||
:fallback="previewTheme.colors.btnPressed"
|
||||
:label="$t('settings.background')"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="btnPressedTextColorLocal"
|
||||
name="btnPressedTextColor"
|
||||
:fallback="previewTheme.colors.btnPressedText"
|
||||
:label="$t('settings.text')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.btnPressedText" />
|
||||
<ColorInput
|
||||
v-model="btnPressedPanelTextColorLocal"
|
||||
name="btnPressedPanelTextColor"
|
||||
:fallback="previewTheme.colors.btnPressedPanelText"
|
||||
:label="$t('settings.style.advanced_colors.panel_header')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.btnPressedPanelText" />
|
||||
<ColorInput
|
||||
v-model="btnPressedTopBarTextColorLocal"
|
||||
name="btnPressedTopBarTextColor"
|
||||
:fallback="previewTheme.colors.btnPressedTopBarText"
|
||||
:label="$t('settings.style.advanced_colors.top_bar')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.btnPressedTopBarText" />
|
||||
<h5>{{ $t('settings.style.advanced_colors.disabled') }}</h5>
|
||||
<ColorInput
|
||||
v-model="btnDisabledColorLocal"
|
||||
name="btnDisabledColor"
|
||||
:fallback="previewTheme.colors.btnDisabled"
|
||||
:label="$t('settings.background')"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="btnDisabledTextColorLocal"
|
||||
name="btnDisabledTextColor"
|
||||
:fallback="previewTheme.colors.btnDisabledText"
|
||||
:label="$t('settings.text')"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="btnDisabledPanelTextColorLocal"
|
||||
name="btnDisabledPanelTextColor"
|
||||
:fallback="previewTheme.colors.btnDisabledPanelText"
|
||||
:label="$t('settings.style.advanced_colors.panel_header')"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="btnDisabledTopBarTextColorLocal"
|
||||
name="btnDisabledTopBarTextColor"
|
||||
:fallback="previewTheme.colors.btnDisabledTopBarText"
|
||||
:label="$t('settings.style.advanced_colors.top_bar')"
|
||||
/>
|
||||
<h5>{{ $t('settings.style.advanced_colors.toggled') }}</h5>
|
||||
<ColorInput
|
||||
v-model="btnToggledColorLocal"
|
||||
name="btnToggledColor"
|
||||
:fallback="previewTheme.colors.btnToggled"
|
||||
:label="$t('settings.background')"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="btnToggledTextColorLocal"
|
||||
name="btnToggledTextColor"
|
||||
:fallback="previewTheme.colors.btnToggledText"
|
||||
:label="$t('settings.text')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.btnToggledText" />
|
||||
<ColorInput
|
||||
v-model="btnToggledPanelTextColorLocal"
|
||||
name="btnToggledPanelTextColor"
|
||||
:fallback="previewTheme.colors.btnToggledPanelText"
|
||||
:label="$t('settings.style.advanced_colors.panel_header')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.btnToggledPanelText" />
|
||||
<ColorInput
|
||||
v-model="btnToggledTopBarTextColorLocal"
|
||||
name="btnToggledTopBarTextColor"
|
||||
:fallback="previewTheme.colors.btnToggledTopBarText"
|
||||
:label="$t('settings.style.advanced_colors.top_bar')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.btnToggledTopBarText" />
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.tabs') }}</h4>
|
||||
<ColorInput
|
||||
v-model="tabColorLocal"
|
||||
name="tabColor"
|
||||
:fallback="previewTheme.colors.tab"
|
||||
:label="$t('settings.background')"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="tabTextColorLocal"
|
||||
name="tabTextColor"
|
||||
:fallback="previewTheme.colors.tabText"
|
||||
:label="$t('settings.text')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.tabText" />
|
||||
<ColorInput
|
||||
v-model="tabActiveTextColorLocal"
|
||||
name="tabActiveTextColor"
|
||||
:fallback="previewTheme.colors.tabActiveText"
|
||||
:label="$t('settings.text')"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.tabActiveText" />
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.borders') }}</h4>
|
||||
@ -328,7 +559,8 @@
|
||||
<OpacityInput
|
||||
v-model="borderOpacityLocal"
|
||||
name="borderOpacity"
|
||||
:fallback="previewTheme.opacity.border || 1"
|
||||
:fallback="previewTheme.opacity.border"
|
||||
:disabled="borderColorLocal === 'transparent'"
|
||||
/>
|
||||
</div>
|
||||
<div class="color-item">
|
||||
@ -336,7 +568,7 @@
|
||||
<ColorInput
|
||||
v-model="faintColorLocal"
|
||||
name="faintColor"
|
||||
:fallback="previewTheme.colors.faint || 1"
|
||||
:fallback="previewTheme.colors.faint"
|
||||
:label="$t('settings.text')"
|
||||
/>
|
||||
<ColorInput
|
||||
@ -354,9 +586,146 @@
|
||||
<OpacityInput
|
||||
v-model="faintOpacityLocal"
|
||||
name="faintOpacity"
|
||||
:fallback="previewTheme.opacity.faint || 0.5"
|
||||
:fallback="previewTheme.opacity.faint"
|
||||
/>
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.underlay') }}</h4>
|
||||
<ColorInput
|
||||
v-model="underlayColorLocal"
|
||||
name="underlay"
|
||||
:label="$t('settings.style.advanced_colors.underlay')"
|
||||
:fallback="previewTheme.colors.underlay"
|
||||
/>
|
||||
<OpacityInput
|
||||
v-model="underlayOpacityLocal"
|
||||
name="underlayOpacity"
|
||||
:fallback="previewTheme.opacity.underlay"
|
||||
:disabled="underlayOpacityLocal === 'transparent'"
|
||||
/>
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.poll') }}</h4>
|
||||
<ColorInput
|
||||
v-model="pollColorLocal"
|
||||
name="poll"
|
||||
:label="$t('settings.background')"
|
||||
:fallback="previewTheme.colors.poll"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="pollTextColorLocal"
|
||||
name="pollText"
|
||||
:label="$t('settings.text')"
|
||||
:fallback="previewTheme.colors.pollText"
|
||||
/>
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.icons') }}</h4>
|
||||
<ColorInput
|
||||
v-model="iconColorLocal"
|
||||
name="icon"
|
||||
:label="$t('settings.style.advanced_colors.icons')"
|
||||
:fallback="previewTheme.colors.icon"
|
||||
/>
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.highlight') }}</h4>
|
||||
<ColorInput
|
||||
v-model="highlightColorLocal"
|
||||
name="highlight"
|
||||
:label="$t('settings.background')"
|
||||
:fallback="previewTheme.colors.highlight"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="highlightTextColorLocal"
|
||||
name="highlightText"
|
||||
:label="$t('settings.text')"
|
||||
:fallback="previewTheme.colors.highlightText"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.highlightText" />
|
||||
<ColorInput
|
||||
v-model="highlightLinkColorLocal"
|
||||
name="highlightLink"
|
||||
:label="$t('settings.links')"
|
||||
:fallback="previewTheme.colors.highlightLink"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.highlightLink" />
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.popover') }}</h4>
|
||||
<ColorInput
|
||||
v-model="popoverColorLocal"
|
||||
name="popover"
|
||||
:label="$t('settings.background')"
|
||||
:fallback="previewTheme.colors.popover"
|
||||
/>
|
||||
<OpacityInput
|
||||
v-model="popoverOpacityLocal"
|
||||
name="popoverOpacity"
|
||||
:fallback="previewTheme.opacity.popover"
|
||||
:disabled="popoverOpacityLocal === 'transparent'"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="popoverTextColorLocal"
|
||||
name="popoverText"
|
||||
:label="$t('settings.text')"
|
||||
:fallback="previewTheme.colors.popoverText"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.popoverText" />
|
||||
<ColorInput
|
||||
v-model="popoverLinkColorLocal"
|
||||
name="popoverLink"
|
||||
:label="$t('settings.links')"
|
||||
:fallback="previewTheme.colors.popoverLink"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.popoverLink" />
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.selectedPost') }}</h4>
|
||||
<ColorInput
|
||||
v-model="selectedPostColorLocal"
|
||||
name="selectedPost"
|
||||
:label="$t('settings.background')"
|
||||
:fallback="previewTheme.colors.selectedPost"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="selectedPostTextColorLocal"
|
||||
name="selectedPostText"
|
||||
:label="$t('settings.text')"
|
||||
:fallback="previewTheme.colors.selectedPostText"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.selectedPostText" />
|
||||
<ColorInput
|
||||
v-model="selectedPostLinkColorLocal"
|
||||
name="selectedPostLink"
|
||||
:label="$t('settings.links')"
|
||||
:fallback="previewTheme.colors.selectedPostLink"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.selectedPostLink" />
|
||||
</div>
|
||||
<div class="color-item">
|
||||
<h4>{{ $t('settings.style.advanced_colors.selectedMenu') }}</h4>
|
||||
<ColorInput
|
||||
v-model="selectedMenuColorLocal"
|
||||
name="selectedMenu"
|
||||
:label="$t('settings.background')"
|
||||
:fallback="previewTheme.colors.selectedMenu"
|
||||
/>
|
||||
<ColorInput
|
||||
v-model="selectedMenuTextColorLocal"
|
||||
name="selectedMenuText"
|
||||
:label="$t('settings.text')"
|
||||
:fallback="previewTheme.colors.selectedMenuText"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.selectedMenuText" />
|
||||
<ColorInput
|
||||
v-model="selectedMenuLinkColorLocal"
|
||||
name="selectedMenuLink"
|
||||
:label="$t('settings.links')"
|
||||
:fallback="previewTheme.colors.selectedMenuLink"
|
||||
/>
|
||||
<ContrastRatio :contrast="previewContrast.selectedMenuLink" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
@ -491,7 +860,7 @@
|
||||
{{ $t('settings.style.switcher.clear_all') }}
|
||||
</button>
|
||||
</div>
|
||||
<shadow-control
|
||||
<ShadowControl
|
||||
v-model="currentShadow"
|
||||
:ready="!!currentShadowFallback"
|
||||
:fallback="currentShadowFallback"
|
||||
|
@ -52,6 +52,11 @@
|
||||
margin-bottom: 6px - 99px;
|
||||
white-space: nowrap;
|
||||
|
||||
color: $fallback--text;
|
||||
color: var(--tabText, $fallback--text);
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--tab, $fallback--fg);
|
||||
|
||||
&:not(.active) {
|
||||
z-index: 4;
|
||||
|
||||
@ -63,6 +68,8 @@
|
||||
&.active {
|
||||
background: transparent;
|
||||
z-index: 5;
|
||||
color: $fallback--text;
|
||||
color: var(--tabActiveText, $fallback--text);
|
||||
}
|
||||
|
||||
img {
|
||||
|
@ -151,7 +151,7 @@
|
||||
</ProgressButton>
|
||||
<ProgressButton
|
||||
v-else
|
||||
class="btn btn-default pressed"
|
||||
class="btn btn-default toggled"
|
||||
:click="unsubscribeUser"
|
||||
:title="$t('user_card.unsubscribe')"
|
||||
>
|
||||
@ -162,7 +162,7 @@
|
||||
<div>
|
||||
<button
|
||||
v-if="user.muted"
|
||||
class="btn btn-default btn-block pressed"
|
||||
class="btn btn-default btn-block toggled"
|
||||
@click="unmuteUser"
|
||||
>
|
||||
{{ $t('user_card.muted') }}
|
||||
@ -299,6 +299,11 @@
|
||||
&-bio {
|
||||
text-align: center;
|
||||
|
||||
a {
|
||||
color: $fallback--link;
|
||||
color: var(--postLink, $fallback--link);
|
||||
}
|
||||
|
||||
img {
|
||||
object-fit: contain;
|
||||
vertical-align: middle;
|
||||
@ -460,14 +465,13 @@
|
||||
color: var(--text, $fallback--text);
|
||||
}
|
||||
|
||||
// TODO use proper colors
|
||||
.staff {
|
||||
flex: none;
|
||||
text-transform: capitalize;
|
||||
color: $fallback--text;
|
||||
color: var(--btnText, $fallback--text);
|
||||
color: var(--alertNeutralText, $fallback--text);
|
||||
background-color: $fallback--fg;
|
||||
background-color: var(--btn, $fallback--fg);
|
||||
background-color: var(--alertNeutral, $fallback--fg);
|
||||
}
|
||||
}
|
||||
|
||||
@ -538,12 +542,6 @@
|
||||
|
||||
button {
|
||||
margin: 0;
|
||||
|
||||
&.pressed {
|
||||
// TODO: This should be themed.
|
||||
border-bottom-color: rgba(255, 255, 255, 0.2);
|
||||
border-top-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -63,6 +63,7 @@
|
||||
"optional": "optional",
|
||||
"show_more": "Show more",
|
||||
"show_less": "Show less",
|
||||
"dismiss": "Dismiss",
|
||||
"cancel": "Cancel",
|
||||
"disable": "Disable",
|
||||
"enable": "Enable",
|
||||
@ -295,6 +296,7 @@
|
||||
"follow_import": "Follow import",
|
||||
"follow_import_error": "Error importing followers",
|
||||
"follows_imported": "Follows imported! Processing them will take a while.",
|
||||
"accent": "Accent",
|
||||
"foreground": "Foreground",
|
||||
"general": "General",
|
||||
"hide_attachments_in_convo": "Hide attachments in conversations",
|
||||
@ -420,7 +422,24 @@
|
||||
"save_load_hint": "\"Keep\" options preserve currently set options when selecting or loading themes, it also stores said options when exporting a theme. When all checkboxes unset, exporting theme will save everything.",
|
||||
"reset": "Reset",
|
||||
"clear_all": "Clear all",
|
||||
"clear_opacity": "Clear opacity"
|
||||
"clear_opacity": "Clear opacity",
|
||||
"load_theme": "Load theme",
|
||||
"keep_as_is": "Keep as is",
|
||||
"use_snapshot": "Old version",
|
||||
"use_source": "New version",
|
||||
"help": {
|
||||
"upgraded_from_v2": "PleromaFE has been upgraded, theme could look a little bit different than you remember.",
|
||||
"v2_imported": "File you imported was made for older FE. We try to maximize compatibility but there still could be inconsitencies.",
|
||||
"future_version_imported": "File you imported was made in newer version of FE.",
|
||||
"older_version_imported": "File you imported was made in older version of FE.",
|
||||
"snapshot_present": "Theme snapshot is loaded, so all values are overriden. You can load theme's actual data instead.",
|
||||
"snapshot_missing": "No theme snapshot was in the file so it could look different than originally envisioned.",
|
||||
"fe_upgraded": "PleromaFE's theme engine upgraded after version update.",
|
||||
"fe_downgraded": "PleromaFE's version rolled back.",
|
||||
"migration_snapshot_ok": "Just to be safe, theme snapshot loaded. You can try loading theme data.",
|
||||
"migration_napshot_gone": "For whatever reason snapshot was missing, some stuff could look different than you remember.",
|
||||
"snapshot_source_mismatch": "Versions conflict: most likely FE was rolled back and updated again, if you changed theme using older version of FE you most likely want to use old version, otherwise use new version."
|
||||
}
|
||||
},
|
||||
"common": {
|
||||
"color": "Color",
|
||||
@ -449,14 +468,27 @@
|
||||
"alert": "Alert background",
|
||||
"alert_error": "Error",
|
||||
"alert_warning": "Warning",
|
||||
"alert_neutral": "Neutral",
|
||||
"post": "Posts/User bios",
|
||||
"badge": "Badge background",
|
||||
"popover": "Tooltips, menus, popovers",
|
||||
"badge_notification": "Notification",
|
||||
"panel_header": "Panel header",
|
||||
"top_bar": "Top bar",
|
||||
"borders": "Borders",
|
||||
"buttons": "Buttons",
|
||||
"inputs": "Input fields",
|
||||
"faint_text": "Faded text"
|
||||
"faint_text": "Faded text",
|
||||
"underlay": "Underlay",
|
||||
"poll": "Poll graph",
|
||||
"icons": "Icons",
|
||||
"highlight": "Highlighted elements",
|
||||
"pressed": "Pressed",
|
||||
"selectedPost": "Selected post",
|
||||
"selectedMenu": "Selected menu item",
|
||||
"disabled": "Disabled",
|
||||
"toggled": "Toggled",
|
||||
"tabs": "Tabs"
|
||||
},
|
||||
"radii": {
|
||||
"_tab_label": "Roundness"
|
||||
@ -469,7 +501,7 @@
|
||||
"blur": "Blur",
|
||||
"spread": "Spread",
|
||||
"inset": "Inset",
|
||||
"hint": "For shadows you can also use --variable as a color value to use CSS3 variables. Please note that setting opacity won't work in this case.",
|
||||
"hintV3": "For shadows you can also use the {0} notation to use other color slot.",
|
||||
"filter_hint": {
|
||||
"always_drop_shadow": "Warning, this shadow always uses {0} when browser supports it.",
|
||||
"drop_shadow_syntax": "{0} does not support {1} parameter and {2} keyword.",
|
||||
|
@ -5,6 +5,9 @@ const browserLocale = (window.navigator.language || 'en').split('-')[0]
|
||||
|
||||
export const defaultState = {
|
||||
colors: {},
|
||||
theme: undefined,
|
||||
customTheme: undefined,
|
||||
customThemeSource: undefined,
|
||||
hideISP: false,
|
||||
// bad name: actually hides posts of muted USERS
|
||||
hideMutedPosts: undefined, // instance default
|
||||
@ -96,10 +99,10 @@ const config = {
|
||||
commit('setOption', { name, value })
|
||||
switch (name) {
|
||||
case 'theme':
|
||||
setPreset(value, commit)
|
||||
setPreset(value)
|
||||
break
|
||||
case 'customTheme':
|
||||
applyTheme(value, commit)
|
||||
applyTheme(value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { set } from 'vue'
|
||||
import { setPreset } from '../services/style_setter/style_setter.js'
|
||||
import { getPreset, applyTheme } from '../services/style_setter/style_setter.js'
|
||||
import { instanceDefaultProperties } from './config.js'
|
||||
|
||||
const defaultState = {
|
||||
@ -10,6 +10,7 @@ const defaultState = {
|
||||
textlimit: 5000,
|
||||
server: 'http://localhost:4040/',
|
||||
theme: 'pleroma-dark',
|
||||
themeData: undefined,
|
||||
background: '/static/aurora_borealis.jpg',
|
||||
logo: '/static/logo.png',
|
||||
logoMask: true,
|
||||
@ -96,6 +97,9 @@ const instance = {
|
||||
dispatch('initializeSocket')
|
||||
}
|
||||
break
|
||||
case 'theme':
|
||||
dispatch('setTheme', value)
|
||||
break
|
||||
}
|
||||
},
|
||||
async getStaticEmoji ({ commit }) {
|
||||
@ -147,9 +151,16 @@ const instance = {
|
||||
}
|
||||
},
|
||||
|
||||
setTheme ({ commit }, themeName) {
|
||||
setTheme ({ commit, rootState }, themeName) {
|
||||
commit('setInstanceOption', { name: 'theme', value: themeName })
|
||||
return setPreset(themeName, commit)
|
||||
getPreset(themeName)
|
||||
.then(themeData => {
|
||||
commit('setInstanceOption', { name: 'themeData', value: themeData })
|
||||
// No need to apply theme if there's user theme already
|
||||
const { customTheme } = rootState.config
|
||||
if (customTheme) return
|
||||
applyTheme(themeData.theme)
|
||||
})
|
||||
},
|
||||
fetchEmoji ({ dispatch, state }) {
|
||||
if (!state.customEmojiFetched) {
|
||||
|
@ -1,16 +1,27 @@
|
||||
import { map } from 'lodash'
|
||||
import { invertLightness, contrastRatio } from 'chromatism'
|
||||
|
||||
const rgb2hex = (r, g, b) => {
|
||||
// useful for visualizing color when debugging
|
||||
export const consoleColor = (color) => console.log('%c##########', 'background: ' + color + '; color: ' + color)
|
||||
|
||||
/**
|
||||
* Convert r, g, b values into hex notation. All components are [0-255]
|
||||
*
|
||||
* @param {Number|String|Object} r - Either red component, {r,g,b} object, or hex string
|
||||
* @param {Number} [g] - Green component
|
||||
* @param {Number} [b] - Blue component
|
||||
*/
|
||||
export const rgb2hex = (r, g, b) => {
|
||||
if (r === null || typeof r === 'undefined') {
|
||||
return undefined
|
||||
}
|
||||
if (r[0] === '#') {
|
||||
// TODO: clean up this mess
|
||||
if (r[0] === '#' || r === 'transparent') {
|
||||
return r
|
||||
}
|
||||
if (typeof r === 'object') {
|
||||
({ r, g, b } = r)
|
||||
}
|
||||
[r, g, b] = map([r, g, b], (val) => {
|
||||
[r, g, b] = [r, g, b].map(val => {
|
||||
val = Math.ceil(val)
|
||||
val = val < 0 ? 0 : val
|
||||
val = val > 255 ? 255 : val
|
||||
@ -58,7 +69,7 @@ const srgbToLinear = (srgb) => {
|
||||
* @param {Object} srgb - sRGB color
|
||||
* @returns {Number} relative luminance
|
||||
*/
|
||||
const relativeLuminance = (srgb) => {
|
||||
export const relativeLuminance = (srgb) => {
|
||||
const { r, g, b } = srgbToLinear(srgb)
|
||||
return 0.2126 * r + 0.7152 * g + 0.0722 * b
|
||||
}
|
||||
@ -71,7 +82,7 @@ const relativeLuminance = (srgb) => {
|
||||
* @param {Object} b - sRGB color
|
||||
* @returns {Number} color ratio
|
||||
*/
|
||||
const getContrastRatio = (a, b) => {
|
||||
export const getContrastRatio = (a, b) => {
|
||||
const la = relativeLuminance(a)
|
||||
const lb = relativeLuminance(b)
|
||||
const [l1, l2] = la > lb ? [la, lb] : [lb, la]
|
||||
@ -79,6 +90,17 @@ const getContrastRatio = (a, b) => {
|
||||
return (l1 + 0.05) / (l2 + 0.05)
|
||||
}
|
||||
|
||||
/**
|
||||
* Same as `getContrastRatio` but for multiple layers in-between
|
||||
*
|
||||
* @param {Object} text - text color (topmost layer)
|
||||
* @param {[Object, Number]} layers[] - layers between text and bedrock
|
||||
* @param {Object} bedrock - layer at the very bottom
|
||||
*/
|
||||
export const getContrastRatioLayers = (text, layers, bedrock) => {
|
||||
return getContrastRatio(alphaBlendLayers(bedrock, layers), text)
|
||||
}
|
||||
|
||||
/**
|
||||
* This performs alpha blending between solid background and semi-transparent foreground
|
||||
*
|
||||
@ -87,7 +109,7 @@ const getContrastRatio = (a, b) => {
|
||||
* @param {Object} bg - bottom layer color
|
||||
* @returns {Object} sRGB of resulting color
|
||||
*/
|
||||
const alphaBlend = (fg, fga, bg) => {
|
||||
export const alphaBlend = (fg, fga, bg) => {
|
||||
if (fga === 1 || typeof fga === 'undefined') return fg
|
||||
return 'rgb'.split('').reduce((acc, c) => {
|
||||
// Simplified https://en.wikipedia.org/wiki/Alpha_compositing#Alpha_blending
|
||||
@ -97,14 +119,30 @@ const alphaBlend = (fg, fga, bg) => {
|
||||
}, {})
|
||||
}
|
||||
|
||||
const invert = (rgb) => {
|
||||
/**
|
||||
* Same as `alphaBlend` but for multiple layers in-between
|
||||
*
|
||||
* @param {Object} bedrock - layer at the very bottom
|
||||
* @param {[Object, Number]} layers[] - layers between text and bedrock
|
||||
*/
|
||||
export const alphaBlendLayers = (bedrock, layers) => layers.reduce((acc, [color, opacity]) => {
|
||||
return alphaBlend(color, opacity, acc)
|
||||
}, bedrock)
|
||||
|
||||
export const invert = (rgb) => {
|
||||
return 'rgb'.split('').reduce((acc, c) => {
|
||||
acc[c] = 255 - rgb[c]
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
const hex2rgb = (hex) => {
|
||||
/**
|
||||
* Converts #rrggbb hex notation into an {r, g, b} object
|
||||
*
|
||||
* @param {String} hex - #rrggbb string
|
||||
* @returns {Object} rgb representation of the color, values are 0-255
|
||||
*/
|
||||
export const hex2rgb = (hex) => {
|
||||
const result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex)
|
||||
return result ? {
|
||||
r: parseInt(result[1], 16),
|
||||
@ -113,18 +151,72 @@ const hex2rgb = (hex) => {
|
||||
} : null
|
||||
}
|
||||
|
||||
const mixrgb = (a, b) => {
|
||||
return Object.keys(a).reduce((acc, k) => {
|
||||
/**
|
||||
* Old somewhat weird function for mixing two colors together
|
||||
*
|
||||
* @param {Object} a - one color (rgb)
|
||||
* @param {Object} b - other color (rgb)
|
||||
* @returns {Object} result
|
||||
*/
|
||||
export const mixrgb = (a, b) => {
|
||||
return 'rgb'.split('').reduce((acc, k) => {
|
||||
acc[k] = (a[k] + b[k]) / 2
|
||||
return acc
|
||||
}, {})
|
||||
}
|
||||
|
||||
export {
|
||||
rgb2hex,
|
||||
hex2rgb,
|
||||
mixrgb,
|
||||
invert,
|
||||
getContrastRatio,
|
||||
alphaBlend
|
||||
/**
|
||||
* Converts rgb object into a CSS rgba() color
|
||||
*
|
||||
* @param {Object} color - rgb
|
||||
* @returns {String} CSS rgba() color
|
||||
*/
|
||||
export const rgba2css = function (rgba) {
|
||||
return `rgba(${Math.floor(rgba.r)}, ${Math.floor(rgba.g)}, ${Math.floor(rgba.b)}, ${rgba.a})`
|
||||
}
|
||||
|
||||
/**
|
||||
* Get text color for given background color and intended text color
|
||||
* This checks if text and background don't have enough color and inverts
|
||||
* text color's lightness if needed. If text color is still not enough it
|
||||
* will fall back to black or white
|
||||
*
|
||||
* @param {Object} bg - background color
|
||||
* @param {Object} text - intended text color
|
||||
* @param {Boolean} preserve - try to preserve intended text color's hue/saturation (i.e. no BW)
|
||||
*/
|
||||
export const getTextColor = function (bg, text, preserve) {
|
||||
const contrast = getContrastRatio(bg, text)
|
||||
|
||||
if (contrast < 4.5) {
|
||||
const base = typeof text.a !== 'undefined' ? { a: text.a } : {}
|
||||
const result = Object.assign(base, invertLightness(text).rgb)
|
||||
if (!preserve && getContrastRatio(bg, result) < 4.5) {
|
||||
// B&W
|
||||
return contrastRatio(bg, text).rgb
|
||||
}
|
||||
// Inverted color
|
||||
return result
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts color to CSS Color value
|
||||
*
|
||||
* @param {Object|String} input - color
|
||||
* @param {Number} [a] - alpha value
|
||||
* @returns {String} a CSS Color value
|
||||
*/
|
||||
export const getCssColor = (input, a) => {
|
||||
let rgb = {}
|
||||
if (typeof input === 'object') {
|
||||
rgb = input
|
||||
} else if (typeof input === 'string') {
|
||||
if (input.startsWith('#')) {
|
||||
rgb = hex2rgb(input)
|
||||
} else {
|
||||
return input
|
||||
}
|
||||
}
|
||||
return rgba2css({ ...rgb, a })
|
||||
}
|
||||
|
@ -1,78 +1,9 @@
|
||||
import { times } from 'lodash'
|
||||
import { brightness, invertLightness, convert, contrastRatio } from 'chromatism'
|
||||
import { rgb2hex, hex2rgb, mixrgb, getContrastRatio, alphaBlend } from '../color_convert/color_convert.js'
|
||||
import { convert } from 'chromatism'
|
||||
import { rgb2hex, hex2rgb, rgba2css, getCssColor, relativeLuminance } from '../color_convert/color_convert.js'
|
||||
import { getColors, computeDynamicColor, getOpacitySlot } from '../theme_data/theme_data.service.js'
|
||||
|
||||
// While this is not used anymore right now, I left it in if we want to do custom
|
||||
// styles that aren't just colors, so user can pick from a few different distinct
|
||||
// styles as well as set their own colors in the future.
|
||||
|
||||
const setStyle = (href, commit) => {
|
||||
/***
|
||||
What's going on here?
|
||||
I want to make it easy for admins to style this application. To have
|
||||
a good set of default themes, I chose the system from base16
|
||||
(https://chriskempson.github.io/base16/) to style all elements. They
|
||||
all have the base00..0F classes. So the only thing an admin needs to
|
||||
do to style Pleroma is to change these colors in that one css file.
|
||||
Some default things (body text color, link color) need to be set dy-
|
||||
namically, so this is done here by waiting for the stylesheet to be
|
||||
loaded and then creating an element with the respective classes.
|
||||
|
||||
It is a bit weird, but should make life for admins somewhat easier.
|
||||
***/
|
||||
const head = document.head
|
||||
const body = document.body
|
||||
body.classList.add('hidden')
|
||||
const cssEl = document.createElement('link')
|
||||
cssEl.setAttribute('rel', 'stylesheet')
|
||||
cssEl.setAttribute('href', href)
|
||||
head.appendChild(cssEl)
|
||||
|
||||
const setDynamic = () => {
|
||||
const baseEl = document.createElement('div')
|
||||
body.appendChild(baseEl)
|
||||
|
||||
let colors = {}
|
||||
times(16, (n) => {
|
||||
const name = `base0${n.toString(16).toUpperCase()}`
|
||||
baseEl.setAttribute('class', name)
|
||||
const color = window.getComputedStyle(baseEl).getPropertyValue('color')
|
||||
colors[name] = color
|
||||
})
|
||||
|
||||
body.removeChild(baseEl)
|
||||
|
||||
const styleEl = document.createElement('style')
|
||||
head.appendChild(styleEl)
|
||||
// const styleSheet = styleEl.sheet
|
||||
|
||||
body.classList.remove('hidden')
|
||||
}
|
||||
|
||||
cssEl.addEventListener('load', setDynamic)
|
||||
}
|
||||
|
||||
const rgb2rgba = function (rgba) {
|
||||
return `rgba(${rgba.r}, ${rgba.g}, ${rgba.b}, ${rgba.a})`
|
||||
}
|
||||
|
||||
const getTextColor = function (bg, text, preserve) {
|
||||
const bgIsLight = convert(bg).hsl.l > 50
|
||||
const textIsLight = convert(text).hsl.l > 50
|
||||
|
||||
if ((bgIsLight && textIsLight) || (!bgIsLight && !textIsLight)) {
|
||||
const base = typeof text.a !== 'undefined' ? { a: text.a } : {}
|
||||
const result = Object.assign(base, invertLightness(text).rgb)
|
||||
if (!preserve && getContrastRatio(bg, result) < 4.5) {
|
||||
return contrastRatio(bg, text).rgb
|
||||
}
|
||||
return result
|
||||
}
|
||||
return text
|
||||
}
|
||||
|
||||
const applyTheme = (input, commit) => {
|
||||
const { rules, theme } = generatePreset(input)
|
||||
export const applyTheme = (input) => {
|
||||
const { rules } = generatePreset(input)
|
||||
const head = document.head
|
||||
const body = document.body
|
||||
body.classList.add('hidden')
|
||||
@ -87,14 +18,9 @@ const applyTheme = (input, commit) => {
|
||||
styleSheet.insertRule(`body { ${rules.shadows} }`, 'index-max')
|
||||
styleSheet.insertRule(`body { ${rules.fonts} }`, 'index-max')
|
||||
body.classList.remove('hidden')
|
||||
|
||||
// commit('setOption', { name: 'colors', value: htmlColors })
|
||||
// commit('setOption', { name: 'radii', value: radii })
|
||||
commit('setOption', { name: 'customTheme', value: input })
|
||||
commit('setOption', { name: 'colors', value: theme.colors })
|
||||
}
|
||||
|
||||
const getCssShadow = (input, usesDropShadow) => {
|
||||
export const getCssShadow = (input, usesDropShadow) => {
|
||||
if (input.length === 0) {
|
||||
return 'none'
|
||||
}
|
||||
@ -132,122 +58,18 @@ const getCssShadowFilter = (input) => {
|
||||
.join(' ')
|
||||
}
|
||||
|
||||
const getCssColor = (input, a) => {
|
||||
let rgb = {}
|
||||
if (typeof input === 'object') {
|
||||
rgb = input
|
||||
} else if (typeof input === 'string') {
|
||||
if (input.startsWith('#')) {
|
||||
rgb = hex2rgb(input)
|
||||
} else if (input.startsWith('--')) {
|
||||
return `var(${input})`
|
||||
} else {
|
||||
return input
|
||||
}
|
||||
}
|
||||
return rgb2rgba({ ...rgb, a })
|
||||
}
|
||||
export const generateColors = (themeData) => {
|
||||
const sourceColors = !themeData.themeEngineVersion
|
||||
? colors2to3(themeData.colors || themeData)
|
||||
: themeData.colors || themeData
|
||||
|
||||
const generateColors = (input) => {
|
||||
const colors = {}
|
||||
const opacity = Object.assign({
|
||||
alert: 0.5,
|
||||
input: 0.5,
|
||||
faint: 0.5
|
||||
}, Object.entries(input.opacity || {}).reduce((acc, [k, v]) => {
|
||||
if (typeof v !== 'undefined') {
|
||||
acc[k] = v
|
||||
}
|
||||
return acc
|
||||
}, {}))
|
||||
const col = Object.entries(input.colors || input).reduce((acc, [k, v]) => {
|
||||
if (typeof v === 'object') {
|
||||
acc[k] = v
|
||||
} else {
|
||||
acc[k] = hex2rgb(v)
|
||||
}
|
||||
return acc
|
||||
}, {})
|
||||
|
||||
const isLightOnDark = convert(col.bg).hsl.l < convert(col.text).hsl.l
|
||||
const mod = isLightOnDark ? 1 : -1
|
||||
|
||||
colors.text = col.text
|
||||
colors.lightText = brightness(20 * mod, colors.text).rgb
|
||||
colors.link = col.link
|
||||
colors.faint = col.faint || Object.assign({}, col.text)
|
||||
|
||||
colors.bg = col.bg
|
||||
colors.lightBg = col.lightBg || brightness(5, colors.bg).rgb
|
||||
|
||||
colors.fg = col.fg
|
||||
colors.fgText = col.fgText || getTextColor(colors.fg, colors.text)
|
||||
colors.fgLink = col.fgLink || getTextColor(colors.fg, colors.link, true)
|
||||
|
||||
colors.border = col.border || brightness(2 * mod, colors.fg).rgb
|
||||
|
||||
colors.btn = col.btn || Object.assign({}, col.fg)
|
||||
colors.btnText = col.btnText || getTextColor(colors.btn, colors.fgText)
|
||||
|
||||
colors.input = col.input || Object.assign({}, col.fg)
|
||||
colors.inputText = col.inputText || getTextColor(colors.input, colors.lightText)
|
||||
|
||||
colors.panel = col.panel || Object.assign({}, col.fg)
|
||||
colors.panelText = col.panelText || getTextColor(colors.panel, colors.fgText)
|
||||
colors.panelLink = col.panelLink || getTextColor(colors.panel, colors.fgLink)
|
||||
colors.panelFaint = col.panelFaint || getTextColor(colors.panel, colors.faint)
|
||||
|
||||
colors.topBar = col.topBar || Object.assign({}, col.fg)
|
||||
colors.topBarText = col.topBarText || getTextColor(colors.topBar, colors.fgText)
|
||||
colors.topBarLink = col.topBarLink || getTextColor(colors.topBar, colors.fgLink)
|
||||
|
||||
colors.faintLink = col.faintLink || Object.assign({}, col.link)
|
||||
colors.linkBg = alphaBlend(colors.link, 0.4, colors.bg)
|
||||
|
||||
colors.icon = mixrgb(colors.bg, colors.text)
|
||||
|
||||
colors.cBlue = col.cBlue || hex2rgb('#0000FF')
|
||||
colors.cRed = col.cRed || hex2rgb('#FF0000')
|
||||
colors.cGreen = col.cGreen || hex2rgb('#00FF00')
|
||||
colors.cOrange = col.cOrange || hex2rgb('#E3FF00')
|
||||
|
||||
colors.alertError = col.alertError || Object.assign({}, colors.cRed)
|
||||
colors.alertErrorText = getTextColor(alphaBlend(colors.alertError, opacity.alert, colors.bg), colors.text)
|
||||
colors.alertErrorPanelText = getTextColor(alphaBlend(colors.alertError, opacity.alert, colors.panel), colors.panelText)
|
||||
|
||||
colors.alertWarning = col.alertWarning || Object.assign({}, colors.cOrange)
|
||||
colors.alertWarningText = getTextColor(alphaBlend(colors.alertWarning, opacity.alert, colors.bg), colors.text)
|
||||
colors.alertWarningPanelText = getTextColor(alphaBlend(colors.alertWarning, opacity.alert, colors.panel), colors.panelText)
|
||||
|
||||
colors.badgeNotification = col.badgeNotification || Object.assign({}, colors.cRed)
|
||||
colors.badgeNotificationText = contrastRatio(colors.badgeNotification).rgb
|
||||
|
||||
Object.entries(opacity).forEach(([ k, v ]) => {
|
||||
if (typeof v === 'undefined') return
|
||||
if (k === 'alert') {
|
||||
colors.alertError.a = v
|
||||
colors.alertWarning.a = v
|
||||
return
|
||||
}
|
||||
if (k === 'faint') {
|
||||
colors[k + 'Link'].a = v
|
||||
colors['panelFaint'].a = v
|
||||
}
|
||||
if (k === 'bg') {
|
||||
colors['lightBg'].a = v
|
||||
}
|
||||
if (colors[k]) {
|
||||
colors[k].a = v
|
||||
} else {
|
||||
console.error('Wrong key ' + k)
|
||||
}
|
||||
})
|
||||
const { colors, opacity } = getColors(sourceColors, themeData.opacity || {})
|
||||
|
||||
const htmlColors = Object.entries(colors)
|
||||
.reduce((acc, [k, v]) => {
|
||||
if (!v) return acc
|
||||
acc.solid[k] = rgb2hex(v)
|
||||
acc.complete[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgb2rgba(v)
|
||||
acc.complete[k] = typeof v.a === 'undefined' ? rgb2hex(v) : rgba2css(v)
|
||||
return acc
|
||||
}, { complete: {}, solid: {} })
|
||||
return {
|
||||
@ -264,7 +86,7 @@ const generateColors = (input) => {
|
||||
}
|
||||
}
|
||||
|
||||
const generateRadii = (input) => {
|
||||
export const generateRadii = (input) => {
|
||||
let inputRadii = input.radii || {}
|
||||
// v1 -> v2
|
||||
if (typeof input.btnRadius !== 'undefined') {
|
||||
@ -297,7 +119,7 @@ const generateRadii = (input) => {
|
||||
}
|
||||
}
|
||||
|
||||
const generateFonts = (input) => {
|
||||
export const generateFonts = (input) => {
|
||||
const fonts = Object.entries(input.fonts || {}).filter(([k, v]) => v).reduce((acc, [k, v]) => {
|
||||
acc[k] = Object.entries(v).filter(([k, v]) => v).reduce((acc, [k, v]) => {
|
||||
acc[k] = v
|
||||
@ -332,89 +154,123 @@ const generateFonts = (input) => {
|
||||
}
|
||||
}
|
||||
|
||||
const generateShadows = (input) => {
|
||||
const border = (top, shadow) => ({
|
||||
x: 0,
|
||||
y: top ? 1 : -1,
|
||||
blur: 0,
|
||||
const border = (top, shadow) => ({
|
||||
x: 0,
|
||||
y: top ? 1 : -1,
|
||||
blur: 0,
|
||||
spread: 0,
|
||||
color: shadow ? '#000000' : '#FFFFFF',
|
||||
alpha: 0.2,
|
||||
inset: true
|
||||
})
|
||||
const buttonInsetFakeBorders = [border(true, false), border(false, true)]
|
||||
const inputInsetFakeBorders = [border(true, true), border(false, false)]
|
||||
const hoverGlow = {
|
||||
x: 0,
|
||||
y: 0,
|
||||
blur: 4,
|
||||
spread: 0,
|
||||
color: '--faint',
|
||||
alpha: 1
|
||||
}
|
||||
|
||||
export const DEFAULT_SHADOWS = {
|
||||
panel: [{
|
||||
x: 1,
|
||||
y: 1,
|
||||
blur: 4,
|
||||
spread: 0,
|
||||
color: shadow ? '#000000' : '#FFFFFF',
|
||||
alpha: 0.2,
|
||||
inset: true
|
||||
})
|
||||
const buttonInsetFakeBorders = [border(true, false), border(false, true)]
|
||||
const inputInsetFakeBorders = [border(true, true), border(false, false)]
|
||||
const hoverGlow = {
|
||||
color: '#000000',
|
||||
alpha: 0.6
|
||||
}],
|
||||
topBar: [{
|
||||
x: 0,
|
||||
y: 0,
|
||||
blur: 4,
|
||||
spread: 0,
|
||||
color: '--faint',
|
||||
color: '#000000',
|
||||
alpha: 0.6
|
||||
}],
|
||||
popup: [{
|
||||
x: 2,
|
||||
y: 2,
|
||||
blur: 3,
|
||||
spread: 0,
|
||||
color: '#000000',
|
||||
alpha: 0.5
|
||||
}],
|
||||
avatar: [{
|
||||
x: 0,
|
||||
y: 1,
|
||||
blur: 8,
|
||||
spread: 0,
|
||||
color: '#000000',
|
||||
alpha: 0.7
|
||||
}],
|
||||
avatarStatus: [],
|
||||
panelHeader: [],
|
||||
button: [{
|
||||
x: 0,
|
||||
y: 0,
|
||||
blur: 2,
|
||||
spread: 0,
|
||||
color: '#000000',
|
||||
alpha: 1
|
||||
}, ...buttonInsetFakeBorders],
|
||||
buttonHover: [hoverGlow, ...buttonInsetFakeBorders],
|
||||
buttonPressed: [hoverGlow, ...inputInsetFakeBorders],
|
||||
input: [...inputInsetFakeBorders, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
blur: 2,
|
||||
inset: true,
|
||||
spread: 0,
|
||||
color: '#000000',
|
||||
alpha: 1
|
||||
}]
|
||||
}
|
||||
export const generateShadows = (input, colors) => {
|
||||
// TODO this is a small hack for `mod` to work with shadows
|
||||
// this is used to get the "context" of shadow, i.e. for `mod` properly depend on background color of element
|
||||
const hackContextDict = {
|
||||
button: 'btn',
|
||||
panel: 'bg',
|
||||
top: 'topBar',
|
||||
popup: 'popover',
|
||||
avatar: 'bg',
|
||||
panelHeader: 'panel',
|
||||
input: 'input'
|
||||
}
|
||||
|
||||
const shadows = {
|
||||
panel: [{
|
||||
x: 1,
|
||||
y: 1,
|
||||
blur: 4,
|
||||
spread: 0,
|
||||
color: '#000000',
|
||||
alpha: 0.6
|
||||
}],
|
||||
topBar: [{
|
||||
x: 0,
|
||||
y: 0,
|
||||
blur: 4,
|
||||
spread: 0,
|
||||
color: '#000000',
|
||||
alpha: 0.6
|
||||
}],
|
||||
popup: [{
|
||||
x: 2,
|
||||
y: 2,
|
||||
blur: 3,
|
||||
spread: 0,
|
||||
color: '#000000',
|
||||
alpha: 0.5
|
||||
}],
|
||||
avatar: [{
|
||||
x: 0,
|
||||
y: 1,
|
||||
blur: 8,
|
||||
spread: 0,
|
||||
color: '#000000',
|
||||
alpha: 0.7
|
||||
}],
|
||||
avatarStatus: [],
|
||||
panelHeader: [],
|
||||
button: [{
|
||||
x: 0,
|
||||
y: 0,
|
||||
blur: 2,
|
||||
spread: 0,
|
||||
color: '#000000',
|
||||
alpha: 1
|
||||
}, ...buttonInsetFakeBorders],
|
||||
buttonHover: [hoverGlow, ...buttonInsetFakeBorders],
|
||||
buttonPressed: [hoverGlow, ...inputInsetFakeBorders],
|
||||
input: [...inputInsetFakeBorders, {
|
||||
x: 0,
|
||||
y: 0,
|
||||
blur: 2,
|
||||
inset: true,
|
||||
spread: 0,
|
||||
color: '#000000',
|
||||
alpha: 1
|
||||
}],
|
||||
...(input.shadows || {})
|
||||
}
|
||||
const inputShadows = input.shadows && !input.themeEngineVersion
|
||||
? shadows2to3(input.shadows, input.opacity)
|
||||
: input.shadows || {}
|
||||
const shadows = Object.entries({
|
||||
...DEFAULT_SHADOWS,
|
||||
...inputShadows
|
||||
}).reduce((shadowsAcc, [slotName, shadowDefs]) => {
|
||||
const slotFirstWord = slotName.replace(/[A-Z].*$/, '')
|
||||
const colorSlotName = hackContextDict[slotFirstWord]
|
||||
const isLightOnDark = relativeLuminance(convert(colors[colorSlotName]).rgb) < 0.5
|
||||
const mod = isLightOnDark ? 1 : -1
|
||||
const newShadow = shadowDefs.reduce((shadowAcc, def) => [
|
||||
...shadowAcc,
|
||||
{
|
||||
...def,
|
||||
color: rgb2hex(computeDynamicColor(
|
||||
def.color,
|
||||
(variableSlot) => convert(colors[variableSlot]).rgb,
|
||||
mod
|
||||
))
|
||||
}
|
||||
], [])
|
||||
return { ...shadowsAcc, [slotName]: newShadow }
|
||||
}, {})
|
||||
|
||||
return {
|
||||
rules: {
|
||||
shadows: Object
|
||||
.entries(shadows)
|
||||
// TODO for v2.1: if shadow doesn't have non-inset shadows with spread > 0 - optionally
|
||||
// TODO for v2.2: if shadow doesn't have non-inset shadows with spread > 0 - optionally
|
||||
// convert all non-inset shadows into filter: drop-shadow() to boost performance
|
||||
.map(([k, v]) => [
|
||||
`--${k}Shadow: ${getCssShadow(v)}`,
|
||||
@ -429,7 +285,7 @@ const generateShadows = (input) => {
|
||||
}
|
||||
}
|
||||
|
||||
const composePreset = (colors, radii, shadows, fonts) => {
|
||||
export const composePreset = (colors, radii, shadows, fonts) => {
|
||||
return {
|
||||
rules: {
|
||||
...shadows.rules,
|
||||
@ -446,98 +302,110 @@ const composePreset = (colors, radii, shadows, fonts) => {
|
||||
}
|
||||
}
|
||||
|
||||
const generatePreset = (input) => {
|
||||
const shadows = generateShadows(input)
|
||||
export const generatePreset = (input) => {
|
||||
const colors = generateColors(input)
|
||||
const radii = generateRadii(input)
|
||||
const fonts = generateFonts(input)
|
||||
|
||||
return composePreset(colors, radii, shadows, fonts)
|
||||
return composePreset(
|
||||
colors,
|
||||
generateRadii(input),
|
||||
generateShadows(input, colors.theme.colors, colors.mod),
|
||||
generateFonts(input)
|
||||
)
|
||||
}
|
||||
|
||||
const getThemes = () => {
|
||||
return window.fetch('/static/styles.json')
|
||||
export const getThemes = () => {
|
||||
const cache = 'no-store'
|
||||
|
||||
return window.fetch('/static/styles.json', { cache })
|
||||
.then((data) => data.json())
|
||||
.then((themes) => {
|
||||
return Promise.all(Object.entries(themes).map(([k, v]) => {
|
||||
return Object.entries(themes).map(([k, v]) => {
|
||||
let promise = null
|
||||
if (typeof v === 'object') {
|
||||
return Promise.resolve([k, v])
|
||||
promise = Promise.resolve(v)
|
||||
} else if (typeof v === 'string') {
|
||||
return window.fetch(v)
|
||||
promise = window.fetch(v, { cache })
|
||||
.then((data) => data.json())
|
||||
.then((theme) => {
|
||||
return [k, theme]
|
||||
})
|
||||
.catch((e) => {
|
||||
console.error(e)
|
||||
return []
|
||||
return null
|
||||
})
|
||||
}
|
||||
}))
|
||||
return [k, promise]
|
||||
})
|
||||
})
|
||||
.then((promises) => {
|
||||
return promises
|
||||
.filter(([k, v]) => v)
|
||||
.reduce((acc, [k, v]) => {
|
||||
acc[k] = v
|
||||
return acc
|
||||
}, {})
|
||||
})
|
||||
}
|
||||
export const colors2to3 = (colors) => {
|
||||
return Object.entries(colors).reduce((acc, [slotName, color]) => {
|
||||
const btnPositions = ['', 'Panel', 'TopBar']
|
||||
switch (slotName) {
|
||||
case 'lightBg':
|
||||
return { ...acc, highlight: color }
|
||||
case 'btnText':
|
||||
return {
|
||||
...acc,
|
||||
...btnPositions
|
||||
.reduce(
|
||||
(statePositionAcc, position) =>
|
||||
({ ...statePositionAcc, ['btn' + position + 'Text']: color })
|
||||
, {}
|
||||
)
|
||||
}
|
||||
default:
|
||||
return { ...acc, [slotName]: color }
|
||||
}
|
||||
}, {})
|
||||
}
|
||||
|
||||
const setPreset = (val, commit) => {
|
||||
return getThemes().then((themes) => {
|
||||
const theme = themes[val] ? themes[val] : themes['pleroma-dark']
|
||||
const isV1 = Array.isArray(theme)
|
||||
const data = isV1 ? {} : theme.theme
|
||||
|
||||
if (isV1) {
|
||||
const bgRgb = hex2rgb(theme[1])
|
||||
const fgRgb = hex2rgb(theme[2])
|
||||
const textRgb = hex2rgb(theme[3])
|
||||
const linkRgb = hex2rgb(theme[4])
|
||||
|
||||
const cRedRgb = hex2rgb(theme[5] || '#FF0000')
|
||||
const cGreenRgb = hex2rgb(theme[6] || '#00FF00')
|
||||
const cBlueRgb = hex2rgb(theme[7] || '#0000FF')
|
||||
const cOrangeRgb = hex2rgb(theme[8] || '#E3FF00')
|
||||
|
||||
data.colors = {
|
||||
bg: bgRgb,
|
||||
fg: fgRgb,
|
||||
text: textRgb,
|
||||
link: linkRgb,
|
||||
cRed: cRedRgb,
|
||||
cBlue: cBlueRgb,
|
||||
cGreen: cGreenRgb,
|
||||
cOrange: cOrangeRgb
|
||||
/**
|
||||
* This handles compatibility issues when importing v2 theme's shadows to current format
|
||||
*
|
||||
* Back in v2 shadows allowed you to use dynamic colors however those used pure CSS3 variables
|
||||
*/
|
||||
export const shadows2to3 = (shadows, opacity) => {
|
||||
return Object.entries(shadows).reduce((shadowsAcc, [slotName, shadowDefs]) => {
|
||||
const isDynamic = ({ color }) => color.startsWith('--')
|
||||
const getOpacity = ({ color }) => opacity[getOpacitySlot(color.substring(2).split(',')[0])]
|
||||
const newShadow = shadowDefs.reduce((shadowAcc, def) => [
|
||||
...shadowAcc,
|
||||
{
|
||||
...def,
|
||||
alpha: isDynamic(def) ? getOpacity(def) || 1 : def.alpha
|
||||
}
|
||||
}
|
||||
|
||||
// This is a hack, this function is only called during initial load.
|
||||
// We want to cancel loading the theme from config.json if we're already
|
||||
// loading a theme from the persisted state.
|
||||
// Needed some way of dealing with the async way of things.
|
||||
// load config -> set preset -> wait for styles.json to load ->
|
||||
// load persisted state -> set colors -> styles.json loaded -> set colors
|
||||
if (!window.themeLoaded) {
|
||||
applyTheme(data, commit)
|
||||
}
|
||||
})
|
||||
], [])
|
||||
return { ...shadowsAcc, [slotName]: newShadow }
|
||||
}, {})
|
||||
}
|
||||
|
||||
export {
|
||||
setStyle,
|
||||
setPreset,
|
||||
applyTheme,
|
||||
getTextColor,
|
||||
generateColors,
|
||||
generateRadii,
|
||||
generateShadows,
|
||||
generateFonts,
|
||||
generatePreset,
|
||||
getThemes,
|
||||
composePreset,
|
||||
getCssShadow,
|
||||
getCssShadowFilter
|
||||
export const getPreset = (val) => {
|
||||
return getThemes()
|
||||
.then((themes) => themes[val] ? themes[val] : themes['pleroma-dark'])
|
||||
.then((theme) => {
|
||||
const isV1 = Array.isArray(theme)
|
||||
const data = isV1 ? {} : theme.theme
|
||||
|
||||
if (isV1) {
|
||||
const bg = hex2rgb(theme[1])
|
||||
const fg = hex2rgb(theme[2])
|
||||
const text = hex2rgb(theme[3])
|
||||
const link = hex2rgb(theme[4])
|
||||
|
||||
const cRed = hex2rgb(theme[5] || '#FF0000')
|
||||
const cGreen = hex2rgb(theme[6] || '#00FF00')
|
||||
const cBlue = hex2rgb(theme[7] || '#0000FF')
|
||||
const cOrange = hex2rgb(theme[8] || '#E3FF00')
|
||||
|
||||
data.colors = { bg, fg, text, link, cRed, cBlue, cGreen, cOrange }
|
||||
}
|
||||
|
||||
return { theme: data, source: theme.source }
|
||||
})
|
||||
}
|
||||
|
||||
export const setPreset = (val) => getPreset(val).then(data => applyTheme(data.theme))
|
||||
|
615
src/services/theme_data/pleromafe.js
Normal file
615
src/services/theme_data/pleromafe.js
Normal file
@ -0,0 +1,615 @@
|
||||
import { invertLightness, brightness } from 'chromatism'
|
||||
import { alphaBlend, mixrgb } from '../color_convert/color_convert.js'
|
||||
/* This is a definition of all layer combinations
|
||||
* each key is a topmost layer, each value represents layer underneath
|
||||
* this is essentially a simplified tree
|
||||
*/
|
||||
export const LAYERS = {
|
||||
undelay: null, // root
|
||||
topBar: null, // no transparency support
|
||||
badge: null, // no transparency support
|
||||
fg: null,
|
||||
bg: 'underlay',
|
||||
highlight: 'bg',
|
||||
panel: 'bg',
|
||||
popover: 'bg',
|
||||
selectedMenu: 'popover',
|
||||
btn: 'bg',
|
||||
btnPanel: 'panel',
|
||||
btnTopBar: 'topBar',
|
||||
input: 'bg',
|
||||
inputPanel: 'panel',
|
||||
inputTopBar: 'topBar',
|
||||
alert: 'bg',
|
||||
alertPanel: 'panel',
|
||||
poll: 'bg'
|
||||
}
|
||||
|
||||
/* By default opacity slots have 1 as default opacity
|
||||
* this allows redefining it to something else
|
||||
*/
|
||||
export const DEFAULT_OPACITY = {
|
||||
alert: 0.5,
|
||||
input: 0.5,
|
||||
faint: 0.5,
|
||||
underlay: 0.15
|
||||
}
|
||||
|
||||
/** SUBJECT TO CHANGE IN THE FUTURE, this is all beta
|
||||
* Color and opacity slots definitions. Each key represents a slot.
|
||||
*
|
||||
* Short-hands:
|
||||
* String beginning with `--` - value after dashes treated as sole
|
||||
* dependency - i.e. `--value` equivalent to { depends: ['value']}
|
||||
* String beginning with `#` - value would be treated as solid color
|
||||
* defined in hexadecimal representation (i.e. #FFFFFF) and will be
|
||||
* used as default. `#FFFFFF` is equivalent to { default: '#FFFFFF'}
|
||||
*
|
||||
* Full definition:
|
||||
* @property {String[]} depends - color slot names this color depends ones.
|
||||
* cyclic dependencies are supported to some extent but not recommended.
|
||||
* @property {String} [opacity] - opacity slot used by this color slot.
|
||||
* opacity is inherited from parents. To break inheritance graph use null
|
||||
* @property {Number} [priority] - EXPERIMENTAL. used to pre-sort slots so
|
||||
* that slots with higher priority come earlier
|
||||
* @property {Function(mod, ...colors)} [color] - function that will be
|
||||
* used to determine the color. By default it just copies first color in
|
||||
* dependency list.
|
||||
* @argument {Number} mod - `1` (light-on-dark) or `-1` (dark-on-light)
|
||||
* depending on background color (for textColor)/given color.
|
||||
* @argument {...Object} deps - each argument after mod represents each
|
||||
* color from `depends` array. All colors take user customizations into
|
||||
* account and represented by { r, g, b } objects.
|
||||
* @returns {Object} resulting color, should be in { r, g, b } form
|
||||
*
|
||||
* @property {Boolean|String} [textColor] - true to mark color slot as text
|
||||
* color. This enables automatic text color generation for the slot. Use
|
||||
* 'preserve' string if you don't want text color to fall back to
|
||||
* black/white. Use 'bw' to only ever use black or white. This also makes
|
||||
* following properties required:
|
||||
* @property {String} [layer] - which layer the text sit on top on - used
|
||||
* to account for transparency in text color calculation
|
||||
* layer is inherited from parents. To break inheritance graph use null
|
||||
* @property {String} [variant] - which color slot is background (same as
|
||||
* above, used to account for transparency)
|
||||
*/
|
||||
export const SLOT_INHERITANCE = {
|
||||
bg: {
|
||||
depends: [],
|
||||
opacity: 'bg',
|
||||
priority: 1
|
||||
},
|
||||
fg: {
|
||||
depends: [],
|
||||
priority: 1
|
||||
},
|
||||
text: {
|
||||
depends: [],
|
||||
layer: 'bg',
|
||||
opacity: null,
|
||||
priority: 1
|
||||
},
|
||||
underlay: {
|
||||
default: '#000000',
|
||||
opacity: 'underlay'
|
||||
},
|
||||
link: {
|
||||
depends: ['accent'],
|
||||
priority: 1
|
||||
},
|
||||
accent: {
|
||||
depends: ['link'],
|
||||
priority: 1
|
||||
},
|
||||
faint: {
|
||||
depends: ['text'],
|
||||
opacity: 'faint'
|
||||
},
|
||||
faintLink: {
|
||||
depends: ['link'],
|
||||
opacity: 'faint'
|
||||
},
|
||||
postFaintLink: {
|
||||
depends: ['postLink'],
|
||||
opacity: 'faint'
|
||||
},
|
||||
|
||||
cBlue: '#0000ff',
|
||||
cRed: '#FF0000',
|
||||
cGreen: '#00FF00',
|
||||
cOrange: '#E3FF00',
|
||||
|
||||
highlight: {
|
||||
depends: ['bg'],
|
||||
color: (mod, bg) => brightness(5 * mod, bg).rgb
|
||||
},
|
||||
highlightLightText: {
|
||||
depends: ['lightText'],
|
||||
layer: 'highlight',
|
||||
textColor: true
|
||||
},
|
||||
highlightPostLink: {
|
||||
depends: ['postLink'],
|
||||
layer: 'highlight',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
highlightFaintText: {
|
||||
depends: ['faint'],
|
||||
layer: 'highlight',
|
||||
textColor: true
|
||||
},
|
||||
highlightFaintLink: {
|
||||
depends: ['faintLink'],
|
||||
layer: 'highlight',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
highlightPostFaintLink: {
|
||||
depends: ['postFaintLink'],
|
||||
layer: 'highlight',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
highlightText: {
|
||||
depends: ['text'],
|
||||
layer: 'highlight',
|
||||
textColor: true
|
||||
},
|
||||
highlightLink: {
|
||||
depends: ['link'],
|
||||
layer: 'highlight',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
highlightIcon: {
|
||||
depends: ['highlight', 'highlightText'],
|
||||
color: (mod, bg, text) => mixrgb(bg, text)
|
||||
},
|
||||
|
||||
popover: {
|
||||
depends: ['bg'],
|
||||
opacity: 'popover'
|
||||
},
|
||||
popoverLightText: {
|
||||
depends: ['lightText'],
|
||||
layer: 'popover',
|
||||
textColor: true
|
||||
},
|
||||
popoverPostLink: {
|
||||
depends: ['postLink'],
|
||||
layer: 'popover',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
popoverFaintText: {
|
||||
depends: ['faint'],
|
||||
layer: 'popover',
|
||||
textColor: true
|
||||
},
|
||||
popoverFaintLink: {
|
||||
depends: ['faintLink'],
|
||||
layer: 'popover',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
popoverPostFaintLink: {
|
||||
depends: ['postFaintLink'],
|
||||
layer: 'popover',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
popoverText: {
|
||||
depends: ['text'],
|
||||
layer: 'popover',
|
||||
textColor: true
|
||||
},
|
||||
popoverLink: {
|
||||
depends: ['link'],
|
||||
layer: 'popover',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
popoverIcon: {
|
||||
depends: ['popover', 'popoverText'],
|
||||
color: (mod, bg, text) => mixrgb(bg, text)
|
||||
},
|
||||
|
||||
selectedPost: '--highlight',
|
||||
selectedPostFaintText: {
|
||||
depends: ['highlightFaintText'],
|
||||
layer: 'highlight',
|
||||
variant: 'selectedPost',
|
||||
textColor: true
|
||||
},
|
||||
selectedPostLightText: {
|
||||
depends: ['highlightLightText'],
|
||||
layer: 'highlight',
|
||||
variant: 'selectedPost',
|
||||
textColor: true
|
||||
},
|
||||
selectedPostPostLink: {
|
||||
depends: ['highlightPostLink'],
|
||||
layer: 'highlight',
|
||||
variant: 'selectedPost',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
selectedPostFaintLink: {
|
||||
depends: ['highlightFaintLink'],
|
||||
layer: 'highlight',
|
||||
variant: 'selectedPost',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
selectedPostText: {
|
||||
depends: ['highlightText'],
|
||||
layer: 'highlight',
|
||||
variant: 'selectedPost',
|
||||
textColor: true
|
||||
},
|
||||
selectedPostLink: {
|
||||
depends: ['highlightLink'],
|
||||
layer: 'highlight',
|
||||
variant: 'selectedPost',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
selectedPostIcon: {
|
||||
depends: ['selectedPost', 'selectedPostText'],
|
||||
color: (mod, bg, text) => mixrgb(bg, text)
|
||||
},
|
||||
|
||||
selectedMenu: {
|
||||
depends: ['bg'],
|
||||
color: (mod, bg) => brightness(5 * mod, bg).rgb
|
||||
},
|
||||
selectedMenuLightText: {
|
||||
depends: ['highlightLightText'],
|
||||
layer: 'selectedMenu',
|
||||
variant: 'selectedMenu',
|
||||
textColor: true
|
||||
},
|
||||
selectedMenuFaintText: {
|
||||
depends: ['highlightFaintText'],
|
||||
layer: 'selectedMenu',
|
||||
variant: 'selectedMenu',
|
||||
textColor: true
|
||||
},
|
||||
selectedMenuFaintLink: {
|
||||
depends: ['highlightFaintLink'],
|
||||
layer: 'selectedMenu',
|
||||
variant: 'selectedMenu',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
selectedMenuText: {
|
||||
depends: ['highlightText'],
|
||||
layer: 'selectedMenu',
|
||||
variant: 'selectedMenu',
|
||||
textColor: true
|
||||
},
|
||||
selectedMenuLink: {
|
||||
depends: ['highlightLink'],
|
||||
layer: 'selectedMenu',
|
||||
variant: 'selectedMenu',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
selectedMenuIcon: {
|
||||
depends: ['selectedMenu', 'selectedMenuText'],
|
||||
color: (mod, bg, text) => mixrgb(bg, text)
|
||||
},
|
||||
|
||||
selectedMenuPopover: {
|
||||
depends: ['popover'],
|
||||
color: (mod, bg) => brightness(5 * mod, bg).rgb
|
||||
},
|
||||
selectedMenuPopoverLightText: {
|
||||
depends: ['selectedMenuLightText'],
|
||||
layer: 'selectedMenuPopover',
|
||||
variant: 'selectedMenuPopover',
|
||||
textColor: true
|
||||
},
|
||||
selectedMenuPopoverFaintText: {
|
||||
depends: ['selectedMenuFaintText'],
|
||||
layer: 'selectedMenuPopover',
|
||||
variant: 'selectedMenuPopover',
|
||||
textColor: true
|
||||
},
|
||||
selectedMenuPopoverFaintLink: {
|
||||
depends: ['selectedMenuFaintLink'],
|
||||
layer: 'selectedMenuPopover',
|
||||
variant: 'selectedMenuPopover',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
selectedMenuPopoverText: {
|
||||
depends: ['selectedMenuText'],
|
||||
layer: 'selectedMenuPopover',
|
||||
variant: 'selectedMenuPopover',
|
||||
textColor: true
|
||||
},
|
||||
selectedMenuPopoverLink: {
|
||||
depends: ['selectedMenuLink'],
|
||||
layer: 'selectedMenuPopover',
|
||||
variant: 'selectedMenuPopover',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
selectedMenuPopoverIcon: {
|
||||
depends: ['selectedMenuPopover', 'selectedMenuText'],
|
||||
color: (mod, bg, text) => mixrgb(bg, text)
|
||||
},
|
||||
|
||||
lightText: {
|
||||
depends: ['text'],
|
||||
layer: 'bg',
|
||||
textColor: 'preserve',
|
||||
color: (mod, text) => brightness(20 * mod, text).rgb
|
||||
},
|
||||
|
||||
postLink: {
|
||||
depends: ['link'],
|
||||
layer: 'bg',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
|
||||
border: {
|
||||
depends: ['fg'],
|
||||
opacity: 'border',
|
||||
color: (mod, fg) => brightness(2 * mod, fg).rgb
|
||||
},
|
||||
|
||||
poll: {
|
||||
depends: ['accent', 'bg'],
|
||||
copacity: 'poll',
|
||||
color: (mod, accent, bg) => alphaBlend(accent, 0.4, bg)
|
||||
},
|
||||
pollText: {
|
||||
depends: ['text'],
|
||||
layer: 'poll',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
icon: {
|
||||
depends: ['bg', 'text'],
|
||||
inheritsOpacity: false,
|
||||
color: (mod, bg, text) => mixrgb(bg, text)
|
||||
},
|
||||
|
||||
// Foreground
|
||||
fgText: {
|
||||
depends: ['text'],
|
||||
layer: 'fg',
|
||||
textColor: true
|
||||
},
|
||||
fgLink: {
|
||||
depends: ['link'],
|
||||
layer: 'fg',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
|
||||
// Panel header
|
||||
panel: {
|
||||
depends: ['fg'],
|
||||
opacity: 'panel'
|
||||
},
|
||||
panelText: {
|
||||
depends: ['text'],
|
||||
layer: 'panel',
|
||||
textColor: true
|
||||
},
|
||||
panelFaint: {
|
||||
depends: ['fgText'],
|
||||
layer: 'panel',
|
||||
opacity: 'faint',
|
||||
textColor: true
|
||||
},
|
||||
panelLink: {
|
||||
depends: ['fgLink'],
|
||||
layer: 'panel',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
|
||||
// Top bar
|
||||
topBar: '--fg',
|
||||
topBarText: {
|
||||
depends: ['fgText'],
|
||||
layer: 'topBar',
|
||||
textColor: true
|
||||
},
|
||||
topBarLink: {
|
||||
depends: ['fgLink'],
|
||||
layer: 'topBar',
|
||||
textColor: 'preserve'
|
||||
},
|
||||
|
||||
// Tabs
|
||||
tab: {
|
||||
depends: ['btn']
|
||||
},
|
||||
tabText: {
|
||||
depends: ['btnText'],
|
||||
layer: 'btn',
|
||||
textColor: true
|
||||
},
|
||||
tabActiveText: {
|
||||
depends: ['text'],
|
||||
layer: 'bg',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
// Buttons
|
||||
btn: {
|
||||
depends: ['fg'],
|
||||
variant: 'btn',
|
||||
opacity: 'btn'
|
||||
},
|
||||
btnText: {
|
||||
depends: ['fgText'],
|
||||
layer: 'btn',
|
||||
textColor: true
|
||||
},
|
||||
btnPanelText: {
|
||||
depends: ['btnText'],
|
||||
layer: 'btnPanel',
|
||||
variant: 'btn',
|
||||
textColor: true
|
||||
},
|
||||
btnTopBarText: {
|
||||
depends: ['btnText'],
|
||||
layer: 'btnTopBar',
|
||||
variant: 'btn',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
// Buttons: pressed
|
||||
btnPressed: {
|
||||
depends: ['btn'],
|
||||
layer: 'btn'
|
||||
},
|
||||
btnPressedText: {
|
||||
depends: ['btnText'],
|
||||
layer: 'btn',
|
||||
variant: 'btnPressed',
|
||||
textColor: true
|
||||
},
|
||||
btnPressedPanel: {
|
||||
depends: ['btnPressed'],
|
||||
layer: 'btn'
|
||||
},
|
||||
btnPressedPanelText: {
|
||||
depends: ['btnPanelText'],
|
||||
layer: 'btnPanel',
|
||||
variant: 'btnPressed',
|
||||
textColor: true
|
||||
},
|
||||
btnPressedTopBar: {
|
||||
depends: ['btnPressed'],
|
||||
layer: 'btn'
|
||||
},
|
||||
btnPressedTopBarText: {
|
||||
depends: ['btnTopBarText'],
|
||||
layer: 'btnTopBar',
|
||||
variant: 'btnPressed',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
// Buttons: toggled
|
||||
btnToggled: {
|
||||
depends: ['btn'],
|
||||
layer: 'btn',
|
||||
color: (mod, btn) => brightness(mod * 20, btn).rgb
|
||||
},
|
||||
btnToggledText: {
|
||||
depends: ['btnText'],
|
||||
layer: 'btn',
|
||||
variant: 'btnToggled',
|
||||
textColor: true
|
||||
},
|
||||
btnToggledPanelText: {
|
||||
depends: ['btnPanelText'],
|
||||
layer: 'btnPanel',
|
||||
variant: 'btnToggled',
|
||||
textColor: true
|
||||
},
|
||||
btnToggledTopBarText: {
|
||||
depends: ['btnTopBarText'],
|
||||
layer: 'btnTopBar',
|
||||
variant: 'btnToggled',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
// Buttons: disabled
|
||||
btnDisabled: {
|
||||
depends: ['btn', 'bg'],
|
||||
color: (mod, btn, bg) => alphaBlend(btn, 0.25, bg)
|
||||
},
|
||||
btnDisabledText: {
|
||||
depends: ['btnText', 'btnDisabled'],
|
||||
layer: 'btn',
|
||||
variant: 'btnDisabled',
|
||||
color: (mod, text, btn) => alphaBlend(text, 0.25, btn)
|
||||
},
|
||||
btnDisabledPanelText: {
|
||||
depends: ['btnPanelText', 'btnDisabled'],
|
||||
layer: 'btnPanel',
|
||||
variant: 'btnDisabled',
|
||||
color: (mod, text, btn) => alphaBlend(text, 0.25, btn)
|
||||
},
|
||||
btnDisabledTopBarText: {
|
||||
depends: ['btnTopBarText', 'btnDisabled'],
|
||||
layer: 'btnTopBar',
|
||||
variant: 'btnDisabled',
|
||||
color: (mod, text, btn) => alphaBlend(text, 0.25, btn)
|
||||
},
|
||||
|
||||
// Input fields
|
||||
input: {
|
||||
depends: ['fg'],
|
||||
opacity: 'input'
|
||||
},
|
||||
inputText: {
|
||||
depends: ['text'],
|
||||
layer: 'input',
|
||||
textColor: true
|
||||
},
|
||||
inputPanelText: {
|
||||
depends: ['panelText'],
|
||||
layer: 'inputPanel',
|
||||
variant: 'input',
|
||||
textColor: true
|
||||
},
|
||||
inputTopbarText: {
|
||||
depends: ['topBarText'],
|
||||
layer: 'inputTopBar',
|
||||
variant: 'input',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
alertError: {
|
||||
depends: ['cRed'],
|
||||
opacity: 'alert'
|
||||
},
|
||||
alertErrorText: {
|
||||
depends: ['text'],
|
||||
layer: 'alert',
|
||||
variant: 'alertError',
|
||||
textColor: true
|
||||
},
|
||||
alertErrorPanelText: {
|
||||
depends: ['panelText'],
|
||||
layer: 'alertPanel',
|
||||
variant: 'alertError',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
alertWarning: {
|
||||
depends: ['cOrange'],
|
||||
opacity: 'alert'
|
||||
},
|
||||
alertWarningText: {
|
||||
depends: ['text'],
|
||||
layer: 'alert',
|
||||
variant: 'alertWarning',
|
||||
textColor: true
|
||||
},
|
||||
alertWarningPanelText: {
|
||||
depends: ['panelText'],
|
||||
layer: 'alertPanel',
|
||||
variant: 'alertWarning',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
alertNeutral: {
|
||||
depends: ['text'],
|
||||
opacity: 'alert'
|
||||
},
|
||||
alertNeutralText: {
|
||||
depends: ['text'],
|
||||
layer: 'alert',
|
||||
variant: 'alertNeutral',
|
||||
color: (mod, text) => invertLightness(text).rgb,
|
||||
textColor: true
|
||||
},
|
||||
alertNeutralPanelText: {
|
||||
depends: ['panelText'],
|
||||
layer: 'alertPanel',
|
||||
variant: 'alertNeutral',
|
||||
textColor: true
|
||||
},
|
||||
|
||||
badgeNotification: '--cRed',
|
||||
badgeNotificationText: {
|
||||
depends: ['text', 'badgeNotification'],
|
||||
layer: 'badge',
|
||||
variant: 'badgeNotification',
|
||||
textColor: 'bw'
|
||||
}
|
||||
}
|
373
src/services/theme_data/theme_data.service.js
Normal file
373
src/services/theme_data/theme_data.service.js
Normal file
@ -0,0 +1,373 @@
|
||||
import { convert, brightness, contrastRatio } from 'chromatism'
|
||||
import { alphaBlendLayers, getTextColor, relativeLuminance } from '../color_convert/color_convert.js'
|
||||
import { LAYERS, DEFAULT_OPACITY, SLOT_INHERITANCE } from './pleromafe.js'
|
||||
|
||||
/*
|
||||
* # What's all this?
|
||||
* Here be theme engine for pleromafe. All of this supposed to ease look
|
||||
* and feel customization, making widget styles and make developer's life
|
||||
* easier when it comes to supporting themes. Like many other theme systems
|
||||
* it operates on color definitions, or "slots" - for example you define
|
||||
* "button" color slot and then in UI component Button's CSS you refer to
|
||||
* it as a CSS3 Variable.
|
||||
*
|
||||
* Some applications allow you to customize colors for certain things.
|
||||
* Some UI toolkits allow you to define colors for each type of widget.
|
||||
* Most of them are pretty barebones and have no assistance for common
|
||||
* problems and cases, and in general themes themselves are very hard to
|
||||
* maintain in all aspects. This theme engine tries to solve all of the
|
||||
* common problems with themes.
|
||||
*
|
||||
* You don't have redefine several similar colors if you just want to
|
||||
* change one color - all color slots are derived from other ones, so you
|
||||
* can have at least one or two "basic" colors defined and have all other
|
||||
* components inherit and modify basic ones.
|
||||
*
|
||||
* You don't have to test contrast ratio for colors or pick text color for
|
||||
* each element even if you have light-on-dark elements in dark-on-light
|
||||
* theme.
|
||||
*
|
||||
* You don't have to maintain order of code for inheriting slots from othet
|
||||
* slots - dependency graph resolving does it for you.
|
||||
*/
|
||||
|
||||
/* This indicates that this version of code outputs similar theme data and
|
||||
* should be incremented if output changes - for instance if getTextColor
|
||||
* function changes and older themes no longer render text colors as
|
||||
* author intended previously.
|
||||
*/
|
||||
export const CURRENT_VERSION = 3
|
||||
|
||||
export const getLayersArray = (layer, data = LAYERS) => {
|
||||
let array = [layer]
|
||||
let parent = data[layer]
|
||||
while (parent) {
|
||||
array.unshift(parent)
|
||||
parent = data[parent]
|
||||
}
|
||||
return array
|
||||
}
|
||||
|
||||
export const getLayers = (layer, variant = layer, opacitySlot, colors, opacity) => {
|
||||
return getLayersArray(layer).map((currentLayer) => ([
|
||||
currentLayer === layer
|
||||
? colors[variant]
|
||||
: colors[currentLayer],
|
||||
currentLayer === layer
|
||||
? opacity[opacitySlot] || 1
|
||||
: opacity[currentLayer]
|
||||
]))
|
||||
}
|
||||
|
||||
const getDependencies = (key, inheritance) => {
|
||||
const data = inheritance[key]
|
||||
if (typeof data === 'string' && data.startsWith('--')) {
|
||||
return [data.substring(2)]
|
||||
} else {
|
||||
if (data === null) return []
|
||||
const { depends, layer, variant } = data
|
||||
const layerDeps = layer
|
||||
? getLayersArray(layer).map(currentLayer => {
|
||||
return currentLayer === layer
|
||||
? variant || layer
|
||||
: currentLayer
|
||||
})
|
||||
: []
|
||||
if (Array.isArray(depends)) {
|
||||
return [...depends, ...layerDeps]
|
||||
} else {
|
||||
return [...layerDeps]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts inheritance object topologically - dependant slots come after
|
||||
* dependencies
|
||||
*
|
||||
* @property {Object} inheritance - object defining the nodes
|
||||
* @property {Function} getDeps - function that returns dependencies for
|
||||
* given value and inheritance object.
|
||||
* @returns {String[]} keys of inheritance object, sorted in topological
|
||||
* order. Additionally, dependency-less nodes will always be first in line
|
||||
*/
|
||||
export const topoSort = (
|
||||
inheritance = SLOT_INHERITANCE,
|
||||
getDeps = getDependencies
|
||||
) => {
|
||||
// This is an implementation of https://en.wikipedia.org/wiki/Tarjan%27s_strongly_connected_components_algorithm
|
||||
|
||||
const allKeys = Object.keys(inheritance)
|
||||
const whites = new Set(allKeys)
|
||||
const grays = new Set()
|
||||
const blacks = new Set()
|
||||
const unprocessed = [...allKeys]
|
||||
const output = []
|
||||
|
||||
const step = (node) => {
|
||||
if (whites.has(node)) {
|
||||
// Make node "gray"
|
||||
whites.delete(node)
|
||||
grays.add(node)
|
||||
// Do step for each node connected to it (one way)
|
||||
getDeps(node, inheritance).forEach(step)
|
||||
// Make node "black"
|
||||
grays.delete(node)
|
||||
blacks.add(node)
|
||||
// Put it into the output list
|
||||
output.push(node)
|
||||
} else if (grays.has(node)) {
|
||||
console.debug('Cyclic depenency in topoSort, ignoring')
|
||||
output.push(node)
|
||||
} else if (blacks.has(node)) {
|
||||
// do nothing
|
||||
} else {
|
||||
throw new Error('Unintended condition in topoSort!')
|
||||
}
|
||||
}
|
||||
while (unprocessed.length > 0) {
|
||||
step(unprocessed.pop())
|
||||
}
|
||||
return output.sort((a, b) => {
|
||||
const depsA = getDeps(a, inheritance).length
|
||||
const depsB = getDeps(b, inheritance).length
|
||||
|
||||
if (depsA === depsB || (depsB !== 0 && depsA !== 0)) return 0
|
||||
if (depsA === 0 && depsB !== 0) return -1
|
||||
if (depsB === 0 && depsA !== 0) return 1
|
||||
})
|
||||
}
|
||||
|
||||
const expandSlotValue = (value) => {
|
||||
if (typeof value === 'object') return value
|
||||
return {
|
||||
depends: value.startsWith('--') ? [value.substring(2)] : [],
|
||||
default: value.startsWith('#') ? value : undefined
|
||||
}
|
||||
}
|
||||
/**
|
||||
* retrieves opacity slot for given slot. This goes up the depenency graph
|
||||
* to find which parent has opacity slot defined for it.
|
||||
* TODO refactor this
|
||||
*/
|
||||
export const getOpacitySlot = (
|
||||
k,
|
||||
inheritance = SLOT_INHERITANCE,
|
||||
getDeps = getDependencies
|
||||
) => {
|
||||
const value = expandSlotValue(inheritance[k])
|
||||
if (value.opacity === null) return
|
||||
if (value.opacity) return value.opacity
|
||||
const findInheritedOpacity = (key, visited = [k]) => {
|
||||
const depSlot = getDeps(key, inheritance)[0]
|
||||
if (depSlot === undefined) return
|
||||
const dependency = inheritance[depSlot]
|
||||
if (dependency === undefined) return
|
||||
if (dependency.opacity || dependency === null) {
|
||||
return dependency.opacity
|
||||
} else if (dependency.depends && visited.includes(depSlot)) {
|
||||
return findInheritedOpacity(depSlot, [...visited, depSlot])
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
if (value.depends) {
|
||||
return findInheritedOpacity(k)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* retrieves layer slot for given slot. This goes up the depenency graph
|
||||
* to find which parent has opacity slot defined for it.
|
||||
* this is basically copypaste of getOpacitySlot except it checks if key is
|
||||
* in LAYERS
|
||||
* TODO refactor this
|
||||
*/
|
||||
export const getLayerSlot = (
|
||||
k,
|
||||
inheritance = SLOT_INHERITANCE,
|
||||
getDeps = getDependencies
|
||||
) => {
|
||||
const value = expandSlotValue(inheritance[k])
|
||||
if (LAYERS[k]) return k
|
||||
if (value.layer === null) return
|
||||
if (value.layer) return value.layer
|
||||
const findInheritedLayer = (key, visited = [k]) => {
|
||||
const depSlot = getDeps(key, inheritance)[0]
|
||||
if (depSlot === undefined) return
|
||||
const dependency = inheritance[depSlot]
|
||||
if (dependency === undefined) return
|
||||
if (dependency.layer || dependency === null) {
|
||||
return dependency.layer
|
||||
} else if (dependency.depends) {
|
||||
return findInheritedLayer(dependency, [...visited, depSlot])
|
||||
} else {
|
||||
return null
|
||||
}
|
||||
}
|
||||
if (value.depends) {
|
||||
return findInheritedLayer(k)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* topologically sorted SLOT_INHERITANCE
|
||||
*/
|
||||
export const SLOT_ORDERED = topoSort(
|
||||
Object.entries(SLOT_INHERITANCE)
|
||||
.sort(([aK, aV], [bK, bV]) => ((aV && aV.priority) || 0) - ((bV && bV.priority) || 0))
|
||||
.reduce((acc, [k, v]) => ({ ...acc, [k]: v }), {})
|
||||
)
|
||||
|
||||
/**
|
||||
* All opacity slots used in color slots, their default values and affected
|
||||
* color slots.
|
||||
*/
|
||||
export const OPACITIES = Object.entries(SLOT_INHERITANCE).reduce((acc, [k, v]) => {
|
||||
const opacity = getOpacitySlot(k, SLOT_INHERITANCE, getDependencies)
|
||||
if (opacity) {
|
||||
return {
|
||||
...acc,
|
||||
[opacity]: {
|
||||
defaultValue: DEFAULT_OPACITY[opacity] || 1,
|
||||
affectedSlots: [...((acc[opacity] && acc[opacity].affectedSlots) || []), k]
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return acc
|
||||
}
|
||||
}, {})
|
||||
|
||||
/**
|
||||
* Handle dynamic color
|
||||
*/
|
||||
export const computeDynamicColor = (sourceColor, getColor, mod) => {
|
||||
if (typeof sourceColor !== 'string' || !sourceColor.startsWith('--')) return sourceColor
|
||||
let targetColor = null
|
||||
// Color references other color
|
||||
const [variable, modifier] = sourceColor.split(/,/g).map(str => str.trim())
|
||||
const variableSlot = variable.substring(2)
|
||||
targetColor = getColor(variableSlot)
|
||||
if (modifier) {
|
||||
targetColor = brightness(Number.parseFloat(modifier) * mod, targetColor).rgb
|
||||
}
|
||||
return targetColor
|
||||
}
|
||||
|
||||
/**
|
||||
* THE function you want to use. Takes provided colors and opacities
|
||||
* value and uses inheritance data to figure out color needed for the slot.
|
||||
*/
|
||||
export const getColors = (sourceColors, sourceOpacity) => SLOT_ORDERED.reduce(({ colors, opacity }, key) => {
|
||||
const sourceColor = sourceColors[key]
|
||||
const value = expandSlotValue(SLOT_INHERITANCE[key])
|
||||
const deps = getDependencies(key, SLOT_INHERITANCE)
|
||||
const isTextColor = !!value.textColor
|
||||
const variant = value.variant || value.layer
|
||||
|
||||
let backgroundColor = null
|
||||
|
||||
if (isTextColor) {
|
||||
backgroundColor = alphaBlendLayers(
|
||||
{ ...(colors[deps[0]] || convert(sourceColors[key] || '#FF00FF').rgb) },
|
||||
getLayers(
|
||||
getLayerSlot(key) || 'bg',
|
||||
variant || 'bg',
|
||||
getOpacitySlot(variant),
|
||||
colors,
|
||||
opacity
|
||||
)
|
||||
)
|
||||
} else if (variant && variant !== key) {
|
||||
backgroundColor = colors[variant] || convert(sourceColors[variant]).rgb
|
||||
} else {
|
||||
backgroundColor = colors.bg || convert(sourceColors.bg)
|
||||
}
|
||||
|
||||
const isLightOnDark = relativeLuminance(backgroundColor) < 0.5
|
||||
const mod = isLightOnDark ? 1 : -1
|
||||
|
||||
let outputColor = null
|
||||
if (sourceColor) {
|
||||
// Color is defined in source color
|
||||
let targetColor = sourceColor
|
||||
if (targetColor === 'transparent') {
|
||||
// We take only layers below current one
|
||||
const layers = getLayers(
|
||||
getLayerSlot(key),
|
||||
key,
|
||||
getOpacitySlot(key) || key,
|
||||
colors,
|
||||
opacity
|
||||
).slice(0, -1)
|
||||
targetColor = {
|
||||
...alphaBlendLayers(
|
||||
convert('#FF00FF').rgb,
|
||||
layers
|
||||
),
|
||||
a: 0
|
||||
}
|
||||
} else if (typeof sourceColor === 'string' && sourceColor.startsWith('--')) {
|
||||
targetColor = computeDynamicColor(
|
||||
sourceColor,
|
||||
variableSlot => colors[variableSlot] || sourceColors[variableSlot],
|
||||
mod
|
||||
)
|
||||
} else if (typeof sourceColor === 'string' && sourceColor.startsWith('#')) {
|
||||
targetColor = convert(targetColor).rgb
|
||||
}
|
||||
outputColor = { ...targetColor }
|
||||
} else if (value.default) {
|
||||
// same as above except in object form
|
||||
outputColor = convert(value.default).rgb
|
||||
} else {
|
||||
// calculate color
|
||||
const defaultColorFunc = (mod, dep) => ({ ...dep })
|
||||
const colorFunc = value.color || defaultColorFunc
|
||||
|
||||
if (value.textColor) {
|
||||
if (value.textColor === 'bw') {
|
||||
outputColor = contrastRatio(backgroundColor).rgb
|
||||
} else {
|
||||
let color = { ...colors[deps[0]] }
|
||||
if (value.color) {
|
||||
color = colorFunc(mod, ...deps.map((dep) => ({ ...colors[dep] })))
|
||||
}
|
||||
outputColor = getTextColor(
|
||||
backgroundColor,
|
||||
{ ...color },
|
||||
value.textColor === 'preserve'
|
||||
)
|
||||
}
|
||||
} else {
|
||||
// background color case
|
||||
outputColor = colorFunc(
|
||||
mod,
|
||||
...deps.map((dep) => ({ ...colors[dep] }))
|
||||
)
|
||||
}
|
||||
}
|
||||
if (!outputColor) {
|
||||
throw new Error('Couldn\'t generate color for ' + key)
|
||||
}
|
||||
const opacitySlot = getOpacitySlot(key)
|
||||
if (opacitySlot && outputColor.a === undefined) {
|
||||
const dependencySlot = deps[0]
|
||||
if (dependencySlot && colors[dependencySlot] === 'transparent') {
|
||||
outputColor.a = 0
|
||||
} else {
|
||||
outputColor.a = Number(sourceOpacity[opacitySlot]) || OPACITIES[opacitySlot].defaultValue || 1
|
||||
}
|
||||
}
|
||||
if (opacitySlot) {
|
||||
return {
|
||||
colors: { ...colors, [key]: outputColor },
|
||||
opacity: { ...opacity, [opacitySlot]: outputColor.a }
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
colors: { ...colors, [key]: outputColor },
|
||||
opacity
|
||||
}
|
||||
}
|
||||
}, { colors: {}, opacity: {} })
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #090300; }
|
||||
.base01-background { background-color: #3a3432; }
|
||||
.base02-background { background-color: #4a4543; }
|
||||
.base03-background { background-color: #5c5855; }
|
||||
.base04-background { background-color: #807d7c; }
|
||||
.base05-background { background-color: #a5a2a2; }
|
||||
.base06-background { background-color: #d6d5d4; }
|
||||
.base07-background { background-color: #f7f7f7; }
|
||||
.base08-background { background-color: #db2d20; }
|
||||
.base09-background { background-color: #e8bbd0; }
|
||||
.base0A-background { background-color: #fded02; }
|
||||
.base0B-background { background-color: #01a252; }
|
||||
.base0C-background { background-color: #b5e4f4; }
|
||||
.base0D-background { background-color: #01a0e4; }
|
||||
.base0E-background { background-color: #a16a94; }
|
||||
.base0F-background { background-color: #cdab53; }
|
||||
|
||||
.base00 { color: #090300; }
|
||||
.base01 { color: #3a3432; }
|
||||
.base02 { color: #4a4543; }
|
||||
.base03 { color: #5c5855; }
|
||||
.base04 { color: #807d7c; }
|
||||
.base05 { color: #a5a2a2; }
|
||||
.base06 { color: #d6d5d4; }
|
||||
.base07 { color: #f7f7f7; }
|
||||
.base08 { color: #db2d20; }
|
||||
.base09 { color: #e8bbd0; }
|
||||
.base0A { color: #fded02; }
|
||||
.base0B { color: #01a252; }
|
||||
.base0C { color: #b5e4f4; }
|
||||
.base0D { color: #01a0e4; }
|
||||
.base0E { color: #a16a94; }
|
||||
.base0F { color: #cdab53; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #031A16; }
|
||||
.base01-background { background-color: #0B342D; }
|
||||
.base02-background { background-color: #184E45; }
|
||||
.base03-background { background-color: #2B685E; }
|
||||
.base04-background { background-color: #5F9C92; }
|
||||
.base05-background { background-color: #81B5AC; }
|
||||
.base06-background { background-color: #A7CEC8; }
|
||||
.base07-background { background-color: #D2E7E4; }
|
||||
.base08-background { background-color: #3E9688; }
|
||||
.base09-background { background-color: #3E7996; }
|
||||
.base0A-background { background-color: #3E4C96; }
|
||||
.base0B-background { background-color: #883E96; }
|
||||
.base0C-background { background-color: #963E4C; }
|
||||
.base0D-background { background-color: #96883E; }
|
||||
.base0E-background { background-color: #4C963E; }
|
||||
.base0F-background { background-color: #3E965B; }
|
||||
|
||||
.base00 { color: #031A16; }
|
||||
.base01 { color: #0B342D; }
|
||||
.base02 { color: #184E45; }
|
||||
.base03 { color: #2B685E; }
|
||||
.base04 { color: #5F9C92; }
|
||||
.base05 { color: #81B5AC; }
|
||||
.base06 { color: #A7CEC8; }
|
||||
.base07 { color: #D2E7E4; }
|
||||
.base08 { color: #3E9688; }
|
||||
.base09 { color: #3E7996; }
|
||||
.base0A { color: #3E4C96; }
|
||||
.base0B { color: #883E96; }
|
||||
.base0C { color: #963E4C; }
|
||||
.base0D { color: #96883E; }
|
||||
.base0E { color: #4C963E; }
|
||||
.base0F { color: #3E965B; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #1C2023; }
|
||||
.base01-background { background-color: #393F45; }
|
||||
.base02-background { background-color: #565E65; }
|
||||
.base03-background { background-color: #747C84; }
|
||||
.base04-background { background-color: #ADB3BA; }
|
||||
.base05-background { background-color: #C7CCD1; }
|
||||
.base06-background { background-color: #DFE2E5; }
|
||||
.base07-background { background-color: #F3F4F5; }
|
||||
.base08-background { background-color: #C7AE95; }
|
||||
.base09-background { background-color: #C7C795; }
|
||||
.base0A-background { background-color: #AEC795; }
|
||||
.base0B-background { background-color: #95C7AE; }
|
||||
.base0C-background { background-color: #95AEC7; }
|
||||
.base0D-background { background-color: #AE95C7; }
|
||||
.base0E-background { background-color: #C795AE; }
|
||||
.base0F-background { background-color: #C79595; }
|
||||
|
||||
.base00 { color: #1C2023; }
|
||||
.base01 { color: #393F45; }
|
||||
.base02 { color: #565E65; }
|
||||
.base03 { color: #747C84; }
|
||||
.base04 { color: #ADB3BA; }
|
||||
.base05 { color: #C7CCD1; }
|
||||
.base06 { color: #DFE2E5; }
|
||||
.base07 { color: #F3F4F5; }
|
||||
.base08 { color: #C7AE95; }
|
||||
.base09 { color: #C7C795; }
|
||||
.base0A { color: #AEC795; }
|
||||
.base0B { color: #95C7AE; }
|
||||
.base0C { color: #95AEC7; }
|
||||
.base0D { color: #AE95C7; }
|
||||
.base0E { color: #C795AE; }
|
||||
.base0F { color: #C79595; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #19171c; }
|
||||
.base01-background { background-color: #26232a; }
|
||||
.base02-background { background-color: #585260; }
|
||||
.base03-background { background-color: #655f6d; }
|
||||
.base04-background { background-color: #7e7887; }
|
||||
.base05-background { background-color: #8b8792; }
|
||||
.base06-background { background-color: #e2dfe7; }
|
||||
.base07-background { background-color: #efecf4; }
|
||||
.base08-background { background-color: #be4678; }
|
||||
.base09-background { background-color: #aa573c; }
|
||||
.base0A-background { background-color: #a06e3b; }
|
||||
.base0B-background { background-color: #2a9292; }
|
||||
.base0C-background { background-color: #398bc6; }
|
||||
.base0D-background { background-color: #576ddb; }
|
||||
.base0E-background { background-color: #955ae7; }
|
||||
.base0F-background { background-color: #bf40bf; }
|
||||
|
||||
.base00 { color: #19171c; }
|
||||
.base01 { color: #26232a; }
|
||||
.base02 { color: #585260; }
|
||||
.base03 { color: #655f6d; }
|
||||
.base04 { color: #7e7887; }
|
||||
.base05 { color: #8b8792; }
|
||||
.base06 { color: #e2dfe7; }
|
||||
.base07 { color: #efecf4; }
|
||||
.base08 { color: #be4678; }
|
||||
.base09 { color: #aa573c; }
|
||||
.base0A { color: #a06e3b; }
|
||||
.base0B { color: #2a9292; }
|
||||
.base0C { color: #398bc6; }
|
||||
.base0D { color: #576ddb; }
|
||||
.base0E { color: #955ae7; }
|
||||
.base0F { color: #bf40bf; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #20201d; }
|
||||
.base01-background { background-color: #292824; }
|
||||
.base02-background { background-color: #6e6b5e; }
|
||||
.base03-background { background-color: #7d7a68; }
|
||||
.base04-background { background-color: #999580; }
|
||||
.base05-background { background-color: #a6a28c; }
|
||||
.base06-background { background-color: #e8e4cf; }
|
||||
.base07-background { background-color: #fefbec; }
|
||||
.base08-background { background-color: #d73737; }
|
||||
.base09-background { background-color: #b65611; }
|
||||
.base0A-background { background-color: #ae9513; }
|
||||
.base0B-background { background-color: #60ac39; }
|
||||
.base0C-background { background-color: #1fad83; }
|
||||
.base0D-background { background-color: #6684e1; }
|
||||
.base0E-background { background-color: #b854d4; }
|
||||
.base0F-background { background-color: #d43552; }
|
||||
|
||||
.base00 { color: #20201d; }
|
||||
.base01 { color: #292824; }
|
||||
.base02 { color: #6e6b5e; }
|
||||
.base03 { color: #7d7a68; }
|
||||
.base04 { color: #999580; }
|
||||
.base05 { color: #a6a28c; }
|
||||
.base06 { color: #e8e4cf; }
|
||||
.base07 { color: #fefbec; }
|
||||
.base08 { color: #d73737; }
|
||||
.base09 { color: #b65611; }
|
||||
.base0A { color: #ae9513; }
|
||||
.base0B { color: #60ac39; }
|
||||
.base0C { color: #1fad83; }
|
||||
.base0D { color: #6684e1; }
|
||||
.base0E { color: #b854d4; }
|
||||
.base0F { color: #d43552; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #22221b; }
|
||||
.base01-background { background-color: #302f27; }
|
||||
.base02-background { background-color: #5f5e4e; }
|
||||
.base03-background { background-color: #6c6b5a; }
|
||||
.base04-background { background-color: #878573; }
|
||||
.base05-background { background-color: #929181; }
|
||||
.base06-background { background-color: #e7e6df; }
|
||||
.base07-background { background-color: #f4f3ec; }
|
||||
.base08-background { background-color: #ba6236; }
|
||||
.base09-background { background-color: #ae7313; }
|
||||
.base0A-background { background-color: #a5980d; }
|
||||
.base0B-background { background-color: #7d9726; }
|
||||
.base0C-background { background-color: #5b9d48; }
|
||||
.base0D-background { background-color: #36a166; }
|
||||
.base0E-background { background-color: #5f9182; }
|
||||
.base0F-background { background-color: #9d6c7c; }
|
||||
|
||||
.base00 { color: #22221b; }
|
||||
.base01 { color: #302f27; }
|
||||
.base02 { color: #5f5e4e; }
|
||||
.base03 { color: #6c6b5a; }
|
||||
.base04 { color: #878573; }
|
||||
.base05 { color: #929181; }
|
||||
.base06 { color: #e7e6df; }
|
||||
.base07 { color: #f4f3ec; }
|
||||
.base08 { color: #ba6236; }
|
||||
.base09 { color: #ae7313; }
|
||||
.base0A { color: #a5980d; }
|
||||
.base0B { color: #7d9726; }
|
||||
.base0C { color: #5b9d48; }
|
||||
.base0D { color: #36a166; }
|
||||
.base0E { color: #5f9182; }
|
||||
.base0F { color: #9d6c7c; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #1b1918; }
|
||||
.base01-background { background-color: #2c2421; }
|
||||
.base02-background { background-color: #68615e; }
|
||||
.base03-background { background-color: #766e6b; }
|
||||
.base04-background { background-color: #9c9491; }
|
||||
.base05-background { background-color: #a8a19f; }
|
||||
.base06-background { background-color: #e6e2e0; }
|
||||
.base07-background { background-color: #f1efee; }
|
||||
.base08-background { background-color: #f22c40; }
|
||||
.base09-background { background-color: #df5320; }
|
||||
.base0A-background { background-color: #c38418; }
|
||||
.base0B-background { background-color: #7b9726; }
|
||||
.base0C-background { background-color: #3d97b8; }
|
||||
.base0D-background { background-color: #407ee7; }
|
||||
.base0E-background { background-color: #6666ea; }
|
||||
.base0F-background { background-color: #c33ff3; }
|
||||
|
||||
.base00 { color: #1b1918; }
|
||||
.base01 { color: #2c2421; }
|
||||
.base02 { color: #68615e; }
|
||||
.base03 { color: #766e6b; }
|
||||
.base04 { color: #9c9491; }
|
||||
.base05 { color: #a8a19f; }
|
||||
.base06 { color: #e6e2e0; }
|
||||
.base07 { color: #f1efee; }
|
||||
.base08 { color: #f22c40; }
|
||||
.base09 { color: #df5320; }
|
||||
.base0A { color: #c38418; }
|
||||
.base0B { color: #7b9726; }
|
||||
.base0C { color: #3d97b8; }
|
||||
.base0D { color: #407ee7; }
|
||||
.base0E { color: #6666ea; }
|
||||
.base0F { color: #c33ff3; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #1b181b; }
|
||||
.base01-background { background-color: #292329; }
|
||||
.base02-background { background-color: #695d69; }
|
||||
.base03-background { background-color: #776977; }
|
||||
.base04-background { background-color: #9e8f9e; }
|
||||
.base05-background { background-color: #ab9bab; }
|
||||
.base06-background { background-color: #d8cad8; }
|
||||
.base07-background { background-color: #f7f3f7; }
|
||||
.base08-background { background-color: #ca402b; }
|
||||
.base09-background { background-color: #a65926; }
|
||||
.base0A-background { background-color: #bb8a35; }
|
||||
.base0B-background { background-color: #918b3b; }
|
||||
.base0C-background { background-color: #159393; }
|
||||
.base0D-background { background-color: #516aec; }
|
||||
.base0E-background { background-color: #7b59c0; }
|
||||
.base0F-background { background-color: #cc33cc; }
|
||||
|
||||
.base00 { color: #1b181b; }
|
||||
.base01 { color: #292329; }
|
||||
.base02 { color: #695d69; }
|
||||
.base03 { color: #776977; }
|
||||
.base04 { color: #9e8f9e; }
|
||||
.base05 { color: #ab9bab; }
|
||||
.base06 { color: #d8cad8; }
|
||||
.base07 { color: #f7f3f7; }
|
||||
.base08 { color: #ca402b; }
|
||||
.base09 { color: #a65926; }
|
||||
.base0A { color: #bb8a35; }
|
||||
.base0B { color: #918b3b; }
|
||||
.base0C { color: #159393; }
|
||||
.base0D { color: #516aec; }
|
||||
.base0E { color: #7b59c0; }
|
||||
.base0F { color: #cc33cc; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #161b1d; }
|
||||
.base01-background { background-color: #1f292e; }
|
||||
.base02-background { background-color: #516d7b; }
|
||||
.base03-background { background-color: #5a7b8c; }
|
||||
.base04-background { background-color: #7195a8; }
|
||||
.base05-background { background-color: #7ea2b4; }
|
||||
.base06-background { background-color: #c1e4f6; }
|
||||
.base07-background { background-color: #ebf8ff; }
|
||||
.base08-background { background-color: #d22d72; }
|
||||
.base09-background { background-color: #935c25; }
|
||||
.base0A-background { background-color: #8a8a0f; }
|
||||
.base0B-background { background-color: #568c3b; }
|
||||
.base0C-background { background-color: #2d8f6f; }
|
||||
.base0D-background { background-color: #257fad; }
|
||||
.base0E-background { background-color: #6b6bb8; }
|
||||
.base0F-background { background-color: #b72dd2; }
|
||||
|
||||
.base00 { color: #161b1d; }
|
||||
.base01 { color: #1f292e; }
|
||||
.base02 { color: #516d7b; }
|
||||
.base03 { color: #5a7b8c; }
|
||||
.base04 { color: #7195a8; }
|
||||
.base05 { color: #7ea2b4; }
|
||||
.base06 { color: #c1e4f6; }
|
||||
.base07 { color: #ebf8ff; }
|
||||
.base08 { color: #d22d72; }
|
||||
.base09 { color: #935c25; }
|
||||
.base0A { color: #8a8a0f; }
|
||||
.base0B { color: #568c3b; }
|
||||
.base0C { color: #2d8f6f; }
|
||||
.base0D { color: #257fad; }
|
||||
.base0E { color: #6b6bb8; }
|
||||
.base0F { color: #b72dd2; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #1b1818; }
|
||||
.base01-background { background-color: #292424; }
|
||||
.base02-background { background-color: #585050; }
|
||||
.base03-background { background-color: #655d5d; }
|
||||
.base04-background { background-color: #7e7777; }
|
||||
.base05-background { background-color: #8a8585; }
|
||||
.base06-background { background-color: #e7dfdf; }
|
||||
.base07-background { background-color: #f4ecec; }
|
||||
.base08-background { background-color: #ca4949; }
|
||||
.base09-background { background-color: #b45a3c; }
|
||||
.base0A-background { background-color: #a06e3b; }
|
||||
.base0B-background { background-color: #4b8b8b; }
|
||||
.base0C-background { background-color: #5485b6; }
|
||||
.base0D-background { background-color: #7272ca; }
|
||||
.base0E-background { background-color: #8464c4; }
|
||||
.base0F-background { background-color: #bd5187; }
|
||||
|
||||
.base00 { color: #1b1818; }
|
||||
.base01 { color: #292424; }
|
||||
.base02 { color: #585050; }
|
||||
.base03 { color: #655d5d; }
|
||||
.base04 { color: #7e7777; }
|
||||
.base05 { color: #8a8585; }
|
||||
.base06 { color: #e7dfdf; }
|
||||
.base07 { color: #f4ecec; }
|
||||
.base08 { color: #ca4949; }
|
||||
.base09 { color: #b45a3c; }
|
||||
.base0A { color: #a06e3b; }
|
||||
.base0B { color: #4b8b8b; }
|
||||
.base0C { color: #5485b6; }
|
||||
.base0D { color: #7272ca; }
|
||||
.base0E { color: #8464c4; }
|
||||
.base0F { color: #bd5187; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #171c19; }
|
||||
.base01-background { background-color: #232a25; }
|
||||
.base02-background { background-color: #526057; }
|
||||
.base03-background { background-color: #5f6d64; }
|
||||
.base04-background { background-color: #78877d; }
|
||||
.base05-background { background-color: #87928a; }
|
||||
.base06-background { background-color: #dfe7e2; }
|
||||
.base07-background { background-color: #ecf4ee; }
|
||||
.base08-background { background-color: #b16139; }
|
||||
.base09-background { background-color: #9f713c; }
|
||||
.base0A-background { background-color: #a07e3b; }
|
||||
.base0B-background { background-color: #489963; }
|
||||
.base0C-background { background-color: #1c9aa0; }
|
||||
.base0D-background { background-color: #478c90; }
|
||||
.base0E-background { background-color: #55859b; }
|
||||
.base0F-background { background-color: #867469; }
|
||||
|
||||
.base00 { color: #171c19; }
|
||||
.base01 { color: #232a25; }
|
||||
.base02 { color: #526057; }
|
||||
.base03 { color: #5f6d64; }
|
||||
.base04 { color: #78877d; }
|
||||
.base05 { color: #87928a; }
|
||||
.base06 { color: #dfe7e2; }
|
||||
.base07 { color: #ecf4ee; }
|
||||
.base08 { color: #b16139; }
|
||||
.base09 { color: #9f713c; }
|
||||
.base0A { color: #a07e3b; }
|
||||
.base0B { color: #489963; }
|
||||
.base0C { color: #1c9aa0; }
|
||||
.base0D { color: #478c90; }
|
||||
.base0E { color: #55859b; }
|
||||
.base0F { color: #867469; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #131513; }
|
||||
.base01-background { background-color: #242924; }
|
||||
.base02-background { background-color: #5e6e5e; }
|
||||
.base03-background { background-color: #687d68; }
|
||||
.base04-background { background-color: #809980; }
|
||||
.base05-background { background-color: #8ca68c; }
|
||||
.base06-background { background-color: #cfe8cf; }
|
||||
.base07-background { background-color: #f4fbf4; }
|
||||
.base08-background { background-color: #e6193c; }
|
||||
.base09-background { background-color: #87711d; }
|
||||
.base0A-background { background-color: #98981b; }
|
||||
.base0B-background { background-color: #29a329; }
|
||||
.base0C-background { background-color: #1999b3; }
|
||||
.base0D-background { background-color: #3d62f5; }
|
||||
.base0E-background { background-color: #ad2bee; }
|
||||
.base0F-background { background-color: #e619c3; }
|
||||
|
||||
.base00 { color: #131513; }
|
||||
.base01 { color: #242924; }
|
||||
.base02 { color: #5e6e5e; }
|
||||
.base03 { color: #687d68; }
|
||||
.base04 { color: #809980; }
|
||||
.base05 { color: #8ca68c; }
|
||||
.base06 { color: #cfe8cf; }
|
||||
.base07 { color: #f4fbf4; }
|
||||
.base08 { color: #e6193c; }
|
||||
.base09 { color: #87711d; }
|
||||
.base0A { color: #98981b; }
|
||||
.base0B { color: #29a329; }
|
||||
.base0C { color: #1999b3; }
|
||||
.base0D { color: #3d62f5; }
|
||||
.base0E { color: #ad2bee; }
|
||||
.base0F { color: #e619c3; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #202746; }
|
||||
.base01-background { background-color: #293256; }
|
||||
.base02-background { background-color: #5e6687; }
|
||||
.base03-background { background-color: #6b7394; }
|
||||
.base04-background { background-color: #898ea4; }
|
||||
.base05-background { background-color: #979db4; }
|
||||
.base06-background { background-color: #dfe2f1; }
|
||||
.base07-background { background-color: #f5f7ff; }
|
||||
.base08-background { background-color: #c94922; }
|
||||
.base09-background { background-color: #c76b29; }
|
||||
.base0A-background { background-color: #c08b30; }
|
||||
.base0B-background { background-color: #ac9739; }
|
||||
.base0C-background { background-color: #22a2c9; }
|
||||
.base0D-background { background-color: #3d8fd1; }
|
||||
.base0E-background { background-color: #6679cc; }
|
||||
.base0F-background { background-color: #9c637a; }
|
||||
|
||||
.base00 { color: #202746; }
|
||||
.base01 { color: #293256; }
|
||||
.base02 { color: #5e6687; }
|
||||
.base03 { color: #6b7394; }
|
||||
.base04 { color: #898ea4; }
|
||||
.base05 { color: #979db4; }
|
||||
.base06 { color: #dfe2f1; }
|
||||
.base07 { color: #f5f7ff; }
|
||||
.base08 { color: #c94922; }
|
||||
.base09 { color: #c76b29; }
|
||||
.base0A { color: #c08b30; }
|
||||
.base0B { color: #ac9739; }
|
||||
.base0C { color: #22a2c9; }
|
||||
.base0D { color: #3d8fd1; }
|
||||
.base0E { color: #6679cc; }
|
||||
.base0F { color: #9c637a; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #28211c; }
|
||||
.base01-background { background-color: #36312e; }
|
||||
.base02-background { background-color: #5e5d5c; }
|
||||
.base03-background { background-color: #666666; }
|
||||
.base04-background { background-color: #797977; }
|
||||
.base05-background { background-color: #8a8986; }
|
||||
.base06-background { background-color: #9d9b97; }
|
||||
.base07-background { background-color: #baae9e; }
|
||||
.base08-background { background-color: #cf6a4c; }
|
||||
.base09-background { background-color: #cf7d34; }
|
||||
.base0A-background { background-color: #f9ee98; }
|
||||
.base0B-background { background-color: #54be0d; }
|
||||
.base0C-background { background-color: #afc4db; }
|
||||
.base0D-background { background-color: #5ea6ea; }
|
||||
.base0E-background { background-color: #9b859d; }
|
||||
.base0F-background { background-color: #937121; }
|
||||
|
||||
.base00 { color: #28211c; }
|
||||
.base01 { color: #36312e; }
|
||||
.base02 { color: #5e5d5c; }
|
||||
.base03 { color: #666666; }
|
||||
.base04 { color: #797977; }
|
||||
.base05 { color: #8a8986; }
|
||||
.base06 { color: #9d9b97; }
|
||||
.base07 { color: #baae9e; }
|
||||
.base08 { color: #cf6a4c; }
|
||||
.base09 { color: #cf7d34; }
|
||||
.base0A { color: #f9ee98; }
|
||||
.base0B { color: #54be0d; }
|
||||
.base0C { color: #afc4db; }
|
||||
.base0D { color: #5ea6ea; }
|
||||
.base0E { color: #9b859d; }
|
||||
.base0F { color: #937121; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #0c0d0e; }
|
||||
.base01-background { background-color: #2e2f30; }
|
||||
.base02-background { background-color: #515253; }
|
||||
.base03-background { background-color: #737475; }
|
||||
.base04-background { background-color: #959697; }
|
||||
.base05-background { background-color: #b7b8b9; }
|
||||
.base06-background { background-color: #dadbdc; }
|
||||
.base07-background { background-color: #fcfdfe; }
|
||||
.base08-background { background-color: #e31a1c; }
|
||||
.base09-background { background-color: #e6550d; }
|
||||
.base0A-background { background-color: #dca060; }
|
||||
.base0B-background { background-color: #31a354; }
|
||||
.base0C-background { background-color: #80b1d3; }
|
||||
.base0D-background { background-color: #3182bd; }
|
||||
.base0E-background { background-color: #756bb1; }
|
||||
.base0F-background { background-color: #b15928; }
|
||||
|
||||
.base00 { color: #0c0d0e; }
|
||||
.base01 { color: #2e2f30; }
|
||||
.base02 { color: #515253; }
|
||||
.base03 { color: #737475; }
|
||||
.base04 { color: #959697; }
|
||||
.base05 { color: #b7b8b9; }
|
||||
.base06 { color: #dadbdc; }
|
||||
.base07 { color: #fcfdfe; }
|
||||
.base08 { color: #e31a1c; }
|
||||
.base09 { color: #e6550d; }
|
||||
.base0A { color: #dca060; }
|
||||
.base0B { color: #31a354; }
|
||||
.base0C { color: #80b1d3; }
|
||||
.base0D { color: #3182bd; }
|
||||
.base0E { color: #756bb1; }
|
||||
.base0F { color: #b15928; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #000000; }
|
||||
.base01-background { background-color: #303030; }
|
||||
.base02-background { background-color: #505050; }
|
||||
.base03-background { background-color: #b0b0b0; }
|
||||
.base04-background { background-color: #d0d0d0; }
|
||||
.base05-background { background-color: #e0e0e0; }
|
||||
.base06-background { background-color: #f5f5f5; }
|
||||
.base07-background { background-color: #ffffff; }
|
||||
.base08-background { background-color: #fb0120; }
|
||||
.base09-background { background-color: #fc6d24; }
|
||||
.base0A-background { background-color: #fda331; }
|
||||
.base0B-background { background-color: #a1c659; }
|
||||
.base0C-background { background-color: #76c7b7; }
|
||||
.base0D-background { background-color: #6fb3d2; }
|
||||
.base0E-background { background-color: #d381c3; }
|
||||
.base0F-background { background-color: #be643c; }
|
||||
|
||||
.base00 { color: #000000; }
|
||||
.base01 { color: #303030; }
|
||||
.base02 { color: #505050; }
|
||||
.base03 { color: #b0b0b0; }
|
||||
.base04 { color: #d0d0d0; }
|
||||
.base05 { color: #e0e0e0; }
|
||||
.base06 { color: #f5f5f5; }
|
||||
.base07 { color: #ffffff; }
|
||||
.base08 { color: #fb0120; }
|
||||
.base09 { color: #fc6d24; }
|
||||
.base0A { color: #fda331; }
|
||||
.base0B { color: #a1c659; }
|
||||
.base0C { color: #76c7b7; }
|
||||
.base0D { color: #6fb3d2; }
|
||||
.base0E { color: #d381c3; }
|
||||
.base0F { color: #be643c; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #151515; }
|
||||
.base01-background { background-color: #202020; }
|
||||
.base02-background { background-color: #303030; }
|
||||
.base03-background { background-color: #505050; }
|
||||
.base04-background { background-color: #b0b0b0; }
|
||||
.base05-background { background-color: #d0d0d0; }
|
||||
.base06-background { background-color: #e0e0e0; }
|
||||
.base07-background { background-color: #f5f5f5; }
|
||||
.base08-background { background-color: #fb9fb1; }
|
||||
.base09-background { background-color: #eda987; }
|
||||
.base0A-background { background-color: #ddb26f; }
|
||||
.base0B-background { background-color: #acc267; }
|
||||
.base0C-background { background-color: #12cfc0; }
|
||||
.base0D-background { background-color: #6fc2ef; }
|
||||
.base0E-background { background-color: #e1a3ee; }
|
||||
.base0F-background { background-color: #deaf8f; }
|
||||
|
||||
.base00 { color: #151515; }
|
||||
.base01 { color: #202020; }
|
||||
.base02 { color: #303030; }
|
||||
.base03 { color: #505050; }
|
||||
.base04 { color: #b0b0b0; }
|
||||
.base05 { color: #d0d0d0; }
|
||||
.base06 { color: #e0e0e0; }
|
||||
.base07 { color: #f5f5f5; }
|
||||
.base08 { color: #fb9fb1; }
|
||||
.base09 { color: #eda987; }
|
||||
.base0A { color: #ddb26f; }
|
||||
.base0B { color: #acc267; }
|
||||
.base0C { color: #12cfc0; }
|
||||
.base0D { color: #6fc2ef; }
|
||||
.base0E { color: #e1a3ee; }
|
||||
.base0F { color: #deaf8f; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #232c31; }
|
||||
.base01-background { background-color: #1c3657; }
|
||||
.base02-background { background-color: #2a343a; }
|
||||
.base03-background { background-color: #3f4944; }
|
||||
.base04-background { background-color: #84898c; }
|
||||
.base05-background { background-color: #9ea7a6; }
|
||||
.base06-background { background-color: #a7cfa3; }
|
||||
.base07-background { background-color: #b5d8f6; }
|
||||
.base08-background { background-color: #2a5491; }
|
||||
.base09-background { background-color: #43820d; }
|
||||
.base0A-background { background-color: #a03b1e; }
|
||||
.base0B-background { background-color: #237986; }
|
||||
.base0C-background { background-color: #b02f30; }
|
||||
.base0D-background { background-color: #484d79; }
|
||||
.base0E-background { background-color: #c59820; }
|
||||
.base0F-background { background-color: #c98344; }
|
||||
|
||||
.base00 { color: #232c31; }
|
||||
.base01 { color: #1c3657; }
|
||||
.base02 { color: #2a343a; }
|
||||
.base03 { color: #3f4944; }
|
||||
.base04 { color: #84898c; }
|
||||
.base05 { color: #9ea7a6; }
|
||||
.base06 { color: #a7cfa3; }
|
||||
.base07 { color: #b5d8f6; }
|
||||
.base08 { color: #2a5491; }
|
||||
.base09 { color: #43820d; }
|
||||
.base0A { color: #a03b1e; }
|
||||
.base0B { color: #237986; }
|
||||
.base0C { color: #b02f30; }
|
||||
.base0D { color: #484d79; }
|
||||
.base0E { color: #c59820; }
|
||||
.base0F { color: #c98344; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #1D2021; }
|
||||
.base01-background { background-color: #32302F; }
|
||||
.base02-background { background-color: #504945; }
|
||||
.base03-background { background-color: #665C54; }
|
||||
.base04-background { background-color: #928374; }
|
||||
.base05-background { background-color: #A89984; }
|
||||
.base06-background { background-color: #D5C4A1; }
|
||||
.base07-background { background-color: #FDF4C1; }
|
||||
.base08-background { background-color: #FB543F; }
|
||||
.base09-background { background-color: #FE8625; }
|
||||
.base0A-background { background-color: #FAC03B; }
|
||||
.base0B-background { background-color: #95C085; }
|
||||
.base0C-background { background-color: #8BA59B; }
|
||||
.base0D-background { background-color: #0D6678; }
|
||||
.base0E-background { background-color: #8F4673; }
|
||||
.base0F-background { background-color: #A87322; }
|
||||
|
||||
.base00 { color: #1D2021; }
|
||||
.base01 { color: #32302F; }
|
||||
.base02 { color: #504945; }
|
||||
.base03 { color: #665C54; }
|
||||
.base04 { color: #928374; }
|
||||
.base05 { color: #A89984; }
|
||||
.base06 { color: #D5C4A1; }
|
||||
.base07 { color: #FDF4C1; }
|
||||
.base08 { color: #FB543F; }
|
||||
.base09 { color: #FE8625; }
|
||||
.base0A { color: #FAC03B; }
|
||||
.base0B { color: #95C085; }
|
||||
.base0C { color: #8BA59B; }
|
||||
.base0D { color: #0D6678; }
|
||||
.base0E { color: #8F4673; }
|
||||
.base0F { color: #A87322; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #181818; }
|
||||
.base01-background { background-color: #282828; }
|
||||
.base02-background { background-color: #383838; }
|
||||
.base03-background { background-color: #585858; }
|
||||
.base04-background { background-color: #b8b8b8; }
|
||||
.base05-background { background-color: #d8d8d8; }
|
||||
.base06-background { background-color: #e8e8e8; }
|
||||
.base07-background { background-color: #f8f8f8; }
|
||||
.base08-background { background-color: #ab4642; }
|
||||
.base09-background { background-color: #dc9656; }
|
||||
.base0A-background { background-color: #f7ca88; }
|
||||
.base0B-background { background-color: #a1b56c; }
|
||||
.base0C-background { background-color: #86c1b9; }
|
||||
.base0D-background { background-color: #7cafc2; }
|
||||
.base0E-background { background-color: #ba8baf; }
|
||||
.base0F-background { background-color: #a16946; }
|
||||
|
||||
.base00 { color: #181818; }
|
||||
.base01 { color: #282828; }
|
||||
.base02 { color: #383838; }
|
||||
.base03 { color: #585858; }
|
||||
.base04 { color: #b8b8b8; }
|
||||
.base05 { color: #d8d8d8; }
|
||||
.base06 { color: #e8e8e8; }
|
||||
.base07 { color: #f8f8f8; }
|
||||
.base08 { color: #ab4642; }
|
||||
.base09 { color: #dc9656; }
|
||||
.base0A { color: #f7ca88; }
|
||||
.base0B { color: #a1b56c; }
|
||||
.base0C { color: #86c1b9; }
|
||||
.base0D { color: #7cafc2; }
|
||||
.base0E { color: #ba8baf; }
|
||||
.base0F { color: #a16946; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #f8f8f8; }
|
||||
.base01-background { background-color: #e8e8e8; }
|
||||
.base02-background { background-color: #d8d8d8; }
|
||||
.base03-background { background-color: #b8b8b8; }
|
||||
.base04-background { background-color: #585858; }
|
||||
.base05-background { background-color: #383838; }
|
||||
.base06-background { background-color: #282828; }
|
||||
.base07-background { background-color: #181818; }
|
||||
.base08-background { background-color: #ab4642; }
|
||||
.base09-background { background-color: #dc9656; }
|
||||
.base0A-background { background-color: #f7ca88; }
|
||||
.base0B-background { background-color: #a1b56c; }
|
||||
.base0C-background { background-color: #86c1b9; }
|
||||
.base0D-background { background-color: #7cafc2; }
|
||||
.base0E-background { background-color: #ba8baf; }
|
||||
.base0F-background { background-color: #a16946; }
|
||||
|
||||
.base00 { color: #f8f8f8; }
|
||||
.base01 { color: #e8e8e8; }
|
||||
.base02 { color: #d8d8d8; }
|
||||
.base03 { color: #b8b8b8; }
|
||||
.base04 { color: #585858; }
|
||||
.base05 { color: #383838; }
|
||||
.base06 { color: #282828; }
|
||||
.base07 { color: #181818; }
|
||||
.base08 { color: #ab4642; }
|
||||
.base09 { color: #dc9656; }
|
||||
.base0A { color: #f7ca88; }
|
||||
.base0B { color: #a1b56c; }
|
||||
.base0C { color: #86c1b9; }
|
||||
.base0D { color: #7cafc2; }
|
||||
.base0E { color: #ba8baf; }
|
||||
.base0F { color: #a16946; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #2d2d2d; }
|
||||
.base01-background { background-color: #393939; }
|
||||
.base02-background { background-color: #515151; }
|
||||
.base03-background { background-color: #747369; }
|
||||
.base04-background { background-color: #a09f93; }
|
||||
.base05-background { background-color: #d3d0c8; }
|
||||
.base06-background { background-color: #e8e6df; }
|
||||
.base07-background { background-color: #f2f0ec; }
|
||||
.base08-background { background-color: #f2777a; }
|
||||
.base09-background { background-color: #f99157; }
|
||||
.base0A-background { background-color: #ffcc66; }
|
||||
.base0B-background { background-color: #99cc99; }
|
||||
.base0C-background { background-color: #66cccc; }
|
||||
.base0D-background { background-color: #6699cc; }
|
||||
.base0E-background { background-color: #cc99cc; }
|
||||
.base0F-background { background-color: #d27b53; }
|
||||
|
||||
.base00 { color: #2d2d2d; }
|
||||
.base01 { color: #393939; }
|
||||
.base02 { color: #515151; }
|
||||
.base03 { color: #747369; }
|
||||
.base04 { color: #a09f93; }
|
||||
.base05 { color: #d3d0c8; }
|
||||
.base06 { color: #e8e6df; }
|
||||
.base07 { color: #f2f0ec; }
|
||||
.base08 { color: #f2777a; }
|
||||
.base09 { color: #f99157; }
|
||||
.base0A { color: #ffcc66; }
|
||||
.base0B { color: #99cc99; }
|
||||
.base0C { color: #66cccc; }
|
||||
.base0D { color: #6699cc; }
|
||||
.base0E { color: #cc99cc; }
|
||||
.base0F { color: #d27b53; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #16130F; }
|
||||
.base01-background { background-color: #2C2620; }
|
||||
.base02-background { background-color: #433B32; }
|
||||
.base03-background { background-color: #5A5047; }
|
||||
.base04-background { background-color: #8A8075; }
|
||||
.base05-background { background-color: #A39A90; }
|
||||
.base06-background { background-color: #BEB6AE; }
|
||||
.base07-background { background-color: #DBD6D1; }
|
||||
.base08-background { background-color: #826D57; }
|
||||
.base09-background { background-color: #828257; }
|
||||
.base0A-background { background-color: #6D8257; }
|
||||
.base0B-background { background-color: #57826D; }
|
||||
.base0C-background { background-color: #576D82; }
|
||||
.base0D-background { background-color: #6D5782; }
|
||||
.base0E-background { background-color: #82576D; }
|
||||
.base0F-background { background-color: #825757; }
|
||||
|
||||
.base00 { color: #16130F; }
|
||||
.base01 { color: #2C2620; }
|
||||
.base02 { color: #433B32; }
|
||||
.base03 { color: #5A5047; }
|
||||
.base04 { color: #8A8075; }
|
||||
.base05 { color: #A39A90; }
|
||||
.base06 { color: #BEB6AE; }
|
||||
.base07 { color: #DBD6D1; }
|
||||
.base08 { color: #826D57; }
|
||||
.base09 { color: #828257; }
|
||||
.base0A { color: #6D8257; }
|
||||
.base0B { color: #57826D; }
|
||||
.base0C { color: #576D82; }
|
||||
.base0D { color: #6D5782; }
|
||||
.base0E { color: #82576D; }
|
||||
.base0F { color: #825757; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #2C3E50; }
|
||||
.base01-background { background-color: #34495E; }
|
||||
.base02-background { background-color: #7F8C8D; }
|
||||
.base03-background { background-color: #95A5A6; }
|
||||
.base04-background { background-color: #BDC3C7; }
|
||||
.base05-background { background-color: #e0e0e0; }
|
||||
.base06-background { background-color: #f5f5f5; }
|
||||
.base07-background { background-color: #ECF0F1; }
|
||||
.base08-background { background-color: #E74C3C; }
|
||||
.base09-background { background-color: #E67E22; }
|
||||
.base0A-background { background-color: #F1C40F; }
|
||||
.base0B-background { background-color: #2ECC71; }
|
||||
.base0C-background { background-color: #1ABC9C; }
|
||||
.base0D-background { background-color: #3498DB; }
|
||||
.base0E-background { background-color: #9B59B6; }
|
||||
.base0F-background { background-color: #be643c; }
|
||||
|
||||
.base00 { color: #2C3E50; }
|
||||
.base01 { color: #34495E; }
|
||||
.base02 { color: #7F8C8D; }
|
||||
.base03 { color: #95A5A6; }
|
||||
.base04 { color: #BDC3C7; }
|
||||
.base05 { color: #e0e0e0; }
|
||||
.base06 { color: #f5f5f5; }
|
||||
.base07 { color: #ECF0F1; }
|
||||
.base08 { color: #E74C3C; }
|
||||
.base09 { color: #E67E22; }
|
||||
.base0A { color: #F1C40F; }
|
||||
.base0B { color: #2ECC71; }
|
||||
.base0C { color: #1ABC9C; }
|
||||
.base0D { color: #3498DB; }
|
||||
.base0E { color: #9B59B6; }
|
||||
.base0F { color: #be643c; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #ffffff; }
|
||||
.base01-background { background-color: #f5f5f5; }
|
||||
.base02-background { background-color: #c8c8fa; }
|
||||
.base03-background { background-color: #969896; }
|
||||
.base04-background { background-color: #e8e8e8; }
|
||||
.base05-background { background-color: #333333; }
|
||||
.base06-background { background-color: #ffffff; }
|
||||
.base07-background { background-color: #ffffff; }
|
||||
.base08-background { background-color: #ed6a43; }
|
||||
.base09-background { background-color: #0086b3; }
|
||||
.base0A-background { background-color: #795da3; }
|
||||
.base0B-background { background-color: #183691; }
|
||||
.base0C-background { background-color: #183691; }
|
||||
.base0D-background { background-color: #795da3; }
|
||||
.base0E-background { background-color: #a71d5d; }
|
||||
.base0F-background { background-color: #333333; }
|
||||
|
||||
.base00 { color: #ffffff; }
|
||||
.base01 { color: #f5f5f5; }
|
||||
.base02 { color: #c8c8fa; }
|
||||
.base03 { color: #969896; }
|
||||
.base04 { color: #e8e8e8; }
|
||||
.base05 { color: #333333; }
|
||||
.base06 { color: #ffffff; }
|
||||
.base07 { color: #ffffff; }
|
||||
.base08 { color: #ed6a43; }
|
||||
.base09 { color: #0086b3; }
|
||||
.base0A { color: #795da3; }
|
||||
.base0B { color: #183691; }
|
||||
.base0C { color: #183691; }
|
||||
.base0D { color: #795da3; }
|
||||
.base0E { color: #a71d5d; }
|
||||
.base0F { color: #333333; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #1d1f21; }
|
||||
.base01-background { background-color: #282a2e; }
|
||||
.base02-background { background-color: #373b41; }
|
||||
.base03-background { background-color: #969896; }
|
||||
.base04-background { background-color: #b4b7b4; }
|
||||
.base05-background { background-color: #c5c8c6; }
|
||||
.base06-background { background-color: #e0e0e0; }
|
||||
.base07-background { background-color: #ffffff; }
|
||||
.base08-background { background-color: #CC342B; }
|
||||
.base09-background { background-color: #F96A38; }
|
||||
.base0A-background { background-color: #FBA922; }
|
||||
.base0B-background { background-color: #198844; }
|
||||
.base0C-background { background-color: #3971ED; }
|
||||
.base0D-background { background-color: #3971ED; }
|
||||
.base0E-background { background-color: #A36AC7; }
|
||||
.base0F-background { background-color: #3971ED; }
|
||||
|
||||
.base00 { color: #1d1f21; }
|
||||
.base01 { color: #282a2e; }
|
||||
.base02 { color: #373b41; }
|
||||
.base03 { color: #969896; }
|
||||
.base04 { color: #b4b7b4; }
|
||||
.base05 { color: #c5c8c6; }
|
||||
.base06 { color: #e0e0e0; }
|
||||
.base07 { color: #ffffff; }
|
||||
.base08 { color: #CC342B; }
|
||||
.base09 { color: #F96A38; }
|
||||
.base0A { color: #FBA922; }
|
||||
.base0B { color: #198844; }
|
||||
.base0C { color: #3971ED; }
|
||||
.base0D { color: #3971ED; }
|
||||
.base0E { color: #A36AC7; }
|
||||
.base0F { color: #3971ED; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #ffffff; }
|
||||
.base01-background { background-color: #e0e0e0; }
|
||||
.base02-background { background-color: #c5c8c6; }
|
||||
.base03-background { background-color: #b4b7b4; }
|
||||
.base04-background { background-color: #969896; }
|
||||
.base05-background { background-color: #373b41; }
|
||||
.base06-background { background-color: #282a2e; }
|
||||
.base07-background { background-color: #1d1f21; }
|
||||
.base08-background { background-color: #CC342B; }
|
||||
.base09-background { background-color: #F96A38; }
|
||||
.base0A-background { background-color: #FBA922; }
|
||||
.base0B-background { background-color: #198844; }
|
||||
.base0C-background { background-color: #3971ED; }
|
||||
.base0D-background { background-color: #3971ED; }
|
||||
.base0E-background { background-color: #A36AC7; }
|
||||
.base0F-background { background-color: #3971ED; }
|
||||
|
||||
.base00 { color: #ffffff; }
|
||||
.base01 { color: #e0e0e0; }
|
||||
.base02 { color: #c5c8c6; }
|
||||
.base03 { color: #b4b7b4; }
|
||||
.base04 { color: #969896; }
|
||||
.base05 { color: #373b41; }
|
||||
.base06 { color: #282a2e; }
|
||||
.base07 { color: #1d1f21; }
|
||||
.base08 { color: #CC342B; }
|
||||
.base09 { color: #F96A38; }
|
||||
.base0A { color: #FBA922; }
|
||||
.base0B { color: #198844; }
|
||||
.base0C { color: #3971ED; }
|
||||
.base0D { color: #3971ED; }
|
||||
.base0E { color: #A36AC7; }
|
||||
.base0F { color: #3971ED; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #101010; }
|
||||
.base01-background { background-color: #252525; }
|
||||
.base02-background { background-color: #464646; }
|
||||
.base03-background { background-color: #525252; }
|
||||
.base04-background { background-color: #ababab; }
|
||||
.base05-background { background-color: #b9b9b9; }
|
||||
.base06-background { background-color: #e3e3e3; }
|
||||
.base07-background { background-color: #f7f7f7; }
|
||||
.base08-background { background-color: #7c7c7c; }
|
||||
.base09-background { background-color: #999999; }
|
||||
.base0A-background { background-color: #a0a0a0; }
|
||||
.base0B-background { background-color: #8e8e8e; }
|
||||
.base0C-background { background-color: #868686; }
|
||||
.base0D-background { background-color: #686868; }
|
||||
.base0E-background { background-color: #747474; }
|
||||
.base0F-background { background-color: #5e5e5e; }
|
||||
|
||||
.base00 { color: #101010; }
|
||||
.base01 { color: #252525; }
|
||||
.base02 { color: #464646; }
|
||||
.base03 { color: #525252; }
|
||||
.base04 { color: #ababab; }
|
||||
.base05 { color: #b9b9b9; }
|
||||
.base06 { color: #e3e3e3; }
|
||||
.base07 { color: #f7f7f7; }
|
||||
.base08 { color: #7c7c7c; }
|
||||
.base09 { color: #999999; }
|
||||
.base0A { color: #a0a0a0; }
|
||||
.base0B { color: #8e8e8e; }
|
||||
.base0C { color: #868686; }
|
||||
.base0D { color: #686868; }
|
||||
.base0E { color: #747474; }
|
||||
.base0F { color: #5e5e5e; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #f7f7f7; }
|
||||
.base01-background { background-color: #e3e3e3; }
|
||||
.base02-background { background-color: #b9b9b9; }
|
||||
.base03-background { background-color: #ababab; }
|
||||
.base04-background { background-color: #525252; }
|
||||
.base05-background { background-color: #464646; }
|
||||
.base06-background { background-color: #252525; }
|
||||
.base07-background { background-color: #101010; }
|
||||
.base08-background { background-color: #7c7c7c; }
|
||||
.base09-background { background-color: #999999; }
|
||||
.base0A-background { background-color: #a0a0a0; }
|
||||
.base0B-background { background-color: #8e8e8e; }
|
||||
.base0C-background { background-color: #868686; }
|
||||
.base0D-background { background-color: #686868; }
|
||||
.base0E-background { background-color: #747474; }
|
||||
.base0F-background { background-color: #5e5e5e; }
|
||||
|
||||
.base00 { color: #f7f7f7; }
|
||||
.base01 { color: #e3e3e3; }
|
||||
.base02 { color: #b9b9b9; }
|
||||
.base03 { color: #ababab; }
|
||||
.base04 { color: #525252; }
|
||||
.base05 { color: #464646; }
|
||||
.base06 { color: #252525; }
|
||||
.base07 { color: #101010; }
|
||||
.base08 { color: #7c7c7c; }
|
||||
.base09 { color: #999999; }
|
||||
.base0A { color: #a0a0a0; }
|
||||
.base0B { color: #8e8e8e; }
|
||||
.base0C { color: #868686; }
|
||||
.base0D { color: #686868; }
|
||||
.base0E { color: #747474; }
|
||||
.base0F { color: #5e5e5e; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #001100; }
|
||||
.base01-background { background-color: #003300; }
|
||||
.base02-background { background-color: #005500; }
|
||||
.base03-background { background-color: #007700; }
|
||||
.base04-background { background-color: #009900; }
|
||||
.base05-background { background-color: #00bb00; }
|
||||
.base06-background { background-color: #00dd00; }
|
||||
.base07-background { background-color: #00ff00; }
|
||||
.base08-background { background-color: #007700; }
|
||||
.base09-background { background-color: #009900; }
|
||||
.base0A-background { background-color: #007700; }
|
||||
.base0B-background { background-color: #00bb00; }
|
||||
.base0C-background { background-color: #005500; }
|
||||
.base0D-background { background-color: #009900; }
|
||||
.base0E-background { background-color: #00bb00; }
|
||||
.base0F-background { background-color: #005500; }
|
||||
|
||||
.base00 { color: #001100; }
|
||||
.base01 { color: #003300; }
|
||||
.base02 { color: #005500; }
|
||||
.base03 { color: #007700; }
|
||||
.base04 { color: #009900; }
|
||||
.base05 { color: #00bb00; }
|
||||
.base06 { color: #00dd00; }
|
||||
.base07 { color: #00ff00; }
|
||||
.base08 { color: #007700; }
|
||||
.base09 { color: #009900; }
|
||||
.base0A { color: #007700; }
|
||||
.base0B { color: #00bb00; }
|
||||
.base0C { color: #005500; }
|
||||
.base0D { color: #009900; }
|
||||
.base0E { color: #00bb00; }
|
||||
.base0F { color: #005500; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #0b1c2c; }
|
||||
.base01-background { background-color: #223b54; }
|
||||
.base02-background { background-color: #405c79; }
|
||||
.base03-background { background-color: #627e99; }
|
||||
.base04-background { background-color: #aabcce; }
|
||||
.base05-background { background-color: #cbd6e2; }
|
||||
.base06-background { background-color: #e5ebf1; }
|
||||
.base07-background { background-color: #f7f9fb; }
|
||||
.base08-background { background-color: #bf8b56; }
|
||||
.base09-background { background-color: #bfbf56; }
|
||||
.base0A-background { background-color: #8bbf56; }
|
||||
.base0B-background { background-color: #56bf8b; }
|
||||
.base0C-background { background-color: #568bbf; }
|
||||
.base0D-background { background-color: #8b56bf; }
|
||||
.base0E-background { background-color: #bf568b; }
|
||||
.base0F-background { background-color: #bf5656; }
|
||||
|
||||
.base00 { color: #0b1c2c; }
|
||||
.base01 { color: #223b54; }
|
||||
.base02 { color: #405c79; }
|
||||
.base03 { color: #627e99; }
|
||||
.base04 { color: #aabcce; }
|
||||
.base05 { color: #cbd6e2; }
|
||||
.base06 { color: #e5ebf1; }
|
||||
.base07 { color: #f7f9fb; }
|
||||
.base08 { color: #bf8b56; }
|
||||
.base09 { color: #bfbf56; }
|
||||
.base0A { color: #8bbf56; }
|
||||
.base0B { color: #56bf8b; }
|
||||
.base0C { color: #568bbf; }
|
||||
.base0D { color: #8b56bf; }
|
||||
.base0E { color: #bf568b; }
|
||||
.base0F { color: #bf5656; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #f7f9fb; }
|
||||
.base01-background { background-color: #e5ebf1; }
|
||||
.base02-background { background-color: #cbd6e2; }
|
||||
.base03-background { background-color: #aabcce; }
|
||||
.base04-background { background-color: #627e99; }
|
||||
.base05-background { background-color: #405c79; }
|
||||
.base06-background { background-color: #223b54; }
|
||||
.base07-background { background-color: #0b1c2c; }
|
||||
.base08-background { background-color: #bf8b56; }
|
||||
.base09-background { background-color: #bfbf56; }
|
||||
.base0A-background { background-color: #8bbf56; }
|
||||
.base0B-background { background-color: #56bf8b; }
|
||||
.base0C-background { background-color: #568bbf; }
|
||||
.base0D-background { background-color: #8b56bf; }
|
||||
.base0E-background { background-color: #bf568b; }
|
||||
.base0F-background { background-color: #bf5656; }
|
||||
|
||||
.base00 { color: #f7f9fb; }
|
||||
.base01 { color: #e5ebf1; }
|
||||
.base02 { color: #cbd6e2; }
|
||||
.base03 { color: #aabcce; }
|
||||
.base04 { color: #627e99; }
|
||||
.base05 { color: #405c79; }
|
||||
.base06 { color: #223b54; }
|
||||
.base07 { color: #0b1c2c; }
|
||||
.base08 { color: #bf8b56; }
|
||||
.base09 { color: #bfbf56; }
|
||||
.base0A { color: #8bbf56; }
|
||||
.base0B { color: #56bf8b; }
|
||||
.base0C { color: #568bbf; }
|
||||
.base0D { color: #8b56bf; }
|
||||
.base0E { color: #bf568b; }
|
||||
.base0F { color: #bf5656; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #322931; }
|
||||
.base01-background { background-color: #433b42; }
|
||||
.base02-background { background-color: #5c545b; }
|
||||
.base03-background { background-color: #797379; }
|
||||
.base04-background { background-color: #989498; }
|
||||
.base05-background { background-color: #b9b5b8; }
|
||||
.base06-background { background-color: #d5d3d5; }
|
||||
.base07-background { background-color: #ffffff; }
|
||||
.base08-background { background-color: #dd464c; }
|
||||
.base09-background { background-color: #fd8b19; }
|
||||
.base0A-background { background-color: #fdcc59; }
|
||||
.base0B-background { background-color: #8fc13e; }
|
||||
.base0C-background { background-color: #149b93; }
|
||||
.base0D-background { background-color: #1290bf; }
|
||||
.base0E-background { background-color: #c85e7c; }
|
||||
.base0F-background { background-color: #b33508; }
|
||||
|
||||
.base00 { color: #322931; }
|
||||
.base01 { color: #433b42; }
|
||||
.base02 { color: #5c545b; }
|
||||
.base03 { color: #797379; }
|
||||
.base04 { color: #989498; }
|
||||
.base05 { color: #b9b5b8; }
|
||||
.base06 { color: #d5d3d5; }
|
||||
.base07 { color: #ffffff; }
|
||||
.base08 { color: #dd464c; }
|
||||
.base09 { color: #fd8b19; }
|
||||
.base0A { color: #fdcc59; }
|
||||
.base0B { color: #8fc13e; }
|
||||
.base0C { color: #149b93; }
|
||||
.base0D { color: #1290bf; }
|
||||
.base0E { color: #c85e7c; }
|
||||
.base0F { color: #b33508; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #000000; }
|
||||
.base01-background { background-color: #242422; }
|
||||
.base02-background { background-color: #484844; }
|
||||
.base03-background { background-color: #6c6c66; }
|
||||
.base04-background { background-color: #918f88; }
|
||||
.base05-background { background-color: #b5b3aa; }
|
||||
.base06-background { background-color: #d9d7cc; }
|
||||
.base07-background { background-color: #fdfbee; }
|
||||
.base08-background { background-color: #ff6c60; }
|
||||
.base09-background { background-color: #e9c062; }
|
||||
.base0A-background { background-color: #ffffb6; }
|
||||
.base0B-background { background-color: #a8ff60; }
|
||||
.base0C-background { background-color: #c6c5fe; }
|
||||
.base0D-background { background-color: #96cbfe; }
|
||||
.base0E-background { background-color: #ff73fd; }
|
||||
.base0F-background { background-color: #b18a3d; }
|
||||
|
||||
.base00 { color: #000000; }
|
||||
.base01 { color: #242422; }
|
||||
.base02 { color: #484844; }
|
||||
.base03 { color: #6c6c66; }
|
||||
.base04 { color: #918f88; }
|
||||
.base05 { color: #b5b3aa; }
|
||||
.base06 { color: #d9d7cc; }
|
||||
.base07 { color: #fdfbee; }
|
||||
.base08 { color: #ff6c60; }
|
||||
.base09 { color: #e9c062; }
|
||||
.base0A { color: #ffffb6; }
|
||||
.base0B { color: #a8ff60; }
|
||||
.base0C { color: #c6c5fe; }
|
||||
.base0D { color: #96cbfe; }
|
||||
.base0E { color: #ff73fd; }
|
||||
.base0F { color: #b18a3d; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #000000; }
|
||||
.base01-background { background-color: #404040; }
|
||||
.base02-background { background-color: #606060; }
|
||||
.base03-background { background-color: #808080; }
|
||||
.base04-background { background-color: #c0c0c0; }
|
||||
.base05-background { background-color: #d0d0d0; }
|
||||
.base06-background { background-color: #e0e0e0; }
|
||||
.base07-background { background-color: #ffffff; }
|
||||
.base08-background { background-color: #ff0000; }
|
||||
.base09-background { background-color: #ff9900; }
|
||||
.base0A-background { background-color: #ff0099; }
|
||||
.base0B-background { background-color: #33ff00; }
|
||||
.base0C-background { background-color: #00ffff; }
|
||||
.base0D-background { background-color: #0066ff; }
|
||||
.base0E-background { background-color: #cc00ff; }
|
||||
.base0F-background { background-color: #3300ff; }
|
||||
|
||||
.base00 { color: #000000; }
|
||||
.base01 { color: #404040; }
|
||||
.base02 { color: #606060; }
|
||||
.base03 { color: #808080; }
|
||||
.base04 { color: #c0c0c0; }
|
||||
.base05 { color: #d0d0d0; }
|
||||
.base06 { color: #e0e0e0; }
|
||||
.base07 { color: #ffffff; }
|
||||
.base08 { color: #ff0000; }
|
||||
.base09 { color: #ff9900; }
|
||||
.base0A { color: #ff0099; }
|
||||
.base0B { color: #33ff00; }
|
||||
.base0C { color: #00ffff; }
|
||||
.base0D { color: #0066ff; }
|
||||
.base0E { color: #cc00ff; }
|
||||
.base0F { color: #3300ff; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #231f20; }
|
||||
.base01-background { background-color: #1c3f95; }
|
||||
.base02-background { background-color: #5a5758; }
|
||||
.base03-background { background-color: #737171; }
|
||||
.base04-background { background-color: #959ca1; }
|
||||
.base05-background { background-color: #d9d8d8; }
|
||||
.base06-background { background-color: #e7e7e8; }
|
||||
.base07-background { background-color: #ffffff; }
|
||||
.base08-background { background-color: #ee2e24; }
|
||||
.base09-background { background-color: #f386a1; }
|
||||
.base0A-background { background-color: #ffd204; }
|
||||
.base0B-background { background-color: #00853e; }
|
||||
.base0C-background { background-color: #85cebc; }
|
||||
.base0D-background { background-color: #009ddc; }
|
||||
.base0E-background { background-color: #98005d; }
|
||||
.base0F-background { background-color: #b06110; }
|
||||
|
||||
.base00 { color: #231f20; }
|
||||
.base01 { color: #1c3f95; }
|
||||
.base02 { color: #5a5758; }
|
||||
.base03 { color: #737171; }
|
||||
.base04 { color: #959ca1; }
|
||||
.base05 { color: #d9d8d8; }
|
||||
.base06 { color: #e7e7e8; }
|
||||
.base07 { color: #ffffff; }
|
||||
.base08 { color: #ee2e24; }
|
||||
.base09 { color: #f386a1; }
|
||||
.base0A { color: #ffd204; }
|
||||
.base0B { color: #00853e; }
|
||||
.base0C { color: #85cebc; }
|
||||
.base0D { color: #009ddc; }
|
||||
.base0E { color: #98005d; }
|
||||
.base0F { color: #b06110; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #000000; }
|
||||
.base01-background { background-color: #404040; }
|
||||
.base02-background { background-color: #404040; }
|
||||
.base03-background { background-color: #808080; }
|
||||
.base04-background { background-color: #808080; }
|
||||
.base05-background { background-color: #c0c0c0; }
|
||||
.base06-background { background-color: #c0c0c0; }
|
||||
.base07-background { background-color: #ffffff; }
|
||||
.base08-background { background-color: #dd0907; }
|
||||
.base09-background { background-color: #ff6403; }
|
||||
.base0A-background { background-color: #fbf305; }
|
||||
.base0B-background { background-color: #1fb714; }
|
||||
.base0C-background { background-color: #02abea; }
|
||||
.base0D-background { background-color: #0000d3; }
|
||||
.base0E-background { background-color: #4700a5; }
|
||||
.base0F-background { background-color: #90713a; }
|
||||
|
||||
.base00 { color: #000000; }
|
||||
.base01 { color: #404040; }
|
||||
.base02 { color: #404040; }
|
||||
.base03 { color: #808080; }
|
||||
.base04 { color: #808080; }
|
||||
.base05 { color: #c0c0c0; }
|
||||
.base06 { color: #c0c0c0; }
|
||||
.base07 { color: #ffffff; }
|
||||
.base08 { color: #dd0907; }
|
||||
.base09 { color: #ff6403; }
|
||||
.base0A { color: #fbf305; }
|
||||
.base0B { color: #1fb714; }
|
||||
.base0C { color: #02abea; }
|
||||
.base0D { color: #0000d3; }
|
||||
.base0E { color: #4700a5; }
|
||||
.base0F { color: #90713a; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #201602; }
|
||||
.base01-background { background-color: #302e00; }
|
||||
.base02-background { background-color: #5f5b17; }
|
||||
.base03-background { background-color: #6c6823; }
|
||||
.base04-background { background-color: #86813b; }
|
||||
.base05-background { background-color: #948e48; }
|
||||
.base06-background { background-color: #ccc37a; }
|
||||
.base07-background { background-color: #faf0a5; }
|
||||
.base08-background { background-color: #c35359; }
|
||||
.base09-background { background-color: #b36144; }
|
||||
.base0A-background { background-color: #a88339; }
|
||||
.base0B-background { background-color: #18974e; }
|
||||
.base0C-background { background-color: #75a738; }
|
||||
.base0D-background { background-color: #477ca1; }
|
||||
.base0E-background { background-color: #8868b3; }
|
||||
.base0F-background { background-color: #b3588e; }
|
||||
|
||||
.base00 { color: #201602; }
|
||||
.base01 { color: #302e00; }
|
||||
.base02 { color: #5f5b17; }
|
||||
.base03 { color: #6c6823; }
|
||||
.base04 { color: #86813b; }
|
||||
.base05 { color: #948e48; }
|
||||
.base06 { color: #ccc37a; }
|
||||
.base07 { color: #faf0a5; }
|
||||
.base08 { color: #c35359; }
|
||||
.base09 { color: #b36144; }
|
||||
.base0A { color: #a88339; }
|
||||
.base0B { color: #18974e; }
|
||||
.base0C { color: #75a738; }
|
||||
.base0D { color: #477ca1; }
|
||||
.base0E { color: #8868b3; }
|
||||
.base0F { color: #b3588e; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #263238; }
|
||||
.base01-background { background-color: #2C393F; }
|
||||
.base02-background { background-color: #37474F; }
|
||||
.base03-background { background-color: #707880; }
|
||||
.base04-background { background-color: #C9CCD3; }
|
||||
.base05-background { background-color: #CDD3DE; }
|
||||
.base06-background { background-color: #D5DBE5; }
|
||||
.base07-background { background-color: #FFFFFF; }
|
||||
.base08-background { background-color: #EC5F67; }
|
||||
.base09-background { background-color: #EA9560; }
|
||||
.base0A-background { background-color: #FFCC00; }
|
||||
.base0B-background { background-color: #8BD649; }
|
||||
.base0C-background { background-color: #80CBC4; }
|
||||
.base0D-background { background-color: #89DDFF; }
|
||||
.base0E-background { background-color: #82AAFF; }
|
||||
.base0F-background { background-color: #EC5F67; }
|
||||
|
||||
.base00 { color: #263238; }
|
||||
.base01 { color: #2C393F; }
|
||||
.base02 { color: #37474F; }
|
||||
.base03 { color: #707880; }
|
||||
.base04 { color: #C9CCD3; }
|
||||
.base05 { color: #CDD3DE; }
|
||||
.base06 { color: #D5DBE5; }
|
||||
.base07 { color: #FFFFFF; }
|
||||
.base08 { color: #EC5F67; }
|
||||
.base09 { color: #EA9560; }
|
||||
.base0A { color: #FFCC00; }
|
||||
.base0B { color: #8BD649; }
|
||||
.base0C { color: #80CBC4; }
|
||||
.base0D { color: #89DDFF; }
|
||||
.base0E { color: #82AAFF; }
|
||||
.base0F { color: #EC5F67; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #f8f8f8; }
|
||||
.base01-background { background-color: #e8e8e8; }
|
||||
.base02-background { background-color: #d8d8d8; }
|
||||
.base03-background { background-color: #b8b8b8; }
|
||||
.base04-background { background-color: #585858; }
|
||||
.base05-background { background-color: #383838; }
|
||||
.base06-background { background-color: #282828; }
|
||||
.base07-background { background-color: #181818; }
|
||||
.base08-background { background-color: #ab4642; }
|
||||
.base09-background { background-color: #dc9656; }
|
||||
.base0A-background { background-color: #f79a0e; }
|
||||
.base0B-background { background-color: #538947; }
|
||||
.base0C-background { background-color: #4b8093; }
|
||||
.base0D-background { background-color: #7cafc2; }
|
||||
.base0E-background { background-color: #96609e; }
|
||||
.base0F-background { background-color: #a16946; }
|
||||
|
||||
.base00 { color: #f8f8f8; }
|
||||
.base01 { color: #e8e8e8; }
|
||||
.base02 { color: #d8d8d8; }
|
||||
.base03 { color: #b8b8b8; }
|
||||
.base04 { color: #585858; }
|
||||
.base05 { color: #383838; }
|
||||
.base06 { color: #282828; }
|
||||
.base07 { color: #181818; }
|
||||
.base08 { color: #ab4642; }
|
||||
.base09 { color: #dc9656; }
|
||||
.base0A { color: #f79a0e; }
|
||||
.base0B { color: #538947; }
|
||||
.base0C { color: #4b8093; }
|
||||
.base0D { color: #7cafc2; }
|
||||
.base0E { color: #96609e; }
|
||||
.base0F { color: #a16946; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #3B3228; }
|
||||
.base01-background { background-color: #534636; }
|
||||
.base02-background { background-color: #645240; }
|
||||
.base03-background { background-color: #7e705a; }
|
||||
.base04-background { background-color: #b8afad; }
|
||||
.base05-background { background-color: #d0c8c6; }
|
||||
.base06-background { background-color: #e9e1dd; }
|
||||
.base07-background { background-color: #f5eeeb; }
|
||||
.base08-background { background-color: #cb6077; }
|
||||
.base09-background { background-color: #d28b71; }
|
||||
.base0A-background { background-color: #f4bc87; }
|
||||
.base0B-background { background-color: #beb55b; }
|
||||
.base0C-background { background-color: #7bbda4; }
|
||||
.base0D-background { background-color: #8ab3b5; }
|
||||
.base0E-background { background-color: #a89bb9; }
|
||||
.base0F-background { background-color: #bb9584; }
|
||||
|
||||
.base00 { color: #3B3228; }
|
||||
.base01 { color: #534636; }
|
||||
.base02 { color: #645240; }
|
||||
.base03 { color: #7e705a; }
|
||||
.base04 { color: #b8afad; }
|
||||
.base05 { color: #d0c8c6; }
|
||||
.base06 { color: #e9e1dd; }
|
||||
.base07 { color: #f5eeeb; }
|
||||
.base08 { color: #cb6077; }
|
||||
.base09 { color: #d28b71; }
|
||||
.base0A { color: #f4bc87; }
|
||||
.base0B { color: #beb55b; }
|
||||
.base0C { color: #7bbda4; }
|
||||
.base0D { color: #8ab3b5; }
|
||||
.base0E { color: #a89bb9; }
|
||||
.base0F { color: #bb9584; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #272822; }
|
||||
.base01-background { background-color: #383830; }
|
||||
.base02-background { background-color: #49483e; }
|
||||
.base03-background { background-color: #75715e; }
|
||||
.base04-background { background-color: #a59f85; }
|
||||
.base05-background { background-color: #f8f8f2; }
|
||||
.base06-background { background-color: #f5f4f1; }
|
||||
.base07-background { background-color: #f9f8f5; }
|
||||
.base08-background { background-color: #f92672; }
|
||||
.base09-background { background-color: #fd971f; }
|
||||
.base0A-background { background-color: #f4bf75; }
|
||||
.base0B-background { background-color: #a6e22e; }
|
||||
.base0C-background { background-color: #a1efe4; }
|
||||
.base0D-background { background-color: #66d9ef; }
|
||||
.base0E-background { background-color: #ae81ff; }
|
||||
.base0F-background { background-color: #cc6633; }
|
||||
|
||||
.base00 { color: #272822; }
|
||||
.base01 { color: #383830; }
|
||||
.base02 { color: #49483e; }
|
||||
.base03 { color: #75715e; }
|
||||
.base04 { color: #a59f85; }
|
||||
.base05 { color: #f8f8f2; }
|
||||
.base06 { color: #f5f4f1; }
|
||||
.base07 { color: #f9f8f5; }
|
||||
.base08 { color: #f92672; }
|
||||
.base09 { color: #fd971f; }
|
||||
.base0A { color: #f4bf75; }
|
||||
.base0B { color: #a6e22e; }
|
||||
.base0C { color: #a1efe4; }
|
||||
.base0D { color: #66d9ef; }
|
||||
.base0E { color: #ae81ff; }
|
||||
.base0F { color: #cc6633; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #2b303b; }
|
||||
.base01-background { background-color: #343d46; }
|
||||
.base02-background { background-color: #4f5b66; }
|
||||
.base03-background { background-color: #65737e; }
|
||||
.base04-background { background-color: #a7adba; }
|
||||
.base05-background { background-color: #c0c5ce; }
|
||||
.base06-background { background-color: #dfe1e8; }
|
||||
.base07-background { background-color: #eff1f5; }
|
||||
.base08-background { background-color: #bf616a; }
|
||||
.base09-background { background-color: #d08770; }
|
||||
.base0A-background { background-color: #ebcb8b; }
|
||||
.base0B-background { background-color: #a3be8c; }
|
||||
.base0C-background { background-color: #96b5b4; }
|
||||
.base0D-background { background-color: #8fa1b3; }
|
||||
.base0E-background { background-color: #b48ead; }
|
||||
.base0F-background { background-color: #ab7967; }
|
||||
|
||||
.base00 { color: #2b303b; }
|
||||
.base01 { color: #343d46; }
|
||||
.base02 { color: #4f5b66; }
|
||||
.base03 { color: #65737e; }
|
||||
.base04 { color: #a7adba; }
|
||||
.base05 { color: #c0c5ce; }
|
||||
.base06 { color: #dfe1e8; }
|
||||
.base07 { color: #eff1f5; }
|
||||
.base08 { color: #bf616a; }
|
||||
.base09 { color: #d08770; }
|
||||
.base0A { color: #ebcb8b; }
|
||||
.base0B { color: #a3be8c; }
|
||||
.base0C { color: #96b5b4; }
|
||||
.base0D { color: #8fa1b3; }
|
||||
.base0E { color: #b48ead; }
|
||||
.base0F { color: #ab7967; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #1B2B34; }
|
||||
.base01-background { background-color: #343D46; }
|
||||
.base02-background { background-color: #4F5B66; }
|
||||
.base03-background { background-color: #65737E; }
|
||||
.base04-background { background-color: #A7ADBA; }
|
||||
.base05-background { background-color: #C0C5CE; }
|
||||
.base06-background { background-color: #CDD3DE; }
|
||||
.base07-background { background-color: #D8DEE9; }
|
||||
.base08-background { background-color: #EC5f67; }
|
||||
.base09-background { background-color: #F99157; }
|
||||
.base0A-background { background-color: #FAC863; }
|
||||
.base0B-background { background-color: #99C794; }
|
||||
.base0C-background { background-color: #5FB3B3; }
|
||||
.base0D-background { background-color: #6699CC; }
|
||||
.base0E-background { background-color: #C594C5; }
|
||||
.base0F-background { background-color: #AB7967; }
|
||||
|
||||
.base00 { color: #1B2B34; }
|
||||
.base01 { color: #343D46; }
|
||||
.base02 { color: #4F5B66; }
|
||||
.base03 { color: #65737E; }
|
||||
.base04 { color: #A7ADBA; }
|
||||
.base05 { color: #C0C5CE; }
|
||||
.base06 { color: #CDD3DE; }
|
||||
.base07 { color: #D8DEE9; }
|
||||
.base08 { color: #EC5f67; }
|
||||
.base09 { color: #F99157; }
|
||||
.base0A { color: #FAC863; }
|
||||
.base0B { color: #99C794; }
|
||||
.base0C { color: #5FB3B3; }
|
||||
.base0D { color: #6699CC; }
|
||||
.base0E { color: #C594C5; }
|
||||
.base0F { color: #AB7967; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #2f1e2e; }
|
||||
.base01-background { background-color: #41323f; }
|
||||
.base02-background { background-color: #4f424c; }
|
||||
.base03-background { background-color: #776e71; }
|
||||
.base04-background { background-color: #8d8687; }
|
||||
.base05-background { background-color: #a39e9b; }
|
||||
.base06-background { background-color: #b9b6b0; }
|
||||
.base07-background { background-color: #e7e9db; }
|
||||
.base08-background { background-color: #ef6155; }
|
||||
.base09-background { background-color: #f99b15; }
|
||||
.base0A-background { background-color: #fec418; }
|
||||
.base0B-background { background-color: #48b685; }
|
||||
.base0C-background { background-color: #5bc4bf; }
|
||||
.base0D-background { background-color: #06b6ef; }
|
||||
.base0E-background { background-color: #815ba4; }
|
||||
.base0F-background { background-color: #e96ba8; }
|
||||
|
||||
.base00 { color: #2f1e2e; }
|
||||
.base01 { color: #41323f; }
|
||||
.base02 { color: #4f424c; }
|
||||
.base03 { color: #776e71; }
|
||||
.base04 { color: #8d8687; }
|
||||
.base05 { color: #a39e9b; }
|
||||
.base06 { color: #b9b6b0; }
|
||||
.base07 { color: #e7e9db; }
|
||||
.base08 { color: #ef6155; }
|
||||
.base09 { color: #f99b15; }
|
||||
.base0A { color: #fec418; }
|
||||
.base0B { color: #48b685; }
|
||||
.base0C { color: #5bc4bf; }
|
||||
.base0D { color: #06b6ef; }
|
||||
.base0E { color: #815ba4; }
|
||||
.base0F { color: #e96ba8; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #061229; }
|
||||
.base01-background { background-color: #2a3448; }
|
||||
.base02-background { background-color: #4d5666; }
|
||||
.base03-background { background-color: #717885; }
|
||||
.base04-background { background-color: #9a99a3; }
|
||||
.base05-background { background-color: #b8bbc2; }
|
||||
.base06-background { background-color: #dbdde0; }
|
||||
.base07-background { background-color: #ffffff; }
|
||||
.base08-background { background-color: #d07346; }
|
||||
.base09-background { background-color: #f0a000; }
|
||||
.base0A-background { background-color: #fbd461; }
|
||||
.base0B-background { background-color: #99bf52; }
|
||||
.base0C-background { background-color: #72b9bf; }
|
||||
.base0D-background { background-color: #5299bf; }
|
||||
.base0E-background { background-color: #9989cc; }
|
||||
.base0F-background { background-color: #b08060; }
|
||||
|
||||
.base00 { color: #061229; }
|
||||
.base01 { color: #2a3448; }
|
||||
.base02 { color: #4d5666; }
|
||||
.base03 { color: #717885; }
|
||||
.base04 { color: #9a99a3; }
|
||||
.base05 { color: #b8bbc2; }
|
||||
.base06 { color: #dbdde0; }
|
||||
.base07 { color: #ffffff; }
|
||||
.base08 { color: #d07346; }
|
||||
.base09 { color: #f0a000; }
|
||||
.base0A { color: #fbd461; }
|
||||
.base0B { color: #99bf52; }
|
||||
.base0C { color: #72b9bf; }
|
||||
.base0D { color: #5299bf; }
|
||||
.base0E { color: #9989cc; }
|
||||
.base0F { color: #b08060; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #000000; }
|
||||
.base01-background { background-color: #1d2b53; }
|
||||
.base02-background { background-color: #7e2553; }
|
||||
.base03-background { background-color: #008751; }
|
||||
.base04-background { background-color: #ab5236; }
|
||||
.base05-background { background-color: #5f574f; }
|
||||
.base06-background { background-color: #c2c3c7; }
|
||||
.base07-background { background-color: #fff1e8; }
|
||||
.base08-background { background-color: #ff004d; }
|
||||
.base09-background { background-color: #ffa300; }
|
||||
.base0A-background { background-color: #fff024; }
|
||||
.base0B-background { background-color: #00e756; }
|
||||
.base0C-background { background-color: #29adff; }
|
||||
.base0D-background { background-color: #83769c; }
|
||||
.base0E-background { background-color: #ff77a8; }
|
||||
.base0F-background { background-color: #ffccaa; }
|
||||
|
||||
.base00 { color: #000000; }
|
||||
.base01 { color: #1d2b53; }
|
||||
.base02 { color: #7e2553; }
|
||||
.base03 { color: #008751; }
|
||||
.base04 { color: #ab5236; }
|
||||
.base05 { color: #5f574f; }
|
||||
.base06 { color: #c2c3c7; }
|
||||
.base07 { color: #fff1e8; }
|
||||
.base08 { color: #ff004d; }
|
||||
.base09 { color: #ffa300; }
|
||||
.base0A { color: #fff024; }
|
||||
.base0B { color: #00e756; }
|
||||
.base0C { color: #29adff; }
|
||||
.base0D { color: #83769c; }
|
||||
.base0E { color: #ff77a8; }
|
||||
.base0F { color: #ffccaa; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #161c20; }
|
||||
.base01-background { background-color: #282e32; }
|
||||
.base02-background { background-color: #343a3f; }
|
||||
.base03-background { background-color: #4e5256; }
|
||||
.base04-background { background-color: #ababab; }
|
||||
.base05-background { background-color: #b9b9b9; }
|
||||
.base06-background { background-color: #d0d0d0; }
|
||||
.base07-background { background-color: #e7e7e7; }
|
||||
.base08-background { background-color: #baaa9c; }
|
||||
.base09-background { background-color: #999999; }
|
||||
.base0A-background { background-color: #a0a0a0; }
|
||||
.base0B-background { background-color: #8e8e8e; }
|
||||
.base0C-background { background-color: #868686; }
|
||||
.base0D-background { background-color: #686868; }
|
||||
.base0E-background { background-color: #747474; }
|
||||
.base0F-background { background-color: #5e5e5e; }
|
||||
|
||||
.base00 { color: #161c20; }
|
||||
.base01 { color: #282e32; }
|
||||
.base02 { color: #343a3f; }
|
||||
.base03 { color: #4e5256; }
|
||||
.base04 { color: #ababab; }
|
||||
.base05 { color: #b9b9b9; }
|
||||
.base06 { color: #d0d0d0; }
|
||||
.base07 { color: #e7e7e7; }
|
||||
.base08 { color: #baaa9c; }
|
||||
.base09 { color: #999999; }
|
||||
.base0A { color: #a0a0a0; }
|
||||
.base0B { color: #8e8e8e; }
|
||||
.base0C { color: #868686; }
|
||||
.base0D { color: #686868; }
|
||||
.base0E { color: #747474; }
|
||||
.base0F { color: #5e5e5e; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #f2f4f6; }
|
||||
.base01-background { background-color: #dde2e6; }
|
||||
.base02-background { background-color: #c0c6cb; }
|
||||
.base03-background { background-color: #a4a4a4; }
|
||||
.base04-background { background-color: #545454; }
|
||||
.base05-background { background-color: #304055; }
|
||||
.base06-background { background-color: #040404; }
|
||||
.base07-background { background-color: #000000; }
|
||||
.base08-background { background-color: #e92f2f; }
|
||||
.base09-background { background-color: #e09448; }
|
||||
.base0A-background { background-color: #dddd13; }
|
||||
.base0B-background { background-color: #0ed839; }
|
||||
.base0C-background { background-color: #23edda; }
|
||||
.base0D-background { background-color: #3b48e3; }
|
||||
.base0E-background { background-color: #f996e2; }
|
||||
.base0F-background { background-color: #69542d; }
|
||||
|
||||
.base00 { color: #f2f4f6; }
|
||||
.base01 { color: #dde2e6; }
|
||||
.base02 { color: #c0c6cb; }
|
||||
.base03 { color: #a4a4a4; }
|
||||
.base04 { color: #545454; }
|
||||
.base05 { color: #304055; }
|
||||
.base06 { color: #040404; }
|
||||
.base07 { color: #000000; }
|
||||
.base08 { color: #e46f0f; }
|
||||
.base09 { color: #e09448; }
|
||||
.base0A { color: #dddd13; }
|
||||
.base0B { color: #0ed839; }
|
||||
.base0C { color: #23edda; }
|
||||
.base0D { color: #3b48e3; }
|
||||
.base0E { color: #f996e2; }
|
||||
.base0F { color: #69542d; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #000000; }
|
||||
.base01-background { background-color: #202020; }
|
||||
.base02-background { background-color: #303030; }
|
||||
.base03-background { background-color: #505050; }
|
||||
.base04-background { background-color: #b0b0b0; }
|
||||
.base05-background { background-color: #d0d0d0; }
|
||||
.base06-background { background-color: #e0e0e0; }
|
||||
.base07-background { background-color: #ffffff; }
|
||||
.base08-background { background-color: #eb008a; }
|
||||
.base09-background { background-color: #f29333; }
|
||||
.base0A-background { background-color: #f8ca12; }
|
||||
.base0B-background { background-color: #37b349; }
|
||||
.base0C-background { background-color: #00aabb; }
|
||||
.base0D-background { background-color: #0e5a94; }
|
||||
.base0E-background { background-color: #b31e8d; }
|
||||
.base0F-background { background-color: #7a2d00; }
|
||||
|
||||
.base00 { color: #000000; }
|
||||
.base01 { color: #202020; }
|
||||
.base02 { color: #303030; }
|
||||
.base03 { color: #505050; }
|
||||
.base04 { color: #b0b0b0; }
|
||||
.base05 { color: #d0d0d0; }
|
||||
.base06 { color: #e0e0e0; }
|
||||
.base07 { color: #ffffff; }
|
||||
.base08 { color: #eb008a; }
|
||||
.base09 { color: #f29333; }
|
||||
.base0A { color: #f8ca12; }
|
||||
.base0B { color: #37b349; }
|
||||
.base0C { color: #00aabb; }
|
||||
.base0D { color: #0e5a94; }
|
||||
.base0E { color: #b31e8d; }
|
||||
.base0F { color: #7a2d00; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #2b2b2b; }
|
||||
.base01-background { background-color: #272935; }
|
||||
.base02-background { background-color: #3a4055; }
|
||||
.base03-background { background-color: #5a647e; }
|
||||
.base04-background { background-color: #d4cfc9; }
|
||||
.base05-background { background-color: #e6e1dc; }
|
||||
.base06-background { background-color: #f4f1ed; }
|
||||
.base07-background { background-color: #f9f7f3; }
|
||||
.base08-background { background-color: #da4939; }
|
||||
.base09-background { background-color: #cc7833; }
|
||||
.base0A-background { background-color: #ffc66d; }
|
||||
.base0B-background { background-color: #a5c261; }
|
||||
.base0C-background { background-color: #519f50; }
|
||||
.base0D-background { background-color: #6d9cbe; }
|
||||
.base0E-background { background-color: #b6b3eb; }
|
||||
.base0F-background { background-color: #bc9458; }
|
||||
|
||||
.base00 { color: #2b2b2b; }
|
||||
.base01 { color: #272935; }
|
||||
.base02 { color: #3a4055; }
|
||||
.base03 { color: #5a647e; }
|
||||
.base04 { color: #d4cfc9; }
|
||||
.base05 { color: #e6e1dc; }
|
||||
.base06 { color: #f4f1ed; }
|
||||
.base07 { color: #f9f7f3; }
|
||||
.base08 { color: #da4939; }
|
||||
.base09 { color: #cc7833; }
|
||||
.base0A { color: #ffc66d; }
|
||||
.base0B { color: #a5c261; }
|
||||
.base0C { color: #519f50; }
|
||||
.base0D { color: #6d9cbe; }
|
||||
.base0E { color: #b6b3eb; }
|
||||
.base0F { color: #bc9458; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #151718; }
|
||||
.base01-background { background-color: #8ec43d; }
|
||||
.base02-background { background-color: #3B758C; }
|
||||
.base03-background { background-color: #41535B; }
|
||||
.base04-background { background-color: #43a5d5; }
|
||||
.base05-background { background-color: #d6d6d6; }
|
||||
.base06-background { background-color: #eeeeee; }
|
||||
.base07-background { background-color: #ffffff; }
|
||||
.base08-background { background-color: #Cd3f45; }
|
||||
.base09-background { background-color: #db7b55; }
|
||||
.base0A-background { background-color: #e6cd69; }
|
||||
.base0B-background { background-color: #9fca56; }
|
||||
.base0C-background { background-color: #55dbbe; }
|
||||
.base0D-background { background-color: #55b5db; }
|
||||
.base0E-background { background-color: #a074c4; }
|
||||
.base0F-background { background-color: #8a553f; }
|
||||
|
||||
.base00 { color: #151718; }
|
||||
.base01 { color: #8ec43d; }
|
||||
.base02 { color: #3B758C; }
|
||||
.base03 { color: #41535B; }
|
||||
.base04 { color: #43a5d5; }
|
||||
.base05 { color: #d6d6d6; }
|
||||
.base06 { color: #eeeeee; }
|
||||
.base07 { color: #ffffff; }
|
||||
.base08 { color: #Cd3f45; }
|
||||
.base09 { color: #db7b55; }
|
||||
.base0A { color: #e6cd69; }
|
||||
.base0B { color: #9fca56; }
|
||||
.base0C { color: #55dbbe; }
|
||||
.base0D { color: #55b5db; }
|
||||
.base0E { color: #a074c4; }
|
||||
.base0F { color: #8a553f; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #f9f9f9; }
|
||||
.base01-background { background-color: #e0e0e0; }
|
||||
.base02-background { background-color: #ababab; }
|
||||
.base03-background { background-color: #555555; }
|
||||
.base04-background { background-color: #343434; }
|
||||
.base05-background { background-color: #102015; }
|
||||
.base06-background { background-color: #040404; }
|
||||
.base07-background { background-color: #000000; }
|
||||
.base08-background { background-color: #e92f2f; }
|
||||
.base09-background { background-color: #e09448; }
|
||||
.base0A-background { background-color: #dddd13; }
|
||||
.base0B-background { background-color: #0ed839; }
|
||||
.base0C-background { background-color: #23edda; }
|
||||
.base0D-background { background-color: #3b48e3; }
|
||||
.base0E-background { background-color: #f996e2; }
|
||||
.base0F-background { background-color: #69542d; }
|
||||
|
||||
.base00 { color: #f9f9f9; }
|
||||
.base01 { color: #e0e0e0; }
|
||||
.base02 { color: #ababab; }
|
||||
.base03 { color: #555555; }
|
||||
.base04 { color: #343434; }
|
||||
.base05 { color: #102015; }
|
||||
.base06 { color: #040404; }
|
||||
.base07 { color: #000000; }
|
||||
.base08 { color: #e92f2f; }
|
||||
.base09 { color: #e09448; }
|
||||
.base0A { color: #dddd13; }
|
||||
.base0B { color: #0ed839; }
|
||||
.base0C { color: #23edda; }
|
||||
.base0D { color: #3b48e3; }
|
||||
.base0E { color: #f996e2; }
|
||||
.base0F { color: #69542d; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #18262F; }
|
||||
.base01-background { background-color: #222E38; }
|
||||
.base02-background { background-color: #586875; }
|
||||
.base03-background { background-color: #667581; }
|
||||
.base04-background { background-color: #85939E; }
|
||||
.base05-background { background-color: #A6AFB8; }
|
||||
.base06-background { background-color: #E8E9ED; }
|
||||
.base07-background { background-color: #F5F7FA; }
|
||||
.base08-background { background-color: #EF5253; }
|
||||
.base09-background { background-color: #E66B2B; }
|
||||
.base0A-background { background-color: #E4B51C; }
|
||||
.base0B-background { background-color: #7CC844; }
|
||||
.base0C-background { background-color: #52CBB0; }
|
||||
.base0D-background { background-color: #33B5E1; }
|
||||
.base0E-background { background-color: #A363D5; }
|
||||
.base0F-background { background-color: #D73C9A; }
|
||||
|
||||
.base00 { color: #18262F; }
|
||||
.base01 { color: #222E38; }
|
||||
.base02 { color: #586875; }
|
||||
.base03 { color: #667581; }
|
||||
.base04 { color: #85939E; }
|
||||
.base05 { color: #A6AFB8; }
|
||||
.base06 { color: #E8E9ED; }
|
||||
.base07 { color: #F5F7FA; }
|
||||
.base08 { color: #EF5253; }
|
||||
.base09 { color: #E66B2B; }
|
||||
.base0A { color: #E4B51C; }
|
||||
.base0B { color: #7CC844; }
|
||||
.base0C { color: #52CBB0; }
|
||||
.base0D { color: #33B5E1; }
|
||||
.base0E { color: #A363D5; }
|
||||
.base0F { color: #D73C9A; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #002b36; }
|
||||
.base01-background { background-color: #073642; }
|
||||
.base02-background { background-color: #586e75; }
|
||||
.base03-background { background-color: #657b83; }
|
||||
.base04-background { background-color: #839496; }
|
||||
.base05-background { background-color: #93a1a1; }
|
||||
.base06-background { background-color: #eee8d5; }
|
||||
.base07-background { background-color: #fdf6e3; }
|
||||
.base08-background { background-color: #dc322f; }
|
||||
.base09-background { background-color: #cb4b16; }
|
||||
.base0A-background { background-color: #b58900; }
|
||||
.base0B-background { background-color: #859900; }
|
||||
.base0C-background { background-color: #2aa198; }
|
||||
.base0D-background { background-color: #268bd2; }
|
||||
.base0E-background { background-color: #6c71c4; }
|
||||
.base0F-background { background-color: #d33682; }
|
||||
|
||||
.base00 { color: #002b36; }
|
||||
.base01 { color: #073642; }
|
||||
.base02 { color: #586e75; }
|
||||
.base03 { color: #657b83; }
|
||||
.base04 { color: #839496; }
|
||||
.base05 { color: #93a1a1; }
|
||||
.base06 { color: #eee8d5; }
|
||||
.base07 { color: #fdf6e3; }
|
||||
.base08 { color: #dc322f; }
|
||||
.base09 { color: #cb4b16; }
|
||||
.base0A { color: #b58900; }
|
||||
.base0B { color: #859900; }
|
||||
.base0C { color: #2aa198; }
|
||||
.base0D { color: #268bd2; }
|
||||
.base0E { color: #6c71c4; }
|
||||
.base0F { color: #d33682; }
|
@ -1,33 +0,0 @@
|
||||
.base00-background { background-color: #fdf6e3; }
|
||||
.base01-background { background-color: #eee8d5; }
|
||||
.base02-background { background-color: #93a1a1; }
|
||||
.base03-background { background-color: #839496; }
|
||||
.base04-background { background-color: #657b83; }
|
||||
.base05-background { background-color: #586e75; }
|
||||
.base06-background { background-color: #073642; }
|
||||
.base07-background { background-color: #002b36; }
|
||||
.base08-background { background-color: #dc322f; }
|
||||
.base09-background { background-color: #cb4b16; }
|
||||
.base0A-background { background-color: #b58900; }
|
||||
.base0B-background { background-color: #859900; }
|
||||
.base0C-background { background-color: #2aa198; }
|
||||
.base0D-background { background-color: #268bd2; }
|
||||
.base0E-background { background-color: #6c71c4; }
|
||||
.base0F-background { background-color: #d33682; }
|
||||
|
||||
.base00 { color: #fdf6e3; }
|
||||
.base01 { color: #eee8d5; }
|
||||
.base02 { color: #93a1a1; }
|
||||
.base03 { color: #839496; }
|
||||
.base04 { color: #657b83; }
|
||||
.base05 { color: #586e75; }
|
||||
.base06 { color: #073642; }
|
||||
.base07 { color: #002b36; }
|
||||
.base08 { color: #dc322f; }
|
||||
.base09 { color: #cb4b16; }
|
||||
.base0A { color: #b58900; }
|
||||
.base0B { color: #859900; }
|
||||
.base0C { color: #2aa198; }
|
||||
.base0D { color: #268bd2; }
|
||||
.base0E { color: #6c71c4; }
|
||||
.base0F { color: #d33682; }
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user