Merge branch 'develop' into feature/mobile-improvements-3
This commit is contained in:
commit
46de457f50
28 changed files with 457 additions and 116 deletions
10
BREAKING_CHANGES.md
Normal file
10
BREAKING_CHANGES.md
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
# v1.0
|
||||||
|
## Removed features/radically changed behavior
|
||||||
|
### minimalScopesMode
|
||||||
|
As of !633, `scopeOptions` is no longer available and instead is changed for `minimalScopesMode` (default: `false`)
|
||||||
|
|
||||||
|
Reasoning is that scopeOptions option originally existed mostly as a backwards-compatibility with GNU Social which only had `public` scope available and using scope selector would''t work. Since at some point we dropped GNU Social support, this option was mostly a nuisance (being default `false`'), however some people think scopes are an annoyance to a certain degree and want as less of that feature as possible.
|
||||||
|
|
||||||
|
Solution - to only show minimal set among: *Direct*, *User default* and *Scope of post replying to*. This also makes it impossible to reply to a DM with a non-DM post from UI.
|
||||||
|
|
||||||
|
*This setting is admin-default, user-configurable. Admin can choose different default for their instance but user can override it.*
|
|
@ -41,7 +41,7 @@ FE Build process also leaves current commit hash in global variable `___pleromaf
|
||||||
|
|
||||||
# Configuration
|
# Configuration
|
||||||
|
|
||||||
Edit config.json for configuration. scopeOptionsEnabled gives you input fields for CWs and the scope settings.
|
Edit config.json for configuration.
|
||||||
|
|
||||||
## Options
|
## Options
|
||||||
|
|
||||||
|
|
51
src/App.scss
51
src/App.scss
|
@ -735,3 +735,54 @@ nav {
|
||||||
.btn.btn-default {
|
.btn.btn-default {
|
||||||
min-height: 28px;
|
min-height: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.autocomplete {
|
||||||
|
&-panel {
|
||||||
|
position: relative;
|
||||||
|
|
||||||
|
&-body {
|
||||||
|
margin: 0 0.5em 0 0.5em;
|
||||||
|
border-radius: $fallback--tooltipRadius;
|
||||||
|
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
|
||||||
|
position: absolute;
|
||||||
|
z-index: 1;
|
||||||
|
box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5);
|
||||||
|
// this doesn't match original but i don't care, making it uniform.
|
||||||
|
box-shadow: var(--popupShadow);
|
||||||
|
min-width: 75%;
|
||||||
|
background: $fallback--bg;
|
||||||
|
background: var(--bg, $fallback--bg);
|
||||||
|
color: $fallback--lightText;
|
||||||
|
color: var(--lightText, $fallback--lightText);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&-item {
|
||||||
|
cursor: pointer;
|
||||||
|
padding: 0.2em 0.4em 0.2em 0.4em;
|
||||||
|
border-bottom: 1px solid rgba(0, 0, 0, 0.4);
|
||||||
|
display: flex;
|
||||||
|
|
||||||
|
img {
|
||||||
|
width: 24px;
|
||||||
|
height: 24px;
|
||||||
|
object-fit: contain;
|
||||||
|
}
|
||||||
|
|
||||||
|
span {
|
||||||
|
line-height: 24px;
|
||||||
|
margin: 0 0.1em 0 0.2em;
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
margin-left: .5em;
|
||||||
|
color: $fallback--faint;
|
||||||
|
color: var(--faint, $fallback--faint);
|
||||||
|
}
|
||||||
|
|
||||||
|
&.highlighted {
|
||||||
|
background-color: $fallback--fg;
|
||||||
|
background-color: var(--lightBg, $fallback--fg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -95,7 +95,7 @@ const setSettings = async ({ apiConfig, staticConfig, store }) => {
|
||||||
copyInstanceOption('redirectRootNoLogin')
|
copyInstanceOption('redirectRootNoLogin')
|
||||||
copyInstanceOption('redirectRootLogin')
|
copyInstanceOption('redirectRootLogin')
|
||||||
copyInstanceOption('showInstanceSpecificPanel')
|
copyInstanceOption('showInstanceSpecificPanel')
|
||||||
copyInstanceOption('scopeOptionsEnabled')
|
copyInstanceOption('minimalScopesMode')
|
||||||
copyInstanceOption('formattingOptionsEnabled')
|
copyInstanceOption('formattingOptionsEnabled')
|
||||||
copyInstanceOption('hideMutedPosts')
|
copyInstanceOption('hideMutedPosts')
|
||||||
copyInstanceOption('collapseMessageWithSubject')
|
copyInstanceOption('collapseMessageWithSubject')
|
||||||
|
|
107
src/components/emoji-input/emoji-input.js
Normal file
107
src/components/emoji-input/emoji-input.js
Normal file
|
@ -0,0 +1,107 @@
|
||||||
|
import Completion from '../../services/completion/completion.js'
|
||||||
|
import { take, filter, map } from 'lodash'
|
||||||
|
|
||||||
|
const EmojiInput = {
|
||||||
|
props: [
|
||||||
|
'value',
|
||||||
|
'placeholder',
|
||||||
|
'type',
|
||||||
|
'classname'
|
||||||
|
],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
highlighted: 0,
|
||||||
|
caret: 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
suggestions () {
|
||||||
|
const firstchar = this.textAtCaret.charAt(0)
|
||||||
|
if (firstchar === ':') {
|
||||||
|
if (this.textAtCaret === ':') { return }
|
||||||
|
const matchedEmoji = filter(this.emoji.concat(this.customEmoji), (emoji) => emoji.shortcode.startsWith(this.textAtCaret.slice(1)))
|
||||||
|
if (matchedEmoji.length <= 0) {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
return map(take(matchedEmoji, 5), ({shortcode, image_url, utf}, index) => ({
|
||||||
|
shortcode: `:${shortcode}:`,
|
||||||
|
utf: utf || '',
|
||||||
|
// eslint-disable-next-line camelcase
|
||||||
|
img: utf ? '' : this.$store.state.instance.server + image_url,
|
||||||
|
highlighted: index === this.highlighted
|
||||||
|
}))
|
||||||
|
} else {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
},
|
||||||
|
textAtCaret () {
|
||||||
|
return (this.wordAtCaret || {}).word || ''
|
||||||
|
},
|
||||||
|
wordAtCaret () {
|
||||||
|
const word = Completion.wordAtPosition(this.value, this.caret - 1) || {}
|
||||||
|
return word
|
||||||
|
},
|
||||||
|
emoji () {
|
||||||
|
return this.$store.state.instance.emoji || []
|
||||||
|
},
|
||||||
|
customEmoji () {
|
||||||
|
return this.$store.state.instance.customEmoji || []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
replace (replacement) {
|
||||||
|
const newValue = Completion.replaceWord(this.value, this.wordAtCaret, replacement)
|
||||||
|
this.$emit('input', newValue)
|
||||||
|
this.caret = 0
|
||||||
|
},
|
||||||
|
replaceEmoji (e) {
|
||||||
|
const len = this.suggestions.length || 0
|
||||||
|
if (this.textAtCaret === ':' || e.ctrlKey) { return }
|
||||||
|
if (len > 0) {
|
||||||
|
e.preventDefault()
|
||||||
|
const emoji = this.suggestions[this.highlighted]
|
||||||
|
const replacement = emoji.utf || (emoji.shortcode + ' ')
|
||||||
|
const newValue = Completion.replaceWord(this.value, this.wordAtCaret, replacement)
|
||||||
|
this.$emit('input', newValue)
|
||||||
|
this.caret = 0
|
||||||
|
this.highlighted = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cycleBackward (e) {
|
||||||
|
const len = this.suggestions.length || 0
|
||||||
|
if (len > 0) {
|
||||||
|
e.preventDefault()
|
||||||
|
this.highlighted -= 1
|
||||||
|
if (this.highlighted < 0) {
|
||||||
|
this.highlighted = this.suggestions.length - 1
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.highlighted = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
cycleForward (e) {
|
||||||
|
const len = this.suggestions.length || 0
|
||||||
|
if (len > 0) {
|
||||||
|
if (e.shiftKey) { return }
|
||||||
|
e.preventDefault()
|
||||||
|
this.highlighted += 1
|
||||||
|
if (this.highlighted >= len) {
|
||||||
|
this.highlighted = 0
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
this.highlighted = 0
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onKeydown (e) {
|
||||||
|
e.stopPropagation()
|
||||||
|
},
|
||||||
|
onInput (e) {
|
||||||
|
this.$emit('input', e.target.value)
|
||||||
|
},
|
||||||
|
setCaret ({target: {selectionStart}}) {
|
||||||
|
this.caret = selectionStart
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default EmojiInput
|
64
src/components/emoji-input/emoji-input.vue
Normal file
64
src/components/emoji-input/emoji-input.vue
Normal file
|
@ -0,0 +1,64 @@
|
||||||
|
<template>
|
||||||
|
<div class="emoji-input">
|
||||||
|
<input
|
||||||
|
v-if="type !== 'textarea'"
|
||||||
|
:class="classname"
|
||||||
|
:type="type"
|
||||||
|
:value="value"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
@input="onInput"
|
||||||
|
@click="setCaret"
|
||||||
|
@keyup="setCaret"
|
||||||
|
@keydown="onKeydown"
|
||||||
|
@keydown.down="cycleForward"
|
||||||
|
@keydown.up="cycleBackward"
|
||||||
|
@keydown.shift.tab="cycleBackward"
|
||||||
|
@keydown.tab="cycleForward"
|
||||||
|
@keydown.enter="replaceEmoji"
|
||||||
|
/>
|
||||||
|
<textarea
|
||||||
|
v-else
|
||||||
|
:class="classname"
|
||||||
|
:value="value"
|
||||||
|
:placeholder="placeholder"
|
||||||
|
@input="onInput"
|
||||||
|
@click="setCaret"
|
||||||
|
@keyup="setCaret"
|
||||||
|
@keydown="onKeydown"
|
||||||
|
@keydown.down="cycleForward"
|
||||||
|
@keydown.up="cycleBackward"
|
||||||
|
@keydown.shift.tab="cycleBackward"
|
||||||
|
@keydown.tab="cycleForward"
|
||||||
|
@keydown.enter="replaceEmoji"
|
||||||
|
></textarea>
|
||||||
|
<div class="autocomplete-panel" v-if="suggestions">
|
||||||
|
<div class="autocomplete-panel-body">
|
||||||
|
<div
|
||||||
|
v-for="(emoji, index) in suggestions"
|
||||||
|
:key="index"
|
||||||
|
@click="replace(emoji.utf || (emoji.shortcode + ' '))"
|
||||||
|
class="autocomplete-item"
|
||||||
|
:class="{ highlighted: emoji.highlighted }"
|
||||||
|
>
|
||||||
|
<span v-if="emoji.img">
|
||||||
|
<img :src="emoji.img" />
|
||||||
|
</span>
|
||||||
|
<span v-else>{{emoji.utf}}</span>
|
||||||
|
<span>{{emoji.shortcode}}</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./emoji-input.js"></script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
|
.emoji-input {
|
||||||
|
.form-control {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
|
@ -6,7 +6,7 @@ const FeaturesPanel = {
|
||||||
gopher: function () { return this.$store.state.instance.gopherAvailable },
|
gopher: function () { return this.$store.state.instance.gopherAvailable },
|
||||||
whoToFollow: function () { return this.$store.state.instance.suggestionsEnabled },
|
whoToFollow: function () { return this.$store.state.instance.suggestionsEnabled },
|
||||||
mediaProxy: function () { return this.$store.state.instance.mediaProxyAvailable },
|
mediaProxy: function () { return this.$store.state.instance.mediaProxyAvailable },
|
||||||
scopeOptions: function () { return this.$store.state.instance.scopeOptionsEnabled },
|
minimalScopesMode: function () { return this.$store.state.instance.minimalScopesMode },
|
||||||
textlimit: function () { return this.$store.state.instance.textlimit }
|
textlimit: function () { return this.$store.state.instance.textlimit }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
<li v-if="gopher">{{$t('features_panel.gopher')}}</li>
|
<li v-if="gopher">{{$t('features_panel.gopher')}}</li>
|
||||||
<li v-if="whoToFollow">{{$t('features_panel.who_to_follow')}}</li>
|
<li v-if="whoToFollow">{{$t('features_panel.who_to_follow')}}</li>
|
||||||
<li v-if="mediaProxy">{{$t('features_panel.media_proxy')}}</li>
|
<li v-if="mediaProxy">{{$t('features_panel.media_proxy')}}</li>
|
||||||
<li v-if="scopeOptions">{{$t('features_panel.scope_options')}}</li>
|
<li>{{$t('features_panel.scope_options')}}</li>
|
||||||
<li>{{$t('features_panel.text_limit')}} = {{textlimit}}</li>
|
<li>{{$t('features_panel.text_limit')}} = {{textlimit}}</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
@ -31,6 +31,15 @@ const Notification = {
|
||||||
const highlight = this.$store.state.config.highlight
|
const highlight = this.$store.state.config.highlight
|
||||||
const user = this.notification.action.user
|
const user = this.notification.action.user
|
||||||
return highlightStyle(highlight[user.screen_name])
|
return highlightStyle(highlight[user.screen_name])
|
||||||
|
},
|
||||||
|
userInStore () {
|
||||||
|
return this.$store.getters.findUser(this.notification.action.user.id)
|
||||||
|
},
|
||||||
|
user () {
|
||||||
|
if (this.userInStore) {
|
||||||
|
return this.userInStore
|
||||||
|
}
|
||||||
|
return {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
<template>
|
<template>
|
||||||
<status v-if="notification.type === 'mention'" :compact="true" :statusoid="notification.status"></status>
|
<status v-if="notification.type === 'mention'" :compact="true" :statusoid="notification.status"></status>
|
||||||
<div class="non-mention" :class="[userClass, { highlighted: userStyle }]" :style="[ userStyle ]"v-else>
|
<div class="non-mention" :class="[userClass, { highlighted: userStyle }]" :style="[ userStyle ]" v-else>
|
||||||
<a class='avatar-container' :href="notification.action.user.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded">
|
<a class='avatar-container' :href="notification.action.user.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded">
|
||||||
<UserAvatar :compact="true" :betterShadow="betterShadow" :src="notification.action.user.profile_image_url_original"/>
|
<UserAvatar :compact="true" :betterShadow="betterShadow" :src="notification.action.user.profile_image_url_original"/>
|
||||||
</a>
|
</a>
|
||||||
<div class='notification-right'>
|
<div class='notification-right'>
|
||||||
<UserCard :user="notification.action.user" :rounded="true" :bordered="true" v-if="userExpanded"/>
|
<UserCard :user="user" :rounded="true" :bordered="true" v-if="userExpanded"/>
|
||||||
<span class="notification-details">
|
<span class="notification-details">
|
||||||
<div class="name-and-action">
|
<div class="name-and-action">
|
||||||
<span class="username" v-if="!!notification.action.user.name_html" :title="'@'+notification.action.user.screen_name" v-html="notification.action.user.name_html"></span>
|
<span class="username" v-if="!!notification.action.user.name_html" :title="'@'+notification.action.user.screen_name" v-html="notification.action.user.name_html"></span>
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import statusPoster from '../../services/status_poster/status_poster.service.js'
|
import statusPoster from '../../services/status_poster/status_poster.service.js'
|
||||||
import MediaUpload from '../media_upload/media_upload.vue'
|
import MediaUpload from '../media_upload/media_upload.vue'
|
||||||
|
import ScopeSelector from '../scope_selector/scope_selector.vue'
|
||||||
|
import EmojiInput from '../emoji-input/emoji-input.vue'
|
||||||
import fileTypeService from '../../services/file_type/file_type.service.js'
|
import fileTypeService from '../../services/file_type/file_type.service.js'
|
||||||
import Completion from '../../services/completion/completion.js'
|
import Completion from '../../services/completion/completion.js'
|
||||||
import { take, filter, reject, map, uniqBy } from 'lodash'
|
import { take, filter, reject, map, uniqBy } from 'lodash'
|
||||||
|
@ -28,7 +30,9 @@ const PostStatusForm = {
|
||||||
'subject'
|
'subject'
|
||||||
],
|
],
|
||||||
components: {
|
components: {
|
||||||
MediaUpload
|
MediaUpload,
|
||||||
|
ScopeSelector,
|
||||||
|
EmojiInput
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
this.resize(this.$refs.textarea)
|
this.resize(this.$refs.textarea)
|
||||||
|
@ -78,14 +82,6 @@ const PostStatusForm = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
vis () {
|
|
||||||
return {
|
|
||||||
public: { selected: this.newStatus.visibility === 'public' },
|
|
||||||
unlisted: { selected: this.newStatus.visibility === 'unlisted' },
|
|
||||||
private: { selected: this.newStatus.visibility === 'private' },
|
|
||||||
direct: { selected: this.newStatus.visibility === 'direct' }
|
|
||||||
}
|
|
||||||
},
|
|
||||||
candidates () {
|
candidates () {
|
||||||
const firstchar = this.textAtCaret.charAt(0)
|
const firstchar = this.textAtCaret.charAt(0)
|
||||||
if (firstchar === '@') {
|
if (firstchar === '@') {
|
||||||
|
@ -133,6 +129,15 @@ const PostStatusForm = {
|
||||||
users () {
|
users () {
|
||||||
return this.$store.state.users.users
|
return this.$store.state.users.users
|
||||||
},
|
},
|
||||||
|
userDefaultScope () {
|
||||||
|
return this.$store.state.users.currentUser.default_scope
|
||||||
|
},
|
||||||
|
showAllScopes () {
|
||||||
|
const minimalScopesMode = typeof this.$store.state.config.minimalScopesMode === 'undefined'
|
||||||
|
? this.$store.state.instance.minimalScopesMode
|
||||||
|
: this.$store.state.config.minimalScopesMode
|
||||||
|
return !minimalScopesMode
|
||||||
|
},
|
||||||
emoji () {
|
emoji () {
|
||||||
return this.$store.state.instance.emoji || []
|
return this.$store.state.instance.emoji || []
|
||||||
},
|
},
|
||||||
|
@ -157,8 +162,8 @@ const PostStatusForm = {
|
||||||
isOverLengthLimit () {
|
isOverLengthLimit () {
|
||||||
return this.hasStatusLengthLimit && (this.charactersLeft < 0)
|
return this.hasStatusLengthLimit && (this.charactersLeft < 0)
|
||||||
},
|
},
|
||||||
scopeOptionsEnabled () {
|
minimalScopesMode () {
|
||||||
return this.$store.state.instance.scopeOptionsEnabled
|
return this.$store.state.instance.minimalScopesMode
|
||||||
},
|
},
|
||||||
alwaysShowSubject () {
|
alwaysShowSubject () {
|
||||||
if (typeof this.$store.state.config.alwaysShowSubjectInput !== 'undefined') {
|
if (typeof this.$store.state.config.alwaysShowSubjectInput !== 'undefined') {
|
||||||
|
@ -166,7 +171,7 @@ const PostStatusForm = {
|
||||||
} else if (typeof this.$store.state.instance.alwaysShowSubjectInput !== 'undefined') {
|
} else if (typeof this.$store.state.instance.alwaysShowSubjectInput !== 'undefined') {
|
||||||
return this.$store.state.instance.alwaysShowSubjectInput
|
return this.$store.state.instance.alwaysShowSubjectInput
|
||||||
} else {
|
} else {
|
||||||
return this.$store.state.instance.scopeOptionsEnabled
|
return true
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
formattingOptionsEnabled () {
|
formattingOptionsEnabled () {
|
||||||
|
|
|
@ -10,12 +10,13 @@
|
||||||
<router-link :to="{ name: 'user-settings' }">{{ $t('post_status.account_not_locked_warning_link') }}</router-link>
|
<router-link :to="{ name: 'user-settings' }">{{ $t('post_status.account_not_locked_warning_link') }}</router-link>
|
||||||
</i18n>
|
</i18n>
|
||||||
<p v-if="this.newStatus.visibility == 'direct'" class="visibility-notice">{{ $t('post_status.direct_warning') }}</p>
|
<p v-if="this.newStatus.visibility == 'direct'" class="visibility-notice">{{ $t('post_status.direct_warning') }}</p>
|
||||||
<input
|
<EmojiInput
|
||||||
v-if="newStatus.spoilerText || alwaysShowSubject"
|
v-if="newStatus.spoilerText || alwaysShowSubject"
|
||||||
type="text"
|
type="text"
|
||||||
:placeholder="$t('post_status.content_warning')"
|
:placeholder="$t('post_status.content_warning')"
|
||||||
v-model="newStatus.spoilerText"
|
v-model="newStatus.spoilerText"
|
||||||
class="form-cw">
|
classname="form-control"
|
||||||
|
/>
|
||||||
<textarea
|
<textarea
|
||||||
ref="textarea"
|
ref="textarea"
|
||||||
@click="setCaret"
|
@click="setCaret"
|
||||||
|
@ -47,22 +48,26 @@
|
||||||
</label>
|
</label>
|
||||||
</span>
|
</span>
|
||||||
|
|
||||||
<div v-if="scopeOptionsEnabled">
|
<scope-selector
|
||||||
<i v-on:click="changeVis('direct')" class="icon-mail-alt" :class="vis.direct" :title="$t('post_status.scope.direct')"></i>
|
:showAll="showAllScopes"
|
||||||
<i v-on:click="changeVis('private')" class="icon-lock" :class="vis.private" :title="$t('post_status.scope.private')"></i>
|
:userDefault="userDefaultScope"
|
||||||
<i v-on:click="changeVis('unlisted')" class="icon-lock-open-alt" :class="vis.unlisted" :title="$t('post_status.scope.unlisted')"></i>
|
:originalScope="copyMessageScope"
|
||||||
<i v-on:click="changeVis('public')" class="icon-globe" :class="vis.public" :title="$t('post_status.scope.public')"></i>
|
:initialScope="newStatus.visibility"
|
||||||
</div>
|
:onScopeChange="changeVis"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div style="position:relative;" v-if="candidates">
|
<div class="autocomplete-panel" v-if="candidates">
|
||||||
<div class="autocomplete-panel">
|
<div class="autocomplete-panel-body">
|
||||||
<div v-for="candidate in candidates" @click="replace(candidate.utf || (candidate.screen_name + ' '))">
|
<div
|
||||||
<div class="autocomplete" :class="{ highlighted: candidate.highlighted }">
|
v-for="(candidate, index) in candidates"
|
||||||
<span v-if="candidate.img"><img :src="candidate.img"></img></span>
|
:key="index"
|
||||||
<span v-else>{{candidate.utf}}</span>
|
@click="replace(candidate.utf || (candidate.screen_name + ' '))"
|
||||||
<span>{{candidate.screen_name}}<small>{{candidate.name}}</small></span>
|
class="autocomplete-item"
|
||||||
</div>
|
:class="{ highlighted: candidate.highlighted }"
|
||||||
|
>
|
||||||
|
<span v-if="candidate.img"><img :src="candidate.img" /></span>
|
||||||
|
<span v-else>{{candidate.utf}}</span>
|
||||||
|
<span>{{candidate.screen_name}}<small>{{candidate.name}}</small></span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -261,50 +266,5 @@
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
z-index: 4;
|
z-index: 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
.autocomplete-panel {
|
|
||||||
margin: 0 0.5em 0 0.5em;
|
|
||||||
border-radius: $fallback--tooltipRadius;
|
|
||||||
border-radius: var(--tooltipRadius, $fallback--tooltipRadius);
|
|
||||||
position: absolute;
|
|
||||||
z-index: 1;
|
|
||||||
box-shadow: 1px 2px 4px rgba(0, 0, 0, 0.5);
|
|
||||||
// this doesn't match original but i don't care, making it uniform.
|
|
||||||
box-shadow: var(--popupShadow);
|
|
||||||
min-width: 75%;
|
|
||||||
background: $fallback--bg;
|
|
||||||
background: var(--bg, $fallback--bg);
|
|
||||||
color: $fallback--lightText;
|
|
||||||
color: var(--lightText, $fallback--lightText);
|
|
||||||
}
|
|
||||||
|
|
||||||
.autocomplete {
|
|
||||||
cursor: pointer;
|
|
||||||
padding: 0.2em 0.4em 0.2em 0.4em;
|
|
||||||
border-bottom: 1px solid rgba(0, 0, 0, 0.4);
|
|
||||||
display: flex;
|
|
||||||
|
|
||||||
img {
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
object-fit: contain;
|
|
||||||
}
|
|
||||||
|
|
||||||
span {
|
|
||||||
line-height: 24px;
|
|
||||||
margin: 0 0.1em 0 0.2em;
|
|
||||||
}
|
|
||||||
|
|
||||||
small {
|
|
||||||
margin-left: .5em;
|
|
||||||
color: $fallback--faint;
|
|
||||||
color: var(--faint, $fallback--faint);
|
|
||||||
}
|
|
||||||
|
|
||||||
&.highlighted {
|
|
||||||
background-color: $fallback--fg;
|
|
||||||
background-color: var(--lightBg, $fallback--fg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
54
src/components/scope_selector/scope_selector.js
Normal file
54
src/components/scope_selector/scope_selector.js
Normal file
|
@ -0,0 +1,54 @@
|
||||||
|
const ScopeSelector = {
|
||||||
|
props: [
|
||||||
|
'showAll',
|
||||||
|
'userDefault',
|
||||||
|
'originalScope',
|
||||||
|
'initialScope',
|
||||||
|
'onScopeChange'
|
||||||
|
],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
currentScope: this.initialScope
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
showNothing () {
|
||||||
|
return !this.showPublic && !this.showUnlisted && !this.showPrivate && !this.showDirect
|
||||||
|
},
|
||||||
|
showPublic () {
|
||||||
|
return this.originalScope !== 'direct' && this.shouldShow('public')
|
||||||
|
},
|
||||||
|
showUnlisted () {
|
||||||
|
return this.originalScope !== 'direct' && this.shouldShow('unlisted')
|
||||||
|
},
|
||||||
|
showPrivate () {
|
||||||
|
return this.originalScope !== 'direct' && this.shouldShow('private')
|
||||||
|
},
|
||||||
|
showDirect () {
|
||||||
|
return this.shouldShow('direct')
|
||||||
|
},
|
||||||
|
css () {
|
||||||
|
return {
|
||||||
|
public: {selected: this.currentScope === 'public'},
|
||||||
|
unlisted: {selected: this.currentScope === 'unlisted'},
|
||||||
|
private: {selected: this.currentScope === 'private'},
|
||||||
|
direct: {selected: this.currentScope === 'direct'}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
shouldShow (scope) {
|
||||||
|
return this.showAll ||
|
||||||
|
this.currentScope === scope ||
|
||||||
|
this.originalScope === scope ||
|
||||||
|
this.userDefault === scope ||
|
||||||
|
scope === 'direct'
|
||||||
|
},
|
||||||
|
changeVis (scope) {
|
||||||
|
this.currentScope = scope
|
||||||
|
this.onScopeChange && this.onScopeChange(scope)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default ScopeSelector
|
30
src/components/scope_selector/scope_selector.vue
Normal file
30
src/components/scope_selector/scope_selector.vue
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
<template>
|
||||||
|
<div v-if="!showNothing">
|
||||||
|
<i class="icon-mail-alt"
|
||||||
|
:class="css.direct"
|
||||||
|
:title="$t('post_status.scope.direct')"
|
||||||
|
v-if="showDirect"
|
||||||
|
@click="changeVis('direct')">
|
||||||
|
</i>
|
||||||
|
<i class="icon-lock"
|
||||||
|
:class="css.private"
|
||||||
|
:title="$t('post_status.scope.private')"
|
||||||
|
v-if="showPrivate"
|
||||||
|
v-on:click="changeVis('private')">
|
||||||
|
</i>
|
||||||
|
<i class="icon-lock-open-alt"
|
||||||
|
:class="css.unlisted"
|
||||||
|
:title="$t('post_status.scope.unlisted')"
|
||||||
|
v-if="showUnlisted"
|
||||||
|
@click="changeVis('unlisted')">
|
||||||
|
</i>
|
||||||
|
<i class="icon-globe"
|
||||||
|
:class="css.public"
|
||||||
|
:title="$t('post_status.scope.public')"
|
||||||
|
v-if="showPublic"
|
||||||
|
@click="changeVis('public')">
|
||||||
|
</i>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./scope_selector.js"></script>
|
|
@ -70,13 +70,18 @@ const settings = {
|
||||||
alwaysShowSubjectInputLocal: typeof user.alwaysShowSubjectInput === 'undefined'
|
alwaysShowSubjectInputLocal: typeof user.alwaysShowSubjectInput === 'undefined'
|
||||||
? instance.alwaysShowSubjectInput
|
? instance.alwaysShowSubjectInput
|
||||||
: user.alwaysShowSubjectInput,
|
: user.alwaysShowSubjectInput,
|
||||||
alwaysShowSubjectInputDefault: instance.alwaysShowSubjectInput,
|
alwaysShowSubjectInputDefault: this.$t('settings.values.' + instance.alwaysShowSubjectInput),
|
||||||
|
|
||||||
scopeCopyLocal: typeof user.scopeCopy === 'undefined'
|
scopeCopyLocal: typeof user.scopeCopy === 'undefined'
|
||||||
? instance.scopeCopy
|
? instance.scopeCopy
|
||||||
: user.scopeCopy,
|
: user.scopeCopy,
|
||||||
scopeCopyDefault: this.$t('settings.values.' + instance.scopeCopy),
|
scopeCopyDefault: this.$t('settings.values.' + instance.scopeCopy),
|
||||||
|
|
||||||
|
minimalScopesModeLocal: typeof user.minimalScopesMode === 'undefined'
|
||||||
|
? instance.minimalScopesMode
|
||||||
|
: user.minimalScopesMode,
|
||||||
|
minimalScopesModeDefault: this.$t('settings.values.' + instance.minimalScopesMode),
|
||||||
|
|
||||||
stopGifs: user.stopGifs,
|
stopGifs: user.stopGifs,
|
||||||
webPushNotificationsLocal: user.webPushNotifications,
|
webPushNotificationsLocal: user.webPushNotifications,
|
||||||
loopVideoSilentOnlyLocal: user.loopVideosSilentOnly,
|
loopVideoSilentOnlyLocal: user.loopVideosSilentOnly,
|
||||||
|
@ -200,6 +205,9 @@ const settings = {
|
||||||
postContentTypeLocal (value) {
|
postContentTypeLocal (value) {
|
||||||
this.$store.dispatch('setOption', { name: 'postContentType', value })
|
this.$store.dispatch('setOption', { name: 'postContentType', value })
|
||||||
},
|
},
|
||||||
|
minimalScopesModeLocal (value) {
|
||||||
|
this.$store.dispatch('setOption', { name: 'minimalScopesMode', value })
|
||||||
|
},
|
||||||
stopGifs (value) {
|
stopGifs (value) {
|
||||||
this.$store.dispatch('setOption', { name: 'stopGifs', value })
|
this.$store.dispatch('setOption', { name: 'stopGifs', value })
|
||||||
},
|
},
|
||||||
|
|
|
@ -118,6 +118,12 @@
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<input type="checkbox" id="minimalScopesMode" v-model="minimalScopesModeLocal">
|
||||||
|
<label for="minimalScopesMode">
|
||||||
|
{{$t('settings.minimal_scopes_mode')}} {{$t('settings.instance_default', { value: minimalScopesModeDefault })}}
|
||||||
|
</label>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
|
|
@ -251,6 +251,12 @@ const Status = {
|
||||||
},
|
},
|
||||||
maxThumbnails () {
|
maxThumbnails () {
|
||||||
return this.$store.state.config.maxThumbnails
|
return this.$store.state.config.maxThumbnails
|
||||||
|
},
|
||||||
|
contentHtml () {
|
||||||
|
if (!this.status.summary_html) {
|
||||||
|
return this.status.statusnet_html
|
||||||
|
}
|
||||||
|
return this.status.summary_html + '<br />' + this.status.statusnet_html
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
|
|
@ -98,16 +98,16 @@
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="status-content-wrapper" :class="{ 'tall-status': !showingLongSubject }" v-if="longSubject">
|
<div class="status-content-wrapper" :class="{ 'tall-status': !showingLongSubject }" v-if="longSubject">
|
||||||
<a class="tall-status-hider" :class="{ 'tall-status-hider_focused': isFocused }" v-if="!showingLongSubject" href="#" @click.prevent="showingLongSubject=true">Show more</a>
|
<a class="tall-status-hider" :class="{ 'tall-status-hider_focused': isFocused }" v-if="!showingLongSubject" href="#" @click.prevent="showingLongSubject=true">{{$t("general.show_more")}}</a>
|
||||||
<div @click.prevent="linkClicked" class="status-content media-body" v-html="status.statusnet_html"></div>
|
<div @click.prevent="linkClicked" class="status-content media-body" v-html="contentHtml"></div>
|
||||||
<a v-if="showingLongSubject" href="#" class="status-unhider" @click.prevent="showingLongSubject=false">Show less</a>
|
<a v-if="showingLongSubject" href="#" class="status-unhider" @click.prevent="showingLongSubject=false">{{$t("general.show_less")}}</a>
|
||||||
</div>
|
</div>
|
||||||
<div :class="{'tall-status': hideTallStatus}" class="status-content-wrapper" v-else>
|
<div :class="{'tall-status': hideTallStatus}" class="status-content-wrapper" v-else>
|
||||||
<a class="tall-status-hider" :class="{ 'tall-status-hider_focused': isFocused }" v-if="hideTallStatus" href="#" @click.prevent="toggleShowMore">Show more</a>
|
<a class="tall-status-hider" :class="{ 'tall-status-hider_focused': isFocused }" v-if="hideTallStatus" href="#" @click.prevent="toggleShowMore">{{$t("general.show_more")}}</a>
|
||||||
<div @click.prevent="linkClicked" class="status-content media-body" v-html="status.statusnet_html" v-if="!hideSubjectStatus"></div>
|
<div @click.prevent="linkClicked" class="status-content media-body" v-html="contentHtml" v-if="!hideSubjectStatus"></div>
|
||||||
<div @click.prevent="linkClicked" class="status-content media-body" v-html="status.summary_html" v-else></div>
|
<div @click.prevent="linkClicked" class="status-content media-body" v-html="status.summary_html" v-else></div>
|
||||||
<a v-if="hideSubjectStatus" href="#" class="cw-status-hider" @click.prevent="toggleShowMore">Show more</a>
|
<a v-if="hideSubjectStatus" href="#" class="cw-status-hider" @click.prevent="toggleShowMore">{{$t("general.show_more")}}</a>
|
||||||
<a v-if="showingMore" href="#" class="status-unhider" @click.prevent="toggleShowMore">Show less</a>
|
<a v-if="showingMore" href="#" class="status-unhider" @click.prevent="toggleShowMore">{{$t("general.show_less")}}</a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div v-if="status.attachments && (!hideSubjectStatus || showingLongSubject)" class="attachments media-body">
|
<div v-if="status.attachments && (!hideSubjectStatus || showingLongSubject)" class="attachments media-body">
|
||||||
|
|
|
@ -72,9 +72,6 @@ const UserProfile = {
|
||||||
return this.$store.getters.findUser(this.fetchedUserId || routeParams.name || routeParams.id)
|
return this.$store.getters.findUser(this.fetchedUserId || routeParams.name || routeParams.id)
|
||||||
},
|
},
|
||||||
user () {
|
user () {
|
||||||
if (this.timeline.statuses[0]) {
|
|
||||||
return this.timeline.statuses[0].user
|
|
||||||
}
|
|
||||||
if (this.userInStore) {
|
if (this.userInStore) {
|
||||||
return this.userInStore
|
return this.userInStore
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,9 +4,11 @@ import get from 'lodash/get'
|
||||||
import TabSwitcher from '../tab_switcher/tab_switcher.js'
|
import TabSwitcher from '../tab_switcher/tab_switcher.js'
|
||||||
import ImageCropper from '../image_cropper/image_cropper.vue'
|
import ImageCropper from '../image_cropper/image_cropper.vue'
|
||||||
import StyleSwitcher from '../style_switcher/style_switcher.vue'
|
import StyleSwitcher from '../style_switcher/style_switcher.vue'
|
||||||
|
import ScopeSelector from '../scope_selector/scope_selector.vue'
|
||||||
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
|
import fileSizeFormatService from '../../services/file_size_format/file_size_format.js'
|
||||||
import BlockCard from '../block_card/block_card.vue'
|
import BlockCard from '../block_card/block_card.vue'
|
||||||
import MuteCard from '../mute_card/mute_card.vue'
|
import MuteCard from '../mute_card/mute_card.vue'
|
||||||
|
import EmojiInput from '../emoji-input/emoji-input.vue'
|
||||||
import withSubscription from '../../hocs/with_subscription/with_subscription'
|
import withSubscription from '../../hocs/with_subscription/with_subscription'
|
||||||
import withList from '../../hocs/with_list/with_list'
|
import withList from '../../hocs/with_list/with_list'
|
||||||
|
|
||||||
|
@ -66,10 +68,12 @@ const UserSettings = {
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
StyleSwitcher,
|
StyleSwitcher,
|
||||||
|
ScopeSelector,
|
||||||
TabSwitcher,
|
TabSwitcher,
|
||||||
ImageCropper,
|
ImageCropper,
|
||||||
BlockList,
|
BlockList,
|
||||||
MuteList
|
MuteList,
|
||||||
|
EmojiInput
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
user () {
|
user () {
|
||||||
|
@ -78,8 +82,8 @@ const UserSettings = {
|
||||||
pleromaBackend () {
|
pleromaBackend () {
|
||||||
return this.$store.state.instance.pleromaBackend
|
return this.$store.state.instance.pleromaBackend
|
||||||
},
|
},
|
||||||
scopeOptionsEnabled () {
|
minimalScopesMode () {
|
||||||
return this.$store.state.instance.scopeOptionsEnabled
|
return this.$store.state.instance.minimalScopesMode
|
||||||
},
|
},
|
||||||
vis () {
|
vis () {
|
||||||
return {
|
return {
|
||||||
|
|
|
@ -22,20 +22,29 @@
|
||||||
<div class="setting-item" >
|
<div class="setting-item" >
|
||||||
<h2>{{$t('settings.name_bio')}}</h2>
|
<h2>{{$t('settings.name_bio')}}</h2>
|
||||||
<p>{{$t('settings.name')}}</p>
|
<p>{{$t('settings.name')}}</p>
|
||||||
<input class='name-changer' id='username' v-model="newName"></input>
|
<EmojiInput
|
||||||
|
type="text"
|
||||||
|
v-model="newName"
|
||||||
|
id="username"
|
||||||
|
classname="name-changer"
|
||||||
|
/>
|
||||||
<p>{{$t('settings.bio')}}</p>
|
<p>{{$t('settings.bio')}}</p>
|
||||||
<textarea class="bio" v-model="newBio"></textarea>
|
<EmojiInput
|
||||||
|
type="textarea"
|
||||||
|
v-model="newBio"
|
||||||
|
classname="bio"
|
||||||
|
/>
|
||||||
<p>
|
<p>
|
||||||
<input type="checkbox" v-model="newLocked" id="account-locked">
|
<input type="checkbox" v-model="newLocked" id="account-locked">
|
||||||
<label for="account-locked">{{$t('settings.lock_account_description')}}</label>
|
<label for="account-locked">{{$t('settings.lock_account_description')}}</label>
|
||||||
</p>
|
</p>
|
||||||
<div v-if="scopeOptionsEnabled">
|
<div>
|
||||||
<label for="default-vis">{{$t('settings.default_vis')}}</label>
|
<label for="default-vis">{{$t('settings.default_vis')}}</label>
|
||||||
<div id="default-vis" class="visibility-tray">
|
<div id="default-vis" class="visibility-tray">
|
||||||
<i v-on:click="changeVis('direct')" class="icon-mail-alt" :class="vis.direct" :title="$t('post_status.scope.direct')" ></i>
|
<scope-selector
|
||||||
<i v-on:click="changeVis('private')" class="icon-lock" :class="vis.private" :title="$t('post_status.scope.private')"></i>
|
:showAll="true"
|
||||||
<i v-on:click="changeVis('unlisted')" class="icon-lock-open-alt" :class="vis.unlisted" :title="$t('post_status.scope.unlisted')"></i>
|
:userDefault="newDefaultScope"
|
||||||
<i v-on:click="changeVis('public')" class="icon-globe" :class="vis.public" :title="$t('post_status.scope.public')"></i>
|
:onScopeChange="changeVis"/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
|
@ -61,7 +70,7 @@
|
||||||
<h2>{{$t('settings.avatar')}}</h2>
|
<h2>{{$t('settings.avatar')}}</h2>
|
||||||
<p class="visibility-notice">{{$t('settings.avatar_size_instruction')}}</p>
|
<p class="visibility-notice">{{$t('settings.avatar_size_instruction')}}</p>
|
||||||
<p>{{$t('settings.current_avatar')}}</p>
|
<p>{{$t('settings.current_avatar')}}</p>
|
||||||
<img :src="user.profile_image_url_original" class="current-avatar"></img>
|
<img :src="user.profile_image_url_original" class="current-avatar" />
|
||||||
<p>{{$t('settings.set_new_avatar')}}</p>
|
<p>{{$t('settings.set_new_avatar')}}</p>
|
||||||
<button class="btn" type="button" id="pick-avatar" v-show="pickAvatarBtnVisible">{{$t('settings.upload_a_photo')}}</button>
|
<button class="btn" type="button" id="pick-avatar" v-show="pickAvatarBtnVisible">{{$t('settings.upload_a_photo')}}</button>
|
||||||
<image-cropper trigger="#pick-avatar" :submitHandler="submitAvatar" @open="pickAvatarBtnVisible=false" @close="pickAvatarBtnVisible=true" />
|
<image-cropper trigger="#pick-avatar" :submitHandler="submitAvatar" @open="pickAvatarBtnVisible=false" @close="pickAvatarBtnVisible=true" />
|
||||||
|
@ -69,12 +78,11 @@
|
||||||
<div class="setting-item">
|
<div class="setting-item">
|
||||||
<h2>{{$t('settings.profile_banner')}}</h2>
|
<h2>{{$t('settings.profile_banner')}}</h2>
|
||||||
<p>{{$t('settings.current_profile_banner')}}</p>
|
<p>{{$t('settings.current_profile_banner')}}</p>
|
||||||
<img :src="user.cover_photo" class="banner"></img>
|
<img :src="user.cover_photo" class="banner" />
|
||||||
<p>{{$t('settings.set_new_profile_banner')}}</p>
|
<p>{{$t('settings.set_new_profile_banner')}}</p>
|
||||||
<img class="banner" v-bind:src="bannerPreview" v-if="bannerPreview">
|
<img class="banner" v-bind:src="bannerPreview" v-if="bannerPreview" />
|
||||||
</img>
|
|
||||||
<div>
|
<div>
|
||||||
<input type="file" @change="uploadFile('banner', $event)" ></input>
|
<input type="file" @change="uploadFile('banner', $event)" />
|
||||||
</div>
|
</div>
|
||||||
<i class=" icon-spin4 animate-spin uploading" v-if="bannerUploading"></i>
|
<i class=" icon-spin4 animate-spin uploading" v-if="bannerUploading"></i>
|
||||||
<button class="btn btn-default" v-else-if="bannerPreview" @click="submitBanner">{{$t('general.submit')}}</button>
|
<button class="btn btn-default" v-else-if="bannerPreview" @click="submitBanner">{{$t('general.submit')}}</button>
|
||||||
|
@ -86,10 +94,9 @@
|
||||||
<div class="setting-item">
|
<div class="setting-item">
|
||||||
<h2>{{$t('settings.profile_background')}}</h2>
|
<h2>{{$t('settings.profile_background')}}</h2>
|
||||||
<p>{{$t('settings.set_new_profile_background')}}</p>
|
<p>{{$t('settings.set_new_profile_background')}}</p>
|
||||||
<img class="bg" v-bind:src="backgroundPreview" v-if="backgroundPreview">
|
<img class="bg" v-bind:src="backgroundPreview" v-if="backgroundPreview" />
|
||||||
</img>
|
|
||||||
<div>
|
<div>
|
||||||
<input type="file" @change="uploadFile('background', $event)" ></input>
|
<input type="file" @change="uploadFile('background', $event)" />
|
||||||
</div>
|
</div>
|
||||||
<i class=" icon-spin4 animate-spin uploading" v-if="backgroundUploading"></i>
|
<i class=" icon-spin4 animate-spin uploading" v-if="backgroundUploading"></i>
|
||||||
<button class="btn btn-default" v-else-if="backgroundPreview" @click="submitBg">{{$t('general.submit')}}</button>
|
<button class="btn btn-default" v-else-if="backgroundPreview" @click="submitBg">{{$t('general.submit')}}</button>
|
||||||
|
@ -165,7 +172,7 @@
|
||||||
<h2>{{$t('settings.follow_import')}}</h2>
|
<h2>{{$t('settings.follow_import')}}</h2>
|
||||||
<p>{{$t('settings.import_followers_from_a_csv_file')}}</p>
|
<p>{{$t('settings.import_followers_from_a_csv_file')}}</p>
|
||||||
<form>
|
<form>
|
||||||
<input type="file" ref="followlist" v-on:change="followListChange"></input>
|
<input type="file" ref="followlist" v-on:change="followListChange" />
|
||||||
</form>
|
</form>
|
||||||
<i class=" icon-spin4 animate-spin uploading" v-if="followListUploading"></i>
|
<i class=" icon-spin4 animate-spin uploading" v-if="followListUploading"></i>
|
||||||
<button class="btn btn-default" v-else @click="importFollows">{{$t('general.submit')}}</button>
|
<button class="btn btn-default" v-else @click="importFollows">{{$t('general.submit')}}</button>
|
||||||
|
|
|
@ -20,7 +20,9 @@
|
||||||
"submit": "Submit",
|
"submit": "Submit",
|
||||||
"more": "More",
|
"more": "More",
|
||||||
"generic_error": "An error occured",
|
"generic_error": "An error occured",
|
||||||
"optional": "optional"
|
"optional": "optional",
|
||||||
|
"show_more": "Show more",
|
||||||
|
"show_less": "Show less"
|
||||||
},
|
},
|
||||||
"image_cropper": {
|
"image_cropper": {
|
||||||
"crop_picture": "Crop picture",
|
"crop_picture": "Crop picture",
|
||||||
|
@ -215,6 +217,7 @@
|
||||||
"saving_ok": "Settings saved",
|
"saving_ok": "Settings saved",
|
||||||
"security_tab": "Security",
|
"security_tab": "Security",
|
||||||
"scope_copy": "Copy scope when replying (DMs are always copied)",
|
"scope_copy": "Copy scope when replying (DMs are always copied)",
|
||||||
|
"minimal_scopes_mode": "Minimize post scope selection options",
|
||||||
"set_new_avatar": "Set new avatar",
|
"set_new_avatar": "Set new avatar",
|
||||||
"set_new_profile_background": "Set new profile background",
|
"set_new_profile_background": "Set new profile background",
|
||||||
"set_new_profile_banner": "Set new profile banner",
|
"set_new_profile_banner": "Set new profile banner",
|
||||||
|
|
|
@ -111,6 +111,8 @@
|
||||||
"import_theme": "Загрузить Тему",
|
"import_theme": "Загрузить Тему",
|
||||||
"inputRadius": "Поля ввода",
|
"inputRadius": "Поля ввода",
|
||||||
"checkboxRadius": "Чекбоксы",
|
"checkboxRadius": "Чекбоксы",
|
||||||
|
"instance_default": "(по умолчанию: {value})",
|
||||||
|
"instance_default_simple": "(по умолчанию)",
|
||||||
"interface": "Интерфейс",
|
"interface": "Интерфейс",
|
||||||
"interfaceLanguage": "Язык интерфейса",
|
"interfaceLanguage": "Язык интерфейса",
|
||||||
"limited_availability": "Не доступно в вашем браузере",
|
"limited_availability": "Не доступно в вашем браузере",
|
||||||
|
@ -149,7 +151,11 @@
|
||||||
"reply_visibility_all": "Показывать все ответы",
|
"reply_visibility_all": "Показывать все ответы",
|
||||||
"reply_visibility_following": "Показывать только ответы мне и тех на кого я подписан",
|
"reply_visibility_following": "Показывать только ответы мне и тех на кого я подписан",
|
||||||
"reply_visibility_self": "Показывать только ответы мне",
|
"reply_visibility_self": "Показывать только ответы мне",
|
||||||
|
"saving_err": "Не удалось сохранить настройки",
|
||||||
|
"saving_ok": "Сохранено",
|
||||||
"security_tab": "Безопасность",
|
"security_tab": "Безопасность",
|
||||||
|
"scope_copy": "Копировать видимость поста при ответе (всегда включено для Личных Сообщений)",
|
||||||
|
"minimal_scopes_mode": "Минимизировать набор опций видимости поста",
|
||||||
"set_new_avatar": "Загрузить новый аватар",
|
"set_new_avatar": "Загрузить новый аватар",
|
||||||
"set_new_profile_background": "Загрузить новый фон профиля",
|
"set_new_profile_background": "Загрузить новый фон профиля",
|
||||||
"set_new_profile_banner": "Загрузить новый баннер профиля",
|
"set_new_profile_banner": "Загрузить новый баннер профиля",
|
||||||
|
@ -164,6 +170,10 @@
|
||||||
"theme_help_v2_2": "Под некоторыми полями ввода это идикаторы контрастности, наведите на них мышью чтобы узнать больше. Приспользовании прозрачности контраст расчитывается для наихудшего варианта.",
|
"theme_help_v2_2": "Под некоторыми полями ввода это идикаторы контрастности, наведите на них мышью чтобы узнать больше. Приспользовании прозрачности контраст расчитывается для наихудшего варианта.",
|
||||||
"tooltipRadius": "Всплывающие подсказки/уведомления",
|
"tooltipRadius": "Всплывающие подсказки/уведомления",
|
||||||
"user_settings": "Настройки пользователя",
|
"user_settings": "Настройки пользователя",
|
||||||
|
"values": {
|
||||||
|
"false": "нет",
|
||||||
|
"true": "да"
|
||||||
|
},
|
||||||
"style": {
|
"style": {
|
||||||
"switcher": {
|
"switcher": {
|
||||||
"keep_color": "Оставить цвета",
|
"keep_color": "Оставить цвета",
|
||||||
|
|
|
@ -33,7 +33,8 @@ const defaultState = {
|
||||||
scopeCopy: undefined, // instance default
|
scopeCopy: undefined, // instance default
|
||||||
subjectLineBehavior: undefined, // instance default
|
subjectLineBehavior: undefined, // instance default
|
||||||
alwaysShowSubjectInput: undefined, // instance default
|
alwaysShowSubjectInput: undefined, // instance default
|
||||||
postContentType: undefined // instance default
|
postContentType: undefined, // instance default
|
||||||
|
minimalScopesMode: undefined // instance default
|
||||||
}
|
}
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
|
|
|
@ -15,7 +15,6 @@ const defaultState = {
|
||||||
redirectRootNoLogin: '/main/all',
|
redirectRootNoLogin: '/main/all',
|
||||||
redirectRootLogin: '/main/friends',
|
redirectRootLogin: '/main/friends',
|
||||||
showInstanceSpecificPanel: false,
|
showInstanceSpecificPanel: false,
|
||||||
scopeOptionsEnabled: true,
|
|
||||||
formattingOptionsEnabled: false,
|
formattingOptionsEnabled: false,
|
||||||
alwaysShowSubjectInput: true,
|
alwaysShowSubjectInput: true,
|
||||||
hideMutedPosts: false,
|
hideMutedPosts: false,
|
||||||
|
@ -32,6 +31,7 @@ const defaultState = {
|
||||||
vapidPublicKey: undefined,
|
vapidPublicKey: undefined,
|
||||||
noAttachmentLinks: false,
|
noAttachmentLinks: false,
|
||||||
showFeaturesPanel: true,
|
showFeaturesPanel: true,
|
||||||
|
minimalScopesMode: false,
|
||||||
|
|
||||||
// Nasty stuff
|
// Nasty stuff
|
||||||
pleromaBackend: true,
|
pleromaBackend: true,
|
||||||
|
|
|
@ -123,7 +123,7 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us
|
||||||
|
|
||||||
const maxNew = statuses.length > 0 ? maxBy(statuses, 'id').id : 0
|
const maxNew = statuses.length > 0 ? maxBy(statuses, 'id').id : 0
|
||||||
const minNew = statuses.length > 0 ? minBy(statuses, 'id').id : 0
|
const minNew = statuses.length > 0 ? minBy(statuses, 'id').id : 0
|
||||||
const newer = timeline && maxNew > timelineObject.maxId && statuses.length > 0
|
const newer = timeline && (maxNew > timelineObject.maxId || timelineObject.maxId === 0) && statuses.length > 0
|
||||||
const older = timeline && (minNew < timelineObject.minId || timelineObject.minId === 0) && statuses.length > 0
|
const older = timeline && (minNew < timelineObject.minId || timelineObject.minId === 0) && statuses.length > 0
|
||||||
|
|
||||||
if (!noIdUpdate && newer) {
|
if (!noIdUpdate && newer) {
|
||||||
|
@ -363,6 +363,15 @@ export const mutations = {
|
||||||
},
|
},
|
||||||
setRetweeted (state, { status, value }) {
|
setRetweeted (state, { status, value }) {
|
||||||
const newStatus = state.allStatusesObject[status.id]
|
const newStatus = state.allStatusesObject[status.id]
|
||||||
|
|
||||||
|
if (newStatus.repeated !== value) {
|
||||||
|
if (value) {
|
||||||
|
newStatus.repeat_num++
|
||||||
|
} else {
|
||||||
|
newStatus.repeat_num--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
newStatus.repeated = value
|
newStatus.repeated = value
|
||||||
},
|
},
|
||||||
setDeleted (state, { status }) {
|
setDeleted (state, { status }) {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { includes } from 'lodash'
|
import { includes } from 'lodash'
|
||||||
|
|
||||||
const generateProfileLink = (id, screenName, restrictedNicknames) => {
|
const generateProfileLink = (id, screenName, restrictedNicknames) => {
|
||||||
const complicated = (isExternal(screenName) || includes(restrictedNicknames, screenName))
|
const complicated = !screenName || (isExternal(screenName) || includes(restrictedNicknames, screenName))
|
||||||
return {
|
return {
|
||||||
name: (complicated ? 'external-user-profile' : 'user-profile'),
|
name: (complicated ? 'external-user-profile' : 'user-profile'),
|
||||||
params: (complicated ? { id } : { name: screenName })
|
params: (complicated ? { id } : { name: screenName })
|
||||||
|
|
|
@ -8,7 +8,6 @@
|
||||||
"redirectRootLogin": "/main/friends",
|
"redirectRootLogin": "/main/friends",
|
||||||
"chatDisabled": false,
|
"chatDisabled": false,
|
||||||
"showInstanceSpecificPanel": false,
|
"showInstanceSpecificPanel": false,
|
||||||
"scopeOptionsEnabled": false,
|
|
||||||
"formattingOptionsEnabled": false,
|
"formattingOptionsEnabled": false,
|
||||||
"collapseMessageWithSubject": false,
|
"collapseMessageWithSubject": false,
|
||||||
"scopeCopy": true,
|
"scopeCopy": true,
|
||||||
|
@ -21,5 +20,6 @@
|
||||||
"webPushNotifications": false,
|
"webPushNotifications": false,
|
||||||
"noAttachmentLinks": false,
|
"noAttachmentLinks": false,
|
||||||
"nsfwCensorImage": "",
|
"nsfwCensorImage": "",
|
||||||
"showFeaturesPanel": true
|
"showFeaturesPanel": true,
|
||||||
|
"minimalScopesMode": false
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue