Merge branch 'shadow-control-2.0' into shigusegubu-themes3

This commit is contained in:
Henry Jameson 2024-09-12 23:12:58 +03:00
commit 820b7015e4
31 changed files with 969 additions and 419 deletions

View file

@ -3,6 +3,19 @@ All notable changes to this project will be documented in this file.
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
## 2.7.1
Bugfix release. Added small optimizations to emoji picker that should make it a bit more responsive, however it needs rather large change to make it more performant which might come in a major release.
### Fixed
- Instance default theme not respected
- Nested panel header having wrong sticky position if navbar height != panel header height
- Toggled buttons having bad contrast (when using v2 theme)
### Changed
- Simplify the OAuth client_name to 'PleromaFE'
- Small optimizations to emoji picker
## 2.7.0
### Known issues

View file

@ -0,0 +1 @@
Simplify the OAuth client_name to 'PleromaFE'

View file

@ -1,6 +1,6 @@
{
"name": "pleroma_fe",
"version": "2.7.0",
"version": "2.7.1",
"description": "Pleroma frontend, the default frontend of Pleroma social network server",
"author": "Pleroma contributors <https://git.pleroma.social/pleroma/pleroma-fe/-/blob/develop/CONTRIBUTORS.md>",
"private": false,

View file

@ -96,6 +96,17 @@ export default {
textOpacity: 0.25,
textOpacityMode: 'blend'
}
},
{
component: 'Icon',
parent: {
component: 'Button',
state: ['disabled']
},
directives: {
textOpacity: 0.25,
textOpacityMode: 'blend'
}
}
]
}

View file

@ -3,6 +3,13 @@
class="checkbox"
:class="{ disabled, indeterminate, 'indeterminate-fix': indeterminateTransitionFix }"
>
<span
v-if="!!$slots.before"
class="label -before"
:class="{ faint: disabled }"
>
<slot name="before" />
</span>
<input
type="checkbox"
class="visible-for-screenreader-only"
@ -14,11 +21,13 @@
<i
class="input -checkbox checkbox-indicator"
:aria-hidden="true"
:class="{ disabled }"
@transitionend.capture="onTransitionEnd"
/>
<span
v-if="!!$slots.default"
class="label"
class="label -after"
:class="{ faint: disabled }"
>
<slot />
</span>
@ -93,14 +102,9 @@ export default {
box-sizing: border-box;
}
&.disabled {
.checkbox-indicator::before,
.label {
opacity: 0.5;
}
.label {
color: var(--text);
.disabled {
.checkbox-indicator::before {
background-color: var(--background);
}
}
@ -121,8 +125,14 @@ export default {
}
}
& > span {
margin-left: 0.5em;
& > .label {
&.-after {
margin-left: 0.5em;
}
&.-before {
margin-right: 0.5em;
}
}
}
</style>

View file

@ -1,12 +1,15 @@
.color-input {
display: inline-flex;
.label {
flex: 1 1 auto;
}
&-field.input {
display: inline-flex;
flex: 0 0 0;
max-width: 9em;
align-items: stretch;
padding: 0.2em 8px;
input {
color: var(--text);
@ -25,6 +28,7 @@
.nativeColor {
cursor: pointer;
flex: 0 0 auto;
padding: 0;
input {
appearance: none;
@ -41,10 +45,10 @@
.invalidIndicator,
.transparentIndicator {
flex: 0 0 2em;
margin: 0 0.5em;
margin: 0.2em 0.5em;
min-width: 2em;
align-self: stretch;
min-height: 1.5em;
min-height: 1.1em;
border-radius: var(--roundness);
}
@ -81,9 +85,17 @@
border-bottom-right-radius: var(--roundness);
}
}
}
.label {
flex: 1 1 auto;
&.disabled,
&:disabled {
.nativeColor input,
.computedIndicator,
.validIndicator,
.invalidIndicator,
.transparentIndicator {
/* stylelint-disable-next-line declaration-no-important */
opacity: 0.25 !important;
}
}
}
}

View file

@ -6,6 +6,7 @@
<label
:for="name"
class="label"
:class="{ faint: !present || disabled }"
>
{{ label }}
</label>
@ -16,10 +17,14 @@
class="opt"
@update:modelValue="$emit('update:modelValue', typeof modelValue === 'undefined' ? fallback : undefined)"
/>
<div class="input color-input-field">
<div
class="input color-input-field"
:class="{ disabled: !present || disabled }"
>
<input
:id="name + '-t'"
class="textColor unstyled"
:class="{ disabled: !present || disabled }"
type="text"
:value="modelValue || fallback"
:disabled="!present || disabled"
@ -51,6 +56,7 @@
type="color"
:value="modelValue || fallback"
:disabled="!present || disabled"
:class="{ disabled: !present || disabled }"
@input="$emit('update:modelValue', $event.target.value)"
>
</label>

View file

@ -10,17 +10,18 @@ const hoverGlow = {
export default {
name: 'Input',
selector: '.input',
variant: {
states: {
hover: ':hover:not(.disabled)',
focused: ':focus-within',
disabled: '.disabled'
},
variants: {
checkbox: '.-checkbox',
radio: '.-radio'
},
states: {
disabled: ':disabled',
hover: ':hover:not(:disabled)',
focused: ':focus-within'
},
validInnerComponents: [
'Text'
'Text',
'Icon'
],
defaultRules: [
{
@ -55,6 +56,34 @@ export default {
directives: {
shadow: [hoverGlow, '--defaultInputBevel']
}
},
{
state: ['disabled'],
directives: {
background: '--parent'
}
},
{
component: 'Text',
parent: {
component: 'Input',
state: ['disabled']
},
directives: {
textOpacity: 0.25,
textOpacityMode: 'blend'
}
},
{
component: 'Icon',
parent: {
component: 'Input',
state: ['disabled']
},
directives: {
textOpacity: 0.25,
textOpacityMode: 'blend'
}
}
]
}

View file

@ -6,6 +6,7 @@
<label
:for="name"
class="label"
:class="{ faint: !present || disabled }"
>
{{ $t('settings.style.common.opacity') }}
</label>
@ -22,6 +23,7 @@
type="number"
:value="modelValue || fallback"
:disabled="!present || disabled"
:class="{ disabled: !present || disabled }"
max="1"
min="0"
step=".05"

View file

@ -6,13 +6,14 @@
<select
:disabled="disabled"
:value="modelValue"
v-bind="attrs"
v-bind="$attrs"
@change="$emit('update:modelValue', $event.target.value)"
>
<slot />
</select>
{{ ' ' }}
<FAIcon
v-if="!$attrs.size && !$attrs.multiple"
class="select-down-icon"
icon="chevron-down"
/>
@ -26,6 +27,11 @@
label.Select {
padding: 0;
&.disabled,
&:disabled {
background-color: var(--background);
}
select {
appearance: none;
background: transparent;
@ -39,6 +45,21 @@ label.Select {
z-index: 1;
height: 2em;
line-height: 16px;
&[multiple],
&[size] {
height: 100%;
padding: 0.2em;
option {
background: transparent;
&.-active {
color: var(--selectionText);
background-color: var(--selectionBackground);
}
}
}
}
.select-down-icon {

View file

@ -314,7 +314,18 @@ export default {
},
set (val) {
if (val) {
this.shadowsLocal[this.shadowSelected] = this.currentShadowFallback.map(_ => Object.assign({}, _))
this.shadowsLocal[this.shadowSelected] = (this.currentShadowFallback || [])
.map(s => ({
name: null,
x: 0,
y: 0,
blur: 0,
spread: 0,
inset: false,
color: '#000000',
alpha: 1,
...s
}))
} else {
delete this.shadowsLocal[this.shadowSelected]
}
@ -328,6 +339,7 @@ export default {
return this.shadowsLocal[this.shadowSelected]
},
set (v) {
console.log('TT', v)
this.shadowsLocal[this.shadowSelected] = v
}
},

View file

@ -25,7 +25,9 @@
margin-bottom: 5px;
.label {
margin-right: 1em;
flex: 1;
line-height: 2;
}
.opt {
@ -48,15 +50,14 @@
&[type="range"] {
flex: 1;
min-width: 3em;
align-self: flex-start;
min-width: 2em;
align-self: center;
margin: 0 0.5em;
}
}
&.disabled {
input,
select {
opacity: 0.5;
&[type="checkbox"] + i {
height: 1.1em;
align-self: center;
}
}
}

View file

@ -123,10 +123,13 @@
</div>
</div>
<!-- eslint-disable vue/no-v-text-v-html-on-component -->
<component :is="'style'" v-html="themeV3Preview"/>
<!-- eslint-enable vue/no-v-text-v-html-on-component -->
<preview id="theme-preview"/>
<!-- eslint-disable vue/no-v-html vue/no-v-text-v-html-on-component -->
<component
:is="'style'"
v-html="themeV3Preview"
/>
<!-- eslint-enable vue/no-v-html vue/no-v-text-v-html-on-component -->
<preview id="theme-preview" />
<div>
<button
@ -934,24 +937,14 @@
</Select>
</div>
<div class="override">
<label
for="override"
class="label"
>
{{ $t('settings.style.shadows.override') }}
</label>
{{ ' ' }}
<input
<Checkbox
id="override"
v-model="currentShadowOverriden"
name="override"
class="input-override"
type="checkbox"
>
<label
class="checkbox-label"
for="override"
/>
{{ $t('settings.style.shadows.override') }}
</Checkbox>
</div>
<button
class="btn button-default"
@ -962,38 +955,10 @@
</div>
<ShadowControl
v-model="currentShadow"
:ready="!!currentShadowFallback"
:separate-inset="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'"
:fallback="currentShadowFallback"
/>
<div v-if="shadowSelected === 'avatar' || shadowSelected === 'avatarStatus'">
<i18n-t
scope="global"
keypath="settings.style.shadows.filter_hint.always_drop_shadow"
tag="p"
>
<code>filter: drop-shadow()</code>
</i18n-t>
<p>{{ $t('settings.style.shadows.filter_hint.avatar_inset') }}</p>
<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-t>
<i18n-t
scope="global"
keypath="settings.style.shadows.filter_hint.inset_classic"
tag="p"
>
<code>box-shadow</code>
</i18n-t>
<p>{{ $t('settings.style.shadows.filter_hint.spread_zero') }}</p>
</div>
</div>
<div
:label="$t('settings.style.fonts._tab_label')"
class="fonts-container"

View file

@ -1,7 +1,9 @@
import ColorInput from '../color_input/color_input.vue'
import OpacityInput from '../opacity_input/opacity_input.vue'
import Select from '../select/select.vue'
import { getCssShadow } from '../../services/theme_data/theme_data.service.js'
import ColorInput from 'src/components/color_input/color_input.vue'
import OpacityInput from 'src/components/opacity_input/opacity_input.vue'
import Select from 'src/components/select/select.vue'
import Checkbox from 'src/components/checkbox/checkbox.vue'
import Popover from 'src/components/popover/popover.vue'
import { getCssShadow, getCssShadowFilter } from '../../services/theme_data/theme_data.service.js'
import { hex2rgb } from '../../services/color_convert/color_convert.js'
import { library } from '@fortawesome/fontawesome-svg-core'
import {
@ -30,16 +32,13 @@ const toModel = (object = {}) => ({
})
export default {
// 'modelValue' and 'Fallback' can be undefined, but if they are
// initially vue won't detect it when they become something else
// therefore i'm using "ready" which should be passed as true when
// data becomes available
props: [
'modelValue', 'fallback', 'ready'
'modelValue', 'fallback', 'separateInset'
],
emits: ['update:modelValue'],
data () {
return {
lightGrid: false,
selectedId: 0,
// TODO there are some bugs regarding display of array (it's not getting updated when deleting for some reason)
cValue: (this.modelValue || this.fallback || []).map(toModel)
@ -48,75 +47,87 @@ export default {
components: {
ColorInput,
OpacityInput,
Select
},
methods: {
add () {
this.cValue.push(toModel(this.selected))
this.selectedId = this.cValue.length - 1
},
del () {
this.cValue.splice(this.selectedId, 1)
this.selectedId = this.cValue.length === 0 ? undefined : Math.max(this.selectedId - 1, 0)
},
moveUp () {
const movable = this.cValue.splice(this.selectedId, 1)[0]
this.cValue.splice(this.selectedId - 1, 0, movable)
this.selectedId -= 1
},
moveDn () {
const movable = this.cValue.splice(this.selectedId, 1)[0]
this.cValue.splice(this.selectedId + 1, 0, movable)
this.selectedId += 1
}
Select,
Checkbox,
Popover
},
beforeUpdate () {
this.cValue = this.modelValue || this.fallback
this.cValue = (this.modelValue || this.fallback || []).map(toModel)
},
computed: {
selected () {
const selected = this.cValue[this.selectedId]
if (selected) {
return { ...selected }
}
return null
},
present () {
return this.selected != null && !this.usingFallback
},
shadowsAreNull () {
return this.modelValue == null
},
anyShadows () {
return this.cValue.length > 0
},
anyShadowsFallback () {
return this.fallback.length > 0
},
selected () {
if (this.ready && this.anyShadows) {
return this.cValue[this.selectedId]
} else {
return toModel({})
}
},
currentFallback () {
if (this.ready && this.anyShadowsFallback) {
return this.fallback[this.selectedId]
} else {
return toModel({})
}
return this.fallback?.[this.selectedId]
},
moveUpValid () {
return this.ready && this.selectedId > 0
return this.selectedId > 0
},
moveDnValid () {
return this.ready && this.selectedId < this.cValue.length - 1
},
present () {
return this.ready &&
typeof this.cValue[this.selectedId] !== 'undefined' &&
!this.usingFallback
return this.selectedId < this.cValue.length - 1
},
usingFallback () {
return typeof this.modelValue === 'undefined'
return this.modelValue == null
},
rgb () {
return hex2rgb(this.selected.color)
},
style () {
return this.ready
? {
boxShadow: getCssShadow(this.fallback)
}
: {}
if (!this.ready) return {}
if (this.separateInset) {
return {
filter: getCssShadowFilter(this.fallback),
boxShadow: getCssShadow(this.fallback, true)
}
}
return {
boxShadow: getCssShadow(this.fallback)
}
}
},
methods: {
updateProperty (prop, value) {
this.cValue[this.selectedId][prop] = value
this.$emit('update:modelValue', this.cValue)
},
add () {
this.cValue.push(toModel(this.selected))
this.selectedId = Math.max(this.cValue.length - 1, 0)
this.$emit('update:modelValue', this.cValue)
},
del () {
this.cValue.splice(this.selectedId, 1)
this.selectedId = this.cValue.length === 0 ? undefined : Math.max(this.selectedId - 1, 0)
this.$emit('update:modelValue', this.cValue)
},
moveUp () {
const movable = this.cValue.splice(this.selectedId, 1)[0]
this.cValue.splice(this.selectedId - 1, 0, movable)
this.selectedId -= 1
this.$emit('update:modelValue', this.cValue)
},
moveDn () {
const movable = this.cValue.splice(this.selectedId, 1)[0]
this.cValue.splice(this.selectedId + 1, 0, movable)
this.selectedId += 1
this.$emit('update:modelValue', this.cValue)
}
}
}

View file

@ -0,0 +1,193 @@
.settings-modal .settings-modal-panel .shadow-control {
display: flex;
flex-wrap: wrap;
justify-content: stretch;
grid-gap: 0.25em;
margin-bottom: 1em;
.shadow-switcher {
order: 1;
flex: 1 0 6em;
min-width: 6em;
margin-right: 0.125em;
display: flex;
flex-direction: column;
.shadow-list {
flex: 1 0 auto;
}
.arrange-buttons {
flex: 0 0 auto;
display: grid;
grid-auto-columns: 1fr;
grid-auto-flow: column;
grid-gap: 0.125em;
margin-top: 0.25em;
.button-default {
margin: 0;
padding: 0;
}
}
}
.shadow-tweak {
order: 3;
flex: 2 0 10em;
min-width: 10em;
margin-left: 0.125em;
margin-right: 0.125em;
/* hack */
.input-boolean {
flex: 1;
display: flex;
.label {
flex: 1;
}
}
.input-string {
flex: 1 0 5em;
}
.id-control {
align-items: stretch;
.shadow-switcher,
.btn {
min-width: 1px;
margin-right: 5px;
}
.btn {
padding: 0 0.4em;
margin: 0 0.1em;
}
}
}
.inset-alert {
padding: 0.25em 0.5em;
}
&.disabled {
.inset-alert {
opacity: 0.2;
}
}
.shadow-preview {
order: 2;
flex: 3 3 15em;
min-width: 10em;
display: grid;
margin-left: 0.125em;
align-self: start;
grid-template-columns: 3em 1fr 3em;
grid-template-rows: 2em 1fr 2em;
grid-template-areas:
". header y-num "
". preview y-slide"
"x-num x-slide . "
"options options options";
grid-gap: 0.5em;
.header {
grid-area: header;
justify-self: center;
align-self: baseline;
line-height: 2;
}
.input-light-grid {
grid-area: options;
justify-self: center;
}
.input-number {
min-width: 2em;
}
.x-shift-number {
grid-area: x-num;
}
.x-shift-slider {
grid-area: x-slide;
height: auto;
align-self: start;
min-width: 10em;
}
.y-shift-number {
grid-area: y-num;
}
.y-shift-slider {
grid-area: y-slide;
writing-mode: vertical-lr;
justify-self: left;
min-height: 10em;
}
.x-shift-slider,
.y-shift-slider {
padding: 0;
}
.preview-window {
--__grid-color1: rgb(102 102 102);
--__grid-color2: rgb(153 153 153);
--__grid-color1-disabled: rgba(102 102 102 / 20%);
--__grid-color2-disabled: rgba(153 153 153 / 20%);
&.-light-grid {
--__grid-color1: rgb(205 205 205);
--__grid-color2: rgb(255 255 255);
--__grid-color1-disabled: rgba(205 205 205 / 20%);
--__grid-color2-disabled: rgba(255 255 255 / 20%);
}
grid-area: preview;
aspect-ratio: 1;
display: flex;
align-items: center;
justify-content: center;
min-width: 10em;
min-height: 10em;
background-color: var(--__grid-color2);
background-image:
linear-gradient(45deg, var(--__grid-color1) 25%, transparent 25%),
linear-gradient(-45deg, var(--__grid-color1) 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, var(--__grid-color1) 75%),
linear-gradient(-45deg, transparent 75%, var(--__grid-color1) 75%);
background-size: 20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0;
border-radius: var(--roundness);
&.disabled {
background-color: var(--__grid-color2-disabled);
background-image:
linear-gradient(45deg, var(--__grid-color1-disabled) 25%, transparent 25%),
linear-gradient(-45deg, var(--__grid-color1-disabled) 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, var(--__grid-color1-disabled) 75%),
linear-gradient(-45deg, transparent 75%, var(--__grid-color1-disabled) 75%);
}
.preview-block {
width: 33%;
height: 33%;
border-radius: var(--roundness);
background: var(--background);
}
}
}
}
.inset-tooltip {
padding: 0.5em;
max-width: 30em;
}

View file

@ -1,91 +1,104 @@
<template>
<div
class="shadow-control"
class="label shadow-control"
:class="{ disabled: !present }"
>
<div class="shadow-preview-container">
<div
:disabled="!present"
class="y-shift-control"
<div class="shadow-preview">
<label
class="header"
:class="{ faint: !present }"
>
{{ $t('settings.style.shadows.offset') }}
</label>
<input
:value="selected?.y"
:disabled="!present"
:class="{ disabled: !present }"
class="input input-number y-shift-number"
type="number"
@input="e => updateProperty('y', e.target.value)"
>
<input
:value="selected?.y"
:disabled="!present"
:class="{ disabled: !present }"
class="input input-range y-shift-slider"
type="range"
max="20"
min="-20"
@input="e => updateProperty('y', e.target.value)"
>
<div
class="preview-window"
:class="{ disabled: !present, '-light-grid': lightGrid }"
>
<input
v-model="selected.y"
:disabled="!present"
class="input input-number"
type="number"
>
<div class="wrap">
<input
v-model="selected.y"
:disabled="!present"
class="input input-range"
type="range"
max="20"
min="-20"
>
</div>
</div>
<div class="preview-window">
<div
class="preview-block"
:style="style"
/>
</div>
<div
<input
:value="selected?.x"
:disabled="!present"
class="x-shift-control"
:class="{ disabled: !present }"
class="input input-number x-shift-number"
type="number"
@input="e => updateProperty('x', e.target.value)"
>
<input
v-model="selected.x"
:disabled="!present"
class="input input-number"
type="number"
>
<div class="wrap">
<input
v-model="selected.x"
:disabled="!present"
class="input input-range"
type="range"
max="20"
min="-20"
>
</div>
</div>
<input
:value="selected?.x"
:disabled="!present"
:class="{ disabled: !present }"
class="input input-range x-shift-slider"
type="range"
max="20"
min="-20"
@input="e => updateProperty('x', e.target.value)"
>
<Checkbox
id="inset"
v-model="lightGrid"
:disabled="!present"
name="lightGrid"
class="input-light-grid"
>
{{ $t('settings.style.shadows.light_grid') }}
</Checkbox>
</div>
<div class="shadow-tweak">
<div
:disabled="usingFallback"
class="id-control style-control"
<div class="shadow-switcher">
<Select
id="shadow-list"
v-model="selectedId"
class="shadow-list"
size="10"
:disabled="shadowsAreNull"
>
<Select
id="shadow-switcher"
v-model="selectedId"
class="shadow-switcher"
:disabled="!ready || usingFallback"
<option
v-for="(shadow, index) in cValue"
:key="index"
:value="index"
:class="{ '-active': index === Number(selectedId) }"
>
<option
v-for="(shadow, index) in cValue"
:key="index"
:value="index"
>
{{ $t('settings.style.shadows.shadow_id', { value: index }) }}
</option>
</Select>
{{ shadow?.name ?? $t('settings.style.shadows.shadow_id', { value: index }) }}
</option>
</Select>
<div
class="id-control arrange-buttons"
>
<button
class="btn button-default"
:disabled="!ready || !present"
@click="del"
:disabled="shadowsAreNull"
@click="add"
>
<FAIcon
fixed-width
icon="times"
icon="plus"
/>
</button>
<button
class="btn button-default"
:disabled="!moveUpValid"
:class="{ disabled: !moveUpValid }"
@click="moveUp"
>
<FAIcon
@ -96,6 +109,7 @@
<button
class="btn button-default"
:disabled="!moveDnValid"
:class="{ disabled: !moveDnValid }"
@click="moveDn"
>
<FAIcon
@ -105,222 +119,193 @@
</button>
<button
class="btn button-default"
:disabled="usingFallback"
@click="add"
:disabled="!present"
:class="{ disabled: !present }"
@click="del"
>
<FAIcon
fixed-width
icon="plus"
icon="times"
/>
</button>
</div>
</div>
<div class="shadow-tweak">
<div
:disabled="!present"
:class="{ disabled: !present }"
class="name-control style-control"
>
<label
for="spread"
class="label"
:class="{ faint: !present }"
>
{{ $t('settings.style.shadows.name') }}
</label>
<input
id="name"
:value="selected?.name"
:disabled="!present"
:class="{ disabled: !present }"
name="name"
class="input input-string"
@input="e => updateProperty('name', e.target.value)"
>
</div>
<div
:disabled="!present"
class="inset-control style-control"
>
<label
for="inset"
class="label"
>
{{ $t('settings.style.shadows.inset') }}
</label>
<input
<Checkbox
id="inset"
v-model="selected.inset"
:value="selected?.inset"
:disabled="!present"
name="inset"
class="input -checkbox input-inset visible-for-screenreader-only"
type="checkbox"
class="input-inset input-boolean"
@input="e => updateProperty('inset', e.target.value)"
>
<label
class="checkbox-label"
for="inset"
:aria-hidden="true"
/>
<template #before>
{{ $t('settings.style.shadows.inset') }}
</template>
</Checkbox>
</div>
<div
:disabled="!present"
:class="{ disabled: !present }"
class="blur-control style-control"
>
<label
for="spread"
class="label"
:class="{ faint: !present }"
>
{{ $t('settings.style.shadows.blur') }}
</label>
<input
id="blur"
v-model="selected.blur"
:value="selected?.blur"
:disabled="!present"
:class="{ disabled: !present }"
name="blur"
class="input input-range"
type="range"
max="20"
min="0"
@input="e => updateProperty('blur', e.target.value)"
>
<input
v-model="selected.blur"
:value="selected?.blur"
:disabled="!present"
:class="{ disabled: !present }"
class="input input-number"
type="number"
min="0"
@input="e => updateProperty('blur', e.target.value)"
>
</div>
<div
:disabled="!present"
class="spread-control style-control"
:class="{ disabled: !present }"
>
<label
for="spread"
class="label"
:class="{ faint: !present }"
>
{{ $t('settings.style.shadows.spread') }}
</label>
<input
id="spread"
v-model="selected.spread"
:value="selected?.spread"
:disabled="!present"
:class="{ disabled: !present }"
name="spread"
class="input input-range"
type="range"
max="20"
min="-20"
@input="e => updateProperty('spread', e.target.value)"
>
<input
v-model="selected.spread"
:value="selected?.spread"
:disabled="!present"
:class="{ disabled: !present }"
class="input input-number"
type="number"
@input="e => updateProperty('spread', e.target.value)"
>
</div>
<ColorInput
v-model="selected.color"
:modelValue="selected?.color"
:disabled="!present"
:label="$t('settings.style.common.color')"
:fallback="currentFallback.color"
:fallback="currentFallback?.color"
:show-optional-tickbox="false"
name="shadow"
@update:modelValue="e => updateProperty('color', e.target.value)"
/>
<OpacityInput
v-model="selected.alpha"
:modelValue="selected?.alpha"
:disabled="!present"
@update:modelValue="e => updateProperty('alpha', e.target.value)"
/>
<i18n-t
scope="global"
keypath="settings.style.shadows.hintV3"
:class="{ faint: !present }"
tag="p"
>
<code>--variable,mod</code>
</i18n-t>
<Popover
trigger="hover"
v-if="separateInset"
>
<template #trigger>
<div
class="inset-alert alert warning"
>
<FAIcon icon="exclamation-triangle" />
&nbsp;
{{ $t('settings.style.shadows.filter_hint.avatar_inset_short') }}
</div>
</template>
<template #content>
<div class="inset-tooltip">
<i18n-t
scope="global"
keypath="settings.style.shadows.filter_hint.always_drop_shadow"
tag="p"
>
<code>filter: drop-shadow()</code>
</i18n-t>
<p>{{ $t('settings.style.shadows.filter_hint.avatar_inset') }}</p>
<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-t>
<i18n-t
scope="global"
keypath="settings.style.shadows.filter_hint.inset_classic"
tag="p"
>
<code>box-shadow</code>
</i18n-t>
<p>{{ $t('settings.style.shadows.filter_hint.spread_zero') }}</p>
</div>
</template>
</Popover>
</div>
</div>
</template>
<script src="./shadow_control.js"></script>
<style lang="scss">
.shadow-control {
display: flex;
flex-wrap: wrap;
justify-content: center;
margin-bottom: 1em;
.shadow-preview-container,
.shadow-tweak {
margin: 5px 6px 0 0;
}
.shadow-preview-container {
flex: 0;
display: flex;
flex-wrap: wrap;
input[type="number"] {
width: 5em;
min-width: 2em;
}
.x-shift-control,
.y-shift-control {
display: flex;
flex: 0;
&[disabled="disabled"] * {
opacity: 0.5;
}
}
.x-shift-control {
align-items: flex-start;
}
.x-shift-control .wrap,
input[type="range"] {
margin: 0;
width: 15em;
height: 2em;
}
.y-shift-control {
flex-direction: column;
align-items: flex-end;
.wrap {
width: 2em;
height: 15em;
}
input[type="range"] {
transform-origin: 1em 1em;
transform: rotate(90deg);
}
}
.preview-window {
flex: 1;
background-color: #999;
display: flex;
align-items: center;
justify-content: center;
background-image:
linear-gradient(45deg, #666 25%, transparent 25%),
linear-gradient(-45deg, #666 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #666 75%),
linear-gradient(-45deg, transparent 75%, #666 75%);
background-size: 20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0;
border-radius: var(--roundness);
.preview-block {
width: 33%;
height: 33%;
border-radius: var(--roundness);
}
}
}
.shadow-tweak {
flex: 1;
min-width: 280px;
.id-control {
align-items: stretch;
.shadow-switcher {
flex: 1;
}
.shadow-switcher,
.btn {
min-width: 1px;
margin-right: 5px;
}
.btn {
padding: 0 0.4em;
margin: 0 0.1em;
}
}
}
}
</style>
<style src="./shadow_control.scss" lang="scss"></style>

View file

@ -870,6 +870,9 @@
"component": "Component",
"override": "Override",
"shadow_id": "Shadow #{value}",
"offset": "Shadow offset",
"light_grid": "Use light checkerboard",
"name": "Name",
"blur": "Blur",
"spread": "Spread",
"inset": "Inset",
@ -877,6 +880,7 @@
"filter_hint": {
"always_drop_shadow": "Warning, this shadow always uses {0} when browser supports it.",
"drop_shadow_syntax": "{0} does not support {1} parameter and {2} keyword.",
"avatar_inset_short": "Separate inset shadow",
"avatar_inset": "Please note that combining both inset and non-inset shadows on avatars might give unexpected results with transparent avatars.",
"spread_zero": "Shadows with spread > 0 will appear as if it was set to zero",
"inset_classic": "Inset shadows will be using {0}"

View file

@ -475,7 +475,8 @@
"interface": "Fasado",
"input": "Enigaj kampoj",
"post": "Teksto de afiŝo",
"postCode": "Egallarĝa teksto en afiŝo (riĉteksto)"
"postCode": "Egallarĝa teksto en afiŝo (riĉteksto)",
"monospace": "Egallarĝa teksto"
},
"family": "Nomo de tiparo",
"size": "Grando (en bilderoj)",
@ -495,6 +496,27 @@
"header_faint": "Tio estas en ordo",
"checkbox": "Mi legetis la kondiĉojn de uzado",
"link": "bela eta ligil"
},
"custom_theme_used": "(Propra haŭto)",
"themes3": {
"hacks": {
"underlay_override_mode_transparent": "Tute forigi (povus rompi iujn haŭtojn)",
"forced_roundness_mode_disabled": "Uzi implicitajn valorojn de haŭto",
"forced_roundness_mode_sharp": "Devigi akrajn randojn",
"forced_roundness_mode_nonsharp": "Devigi ne tiom akrajn randojn (rondigo je 1 bildero)",
"forced_roundness_mode_round": "Devigi rondajn randojn"
},
"font": {
"builtin": {
"serif": "Kalkana",
"sans-serif": "Senkalkana",
"monospace": "Egallarĝa",
"inherit": "Senŝanĝe"
},
"group-local": "Loke instalitaj signoformoj",
"local-unavailable1": "Listo de loke instalitaj signoformoj ne estas disponebla",
"font_list_unavailable": "Ne povis akiri loke instalitajn signoformojn: {error}"
}
}
},
"discoverable": "Permesi trovon de ĉi tiu konto en serĉrezultoj kaj aliaj servoj",
@ -744,7 +766,15 @@
"notification_visibility_reports": "Raportoj",
"notification_setting_ignore_inactionable_seen": "Malatenti legitecon de nereageblaj sciigoj (ŝatoj, ripetoj, ktp.)",
"notification_setting_ignore_inactionable_seen_tip": "Ĉi tio ne markos la sciigojn legitaj, kaj vi ankoraŭ ricevos labortablajn sciigojn pri ili, se vi elektis ricevi tiujn",
"notification_setting_unseen_at_top": "Montri nelegitajn sciigojn super aliaj"
"notification_setting_unseen_at_top": "Montri nelegitajn sciigojn super aliaj",
"appearance": "Aspekto",
"confirm_new_setting": "Ĉu konfirmi novan agordon?",
"confirm_new_question": "Ĉu tio ĉi aspektas ĝuste? La ŝanĝo malfariĝos post 10 sekundoj.",
"revert": "Malfari",
"confirm": "Konfirmi",
"text_size": "Grandeco de teksto kaj fasado",
"emoji_size": "Grandeco de bildosignoj",
"navbar_size": "Grandeco de supra breto"
},
"timeline": {
"collapse": "Maletendi",
@ -999,7 +1029,8 @@
"follows": "Novaj abonoj",
"favs_repeats": "Ripetoj kaj ŝatoj",
"emoji_reactions": "Bildosignaj reagoj",
"reports": "Raportoj"
"reports": "Raportoj",
"statuses": "Abonoj"
},
"errors": {
"storage_unavailable": "Pleroma ne povis aliri deponejon de la foliumilo. Via saluto kaj viaj lokaj agordoj ne estos konservitaj, kaj vi eble renkontos neatenditajn problemojn. Provu permesi kuketojn."
@ -1065,7 +1096,13 @@
"repeat_confirm_title": "Konfirmo de ripeto",
"repeat_confirm_accept_button": "Ripeti",
"repeat_confirm_cancel_button": "Ne ripeti",
"delete_confirm_cancel_button": "Ne forigi"
"delete_confirm_cancel_button": "Ne forigi",
"delete_error": "Eraris forigo de afiŝo: {0}",
"hide_quote": "Kaŝi la cititan afiŝon",
"display_quote": "Montri la cititan afiŝon",
"reaction_count_label": "{num} persono reagis | {num} personoj reagis",
"invisible_quote": "Citita afiŝo ne disponeblas: {link}",
"quotes": "Citaĵoj"
},
"time": {
"years_short": "{0}j",
@ -1267,7 +1304,9 @@
"save_meta": "Konservi pridatumojn",
"description": "Priskribo",
"homepage": "Hejmpaĝo",
"save": "Konservi"
"save": "Konservi",
"revert": "Malfari",
"share": "Kunhavigi"
},
"tabs": {
"emoji": "Bildosignoj",
@ -1283,7 +1322,8 @@
"header": "Limigi aliron por sennomaj vizitantoj",
"timelines": "Aliro al historioj"
},
"access": "Aliro al nodo"
"access": "Aliro al nodo",
"kocaptcha": "Agordo de KoCaptcha"
},
"limits": {
"users": "Limoj de profiloj de uzantoj",
@ -1304,10 +1344,21 @@
":instance": {
":public": {
"label": "Nodo estas publika"
},
":background_image": {
"label": "Fonbildo",
"description": "Fonbildo (uzota ĉefe de PleromaFE)"
},
":description_limit": {
"description": "Limo de signoj por priskriboj de kunsendaĵoj",
"label": "Limo"
}
}
}
},
"commit_all": "Konservi ĉion"
"commit_all": "Konservi ĉion",
"captcha": {
"kocaptcha": "KoCaptcha"
}
}
}

View file

@ -131,7 +131,8 @@
"mobile_notifications_close": "Fermer les notifications",
"search_close": "Fermer la barre de recherche",
"announcements": "Annonces",
"mobile_notifications_mark_as_seen": "Marquer tout comme vu"
"mobile_notifications_mark_as_seen": "Marquer tout comme vu",
"quotes": "Citations"
},
"notifications": {
"broken_favorite": "Message inconnu, recherche en cours…",

View file

@ -565,7 +565,8 @@
"interface": "インターフェース",
"input": "入力欄",
"post": "投稿",
"postCode": "等幅 (投稿がリッチテキストであるとき)"
"postCode": "等幅 (投稿がリッチテキストであるとき)",
"monospace": "等幅テキスト"
},
"family": "フォント名",
"size": "大きさ (px)",
@ -585,7 +586,43 @@
"header_faint": "エラーではありません",
"checkbox": "利用規約を読みました",
"link": "ハイパーリンク"
}
},
"themes2_outdated": "V2テーマのエディタは徐々に廃止され、最終的には新しいV3テーマのものに置き換えられる予定です。現状はまだ動作するはずですが、正しく動作する保証はありません。",
"themes3": {
"font": {
"group-local": "端末上にインストールされたフォント",
"local-unavailable2": "フォント名を直接指定してください",
"lookup_local_fonts": "端末上のフォントの一覧から選ぶ",
"group-builtin": "ブラウザのデフォルトフォント",
"builtin": {
"serif": "明朝体 (Serif)",
"sans-serif": "ゴシック体 (Sans-serif)",
"monospace": "等幅 (Monospace)",
"inherit": "変更しない"
},
"local-unavailable1": "端末上のフォントの一覧が取得できません",
"font_list_unavailable": "端末上のフォントの一覧が取得できません: {error}",
"enter_manually": "フォント名を直接入力する",
"entry": "{fontFamily}を入力",
"select": "フォントを選択"
},
"hacks": {
"underlay_overrides": "背景表示",
"underlay_override_mode_none": "テーマのデフォルトを使用する",
"underlay_override_mode_opaque": "単色に置き換える",
"underlay_override_mode_transparent": "非表示にする (テーマによっては表示が壊れる可能性があります)",
"force_interface_roundness": "インターフェースの角丸設定",
"forced_roundness_mode_disabled": "テーマのデフォルトを使用する",
"forced_roundness_mode_sharp": "角ばったデザインを強制する",
"forced_roundness_mode_nonsharp": "若干の角丸(1px分丸める)デザインを強制する",
"forced_roundness_mode_round": "角丸デザインを強制する"
},
"define": "上書き"
},
"custom_theme_used": "(カスタムテーマ)",
"appearance_tab_note": "以下の設定はテーマには反映されないため、エクスポートしたテーマの見た目は今見えているものと異なる可能性があります",
"update_preview": "プレビューを更新",
"interface_font_user_override": "フォント設定の上書き"
},
"version": {
"title": "バージョン",
@ -802,7 +839,19 @@
}
},
"hide_scrobbles_after": "これより古いScrobbleを表示しない:",
"force_theme_recompilation_debug": "テーマのキャッシュを無効化し、起動の度にコンパイルし直す (デバッグ用)"
"force_theme_recompilation_debug": "テーマのキャッシュを無効化し、起動の度にコンパイルし直す (デバッグ用)",
"scale_and_layout": "インターフェースの表示サイズとレイアウト",
"appearance": "見た目",
"confirm_new_setting": "設定を適用しますか?",
"confirm_new_question": "これで問題ありませんか10秒間操作がない場合、元の設定に戻ります。",
"revert": "元に戻す",
"confirm": "適用",
"text_size": "フォントサイズ",
"text_size_tip2": "{0}以外に設定すると見た目が壊れてしまう場合があります",
"emoji_size": "絵文字のサイズ",
"navbar_size": "トップバーのサイズ",
"panel_header_size": "パネルヘッダーのサイズ",
"notification_visibility_statuses": "購読"
},
"time": {
"day": "{0}日",
@ -941,7 +990,9 @@
"open_gallery": "メディアビューアで開く",
"status_history": "編集履歴",
"sensitive_muted": "閲覧注意な投稿のためミュートされています",
"load_error": "投稿の読み込みに失敗しました: {error}"
"load_error": "投稿の読み込みに失敗しました: {error}",
"loading": "読み込み中…",
"quotes": "引用"
},
"user_card": {
"approve": "承認",

View file

@ -22,6 +22,7 @@ const languages = [
'nl',
'oc',
'pl',
'pdc',
'pt',
'ro',
'ru',

1
src/i18n/pdc.json Normal file
View file

@ -0,0 +1 @@
{}

View file

@ -24,7 +24,10 @@
"media_removal": "Usuwanie multimediów",
"media_removal_desc": "Ta instancja usuwa multimedia z postów od wymienionych instancji:",
"media_nsfw": "Multimedia ustawione jako wrażliwe",
"media_nsfw_desc": "Ta instancja wymusza, by multimedia z wymienionych instancji były ustawione jako wrażliwe:"
"media_nsfw_desc": "Ta instancja wymusza, by multimedia z wymienionych instancji były ustawione jako wrażliwe:",
"instance": "Instancja",
"reason": "Powód",
"not_applicable": "Nie dotyczy"
}
},
"staff": "Administracja"
@ -861,5 +864,13 @@
},
"errors": {
"storage_unavailable": "Pleroma nie mogła uzyskać dostępu do pamięci masowej przeglądarki. Twój login lub lokalne ustawienia nie zostaną zapisane i możesz napotkać problemy. Spróbuj włączyć ciasteczka."
},
"announcements": {
"page_header": "Ogłoszenia",
"title": "Ogłoszenie",
"mark_as_read_action": "Oznacz jako przeczytane",
"post_placeholder": "Wprowadź treść ogłoszenia…",
"close_error": "Zamknij",
"delete_action": "Usuń"
}
}

View file

@ -25,6 +25,7 @@ const messages = {
oc: require('../lib/notification-i18n-loader.js!./oc.json'),
pl: require('../lib/notification-i18n-loader.js!./pl.json'),
pt: require('../lib/notification-i18n-loader.js!./pt.json'),
pdc: require('../lib/notification-i18n-loader.js!./pdc.json'),
ro: require('../lib/notification-i18n-loader.js!./ro.json'),
ru: require('../lib/notification-i18n-loader.js!./ru.json'),
sk: require('../lib/notification-i18n-loader.js!./sk.json'),

View file

@ -130,20 +130,22 @@
"edit_nav_mobile": "自定义导航栏",
"edit_pinned": "编辑固定的项目",
"mobile_sidebar": "切换移动设备侧栏",
"search_close": "关闭搜索栏"
"search_close": "关闭搜索栏",
"mobile_notifications_mark_as_seen": "全部已阅",
"quotes": "引用"
},
"notifications": {
"broken_favorite": "未知的状态,正在搜索中…",
"favorited_you": "喜欢了的状态",
"followed_you": "关注了",
"favorited_you": "喜欢了的状态",
"followed_you": "关注了",
"load_older": "加载更早的通知",
"notifications": "通知",
"read": "已阅!",
"repeated_you": "转发了的状态",
"repeated_you": "转发了的状态",
"no_more_notifications": "没有更多的通知",
"reacted_with": "作出了 {0} 的应",
"reacted_with": "作出了 {0} 的应",
"migrated_to": "迁移到了",
"follow_request": "想要关注",
"follow_request": "想要关注",
"error": "取得通知时发生错误:{0}",
"poll_ended": "投票结束了",
"submitted_report": "提交举报",
@ -152,7 +154,8 @@
"unread_follow_requests": "{num} 个新关注请求",
"configuration_tip": "可以在 {theSettings} 里定制什么会显示在这里。{dismiss}",
"configuration_tip_settings": "设置",
"configuration_tip_dismiss": "不再显示"
"configuration_tip_dismiss": "不再显示",
"subscribed_status": "已发送"
},
"polls": {
"add_poll": "增加投票",
@ -179,11 +182,12 @@
"load_older": "加载更早的互动",
"moves": "用户迁移",
"reports": "举报",
"emoji_reactions": "表情回应"
"emoji_reactions": "表情回应",
"statuses": "订阅"
},
"post_status": {
"new_status": "发布新状态",
"account_not_locked_warning": "你的帐号没有 {0}。任何人都可以关注你并浏览你的上锁内容。",
"account_not_locked_warning": "您的帐号没有 {0}。任何人都可以关注您并浏览您的上锁内容。",
"account_not_locked_warning_link": "上锁",
"attachments_sensitive": "标记附件为敏感内容",
"content_type": {
@ -199,12 +203,12 @@
"posting": "发送中",
"scope_notice": {
"public": "本条内容可以被所有人看到",
"private": "关注的人才能看到本条内容",
"private": "关注的人才能看到本条内容",
"unlisted": "本条内容既不在公共时间线,也不会在所有已知网络上可见"
},
"scope": {
"direct": "私信 - 只发送给被提及的用户",
"private": "仅关注者 - 只有关注了的人能看到",
"private": "仅关注者 - 只有关注了的人能看到",
"public": "公共 - 发送到公共时间轴",
"unlisted": "不公开 - 不会发送到公共时间轴"
},
@ -212,7 +216,7 @@
"preview": "预览",
"media_description": "媒体描述",
"media_description_error": "更新媒体失败,请重试",
"empty_status_error": "不能发布没有内容、没有附件的发文",
"empty_status_error": "不能发布没有内容、没有附件的帖子",
"post": "发送",
"edit_remote_warning": "其它远程实例可能不支持编辑并且无法接收您的帖子的最新版本。",
"edit_unsupported_warning": "Pleroma 不支持对提及或投票进行编辑。",
@ -233,7 +237,7 @@
"new_captcha": "点击图片获取新的验证码",
"username_placeholder": "例如lain",
"fullname_placeholder": "例如:岩仓玲音",
"bio_placeholder": "例如:\n你好我是玲音。\n我是一个住在日本郊区的动画少女。可能在 Wired 见过我。",
"bio_placeholder": "例如:\n你好我是玲音。\n我是一个住在日本郊区的动画少女。可能在 Wired 见过我。",
"validations": {
"username_required": "不能留空",
"fullname_required": "不能留空",
@ -247,7 +251,7 @@
"reason_placeholder": "此实例的注册需要手动批准。\n请让管理员知道您为什么想要注册。",
"reason": "注册理由",
"register": "注册",
"email_language": "想从服务器收到什么语言的邮件?",
"email_language": "想从服务器收到什么语言的邮件?",
"bio_optional": "介绍(可选)",
"email_optional": "电子邮件(可选)",
"birthday": "生日:",
@ -289,7 +293,7 @@
"background": "背景",
"bio": "简介",
"block_export": "屏蔽名单导出",
"block_export_button": "导出的屏蔽名单到一个 csv 文件",
"block_export_button": "导出的屏蔽名单到一个 csv 文件",
"block_import": "屏蔽名单导入",
"block_import_error": "导入屏蔽名单出错",
"blocks_imported": "屏蔽名单导入成功!需要一点时间来处理。",
@ -310,10 +314,10 @@
"current_profile_banner": "您当前的横幅图片",
"data_import_export_tab": "数据导入/导出",
"default_vis": "默认可见范围",
"delete_account": "删除账",
"delete_account_description": "永久删除的帐号和所有数据。",
"delete_account_error": "删除账户时发生错误,如果一直删除不了,请联系实例管理员。",
"delete_account_instructions": "在下面输入您的密码来确认删除账。",
"delete_account": "删除账",
"delete_account_description": "永久删除的帐号和所有数据。",
"delete_account_error": "删除账号时发生错误。如果一直删除不了,请联系实例管理员。",
"delete_account_instructions": "在下面输入您的密码来确认删除账。",
"avatar_size_instruction": "推荐的头像图片最小尺寸为 150x150 像素。",
"export_theme": "导出预置主题",
"filtering": "过滤器",
@ -388,11 +392,11 @@
"autohide_floating_post_button": "自动隐藏新帖子的按钮(移动设备)",
"saving_err": "保存设置时发生错误",
"saving_ok": "设置已保存",
"search_user_to_block": "搜索想屏蔽的用户",
"search_user_to_mute": "搜索想要隐藏的用户",
"search_user_to_block": "搜索想屏蔽的用户",
"search_user_to_mute": "搜索想要隐藏的用户",
"security_tab": "安全",
"scope_copy": "回复时复制可见范围(私信中永远会复制)",
"minimal_scopes_mode": "使发文可见范围的选项最少化",
"minimal_scopes_mode": "使帖子可见范围的选项最小化",
"set_new_avatar": "设置新头像",
"set_new_profile_background": "设置新的个人资料背景",
"set_new_profile_banner": "设置新的横幅图片",
@ -402,7 +406,7 @@
"subject_line_email": "类似电子邮件: \"re: 主题\"",
"subject_line_mastodon": "类似 mastodon: 与原主题相同",
"subject_line_noop": "不要复制",
"post_status_content_type": "发文状态内容类型",
"post_status_content_type": "帖子状态内容类型",
"stop_gifs": "鼠标悬停时播放GIF",
"streaming": "滚动到顶部时自动推送新内容",
"text": "文本",
@ -546,7 +550,8 @@
"interface": "界面",
"input": "输入框",
"post": "发帖文字",
"postCode": "帖子中使用等间距文字(富文本)"
"postCode": "帖子中使用等间距文字(富文本)",
"monospace": "等宽文本"
},
"family": "字体名称",
"size": "大小 (in px)",
@ -566,7 +571,43 @@
"header_faint": "这很正常",
"checkbox": "我已经浏览了条款及细则",
"link": "一个棒棒的小小链接"
}
},
"custom_theme_used": "(自定义主题)",
"themes2_outdated": "V2 主题的编辑器正在被淘汰并且最终会被新的利用 V3 主题引擎的编辑器取代。但是体验有可能会被降级并且不稳定。",
"appearance_tab_note": "在这个标签页的更改不会影响使用的主题,所以导出的主题会和界面显示的主题不同",
"update_preview": "更新预览",
"themes3": {
"define": "覆盖",
"hacks": {
"underlay_overrides": "更改底色",
"underlay_override_mode_none": "主题默认",
"underlay_override_mode_opaque": "使用单色更改",
"underlay_override_mode_transparent": "完全移除(有可能破外一些主题)",
"force_interface_roundness": "覆盖界面圆角/锐度",
"forced_roundness_mode_disabled": "使用主题默认",
"forced_roundness_mode_sharp": "强制使用锐利边角",
"forced_roundness_mode_nonsharp": "强制使用不太锋利1px 圆角)的边角",
"forced_roundness_mode_round": "强制使用圆角"
},
"font": {
"group-builtin": "浏览器默认字体",
"builtin": {
"serif": "衬线字体",
"sans-serif": "无衬线字体",
"monospace": "等宽字体",
"inherit": "未更改"
},
"group-local": "本地字体",
"local-unavailable1": "不可用的本地字体列表",
"local-unavailable2": "使用手动输入来指定自定义字体",
"font_list_unavailable": "无法找到本地字体:{error}",
"lookup_local_fonts": "加载这台电脑的本地字体列表",
"enter_manually": "手动输入字体名称",
"entry": "输入 {fontFamily}",
"select": "选择字体"
}
},
"interface_font_user_override": "覆盖使用的主题/浏览器字体"
},
"version": {
"title": "版本",
@ -582,12 +623,12 @@
"notification_setting_privacy_option": "在通知推送中隐藏发送者和内容",
"notification_setting_privacy": "隐私",
"hide_follows_count_description": "不显示关注数",
"notification_visibility_emoji_reactions": "互动",
"notification_visibility_emoji_reactions": "回应",
"notification_visibility_moves": "用户迁移",
"new_email": "新邮箱",
"emoji_reactions_on_timeline": "在时间线上显示表情符号互动",
"emoji_reactions_on_timeline": "在时间线上显示表情符号回应",
"notification_setting_hide_notification_contents": "隐藏推送通知中的发送者与内容信息",
"notification_setting_block_from_strangers": "屏蔽来自没有关注的用户的通知",
"notification_setting_block_from_strangers": "屏蔽来自没有关注的用户的通知",
"type_domains_to_mute": "搜索需要隐藏的域名",
"useStreamingApi": "实时接收帖子和通知",
"user_mutes": "用户",
@ -618,15 +659,15 @@
"mutes_imported": "隐藏名单导入成功!处理它们将需要一段时间。",
"mute_import_error": "导入隐藏名单出错",
"mute_import": "隐藏名单导入",
"mute_export_button": "导出的隐藏名单到一个 csv 文件",
"mute_export_button": "导出的隐藏名单到一个 csv 文件",
"mute_export": "隐藏名单导出",
"hide_wallpaper": "隐藏实例壁纸",
"setting_changed": "与默认设置不同",
"more_settings": "更多设置",
"sensitive_by_default": "默认标记发文为敏感内容",
"sensitive_by_default": "默认标记帖子为敏感内容",
"reply_visibility_self_short": "只显示对我本人的回复",
"reply_visibility_following_short": "显示对我关注的人的回复",
"hide_all_muted_posts": "不显示已隐藏的发文",
"hide_all_muted_posts": "不显示已隐藏的帖子",
"hide_media_previews": "隐藏媒体预览",
"word_filter": "词语过滤",
"save": "保存更改",
@ -664,14 +705,14 @@
"move_account_target": "目标账号(例如 {example}",
"moved_account": "账号移动好了。",
"move_account_error": "移动账号时出错:{error}",
"setting_server_side": "这个设置是捆绑到的个人资料的,能影响所有会话和客户端",
"setting_server_side": "这个设置是捆绑到的个人资料的,能影响所有会话和客户端",
"post_look_feel": "文章的样子跟感受",
"email_language": "从服务器收邮件的语言",
"account_backup_description": "这个允许下载一份账号信息和文章的存档,但是现在还不能导入到 Pleroma 账号里。",
"account_backup_description": "这个允许下载一份账号信息和文章的存档,但是现在还不能导入到 Pleroma 账号里。",
"backup_not_ready": "备份还没准备好。",
"add_backup_error": "添加新备份时出错:{error}",
"add_alias_error": "添加别名时出错:{error}",
"move_account_notes": "如果你想把账号移动到别的地方,你必须去目标账号,然后加一个指向这里的别名。",
"move_account_notes": "如果您想把账号移动到别的地方,您必须去目标账号,然后加一个指向这里的别名。",
"wordfilter": "词语过滤器",
"user_profiles": "用户资料",
"third_column_mode_notifications": "通知栏",
@ -685,7 +726,7 @@
},
"hide_favorites_description": "不显示我的喜欢列表(人们仍然会收到通知)",
"third_column_mode": "当有足够的空间时,显示第三栏包含",
"third_column_mode_postform": "主要的发文形式和导航",
"third_column_mode_postform": "主要的帖子形式和导航",
"columns": "分栏",
"user_popover_avatar_overlay": "在用户头像上显示用户弹出窗口",
"navbar_column_stretch": "延伸导航栏至分栏宽度",
@ -705,12 +746,12 @@
"max_depth_in_thread": "默认显示同主题帖子中的最大层数",
"hide_wordfiltered_statuses": "隐藏经过词语过滤的状态",
"hide_muted_threads": "不显示已隐藏的同主题帖子",
"notification_visibility_polls": "所投的投票的结束于",
"notification_visibility_polls": "所投的投票的结束于",
"tree_advanced": "允许在树状视图中进行更灵活的导航",
"tree_fade_ancestors": "以模糊的文字显示当前状态的上级",
"conversation_display_linear": "线性样式",
"mention_link_fade_domain": "淡化域名(例如:{'@'}example.org 中的 {'@'}foo{'@'}example.org",
"mention_link_bolden_you": "当你被提及时突出显示提及你",
"mention_link_bolden_you": "当您被提及时突出显示提及您",
"user_popover_avatar_action": "弹出式头像点击动作",
"user_popover_avatar_action_zoom": "缩放头像",
"user_popover_avatar_action_close": "关闭弹出窗口",
@ -750,7 +791,7 @@
"url": "URL",
"preview": "预览",
"commit_value": "保存",
"commit_value_tooltip": "当前值未保存,请按此按钮以提交的修改",
"commit_value_tooltip": "当前值未保存,请按此按钮以提交的修改",
"reset_value": "重置",
"reset_value_tooltip": "重置草稿",
"hard_reset_value": "硬重置",
@ -760,7 +801,52 @@
"notification_extra_chats": "显示未读聊天",
"notification_extra_announcements": "显示未读公告",
"notification_extra_follow_requests": "显示新的关注请求",
"notification_extra_tip": "显示额外通知的定制提示"
"notification_extra_tip": "显示额外通知的定制提示",
"notification_visibility_follow_requests": "关注请求",
"notification_visibility_reports": "举报",
"mute_sensitive_posts": "隐藏敏感帖子",
"notification_visibility_in_column": "在侧栏/菜单显示通知菜单",
"notification_visibility_native_notifications": "显示本地通知",
"units": {
"time": {
"m": "分钟",
"s": "秒",
"h": "小时",
"d": "天"
}
},
"hide_scrobbles_after": "隐藏比这个时间更早的 scrobble",
"notification_setting_ignore_inactionable_seen": "忽略无法回复通知(喜欢,转发等)的已阅状态",
"notification_setting_unseen_at_top": "将未读通知置顶",
"notification_setting_ignore_inactionable_seen_tip": "如果您继续,这将不会标记这些通知为已读,并且您仍会接收到桌面推送通知",
"actor_type": "账号:",
"actor_type_description": "将您的账号标记为组会使其转发所有提及它的状态。",
"actor_type_Person": "正常用户",
"actor_type_Service": "机器人",
"actor_type_Group": "组",
"hide_actor_type_indication": "隐藏帖子中账号类型(机器人,组等)的表示",
"notification_setting_annoyance": "烦扰",
"notification_setting_drawer_marks_as_seen": "关闭菜单(移动端)来标记全部通知为已阅",
"enable_web_push_always_show_tip": "一些浏览器ChromiumChrome需要推送信息才能显示通知否则会显示“网页在背景发生了更改”的通知勾选这个选项可以防止这种通知显示因为 Chrome 在标签页激活时会隐藏网页推送通知。可能会在其他浏览器中显示双重通知。",
"enable_web_push_always_show": "总是显示网页推送通知",
"force_theme_recompilation_debug": "禁用主题缓存,强制在每次启动时重新编译(调试)",
"notification_setting_filters_chrome_push": "在一些浏览器中Chrome有可能无法完全按照类型过滤通过推送传递的通知",
"hide_scrobbles": "隐藏 scrobble",
"appearance": "外观",
"confirm_new_setting": "确认新的设置?",
"confirm_new_question": "是否保留这些设置?设置将在 10 秒后还原。",
"revert": "恢复",
"confirm": "确定",
"text_size": "文字与界面大小",
"text_size_tip": "用 {0} 作为绝对值,{1} 会根据浏览器默认文字大小进行缩放。",
"text_size_tip2": "{0} 之外的值可能会破坏一些功能和主题",
"emoji_size": "表情符号大小",
"navbar_size": "顶栏大小",
"panel_header_size": "面板标题大小",
"visual_tweaks": "细微外观调整",
"theme_debug": "显示当遇到透明背景时背景主题引擎的假设(调试)",
"scale_and_layout": "界面大小与布局",
"notification_visibility_statuses": "订阅"
},
"time": {
"day": "{0} 天",
@ -856,7 +942,7 @@
"nsfw": "NSFW",
"external_source": "外部来源",
"expand": "展开",
"you": "",
"you": "",
"plus_more": "还有 {number} 个",
"many_attachments": "文章有 {number} 个附件",
"collapse_attachments": "折起附件",
@ -896,7 +982,12 @@
"reaction_count_label": "{num} 人作出了表情回应",
"invisible_quote": "引用的状态不可用:{link}",
"hide_quote": "隐藏引用的状态",
"display_quote": "显示引用的状态"
"display_quote": "显示引用的状态",
"quotes": "引用",
"sensitive_muted": "正在隐藏敏感内容",
"loading": "加载中...",
"load_error": "无法加载动态:{error}",
"more_actions": "状态的更多动作"
},
"user_card": {
"approve": "核准",
@ -911,14 +1002,14 @@
"followees": "正在关注",
"followers": "关注者",
"following": "正在关注!",
"follows_you": "关注了",
"its_you": "就是",
"follows_you": "关注了",
"its_you": "就是",
"media": "媒体",
"mute": "隐藏",
"muted": "已隐藏",
"per_day": "每天",
"remote_follow": "跨站关注",
"report": "",
"report": "报",
"statuses": "状态",
"subscribe": "订阅",
"unsubscribe": "退订",
@ -945,7 +1036,7 @@
"disable_any_subscription": "完全禁止关注用户",
"quarantine": "不许帖子传入别站",
"delete_user": "删除用户",
"delete_user_data_and_deactivate_confirmation": "这将永久删除该账户的数据并停用该账户。你完全确定吗?"
"delete_user_data_and_deactivate_confirmation": "这将永久删除该账号的数据并停用该账号。您完全确定吗?"
},
"hidden": "已隐藏",
"show_repeats": "显示转发",
@ -993,7 +1084,8 @@
"note_blank": "(空)",
"edit_note": "编辑备注",
"edit_note_apply": "应用",
"edit_note_cancel": "取消"
"edit_note_cancel": "取消",
"group": "组"
},
"user_profile": {
"timeline_title": "用户时间线",
@ -1001,10 +1093,10 @@
"profile_loading_error": "抱歉,载入个人资料时出错。"
},
"user_reporting": {
"title": " {0}",
"add_comment_description": "此会发送给您的实例监察员。您可以在下面提供更多详细信息解释报的缘由:",
"title": "报 {0}",
"add_comment_description": "此报会发送给您的实例监察员。您可以在下面提供更多详细信息解释报的缘由:",
"additional_comments": "其它信息",
"forward_description": "这个账号来自另一个服务器。是否同时发送一份副本到那里?",
"forward_description": "这个账号来自另一个服务器。是否同时发送一份报副本到那里?",
"forward_to": "转发 {0}",
"submit": "提交",
"generic_error": "当处理您的请求时,发生了一个错误。"
@ -1020,7 +1112,7 @@
"favorite": "喜欢",
"user_settings": "用户设置",
"reject_follow_request": "拒绝关注请求",
"add_reaction": "添加互动",
"add_reaction": "添加回应",
"bookmark": "书签",
"accept_follow_request": "接受关注请求",
"toggle_expand": "展开或折叠通知以显示帖子全文",
@ -1090,7 +1182,8 @@
"smileys-and-emotion": "表情与情感"
},
"regional_indicator": "地区指示符 {letter}",
"unpacked": "未分组的表情符号"
"unpacked": "未分组的表情符号",
"hide_custom_emoji": "隐藏自定义表情符号"
},
"about": {
"mrf": {
@ -1157,7 +1250,7 @@
"chats": "聊天",
"delete": "删除",
"message_user": "发消息给 {nickname}",
"you": ""
"you": ""
},
"announcements": {
"page_header": "公告",
@ -1198,8 +1291,8 @@
"update_changelog": "关于变化的更多细节,请参见 {theFullChangelog} 。",
"update_changelog_here": "完整的更新日志",
"big_update_title": "请忍耐一下",
"big_update_content": "我们已经有一段时间没有发布发行版,所以事情的外观和感觉可能与习惯的不一样。",
"update_bugs": "请在 {pleromaGitlab} 上报告任何问题和bug因为我们已经改变了很多虽然我们进行了彻底的测试并且自己使用了开发版本但我们可能错过了一些东西。我们欢迎你对你可能遇到的问题或如何改进Pleroma和Pleroma-FE提出反馈和建议。",
"big_update_content": "我们已经有一段时间没有发布发行版,所以事情的外观和感觉可能与习惯的不一样。",
"update_bugs": "请在 {pleromaGitlab} 上报告任何问题和 bug因为我们改变了软件中的很多东西虽然我们进行了彻底的测试并且我们自己使用开发版本但我们可能错过了一些东西。我们欢迎您对您可能遇到的问题或如何改进 Pleroma 和 Pleroma-FE 提出反馈和建议。",
"art_by": "{linkToArtist} 的作品"
},
"lists": {
@ -1232,13 +1325,14 @@
"nodb": "无数据库配置",
"instance": "实例",
"limits": "限制",
"frontends": "前端"
"frontends": "前端",
"emoji": "表情符号"
},
"nodb": {
"heading": "数据库配置已禁用",
"documentation": "文档",
"text2": "大多数配置选项将不可用。",
"text": "需要修改后端配置文件,以便将 {property} 设置为 {value},更多内容请参见 {documentation}。"
"text": "需要修改后端配置文件,以便将 {property} 设置为 {value},更多内容请参见 {documentation}。"
},
"captcha": {
"native": "本地",
@ -1281,8 +1375,11 @@
"set_default_version": "将版本 {version} 设为默认",
"wip_notice": "请注意此部分是一个WIP缺乏某些功能因为前端管理的后台实现并不完整。",
"default_frontend": "默认前端",
"default_frontend_tip": "默认的前端将显示给所有用户。目前还没有办法让用户选择个人的前端。如果你不使用 PleromaFE你很可能不得不使用旧的和有问题的 AdminFE 来进行实例配置,直到我们替换它。",
"available_frontends": "可供安装"
"default_frontend_tip": "默认的前端将显示给所有用户。目前还没有办法让用户选择自己的前端。如果您不使用 PleromaFE您很可能不得不使用旧的和有问题的 AdminFE 来进行实例配置,直到我们替换它。",
"available_frontends": "可供安装",
"failure_installing_frontend": "无法安装前端 {version}{reason}",
"success_installing_frontend": "前端 {version} 成功安装",
"default_frontend_unavail": "默认前端设置不可以,因为这需要数据库中的配置"
},
"temp_overrides": {
":pleroma": {
@ -1306,6 +1403,50 @@
}
}
},
"wip_notice": "此管理仪表板是实验性和 WIP 的,{adminFeLink}。"
"wip_notice": "此管理仪表板是实验性和 WIP 的,{adminFeLink}。",
"emoji": {
"remote_pack_instance": "远程表情包实例",
"fallback_src": "回退源",
"fallback_sha256": "回退 SHA256",
"delete_confirm": "您确定要删除 {0} 吗?",
"download_pack": "下载表情包",
"files": "文件",
"downloading_pack": "正在下载 {0}",
"download": "下载",
"download_as_name": "新名称",
"download_as_name_full": "新名称,留空来使用旧的名称",
"emoji_changed": "未保存的表情符号文件更改,检查突出显示的的表情符号",
"replace_warning": "这将替换本地同名的表情包",
"reload": "重新加载表情符号",
"create_pack": "创建表情包",
"emoji_pack": "表情包",
"save_meta": "保存元数据",
"delete": "删除",
"revert": "恢复",
"add_file": "添加文件",
"adding_new": "添加新的表情符号",
"shortcode": "简码",
"filename": "文件名",
"new_shortcode": "简码,留空来自动推断",
"emoji_packs": "表情包",
"remote_packs": "远程表情包",
"do_list": "列表",
"edit_pack": "编辑表情包",
"description": "描述",
"global_actions": "全局动作",
"importFS": "从文件系统导入表情符号",
"error": "错误:{0}",
"delete_pack": "删除表情包",
"new_pack_name": "新的表情包名称",
"create": "创建",
"homepage": "主页",
"share": "分享",
"save": "保存",
"revert_meta": "回复元数据",
"new_filename": "文件名,留空来自动推断",
"editing": "正在编辑 {0}",
"delete_title": "确定删除?",
"metadata_changed": "元数据和保存的不同"
}
}
}

