Merge remote-tracking branch 'upstream/develop' into develop

This commit is contained in:
FloatingGhost 2022-06-08 18:09:16 +01:00
commit f6cf509a04
229 changed files with 9798 additions and 5400 deletions

View file

@ -1,14 +1,17 @@
import { get, set } from 'lodash'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import ModifiedIndicator from './modified_indicator.vue'
import ServerSideIndicator from './server_side_indicator.vue'
export default {
components: {
Checkbox,
ModifiedIndicator
ModifiedIndicator,
ServerSideIndicator
},
props: [
'path',
'disabled'
'disabled',
'expert'
],
computed: {
pathDefault () {
@ -26,8 +29,14 @@ export default {
defaultState () {
return get(this.$parent, this.pathDefault)
},
isServerSide () {
return this.path.startsWith('serverSide_')
},
isChanged () {
return this.state !== this.defaultState
return !this.path.startsWith('serverSide_') && this.state !== this.defaultState
},
matchesExpertLevel () {
return (this.expert || 0) <= this.$parent.expertLevel
}
},
methods: {

View file

@ -1,11 +1,12 @@
<template>
<label
v-if="matchesExpertLevel"
class="BooleanSetting"
>
<Checkbox
:checked="state"
:model-value="state"
:disabled="disabled"
@change="update"
@update:modelValue="update"
>
<span
v-if="!!$slots.default"
@ -13,8 +14,8 @@
>
<slot />
</span>
<ModifiedIndicator :changed="isChanged" />
</Checkbox>
{{ ' ' }}
<ModifiedIndicator :changed="isChanged" /><ServerSideIndicator :server-side="isServerSide" /> </Checkbox>
</label>
</template>

View file

@ -1,15 +1,18 @@
import { get, set } from 'lodash'
import Select from 'src/components/select/select.vue'
import ModifiedIndicator from './modified_indicator.vue'
import ServerSideIndicator from './server_side_indicator.vue'
export default {
components: {
Select,
ModifiedIndicator
ModifiedIndicator,
ServerSideIndicator
},
props: [
'path',
'disabled',
'options'
'options',
'expert'
],
computed: {
pathDefault () {
@ -27,8 +30,14 @@ export default {
defaultState () {
return get(this.$parent, this.pathDefault)
},
isServerSide () {
return this.path.startsWith('serverSide_')
},
isChanged () {
return this.state !== this.defaultState
return !this.path.startsWith('serverSide_') && this.state !== this.defaultState
},
matchesExpertLevel () {
return (this.expert || 0) <= this.$parent.expertLevel
}
},
methods: {

View file

@ -1,12 +1,14 @@
<template>
<label
v-if="matchesExpertLevel"
class="ChoiceSetting"
>
<slot />
{{ ' ' }}
<Select
:value="state"
:model-value="state"
:disabled="disabled"
@change="update"
@update:modelValue="update"
>
<option
v-for="option in options"
@ -18,6 +20,7 @@
</option>
</Select>
<ModifiedIndicator :changed="isChanged" />
<ServerSideIndicator :server-side="isServerSide" />
</label>
</template>

View file

@ -0,0 +1,41 @@
import { get, set } from 'lodash'
import ModifiedIndicator from './modified_indicator.vue'
export default {
components: {
ModifiedIndicator
},
props: {
path: String,
disabled: Boolean,
min: Number,
expert: [Number, String]
},
computed: {
pathDefault () {
const [firstSegment, ...rest] = this.path.split('.')
return [firstSegment + 'DefaultValue', ...rest].join('.')
},
state () {
const value = get(this.$parent, this.path)
if (value === undefined) {
return this.defaultState
} else {
return value
}
},
defaultState () {
return get(this.$parent, this.pathDefault)
},
isChanged () {
return this.state !== this.defaultState
},
matchesExpertLevel () {
return (this.expert || 0) <= this.$parent.expertLevel
}
},
methods: {
update (e) {
set(this.$parent, this.path, parseInt(e.target.value))
}
}
}

View file

@ -0,0 +1,24 @@
<template>
<span
v-if="matchesExpertLevel"
class="IntegerSetting"
>
<label :for="path">
<slot />
</label>
<input
:id="path"
class="number-input"
type="number"
step="1"
:disabled="disabled"
:min="min || 0"
:value="state"
@change="update"
>
{{ ' ' }}
<ModifiedIndicator :changed="isChanged" />
</span>
</template>
<script src="./integer_setting.js"></script>

View file

@ -0,0 +1,51 @@
<template>
<span
v-if="serverSide"
class="ServerSideIndicator"
>
<Popover
trigger="hover"
>
<template v-slot:trigger>
&nbsp;
<FAIcon
icon="server"
:aria-label="$t('settings.setting_server_side')"
/>
</template>
<template v-slot:content>
<div class="serverside-tooltip">
{{ $t('settings.setting_server_side') }}
</div>
</template>
</Popover>
</span>
</template>
<script>
import Popover from 'src/components/popover/popover.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { faServer } from '@fortawesome/free-solid-svg-icons'
library.add(
faServer
)
export default {
components: { Popover },
props: ['serverSide']
}
</script>
<style lang="scss">
.ServerSideIndicator {
display: inline-block;
position: relative;
.serverside-tooltip {
margin: 0.5em 1em;
min-width: 10em;
text-align: center;
}
}
</style>

View file

@ -1,4 +1,5 @@
import { defaultState as configDefaultState } from 'src/modules/config.js'
import { defaultState as serverSideConfigDefaultState } from 'src/modules/serverSideConfig.js'
const SharedComputedObject = () => ({
user () {
@ -22,6 +23,14 @@ const SharedComputedObject = () => ({
}
}])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
...Object.keys(serverSideConfigDefaultState)
.map(key => ['serverSide_' + key, {
get () { return this.$store.state.serverSideConfig[key] },
set (value) {
this.$store.dispatch('setServerSideOption', { name: key, value })
}
}])
.reduce((acc, [key, value]) => ({ ...acc, [key]: value }), {}),
// Special cases (need to transform values or perform actions first)
useStreamingApi: {
get () { return this.$store.getters.mergedConfig.useStreamingApi },

View file

@ -3,6 +3,7 @@ import PanelLoading from 'src/components/panel_loading/panel_loading.vue'
import AsyncComponentError from 'src/components/async_component_error/async_component_error.vue'
import getResettableAsyncComponent from 'src/services/resettable_async_component.js'
import Popover from '../popover/popover.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import { cloneDeep } from 'lodash'
import {
@ -51,11 +52,12 @@ const SettingsModal = {
components: {
Modal,
Popover,
Checkbox,
SettingsModalContent: getResettableAsyncComponent(
() => import('./settings_modal_content.vue'),
{
loading: PanelLoading,
error: AsyncComponentError,
loadingComponent: PanelLoading,
errorComponent: AsyncComponentError,
delay: 0
}
)
@ -159,6 +161,15 @@ const SettingsModal = {
},
modalPeeked () {
return this.$store.state.interface.settingsModalState === 'minimized'
},
expertLevel: {
get () {
return this.$store.state.config.expertLevel > 0
},
set (value) {
console.log(value)
this.$store.dispatch('setOption', { name: 'expertLevel', value: value ? 1 : 0 })
}
}
}
}

View file

@ -2,6 +2,18 @@
.settings-modal {
overflow: hidden;
.setting-list,
.option-list {
list-style-type: none;
padding-left: 2em;
li {
margin-bottom: 0.5em;
}
.suboptions {
margin-top: 0.3em
}
}
&.peek {
.settings-modal-panel {
/* Explanation:
@ -42,10 +54,22 @@
overflow-y: hidden;
.btn {
min-height: 28px;
min-height: 2em;
min-width: 10em;
padding: 0 2em;
}
}
}
.settings-footer {
display: flex;
>* {
margin-right: 0.5em;
}
.extra-content {
display: flex;
flex-grow: 1;
}
}
}

View file

@ -11,23 +11,14 @@
{{ $t('settings.settings') }}
</span>
<transition name="fade">
<template v-if="currentSaveStateNotice">
<div
v-if="currentSaveStateNotice.error"
class="alert error"
@click.prevent
>
{{ $t('settings.saving_err') }}
</div>
<div
v-if="!currentSaveStateNotice.error"
class="alert transparent"
@click.prevent
>
{{ $t('settings.saving_ok') }}
</div>
</template>
<div
v-if="currentSaveStateNotice"
class="alert"
:class="{ transparent: !currentSaveStateNotice.error, error: currentSaveStateNotice.error}"
@click.prevent
>
{{ currentSaveStateNotice.error ? $t('settings.saving_err') : $t('settings.saving_ok') }}
</div>
</transition>
<button
class="btn button-default"
@ -53,7 +44,7 @@
<div class="panel-body">
<SettingsModalContent v-if="modalOpenedOnce" />
</div>
<div class="panel-footer">
<div class="panel-footer settings-footer">
<Popover
class="export"
trigger="click"
@ -68,6 +59,7 @@
:title="$t('general.close')"
>
<span>{{ $t("settings.file_export_import.backup_restore") }}</span>
{{ ' ' }}
<FAIcon
icon="chevron-down"
/>
@ -108,6 +100,17 @@
</div>
</template>
</Popover>
<Checkbox
:model-value="!!expertLevel"
@update:modelValue="expertLevel = Number($event)"
>
{{ $t("settings.expert_mode") }}
</Checkbox>
<span
id="unscrolled-content"
class="extra-content"
/>
</div>
</div>
</Modal>

View file

@ -1,4 +1,4 @@
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.js'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import DataImportExportTab from './tabs/data_import_export_tab.vue'
import MutesAndBlocksTab from './tabs/mutes_and_blocks_tab.vue'
@ -53,6 +53,9 @@ const SettingsModalContent = {
},
open () {
return this.$store.state.interface.settingsModalState !== 'hidden'
},
bodyLock () {
return this.$store.state.interface.settingsModalState === 'visible'
}
},
methods: {
@ -60,8 +63,8 @@ const SettingsModalContent = {
const targetTab = this.$store.state.interface.settingsModalTargetTab
// We're being told to open in specific tab
if (targetTab) {
const tabIndex = this.$refs.tabSwitcher.$slots.default.findIndex(elm => {
return elm.data && elm.data.attrs['data-tab-name'] === targetTab
const tabIndex = this.$refs.tabSwitcher.$slots.default().findIndex(elm => {
return elm.props && elm.props['data-tab-name'] === targetTab
})
if (tabIndex >= 0) {
this.$refs.tabSwitcher.setTab(tabIndex)

View file

@ -4,6 +4,7 @@
class="settings_tab-switcher"
:side-tab-bar="true"
:scrollable-tabs="true"
:body-scroll-lock="bodyLock"
>
<div
:label="$t('settings.general')"

View file

@ -1,6 +1,7 @@
import { filter, trim } from 'lodash'
import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue'
import IntegerSetting from '../helpers/integer_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js'
@ -17,7 +18,8 @@ const FilteringTab = {
},
components: {
BooleanSetting,
ChoiceSetting
ChoiceSetting,
IntegerSetting
},
computed: {
...SharedComputedObject(),

View file

@ -1,73 +1,110 @@
<template>
<div :label="$t('settings.filtering')">
<div class="setting-item">
<div class="select-multiple">
<span class="label">{{ $t('settings.notification_visibility') }}</span>
<ul class="option-list">
<li>
<BooleanSetting path="notificationVisibility.likes">
{{ $t('settings.notification_visibility_likes') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationVisibility.repeats">
{{ $t('settings.notification_visibility_repeats') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationVisibility.follows">
{{ $t('settings.notification_visibility_follows') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationVisibility.mentions">
{{ $t('settings.notification_visibility_mentions') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationVisibility.moves">
{{ $t('settings.notification_visibility_moves') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationVisibility.emojiReactions">
{{ $t('settings.notification_visibility_emoji_reactions') }}
</BooleanSetting>
</li>
</ul>
</div>
<ChoiceSetting
id="replyVisibility"
path="replyVisibility"
:options="replyVisibilityOptions"
>
{{ $t('settings.replies_in_timeline') }}
</ChoiceSetting>
<div>
<BooleanSetting path="hidePostStats">
{{ $t('settings.hide_post_stats') }}
</BooleanSetting>
</div>
<div>
<BooleanSetting path="hideUserStats">
{{ $t('settings.hide_user_stats') }}
</BooleanSetting>
</div>
<h2>{{ $t('settings.posts') }}</h2>
<ul class="setting-list">
<li>
<BooleanSetting path="hideFilteredStatuses">
{{ $t('settings.hide_filtered_statuses') }}
</BooleanSetting>
<ul
class="setting-list suboptions"
:class="[{disabled: !streaming}]"
>
<li>
<BooleanSetting
:disabled="hideFilteredStatuses"
path="hideWordFilteredPosts"
>
{{ $t('settings.hide_wordfiltered_statuses') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
v-if="user"
:disabled="hideFilteredStatuses"
path="hideMutedThreads"
>
{{ $t('settings.hide_muted_threads') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
v-if="user"
:disabled="hideFilteredStatuses"
path="hideMutedPosts"
>
{{ $t('settings.hide_muted_posts') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<BooleanSetting path="muteBotStatuses">
{{ $t('settings.mute_bot_posts') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="hidePostStats">
{{ $t('settings.hide_post_stats') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="hideBotIndication">
{{ $t('settings.hide_bot_indication') }}
</BooleanSetting>
</li>
<ChoiceSetting
v-if="user"
id="replyVisibility"
path="replyVisibility"
:options="replyVisibilityOptions"
>
{{ $t('settings.replies_in_timeline') }}
</ChoiceSetting>
<li>
<h3>{{ $t('settings.wordfilter') }}</h3>
<textarea
id="muteWords"
v-model="muteWordsString"
class="resize-height"
/>
<div>{{ $t('settings.filtering_explanation') }}</div>
</li>
<h3>{{ $t('settings.attachments') }}</h3>
<li>
<IntegerSetting
path="maxThumbnails"
expert="1"
:min="0"
>
{{ $t('settings.max_thumbnails') }}
</IntegerSetting>
</li>
<li>
<BooleanSetting path="hideAttachments">
{{ $t('settings.hide_attachments_in_tl') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="hideAttachmentsInConv">
{{ $t('settings.hide_attachments_in_convo') }}
</BooleanSetting>
</li>
</ul>
</div>
<div class="setting-item">
<div>
<p>{{ $t('settings.filtering_explanation') }}</p>
<textarea
id="muteWords"
v-model="muteWordsString"
class="resize-height"
/>
</div>
<div>
<BooleanSetting path="hideFilteredStatuses">
{{ $t('settings.hide_filtered_statuses') }}
</BooleanSetting>
</div>
<div
v-if="expertLevel > 0"
class="setting-item"
>
<h2>{{ $t('settings.user_profiles') }}</h2>
<ul class="setting-list">
<li>
<BooleanSetting path="hideUserStats">
{{ $t('settings.hide_user_stats') }}
</BooleanSetting>
</li>
</ul>
</div>
</div>
</template>

View file

@ -1,8 +1,11 @@
import BooleanSetting from '../helpers/boolean_setting.vue'
import ChoiceSetting from '../helpers/choice_setting.vue'
import ScopeSelector from 'src/components/scope_selector/scope_selector.vue'
import IntegerSetting from '../helpers/integer_setting.vue'
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js'
import ServerSideIndicator from '../helpers/server_side_indicator.vue'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faGlobe
@ -20,6 +23,26 @@ const GeneralTab = {
value: mode,
label: this.$t(`settings.subject_line_${mode === 'masto' ? 'mastodon' : mode}`)
})),
conversationDisplayOptions: ['tree', 'linear'].map(mode => ({
key: mode,
value: mode,
label: this.$t(`settings.conversation_display_${mode}`)
})),
conversationOtherRepliesButtonOptions: ['below', 'inside'].map(mode => ({
key: mode,
value: mode,
label: this.$t(`settings.conversation_other_replies_button_${mode}`)
})),
mentionLinkDisplayOptions: ['short', 'full_for_remote', 'full'].map(mode => ({
key: mode,
value: mode,
label: this.$t(`settings.mention_link_display_${mode}`)
})),
thirdColumnModeOptions: ['none', 'notifications', 'postform'].map(mode => ({
key: mode,
value: mode,
label: this.$t(`settings.third_column_mode_${mode}`)
})),
loopSilentAvailable:
// Firefox
Object.getOwnPropertyDescriptor(HTMLVideoElement.prototype, 'mozHasAudio') ||
@ -32,7 +55,10 @@ const GeneralTab = {
components: {
BooleanSetting,
ChoiceSetting,
InterfaceLanguageSwitcher
IntegerSetting,
InterfaceLanguageSwitcher,
ScopeSelector,
ServerSideIndicator
},
computed: {
postFormats () {
@ -51,7 +77,18 @@ const GeneralTab = {
!this.$store.state.users.currentUser.background_image
},
instanceShoutboxPresent () { return this.$store.state.instance.shoutAvailable },
language: {
get: function () { return this.$store.getters.mergedConfig.interfaceLanguage },
set: function (val) {
this.$store.dispatch('setOption', { name: 'interfaceLanguage', value: val })
}
},
...SharedComputedObject()
},
methods: {
changeDefaultScope (value) {
this.$store.dispatch('setServerSideOption', { name: 'defaultScope', value })
}
}
}

View file

@ -4,7 +4,11 @@
<h2>{{ $t('settings.interface') }}</h2>
<ul class="setting-list">
<li>
<interface-language-switcher />
<interface-language-switcher
:prompt-text="$t('settings.interfaceLanguage')"
:language="language"
:set-language="val => language = val"
/>
</li>
<li v-if="instanceSpecificPanelPresent">
<BooleanSetting path="hideISP">
@ -21,24 +25,9 @@
{{ $t('settings.hide_wallpaper') }}
</BooleanSetting>
</li>
<li v-if="instanceShoutboxPresent">
<BooleanSetting path="hideShoutbox">
{{ $t('settings.hide_shoutbox') }}
</BooleanSetting>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('nav.timeline') }}</h2>
<ul class="setting-list">
<li>
<BooleanSetting path="hideMutedPosts">
{{ $t('settings.hide_muted_posts') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="collapseMessageWithSubject">
{{ $t('settings.collapse_subject') }}
<BooleanSetting path="stopGifs">
{{ $t('settings.stop_gifs') }}
</BooleanSetting>
</li>
<li>
@ -60,56 +49,39 @@
</ul>
</li>
<li>
<BooleanSetting path="useStreamingApi">
<BooleanSetting
path="useStreamingApi"
expert="1"
>
{{ $t('settings.useStreamingApi') }}
<br>
<small>
{{ $t('settings.useStreamingApiWarning') }}
</small>
</BooleanSetting>
</li>
<li>
<BooleanSetting path="emojiReactionsOnTimeline">
{{ $t('settings.emoji_reactions_on_timeline') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="virtualScrolling">
<BooleanSetting
path="virtualScrolling"
expert="1"
>
{{ $t('settings.virtual_scrolling') }}
</BooleanSetting>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('settings.composing') }}</h2>
<ul class="setting-list">
<li>
<BooleanSetting path="scopeCopy">
{{ $t('settings.scope_copy') }}
<BooleanSetting path="disableStickyHeaders">
{{ $t('settings.disable_sticky_headers') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="alwaysShowSubjectInput">
{{ $t('settings.subject_input_always_show') }}
<BooleanSetting path="showScrollbars">
{{ $t('settings.show_scrollbars') }}
</BooleanSetting>
</li>
<li>
<ChoiceSetting
id="subjectLineBehavior"
path="subjectLineBehavior"
:options="subjectLineOptions"
v-if="user"
id="thirdColumnMode"
path="thirdColumnMode"
:options="thirdColumnModeOptions"
>
{{ $t('settings.subject_line_behavior') }}
</ChoiceSetting>
</li>
<li v-if="postFormats.length > 0">
<ChoiceSetting
id="postContentType"
path="postContentType"
:options="postContentOptions"
>
{{ $t('settings.post_status_content_type') }}
{{ $t('settings.third_column_mode') }}
</ChoiceSetting>
</li>
<li>
@ -128,48 +100,110 @@
</BooleanSetting>
</li>
<li>
<BooleanSetting path="alwaysShowNewPostButton">
<BooleanSetting
path="alwaysShowNewPostButton"
expert="1"
>
{{ $t('settings.always_show_post_button') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="autohideFloatingPostButton">
<BooleanSetting
path="autohideFloatingPostButton"
expert="1"
>
{{ $t('settings.autohide_floating_post_button') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="padEmoji">
{{ $t('settings.pad_emoji') }}
<li v-if="instanceShoutboxPresent">
<BooleanSetting
path="hideShoutbox"
expert="1"
>
{{ $t('settings.hide_shoutbox') }}
</BooleanSetting>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('settings.attachments') }}</h2>
<h2>{{ $t('settings.post_look_feel') }}</h2>
<ul class="setting-list">
<li>
<BooleanSetting path="hideAttachments">
{{ $t('settings.hide_attachments_in_tl') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="hideAttachmentsInConv">
{{ $t('settings.hide_attachments_in_convo') }}
</BooleanSetting>
</li>
<li>
<label for="maxThumbnails">
{{ $t('settings.max_thumbnails') }}
</label>
<input
id="maxThumbnails"
path.number="maxThumbnails"
class="number-input"
type="number"
min="0"
step="1"
<ChoiceSetting
id="conversationDisplay"
path="conversationDisplay"
:options="conversationDisplayOptions"
>
{{ $t('settings.conversation_display') }}
</ChoiceSetting>
</li>
<ul
v-if="conversationDisplay !== 'linear'"
class="setting-list suboptions"
>
<li>
<BooleanSetting path="conversationTreeAdvanced">
{{ $t('settings.tree_advanced') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="conversationTreeFadeAncestors"
:expert="1"
>
{{ $t('settings.tree_fade_ancestors') }}
</BooleanSetting>
</li>
<li>
<IntegerSetting
path="maxDepthInThread"
:min="3"
:expert="1"
>
{{ $t('settings.max_depth_in_thread') }}
</IntegerSetting>
</li>
<li>
<ChoiceSetting
id="conversationOtherRepliesButton"
path="conversationOtherRepliesButton"
:options="conversationOtherRepliesButtonOptions"
:expert="1"
>
{{ $t('settings.conversation_other_replies_button') }}
</ChoiceSetting>
</li>
</ul>
<li>
<BooleanSetting path="collapseMessageWithSubject">
{{ $t('settings.collapse_subject') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="emojiReactionsOnTimeline"
expert="1"
>
{{ $t('settings.emoji_reactions_on_timeline') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
v-if="user"
path="serverSide_stripRichContent"
expert="1"
>
{{ $t('settings.no_rich_text_description') }}
</BooleanSetting>
</li>
<h3>{{ $t('settings.attachments') }}</h3>
<li>
<BooleanSetting
path="useContainFit"
expert="1"
>
{{ $t('settings.use_contain_fit') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="hideNsfw">
@ -180,6 +214,7 @@
<li>
<BooleanSetting
path="preloadImage"
expert="1"
:disabled="!hideNsfw"
>
{{ $t('settings.preload_images') }}
@ -188,6 +223,7 @@
<li>
<BooleanSetting
path="useOneClickNsfw"
expert="1"
:disabled="!hideNsfw"
>
{{ $t('settings.use_one_click_nsfw') }}
@ -195,12 +231,10 @@
</li>
</ul>
<li>
<BooleanSetting path="stopGifs">
{{ $t('settings.stop_gifs') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="loopVideo">
<BooleanSetting
path="loopVideo"
expert="1"
>
{{ $t('settings.loop_video') }}
</BooleanSetting>
<ul
@ -210,6 +244,7 @@
<li>
<BooleanSetting
path="loopVideoSilentOnly"
expert="1"
:disabled="!loopVideo || !loopSilentAvailable"
>
{{ $t('settings.loop_video_silent_only') }}
@ -224,37 +259,177 @@
</ul>
</li>
<li>
<BooleanSetting path="playVideosInModal">
<BooleanSetting
path="playVideosInModal"
expert="1"
>
{{ $t('settings.play_videos_in_modal') }}
</BooleanSetting>
</li>
<h3>{{ $t('settings.mention_links') }}</h3>
<li>
<BooleanSetting path="useContainFit">
{{ $t('settings.use_contain_fit') }}
<ChoiceSetting
id="mentionLinkDisplay"
path="mentionLinkDisplay"
:options="mentionLinkDisplayOptions"
>
{{ $t('settings.mention_link_display') }}
</ChoiceSetting>
</li>
<ul
class="setting-list suboptions"
>
<li v-if="mentionLinkDisplay === 'short'">
<BooleanSetting
path="mentionLinkShowTooltip"
expert="1"
>
{{ $t('settings.mention_link_show_tooltip') }}
</BooleanSetting>
</li>
</ul>
<li>
<BooleanSetting
path="useAtIcon"
expert="1"
>
{{ $t('settings.use_at_icon') }}
</BooleanSetting>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('settings.notifications') }}</h2>
<ul class="setting-list">
<li>
<BooleanSetting path="webPushNotifications">
{{ $t('settings.enable_web_push_notifications') }}
<BooleanSetting path="mentionLinkShowAvatar">
{{ $t('settings.mention_link_show_avatar') }}
</BooleanSetting>
</li>
</ul>
</div>
<div class="setting-item">
<h2>{{ $t('settings.fun') }}</h2>
<ul class="setting-list">
<li>
<BooleanSetting path="greentext">
<BooleanSetting
path="mentionLinkFadeDomain"
expert="1"
>
{{ $t('settings.mention_link_fade_domain') }}
</BooleanSetting>
</li>
<li v-if="user">
<BooleanSetting
path="mentionLinkBoldenYou"
expert="1"
>
{{ $t('settings.mention_link_bolden_you') }}
</BooleanSetting>
</li>
<h3 v-if="expertLevel > 0">
{{ $t('settings.fun') }}
</h3>
<li>
<BooleanSetting
path="greentext"
expert="1"
>
{{ $t('settings.greentext') }}
</BooleanSetting>
</li>
<li v-if="user">
<BooleanSetting
path="mentionLinkShowYous"
expert="1"
>
{{ $t('settings.show_yous') }}
</BooleanSetting>
</li>
</ul>
</div>
<div
v-if="user"
class="setting-item"
>
<h2>{{ $t('settings.composing') }}</h2>
<ul class="setting-list">
<li>
<label for="default-vis">
{{ $t('settings.default_vis') }} <ServerSideIndicator :server-side="true" />
<ScopeSelector
class="scope-selector"
:show-all="true"
:user-default="serverSide_defaultScope"
:initial-scope="serverSide_defaultScope"
:on-scope-change="changeDefaultScope"
/>
</label>
</li>
<li>
<!-- <BooleanSetting path="serverSide_defaultNSFW"> -->
<BooleanSetting path="sensitiveByDefault">
{{ $t('settings.sensitive_by_default') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="scopeCopy"
expert="1"
>
{{ $t('settings.scope_copy') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="alwaysShowSubjectInput"
expert="1"
>
{{ $t('settings.subject_input_always_show') }}
</BooleanSetting>
</li>
<li>
<ChoiceSetting
id="subjectLineBehavior"
path="subjectLineBehavior"
:options="subjectLineOptions"
expert="1"
>
{{ $t('settings.subject_line_behavior') }}
</ChoiceSetting>
</li>
<li v-if="postFormats.length > 0">
<ChoiceSetting
id="postContentType"
path="postContentType"
:options="postContentOptions"
>
{{ $t('settings.post_status_content_type') }}
</ChoiceSetting>
</li>
<li>
<BooleanSetting
path="minimalScopesMode"
expert="1"
>
{{ $t('settings.minimal_scopes_mode') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="alwaysShowNewPostButton"
expert="1"
>
{{ $t('settings.always_show_post_button') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="autohideFloatingPostButton"
expert="1"
>
{{ $t('settings.autohide_floating_post_button') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="padEmoji"
expert="1"
>
{{ $t('settings.pad_emoji') }}
</BooleanSetting>
</li>
</ul>
</div>
</div>

View file

@ -2,7 +2,7 @@ import get from 'lodash/get'
import map from 'lodash/map'
import reject from 'lodash/reject'
import Autosuggest from 'src/components/autosuggest/autosuggest.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.js'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import BlockCard from 'src/components/block_card/block_card.vue'
import MuteCard from 'src/components/mute_card/mute_card.vue'
import DomainMuteCard from 'src/components/domain_mute_card/domain_mute_card.vue'

View file

@ -8,7 +8,7 @@
.bulk-actions {
text-align: right;
padding: 0 1em;
min-height: 28px;
min-height: 2em;
}
.bulk-action-button {

View file

@ -1,4 +1,5 @@
import Checkbox from 'src/components/checkbox/checkbox.vue'
import BooleanSetting from '../helpers/boolean_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js'
const NotificationsTab = {
data () {
@ -9,12 +10,13 @@ const NotificationsTab = {
}
},
components: {
Checkbox
BooleanSetting
},
computed: {
user () {
return this.$store.state.users.currentUser
}
},
...SharedComputedObject()
},
methods: {
updateNotificationSettings () {

View file

@ -2,30 +2,82 @@
<div :label="$t('settings.notifications')">
<div class="setting-item">
<h2>{{ $t('settings.notification_setting_filters') }}</h2>
<p>
<Checkbox v-model="notificationSettings.block_from_strangers">
{{ $t('settings.notification_setting_block_from_strangers') }}
</Checkbox>
</p>
<ul class="setting-list">
<li>
<BooleanSetting path="serverSide_blockNotificationsFromStrangers">
{{ $t('settings.notification_setting_block_from_strangers') }}
</BooleanSetting>
</li>
<li class="select-multiple">
<span class="label">{{ $t('settings.notification_visibility') }}</span>
<ul class="option-list">
<li>
<BooleanSetting path="notificationVisibility.likes">
{{ $t('settings.notification_visibility_likes') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationVisibility.repeats">
{{ $t('settings.notification_visibility_repeats') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationVisibility.follows">
{{ $t('settings.notification_visibility_follows') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationVisibility.mentions">
{{ $t('settings.notification_visibility_mentions') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationVisibility.moves">
{{ $t('settings.notification_visibility_moves') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationVisibility.emojiReactions">
{{ $t('settings.notification_visibility_emoji_reactions') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="notificationVisibility.polls">
{{ $t('settings.notification_visibility_polls') }}
</BooleanSetting>
</li>
</ul>
</li>
</ul>
</div>
<div class="setting-item">
<div
v-if="expertLevel > 0"
class="setting-item"
>
<h2>{{ $t('settings.notification_setting_privacy') }}</h2>
<p>
<Checkbox v-model="notificationSettings.hide_notification_contents">
{{ $t('settings.notification_setting_hide_notification_contents') }}
</Checkbox>
</p>
<ul class="setting-list">
<li>
<BooleanSetting
path="webPushNotifications"
expert="1"
>
{{ $t('settings.enable_web_push_notifications') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting
path="serverSide_webPushHideContents"
expert="1"
>
{{ $t('settings.notification_setting_hide_notification_contents') }}
</BooleanSetting>
</li>
</ul>
</div>
<div class="setting-item">
<p>{{ $t('settings.notification_mutes') }}</p>
<p>{{ $t('settings.notification_blocks') }}</p>
<button
class="btn button-default"
@click="updateNotificationSettings"
>
{{ $t('settings.save') }}
</button>
</div>
</div>
</template>

View file

@ -8,6 +8,11 @@ import EmojiInput from 'src/components/emoji_input/emoji_input.vue'
import suggestor from 'src/components/emoji_input/suggestor.js'
import Autosuggest from 'src/components/autosuggest/autosuggest.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import InterfaceLanguageSwitcher from 'src/components/interface_language_switcher/interface_language_switcher.vue'
import BooleanSetting from '../helpers/boolean_setting.vue'
import SharedComputedObject from '../helpers/shared_computed_object.js'
import localeService from 'src/services/locale/locale.service.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
faTimes,
@ -27,25 +32,18 @@ const ProfileTab = {
newName: this.$store.state.users.currentUser.name_unescaped,
newBio: unescape(this.$store.state.users.currentUser.description),
newLocked: this.$store.state.users.currentUser.locked,
newNoRichText: this.$store.state.users.currentUser.no_rich_text,
newDefaultScope: this.$store.state.users.currentUser.default_scope,
newFields: this.$store.state.users.currentUser.fields.map(field => ({ name: field.name, value: field.value })),
hideFollows: this.$store.state.users.currentUser.hide_follows,
hideFollowers: this.$store.state.users.currentUser.hide_followers,
hideFollowsCount: this.$store.state.users.currentUser.hide_follows_count,
hideFollowersCount: this.$store.state.users.currentUser.hide_followers_count,
showRole: this.$store.state.users.currentUser.show_role,
role: this.$store.state.users.currentUser.role,
discoverable: this.$store.state.users.currentUser.discoverable,
bot: this.$store.state.users.currentUser.bot,
allowFollowingMove: this.$store.state.users.currentUser.allow_following_move,
pickAvatarBtnVisible: true,
bannerUploading: false,
backgroundUploading: false,
banner: null,
bannerPreview: null,
background: null,
backgroundPreview: null
backgroundPreview: null,
emailLanguage: this.$store.state.users.currentUser.language || ''
}
},
components: {
@ -54,12 +52,15 @@ const ProfileTab = {
EmojiInput,
Autosuggest,
ProgressButton,
Checkbox
Checkbox,
BooleanSetting,
InterfaceLanguageSwitcher
},
computed: {
user () {
return this.$store.state.users.currentUser
},
...SharedComputedObject(),
emojiUserSuggestor () {
return suggestor({
emoji: [
@ -114,27 +115,25 @@ const ProfileTab = {
},
methods: {
updateProfile () {
const params = {
note: this.newBio,
locked: this.newLocked,
// Backend notation.
/* eslint-disable camelcase */
display_name: this.newName,
fields_attributes: this.newFields.filter(el => el != null),
bot: this.bot,
show_role: this.showRole
/* eslint-enable camelcase */
}
if (this.emailLanguage) {
params.language = localeService.internalToBackendLocale(this.emailLanguage)
}
this.$store.state.api.backendInteractor
.updateProfile({
params: {
note: this.newBio,
locked: this.newLocked,
// Backend notation.
/* eslint-disable camelcase */
display_name: this.newName,
fields_attributes: this.newFields.filter(el => el != null),
default_scope: this.newDefaultScope,
no_rich_text: this.newNoRichText,
hide_follows: this.hideFollows,
hide_followers: this.hideFollowers,
discoverable: this.discoverable,
bot: this.bot,
allow_following_move: this.allowFollowingMove,
hide_follows_count: this.hideFollowsCount,
hide_followers_count: this.hideFollowersCount,
show_role: this.showRole
/* eslint-enable camelcase */
} }).then((user) => {
.updateProfile({ params })
.then((user) => {
this.newFields.splice(user.fields.length)
merge(this.newFields, user.fields)
this.$store.commit('addNewUsers', [user])
@ -204,8 +203,8 @@ const ProfileTab = {
submitAvatar (cropper, file) {
const that = this
return new Promise((resolve, reject) => {
function updateAvatar (avatar) {
that.$store.state.api.backendInteractor.updateProfileImages({ avatar })
function updateAvatar (avatar, avatarName) {
that.$store.state.api.backendInteractor.updateProfileImages({ avatar, avatarName })
.then((user) => {
that.$store.commit('addNewUsers', [user])
that.$store.commit('setCurrentUser', user)
@ -218,9 +217,9 @@ const ProfileTab = {
}
if (cropper) {
cropper.getCroppedCanvas().toBlob(updateAvatar, file.type)
cropper.getCroppedCanvas().toBlob((data) => updateAvatar(data, file.name), file.type)
} else {
updateAvatar(file)
updateAvatar(file, file.name)
}
})
},

View file

@ -54,16 +54,20 @@
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
background-color: rgba(0, 0, 0, 0.6);
opacity: 0.7;
color: white;
width: 1.5em;
height: 1.5em;
text-align: center;
line-height: 1.5em;
font-size: 1.5em;
cursor: pointer;
&:hover {
opacity: 1;
}
svg {
color: white;
}
}
.oauth-tokens {
@ -85,7 +89,7 @@
&-bulk-actions {
text-align: right;
padding: 0 1em;
min-height: 28px;
min-height: 2em;
button {
width: 10em;

View file

@ -25,61 +25,6 @@
class="bio resize-height"
/>
</EmojiInput>
<p>
<Checkbox v-model="newLocked">
{{ $t('settings.lock_account_description') }}
</Checkbox>
</p>
<div>
<label for="default-vis">{{ $t('settings.default_vis') }}</label>
<div
id="default-vis"
class="visibility-tray"
>
<scope-selector
:show-all="true"
:user-default="newDefaultScope"
:initial-scope="newDefaultScope"
:on-scope-change="changeVis"
/>
</div>
</div>
<p>
<Checkbox v-model="newNoRichText">
{{ $t('settings.no_rich_text_description') }}
</Checkbox>
</p>
<p>
<Checkbox v-model="hideFollows">
{{ $t('settings.hide_follows_description') }}
</Checkbox>
</p>
<p class="setting-subitem">
<Checkbox
v-model="hideFollowsCount"
:disabled="!hideFollows"
>
{{ $t('settings.hide_follows_count_description') }}
</Checkbox>
</p>
<p>
<Checkbox v-model="hideFollowers">
{{ $t('settings.hide_followers_description') }}
</Checkbox>
</p>
<p class="setting-subitem">
<Checkbox
v-model="hideFollowersCount"
:disabled="!hideFollowers"
>
{{ $t('settings.hide_followers_count_description') }}
</Checkbox>
</p>
<p>
<Checkbox v-model="allowFollowingMove">
{{ $t('settings.allow_following_move') }}
</Checkbox>
</p>
<p v-if="role === 'admin' || role === 'moderator'">
<Checkbox v-model="showRole">
<template v-if="role === 'admin'">
@ -90,11 +35,6 @@
</template>
</Checkbox>
</p>
<p>
<Checkbox v-model="discoverable">
{{ $t('settings.discoverable') }}
</Checkbox>
</p>
<div v-if="maxFields > 0">
<p>{{ $t('settings.profile_fields.label') }}</p>
<div
@ -128,8 +68,9 @@
class="delete-field button-unstyled -hover-highlight"
@click="deleteField(i)"
>
<!-- TODO something is wrong with v-show here -->
<FAIcon
v-show="newFields.length > 1"
v-if="newFields.length > 1"
icon="times"
/>
</button>
@ -148,6 +89,13 @@
{{ $t('settings.bot') }}
</Checkbox>
</p>
<p>
<interface-language-switcher
:prompt-text="$t('settings.email_language')"
:language="emailLanguage"
:set-language="val => emailLanguage = val"
/>
</p>
<button
:disabled="newName && newName.length === 0"
class="btn button-default"
@ -166,14 +114,17 @@
:src="user.profile_image_url_original"
class="current-avatar"
>
<FAIcon
<button
v-if="!isDefaultAvatar && pickAvatarBtnVisible"
:title="$t('settings.reset_avatar')"
class="reset-button"
icon="times"
type="button"
@click="resetAvatar"
/>
class="button-unstyled reset-button"
>
<FAIcon
icon="times"
type="button"
/>
</button>
</div>
<p>{{ $t('settings.set_new_avatar') }}</p>
<button
@ -195,14 +146,17 @@
<h2>{{ $t('settings.profile_banner') }}</h2>
<div class="banner-background-preview">
<img :src="user.cover_photo">
<FAIcon
<button
v-if="!isDefaultBanner"
class="button-unstyled reset-button"
:title="$t('settings.reset_profile_banner')"
class="reset-button"
icon="times"
type="button"
@click="resetBanner"
/>
>
<FAIcon
icon="times"
type="button"
/>
</button>
</div>
<p>{{ $t('settings.set_new_profile_banner') }}</p>
<img
@ -234,14 +188,17 @@
<h2>{{ $t('settings.profile_background') }}</h2>
<div class="banner-background-preview">
<img :src="user.background_image">
<FAIcon
<button
v-if="!isDefaultBackground"
class="button-unstyled reset-button"
:title="$t('settings.reset_profile_background')"
class="reset-button"
icon="times"
type="button"
@click="resetBackground"
/>
>
<FAIcon
icon="times"
type="button"
/>
</button>
</div>
<p>{{ $t('settings.set_new_profile_background') }}</p>
<img
@ -269,6 +226,67 @@
{{ $t('settings.save') }}
</button>
</div>
<div class="setting-item">
<h2>{{ $t('settings.account_privacy') }}</h2>
<ul class="setting-list">
<li>
<BooleanSetting path="serverSide_locked">
{{ $t('settings.lock_account_description') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="serverSide_discoverable">
{{ $t('settings.discoverable') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="serverSide_allowFollowingMove">
{{ $t('settings.allow_following_move') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="serverSide_hideFavorites">
{{ $t('settings.hide_favorites_description') }}
</BooleanSetting>
</li>
<li>
<BooleanSetting path="serverSide_hideFollowers">
{{ $t('settings.hide_followers_description') }}
</BooleanSetting>
<ul
class="setting-list suboptions"
:class="[{disabled: !serverSide_hideFollowers}]"
>
<li>
<BooleanSetting
path="serverSide_hideFollowersCount"
:disabled="!serverSide_hideFollowers"
>
{{ $t('settings.hide_followers_count_description') }}
</BooleanSetting>
</li>
</ul>
</li>
<li>
<BooleanSetting path="serverSide_hideFollows">
{{ $t('settings.hide_follows_description') }}
</BooleanSetting>
<ul
class="setting-list suboptions"
:class="[{disabled: !serverSide_hideFollows}]"
>
<li>
<BooleanSetting
path="serverSide_hideFollowsCount"
:disabled="!serverSide_hideFollows"
>
{{ $t('settings.hide_follows_count_description') }}
</BooleanSetting>
</li>
</ul>
</li>
</ul>
</div>
</div>
</template>

View file

@ -29,14 +29,14 @@
{{ $t('settings.style.preview.content') }}
</h4>
<i18n path="settings.style.preview.text">
<i18n-t scope="global" keypath="settings.style.preview.text">
<code style="font-family: var(--postCodeFont)">
{{ $t('settings.style.preview.mono') }}
</code>
<a style="color: var(--link)">
{{ $t('settings.style.preview.link') }}
</a>
</i18n>
</i18n-t>
<div class="icons">
<FAIcon
@ -72,15 +72,16 @@
:^)
</div>
<div class="content">
<i18n
path="settings.style.preview.fine_print"
<i18n-t
keypath="settings.style.preview.fine_print"
tag="span"
class="faint"
scope="global"
>
<a style="color: var(--faintLink)">
{{ $t('settings.style.preview.faint_link') }}
</a>
</i18n>
</i18n-t>
</div>
</div>
<div class="separator" />

View file

@ -1,4 +1,3 @@
import { set, delete as del } from 'vue'
import {
rgb2hex,
hex2rgb,
@ -34,7 +33,7 @@ import OpacityInput from 'src/components/opacity_input/opacity_input.vue'
import ShadowControl from 'src/components/shadow_control/shadow_control.vue'
import FontControl from 'src/components/font_control/font_control.vue'
import ContrastRatio from 'src/components/contrast_ratio/contrast_ratio.vue'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.js'
import TabSwitcher from 'src/components/tab_switcher/tab_switcher.jsx'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import Select from 'src/components/select/select.vue'
@ -320,9 +319,9 @@ export default {
},
set (val) {
if (val) {
set(this.shadowsLocal, this.shadowSelected, this.currentShadowFallback.map(_ => Object.assign({}, _)))
this.shadowsLocal[this.shadowSelected] = this.currentShadowFallback.map(_ => Object.assign({}, _))
} else {
del(this.shadowsLocal, this.shadowSelected)
delete this.shadowsLocal[this.shadowSelected]
}
}
},
@ -334,7 +333,7 @@ export default {
return this.shadowsLocal[this.shadowSelected]
},
set (v) {
set(this.shadowsLocal, this.shadowSelected, v)
this.shadowsLocal[this.shadowSelected] = v
}
},
themeValid () {
@ -378,6 +377,10 @@ export default {
// To separate from other random JSON files and possible future source formats
_pleroma_theme_version: 2, theme, source
}
},
isActive () {
const tabSwitcher = this.$parent
return tabSwitcher ? tabSwitcher.isActive('theme') : false
}
},
components: {
@ -557,7 +560,7 @@ export default {
.filter(_ => _.endsWith('ColorLocal') || _.endsWith('OpacityLocal'))
.filter(_ => !v1OnlyNames.includes(_))
.forEach(key => {
set(this.$data, key, undefined)
this.$data[key] = undefined
})
},
@ -565,7 +568,7 @@ export default {
Object.keys(this.$data)
.filter(_ => _.endsWith('RadiusLocal'))
.forEach(key => {
set(this.$data, key, undefined)
this.$data[key] = undefined
})
},
@ -573,7 +576,7 @@ export default {
Object.keys(this.$data)
.filter(_ => _.endsWith('OpacityLocal'))
.forEach(key => {
set(this.$data, key, undefined)
this.$data[key] = undefined
})
},

View file

@ -245,36 +245,12 @@
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;
position: absolute;
bottom: 8px;
right: 5px;
}
.radius-item,
.color-item {
min-width: 20em;
@ -334,16 +310,25 @@
padding: 20px;
}
.apply-container {
.btn {
min-height: 28px;
min-width: 10em;
padding: 0 2em;
}
}
.btn {
margin-left: .25em;
margin-right: .25em;
}
}
.extra-content {
.apply-container {
display: flex;
flex-direction: row;
justify-content: space-around;
flex-grow: 1;
.btn {
flex-grow: 1;
min-height: 2em;
min-width: 0;
max-width: 10em;
padding: 0;
}
}
}

View file

@ -903,6 +903,7 @@
<div class="tab-header shadow-selector">
<div class="select-container">
{{ $t('settings.style.shadows.component') }}
{{ ' ' }}
<Select
id="shadow-switcher"
v-model="shadowSelected"
@ -924,6 +925,7 @@
>
{{ $t('settings.style.shadows.override') }}
</label>
{{ ' ' }}
<input
id="override"
v-model="currentShadowOverriden"
@ -949,27 +951,30 @@
:fallback="currentShadowFallback"
/>
<div v-if="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'">
<i18n
path="settings.style.shadows.filter_hint.always_drop_shadow"
<i18n-t
scope="global"
keypath="settings.style.shadows.filter_hint.always_drop_shadow"
tag="p"
>
<code>filter: drop-shadow()</code>
</i18n>
</i18n-t>
<p>{{ $t('settings.style.shadows.filter_hint.avatar_inset') }}</p>
<i18n
path="settings.style.shadows.filter_hint.drop_shadow_syntax"
<i18n-t
scope="global"
keypath="settings.style.shadows.filter_hint.drop_shadow_syntax"
tag="p"
>
<code>drop-shadow</code>
<code>spread-radius</code>
<code>inset</code>
</i18n>
<i18n
path="settings.style.shadows.filter_hint.inset_classic"
</i18n-t>
<i18n-t
scope="global"
keypath="settings.style.shadows.filter_hint.inset_classic"
tag="p"
>
<code>box-shadow</code>
</i18n>
</i18n-t>
<p>{{ $t('settings.style.shadows.filter_hint.spread_zero') }}</p>
</div>
</div>
@ -1016,21 +1021,26 @@
</tab-switcher>
</keep-alive>
<div class="apply-container">
<button
class="btn button-default submit"
:disabled="!themeValid"
@click="setCustomTheme"
>
{{ $t('general.apply') }}
</button>
<button
class="btn button-default"
@click="clearAll"
>
{{ $t('settings.style.switcher.reset') }}
</button>
</div>
<teleport
v-if="isActive"
to="#unscrolled-content"
>
<div class="apply-container">
<button
class="btn button-default submit"
:disabled="!themeValid"
@click="setCustomTheme"
>
{{ $t('general.apply') }}
</button>
<button
class="btn button-default"
@click="clearAll"
>
{{ $t('settings.style.switcher.reset') }}
</button>
</div>
</teleport>
</div>
</template>

View file

@ -28,4 +28,4 @@
</div>
</div>
</template>
<script src="./version_tab.js">
<script src="./version_tab.js" />