massive visual overhaul

This commit is contained in:
Henry Jameson 2025-12-10 18:34:19 +02:00
commit 1642d62b82
63 changed files with 387 additions and 399 deletions

View file

@ -704,6 +704,7 @@ option {
position: relative; position: relative;
display: inline-flex; display: inline-flex;
vertical-align: middle; vertical-align: middle;
min-height: 2em;
.Select select { .Select select {
line-height: 1; line-height: 1;

View file

@ -1,24 +1,28 @@
<template> <template>
<div class="font-control"> <div class="font-control">
<Checkbox <div class="setting-item">
v-if="typeof fallback !== 'undefined'" <Checkbox
:id="name + '-o'" v-if="typeof fallback !== 'undefined'"
class="font-checkbox" :id="name + '-o'"
:model-value="present" class="font-checkbox setting-control setting-label"
@change="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)" :model-value="present"
> @change="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
<i18n-t
scope="global"
keypath="settings.style.fonts.override"
tag="span"
> >
{{ label }} <i18n-t
</i18n-t> scope="global"
</Checkbox> keypath="settings.style.fonts.override"
tag="span"
>
<span class="label">
{{ label }}
</span>
</i18n-t>
</Checkbox>
</div>
{{ ' ' }} {{ ' ' }}
<div <div
v-if="modelValue?.family" v-if="modelValue?.family"
class="font-input" class="font-input setting-item"
> >
<label <label
v-if="manualEntry" v-if="manualEntry"
@ -132,15 +136,29 @@
<script src="./font_control.js"></script> <script src="./font_control.js"></script>
<style lang="scss"> <style lang="scss">
// Copy-paste of BooleanSetting
.font-control { .font-control {
.custom-font { display: grid;
min-width: 20em; grid-template-columns: subgrid;
max-width: 20em;
.checkbox {
display: grid;
grid-template-columns: subgrid;
} }
.font-input { .label {
margin-left: 2em; grid-area: label;
margin-top: 0.5em; text-align: right;
}
.-mobile & {
.label {
text-align: left;
}
}
.checkbox-indicator {
grid-area: control;
} }
} }

View file

@ -3,6 +3,8 @@ import localeService from '../../services/locale/locale.service.js'
import Select from '../select/select.vue' import Select from '../select/select.vue'
import ProfileSettingIndicator from 'src/components/settings_modal/helpers/profile_setting_indicator.vue' import ProfileSettingIndicator from 'src/components/settings_modal/helpers/profile_setting_indicator.vue'
import { v4 as uuidv4 } from 'uuid';
export default { export default {
components: { components: {
Select, Select,
@ -26,7 +28,9 @@ export default {
languages () { languages () {
return localeService.languages return localeService.languages
}, },
uniqueId () {
return uuidv4()
},
controlledLanguage: { controlledLanguage: {
get: function () { get: function () {
return Array.isArray(this.modelValue) ? this.modelValue : [this.modelValue] return Array.isArray(this.modelValue) ? this.modelValue : [this.modelValue]

View file

@ -1,30 +1,32 @@
<template> <template>
<div class="interface-language-switcher"> <ul class="interface-language-switcher setting-list">
<label> <li
<slot /> v-for="index of controlledLanguage.keys()"
<ProfileSettingIndicator :is-profile="profile" /> :key="index"
</label> class="setting-item"
<ul class="setting-list"> >
<li <label
v-for="index of controlledLanguage.keys()" class="setting-label"
:key="index" :for="uniqueId+index"
> >
<label> {{ index === 0 ? $t('settings.primary_language') : $t('settings.fallback_language', { index }, index) }}
{{ index === 0 ? $t('settings.primary_language') : $t('settings.fallback_language', { index }, index) }} </label>
<Select <span class="setting-control btn-group">
class="language-select" <Select
:model-value="controlledLanguage[index]" :name="uniqueId+index"
@update:model-value="val => setLanguageAt(index, val)" :id="uniqueId+index"
class="language-select"
:model-value="controlledLanguage[index]"
@update:model-value="val => setLanguageAt(index, val)"
>
<option
v-for="lang in languages"
:key="lang.code"
:value="lang.code"
> >
<option {{ lang.name }}
v-for="lang in languages" </option>
:key="lang.code" </Select>
:value="lang.code"
>
{{ lang.name }}
</option>
</Select>
</label>
<button <button
v-if="controlledLanguage.length > 1 && index !== 0" v-if="controlledLanguage.length > 1 && index !== 0"
class="button-default btn" class="button-default btn"
@ -32,25 +34,38 @@
> >
{{ $t('settings.remove_language') }} {{ $t('settings.remove_language') }}
</button> </button>
</li> </span>
<li> </li>
<button <li class="add-button">
class="button-default btn" <button
@click="addLanguage" class="button-default btn"
> @click="addLanguage"
{{ $t('settings.add_language') }} >
</button> {{ $t('settings.add_language') }}
</li> </button>
</ul> </li>
</div> </ul>
</template> </template>
<script src="./interface_language_switcher.js"></script> <script src="./interface_language_switcher.js"></script>
<style lang="scss"> <style lang="scss">
.interface-language-switcher { .interface-language-switcher {
.language-select { .setting-list {
margin-right: 1em; .setting-item {
display: grid;
grid-template-columns: subgrid;
}
}
.add-button {
display: block;
text-align: center;
.default-button {
display: block;
width: auto;
}
} }
} }
</style> </style>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.job_queues')"> <div :label="$t('admin_dash.tabs.job_queues')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.auth.MFA') }}</h3> <h3>{{ $t('admin_dash.auth.MFA') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -3,7 +3,7 @@
class="EmojiTab" class="EmojiTab"
:label="$t('admin_dash.tabs.emoji')" :label="$t('admin_dash.tabs.emoji')"
> >
<div class="setting-item"> <div class="setting-section">
<h3 class="toolbar"> <h3 class="toolbar">
<span class="header-text"> <span class="header-text">
{{ $t('admin_dash.emoji.emoji_packs') }} {{ $t('admin_dash.emoji.emoji_packs') }}

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.federation')"> <div :label="$t('admin_dash.tabs.federation')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.federation.global') }}</h3> <h3>{{ $t('admin_dash.federation.global') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -3,7 +3,7 @@
class="FrontendsTab" class="FrontendsTab"
:label="$t('admin_dash.tabs.frontends')" :label="$t('admin_dash.tabs.frontends')"
> >
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.frontend.title') }}</h3> <h3>{{ $t('admin_dash.frontend.title') }}</h3>
<p>{{ $t('admin_dash.frontend.wip_notice') }}</p> <p>{{ $t('admin_dash.frontend.wip_notice') }}</p>
<ul <ul

View file

@ -3,7 +3,7 @@
class="LinksTab" class="LinksTab"
:label="$t('admin_dash.tabs.http')" :label="$t('admin_dash.tabs.http')"
> >
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.http.outbound') }}</h3> <h3>{{ $t('admin_dash.http.outbound') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
@ -30,7 +30,7 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.http.incoming') }}</h3> <h3>{{ $t('admin_dash.http.incoming') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<h4>{{ $t('admin_dash.http.security') }}</h4> <h4>{{ $t('admin_dash.http.security') }}</h4>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.instance')"> <div :label="$t('admin_dash.tabs.instance')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.instance.instance') }}</h3> <h3>{{ $t('admin_dash.instance.instance') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
@ -73,7 +73,7 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.instance.access') }}</h3> <h3>{{ $t('admin_dash.instance.access') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.job_queues')"> <div :label="$t('admin_dash.tabs.job_queues')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.job_queues.Gun.title') }}</h3> <h3>{{ $t('admin_dash.job_queues.Gun.title') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.limits')"> <div :label="$t('admin_dash.tabs.limits')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.limits.arbitrary_limits') }}</h3> <h3>{{ $t('admin_dash.limits.arbitrary_limits') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,26 +0,0 @@
.LinksTab {
// awkward "disable = false" backend options
.weird-options {
.checkbox {
margin: 0;
}
}
.setting-list.suboptions.weird-suboptions {
display: flex;
flex-direction: column;
gap: 0.5em;
margin: 0;
li {
margin: 0;
display: flex;
}
.GroupSetting {
display: inline-block;
margin: 0;
padding: 0;
}
}
}

View file

@ -3,7 +3,7 @@
class="LinksTab" class="LinksTab"
:label="$t('admin_dash.tabs.media_proxy')" :label="$t('admin_dash.tabs.media_proxy')"
> >
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.links.link_previews') }}</h3> <h3>{{ $t('admin_dash.links.link_previews') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
@ -43,5 +43,3 @@
</template> </template>
<script src="./links_tab.js"></script> <script src="./links_tab.js"></script>
<style lang="scss" src="./links_tab.scss"></style>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.mailer')"> <div :label="$t('admin_dash.tabs.mailer')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.mailer.adapter') }}</h3> <h3>{{ $t('admin_dash.mailer.adapter') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.media_proxy')"> <div :label="$t('admin_dash.tabs.media_proxy')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.media_proxy.basic') }}</h3> <h3>{{ $t('admin_dash.media_proxy.basic') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.monitoring')"> <div :label="$t('admin_dash.tabs.monitoring')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.monitoring.builtins') }}</h3> <h3>{{ $t('admin_dash.monitoring.builtins') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.other')"> <div :label="$t('admin_dash.tabs.other')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.other.uncategorized') }}</h3> <h3>{{ $t('admin_dash.other.uncategorized') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.posts')"> <div :label="$t('admin_dash.tabs.posts')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.posts.global') }}</h3> <h3>{{ $t('admin_dash.posts.global') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.instance')"> <div :label="$t('admin_dash.tabs.instance')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.rate_limit.account_confirmation_resend') }}</h3> <h3>{{ $t('admin_dash.rate_limit.account_confirmation_resend') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.instance')"> <div :label="$t('admin_dash.tabs.instance')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.instance.registrations') }}</h3> <h3>{{ $t('admin_dash.instance.registrations') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.uploads')"> <div :label="$t('admin_dash.tabs.uploads')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.uploads.upload') }}</h3> <h3>{{ $t('admin_dash.uploads.upload') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,10 +1,11 @@
<template> <template>
<span <span
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="AttachmentSetting" class="AttachmentSetting setting-item"
:class="{ '-compact': compact }" :class="{ '-compact': compact }"
> >
<label <label
class="setting-label"
:for="path" :for="path"
:class="{ 'faint': shouldBeDisabled }" :class="{ 'faint': shouldBeDisabled }"
> >

View file

@ -1,9 +1,10 @@
<template> <template>
<label <label
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="BooleanSetting" class="BooleanSetting setting-item"
> >
<Checkbox <Checkbox
class="setting-control setting-label"
:model-value="visibleState" :model-value="visibleState"
:disabled="shouldBeDisabled" :disabled="shouldBeDisabled"
:indeterminate="isIndeterminate" :indeterminate="isIndeterminate"
@ -13,6 +14,12 @@
class="label" class="label"
:class="{ 'faint': shouldBeDisabled }" :class="{ 'faint': shouldBeDisabled }"
> >
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<ProfileSettingIndicator :is-profile="isProfileSetting" />
{{ ' ' }}
<template v-if="backendDescriptionLabel"> <template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel }} {{ backendDescriptionLabel }}
</template> </template>
@ -22,13 +29,6 @@
<slot v-else /> <slot v-else />
</span> </span>
</Checkbox> </Checkbox>
{{ ' ' }}
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<ProfileSettingIndicator :is-profile="isProfileSetting" />
<DraftButtons />
<p <p
v-if="backendDescriptionDescription" v-if="backendDescriptionDescription"
class="setting-description" class="setting-description"
@ -36,7 +36,35 @@
> >
{{ backendDescriptionDescription + ' ' }} {{ backendDescriptionDescription + ' ' }}
</p> </p>
<DraftButtons />
</label> </label>
</template> </template>
<script src="./boolean_setting.js"></script> <script src="./boolean_setting.js"></script>
<style lang="scss">
.BooleanSetting {
display: grid;
grid-template-columns: subgrid;
.checkbox {
display: grid;
grid-template-columns: subgrid;
}
.label {
grid-area: label;
text-align: right;
}
.-mobile & {
.label {
text-align: left;
}
}
.checkbox-indicator {
grid-area: control;
}
}
</style>

View file

@ -1,17 +1,25 @@
<template> <template>
<label <label
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="ChoiceSetting" class="ChoiceSetting setting-item"
:class="{ 'faint': shouldBeDisabled }" :class="{ 'faint': shouldBeDisabled }"
> >
<template v-if="backendDescriptionLabel"> <span class="setting-label">
{{ backendDescriptionLabel }} <ModifiedIndicator
</template> :changed="isChanged"
<template v-else> :onclick="reset"
<slot /> />
</template> <ProfileSettingIndicator :is-profile="isProfileSetting" />
{{ ' ' }} {{ ' ' }}
<template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel }}
</template>
<template v-else>
<slot />
</template>
</span>
<Select <Select
class="setting-control"
:model-value="realDraftMode ? draft : state" :model-value="realDraftMode ? draft : state"
:disabled="shouldBeDisabled" :disabled="shouldBeDisabled"
@update:model-value="update" @update:model-value="update"
@ -25,11 +33,6 @@
{{ option.value === defaultState ? $t('settings.instance_default_simple') : '' }} {{ option.value === defaultState ? $t('settings.instance_default_simple') : '' }}
</option> </option>
</Select> </Select>
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<ProfileSettingIndicator :is-profile="isProfileSetting" />
<DraftButtons /> <DraftButtons />
<p <p
v-if="backendDescriptionDescription" v-if="backendDescriptionDescription"
@ -41,3 +44,16 @@
</template> </template>
<script src="./choice_setting.js"></script> <script src="./choice_setting.js"></script>
<style lang="scss">
.ChoiceSetting.setting-item {
.-mobile & {
display: block;
.setting-label {
display: block;
margin-bottom: 0.5em
}
}
}
</style>

View file

@ -1,7 +1,7 @@
<template> <template>
<label <label
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="ColorSetting" class="ColorSetting setting-item"
> >
<label <label
v-if="!hideLabel" v-if="!hideLabel"

View file

@ -1,7 +1,7 @@
<template> <template>
<span <span
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="GroupSetting" class="GroupSetting setting-item"
> >
<ModifiedIndicator <ModifiedIndicator
:changed="isChanged" :changed="isChanged"

View file

@ -1,7 +1,7 @@
<template> <template>
<div <div
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="ListSetting" class="ListSetting setting-item"
> >
<label <label
class="setting-label" class="setting-label"

View file

@ -1,7 +1,7 @@
<template> <template>
<div <div
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="MapSetting" class="MapSetting setting-item"
> >
<label <label
class="setting-label" class="setting-label"

View file

@ -1,7 +1,7 @@
<template> <template>
<span <span
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="NumberSetting" class="NumberSetting setting-item"
> >
<label <label
v-if="!hideLabel" v-if="!hideLabel"
@ -20,7 +20,7 @@
{{ ' ' }} {{ ' ' }}
<input <input
:id="path" :id="path"
class="input number-input" class="input number-input setting-control"
type="number" type="number"
:step="step || 1" :step="step || 1"
:disabled="shouldBeDisabled" :disabled="shouldBeDisabled"