View file

@ -145,10 +145,6 @@ const defaultState = {
quotingAvailable: false,
groupActorAvailable: false,
// Emoji stuff
standardEmojiList: null,
standardEmojiGroupList: null,
// Html stuff
instanceSpecificPanelContent: '',
tos: '',

View file

@ -3,6 +3,7 @@ import ISO6391 from 'iso-639-1'
import _ from 'lodash'
const specialLanguageCodes = {
pdc: 'en',
ja_easy: 'ja',
zh_Hant: 'zh-HANT',
zh: 'zh-Hans'
@ -18,6 +19,7 @@ const internalToBackendLocaleMulti = codes => {
const getLanguageName = (code) => {
const specialLanguageNames = {
pdc: 'Pennsylvania Dutch',
ja_easy: 'やさしいにほんご',
'nan-TW': '臺語(閩南語)',
zh: '简体中文',

View file

@ -10,7 +10,8 @@ export const getOrCreateApp = ({ clientId, clientSecret, instance, commit }) =>
const url = `${instance}/api/v1/apps`
const form = new window.FormData()
form.append('client_name', `PleromaFE_${window.___pleromafe_commit_hash}_${(new Date()).toISOString()}`)
form.append('client_name', 'PleromaFE')
form.append('website', 'https://pleroma.social')
form.append('redirect_uris', REDIRECT_URI)
form.append('scopes', 'read write follow push admin')

View file

@ -351,7 +351,6 @@ export const convertTheme2To3 = (data) => {
newRules.push({ ...rule, parent: { component: 'Notification' } })
}
if (key === 'buttonPressed') {
console.log(key)
newRules.push({ ...rule, state: ['toggled'] })
newRules.push({ ...rule, state: ['toggled', 'focus'] })
newRules.push({ ...rule, state: ['pressed', 'focus'] })

View file

@ -452,7 +452,7 @@ export const getCssShadow = (input, usesDropShadow) => {
]).join(' ')).join(', ')
}
const getCssShadowFilter = (input) => {
export const getCssShadowFilter = (input) => {
if (input.length === 0) {
return 'none'
}

View file

@ -182,7 +182,7 @@ export const init = ({
const rulesetUnsorted = [
...Object.values(components)
.map(c => (c.defaultRules || []).map(r => ({ component: c.name, ...r, source: 'Built-in' })))
.map(c => (c.defaultRules || []).map(r => ({ source: 'Built-in', component: c.name, ...r })))
.reduce((acc, arr) => [...acc, ...arr], []),
...inputRuleset
].map(rule => {
@ -198,18 +198,33 @@ export const init = ({
const ruleset = rulesetUnsorted
.map((data, index) => ({ data, index }))
.sort(({ data: a, index: ai }, { data: b, index: bi }) => {
.toSorted(({ data: a, index: ai }, { data: b, index: bi }) => {
const parentsA = unroll(a).length
const parentsB = unroll(b).length
if (parentsA === parentsB) {
if (a.component === 'Text') return -1
if (b.component === 'Text') return 1
let aScore = 0
let bScore = 0
aScore += parentsA * 1000
bScore += parentsB * 1000
aScore += a.variant !== 'normal' ? 100 : 0
bScore += b.variant !== 'normal' ? 100 : 0
aScore += a.state.filter(x => x !== 'normal').length * 1000
bScore += b.state.filter(x => x !== 'normal').length * 1000
aScore += a.component === 'Text' ? 1 : 0
bScore += b.component === 'Text' ? 1 : 0
// Debug
a.specifityScore = aScore
b.specifityScore = bScore
if (aScore === bScore) {
return ai - bi
}
if (parentsA === 0 && parentsB !== 0) return -1
if (parentsB === 0 && parentsA !== 0) return 1
return parentsA - parentsB
return aScore - bScore
})
.map(({ data }) => data)
@ -235,7 +250,10 @@ export const init = ({
// Inheriting all of the applicable rules
const existingRules = ruleset.filter(findRules(combination))
const computedDirectives = existingRules.map(r => r.directives).reduce((acc, directives) => ({ ...acc, ...directives }), {})
const computedDirectives =
existingRules
.map(r => r.directives)
.reduce((acc, directives) => ({ ...acc, ...directives }), {})
const computedRule = {
...combination,
directives: computedDirectives