Page MenuHomePhorge

No OneTemporary

Size
117 KB
Referenced Files
None
Subscribers
None
diff --git a/src/App.js b/src/App.js
index 5270031915..c79184abe7 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,93 +1,96 @@
import UserPanel from './components/user_panel/user_panel.vue'
import NavPanel from './components/nav_panel/nav_panel.vue'
import Notifications from './components/notifications/notifications.vue'
import InstanceSpecificPanel from './components/instance_specific_panel/instance_specific_panel.vue'
import FeaturesPanel from './components/features_panel/features_panel.vue'
import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_panel.vue'
import ChatPanel from './components/chat_panel/chat_panel.vue'
import SettingsModal from './components/settings_modal/settings_modal.vue'
import MediaModal from './components/media_modal/media_modal.vue'
import SideDrawer from './components/side_drawer/side_drawer.vue'
import MobilePostStatusButton from './components/mobile_post_status_button/mobile_post_status_button.vue'
import MobileNav from './components/mobile_nav/mobile_nav.vue'
import DesktopNav from './components/desktop_nav/desktop_nav.vue'
import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue'
import PostStatusModal from './components/post_status_modal/post_status_modal.vue'
import GlobalNoticeList from './components/global_notice_list/global_notice_list.vue'
import { windowWidth, windowHeight } from './services/window_utils/window_utils'
export default {
name: 'app',
components: {
UserPanel,
NavPanel,
Notifications,
InstanceSpecificPanel,
FeaturesPanel,
WhoToFollowPanel,
ChatPanel,
MediaModal,
SideDrawer,
MobilePostStatusButton,
MobileNav,
DesktopNav,
SettingsModal,
UserReportingModal,
PostStatusModal,
GlobalNoticeList
},
data: () => ({
mobileActivePanel: 'timeline'
}),
created () {
// Load the locale from the storage
const val = this.$store.getters.mergedConfig.interfaceLanguage
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
window.addEventListener('resize', this.updateMobileState)
},
destroyed () {
window.removeEventListener('resize', this.updateMobileState)
},
computed: {
currentUser () { return this.$store.state.users.currentUser },
background () {
return this.currentUser.background_image || this.$store.state.instance.background
},
bgStyle () {
- return {
- 'background-image': `url(${this.background})`
- }
- },
- bgAppStyle () {
- return {
- '--body-background-image': `url(${this.background})`
+ if (
+ this.currentUser.background_image ||
+ (
+ this.$store.state.instance.background &&
+ !this.$store.getters.mergedConfig.hideInstanceWallpaper
+ )
+ ) {
+ return {
+ '--body-background-image': `url(${this.background})`
+ }
}
},
chat () { return this.$store.state.chat.channel.state === 'joined' },
suggestionsEnabled () { return this.$store.state.instance.suggestionsEnabled },
showInstanceSpecificPanel () {
return this.$store.state.instance.showInstanceSpecificPanel &&
!this.$store.getters.mergedConfig.hideISP &&
this.$store.state.instance.instanceSpecificPanelContent
},
showFeaturesPanel () { return this.$store.state.instance.showFeaturesPanel },
isMobileLayout () { return this.$store.state.interface.mobileLayout },
privateMode () { return this.$store.state.instance.private },
sidebarAlign () {
return {
'order': this.$store.state.instance.sidebarRight ? 99 : 0
}
}
},
methods: {
updateMobileState () {
const mobileLayout = windowWidth() <= 800
const layoutHeight = windowHeight()
const changed = mobileLayout !== this.isMobileLayout
if (changed) {
this.$store.dispatch('setMobileLayout', mobileLayout)
}
this.$store.dispatch('setLayoutHeight', layoutHeight)
}
}
}
diff --git a/src/App.scss b/src/App.scss
index cdc3209c91..394d643416 100644
--- a/src/App.scss
+++ b/src/App.scss
@@ -1,896 +1,898 @@
@import './_variables.scss';
#app {
min-height: 100vh;
max-width: 100%;
overflow: hidden;
}
.app-bg-wrapper {
position: fixed;
z-index: -1;
height: 100%;
left: 0;
right: -20px;
background-size: cover;
background-repeat: no-repeat;
- background-position: 0 50%;
+ background-color: var(--wallpaper);
+ background-image: var(--body-background-image);
+ background-position: 50% 50px;
}
i[class^='icon-'] {
user-select: none;
}
h4 {
margin: 0;
}
#content {
box-sizing: border-box;
padding-top: 60px;
margin: auto;
min-height: 100vh;
max-width: 980px;
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;
}
html {
font-size: 14px;
}
body {
overscroll-behavior-y: none;
font-family: sans-serif;
font-family: var(--interfaceFont, sans-serif);
margin: 0;
color: $fallback--text;
color: var(--text, $fallback--text);
max-width: 100vw;
overflow-x: hidden;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
&.hidden {
display: none;
}
}
a {
text-decoration: none;
color: $fallback--link;
color: var(--link, $fallback--link);
}
.button-default {
user-select: none;
color: $fallback--text;
color: var(--btnText, $fallback--text);
background-color: $fallback--fg;
background-color: var(--btn, $fallback--fg);
border: none;
border-radius: $fallback--btnRadius;
border-radius: var(--btnRadius, $fallback--btnRadius);
cursor: pointer;
box-shadow: $fallback--buttonShadow;
box-shadow: var(--buttonShadow);
font-size: 14px;
font-family: sans-serif;
font-family: var(--interfaceFont, sans-serif);
i[class*=icon-],
.svg-inline--fa {
color: $fallback--text;
color: var(--btnText, $fallback--text);
}
&::-moz-focus-inner {
border: none;
}
&:hover {
box-shadow: 0px 0px 4px rgba(255, 255, 255, 0.3);
box-shadow: var(--buttonHoverShadow);
}
&: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);
svg,
i {
color: $fallback--text;
color: var(--btnPressedText, $fallback--text);
}
}
&:disabled {
cursor: not-allowed;
color: $fallback--text;
color: var(--btnDisabledText, $fallback--text);
background-color: $fallback--fg;
background-color: var(--btnDisabled, $fallback--fg);
svg,
i {
color: $fallback--text;
color: var(--btnDisabledText, $fallback--text);
}
}
&.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);
svg,
i {
color: $fallback--text;
color: var(--btnToggledText, $fallback--text);
}
}
&.danger {
// TODO: add better color variable
color: $fallback--text;
color: var(--alertErrorPanelText, $fallback--text);
background-color: $fallback--alertError;
background-color: var(--alertError, $fallback--alertError);
}
}
.button-unstyled {
background: none;
border: none;
outline: none;
display: inline;
text-align: initial;
font-size: 100%;
font-family: inherit;
padding: 0;
line-height: unset;
cursor: pointer;
box-sizing: content-box;
color: inherit;
&.-link {
color: $fallback--link;
color: var(--link, $fallback--link);
}
&.-fullwidth {
width: 100%;
}
}
input, textarea, .select, .input {
&.unstyled {
border-radius: 0;
background: none;
box-shadow: none;
height: unset;
}
border: none;
border-radius: $fallback--inputRadius;
border-radius: var(--inputRadius, $fallback--inputRadius);
box-shadow: 0px 1px 0px 0px rgba(0, 0, 0, 0.2) inset, 0px -1px 0px 0px rgba(255, 255, 255, 0.2) inset, 0px 0px 2px 0px rgba(0, 0, 0, 1) inset;
box-shadow: var(--inputShadow);
background-color: $fallback--fg;
background-color: var(--input, $fallback--fg);
color: $fallback--lightText;
color: var(--inputText, $fallback--lightText);
font-family: sans-serif;
font-family: var(--inputFont, sans-serif);
font-size: 14px;
margin: 0;
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;
opacity: 0.5;
}
.select-down-icon {
position: absolute;
top: 0;
bottom: 0;
right: 5px;
height: 100%;
color: $fallback--text;
color: var(--inputText, $fallback--text);
line-height: 28px;
z-index: 0;
pointer-events: none;
}
select {
-webkit-appearance: none;
-moz-appearance: none;
appearance: none;
background: transparent;
border: none;
color: $fallback--text;
color: var(--inputText, --text, $fallback--text);
margin: 0;
padding: 0 2em 0 .2em;
font-family: sans-serif;
font-family: var(--inputFont, sans-serif);
font-size: 14px;
width: 100%;
z-index: 1;
height: 28px;
line-height: 16px;
}
&[type=range] {
background: none;
border: none;
margin: 0;
box-shadow: none;
flex: 1;
}
&[type=radio] {
display: none;
&: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(--accent, $fallback--link);
}
&:disabled {
&,
& + label,
& + label::before {
opacity: .5;
}
}
+ label::before {
flex-shrink: 0;
display: inline-block;
content: '';
transition: box-shadow 200ms;
width: 1.1em;
height: 1.1em;
border-radius: 100%; // Radio buttons should always be circle
box-shadow: 0px 0px 2px black inset;
box-shadow: var(--inputShadow);
margin-right: .5em;
background-color: $fallback--fg;
background-color: var(--input, $fallback--fg);
vertical-align: top;
text-align: center;
line-height: 1.1em;
font-size: 1.1em;
box-sizing: border-box;
color: transparent;
overflow: hidden;
box-sizing: border-box;
}
}
&[type=checkbox] {
display: none;
&:checked + label::before {
color: $fallback--text;
color: var(--inputText, $fallback--text);
}
&:disabled {
&,
& + label,
& + label::before {
opacity: .5;
}
}
+ label::before {
flex-shrink: 0;
display: inline-block;
content: '✓';
transition: color 200ms;
width: 1.1em;
height: 1.1em;
border-radius: $fallback--checkboxRadius;
border-radius: var(--checkboxRadius, $fallback--checkboxRadius);
box-shadow: 0px 0px 2px black inset;
box-shadow: var(--inputShadow);
margin-right: .5em;
background-color: $fallback--fg;
background-color: var(--input, $fallback--fg);
vertical-align: top;
text-align: center;
line-height: 1.1em;
font-size: 1.1em;
box-sizing: border-box;
color: transparent;
overflow: hidden;
box-sizing: border-box;
}
}
}
option {
color: $fallback--text;
color: var(--text, $fallback--text);
background-color: $fallback--bg;
background-color: var(--bg, $fallback--bg);
}
.hide-number-spinner {
-moz-appearance: textfield;
&[type=number]::-webkit-inner-spin-button,
&[type=number]::-webkit-outer-spin-button {
opacity: 0;
display: none;
}
}
i[class*=icon-], .svg-inline--fa {
color: $fallback--icon;
color: var(--icon, $fallback--icon);
}
.btn-block {
display: block;
width: 100%;
}
.btn-group {
position: relative;
display: inline-flex;
vertical-align: middle;
button {
position: relative;
flex: 1 1 auto;
&:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
}
.container {
display: flex;
flex-wrap: wrap;
margin: 0;
padding: 0 10px 0 10px;
}
.auto-size {
flex: 1
}
main-router {
flex: 1;
}
.status.compact {
color: rgba(0, 0, 0, 0.42);
font-weight: 300;
p {
margin: 0;
font-size: 0.8em
}
}
/* Panel */
.panel {
display: flex;
position: relative;
flex-direction: column;
margin: 0.5em;
background-color: $fallback--bg;
background-color: var(--bg, $fallback--bg);
&::after, & {
border-radius: $fallback--panelRadius;
border-radius: var(--panelRadius, $fallback--panelRadius);
}
&::after {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
pointer-events: none;
box-shadow: 1px 1px 4px rgba(0,0,0,.6);
box-shadow: var(--panelShadow);
}
}
.panel-body:empty::before {
content: "¯\\_(ツ)_/¯"; // Could use words but it'd require translations
display: block;
margin: 1em;
text-align: center;
}
.panel-heading {
display: flex;
flex: none;
border-radius: $fallback--panelRadius $fallback--panelRadius 0 0;
border-radius: var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius) 0 0;
background-size: cover;
padding: .6em .6em;
text-align: left;
line-height: 28px;
color: var(--panelText);
background-color: $fallback--fg;
background-color: var(--panel, $fallback--fg);
align-items: baseline;
box-shadow: var(--panelHeaderShadow);
.title {
flex: 1 0 auto;
font-size: 1.3em;
}
.faint {
background-color: transparent;
color: $fallback--faint;
color: var(--panelFaint, $fallback--faint);
}
.faint-link {
color: $fallback--faint;
color: var(--faintLink, $fallback--faint);
}
.alert {
white-space: nowrap;
text-overflow: ellipsis;
overflow-x: hidden;
}
.button-default,
.alert {
// height: 100%;
line-height: 21px;
min-height: 0;
box-sizing: border-box;
margin: 0;
margin-left: .5em;
min-width: 1px;
align-self: stretch;
}
.button-default {
flex-shrink: 0;
&,
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,
.-link {
color: $fallback--link;
color: var(--panelLink, $fallback--link)
}
}
.panel-heading.stub {
border-radius: $fallback--panelRadius;
border-radius: var(--panelRadius, $fallback--panelRadius);
}
.panel-footer {
border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
.faint {
color: $fallback--faint;
color: var(--panelFaint, $fallback--faint);
}
a,
.-link {
color: $fallback--link;
color: var(--panelLink, $fallback--link);
}
}
.panel-body > p {
line-height: 18px;
padding: 1em;
margin: 0;
}
.container > * {
min-width: 0px;
}
.fa {
color: grey;
}
nav {
z-index: 1000;
color: var(--topBarText);
background-color: $fallback--fg;
background-color: var(--topBar, $fallback--fg);
color: $fallback--faint;
color: var(--faint, $fallback--faint);
box-shadow: 0px 0px 4px rgba(0,0,0,.6);
box-shadow: var(--topBarShadow);
}
.fade-enter-active, .fade-leave-active {
transition: opacity .2s
}
.fade-enter, .fade-leave-active {
opacity: 0
}
.main {
flex-basis: 50%;
flex-grow: 1;
flex-shrink: 1;
}
.sidebar-bounds {
flex: 0;
flex-basis: 35%;
}
.sidebar-flexer {
flex: 1;
flex-basis: 345px;
width: 365px;
}
.mobile-shown {
display: none;
}
@media all and (min-width: 800px) {
body {
overflow-y: scroll;
}
.sidebar-bounds {
overflow: hidden;
max-height: 100vh;
width: 345px;
position: fixed;
margin-top: -10px;
.sidebar-scroller {
height: 96vh;
width: 365px;
padding-top: 10px;
padding-right: 50px;
overflow-x: hidden;
overflow-y: scroll;
}
.sidebar {
width: 345px;
}
}
.sidebar-flexer {
max-height: 96vh;
flex-shrink: 0;
flex-grow: 0;
}
}
.badge {
box-sizing: border-box;
display: inline-block;
border-radius: 99px;
max-width: 10em;
min-width: 1.7em;
height: 1.3em;
padding: 0.15em 0.15em;
vertical-align: middle;
font-weight: normal;
font-style: normal;
font-size: 0.9em;
line-height: 1;
text-align: center;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
&.badge-notification {
background-color: $fallback--cRed;
background-color: var(--badgeNotification, $fallback--cRed);
color: white;
color: var(--badgeNotificationText, white);
}
}
.alert {
margin: 0.35em;
padding: 0.25em;
border-radius: $fallback--tooltipRadius;
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
min-height: 28px;
line-height: 28px;
&.error {
background-color: $fallback--alertError;
background-color: var(--alertError, $fallback--alertError);
color: $fallback--text;
color: var(--alertErrorText, $fallback--text);
.panel-heading & {
color: $fallback--text;
color: var(--alertErrorPanelText, $fallback--text);
}
}
&.warning {
background-color: $fallback--alertWarning;
background-color: var(--alertWarning, $fallback--alertWarning);
color: $fallback--text;
color: var(--alertWarningText, $fallback--text);
.panel-heading & {
color: $fallback--text;
color: var(--alertWarningPanelText, $fallback--text);
}
}
}
.faint {
color: $fallback--faint;
color: var(--faint, $fallback--faint);
}
.faint-link {
color: $fallback--faint;
color: var(--faint, $fallback--faint);
&:hover {
text-decoration: underline;
}
}
.visibility-notice {
padding: .5em;
border: 1px solid $fallback--faint;
border: 1px solid var(--faint, $fallback--faint);
border-radius: $fallback--inputRadius;
border-radius: var(--inputRadius, $fallback--inputRadius);
}
.notice-dismissible {
padding-right: 4rem;
position: relative;
.dismiss {
position: absolute;
top: 0;
right: 0;
padding: .5em;
color: inherit;
}
}
.fa-scale-110 {
&.svg-inline--fa {
font-size: 1.1em;
}
}
.fa-old-padding {
&.svg-inline--fa {
padding: 0 0.3em;
}
}
@keyframes shakeError {
0% {
transform: translateX(0);
}
15% {
transform: translateX(0.375rem);
}
30% {
transform: translateX(-0.375rem);
}
45% {
transform: translateX(0.375rem);
}
60% {
transform: translateX(-0.375rem);
}
75% {
transform: translateX(0.375rem);
}
90% {
transform: translateX(-0.375rem);
}
100% {
transform: translateX(0);
}
}
@media all and (max-width: 800px) {
.mobile-hidden {
display: none;
}
.panel-switcher {
display: flex;
}
.container {
padding: 0;
}
.panel {
margin: 0.5em 0 0.5em 0;
}
.menu-button {
display: block;
margin-right: 0.8em;
}
.main {
margin-bottom: 7em;
}
}
.select-multiple {
display: flex;
.option-list {
margin: 0;
padding-left: .5em;
}
}
.setting-list,
.option-list{
list-style-type: none;
padding-left: 2em;
li {
margin-bottom: 0.5em;
}
.suboptions {
margin-top: 0.3em
}
}
.login-hint {
text-align: center;
@media all and (min-width: 801px) {
display: none;
}
a {
display: inline-block;
padding: 1em 0px;
width: 100%;
}
}
.btn.button-default {
min-height: 28px;
}
.animate-spin {
animation: spin 2s infinite linear;
display: inline-block;
}
@keyframes spin {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(359deg);
}
}
.new-status-notification {
position:relative;
margin-top: -1px;
font-size: 1.1em;
border-width: 1px 0 0 0;
border-style: solid;
border-color: var(--border, $fallback--border);
padding: 10px;
z-index: 1;
background-color: $fallback--fg;
background-color: var(--panel, $fallback--fg);
}
.chat-layout {
// Needed for smoother chat navigation in the desktop Safari (otherwise the chat layout "jumps" as the chat opens).
overflow: hidden;
height: 100%;
// Ensures the fixed position of the mobile browser bars on scroll up / down events.
// Prevents the mobile browser bars from overlapping or hiding the message posting form.
@media all and (max-width: 800px) {
body {
height: 100%;
}
#app {
height: 100%;
overflow: hidden;
min-height: auto;
}
#app_bg_wrapper {
overflow: hidden;
}
.main {
overflow: hidden;
height: 100%;
}
#content {
padding-top: 0;
height: 100%;
overflow: visible;
}
}
}
diff --git a/src/App.vue b/src/App.vue
index b4eb052467..1a1667788d 100644
--- a/src/App.vue
+++ b/src/App.vue
@@ -1,68 +1,67 @@
<template>
<div
id="app"
- :style="bgAppStyle"
+ :style="bgStyle"
>
<div
id="app_bg_wrapper"
class="app-bg-wrapper"
- :style="bgStyle"
/>
<MobileNav v-if="isMobileLayout" />
<DesktopNav v-else />
<div class="app-bg-wrapper app-container-wrapper" />
<div
id="content"
class="container underlay"
>
<div
class="sidebar-flexer mobile-hidden"
:style="sidebarAlign"
>
<div class="sidebar-bounds">
<div class="sidebar-scroller">
<div class="sidebar">
<user-panel />
<div v-if="!isMobileLayout">
<nav-panel />
<instance-specific-panel v-if="showInstanceSpecificPanel" />
<features-panel v-if="!currentUser && showFeaturesPanel" />
<who-to-follow-panel v-if="currentUser && suggestionsEnabled" />
<notifications v-if="currentUser" />
</div>
</div>
</div>
</div>
</div>
<div class="main">
<div
v-if="!currentUser"
class="login-hint panel panel-default"
>
<router-link
:to="{ name: 'login' }"
class="panel-body"
>
{{ $t("login.hint") }}
</router-link>
</div>
<router-view />
</div>
<media-modal />
</div>
<chat-panel
v-if="currentUser && chat"
:floating="true"
class="floating-chat mobile-hidden"
/>
<MobilePostStatusButton />
<UserReportingModal />
<PostStatusModal />
<SettingsModal />
<portal-target name="modal" />
<GlobalNoticeList />
</div>
</template>
<script src="./App.js"></script>
<style lang="scss" src="./App.scss"></style>
diff --git a/src/components/desktop_nav/desktop_nav.scss b/src/components/desktop_nav/desktop_nav.scss
index 8fd8e6202e..2d46858854 100644
--- a/src/components/desktop_nav/desktop_nav.scss
+++ b/src/components/desktop_nav/desktop_nav.scss
@@ -1,113 +1,117 @@
@import '../../_variables.scss';
.DesktopNav {
height: 50px;
width: 100%;
position: fixed;
+ a {
+ color: var(--topBarLink, $fallback--link);
+ }
+
.inner-nav {
display: grid;
grid-template-rows: 50px;
grid-template-columns: 2fr auto 2fr;
grid-template-areas: "sitename logo actions";
box-sizing: border-box;
padding: 0 1.2em;
margin: auto;
max-width: 980px;
}
&.-logoLeft {
grid-template-columns: auto 2fr 2fr;
grid-template-areas: "logo sitename actions";
}
.button-default {
&, svg {
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 {
grid-area: logo;
position: relative;
transition: opacity;
transition-timing-function: ease-out;
transition-duration: 100ms;
@media all and (min-width: 800px) {
opacity: 1 !important;
}
.mask {
mask-repeat: no-repeat;
mask-position: center;
mask-size: contain;
background-color: $fallback--fg;
background-color: var(--topBarText, $fallback--fg);
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
}
img {
display: inline-block;
height: 50px;
}
}
.nav-icon {
margin-left: 0.2em;
width: 2em;
height: 100%;
text-align: center;
.svg-inline--fa {
color: $fallback--link;
color: var(--topBarLink, $fallback--link);
}
}
.sitename {
grid-area: sitename;
}
.actions {
grid-area: actions;
}
.item {
flex: 1;
line-height: 50px;
height: 50px;
overflow: hidden;
display: flex;
flex-wrap: wrap;
&.right {
justify-content: flex-end;
text-align: right;
}
}
}
diff --git a/src/components/settings_modal/tabs/general_tab.js b/src/components/settings_modal/tabs/general_tab.js
index df592a1094..029ee7a1cc 100644
--- a/src/components/settings_modal/tabs/general_tab.js
+++ b/src/components/settings_modal/tabs/general_tab.js
@@ -1,41 +1,45 @@
import Checkbox from 'src/components/checkbox/checkbox.vue'
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faChevronDown,
faGlobe
} from '@fortawesome/free-solid-svg-icons'
library.add(
faChevronDown,
faGlobe
)
const GeneralTab = {
data () {
return {
loopSilentAvailable:
// Firefox
Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') ||
// Chrome-likes
Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'webkitAudioDecodedByteCount') ||
// Future spec, still not supported in Nightly 63 as of 08/2018
Object.getOwnPropertyDescriptor(HTMLMediaElement.prototype, 'audioTracks')
}
},
components: {
Checkbox,
InterfaceLanguageSwitcher
},
computed: {
postFormats () {
return this.$store.state.instance.postFormats || []
},
instanceSpecificPanelPresent () { return this.$store.state.instance.showInstanceSpecificPanel },
+ instanceWallpaperUsed () {
+ return this.$store.state.instance.background &&
+ !this.$store.state.users.currentUser.background_image
+ },
...SharedComputedObject()
}
}
export default GeneralTab
diff --git a/src/components/settings_modal/tabs/general_tab.vue b/src/components/settings_modal/tabs/general_tab.vue
index c1d0d0ecb8..a9081793bd 100644
--- a/src/components/settings_modal/tabs/general_tab.vue
+++ b/src/components/settings_modal/tabs/general_tab.vue
@@ -1,273 +1,278 @@
<template>
<div :label="$t('settings.general')">
<div class="setting-item">
<h2>{{ $t('settings.interface') }}</h2>
<ul class="setting-list">
<li>
<interface-language-switcher />
</li>
<li v-if="instanceSpecificPanelPresent">
<Checkbox v-model="hideISP">
{{ $t('settings.hide_isp') }}
</Checkbox>
</li>
+ <li v-if="instanceWallpaperUsed">
+ <Checkbox v-model="hideInstanceWallpaper">
+ {{ $t('settings.hide_wallpaper') }}
+ </Checkbox>
+ </li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('nav.timeline') }}</h2>
<ul class="setting-list">
<li>
<Checkbox v-model="hideMutedPosts">
{{ $t('settings.hide_muted_posts') }} {{ $t('settings.instance_default', { value: hideMutedPostsLocalizedValue }) }}
</Checkbox>
</li>
<li>
<Checkbox v-model="collapseMessageWithSubject">
{{ $t('settings.collapse_subject') }} {{ $t('settings.instance_default', { value: collapseMessageWithSubjectLocalizedValue }) }}
</Checkbox>
</li>
<li>
<Checkbox v-model="streaming">
{{ $t('settings.streaming') }}
</Checkbox>
<ul
class="setting-list suboptions"
:class="[{disabled: !streaming}]"
>
<li>
<Checkbox
v-model="pauseOnUnfocused"
:disabled="!streaming"
>
{{ $t('settings.pause_on_unfocused') }}
</Checkbox>
</li>
</ul>
</li>
<li>
<Checkbox v-model="useStreamingApi">
{{ $t('settings.useStreamingApi') }}
<br>
<small>
{{ $t('settings.useStreamingApiWarning') }}
</small>
</Checkbox>
</li>
<li>
<Checkbox v-model="emojiReactionsOnTimeline">
{{ $t('settings.emoji_reactions_on_timeline') }}
</Checkbox>
</li>
<li>
<Checkbox v-model="virtualScrolling">
{{ $t('settings.virtual_scrolling') }}
</Checkbox>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('settings.composing') }}</h2>
<ul class="setting-list">
<li>
<Checkbox v-model="scopeCopy">
{{ $t('settings.scope_copy') }} {{ $t('settings.instance_default', { value: scopeCopyLocalizedValue }) }}
</Checkbox>
</li>
<li>
<Checkbox v-model="alwaysShowSubjectInput">
{{ $t('settings.subject_input_always_show') }} {{ $t('settings.instance_default', { value: alwaysShowSubjectInputLocalizedValue }) }}
</Checkbox>
</li>
<li>
<div>
{{ $t('settings.subject_line_behavior') }}
<label
for="subjectLineBehavior"
class="select"
>
<select
id="subjectLineBehavior"
v-model="subjectLineBehavior"
>
<option value="email">
{{ $t('settings.subject_line_email') }}
{{ subjectLineBehaviorDefaultValue == 'email' ? $t('settings.instance_default_simple') : '' }}
</option>
<option value="masto">
{{ $t('settings.subject_line_mastodon') }}
{{ subjectLineBehaviorDefaultValue == 'mastodon' ? $t('settings.instance_default_simple') : '' }}
</option>
<option value="noop">
{{ $t('settings.subject_line_noop') }}
{{ subjectLineBehaviorDefaultValue == 'noop' ? $t('settings.instance_default_simple') : '' }}
</option>
</select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label>
</div>
</li>
<li v-if="postFormats.length > 0">
<div>
{{ $t('settings.post_status_content_type') }}
<label
for="postContentType"
class="select"
>
<select
id="postContentType"
v-model="postContentType"
>
<option
v-for="postFormat in postFormats"
:key="postFormat"
:value="postFormat"
>
{{ $t(`post_status.content_type["${postFormat}"]`) }}
{{ postContentTypeDefaultValue === postFormat ? $t('settings.instance_default_simple') : '' }}
</option>
</select>
<FAIcon
class="select-down-icon"
icon="chevron-down"
/>
</label>
</div>
</li>
<li>
<Checkbox v-model="minimalScopesMode">
{{ $t('settings.minimal_scopes_mode') }} {{ $t('settings.instance_default', { value: minimalScopesModeLocalizedValue }) }}
</Checkbox>
</li>
<li>
<Checkbox v-model="autohideFloatingPostButton">
{{ $t('settings.autohide_floating_post_button') }}
</Checkbox>
</li>
<li>
<Checkbox v-model="padEmoji">
{{ $t('settings.pad_emoji') }}
</Checkbox>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('settings.attachments') }}</h2>
<ul class="setting-list">
<li>
<Checkbox v-model="hideAttachments">
{{ $t('settings.hide_attachments_in_tl') }}
</Checkbox>
</li>
<li>
<Checkbox v-model="hideAttachmentsInConv">
{{ $t('settings.hide_attachments_in_convo') }}
</Checkbox>
</li>
<li>
<label for="maxThumbnails">
{{ $t('settings.max_thumbnails') }}
</label>
<input
id="maxThumbnails"
v-model.number="maxThumbnails"
class="number-input"
type="number"
min="0"
step="1"
>
</li>
<li>
<Checkbox v-model="hideNsfw">
{{ $t('settings.nsfw_clickthrough') }}
</Checkbox>
</li>
<ul class="setting-list suboptions">
<li>
<Checkbox
v-model="preloadImage"
:disabled="!hideNsfw"
>
{{ $t('settings.preload_images') }}
</Checkbox>
</li>
<li>
<Checkbox
v-model="useOneClickNsfw"
:disabled="!hideNsfw"
>
{{ $t('settings.use_one_click_nsfw') }}
</Checkbox>
</li>
</ul>
<li>
<Checkbox v-model="stopGifs">
{{ $t('settings.stop_gifs') }}
</Checkbox>
</li>
<li>
<Checkbox v-model="loopVideo">
{{ $t('settings.loop_video') }}
</Checkbox>
<ul
class="setting-list suboptions"
:class="[{disabled: !streaming}]"
>
<li>
<Checkbox
v-model="loopVideoSilentOnly"
:disabled="!loopVideo || !loopSilentAvailable"
>
{{ $t('settings.loop_video_silent_only') }}
</Checkbox>
<div
v-if="!loopSilentAvailable"
class="unavailable"
>
<FAIcon icon="globe" />! {{ $t('settings.limited_availability') }}
</div>
</li>
</ul>
</li>
<li>
<Checkbox v-model="playVideosInModal">
{{ $t('settings.play_videos_in_modal') }}
</Checkbox>
</li>
<li>
<Checkbox v-model="useContainFit">
{{ $t('settings.use_contain_fit') }}
</Checkbox>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('settings.notifications') }}</h2>
<ul class="setting-list">
<li>
<Checkbox v-model="webPushNotifications">
{{ $t('settings.enable_web_push_notifications') }}
</Checkbox>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('settings.fun') }}</h2>
<ul class="setting-list">
<li>
<Checkbox v-model="greentext">
{{ $t('settings.greentext') }} {{ $t('settings.instance_default', { value: greentextLocalizedValue }) }}
</Checkbox>
</li>
</ul>
</div>
</div>
</template>
<script src="./general_tab.js"></script>
diff --git a/src/components/settings_modal/tabs/theme_tab/theme_tab.scss b/src/components/settings_modal/tabs/theme_tab/theme_tab.scss
index 926eceff57..1b7d9f3152 100644
--- a/src/components/settings_modal/tabs/theme_tab/theme_tab.scss
+++ b/src/components/settings_modal/tabs/theme_tab/theme_tab.scss
@@ -1,345 +1,346 @@
@import 'src/_variables.scss';
.theme-tab {
padding-bottom: 2em;
.theme-warning {
display: flex;
align-items: baseline;
margin-bottom: .5em;
.buttons {
.btn {
margin-bottom: .5em;
}
}
}
.preset-switcher {
margin-right: 1em;
}
.style-control {
display: flex;
align-items: baseline;
margin-bottom: 5px;
.label {
flex: 1;
}
&.disabled {
input, select {
opacity: .5
}
}
.opt {
margin: .5em;
}
.color-input {
flex: 0 0 0;
}
input, select {
min-width: 3em;
margin: 0;
flex: 0;
&[type=number] {
min-width: 5em;
}
&[type=range] {
flex: 1;
min-width: 3em;
align-self: flex-start;
}
}
}
.reset-container {
flex-wrap: wrap;
}
.fonts-container,
.reset-container,
.apply-container,
.radius-container,
.color-container,
{
display: flex;
}
.fonts-container,
.radius-container {
flex-direction: column;
}
.color-container{
> h4 {
width: 99%;
}
flex-wrap: wrap;
justify-content: space-between;
}
.fonts-container,
.color-container,
.shadow-container,
.radius-container,
.presets-container {
margin: 1em 1em 0;
}
.tab-header {
display: flex;
justify-content: space-between;
align-items: baseline;
width: 100%;
min-height: 30px;
margin-bottom: 1em;
p {
flex: 1;
margin: 0;
margin-right: .5em;
}
}
.tab-header-buttons {
display: flex;
flex-direction: column;
.btn {
min-width: 1px;
flex: 0 auto;
padding: 0 1em;
margin-bottom: .5em;
}
}
.shadow-selector {
.override {
flex: 1;
margin-left: .5em;
}
.select-container {
margin-top: -4px;
margin-bottom: -3px;
}
}
.save-load,
.save-load-options {
display: flex;
justify-content: center;
align-items: baseline;
flex-wrap: wrap;
.presets,
.import-export {
margin-bottom: .5em;
}
.import-export {
display: flex;
}
.override {
margin-left: .5em;
}
}
.save-load-options {
flex-wrap: wrap;
margin-top: .5em;
justify-content: center;
.keep-option {
margin: 0 .5em .5em;
min-width: 25%;
}
}
.preview-container {
border-top: 1px dashed;
border-bottom: 1px dashed;
border-color: $fallback--border;
border-color: var(--border, $fallback--border);
margin: 1em 0;
padding: 1em;
- background: var(--body-background-image);
+ background-color: var(--wallpaper);
+ background-image: var(--body-background-image);
background-size: cover;
background-position: 50% 50%;
.dummy {
.post {
font-family: var(--postFont);
display: flex;
.content {
flex: 1;
h4 {
margin-bottom: .25em;
}
.icons {
margin-top: .5em;
display: flex;
i {
margin-right: 1em;
}
}
}
}
.after-post {
margin-top: 1em;
display: flex;
align-items: center;
}
.avatar, .avatar-alt{
background: linear-gradient(135deg, #b8e1fc 0%,#a9d2f3 10%,#90bae4 25%,#90bcea 37%,#90bff0 50%,#6ba8e5 51%,#a2daf5 83%,#bdf3fd 100%);
color: black;
font-family: sans-serif;
text-align: center;
margin-right: 1em;
}
.avatar-alt {
flex: 0 auto;
margin-left: 28px;
font-size: 12px;
min-width: 20px;
min-height: 20px;
line-height: 20px;
border-radius: $fallback--avatarAltRadius;
border-radius: var(--avatarAltRadius, $fallback--avatarAltRadius);
}
.avatar {
flex: 0 auto;
width: 48px;
height: 48px;
font-size: 14px;
line-height: 48px;
}
.actions {
display: flex;
align-items: baseline;
.checkbox {
display: inline-flex;
align-items: baseline;
margin-right: 1em;
flex: 1;
}
}
.separator {
margin: 1em;
border-bottom: 1px solid;
border-color: $fallback--border;
border-color: var(--border, $fallback--border);
}
.panel-heading {
.badge, .alert, .btn, .faint {
margin-left: 1em;
white-space: nowrap;
}
.faint {
text-overflow: ellipsis;
min-width: 2em;
overflow-x: hidden;
}
.flex-spacer {
flex: 1;
}
}
.btn {
margin-left: 0;
padding: 0 1em;
min-width: 3em;
min-height: 30px;
}
}
}
.apply-container {
justify-content: center;
}
.radius-item,
.color-item {
min-width: 20em;
margin: 5px 6px 0 0;
display:flex;
flex-direction: column;
flex: 1 1 0;
&.wide {
min-width: 60%
}
&:not(.wide):nth-child(2n+1) {
margin-right: 7px;
}
.color, .opacity {
display:flex;
align-items: baseline;
}
}
.radius-item {
flex-basis: auto;
}
.theme-radius-rn,
.theme-color-cl {
border: 0;
box-shadow: none;
background: transparent;
color: var(--faint, $fallback--faint);
align-self: stretch;
}
.theme-color-cl,
.theme-radius-in,
.theme-color-in {
margin-left: 4px;
}
.theme-radius-in {
min-width: 1em;
}
.theme-radius-in {
max-width: 7em;
flex: 1;
}
.theme-radius-lb{
max-width: 50em;
}
.theme-preview-content {
padding: 20px;
}
.apply-container {
.btn {
min-height: 28px;
min-width: 10em;
padding: 0 2em;
}
}
.btn {
margin-left: .25em;
margin-right: .25em;
}
}
diff --git a/src/i18n/en.json b/src/i18n/en.json
index ef23efd60c..7c8bfec250 100644
--- a/src/i18n/en.json
+++ b/src/i18n/en.json
@@ -1,813 +1,814 @@
{
"about": {
"mrf": {
"federation": "Federation",
"keyword": {
"keyword_policies": "Keyword Policies",
"ftl_removal": "Removal from \"The Whole Known Network\" Timeline",
"reject": "Reject",
"replace": "Replace",
"is_replaced_by": "→"
},
"mrf_policies": "Enabled MRF Policies",
"mrf_policies_desc": "MRF policies manipulate the federation behaviour of the instance. The following policies are enabled:",
"simple": {
"simple_policies": "Instance-specific Policies",
"accept": "Accept",
"accept_desc": "This instance only accepts messages from the following instances:",
"reject": "Reject",
"reject_desc": "This instance will not accept messages from the following instances:",
"quarantine": "Quarantine",
"quarantine_desc": "This instance will send only public posts to the following instances:",
"ftl_removal": "Removal from \"The Whole Known Network\" Timeline",
"ftl_removal_desc": "This instance removes these instances from \"The Whole Known Network\" timeline:",
"media_removal": "Media Removal",
"media_removal_desc": "This instance removes media from posts on the following instances:",
"media_nsfw": "Media Force-set As Sensitive",
"media_nsfw_desc": "This instance forces media to be set sensitive in posts on the following instances:"
}
},
"staff": "Staff"
},
"shoutbox": {
"title": "Shoutbox"
},
"domain_mute_card": {
"mute": "Mute",
"mute_progress": "Muting…",
"unmute": "Unmute",
"unmute_progress": "Unmuting…"
},
"exporter": {
"export": "Export",
"processing": "Processing, you'll soon be asked to download your file"
},
"features_panel": {
"chat": "Chat",
"pleroma_chat_messages": "Pleroma Chat",
"gopher": "Gopher",
"media_proxy": "Media proxy",
"scope_options": "Scope options",
"text_limit": "Text limit",
"title": "Features",
"who_to_follow": "Who to follow"
},
"finder": {
"error_fetching_user": "Error fetching user",
"find_user": "Find user"
},
"general": {
"apply": "Apply",
"submit": "Submit",
"more": "More",
"loading": "Loading…",
"generic_error": "An error occured",
"error_retry": "Please try again",
"retry": "Try again",
"optional": "optional",
"show_more": "Show more",
"show_less": "Show less",
"dismiss": "Dismiss",
"cancel": "Cancel",
"disable": "Disable",
"enable": "Enable",
"confirm": "Confirm",
"verify": "Verify",
"close": "Close",
"peek": "Peek"
},
"image_cropper": {
"crop_picture": "Crop picture",
"save": "Save",
"save_without_cropping": "Save without cropping",
"cancel": "Cancel"
},
"importer": {
"submit": "Submit",
"success": "Imported successfully.",
"error": "An error occured while importing this file."
},
"login": {
"login": "Log in",
"description": "Log in with OAuth",
"logout": "Log out",
"password": "Password",
"placeholder": "e.g. lain",
"register": "Register",
"username": "Username",
"hint": "Log in to join the discussion",
"authentication_code": "Authentication code",
"enter_recovery_code": "Enter a recovery code",
"enter_two_factor_code": "Enter a two-factor code",
"recovery_code": "Recovery code",
"heading": {
"totp": "Two-factor authentication",
"recovery": "Two-factor recovery"
}
},
"media_modal": {
"previous": "Previous",
"next": "Next"
},
"nav": {
"about": "About",
"administration": "Administration",
"back": "Back",
"friend_requests": "Follow Requests",
"mentions": "Mentions",
"interactions": "Interactions",
"dms": "Direct Messages",
"public_tl": "Public Timeline",
"timeline": "Timeline",
"twkn": "Known Network",
"bookmarks": "Bookmarks",
"user_search": "User Search",
"search": "Search",
"who_to_follow": "Who to follow",
"preferences": "Preferences",
"timelines": "Timelines",
"chats": "Chats"
},
"notifications": {
"broken_favorite": "Unknown status, searching for it…",
"error": "Error fetching notifications: {0}",
"favorited_you": "favorited your status",
"followed_you": "followed you",
"follow_request": "wants to follow you",
"load_older": "Load older notifications",
"notifications": "Notifications",
"read": "Read!",
"repeated_you": "repeated your status",
"no_more_notifications": "No more notifications",
"migrated_to": "migrated to",
"reacted_with": "reacted with {0}"
},
"polls": {
"add_poll": "Add Poll",
"add_option": "Add Option",
"option": "Option",
"votes": "votes",
"vote": "Vote",
"type": "Poll type",
"single_choice": "Single choice",
"multiple_choices": "Multiple choices",
"expiry": "Poll age",
"expires_in": "Poll ends in {0}",
"expired": "Poll ended {0} ago",
"not_enough_options": "Too few unique options in poll"
},
"emoji": {
"stickers": "Stickers",
"emoji": "Emoji",
"keep_open": "Keep picker open",
"search_emoji": "Search for an emoji",
"add_emoji": "Insert emoji",
"custom": "Custom emoji",
"unicode": "Unicode emoji",
"load_all_hint": "Loaded first {saneAmount} emoji, loading all emoji may cause performance issues.",
"load_all": "Loading all {emojiAmount} emoji"
},
"errors": {
"storage_unavailable": "Pleroma could not access browser storage. Your login or your local settings won't be saved and you might encounter unexpected issues. Try enabling cookies."
},
"interactions": {
"favs_repeats": "Repeats and Favorites",
"follows": "New follows",
"moves": "User migrates",
"load_older": "Load older interactions"
},
"post_status": {
"new_status": "Post new status",
"account_not_locked_warning": "Your account is not {0}. Anyone can follow you to view your follower-only posts.",
"account_not_locked_warning_link": "locked",
"attachments_sensitive": "Mark attachments as sensitive",
"media_description": "Media description",
"content_type": {
"text/plain": "Plain text",
"text/html": "HTML",
"text/markdown": "Markdown",
"text/bbcode": "BBCode"
},
"content_warning": "Subject (optional)",
"default": "Just landed in L.A.",
"direct_warning_to_all": "This post will be visible to all the mentioned users.",
"direct_warning_to_first_only": "This post will only be visible to the mentioned users at the beginning of the message.",
"posting": "Posting",
"preview": "Preview",
"preview_empty": "Empty",
"empty_status_error": "Can't post an empty status with no files",
"media_description_error": "Failed to update media, try again",
"scope_notice": {
"public": "This post will be visible to everyone",
"private": "This post will be visible to your followers only",
"unlisted": "This post will not be visible in Public Timeline and The Whole Known Network"
},
"scope": {
"direct": "Direct - Post to mentioned users only",
"private": "Followers-only - Post to followers only",
"public": "Public - Post to public timelines",
"unlisted": "Unlisted - Do not post to public timelines"
}
},
"registration": {
"bio": "Bio",
"email": "Email",
"fullname": "Display name",
"password_confirm": "Password confirmation",
"registration": "Registration",
"token": "Invite token",
"captcha": "CAPTCHA",
"new_captcha": "Click the image to get a new captcha",
"username_placeholder": "e.g. lain",
"fullname_placeholder": "e.g. Lain Iwakura",
"bio_placeholder": "e.g.\nHi, I'm Lain.\nI’m an anime girl living in suburban Japan. You may know me from the Wired.",
"validations": {
"username_required": "cannot be left blank",
"fullname_required": "cannot be left blank",
"email_required": "cannot be left blank",
"password_required": "cannot be left blank",
"password_confirmation_required": "cannot be left blank",
"password_confirmation_match": "should be the same as password"
}
},
"remote_user_resolver": {
"remote_user_resolver": "Remote user resolver",
"searching_for": "Searching for",
"error": "Not found."
},
"selectable_list": {
"select_all": "Select all"
},
"settings": {
"app_name": "App name",
"security": "Security",
"enter_current_password_to_confirm": "Enter your current password to confirm your identity",
"mfa": {
"otp": "OTP",
"setup_otp": "Setup OTP",
"wait_pre_setup_otp": "presetting OTP",
"confirm_and_enable": "Confirm & enable OTP",
"title": "Two-factor Authentication",
"generate_new_recovery_codes": "Generate new recovery codes",
"warning_of_generate_new_codes": "When you generate new recovery codes, your old codes won’t work anymore.",
"recovery_codes": "Recovery codes.",
"waiting_a_recovery_codes": "Receiving backup codes…",
"recovery_codes_warning": "Write the codes down or save them somewhere secure - otherwise you won't see them again. If you lose access to your 2FA app and recovery codes you'll be locked out of your account.",
"authentication_methods": "Authentication methods",
"scan": {
"title": "Scan",
"desc": "Using your two-factor app, scan this QR code or enter text key:",
"secret_code": "Key"
},
"verify": {
"desc": "To enable two-factor authentication, enter the code from your two-factor app:"
}
},
"allow_following_move": "Allow auto-follow when following account moves",
"attachmentRadius": "Attachments",
"attachments": "Attachments",
"avatar": "Avatar",
"avatarAltRadius": "Avatars (Notifications)",
"avatarRadius": "Avatars",
"background": "Background",
"bio": "Bio",
"block_export": "Block export",
"block_export_button": "Export your blocks to a csv file",
"block_import": "Block import",
"block_import_error": "Error importing blocks",
"blocks_imported": "Blocks imported! Processing them will take a while.",
"mute_export": "Mute export",
"mute_export_button": "Export your mutes to a csv file",
"mute_import": "Mute import",
"mute_import_error": "Error importing mutes",
"mutes_imported": "Mutes imported! Processing them will take a while.",
"import_mutes_from_a_csv_file": "Import mutes from a csv file",
"blocks_tab": "Blocks",
"bot": "This is a bot account",
"btnRadius": "Buttons",
"cBlue": "Blue (Reply, follow)",
"cGreen": "Green (Retweet)",
"cOrange": "Orange (Favorite)",
"cRed": "Red (Cancel)",
"change_email": "Change Email",
"change_email_error": "There was an issue changing your email.",
"changed_email": "Email changed successfully!",
"change_password": "Change Password",
"change_password_error": "There was an issue changing your password.",
"changed_password": "Password changed successfully!",
"chatMessageRadius": "Chat message",
"collapse_subject": "Collapse posts with subjects",
"composing": "Composing",
"confirm_new_password": "Confirm new password",
"current_password": "Current password",
"mutes_and_blocks": "Mutes and Blocks",
"data_import_export_tab": "Data Import / Export",
"default_vis": "Default visibility scope",
"delete_account": "Delete Account",
"delete_account_description": "Permanently delete your data and deactivate your account.",
"delete_account_error": "There was an issue deleting your account. If this persists please contact your instance administrator.",
"delete_account_instructions": "Type your password in the input below to confirm account deletion.",
"discoverable": "Allow discovery of this account in search results and other services",
"domain_mutes": "Domains",
"avatar_size_instruction": "The recommended minimum size for avatar images is 150x150 pixels.",
"pad_emoji": "Pad emoji with spaces when adding from picker",
"emoji_reactions_on_timeline": "Show emoji reactions on timeline",
"export_theme": "Save preset",
"filtering": "Filtering",
"filtering_explanation": "All statuses containing these words will be muted, one per line",
"follow_export": "Follow export",
"follow_export_button": "Export your follows to a csv file",
"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",
"hide_attachments_in_tl": "Hide attachments in timeline",
"hide_muted_posts": "Hide posts of muted users",
"max_thumbnails": "Maximum amount of thumbnails per post",
"hide_isp": "Hide instance-specific panel",
+ "hide_wallpaper": "Hide instance wallpaper",
"preload_images": "Preload images",
"use_one_click_nsfw": "Open NSFW attachments with just one click",
"hide_post_stats": "Hide post statistics (e.g. the number of favorites)",
"hide_user_stats": "Hide user statistics (e.g. the number of followers)",
"hide_filtered_statuses": "Hide filtered statuses",
"import_blocks_from_a_csv_file": "Import blocks from a csv file",
"import_followers_from_a_csv_file": "Import follows from a csv file",
"import_theme": "Load preset",
"inputRadius": "Input fields",
"checkboxRadius": "Checkboxes",
"instance_default": "(default: {value})",
"instance_default_simple": "(default)",
"interface": "Interface",
"interfaceLanguage": "Interface language",
"invalid_theme_imported": "The selected file is not a supported Pleroma theme. No changes to your theme were made.",
"limited_availability": "Unavailable in your browser",
"links": "Links",
"lock_account_description": "Restrict your account to approved followers only",
"loop_video": "Loop videos",
"loop_video_silent_only": "Loop only videos without sound (i.e. Mastodon's \"gifs\")",
"mutes_tab": "Mutes",
"play_videos_in_modal": "Play videos in a popup frame",
"profile_fields": {
"label": "Profile metadata",
"add_field": "Add Field",
"name": "Label",
"value": "Content"
},
"use_contain_fit": "Don't crop the attachment in thumbnails",
"name": "Name",
"name_bio": "Name & Bio",
"new_email": "New Email",
"new_password": "New password",
"notification_visibility": "Types of notifications to show",
"notification_visibility_follows": "Follows",
"notification_visibility_likes": "Likes",
"notification_visibility_mentions": "Mentions",
"notification_visibility_repeats": "Repeats",
"notification_visibility_moves": "User Migrates",
"notification_visibility_emoji_reactions": "Reactions",
"no_rich_text_description": "Strip rich text formatting from all posts",
"no_blocks": "No blocks",
"no_mutes": "No mutes",
"hide_follows_description": "Don't show who I'm following",
"hide_followers_description": "Don't show who's following me",
"hide_follows_count_description": "Don't show follow count",
"hide_followers_count_description": "Don't show follower count",
"show_admin_badge": "Show Admin badge in my profile",
"show_moderator_badge": "Show Moderator badge in my profile",
"nsfw_clickthrough": "Enable clickthrough attachment and link preview image hiding for NSFW statuses",
"oauth_tokens": "OAuth tokens",
"token": "Token",
"refresh_token": "Refresh Token",
"valid_until": "Valid Until",
"revoke_token": "Revoke",
"panelRadius": "Panels",
"pause_on_unfocused": "Pause streaming when tab is not focused",
"presets": "Presets",
"profile_background": "Profile Background",
"profile_banner": "Profile Banner",
"profile_tab": "Profile",
"radii_help": "Set up interface edge rounding (in pixels)",
"replies_in_timeline": "Replies in timeline",
"reply_visibility_all": "Show all replies",
"reply_visibility_following": "Only show replies directed at me or users I'm following",
"reply_visibility_self": "Only show replies directed at me",
"autohide_floating_post_button": "Automatically hide New Post button (mobile)",
"saving_err": "Error saving settings",
"saving_ok": "Settings saved",
"search_user_to_block": "Search whom you want to block",
"search_user_to_mute": "Search whom you want to mute",
"security_tab": "Security",
"scope_copy": "Copy scope when replying (DMs are always copied)",
"minimal_scopes_mode": "Minimize post scope selection options",
"set_new_avatar": "Set new avatar",
"set_new_profile_background": "Set new profile background",
"set_new_profile_banner": "Set new profile banner",
"reset_avatar": "Reset avatar",
"reset_profile_background": "Reset profile background",
"reset_profile_banner": "Reset profile banner",
"reset_avatar_confirm": "Do you really want to reset the avatar?",
"reset_banner_confirm": "Do you really want to reset the banner?",
"reset_background_confirm": "Do you really want to reset the background?",
"settings": "Settings",
"subject_input_always_show": "Always show subject field",
"subject_line_behavior": "Copy subject when replying",
"subject_line_email": "Like email: \"re: subject\"",
"subject_line_mastodon": "Like mastodon: copy as is",
"subject_line_noop": "Do not copy",
"post_status_content_type": "Post status content type",
"stop_gifs": "Play-on-hover GIFs",
"streaming": "Enable automatic streaming of new posts when scrolled to the top",
"user_mutes": "Users",
"useStreamingApi": "Receive posts and notifications real-time",
"useStreamingApiWarning": "(Not recommended, experimental, known to skip posts)",
"text": "Text",
"theme": "Theme",
"theme_help": "Use hex color codes (#rrggbb) to customize your color theme.",
"theme_help_v2_1": "You can also override certain component's colors and opacity by toggling the checkbox, use \"Clear all\" button to clear all overrides.",
"theme_help_v2_2": "Icons underneath some entries are background/text contrast indicators, hover over for detailed info. Please keep in mind that when using transparency contrast indicators show the worst possible case.",
"tooltipRadius": "Tooltips/alerts",
"type_domains_to_mute": "Search domains to mute",
"upload_a_photo": "Upload a photo",
"user_settings": "User Settings",
"values": {
"false": "no",
"true": "yes"
},
"virtual_scrolling": "Optimize timeline rendering",
"fun": "Fun",
"greentext": "Meme arrows",
"notifications": "Notifications",
"notification_setting_filters": "Filters",
"notification_setting_block_from_strangers": "Block notifications from users who you do not follow",
"notification_setting_privacy": "Privacy",
"notification_setting_hide_notification_contents": "Hide the sender and contents of push notifications",
"notification_mutes": "To stop receiving notifications from a specific user, use a mute.",
"notification_blocks": "Blocking a user stops all notifications as well as unsubscribes them.",
"enable_web_push_notifications": "Enable web push notifications",
"style": {
"switcher": {
"keep_color": "Keep colors",
"keep_shadows": "Keep shadows",
"keep_opacity": "Keep opacity",
"keep_roundness": "Keep roundness",
"keep_fonts": "Keep fonts",
"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",
"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 inconsistencies.",
"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",
"opacity": "Opacity",
"contrast": {
"hint": "Contrast ratio is {ratio}, it {level} {context}",
"level": {
"aa": "meets Level AA guideline (minimal)",
"aaa": "meets Level AAA guideline (recommended)",
"bad": "doesn't meet any accessibility guidelines"
},
"context": {
"18pt": "for large (18pt+) text",
"text": "for text"
}
}
},
"common_colors": {
"_tab_label": "Common",
"main": "Common colors",
"foreground_hint": "See \"Advanced\" tab for more detailed control",
"rgbo": "Icons, accents, badges"
},
"advanced_colors": {
"_tab_label": "Advanced",
"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",
"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",
"chat": {
"incoming": "Incoming",
"outgoing": "Outgoing",
"border": "Border"
}
},
"radii": {
"_tab_label": "Roundness"
},
"shadows": {
"_tab_label": "Shadow and lighting",
"component": "Component",
"override": "Override",
"shadow_id": "Shadow #{value}",
"blur": "Blur",
"spread": "Spread",
"inset": "Inset",
"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.",
"avatar_inset": "Please note that combining both inset and non-inset shadows on avatars might give unexpected results with transparent avatars.",
"spread_zero": "Shadows with spread > 0 will appear as if it was set to zero",
"inset_classic": "Inset shadows will be using {0}"
},
"components": {
"panel": "Panel",
"panelHeader": "Panel header",
"topBar": "Top bar",
"avatar": "User avatar (in profile view)",
"avatarStatus": "User avatar (in post display)",
"popup": "Popups and tooltips",
"button": "Button",
"buttonHover": "Button (hover)",
"buttonPressed": "Button (pressed)",
"buttonPressedHover": "Button (pressed+hover)",
"input": "Input field"
}
},
"fonts": {
"_tab_label": "Fonts",
"help": "Select font to use for elements of UI. For \"custom\" you have to enter exact font name as it appears in system.",
"components": {
"interface": "Interface",
"input": "Input fields",
"post": "Post text",
"postCode": "Monospaced text in a post (rich text)"
},
"family": "Font name",
"size": "Size (in px)",
"weight": "Weight (boldness)",
"custom": "Custom"
},
"preview": {
"header": "Preview",
"content": "Content",
"error": "Example error",
"button": "Button",
"text": "A bunch of more {0} and {1}",
"mono": "content",
"input": "Just landed in L.A.",
"faint_link": "helpful manual",
"fine_print": "Read our {0} to learn nothing useful!",
"header_faint": "This is fine",
"checkbox": "I have skimmed over terms and conditions",
"link": "a nice lil' link"
}
},
"version": {
"title": "Version",
"backend_version": "Backend Version",
"frontend_version": "Frontend Version"
}
},
"time": {
"day": "{0} day",
"days": "{0} days",
"day_short": "{0}d",
"days_short": "{0}d",
"hour": "{0} hour",
"hours": "{0} hours",
"hour_short": "{0}h",
"hours_short": "{0}h",
"in_future": "in {0}",
"in_past": "{0} ago",
"minute": "{0} minute",
"minutes": "{0} minutes",
"minute_short": "{0}min",
"minutes_short": "{0}min",
"month": "{0} month",
"months": "{0} months",
"month_short": "{0}mo",
"months_short": "{0}mo",
"now": "just now",
"now_short": "now",
"second": "{0} second",
"seconds": "{0} seconds",
"second_short": "{0}s",
"seconds_short": "{0}s",
"week": "{0} week",
"weeks": "{0} weeks",
"week_short": "{0}w",
"weeks_short": "{0}w",
"year": "{0} year",
"years": "{0} years",
"year_short": "{0}y",
"years_short": "{0}y"
},
"timeline": {
"collapse": "Collapse",
"conversation": "Conversation",
"error": "Error fetching timeline: {0}",
"load_older": "Load older statuses",
"no_retweet_hint": "Post is marked as followers-only or direct and cannot be repeated",
"repeated": "repeated",
"show_new": "Show new",
"reload": "Reload",
"up_to_date": "Up-to-date",
"no_more_statuses": "No more statuses",
"no_statuses": "No statuses"
},
"status": {
"favorites": "Favorites",
"repeats": "Repeats",
"delete": "Delete status",
"pin": "Pin on profile",
"unpin": "Unpin from profile",
"pinned": "Pinned",
"bookmark": "Bookmark",
"unbookmark": "Unbookmark",
"delete_confirm": "Do you really want to delete this status?",
"reply_to": "Reply to",
"replies_list": "Replies:",
"mute_conversation": "Mute conversation",
"unmute_conversation": "Unmute conversation",
"status_unavailable": "Status unavailable",
"copy_link": "Copy link to status",
"thread_muted": "Thread muted",
"thread_muted_and_words": ", has words:",
"show_full_subject": "Show full subject",
"hide_full_subject": "Hide full subject",
"show_content": "Show content",
"hide_content": "Hide content",
"status_deleted": "This post was deleted",
"nsfw": "NSFW"
},
"user_card": {
"approve": "Approve",
"block": "Block",
"blocked": "Blocked!",
"deny": "Deny",
"favorites": "Favorites",
"follow": "Follow",
"follow_sent": "Request sent!",
"follow_progress": "Requesting…",
"follow_again": "Send request again?",
"follow_unfollow": "Unfollow",
"followees": "Following",
"followers": "Followers",
"following": "Following!",
"follows_you": "Follows you!",
"hidden": "Hidden",
"its_you": "It's you!",
"media": "Media",
"mention": "Mention",
"message": "Message",
"mute": "Mute",
"muted": "Muted",
"per_day": "per day",
"remote_follow": "Remote follow",
"report": "Report",
"statuses": "Statuses",
"subscribe": "Subscribe",
"unsubscribe": "Unsubscribe",
"unblock": "Unblock",
"unblock_progress": "Unblocking…",
"block_progress": "Blocking…",
"unmute": "Unmute",
"unmute_progress": "Unmuting…",
"mute_progress": "Muting…",
"hide_repeats": "Hide repeats",
"show_repeats": "Show repeats",
"admin_menu": {
"moderation": "Moderation",
"grant_admin": "Grant Admin",
"revoke_admin": "Revoke Admin",
"grant_moderator": "Grant Moderator",
"revoke_moderator": "Revoke Moderator",
"activate_account": "Activate account",
"deactivate_account": "Deactivate account",
"delete_account": "Delete account",
"force_nsfw": "Mark all posts as NSFW",
"strip_media": "Remove media from posts",
"force_unlisted": "Force posts to be unlisted",
"sandbox": "Force posts to be followers-only",
"disable_remote_subscription": "Disallow following user from remote instances",
"disable_any_subscription": "Disallow following user at all",
"quarantine": "Disallow user posts from federating",
"delete_user": "Delete user",
"delete_user_confirmation": "Are you absolutely sure? This action cannot be undone."
}
},
"user_profile": {
"timeline_title": "User Timeline",
"profile_does_not_exist": "Sorry, this profile does not exist.",
"profile_loading_error": "Sorry, there was an error loading this profile."
},
"user_reporting": {
"title": "Reporting {0}",
"add_comment_description": "The report will be sent to your instance moderators. You can provide an explanation of why you are reporting this account below:",
"additional_comments": "Additional comments",
"forward_description": "The account is from another server. Send a copy of the report there as well?",
"forward_to": "Forward to {0}",
"submit": "Submit",
"generic_error": "An error occurred while processing your request."
},
"who_to_follow": {
"more": "More",
"who_to_follow": "Who to follow"
},
"tool_tip": {
"media_upload": "Upload Media",
"repeat": "Repeat",
"reply": "Reply",
"favorite": "Favorite",
"add_reaction": "Add Reaction",
"user_settings": "User Settings",
"accept_follow_request": "Accept follow request",
"reject_follow_request": "Reject follow request",
"bookmark": "Bookmark"
},
"upload": {
"error": {
"base": "Upload failed.",
"file_too_big": "File too big [{filesize}{filesizeunit} / {allowedsize}{allowedsizeunit}]",
"default": "Try again later"
},
"file_size_units": {
"B": "B",
"KiB": "KiB",
"MiB": "MiB",
"GiB": "GiB",
"TiB": "TiB"
}
},
"search": {
"people": "People",
"hashtags": "Hashtags",
"person_talking": "{count} person talking",
"people_talking": "{count} people talking",
"no_results": "No results"
},
"password_reset": {
"forgot_password": "Forgot password?",
"password_reset": "Password reset",
"instruction": "Enter your email address or username. We will send you a link to reset your password.",
"placeholder": "Your email or username",
"check_email": "Check your email for a link to reset your password.",
"return_home": "Return to the home page",
"too_many_requests": "You have reached the limit of attempts, try again later.",
"password_reset_disabled": "Password reset is disabled. Please contact your instance administrator.",
"password_reset_required": "You must reset your password to log in.",
"password_reset_required_but_mailer_is_disabled": "You must reset your password, but password reset is disabled. Please contact your instance administrator."
},
"chats": {
"you": "You:",
"message_user": "Message {nickname}",
"delete": "Delete",
"chats": "Chats",
"new": "New Chat",
"empty_message_error": "Cannot post empty message",
"more": "More",
"delete_confirm": "Do you really want to delete this message?",
"error_loading_chat": "Something went wrong when loading the chat.",
"error_sending_message": "Something went wrong when sending the message.",
"empty_chat_list_placeholder": "You don't have any chats yet. Start a new chat!"
},
"file_type": {
"audio": "Audio",
"video": "Video",
"image": "Image",
"file": "File"
},
"display_date": {
"today": "Today"
}
}
diff --git a/src/modules/config.js b/src/modules/config.js
index 444b8ec7c3..cd088737cb 100644
--- a/src/modules/config.js
+++ b/src/modules/config.js
@@ -1,128 +1,129 @@
import { set, delete as del } from 'vue'
import { setPreset, applyTheme } from '../services/style_setter/style_setter.js'
import messages from '../i18n/messages'
const browserLocale = (window.navigator.language || 'en').split('-')[0]
/* TODO this is a bit messy.
* We need to declare settings with their types and also deal with
* instance-default settings in some way, hopefully try to avoid copy-pasta
* in general.
*/
export const multiChoiceProperties = [
'postContentType',
'subjectLineBehavior'
]
export const defaultState = {
colors: {},
theme: undefined,
customTheme: undefined,
customThemeSource: undefined,
hideISP: false,
+ hideInstanceWallpaper: false,
// bad name: actually hides posts of muted USERS
hideMutedPosts: undefined, // instance default
collapseMessageWithSubject: undefined, // instance default
padEmoji: true,
hideAttachments: false,
hideAttachmentsInConv: false,
maxThumbnails: 16,
hideNsfw: true,
preloadImage: true,
loopVideo: true,
loopVideoSilentOnly: true,
streaming: false,
emojiReactionsOnTimeline: true,
autohideFloatingPostButton: false,
pauseOnUnfocused: true,
stopGifs: false,
replyVisibility: 'all',
notificationVisibility: {
follows: true,
mentions: true,
likes: true,
repeats: true,
moves: true,
emojiReactions: false,
followRequest: true,
chatMention: true
},
webPushNotifications: false,
muteWords: [],
highlight: {},
interfaceLanguage: browserLocale,
hideScopeNotice: false,
useStreamingApi: false,
scopeCopy: undefined, // instance default
subjectLineBehavior: undefined, // instance default
alwaysShowSubjectInput: undefined, // instance default
postContentType: undefined, // instance default
minimalScopesMode: undefined, // instance default
// This hides statuses filtered via a word filter
hideFilteredStatuses: undefined, // instance default
playVideosInModal: false,
useOneClickNsfw: false,
useContainFit: false,
greentext: undefined, // instance default
hidePostStats: undefined, // instance default
hideUserStats: undefined, // instance default
virtualScrolling: undefined // instance default
}
// caching the instance default properties
export const instanceDefaultProperties = Object.entries(defaultState)
.filter(([key, value]) => value === undefined)
.map(([key, value]) => key)
const config = {
state: defaultState,
getters: {
mergedConfig (state, getters, rootState, rootGetters) {
const { instance } = rootState
return {
...state,
...instanceDefaultProperties
.map(key => [key, state[key] === undefined
? instance[key]
: state[key]
])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {})
}
}
},
mutations: {
setOption (state, { name, value }) {
set(state, name, value)
},
setHighlight (state, { user, color, type }) {
const data = this.state.config.highlight[user]
if (color || type) {
set(state.highlight, user, { color: color || data.color, type: type || data.type })
} else {
del(state.highlight, user)
}
}
},
actions: {
setHighlight ({ commit, dispatch }, { user, color, type }) {
commit('setHighlight', { user, color, type })
},
setOption ({ commit, dispatch }, { name, value }) {
commit('setOption', { name, value })
switch (name) {
case 'theme':
setPreset(value)
break
case 'customTheme':
case 'customThemeSource':
applyTheme(value)
break
case 'interfaceLanguage':
messages.setLanguage(this.getters.i18n, value)
break
}
}
}
}
export default config
diff --git a/src/services/theme_data/pleromafe.js b/src/services/theme_data/pleromafe.js
index 7ed8579757..bec1eebdfc 100644
--- a/src/services/theme_data/pleromafe.js
+++ b/src/services/theme_data/pleromafe.js
@@ -1,726 +1,730 @@
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
profileTint: null, // doesn't matter
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',
chatBg: 'underlay',
chatMessage: 'chatBg'
}
/* By default opacity slots have 1 as default opacity
* this allows redefining it to something else
*/
export const DEFAULT_OPACITY = {
profileTint: 0.5,
alert: 0.5,
input: 0.5,
faint: 0.5,
underlay: 0.15,
alertPopup: 0.95
}
/** 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
},
+ wallpaper: {
+ depends: ['bg'],
+ color: (mod, bg) => brightness(-2 * mod, bg).rgb
+ },
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',
profileBg: {
depends: ['bg'],
color: (mod, bg) => ({
r: Math.floor(bg.r * 0.53),
g: Math.floor(bg.g * 0.56),
b: Math.floor(bg.b * 0.59)
})
},
profileTint: {
depends: ['bg'],
layer: 'profileTint',
opacity: 'profileTint'
},
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'
},
postGreentext: {
depends: ['cGreen'],
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
},
alertPopupError: {
depends: ['alertError'],
opacity: 'alertPopup'
},
alertPopupErrorText: {
depends: ['alertErrorText'],
layer: 'popover',
variant: 'alertPopupError',
textColor: true
},
alertPopupWarning: {
depends: ['alertWarning'],
opacity: 'alertPopup'
},
alertPopupWarningText: {
depends: ['alertWarningText'],
layer: 'popover',
variant: 'alertPopupWarning',
textColor: true
},
alertPopupNeutral: {
depends: ['alertNeutral'],
opacity: 'alertPopup'
},
alertPopupNeutralText: {
depends: ['alertNeutralText'],
layer: 'popover',
variant: 'alertPopupNeutral',
textColor: true
},
badgeNotification: '--cRed',
badgeNotificationText: {
depends: ['text', 'badgeNotification'],
layer: 'badge',
variant: 'badgeNotification',
textColor: 'bw'
},
chatBg: {
depends: ['bg']
},
chatMessageIncomingBg: {
depends: ['chatBg']
},
chatMessageIncomingText: {
depends: ['text'],
layer: 'chatMessage',
variant: 'chatMessageIncomingBg',
textColor: true
},
chatMessageIncomingLink: {
depends: ['link'],
layer: 'chatMessage',
variant: 'chatMessageIncomingBg',
textColor: 'preserve'
},
chatMessageIncomingBorder: {
depends: ['border'],
opacity: 'border',
color: (mod, border) => brightness(2 * mod, border).rgb
},
chatMessageOutgoingBg: {
depends: ['chatMessageIncomingBg'],
color: (mod, chatMessage) => brightness(5 * mod, chatMessage).rgb
},
chatMessageOutgoingText: {
depends: ['text'],
layer: 'chatMessage',
variant: 'chatMessageOutgoingBg',
textColor: true
},
chatMessageOutgoingLink: {
depends: ['link'],
layer: 'chatMessage',
variant: 'chatMessageOutgoingBg',
textColor: 'preserve'
},
chatMessageOutgoingBorder: {
depends: ['chatMessageOutgoingBg'],
opacity: 'border',
color: (mod, border) => brightness(2 * mod, border).rgb
}
}
diff --git a/static/themes/redmond-xx-se.json b/static/themes/redmond-xx-se.json
index 24480d2c7b..b62769dbc7 100644
--- a/static/themes/redmond-xx-se.json
+++ b/static/themes/redmond-xx-se.json
@@ -1,304 +1,305 @@
{
"_pleroma_theme_version": 2,
"name": "Redmond XX SE",
"source": {
"themeEngineVersion": 3,
"shadows": {
"panel": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#000000",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#dfdfdf",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"panelHeader": [
{
"x": 0,
"y": 0,
"blur": 0,
"spread": "3",
"inset": true,
"color": "#c0c0c0",
"alpha": 1
},
{
"x": "-2200",
"y": 0,
"blur": "200",
"spread": "-2000",
"inset": true,
"color": "#1084d0",
"alpha": 1
}
],
"button": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#000000",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#dfdfdf",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"buttonHover": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#000000",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#dfdfdf",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"buttonPressed": [
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#000000",
"alpha": "1",
"inset": true
},
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#dfdfdf",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"input": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#dfdfdf",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#000000",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--input",
"alpha": "1",
"inset": true
}
]
},
"fonts": {},
"opacity": {
"input": "1",
"faint": "1"
},
"colors": {
"bg": "#c0c0c0",
+ "wallpaper": "#008080",
"text": "#000000",
"link": "#0000ff",
"accent": "#000080",
"fg": "#c0c0c0",
"panel": "#000080",
"panelFaint": "#c0c0c0",
"input": "#ffffff",
"topBar": "#000080",
"topBarLink": "#ffffff",
"btn": "#c0c0c0",
"btnToggled": "--btn",
"faint": "#3f3f3f",
"faintLink": "#404080",
"border": "#808080",
"cRed": "#FF0000",
"cBlue": "#008080",
"cGreen": "#008000",
"cOrange": "#808000",
"highlight": "--accent",
"selectedPost": "--bg,-10",
"selectedMenu": "--accent",
"selectedMenuPopover": "--accent"
},
"radii": {
"btn": "0",
"input": "0",
"checkbox": "0",
"panel": "0",
"avatar": "0",
"avatarAlt": "0",
"tooltip": "0",
"attachment": "0"
}
}
}
diff --git a/static/themes/redmond-xx.json b/static/themes/redmond-xx.json
index cf9010fe20..83b591091d 100644
--- a/static/themes/redmond-xx.json
+++ b/static/themes/redmond-xx.json
@@ -1,295 +1,296 @@
{
"_pleroma_theme_version": 2,
"name": "Redmond XX",
"source": {
"themeEngineVersion": 3,
"shadows": {
"panel": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#000000",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#dfdfdf",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"panelHeader": [
{
"x": 0,
"y": 0,
"blur": 0,
"spread": "3",
"inset": true,
"color": "#c0c0c0",
"alpha": 1
}
],
"button": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#000000",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#dfdfdf",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"buttonHover": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#000000",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#dfdfdf",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"buttonPressed": [
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#000000",
"alpha": "1",
"inset": true
},
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#dfdfdf",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"input": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#dfdfdf",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#000000",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--input",
"alpha": "1",
"inset": true
}
]
},
"fonts": {},
"opacity": {
"input": "1",
"faint": "1"
},
"colors": {
"bg": "#c0c0c0",
+ "wallpaper": "#008080",
"text": "#000000",
"link": "#0000ff",
"accent": "#000080",
"fg": "#c0c0c0",
"panel": "#000080",
"panelFaint": "#c0c0c0",
"input": "#ffffff",
"topBar": "#000080",
"topBarLink": "#ffffff",
"btn": "#c0c0c0",
"btnToggled": "--btn",
"faint": "#3f3f3f",
"faintLink": "#404080",
"border": "#808080",
"cRed": "#FF0000",
"cBlue": "#008080",
"cGreen": "#008000",
"cOrange": "#808000",
"highlight": "--accent",
"selectedPost": "--bg,-10",
"selectedMenu": "--accent",
"selectedMenuPopover": "--accent"
},
"radii": {
"btn": "0",
"input": "0",
"checkbox": "0",
"panel": "0",
"avatar": "0",
"avatarAlt": "0",
"tooltip": "0",
"attachment": "0"
}
}
}
diff --git a/static/themes/redmond-xxi.json b/static/themes/redmond-xxi.json
index 7fdc4a6d65..60ceae7c2c 100644
--- a/static/themes/redmond-xxi.json
+++ b/static/themes/redmond-xxi.json
@@ -1,277 +1,278 @@
{
"_pleroma_theme_version": 2,
"name": "Redmond XXI",
"source": {
"themeEngineVersion": 3,
"shadows": {
"panel": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#404040",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#dfdfdf",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"panelHeader": [
{
"x": 0,
"y": 0,
"blur": 0,
"spread": "3",
"inset": true,
"color": "#d6d6ce",
"alpha": 1
},
{
"x": "-2200",
"y": 0,
"blur": "200",
"spread": "-2000",
"inset": true,
"color": "#a5cef7",
"alpha": 1
}
],
"button": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#404040",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"buttonHover": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#404040",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"buttonPressed": [
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#404040",
"alpha": "1",
"inset": true
},
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--bg",
"alpha": "1",
"inset": true
}
],
"input": [
{
"x": "-1",
"y": "-1",
"blur": "0",
"spread": 0,
"color": "#FFFFFF",
"alpha": "1",
"inset": true
},
{
"x": "1",
"y": "1",
"blur": "0",
"spread": 0,
"color": "#848484",
"alpha": "1",
"inset": true
},
{
"x": "-2",
"y": "-2",
"blur": "0",
"spread": 0,
"color": "#d4d0c8",
"alpha": "1",
"inset": true
},
{
"x": "2",
"y": "2",
"blur": "0",
"spread": 0,
"color": "#404040",
"alpha": "1",
"inset": true
},
{
"x": "0",
"y": "0",
"blur": "0",
"spread": "3",
"color": "--input",
"alpha": "1",
"inset": true
}
]
},
"fonts": {},
"opacity": {
"input": "1",
"faint": "1"
},
"colors": {
"bg": "#d6d6ce",
+ "wallpaper": "#396ba5",
"text": "#000000",
"link": "#0000ff",
"accent": "#0a246a",
"fg": "#d6d6ce",
"panel": "#042967",
"panelFaint": "#FFFFFF",
"input": "#ffffff",
"topBar": "#042967",
"topBarLink": "#ffffff",
"btn": "#d6d6ce",
"btnToggled": "--btn",
"faint": "#3f3f3f",
"faintLink": "#404080",
"border": "#808080",
"cRed": "#c42726",
"cBlue": "#6699cc",
"cGreen": "#669966",
"cOrange": "#cc6633",
"highlight": "--accent",
"selectedPost": "--bg,-10",
"selectedMenu": "--accent",
"selectedMenuPopover": "--accent"
},
"radii": {
"btn": "0",
"input": "0",
"checkbox": "0",
"panel": "0",
"avatar": "0",
"avatarAlt": "0",
"tooltip": "0",
"attachment": "0"
}
}
}

File Metadata

Mime Type
text/x-diff
Expires
Sun, Aug 30, 9:56 AM (1 d, 18 h)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1737892
Default Alt Text
(117 KB)

Event Timeline