View file

@ -1,7 +1,7 @@
<template> <template>
<label <label
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="ProxySetting" class="ProxySetting setting-item"
> >
<label <label
v-if="!hideLabel" v-if="!hideLabel"

View file

@ -1,7 +1,7 @@
<template> <template>
<div <div
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="PWAManifestIconsSetting" class="PWAManifestIconsSetting setting-item"
> >
<label <label
class="setting-label" class="setting-label"

View file

@ -1,7 +1,7 @@
<template> <template>
<div <div
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="RateSetting" class="RateSetting setting-item"
> >
<label <label
class="setting-label" class="setting-label"

View file

@ -1,7 +1,7 @@
<template> <template>
<label <span
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="StringSetting" class="StringSetting setting-item"
> >
<label <label
v-if="!hideLabel" v-if="!hideLabel"
@ -9,6 +9,12 @@
class="setting-label" class="setting-label"
:class="{ 'faint': shouldBeDisabled }" :class="{ 'faint': shouldBeDisabled }"
> >
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<ProfileSettingIndicator :is-profile="isProfileSetting" />
{{ ' ' }}
<template v-if="backendDescriptionLabel"> <template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel + ' ' }} {{ backendDescriptionLabel + ' ' }}
</template> </template>
@ -17,10 +23,9 @@
</template> </template>
<slot v-else /> <slot v-else />
</label> </label>
{{ ' ' }}
<input <input
:id="path" :id="path"
class="input string-input" class="setting-control input string-input"
:class="{ disabled: shouldBeDisabled }" :class="{ disabled: shouldBeDisabled }"
:disabled="shouldBeDisabled" :disabled="shouldBeDisabled"
:placeholder="backendDescriptionSuggestions" :placeholder="backendDescriptionSuggestions"
@ -28,11 +33,6 @@
@change="update" @change="update"
> >
{{ ' ' }} {{ ' ' }}
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<ProfileSettingIndicator :is-profile="isProfileSetting" />
<DraftButtons v-if="!hideDraftButtons" /> <DraftButtons v-if="!hideDraftButtons" />
<p <p
v-if="backendDescriptionDescription" v-if="backendDescriptionDescription"
@ -41,7 +41,7 @@
> >
{{ backendDescriptionDescription + ' ' }} {{ backendDescriptionDescription + ' ' }}
</p> </p>
</label> </span>
</template> </template>
<script src="./string_setting.js"></script> <script src="./string_setting.js"></script>

View file

@ -1,7 +1,7 @@
<template> <template>
<label <span
class="setting-item"
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="TupleSetting"
> >
<label <label
v-if="!hideLabel" v-if="!hideLabel"
@ -9,6 +9,12 @@
class="setting-label" class="setting-label"
:class="{ 'faint': shouldBeDisabled }" :class="{ 'faint': shouldBeDisabled }"
> >
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<ProfileSettingIndicator :is-profile="isProfileSetting" />
{{ ' ' }}
<template v-if="backendDescriptionLabel"> <template v-if="backendDescriptionLabel">
{{ backendDescriptionLabel + ' ' }} {{ backendDescriptionLabel + ' ' }}
</template> </template>
@ -17,42 +23,27 @@
</template> </template>
<slot v-else /> <slot v-else />
</label> </label>
{{ ' ' }} <span class="setting-control">
<input <input
:id="path" :id="path"
class="input string-input" class="input string-input"
:class="{ disabled: shouldBeDisabled }" :class="{ disabled: shouldBeDisabled }"
:disabled="shouldBeDisabled" :disabled="shouldBeDisabled"
:placeholder="backendDescriptionSuggestions?.[0]?.[0]" :placeholder="backendDescriptionSuggestions?.[0]?.[0]"
:value="visibleState?.tuple?.[0]" :value="visibleState?.tuple?.[0]"
@change="e => update({ e, side: 0 })" @change="e => update({ e, side: 0 })"
> >
{{ ' ' }} {{ ' ' }}
<input <input
:id="path" :id="path"
class="input string-input" class="input string-input"
:class="{ disabled: shouldBeDisabled }" :class="{ disabled: shouldBeDisabled }"
:disabled="shouldBeDisabled" :disabled="shouldBeDisabled"
:placeholder="backendDescriptionSuggestions?.[0]?.[1]" :placeholder="backendDescriptionSuggestions?.[0]?.[1]"
:value="visibleState?.tuple?.[1]" :value="visibleState?.tuple?.[1]"
@change="e => update({ e, side: 1 })" @change="e => update({ e, side: 1 })"
> >
{{ ' ' }} </span>
<input
:id="path"
class="input string-input"
:class="{ disabled: shouldBeDisabled }"
:disabled="shouldBeDisabled"
:placeholder="backendDescriptionSuggestions?.[0]?.[1]"
:value="visibleState?.tuple?.[2]"
@change="e => update({ e, side: 2 })"
>
{{ ' ' }}
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<ProfileSettingIndicator :is-profile="isProfileSetting" />
<DraftButtons v-if="!hideDraftButtons" /> <DraftButtons v-if="!hideDraftButtons" />
<p <p
v-if="backendDescriptionDescription" v-if="backendDescriptionDescription"
@ -61,7 +52,7 @@
> >
{{ backendDescriptionDescription + ' ' }} {{ backendDescriptionDescription + ' ' }}
</p> </p>
</label> </span>
</template> </template>
<script src="./tuple_setting.js"></script> <script src="./tuple_setting.js"></script>

View file

@ -1,16 +1,16 @@
<template> <template>
<span <span
v-if="matchesExpertLevel" v-if="matchesExpertLevel"
class="UnitSetting" class="UnitSetting setting-item"
> >
<label <label
:for="path" :for="path"
class="size-label" class="setting-label size-label"
> >
<slot /> <slot />
</label> </label>
{{ ' ' }} {{ ' ' }}
<span class="no-break"> <span class="no-break setting-control">
<input <input
:id="path" :id="path"
class="input number-input" class="input number-input"
@ -50,7 +50,7 @@
<style lang="scss"> <style lang="scss">
.UnitSetting { .UnitSetting {
.no-break { .no-break {
display: inline-block; display: inline-flex;
} }
.number-input { .number-input {

View file

@ -161,9 +161,11 @@ export default {
const contentClasses = ['tab-content'] const contentClasses = ['tab-content']
if (props['full-width'] || props['full-width'] === '') { if (props['full-width'] || props['full-width'] === '') {
contentClasses.push('-full-width') contentClasses.push('-full-width')
wrapperClasses.push('-full-width')
} }
if (props['full-height'] || props['full-width'] === '') { if (props['full-height'] || props['full-width'] === '') {
contentClasses.push('-full-height') contentClasses.push('-full-height')
wrapperClasses.push('-full-height')
} }
return ( return (
<div class={wrapperClasses} > <div class={wrapperClasses} >

View file

@ -26,24 +26,6 @@
} }
> .contents { > .contents {
flex: 1 0 35em;
.tab-content {
align-self: center;
&:not(.-full-width) {
max-width: 40em;
}
&.-full-width {
align-self: stretch;
}
&.-full-height {
flex: 1;
}
}
.tab-content-label { .tab-content-label {
box-sizing: border-box; box-sizing: border-box;
margin: 0; margin: 0;
@ -60,8 +42,24 @@
flex: 1 1 auto; flex: 1 1 auto;
height: 100%; height: 100%;
overflow-y: auto; overflow-y: auto;
display: flex; display: grid;
grid-template-columns: minmax(1em, 1fr) minmax(min-content, 45em) minmax(1em, 1fr);
grid-template-areas: ". content .";
flex-direction: column; flex-direction: column;
.tab-content {
grid-area: content;
&.-full-width {
grid-column: 1 / 4;
}
&.-full-height {
> * {
height: 100%;
}
}
}
} }
.tab-content-wrapper { .tab-content-wrapper {

View file

@ -35,14 +35,53 @@
line-height: 1.5; line-height: 1.5;
} }
.setting-item > p { .setting-item {
margin-left: 1em; display: grid;
grid-template-areas:
"label control"
". desc"
". draft";
grid-template-columns: 1fr 1fr;
column-gap: 0.5em;
align-items: baseline;
padding: 0.5em 0;
.setting-label {
grid-area: label;
text-align: right;
}
.ModifiedIndicator,
.ProfileSettingIndicator {
grid-area: indicator;
}
.setting-control {
grid-area: control;
}
.setting-control.setting-label {
grid-column: 1 / 3;
text-align: left;
}
.setting-description {
grid-area: desc;
}
.DraftButtons {
grid-area: draft;
}
}
.vertical-tab-switcher {
height: 100%;
} }
.setting-list, .setting-list,
.option-list { .option-list {
list-style-type: none; list-style-type: none;
padding-left: 2em; padding-left: 0;
margin: 0; margin: 0;
.btn:not(.dropdown-button) { .btn:not(.dropdown-button) {
@ -55,21 +94,6 @@
} }
} }
li {
display: block;
margin: 0.75em 0;
> label {
display: block;
margin: 0.75em 0;
padding: 0.5em 0;
}
}
.suboptions {
margin-top: 0.3em;
}
&.two-column { &.two-column {
display: grid; display: grid;
grid-template-columns: 1fr 1fr; grid-template-columns: 1fr 1fr;
@ -135,20 +159,24 @@
} }
} }
.setting-item {
border-bottom: 1px solid var(--border);
grid-template-columns: 1fr min-content;
column-gap: 0.5em;
padding: 1em 0;
align-items: center;
.setting-label {
text-align: left;
}
}
ul {
padding: 0;
}
.setting-list:not(.suboptions), .setting-list:not(.suboptions),
.option-list { .option-list {
padding-left: 0.25em;
/* stylelint-disable no-descending-specificity */
// it makes no sense
> li {
margin: 1em 0;
line-height: 1.5em;
vertical-align: middle;
}
/* stylelint-enable no-descending-specificity */
&.two-column { &.two-column {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }

View file

@ -1,48 +0,0 @@
.settings_tab-switcher {
height: 100%;
.setting-item {
border-bottom: 2px solid var(--border);
margin: 1em 1em 1.4em;
padding-bottom: 1.4em;
> div,
> label {
display: block;
margin-bottom: 0.5em;
&:last-child {
margin-bottom: 0;
}
}
.select-multiple {
margin-top: 0.5em;
display: flex;
flex-direction: column;
.option-list {
margin: 0;
margin-top: 0.5em;
padding-left: 0.5em;
}
}
&:last-child {
border-bottom: none;
padding-bottom: 0;
margin-bottom: 1em;
}
textarea {
width: 100%;
max-width: 100%;
height: 100px;
}
.unavailable,
.unavailable svg {
color: var(--cRed);
}
}
}

View file

@ -2,7 +2,7 @@
<vertical-tab-switcher <vertical-tab-switcher
v-if="adminDescriptionsLoaded && (noDb || adminDbLoaded)" v-if="adminDescriptionsLoaded && (noDb || adminDbLoaded)"
ref="tabSwitcher" ref="tabSwitcher"
class="settings_tab-switcher" class="settings-admin-content settings_tab-switcher"
:side-tab-bar="true" :side-tab-bar="true"
:scrollable-tabs="true" :scrollable-tabs="true"
:render-only-focused="true" :render-only-focused="true"
@ -15,7 +15,7 @@
data-tab-name="nodb-notice" data-tab-name="nodb-notice"
> >
<div :label="$t('admin_dash.tabs.nodb')"> <div :label="$t('admin_dash.tabs.nodb')">
<div class="setting-item"> <div class="setting-section">
<h2>{{ $t('admin_dash.nodb.heading') }}</h2> <h2>{{ $t('admin_dash.nodb.heading') }}</h2>
<i18n-t <i18n-t
scope="global" scope="global"
@ -185,4 +185,10 @@
<script src="./settings_modal_admin_content.js"></script> <script src="./settings_modal_admin_content.js"></script>
<style src="./settings_modal_admin_content.scss" lang="scss"></style> <style lang="scss">
.settings-admin-content {
.setting-item {
grid-template-columns: 1fr 3fr;
}
}
</style>

View file

@ -1,50 +0,0 @@
.settings_tab-switcher {
height: 100%;
[full-height="true"] {
height: 100%
}
.setting-item {
margin: 1em 1em 1.4em;
padding-bottom: 1.4em;
> div,
> label {
margin-bottom: 0.5em;
&:last-child {
margin-bottom: 0;
}
}
.select-multiple {
margin-top: 1em;
display: flex;
flex-direction: column;
.option-list {
margin: 0;
margin-top: 0.5em;
padding-left: 0.5em;
}
}
&:last-child {
border-bottom: none;
padding-bottom: 0;
margin-bottom: 1em;
}
textarea {
width: 100%;
max-width: 100%;
height: 100px;
}
.unavailable,
.unavailable svg {
color: var(--cRed);
}
}
}

View file

@ -49,7 +49,7 @@
<AppearanceTab /> <AppearanceTab />
</div> </div>
<div <div
:full-width="true" :full-width="$store.getters.mergedConfig.expertLevel > 0"
:label="$t('settings.layout')" :label="$t('settings.layout')"
icon="table-columns" icon="table-columns"
data-tab-name="layout" data-tab-name="layout"
@ -68,7 +68,6 @@
</div> </div>
<div <div
:label="$t('settings.filtering')" :label="$t('settings.filtering')"
:full-width="true"
icon="filter" icon="filter"
data-tab-name="filtering" data-tab-name="filtering"
> >
@ -139,5 +138,3 @@
</template> </template>
<script src="./settings_modal_user_content.js"></script> <script src="./settings_modal_user_content.js"></script>
<style src="./settings_modal_user_content.scss" lang="scss"></style>

View file

@ -1,4 +1,6 @@
.appearance-tab { .appearance-tab {
margin: 1em;
h3 { h3 {
border: none border: none
} }
@ -67,7 +69,7 @@
aspect-ratio: 16 / 9; aspect-ratio: 16 / 9;
width: 16em; width: 16em;
} }
img { img {
object-fit: cover; object-fit: cover;
} }
@ -138,6 +140,7 @@
border: 1px solid var(--border); border: 1px solid var(--border);
margin-bottom: 0.5em; margin-bottom: 0.5em;
margin-top: 0; margin-top: 0;
padding: 0.5em;
} }
.palettes { .palettes {

View file

@ -5,7 +5,7 @@
icon="table-columns" icon="table-columns"
> >
<div <div
class="setting-item" class="setting-section"
:label="$t('settings.theme')" :label="$t('settings.theme')"
icon="paintbrush" icon="paintbrush"
> >

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="clutter-tab"> <div class="clutter-tab">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.interface') }}</h3> <h3>{{ $t('settings.interface') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,14 +1,16 @@
<template> <template>
<div :label="$t('settings.posts')"> <div :label="$t('settings.posts')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.general') }}</h3> <h3>{{ $t('settings.general') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<label for="default-vis"> <label class="setting-item " for="default-vis">
{{ $t('settings.default_vis') }} <span class="setting-label">
{{ ' ' }} <ProfileSettingIndicator :is-profile="true" />
{{ $t('settings.default_vis') }}
</span>
<ScopeSelector <ScopeSelector
class="scope-selector" class="scope-selector setting-control"
:show-all="true" :show-all="true"
:user-default="$store.state.profileConfig.defaultScope" :user-default="$store.state.profileConfig.defaultScope"
:initial-scope="$store.state.profileConfig.defaultScope" :initial-scope="$store.state.profileConfig.defaultScope"
@ -16,7 +18,6 @@
:unstyled="false" :unstyled="false"
uns uns
/> />
<ProfileSettingIndicator :is-profile="true" />
</label> </label>
</li> </li>
<li> <li>

View file

@ -3,7 +3,7 @@
class="data-import-export-tab" class="data-import-export-tab"
:label="$t('settings.data_import_export_tab')" :label="$t('settings.data_import_export_tab')"
> >
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.import_export.title') }}</h3> <h3>{{ $t('settings.import_export.title') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -3,7 +3,7 @@
:label="$t('settings.developer')" :label="$t('settings.developer')"
class="developer-tab" class="developer-tab"
> >
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.version.title') }}</h3> <h3>{{ $t('settings.version.title') }}</h3>
<dl class="setting-list"> <dl class="setting-list">
<dt>{{ $t('settings.version.backend_version') }}</dt> <dt>{{ $t('settings.version.backend_version') }}</dt>

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="filtering-tab"> <div class="filtering-tab">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.filter.mute_filter') }}</h3> <h3>{{ $t('settings.filter.mute_filter') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,25 +1,25 @@
<template> <template>
<div> <div>
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.format_and_language') }}</h3> <h3>{{ $t('settings.format_and_language') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <h4>{{ $t('settings.interfaceLanguage') }}</h4>
<interface-language-switcher <interface-language-switcher
v-model="language" v-model="language"
@update="val => language = val" class="lang-selector"
> @update="val => language = val"
{{ $t('settings.interfaceLanguage') }} />
</interface-language-switcher> <h4>
</li> {{ $t('settings.email_language') }}
<li> {{ ' ' }}
<interface-language-switcher <ProfileSettingIndicator :is-profile="true" />
v-model="emailLanguage" </h4>
:profile="true" <interface-language-switcher
@update:model-value="updateProfile()" v-model="emailLanguage"
> class="lang-selector"
{{ $t('settings.email_language') }} :profile="true"
</interface-language-switcher> @update:model-value="updateProfile()"
</li> />
<li> <li>
<BooleanSetting path="useAbsoluteTimeFormat"> <BooleanSetting path="useAbsoluteTimeFormat">
{{ $t('settings.absolute_time_format') }} {{ $t('settings.absolute_time_format') }}

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('settings.layout')"> <div :label="$t('settings.layout')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.general') }}</h3> <h3>{{ $t('settings.general') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('settings.notifications')"> <div :label="$t('settings.notifications')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.notification_setting_annoyance') }}</h3> <h3>{{ $t('settings.notification_setting_annoyance') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
@ -28,7 +28,7 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.notification_setting_filters') }}</h3> <h3>{{ $t('settings.notification_setting_filters') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
@ -241,7 +241,7 @@
<div <div
v-if="expertLevel > 0" v-if="expertLevel > 0"
class="setting-item" class="setting-section"
> >
<h3>{{ $t('settings.notification_setting_privacy') }}</h3> <h3>{{ $t('settings.notification_setting_privacy') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
@ -279,7 +279,7 @@
</li> </li>
</ul> </ul>
</div> </div>
<div class="setting-item"> <div class="setting-section">
<p>{{ $t('settings.notification_mutes') }}</p> <p>{{ $t('settings.notification_mutes') }}</p>
<p>{{ $t('settings.notification_blocks') }}</p> <p>{{ $t('settings.notification_blocks') }}</p>
</div> </div>

View file

@ -1,5 +1,6 @@
.old-theme-tab { .old-theme-tab {
min-width: var(--themeEditorMinWidth, fit-content); min-width: var(--themeEditorMinWidth, fit-content);
margin: 1em;
.deprecation-warning { .deprecation-warning {
padding: 0.5em; padding: 0.5em;

View file

@ -1,6 +1,6 @@
<template> <template>
<div class="posts-tab"> <div class="posts-tab">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.posts_appearance') }}</h3> <h3>{{ $t('settings.posts_appearance') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>

View file

@ -1,6 +1,6 @@
.profile-tab { .profile-tab {
// overriding global for better look // overriding global for better look
.setting-item.profile-edit { .setting-section.profile-edit {
margin: 0; margin: 0;
h2 { h2 {

View file

@ -1,17 +1,20 @@
<template> <template>
<div class="profile-tab"> <div class="profile-tab">
<div class="setting-item profile-edit"> <div class="setting-section profile-edit">
<UserCard <UserCard
:user-id="user.id" :user-id="user.id"
:editable="true" :editable="true"
:switcher="false" :switcher="false"
/> />
</div> </div>
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.account_privacy') }}</h3> <h3>{{ $t('settings.account_privacy') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<Checkbox v-model="locked"> <Checkbox
class="setting-item"
v-model="locked"
>
{{ $t('settings.lock_account_description') }} {{ $t('settings.lock_account_description') }}
</Checkbox> </Checkbox>
<ProfileSettingIndicator :is-profile="true" /> <ProfileSettingIndicator :is-profile="true" />

View file

@ -1,7 +1,7 @@
<template> <template>
<div <div
v-if="readyInit && settings.available" v-if="readyInit && settings.available"
class="setting-item mfa-settings" class="setting-section mfa-settings"
> >
<div class="mfa-heading"> <div class="mfa-heading">
<h2>{{ $t('settings.mfa.title') }}</h2> <h2>{{ $t('settings.mfa.title') }}</h2>
@ -10,7 +10,7 @@
<div> <div>
<div <div
v-if="!setupInProgress" v-if="!setupInProgress"
class="setting-item" class="setting-section"
> >
<!-- Enabled methods --> <!-- Enabled methods -->
<h3>{{ $t('settings.mfa.authentication_methods') }}</h3> <h3>{{ $t('settings.mfa.authentication_methods') }}</h3>

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('settings.security_tab')"> <div :label="$t('settings.security_tab')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.change_email') }}</h3> <h3>{{ $t('settings.change_email') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
@ -41,7 +41,7 @@
</ul> </ul>
</div> </div>
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.change_password') }}</h3> <h3>{{ $t('settings.change_password') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
@ -90,7 +90,7 @@
</ul> </ul>
</div> </div>
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.account_alias') }}</h3> <h3>{{ $t('settings.account_alias') }}</h3>
<table> <table>
<thead> <thead>
@ -160,7 +160,7 @@
</div> </div>
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.oauth_tokens') }}</h3> <h3>{{ $t('settings.oauth_tokens') }}</h3>
<table class="oauth-tokens"> <table class="oauth-tokens">
<thead> <thead>
@ -191,7 +191,7 @@
</div> </div>
<mfa /> <mfa />
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.move_account') }}</h3> <h3>{{ $t('settings.move_account') }}</h3>
<p>{{ $t('settings.move_account_notes') }}</p> <p>{{ $t('settings.move_account_notes') }}</p>
<div> <div>
@ -234,7 +234,7 @@
</template> </template>
</div> </div>
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('settings.delete_account') }}</h3> <h3>{{ $t('settings.delete_account') }}</h3>
<p v-if="!deletingAccount"> <p v-if="!deletingAccount">
{{ $t('settings.delete_account_description') }} {{ $t('settings.delete_account_description') }}

View file

@ -1,5 +1,6 @@
.StyleTab { .StyleTab {
min-width: var(--themeEditorMinWidth, fit-content); min-width: var(--themeEditorMinWidth, fit-content);
margin: 1em;
.style-control { .style-control {
align-items: baseline; align-items: baseline;
@ -45,7 +46,7 @@
} }
} }
.setting-item.heading { .setting-section.heading {
padding: 0; padding: 0;
} }
@ -84,7 +85,7 @@
} }
} }
.setting-item { .setting-section {
padding-bottom: 0; padding-bottom: 0;
.btn { .btn {

View file

@ -3,7 +3,7 @@
<template> <template>
<div class="StyleTab"> <div class="StyleTab">
<div class="setting-item heading"> <div class="setting-section heading">
<div class="meta-preview"> <div class="meta-preview">
<Preview id="edited-style-preview" /> <Preview id="edited-style-preview" />
<teleport <teleport
@ -82,7 +82,7 @@
<tab-switcher> <tab-switcher>
<div <div
key="component" key="component"
class="setting-item component-editor" class="setting-section component-editor"
:label="$t('settings.style.themes3.editor.component_tab')" :label="$t('settings.style.themes3.editor.component_tab')"
:full-width="true" :full-width="true"
> >
@ -331,7 +331,7 @@
<div <div
key="palette" key="palette"
:label="$t('settings.style.themes3.editor.palette_tab')" :label="$t('settings.style.themes3.editor.palette_tab')"
class="setting-item list-editor palette-editor" class="setting-section list-editor palette-editor"
:full-width="true" :full-width="true"
> >
<label <label

View file

@ -1,7 +1,7 @@
<script src="./virtual_directives_tab.js"></script> <script src="./virtual_directives_tab.js"></script>
<template> <template>
<div class="setting-item list-editor variables-editor"> <div class="setting-section list-editor variables-editor">
<label <label
class="list-select-label" class="list-select-label"
for="variables-selector" for="variables-selector"

View file

@ -1,6 +1,6 @@
<template> <template>
<div :label="$t('admin_dash.tabs.uploads')"> <div :label="$t('admin_dash.tabs.uploads')">
<div class="setting-item"> <div class="setting-section">
<h3>{{ $t('admin_dash.uploads.general') }}</h3> <h3>{{ $t('admin_dash.uploads.general') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>