Merge branch 'admin-tabs-2' into shigusegubu-themes3

This commit is contained in:
Henry Jameson 2025-12-11 18:31:26 +02:00
commit 30966210f4
15 changed files with 258 additions and 111 deletions

View file

@ -381,7 +381,6 @@ nav {
font-size: 1em; font-size: 1em;
font-family: sans-serif; font-family: sans-serif;
font-family: var(--font); font-family: var(--font);
height: 2em;
&.-transparent { &.-transparent {
backdrop-filter: blur(0.125em) contrast(60%); backdrop-filter: blur(0.125em) contrast(60%);
@ -705,13 +704,8 @@ option {
position: relative; position: relative;
display: inline-flex; display: inline-flex;
vertical-align: middle; vertical-align: middle;
min-height: 2em;
align-items: end; align-items: end;
.input {
height: 2em;
}
> *, > *,
> * .button-default { > * .button-default {
--_roundness-left: 0; --_roundness-left: 0;

View file

@ -13,8 +13,8 @@
</label> </label>
<span class="setting-control btn-group"> <span class="setting-control btn-group">
<Select <Select
:name="uniqueId+index"
:id="uniqueId+index" :id="uniqueId+index"
:name="uniqueId+index"
class="language-select" class="language-select"
:model-value="controlledLanguage[index]" :model-value="controlledLanguage[index]"
@update:model-value="val => setLanguageAt(index, val)" @update:model-value="val => setLanguageAt(index, val)"

View file

@ -44,6 +44,7 @@
path=":pleroma.:instance.:instance_thumbnail" path=":pleroma.:instance.:instance_thumbnail"
/> />
</li> </li>
<h4>{{ $t('admin_dash.instance.pwa.manifest') }}</H4>
<li> <li>
<PWAManifestIconsSetting path=":pleroma.:manifest.:icons" /> <PWAManifestIconsSetting path=":pleroma.:manifest.:icons" />
</li> </li>

View file

@ -1,12 +1,69 @@
import { clone } from 'lodash' import { clone } from 'lodash'
import { fileTypeExt } from 'src/services/file_type/file_type.service.js'
import Setting from './setting.js' import Setting from './setting.js'
import Select from 'src/components/select/select.vue'
import Attachment from 'src/components/attachment/attachment.vue'
import MediaUpload from 'src/components/media_upload/media_upload.vue'
export default { export default {
...Setting, ...Setting,
components: {
...Setting.components,
Select,
Attachment,
MediaUpload
},
computed: {
...Setting.computed,
purposeOptions () {
return ['any','monochrome','maskable'].map(value => ({
value,
key: value,
label: this.$t('admin_dash.instance.pwa.icon.' + value)
}))
}
},
methods: { methods: {
...Setting.methods, ...Setting.methods,
optionPresent (option) { attachment (e) {
return this.valueSet.has(option) const path = e[':src']
if (!path) {
return {
mimetype: '',
url: ''
}
}
const url = path.includes('://') ? path : this.$store.state.instance.server + path
return {
mimetype: fileTypeExt(url),
url
}
},
setMediaFile ({ event, index }) {
this.update({
event: {
target: {
value: event.url
},
},
index,
eventType: 'edit',
field: ':src'
})
},
setPurpose ({ event, index }) {
this.update({
event: {
target: {
value: event
},
},
index,
eventType: 'edit',
field: ':purpose'
})
}, },
getValue ({ event, field, index, eventType }) { getValue ({ event, field, index, eventType }) {
switch (eventType) { switch (eventType) {
@ -27,7 +84,6 @@ export default {
const post = this.visibleState.slice(index + 1) const post = this.visibleState.slice(index + 1)
const item = clone(this.visibleState[index]) const item = clone(this.visibleState[index])
const string = event.target.value const string = event.target.value
console.log(item)
if (!string) { if (!string) {
delete item[field] delete item[field]
@ -35,8 +91,6 @@ export default {
item[field] = string item[field] = string
} }
console.log(item)
return [...pre, item, ...post] return [...pre, item, ...post]
} }
} }

View file

@ -7,6 +7,12 @@
class="pwa-label setting-label" class="pwa-label 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>
@ -22,106 +28,130 @@
> >
{{ backendDescriptionDescription + ' ' }} {{ backendDescriptionDescription + ' ' }}
</p> </p>
<ul class="setting-list setting-control"> <div class="setting-control">
<li <ul class="item-list">
v-for="(item, index) in visibleState" <li
:key="index" v-if="visibleState.length === 0"
> class="no_items"
<div class="setting-item"> >
<dl> {{ $t('admin_dash.instance.pwa.no_icons') }}
<dt><code>purpose</code></dt> <button
<dd> v-if="visibleState.length === 0"
<input class="button-default add-button"
class="input string-input" @click="e => update({ eventType: 'add' })"
>
<FAIcon icon="plus" />
</button>
</li>
<li
v-for="(item, index) in visibleState"
:key="index"
>
<div class="icon-element">
<div class="src-field">
<Attachment
class="src-attachment"
:compact="compact"
:attachment="attachment(item)"
size="small"
hide-description
/>
<div class="src-url">
<label for="path">{{ $t('settings.url') }}</label>
<input
:id="path"
class="input string-input"
:disabled="shouldBeDisabled"
:value="item[':src']"
@change="event => update({ event, index, eventType: 'edit', field: ':src' })"
>
</div>
<MediaUpload
ref="mediaUpload"
class="src-upload media-upload-icon"
:class="{ disabled: shouldBeDisabled }" :class="{ disabled: shouldBeDisabled }"
:value="item[':purpose']" normal-button
@change="e => update({ event: e, index, eventType: 'edit', field: ':purpose' })" :accept-types="acceptTypes"
@uploaded="event => setMediaFile({ event, index })"
/>
</div>
<dl>
<dt>{{ $t('admin_dash.instance.pwa.icon.purpose') }}</dt>
<dd>
<Select
:class="{ disabled: shouldBeDisabled }"
:disabled="shouldBeDisabled"
:model-value="item[':purpose']"
@update:model-value="event => setPurpose({ event, index })"
>
<option
v-for="(purpose, index) in purposeOptions"
:key="index"
:value="purpose.value"
>
{{ purpose.label }}
</option>
</Select>
</dd>
<dt><code>sizes</code>{{ $t('admin_dash.instance.pwa.optional') }}</dt>
<dd>
<input
class="input string-input"
:class="{ disabled: shouldBeDisabled }"
:value="item[':sizes']"
@change="e => update({ event: e, index, eventType: 'edit', field: ':sizes' })"
>
</dd>
<dt><code>type</code>{{ $t('admin_dash.instance.pwa.optional') }}</dt>
<dd>
<input
class="input string-input"
:class="{ disabled: shouldBeDisabled }"
:value="item[':type']"
@change="e => update({ event: e, index, eventType: 'edit', field: ':type' })"
>
</dd>
</dl>
<div class="buttons">
<button
v-if="index === visibleState.length - 1"
class="button-default add-button"
@click="e => update({ eventType: 'add' })"
> >
</dd> <FAIcon icon="plus" />
<dt><code>sizes</code></dt> </button>
<dd> <button
<input class="button-default delete-button"
class="input string-input" @click="e => update({ index, eventType: 'remove' })"
:class="{ disabled: shouldBeDisabled }"
:value="item[':sizes']"
@change="e => update({ event: e, index, eventType: 'edit', field: ':sizes' })"
> >
</dd> <FAIcon icon="times" />
<dt><code>src</code></dt> </button>
<dd> </div>
<input
class="input string-input"
:class="{ disabled: shouldBeDisabled }"
:value="item[':src']"
@change="e => update({ event: e, index, eventType: 'edit', field: ':src' })"
>
</dd>
<dt><code>type</code></dt>
<dd>
<input
class="input string-input"
:class="{ disabled: shouldBeDisabled }"
:value="item[':type']"
@change="e => update({ event: e, index, eventType: 'edit', field: ':type' })"
>
</dd>
</dl>
<div class="buttons">
<button
v-if="index === visibleState.length - 1"
class="button-default add-button"
@click="e => update({ eventType: 'add' })"
>
<FAIcon icon="plus" />
</button>
<button
class="button-default delete-button"
@click="e => update({ index, eventType: 'remove' })"
>
<FAIcon icon="times" />
</button>
</div> </div>
</div> </li>
</li> </ul>
</ul> </div>
<ModifiedIndicator
:changed="isChanged"
:onclick="reset"
/>
<ProfileSettingIndicator :is-profile="isProfileSetting" />
<DraftButtons /> <DraftButtons />
</div> </div>
</template> </template>
<script src="./pwa_manifest_icons_setting.js"></script> <script src="./pwa_manifest_icons_setting.js"></script>
<style lang="scss"> <style lang="scss">
.PWAManifestIconsSetting { div.PWAManifestIconsSetting {
&.setting-item { &.setting-item {
display: grid; display: grid;
grid-template-areas: grid-template-areas:
"label control" "label"
"desc control" "desc"
". draft"; "control"
"draft";
grid-template-rows: 2em auto 1fr; grid-template-rows: 2em auto 1fr;
grid-template-columns: 1fr;
} }
.pwa-label.setting-label { .pwa-label.setting-label {
align-self: end; align-self: end;
text-align: left;
}
.setting-description {
text-align: right;
align-self: start;
}
.setting-list {
display: grid;
gap: 0.5em;
}
.setting-item {
display: inline-block;
} }
.buttons { .buttons {
@ -135,16 +165,22 @@
} }
} }
ul {
list-style: none;
display: grid;
grid-template-columns: repeat(auto-fit, 12em);
grid-gap: 2em;
}
dl { dl {
display: inline-grid; display: grid;
grid-template-columns: auto auto; grid-template-columns: 1fr;
gap: 0.5em; margin-top: 0.5em;
gap: 0.25em;
align-items: baseline; align-items: baseline;
dt { dt {
display: inline;
font-weight: 800; font-weight: 800;
text-align: right;
&::after { &::after {
content: ':' content: ':'
@ -152,9 +188,38 @@
} }
dd { dd {
display: inline;
margin: 0 margin: 0
} }
} }
.src-field {
display: grid;
grid-template-columns: auto;
justify-items: center;
gap: 0.5em;
.src-attachment {
width: 10em;
height: 10em;
display: block;
margin-bottom: 0.5em;
}
.src-upload {
display: block;
width: 100%;
}
.src-url {
display: flex;
flex-direction: column;
gap: 0.25em;
width: 100%;
label {
display: block;
}
}
}
} }
</style> </style>

View file

@ -87,13 +87,13 @@
</table> </table>
<Checkbox <Checkbox
:model-value="isSeparate" :model-value="isSeparate"
@update:model-value="event => update({ event: event ? 'join' : 'split', eventType: 'toggleMode' })" @update:model-value="event => update({ event: event ? 'join' : 'split', eventType: 'toggleMode' })"
> >
{{ $t('admin_dash.rate_limit.separate') }} {{ $t('admin_dash.rate_limit.separate') }}
</Checkbox> </Checkbox>
</div> </div>
<DraftButtons /> <DraftButtons />
</div> </div>
</template> </template>
<script src="./rate_setting.js"></script> <script src="./rate_setting.js"></script>

View file

@ -161,7 +161,6 @@ export default {
} }
}, },
backendDescriptionDescription () { backendDescriptionDescription () {
console.log('LOL', this.description)
if (this.description) return this.description if (this.description) return this.description
if (this.realSource !== 'admin') return '' if (this.realSource !== 'admin') return ''
if (this.hideDescription) return null if (this.hideDescription) return null

View file

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

View file

@ -208,10 +208,11 @@
} }
} }
/* stylelint-disable no-descending-specificity */
.setting-item { .setting-item {
grid-template-columns: 1fr min-content; grid-template-columns: 1fr min-content;
column-gap: 0.5em; column-gap: 0.5em;
padding: 1em 1em; padding: 1em;
align-items: center; align-items: center;
.setting-label { .setting-label {
@ -229,6 +230,8 @@
} }
} }
.setting-list:not(.suboptions), .setting-list:not(.suboptions),
.option-list { .option-list {
&.two-column { &.two-column {

View file

@ -4,7 +4,10 @@
<h3>{{ $t('settings.general') }}</h3> <h3>{{ $t('settings.general') }}</h3>
<ul class="setting-list"> <ul class="setting-list">
<li> <li>
<label class="setting-item " for="default-vis"> <label
class="setting-item "
for="default-vis"
>
<span class="setting-label"> <span class="setting-label">
<ProfileSettingIndicator :is-profile="true" /> <ProfileSettingIndicator :is-profile="true" />
{{ $t('settings.default_vis') }} {{ $t('settings.default_vis') }}

View file

@ -54,8 +54,8 @@
</span> </span>
<Select <Select
id="onBlockDefaultActionLv1" id="onBlockDefaultActionLv1"
class="setting-control"
v-model="onBlockDefaultActionLv1" v-model="onBlockDefaultActionLv1"
class="setting-control"
> >
<option <option
v-for="option in muteBlockLv1Options" v-for="option in muteBlockLv1Options"

View file

@ -142,7 +142,9 @@
class="setting-list" class="setting-list"
> >
<li class="select-multiple"> <li class="select-multiple">
<h4 class="label">{{ $t('settings.confirm_dialogs') }}</h4> <h4 class="label">
{{ $t('settings.confirm_dialogs') }}
</h4>
<ul class="option-list"> <ul class="option-list">
<li> <li>
<BooleanSetting path="modalOnRepeat"> <BooleanSetting path="modalOnRepeat">

View file

@ -40,8 +40,8 @@
<li> <li>
<h4> {{ $t('settings.notification_visibility') }}</h4> <h4> {{ $t('settings.notification_visibility') }}</h4>
<p <p
class="sidenote"
v-if="expertLevel > 0" v-if="expertLevel > 0"
class="sidenote"
> >
{{ $t('settings.notification_setting_filters_chrome_push') }} {{ $t('settings.notification_setting_filters_chrome_push') }}
</p> </p>

View file

@ -13,8 +13,8 @@
<li> <li>
<div class="setting-item"> <div class="setting-item">
<Checkbox <Checkbox
class="setting-label setting-control custom-boolean-setting"
v-model="locked" v-model="locked"
class="setting-label setting-control custom-boolean-setting"
> >
<ProfileSettingIndicator :is-profile="true" /> <ProfileSettingIndicator :is-profile="true" />
{{ $t('settings.lock_account_description') }} {{ $t('settings.lock_account_description') }}

View file

@ -1391,6 +1391,32 @@
"always": "Always", "always": "Always",
"never": "Never" "never": "Never"
}, },
"instance": {
"instance": "Instance information",
"pwa": {
"manifest": "PWA Manifest",
"optional": "(optional)",
"no_icons": "No icons defined",
"icon": {
"purpose": "Icon purpose",
"any": "Any",
"monochrome": "Monochrome",
"maskable": "Maskable"
}
},
"branding": "Branding",
"access": "Instance access",
"rich_metadata": "Metadata",
"restrict": {
"header": "Restrict access for anonymous visitors",
"description": "Detailed setting for allowing/disallowing access to certain aspects of API. By default (indeterminate state) it will disallow if instance is not public, ticked checkbox means disallow access even if instance is public, unticked means allow access even if instance is private. Please note that unexpected behavior might happen if some settings are set, i.e. if profile access is disabled posts will show without profile information.",
"timelines": "Timelines access",
"profiles": "User profiles access",
"activities": "Statuses/activities access"
},
":unauthenticated": "Unauthenticated",
":all": "Everyone"
},
"temp_overrides": { "temp_overrides": {
":pleroma": { ":pleroma": {
":connections_pool": { ":connections_pool": {