Merge branch 'develop' into 'feat/conversation-muting'
# Conflicts: # src/components/extra_buttons/extra_buttons.js # src/components/extra_buttons/extra_buttons.vue
This commit is contained in:
commit
d3f6b581d1
28 changed files with 638 additions and 177 deletions
|
@ -24,9 +24,6 @@ var devMiddleware = require('webpack-dev-middleware')(compiler, {
|
||||||
stats: {
|
stats: {
|
||||||
colors: true,
|
colors: true,
|
||||||
chunks: false
|
chunks: false
|
||||||
},
|
|
||||||
headers: {
|
|
||||||
'content-security-policy': "base-uri 'self'; frame-ancestors 'none'; img-src 'self' data: https:; media-src 'self' https:; style-src 'self' 'unsafe-inline'; font-src 'self'; manifest-src 'self'; script-src 'self' 'unsafe-eval';"
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
|
|
@ -25,14 +25,13 @@
|
||||||
"localforage": "^1.5.0",
|
"localforage": "^1.5.0",
|
||||||
"object-path": "^0.11.3",
|
"object-path": "^0.11.3",
|
||||||
"phoenix": "^1.3.0",
|
"phoenix": "^1.3.0",
|
||||||
"popper.js": "^1.14.7",
|
|
||||||
"portal-vue": "^2.1.4",
|
"portal-vue": "^2.1.4",
|
||||||
"sanitize-html": "^1.13.0",
|
"sanitize-html": "^1.13.0",
|
||||||
"v-click-outside": "^2.1.1",
|
"v-click-outside": "^2.1.1",
|
||||||
|
"v-tooltip": "^2.0.2",
|
||||||
"vue": "^2.5.13",
|
"vue": "^2.5.13",
|
||||||
"vue-chat-scroll": "^1.2.1",
|
"vue-chat-scroll": "^1.2.1",
|
||||||
"vue-i18n": "^7.3.2",
|
"vue-i18n": "^7.3.2",
|
||||||
"vue-popperjs": "^2.0.3",
|
|
||||||
"vue-router": "^3.0.1",
|
"vue-router": "^3.0.1",
|
||||||
"vue-template-compiler": "^2.3.4",
|
"vue-template-compiler": "^2.3.4",
|
||||||
"vuelidate": "^0.7.4",
|
"vuelidate": "^0.7.4",
|
||||||
|
@ -81,8 +80,8 @@
|
||||||
"json-loader": "^0.5.4",
|
"json-loader": "^0.5.4",
|
||||||
"karma": "^3.0.0",
|
"karma": "^3.0.0",
|
||||||
"karma-coverage": "^1.1.1",
|
"karma-coverage": "^1.1.1",
|
||||||
"karma-mocha": "^1.2.0",
|
|
||||||
"karma-firefox-launcher": "^1.1.0",
|
"karma-firefox-launcher": "^1.1.0",
|
||||||
|
"karma-mocha": "^1.2.0",
|
||||||
"karma-sinon-chai": "^2.0.2",
|
"karma-sinon-chai": "^2.0.2",
|
||||||
"karma-sourcemap-loader": "^0.3.7",
|
"karma-sourcemap-loader": "^0.3.7",
|
||||||
"karma-spec-reporter": "0.0.26",
|
"karma-spec-reporter": "0.0.26",
|
||||||
|
|
|
@ -148,6 +148,37 @@ const getInstancePanel = async ({ store }) => {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getStickers = async ({ store }) => {
|
||||||
|
try {
|
||||||
|
const res = await window.fetch('/static/stickers.json')
|
||||||
|
if (res.ok) {
|
||||||
|
const values = await res.json()
|
||||||
|
const stickers = (await Promise.all(
|
||||||
|
Object.entries(values).map(async ([name, path]) => {
|
||||||
|
const resPack = await window.fetch(path + 'pack.json')
|
||||||
|
var meta = {}
|
||||||
|
if (resPack.ok) {
|
||||||
|
meta = await resPack.json()
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
pack: name,
|
||||||
|
path,
|
||||||
|
meta
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)).sort((a, b) => {
|
||||||
|
return a.meta.title.localeCompare(b.meta.title)
|
||||||
|
})
|
||||||
|
store.dispatch('setInstanceOption', { name: 'stickers', value: stickers })
|
||||||
|
} else {
|
||||||
|
throw (res)
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
console.warn("Can't load stickers")
|
||||||
|
console.warn(e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const getStaticEmoji = async ({ store }) => {
|
const getStaticEmoji = async ({ store }) => {
|
||||||
try {
|
try {
|
||||||
const res = await window.fetch('/static/emoji.json')
|
const res = await window.fetch('/static/emoji.json')
|
||||||
|
@ -286,6 +317,7 @@ const afterStoreSetup = async ({ store, i18n }) => {
|
||||||
setConfig({ store }),
|
setConfig({ store }),
|
||||||
getTOS({ store }),
|
getTOS({ store }),
|
||||||
getInstancePanel({ store }),
|
getInstancePanel({ store }),
|
||||||
|
getStickers({ store }),
|
||||||
getStaticEmoji({ store }),
|
getStaticEmoji({ store }),
|
||||||
getCustomEmoji({ store }),
|
getCustomEmoji({ store }),
|
||||||
getNodeInfo({ store })
|
getNodeInfo({ store })
|
||||||
|
|
|
@ -19,6 +19,14 @@ import WhoToFollow from 'components/who_to_follow/who_to_follow.vue'
|
||||||
import About from 'components/about/about.vue'
|
import About from 'components/about/about.vue'
|
||||||
|
|
||||||
export default (store) => {
|
export default (store) => {
|
||||||
|
const validateAuthenticatedRoute = (to, from, next) => {
|
||||||
|
if (store.state.users.currentUser) {
|
||||||
|
next()
|
||||||
|
} else {
|
||||||
|
next(store.state.instance.redirectRootNoLogin || '/main/all')
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return [
|
return [
|
||||||
{ name: 'root',
|
{ name: 'root',
|
||||||
path: '/',
|
path: '/',
|
||||||
|
@ -30,23 +38,23 @@ export default (store) => {
|
||||||
},
|
},
|
||||||
{ name: 'public-external-timeline', path: '/main/all', component: PublicAndExternalTimeline },
|
{ name: 'public-external-timeline', path: '/main/all', component: PublicAndExternalTimeline },
|
||||||
{ name: 'public-timeline', path: '/main/public', component: PublicTimeline },
|
{ name: 'public-timeline', path: '/main/public', component: PublicTimeline },
|
||||||
{ name: 'friends', path: '/main/friends', component: FriendsTimeline },
|
{ name: 'friends', path: '/main/friends', component: FriendsTimeline, beforeEnter: validateAuthenticatedRoute },
|
||||||
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
|
{ name: 'tag-timeline', path: '/tag/:tag', component: TagTimeline },
|
||||||
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
|
{ name: 'conversation', path: '/notice/:id', component: ConversationPage, meta: { dontScroll: true } },
|
||||||
{ name: 'external-user-profile', path: '/users/:id', component: UserProfile },
|
{ name: 'external-user-profile', path: '/users/:id', component: UserProfile },
|
||||||
{ name: 'interactions', path: '/users/:username/interactions', component: Interactions },
|
{ name: 'interactions', path: '/users/:username/interactions', component: Interactions, beforeEnter: validateAuthenticatedRoute },
|
||||||
{ name: 'dms', path: '/users/:username/dms', component: DMs },
|
{ name: 'dms', path: '/users/:username/dms', component: DMs, beforeEnter: validateAuthenticatedRoute },
|
||||||
{ name: 'settings', path: '/settings', component: Settings },
|
{ name: 'settings', path: '/settings', component: Settings },
|
||||||
{ name: 'registration', path: '/registration', component: Registration },
|
{ name: 'registration', path: '/registration', component: Registration },
|
||||||
{ name: 'registration-token', path: '/registration/:token', component: Registration },
|
{ name: 'registration-token', path: '/registration/:token', component: Registration },
|
||||||
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests },
|
{ name: 'friend-requests', path: '/friend-requests', component: FollowRequests, beforeEnter: validateAuthenticatedRoute },
|
||||||
{ name: 'user-settings', path: '/user-settings', component: UserSettings },
|
{ name: 'user-settings', path: '/user-settings', component: UserSettings, beforeEnter: validateAuthenticatedRoute },
|
||||||
{ name: 'notifications', path: '/:username/notifications', component: Notifications },
|
{ name: 'notifications', path: '/:username/notifications', component: Notifications, beforeEnter: validateAuthenticatedRoute },
|
||||||
{ name: 'login', path: '/login', component: AuthForm },
|
{ name: 'login', path: '/login', component: AuthForm },
|
||||||
{ name: 'chat', path: '/chat', component: ChatPanel, props: () => ({ floating: false }) },
|
{ name: 'chat', path: '/chat', component: ChatPanel, props: () => ({ floating: false }) },
|
||||||
{ name: 'oauth-callback', path: '/oauth-callback', component: OAuthCallback, props: (route) => ({ code: route.query.code }) },
|
{ name: 'oauth-callback', path: '/oauth-callback', component: OAuthCallback, props: (route) => ({ code: route.query.code }) },
|
||||||
{ name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) },
|
{ name: 'search', path: '/search', component: Search, props: (route) => ({ query: route.query.query }) },
|
||||||
{ name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow },
|
{ name: 'who-to-follow', path: '/who-to-follow', component: WhoToFollow, beforeEnter: validateAuthenticatedRoute },
|
||||||
{ name: 'about', path: '/about', component: About },
|
{ name: 'about', path: '/about', component: About },
|
||||||
{ name: 'user-profile', path: '/(users/)?:name', component: UserProfile }
|
{ name: 'user-profile', path: '/(users/)?:name', component: UserProfile }
|
||||||
]
|
]
|
||||||
|
|
|
@ -1,20 +1,27 @@
|
||||||
|
import { debounce } from 'lodash'
|
||||||
/**
|
/**
|
||||||
* suggest - generates a suggestor function to be used by emoji-input
|
* suggest - generates a suggestor function to be used by emoji-input
|
||||||
* data: object providing source information for specific types of suggestions:
|
* data: object providing source information for specific types of suggestions:
|
||||||
* data.emoji - optional, an array of all emoji available i.e.
|
* data.emoji - optional, an array of all emoji available i.e.
|
||||||
* (state.instance.emoji + state.instance.customEmoji)
|
* (state.instance.emoji + state.instance.customEmoji)
|
||||||
* data.users - optional, an array of all known users
|
* data.users - optional, an array of all known users
|
||||||
|
* updateUsersList - optional, a function to search and append to users
|
||||||
*
|
*
|
||||||
* Depending on data present one or both (or none) can be present, so if field
|
* Depending on data present one or both (or none) can be present, so if field
|
||||||
* doesn't support user linking you can just provide only emoji.
|
* doesn't support user linking you can just provide only emoji.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
const debounceUserSearch = debounce((data, input) => {
|
||||||
|
data.updateUsersList(input)
|
||||||
|
}, 500, { leading: true, trailing: false })
|
||||||
|
|
||||||
export default data => input => {
|
export default data => input => {
|
||||||
const firstChar = input[0]
|
const firstChar = input[0]
|
||||||
if (firstChar === ':' && data.emoji) {
|
if (firstChar === ':' && data.emoji) {
|
||||||
return suggestEmoji(data.emoji)(input)
|
return suggestEmoji(data.emoji)(input)
|
||||||
}
|
}
|
||||||
if (firstChar === '@' && data.users) {
|
if (firstChar === '@' && data.users) {
|
||||||
return suggestUsers(data.users)(input)
|
return suggestUsers(data)(input)
|
||||||
}
|
}
|
||||||
return []
|
return []
|
||||||
}
|
}
|
||||||
|
@ -38,9 +45,11 @@ export const suggestEmoji = emojis => input => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
export const suggestUsers = users => input => {
|
export const suggestUsers = data => input => {
|
||||||
const noPrefix = input.toLowerCase().substr(1)
|
const noPrefix = input.toLowerCase().substr(1)
|
||||||
return users.filter(
|
const users = data.users
|
||||||
|
|
||||||
|
const newUsers = users.filter(
|
||||||
user =>
|
user =>
|
||||||
user.screen_name.toLowerCase().startsWith(noPrefix) ||
|
user.screen_name.toLowerCase().startsWith(noPrefix) ||
|
||||||
user.name.toLowerCase().startsWith(noPrefix)
|
user.name.toLowerCase().startsWith(noPrefix)
|
||||||
|
@ -75,5 +84,11 @@ export const suggestUsers = users => input => {
|
||||||
imageUrl: profile_image_url_original,
|
imageUrl: profile_image_url_original,
|
||||||
replacement: '@' + screen_name + ' '
|
replacement: '@' + screen_name + ' '
|
||||||
}))
|
}))
|
||||||
|
|
||||||
|
// BE search users if there are no matches
|
||||||
|
if (newUsers.length === 0 && data.updateUsersList) {
|
||||||
|
debounceUserSearch(data, noPrefix)
|
||||||
|
}
|
||||||
|
return newUsers
|
||||||
/* eslint-enable camelcase */
|
/* eslint-enable camelcase */
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,35 +1,18 @@
|
||||||
import Popper from 'vue-popperjs/src/component/popper.js.vue'
|
|
||||||
|
|
||||||
const ExtraButtons = {
|
const ExtraButtons = {
|
||||||
props: [ 'status' ],
|
props: [ 'status' ],
|
||||||
components: {
|
|
||||||
Popper
|
|
||||||
},
|
|
||||||
data () {
|
|
||||||
return {
|
|
||||||
showDropDown: false,
|
|
||||||
showPopper: true
|
|
||||||
}
|
|
||||||
},
|
|
||||||
methods: {
|
methods: {
|
||||||
deleteStatus () {
|
deleteStatus () {
|
||||||
this.refreshPopper()
|
|
||||||
const confirmed = window.confirm(this.$t('status.delete_confirm'))
|
const confirmed = window.confirm(this.$t('status.delete_confirm'))
|
||||||
if (confirmed) {
|
if (confirmed) {
|
||||||
this.$store.dispatch('deleteStatus', { id: this.status.id })
|
this.$store.dispatch('deleteStatus', { id: this.status.id })
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
toggleMenu () {
|
|
||||||
this.showDropDown = !this.showDropDown
|
|
||||||
},
|
|
||||||
pinStatus () {
|
pinStatus () {
|
||||||
this.refreshPopper()
|
|
||||||
this.$store.dispatch('pinStatus', this.status.id)
|
this.$store.dispatch('pinStatus', this.status.id)
|
||||||
.then(() => this.$emit('onSuccess'))
|
.then(() => this.$emit('onSuccess'))
|
||||||
.catch(err => this.$emit('onError', err.error.error))
|
.catch(err => this.$emit('onError', err.error.error))
|
||||||
},
|
},
|
||||||
unpinStatus () {
|
unpinStatus () {
|
||||||
this.refreshPopper()
|
|
||||||
this.$store.dispatch('unpinStatus', this.status.id)
|
this.$store.dispatch('unpinStatus', this.status.id)
|
||||||
.then(() => this.$emit('onSuccess'))
|
.then(() => this.$emit('onSuccess'))
|
||||||
.catch(err => this.$emit('onError', err.error.error))
|
.catch(err => this.$emit('onError', err.error.error))
|
||||||
|
@ -45,13 +28,6 @@ const ExtraButtons = {
|
||||||
this.$store.dispatch('unmuteConversation', this.status.id)
|
this.$store.dispatch('unmuteConversation', this.status.id)
|
||||||
.then(() => this.$emit('onSuccess'))
|
.then(() => this.$emit('onSuccess'))
|
||||||
.catch(err => this.$emit('onError', err.error.error))
|
.catch(err => this.$emit('onError', err.error.error))
|
||||||
},
|
|
||||||
refreshPopper () {
|
|
||||||
this.showPopper = false
|
|
||||||
this.showDropDown = false
|
|
||||||
setTimeout(() => {
|
|
||||||
this.showPopper = true
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
|
|
@ -1,18 +1,13 @@
|
||||||
<template>
|
<template>
|
||||||
<Popper
|
<v-popover
|
||||||
v-if="showPopper"
|
v-if="enabled"
|
||||||
trigger="click"
|
trigger="click"
|
||||||
append-to-body
|
placement="top"
|
||||||
:options="{
|
class="extra-button-popover"
|
||||||
placement: 'top',
|
:offset="5"
|
||||||
modifiers: {
|
:container="false"
|
||||||
arrow: { enabled: true },
|
|
||||||
offset: { offset: '0, 5px' },
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
@hide="showDropDown = false"
|
|
||||||
>
|
>
|
||||||
<div class="popper-wrapper">
|
<div slot="popover">
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<button
|
<button
|
||||||
v-if="!status.muted"
|
v-if="!status.muted"
|
||||||
|
@ -30,6 +25,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="!status.pinned && canPin"
|
v-if="!status.pinned && canPin"
|
||||||
|
v-close-popover
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="pinStatus"
|
@click.prevent="pinStatus"
|
||||||
>
|
>
|
||||||
|
@ -37,6 +33,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="status.pinned && canPin"
|
v-if="status.pinned && canPin"
|
||||||
|
v-close-popover
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="unpinStatus"
|
@click.prevent="unpinStatus"
|
||||||
>
|
>
|
||||||
|
@ -44,6 +41,7 @@
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
v-if="canDelete"
|
v-if="canDelete"
|
||||||
|
v-close-popover
|
||||||
class="dropdown-item dropdown-item-icon"
|
class="dropdown-item dropdown-item-icon"
|
||||||
@click.prevent="deleteStatus"
|
@click.prevent="deleteStatus"
|
||||||
>
|
>
|
||||||
|
@ -51,17 +49,10 @@
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div
|
<div class="button-icon">
|
||||||
slot="reference"
|
<i class="icon-ellipsis" />
|
||||||
class="button-icon"
|
|
||||||
@click="toggleMenu"
|
|
||||||
>
|
|
||||||
<i
|
|
||||||
class="icon-ellipsis"
|
|
||||||
:class="{'icon-clicked': showDropDown}"
|
|
||||||
/>
|
|
||||||
</div>
|
</div>
|
||||||
</Popper>
|
</v-popover>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script src="./extra_buttons.js" ></script>
|
<script src="./extra_buttons.js" ></script>
|
||||||
|
@ -73,7 +64,8 @@
|
||||||
.icon-ellipsis {
|
.icon-ellipsis {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
|
||||||
&:hover, &.icon-clicked {
|
&:hover,
|
||||||
|
.extra-button-popover.open & {
|
||||||
color: $fallback--text;
|
color: $fallback--text;
|
||||||
color: var(--text, $fallback--text);
|
color: var(--text, $fallback--text);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import DialogModal from '../dialog_modal/dialog_modal.vue'
|
import DialogModal from '../dialog_modal/dialog_modal.vue'
|
||||||
import Popper from 'vue-popperjs/src/component/popper.js.vue'
|
|
||||||
|
|
||||||
const FORCE_NSFW = 'mrf_tag:media-force-nsfw'
|
const FORCE_NSFW = 'mrf_tag:media-force-nsfw'
|
||||||
const STRIP_MEDIA = 'mrf_tag:media-strip'
|
const STRIP_MEDIA = 'mrf_tag:media-strip'
|
||||||
|
@ -29,8 +28,7 @@ const ModerationTools = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
DialogModal,
|
DialogModal
|
||||||
Popper
|
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
tagsSet () {
|
tagsSet () {
|
||||||
|
@ -41,9 +39,6 @@ const ModerationTools = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
methods: {
|
methods: {
|
||||||
toggleMenu () {
|
|
||||||
this.showDropDown = !this.showDropDown
|
|
||||||
},
|
|
||||||
hasTag (tagName) {
|
hasTag (tagName) {
|
||||||
return this.tagsSet.has(tagName)
|
return this.tagsSet.has(tagName)
|
||||||
},
|
},
|
||||||
|
|
|
@ -1,18 +1,15 @@
|
||||||
<template>
|
<template>
|
||||||
<div>
|
<div>
|
||||||
<Popper
|
<v-popover
|
||||||
trigger="click"
|
trigger="click"
|
||||||
append-to-body
|
class="moderation-tools-popover"
|
||||||
:options="{
|
:container="false"
|
||||||
placement: 'bottom-end',
|
placement="bottom-end"
|
||||||
modifiers: {
|
:offset="5"
|
||||||
arrow: { enabled: true },
|
@show="showDropDown = true"
|
||||||
offset: { offset: '0, 5px' },
|
|
||||||
}
|
|
||||||
}"
|
|
||||||
@hide="showDropDown = false"
|
@hide="showDropDown = false"
|
||||||
>
|
>
|
||||||
<div class="popper-wrapper">
|
<div slot="popover">
|
||||||
<div class="dropdown-menu">
|
<div class="dropdown-menu">
|
||||||
<span v-if="user.is_local">
|
<span v-if="user.is_local">
|
||||||
<button
|
<button
|
||||||
|
@ -127,14 +124,12 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<button
|
<button
|
||||||
slot="reference"
|
|
||||||
class="btn btn-default btn-block"
|
class="btn btn-default btn-block"
|
||||||
:class="{ pressed: showDropDown }"
|
:class="{ pressed: showDropDown }"
|
||||||
@click="toggleMenu"
|
|
||||||
>
|
>
|
||||||
{{ $t('user_card.admin_menu.moderation') }}
|
{{ $t('user_card.admin_menu.moderation') }}
|
||||||
</button>
|
</button>
|
||||||
</Popper>
|
</v-popover>
|
||||||
<portal to="modal">
|
<portal to="modal">
|
||||||
<DialogModal
|
<DialogModal
|
||||||
v-if="showDeleteUserDialog"
|
v-if="showDeleteUserDialog"
|
||||||
|
@ -188,4 +183,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.moderation-tools-popover {
|
||||||
|
height: 100%;
|
||||||
|
.trigger {
|
||||||
|
display: flex !important;
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
|
|
@ -1,71 +1,99 @@
|
||||||
@import '../../_variables.scss';
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
.popper-wrapper {
|
.tooltip.popover {
|
||||||
z-index: 8;
|
z-index: 8;
|
||||||
}
|
|
||||||
|
|
||||||
.popper-wrapper .popper__arrow {
|
.popover-inner {
|
||||||
|
box-shadow: 1px 1px 4px rgba(0,0,0,.6);
|
||||||
|
box-shadow: var(--panelShadow);
|
||||||
|
border-radius: $fallback--btnRadius;
|
||||||
|
border-radius: var(--btnRadius, $fallback--btnRadius);
|
||||||
|
background-color: $fallback--bg;
|
||||||
|
background-color: var(--bg, $fallback--bg);
|
||||||
|
}
|
||||||
|
|
||||||
|
.popover-arrow {
|
||||||
width: 0;
|
width: 0;
|
||||||
height: 0;
|
height: 0;
|
||||||
border-style: solid;
|
border-style: solid;
|
||||||
position: absolute;
|
position: absolute;
|
||||||
margin: 5px;
|
margin: 5px;
|
||||||
}
|
border-color: $fallback--bg;
|
||||||
|
border-color: var(--bg, $fallback--bg);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
.popper-wrapper[x-placement^="top"] {
|
&[x-placement^="top"] {
|
||||||
margin-bottom: 5px;
|
margin-bottom: 5px;
|
||||||
}
|
|
||||||
|
|
||||||
.popper-wrapper[x-placement^="top"] .popper__arrow {
|
.popover-arrow {
|
||||||
border-width: 5px 5px 0 5px;
|
border-width: 5px 5px 0 5px;
|
||||||
border-color: $fallback--bg transparent transparent transparent;
|
border-left-color: transparent !important;
|
||||||
border-color: var(--bg, $fallback--bg) transparent transparent transparent;
|
border-right-color: transparent !important;
|
||||||
|
border-bottom-color: transparent !important;
|
||||||
bottom: -5px;
|
bottom: -5px;
|
||||||
left: calc(50% - 5px);
|
left: calc(50% - 5px);
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.popper-wrapper[x-placement^="bottom"] {
|
&[x-placement^="bottom"] {
|
||||||
margin-top: 5px;
|
margin-top: 5px;
|
||||||
}
|
|
||||||
|
|
||||||
.popper-wrapper[x-placement^="bottom"] .popper__arrow {
|
.popover-arrow {
|
||||||
border-width: 0 5px 5px 5px;
|
border-width: 0 5px 5px 5px;
|
||||||
border-color: transparent transparent $fallback--bg transparent;
|
border-left-color: transparent !important;
|
||||||
border-color: transparent transparent var(--bg, $fallback--bg) transparent;
|
border-right-color: transparent !important;
|
||||||
|
border-top-color: transparent !important;
|
||||||
top: -5px;
|
top: -5px;
|
||||||
left: calc(50% - 5px);
|
left: calc(50% - 5px);
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
margin-bottom: 0;
|
margin-bottom: 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.popper-wrapper[x-placement^="right"] {
|
&[x-placement^="right"] {
|
||||||
margin-left: 5px;
|
margin-left: 5px;
|
||||||
}
|
|
||||||
|
|
||||||
.popper-wrapper[x-placement^="right"] .popper__arrow {
|
.popover-arrow {
|
||||||
border-width: 5px 5px 5px 0;
|
border-width: 5px 5px 5px 0;
|
||||||
border-color: transparent $fallback--bg transparent transparent;
|
border-left-color: transparent !important;
|
||||||
border-color: transparent var(--bg, $fallback--bg) transparent transparent;
|
border-top-color: transparent !important;
|
||||||
|
border-bottom-color: transparent !important;
|
||||||
left: -5px;
|
left: -5px;
|
||||||
top: calc(50% - 5px);
|
top: calc(50% - 5px);
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.popper-wrapper[x-placement^="left"] {
|
&[x-placement^="left"] {
|
||||||
margin-right: 5px;
|
margin-right: 5px;
|
||||||
}
|
|
||||||
|
|
||||||
.popper-wrapper[x-placement^="left"] .popper__arrow {
|
.popover-arrow {
|
||||||
border-width: 5px 0 5px 5px;
|
border-width: 5px 0 5px 5px;
|
||||||
border-color: transparent transparent transparent $fallback--bg;
|
border-top-color: transparent !important;
|
||||||
border-color: transparent transparent transparent var(--bg, $fallback--bg);
|
border-right-color: transparent !important;
|
||||||
|
border-bottom-color: transparent !important;
|
||||||
right: -5px;
|
right: -5px;
|
||||||
top: calc(50% - 5px);
|
top: calc(50% - 5px);
|
||||||
margin-left: 0;
|
margin-left: 0;
|
||||||
margin-right: 0;
|
margin-right: 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
&[aria-hidden='true'] {
|
||||||
|
visibility: hidden;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity .15s, visibility .15s;
|
||||||
|
}
|
||||||
|
|
||||||
|
&[aria-hidden='false'] {
|
||||||
|
visibility: visible;
|
||||||
|
opacity: 1;
|
||||||
|
transition: opacity .15s;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.dropdown-menu {
|
.dropdown-menu {
|
||||||
|
@ -76,13 +104,6 @@
|
||||||
list-style: none;
|
list-style: none;
|
||||||
max-width: 100vw;
|
max-width: 100vw;
|
||||||
z-index: 10;
|
z-index: 10;
|
||||||
box-shadow: 1px 1px 4px rgba(0,0,0,.6);
|
|
||||||
box-shadow: var(--panelShadow);
|
|
||||||
border: none;
|
|
||||||
border-radius: $fallback--btnRadius;
|
|
||||||
border-radius: var(--btnRadius, $fallback--btnRadius);
|
|
||||||
background-color: $fallback--bg;
|
|
||||||
background-color: var(--bg, $fallback--bg);
|
|
||||||
|
|
||||||
.dropdown-divider {
|
.dropdown-divider {
|
||||||
height: 0;
|
height: 0;
|
||||||
|
|
|
@ -3,6 +3,7 @@ import MediaUpload from '../media_upload/media_upload.vue'
|
||||||
import ScopeSelector from '../scope_selector/scope_selector.vue'
|
import ScopeSelector from '../scope_selector/scope_selector.vue'
|
||||||
import EmojiInput from '../emoji-input/emoji-input.vue'
|
import EmojiInput from '../emoji-input/emoji-input.vue'
|
||||||
import PollForm from '../poll/poll_form.vue'
|
import PollForm from '../poll/poll_form.vue'
|
||||||
|
import StickerPicker from '../sticker_picker/sticker_picker.vue'
|
||||||
import fileTypeService from '../../services/file_type/file_type.service.js'
|
import fileTypeService from '../../services/file_type/file_type.service.js'
|
||||||
import { reject, map, uniqBy } from 'lodash'
|
import { reject, map, uniqBy } from 'lodash'
|
||||||
import suggestor from '../emoji-input/suggestor.js'
|
import suggestor from '../emoji-input/suggestor.js'
|
||||||
|
@ -34,6 +35,7 @@ const PostStatusForm = {
|
||||||
MediaUpload,
|
MediaUpload,
|
||||||
EmojiInput,
|
EmojiInput,
|
||||||
PollForm,
|
PollForm,
|
||||||
|
StickerPicker,
|
||||||
ScopeSelector
|
ScopeSelector
|
||||||
},
|
},
|
||||||
mounted () {
|
mounted () {
|
||||||
|
@ -82,7 +84,8 @@ const PostStatusForm = {
|
||||||
contentType
|
contentType
|
||||||
},
|
},
|
||||||
caret: 0,
|
caret: 0,
|
||||||
pollFormVisible: false
|
pollFormVisible: false,
|
||||||
|
stickerPickerVisible: false
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
@ -104,7 +107,8 @@ const PostStatusForm = {
|
||||||
...this.$store.state.instance.emoji,
|
...this.$store.state.instance.emoji,
|
||||||
...this.$store.state.instance.customEmoji
|
...this.$store.state.instance.customEmoji
|
||||||
],
|
],
|
||||||
users: this.$store.state.users.users
|
users: this.$store.state.users.users,
|
||||||
|
updateUsersList: (input) => this.$store.dispatch('searchUsers', input)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
emojiSuggestor () {
|
emojiSuggestor () {
|
||||||
|
@ -157,6 +161,12 @@ const PostStatusForm = {
|
||||||
safeDMEnabled () {
|
safeDMEnabled () {
|
||||||
return this.$store.state.instance.safeDM
|
return this.$store.state.instance.safeDM
|
||||||
},
|
},
|
||||||
|
stickersAvailable () {
|
||||||
|
if (this.$store.state.instance.stickers) {
|
||||||
|
return this.$store.state.instance.stickers.length > 0
|
||||||
|
}
|
||||||
|
return 0
|
||||||
|
},
|
||||||
pollsAvailable () {
|
pollsAvailable () {
|
||||||
return this.$store.state.instance.pollsAvailable &&
|
return this.$store.state.instance.pollsAvailable &&
|
||||||
this.$store.state.instance.pollLimits.max_options >= 2
|
this.$store.state.instance.pollLimits.max_options >= 2
|
||||||
|
@ -212,6 +222,7 @@ const PostStatusForm = {
|
||||||
poll: {}
|
poll: {}
|
||||||
}
|
}
|
||||||
this.pollFormVisible = false
|
this.pollFormVisible = false
|
||||||
|
this.stickerPickerVisible = false
|
||||||
this.$refs.mediaUpload.clearFile()
|
this.$refs.mediaUpload.clearFile()
|
||||||
this.clearPollForm()
|
this.clearPollForm()
|
||||||
this.$emit('posted')
|
this.$emit('posted')
|
||||||
|
@ -228,6 +239,7 @@ const PostStatusForm = {
|
||||||
addMediaFile (fileInfo) {
|
addMediaFile (fileInfo) {
|
||||||
this.newStatus.files.push(fileInfo)
|
this.newStatus.files.push(fileInfo)
|
||||||
this.enableSubmit()
|
this.enableSubmit()
|
||||||
|
this.stickerPickerVisible = false
|
||||||
},
|
},
|
||||||
removeMediaFile (fileInfo) {
|
removeMediaFile (fileInfo) {
|
||||||
let index = this.newStatus.files.indexOf(fileInfo)
|
let index = this.newStatus.files.indexOf(fileInfo)
|
||||||
|
@ -287,6 +299,14 @@ const PostStatusForm = {
|
||||||
changeVis (visibility) {
|
changeVis (visibility) {
|
||||||
this.newStatus.visibility = visibility
|
this.newStatus.visibility = visibility
|
||||||
},
|
},
|
||||||
|
toggleStickerPicker () {
|
||||||
|
this.stickerPickerVisible = !this.stickerPickerVisible
|
||||||
|
},
|
||||||
|
clearStickerPicker () {
|
||||||
|
if (this.$refs.stickerPicker) {
|
||||||
|
this.$refs.stickerPicker.clear()
|
||||||
|
}
|
||||||
|
},
|
||||||
togglePollForm () {
|
togglePollForm () {
|
||||||
this.pollFormVisible = !this.pollFormVisible
|
this.pollFormVisible = !this.pollFormVisible
|
||||||
},
|
},
|
||||||
|
|
|
@ -157,6 +157,17 @@
|
||||||
@uploaded="addMediaFile"
|
@uploaded="addMediaFile"
|
||||||
@upload-failed="uploadFailed"
|
@upload-failed="uploadFailed"
|
||||||
/>
|
/>
|
||||||
|
<div
|
||||||
|
v-if="stickersAvailable"
|
||||||
|
class="sticker-icon"
|
||||||
|
>
|
||||||
|
<i
|
||||||
|
:title="$t('stickers.add_sticker')"
|
||||||
|
class="icon-picture btn btn-default"
|
||||||
|
:class="{ selected: stickerPickerVisible }"
|
||||||
|
@click="toggleStickerPicker"
|
||||||
|
/>
|
||||||
|
</div>
|
||||||
<div
|
<div
|
||||||
v-if="pollsAvailable"
|
v-if="pollsAvailable"
|
||||||
class="poll-icon"
|
class="poll-icon"
|
||||||
|
@ -169,7 +180,6 @@
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button
|
<button
|
||||||
v-if="posting"
|
v-if="posting"
|
||||||
disabled
|
disabled
|
||||||
|
@ -248,6 +258,11 @@
|
||||||
<label for="filesSensitive">{{ $t('post_status.attachments_sensitive') }}</label>
|
<label for="filesSensitive">{{ $t('post_status.attachments_sensitive') }}</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<sticker-picker
|
||||||
|
v-if="stickerPickerVisible"
|
||||||
|
ref="stickerPicker"
|
||||||
|
@uploaded="addMediaFile"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
@ -310,7 +325,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.poll-icon {
|
.poll-icon, .sticker-icon {
|
||||||
font-size: 26px;
|
font-size: 26px;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
|
|
||||||
|
@ -320,6 +335,11 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.sticker-icon {
|
||||||
|
flex: 0;
|
||||||
|
min-width: 50px;
|
||||||
|
}
|
||||||
|
|
||||||
.icon-chart-bar {
|
.icon-chart-bar {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -110,8 +110,9 @@ const Status = {
|
||||||
},
|
},
|
||||||
muteWordHits () {
|
muteWordHits () {
|
||||||
const statusText = this.status.text.toLowerCase()
|
const statusText = this.status.text.toLowerCase()
|
||||||
|
const statusSummary = this.status.summary.toLowerCase()
|
||||||
const hits = filter(this.muteWords, (muteWord) => {
|
const hits = filter(this.muteWords, (muteWord) => {
|
||||||
return statusText.includes(muteWord.toLowerCase())
|
return statusText.includes(muteWord.toLowerCase()) || statusSummary.includes(muteWord.toLowerCase())
|
||||||
})
|
})
|
||||||
|
|
||||||
return hits
|
return hits
|
||||||
|
@ -280,6 +281,11 @@ const Status = {
|
||||||
},
|
},
|
||||||
tags () {
|
tags () {
|
||||||
return this.status.tags.filter(tagObj => tagObj.hasOwnProperty('name')).map(tagObj => tagObj.name).join(' ')
|
return this.status.tags.filter(tagObj => tagObj.hasOwnProperty('name')).map(tagObj => tagObj.name).join(' ')
|
||||||
|
},
|
||||||
|
hidePostStats () {
|
||||||
|
return typeof this.$store.state.config.hidePostStats === 'undefined'
|
||||||
|
? this.$store.state.instance.hidePostStats
|
||||||
|
: this.$store.state.config.hidePostStats
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
@ -316,11 +322,8 @@ const Status = {
|
||||||
this.error = undefined
|
this.error = undefined
|
||||||
},
|
},
|
||||||
linkClicked (event) {
|
linkClicked (event) {
|
||||||
let { target } = event
|
const target = event.target.closest('.status-content a')
|
||||||
if (target.tagName === 'SPAN') {
|
if (target) {
|
||||||
target = target.parentNode
|
|
||||||
}
|
|
||||||
if (target.tagName === 'A') {
|
|
||||||
if (target.className.match(/mention/)) {
|
if (target.className.match(/mention/)) {
|
||||||
const href = target.href
|
const href = target.href
|
||||||
const attn = this.status.attentions.find(attn => mentionMatchesUrl(attn, href))
|
const attn = this.status.attentions.find(attn => mentionMatchesUrl(attn, href))
|
||||||
|
|
|
@ -344,7 +344,7 @@
|
||||||
|
|
||||||
<transition name="fade">
|
<transition name="fade">
|
||||||
<div
|
<div
|
||||||
v-if="isFocused && combinedFavsAndRepeatsUsers.length > 0"
|
v-if="!hidePostStats && isFocused && combinedFavsAndRepeatsUsers.length > 0"
|
||||||
class="favs-repeated-users"
|
class="favs-repeated-users"
|
||||||
>
|
>
|
||||||
<div class="stats">
|
<div class="stats">
|
||||||
|
@ -820,11 +820,12 @@ $status-margin: 0.75em;
|
||||||
}
|
}
|
||||||
|
|
||||||
.status-actions {
|
.status-actions {
|
||||||
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: flex;
|
||||||
margin-top: $status-margin;
|
margin-top: $status-margin;
|
||||||
|
|
||||||
div, favorite-button {
|
> * {
|
||||||
max-width: 4em;
|
max-width: 4em;
|
||||||
flex: 1;
|
flex: 1;
|
||||||
}
|
}
|
||||||
|
|
52
src/components/sticker_picker/sticker_picker.js
Normal file
52
src/components/sticker_picker/sticker_picker.js
Normal file
|
@ -0,0 +1,52 @@
|
||||||
|
/* eslint-env browser */
|
||||||
|
import statusPosterService from '../../services/status_poster/status_poster.service.js'
|
||||||
|
import TabSwitcher from '../tab_switcher/tab_switcher.js'
|
||||||
|
|
||||||
|
const StickerPicker = {
|
||||||
|
components: [
|
||||||
|
TabSwitcher
|
||||||
|
],
|
||||||
|
data () {
|
||||||
|
return {
|
||||||
|
meta: {
|
||||||
|
stickers: []
|
||||||
|
},
|
||||||
|
path: ''
|
||||||
|
}
|
||||||
|
},
|
||||||
|
computed: {
|
||||||
|
pack () {
|
||||||
|
return this.$store.state.instance.stickers || []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
methods: {
|
||||||
|
clear () {
|
||||||
|
this.meta = {
|
||||||
|
stickers: []
|
||||||
|
}
|
||||||
|
},
|
||||||
|
pick (sticker, name) {
|
||||||
|
const store = this.$store
|
||||||
|
// TODO remove this workaround by finding a way to bypass reuploads
|
||||||
|
fetch(sticker)
|
||||||
|
.then((res) => {
|
||||||
|
res.blob().then((blob) => {
|
||||||
|
var file = new File([blob], name, { mimetype: 'image/png' })
|
||||||
|
var formData = new FormData()
|
||||||
|
formData.append('file', file)
|
||||||
|
statusPosterService.uploadMedia({ store, formData })
|
||||||
|
.then((fileData) => {
|
||||||
|
this.$emit('uploaded', fileData)
|
||||||
|
this.clear()
|
||||||
|
}, (error) => {
|
||||||
|
console.warn("Can't attach sticker")
|
||||||
|
console.warn(error)
|
||||||
|
this.$emit('upload-failed', 'default')
|
||||||
|
})
|
||||||
|
})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export default StickerPicker
|
62
src/components/sticker_picker/sticker_picker.vue
Normal file
62
src/components/sticker_picker/sticker_picker.vue
Normal file
|
@ -0,0 +1,62 @@
|
||||||
|
<template>
|
||||||
|
<div
|
||||||
|
class="sticker-picker"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
class="sticker-picker-panel"
|
||||||
|
>
|
||||||
|
<tab-switcher
|
||||||
|
:render-only-focused="true"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="stickerpack in pack"
|
||||||
|
:key="stickerpack.path"
|
||||||
|
:image-tooltip="stickerpack.meta.title"
|
||||||
|
:image="stickerpack.path + stickerpack.meta.tabIcon"
|
||||||
|
class="sticker-picker-content"
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
v-for="sticker in stickerpack.meta.stickers"
|
||||||
|
:key="sticker"
|
||||||
|
class="sticker"
|
||||||
|
@click="pick(stickerpack.path + sticker, stickerpack.meta.title)"
|
||||||
|
>
|
||||||
|
<img
|
||||||
|
:src="stickerpack.path + sticker"
|
||||||
|
>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</tab-switcher>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script src="./sticker_picker.js"></script>
|
||||||
|
|
||||||
|
<style lang="scss">
|
||||||
|
@import '../../_variables.scss';
|
||||||
|
|
||||||
|
.sticker-picker {
|
||||||
|
.sticker-picker-panel {
|
||||||
|
display: inline-block;
|
||||||
|
width: 100%;
|
||||||
|
.sticker-picker-content {
|
||||||
|
max-height: 300px;
|
||||||
|
overflow-y: scroll;
|
||||||
|
overflow-x: auto;
|
||||||
|
.sticker {
|
||||||
|
display: inline-block;
|
||||||
|
width: 20%;
|
||||||
|
height: 20%;
|
||||||
|
img {
|
||||||
|
width: 100%;
|
||||||
|
&:hover {
|
||||||
|
filter: drop-shadow(0 0 5px var(--link, $fallback--link));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
|
@ -45,7 +45,19 @@ export default Vue.component('tab-switcher', {
|
||||||
classesTab.push('active')
|
classesTab.push('active')
|
||||||
classesWrapper.push('active')
|
classesWrapper.push('active')
|
||||||
}
|
}
|
||||||
|
if (slot.data.attrs.image) {
|
||||||
|
return (
|
||||||
|
<div class={ classesWrapper.join(' ')}>
|
||||||
|
<button
|
||||||
|
disabled={slot.data.attrs.disabled}
|
||||||
|
onClick={this.activateTab(index)}
|
||||||
|
class={classesTab.join(' ')}>
|
||||||
|
<img src={slot.data.attrs.image} title={slot.data.attrs['image-tooltip']}/>
|
||||||
|
{slot.data.attrs.label ? '' : slot.data.attrs.label}
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
||||||
return (
|
return (
|
||||||
<div class={ classesWrapper.join(' ')}>
|
<div class={ classesWrapper.join(' ')}>
|
||||||
<button
|
<button
|
||||||
|
|
|
@ -53,6 +53,12 @@
|
||||||
background: transparent;
|
background: transparent;
|
||||||
z-index: 5;
|
z-index: 5;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
img {
|
||||||
|
max-height: 26px;
|
||||||
|
vertical-align: top;
|
||||||
|
margin-top: -5px;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
&:not(.active) {
|
&:not(.active) {
|
||||||
|
|
|
@ -283,7 +283,6 @@
|
||||||
|
|
||||||
.user-card {
|
.user-card {
|
||||||
background-size: cover;
|
background-size: cover;
|
||||||
overflow: hidden;
|
|
||||||
|
|
||||||
.panel-heading {
|
.panel-heading {
|
||||||
padding: .5em 0;
|
padding: .5em 0;
|
||||||
|
@ -298,6 +297,8 @@
|
||||||
word-wrap: break-word;
|
word-wrap: break-word;
|
||||||
background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80%);
|
background: linear-gradient(to bottom, rgba(0, 0, 0, 0), $fallback--bg 80%);
|
||||||
background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80%);
|
background: linear-gradient(to bottom, rgba(0, 0, 0, 0), var(--bg, $fallback--bg) 80%);
|
||||||
|
border-bottom-right-radius: inherit;
|
||||||
|
border-bottom-left-radius: inherit;
|
||||||
}
|
}
|
||||||
|
|
||||||
p {
|
p {
|
||||||
|
@ -503,6 +504,7 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
.user-interactions {
|
.user-interactions {
|
||||||
|
position: relative;
|
||||||
display: flex;
|
display: flex;
|
||||||
flex-flow: row wrap;
|
flex-flow: row wrap;
|
||||||
justify-content: space-between;
|
justify-content: space-between;
|
||||||
|
|
|
@ -91,7 +91,8 @@ const UserSettings = {
|
||||||
...this.$store.state.instance.emoji,
|
...this.$store.state.instance.emoji,
|
||||||
...this.$store.state.instance.customEmoji
|
...this.$store.state.instance.customEmoji
|
||||||
],
|
],
|
||||||
users: this.$store.state.users.users
|
users: this.$store.state.users.users,
|
||||||
|
updateUsersList: (input) => this.$store.dispatch('searchUsers', input)
|
||||||
})
|
})
|
||||||
},
|
},
|
||||||
emojiSuggestor () {
|
emojiSuggestor () {
|
||||||
|
|
|
@ -106,6 +106,9 @@
|
||||||
"expired": "Poll ended {0} ago",
|
"expired": "Poll ended {0} ago",
|
||||||
"not_enough_options": "Too few unique options in poll"
|
"not_enough_options": "Too few unique options in poll"
|
||||||
},
|
},
|
||||||
|
"stickers": {
|
||||||
|
"add_sticker": "Add Sticker"
|
||||||
|
},
|
||||||
"interactions": {
|
"interactions": {
|
||||||
"favs_repeats": "Repeats and Favorites",
|
"favs_repeats": "Repeats and Favorites",
|
||||||
"follows": "New follows",
|
"follows": "New follows",
|
||||||
|
|
123
src/i18n/es.json
123
src/i18n/es.json
|
@ -27,7 +27,11 @@
|
||||||
"optional": "opcional",
|
"optional": "opcional",
|
||||||
"show_more": "Mostrar más",
|
"show_more": "Mostrar más",
|
||||||
"show_less": "Mostrar menos",
|
"show_less": "Mostrar menos",
|
||||||
"cancel": "Cancelar"
|
"cancel": "Cancelar",
|
||||||
|
"disable": "Inhabilitar",
|
||||||
|
"enable": "Habilitar",
|
||||||
|
"confirm": "Confirmar",
|
||||||
|
"verify": "Verificar"
|
||||||
},
|
},
|
||||||
"image_cropper": {
|
"image_cropper": {
|
||||||
"crop_picture": "Recortar la foto",
|
"crop_picture": "Recortar la foto",
|
||||||
|
@ -48,7 +52,15 @@
|
||||||
"placeholder": "p.ej. lain",
|
"placeholder": "p.ej. lain",
|
||||||
"register": "Registrar",
|
"register": "Registrar",
|
||||||
"username": "Usuario",
|
"username": "Usuario",
|
||||||
"hint": "Inicia sesión para unirte a la discusión"
|
"hint": "Inicia sesión para unirte a la discusión",
|
||||||
|
"authentication_code": "Código de autentificación",
|
||||||
|
"enter_recovery_code": "Inserta el código de recuperación",
|
||||||
|
"enter_two_factor_code": "Inserta el código de doble factor",
|
||||||
|
"recovery_code": "Código de recuperación",
|
||||||
|
"heading" : {
|
||||||
|
"totp" : "Autentificación de doble factor",
|
||||||
|
"recovery" : "Recuperación de doble factor"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"media_modal": {
|
"media_modal": {
|
||||||
"previous": "Anterior",
|
"previous": "Anterior",
|
||||||
|
@ -60,11 +72,13 @@
|
||||||
"chat": "Chat Local",
|
"chat": "Chat Local",
|
||||||
"friend_requests": "Solicitudes de amistad",
|
"friend_requests": "Solicitudes de amistad",
|
||||||
"mentions": "Menciones",
|
"mentions": "Menciones",
|
||||||
|
"interactions": "Interacciones",
|
||||||
"dms": "Mensajes Directo",
|
"dms": "Mensajes Directo",
|
||||||
"public_tl": "Línea Temporal Pública",
|
"public_tl": "Línea Temporal Pública",
|
||||||
"timeline": "Línea Temporal",
|
"timeline": "Línea Temporal",
|
||||||
"twkn": "Toda La Red Conocida",
|
"twkn": "Toda La Red Conocida",
|
||||||
"user_search": "Búsqueda de Usuarios",
|
"user_search": "Búsqueda de Usuarios",
|
||||||
|
"search": "Buscar",
|
||||||
"who_to_follow": "A quién seguir",
|
"who_to_follow": "A quién seguir",
|
||||||
"preferences": "Preferencias"
|
"preferences": "Preferencias"
|
||||||
},
|
},
|
||||||
|
@ -78,6 +92,25 @@
|
||||||
"repeated_you": "repite tu estado",
|
"repeated_you": "repite tu estado",
|
||||||
"no_more_notifications": "No hay más notificaciones"
|
"no_more_notifications": "No hay más notificaciones"
|
||||||
},
|
},
|
||||||
|
"polls": {
|
||||||
|
"add_poll": "Añadir encuesta",
|
||||||
|
"add_option": "Añadir opción",
|
||||||
|
"option": "Opción",
|
||||||
|
"votes": "votos",
|
||||||
|
"vote": "Votar",
|
||||||
|
"type": "Tipo de encuesta",
|
||||||
|
"single_choice": "Elección única",
|
||||||
|
"multiple_choices": "Múltiples elecciones",
|
||||||
|
"expiry": "Tiempo de vida de la encuesta",
|
||||||
|
"expires_in": "La encuensta termina en {0}",
|
||||||
|
"expired": "La encuesta terminó hace {0}",
|
||||||
|
"not_enough_options": "Muy pocas opciones únicas en la encuesta"
|
||||||
|
},
|
||||||
|
"interactions": {
|
||||||
|
"favs_repeats": "Favoritos y Repetidos",
|
||||||
|
"follows": "Nuevos seguidores",
|
||||||
|
"load_older": "Cargar interacciones antiguas"
|
||||||
|
},
|
||||||
"post_status": {
|
"post_status": {
|
||||||
"new_status": "Publicar un nuevo estado",
|
"new_status": "Publicar un nuevo estado",
|
||||||
"account_not_locked_warning": "Tu cuenta no está {0}. Cualquiera puede seguirte y leer las entradas para Solo-Seguidores.",
|
"account_not_locked_warning": "Tu cuenta no está {0}. Cualquiera puede seguirte y leer las entradas para Solo-Seguidores.",
|
||||||
|
@ -91,9 +124,14 @@
|
||||||
},
|
},
|
||||||
"content_warning": "Tema (opcional)",
|
"content_warning": "Tema (opcional)",
|
||||||
"default": "Acabo de aterrizar en L.A.",
|
"default": "Acabo de aterrizar en L.A.",
|
||||||
"direct_warning": "Esta publicación solo será visible para los usuarios mencionados.",
|
"direct_warning_to_all": "Esta publicación será visible para todos los usarios mencionados.",
|
||||||
"direct_warning_to_first_only": "Esta publicación solo será visible para los usuarios mencionados al comienzo del mensaje.",
|
"direct_warning_to_first_only": "Esta publicación solo será visible para los usuarios mencionados al comienzo del mensaje.",
|
||||||
"posting": "Publicando",
|
"posting": "Publicando",
|
||||||
|
"scope_notice": {
|
||||||
|
"public": "Esta publicación será visible para todo el mundo",
|
||||||
|
"private": "Esta publicación solo será visible para tus seguidores.",
|
||||||
|
"unlisted": "Esta publicación no será visible en la Línea Temporal Pública ni en Toda La Red Conocida"
|
||||||
|
},
|
||||||
"scope": {
|
"scope": {
|
||||||
"direct": "Directo - Solo para los usuarios mencionados.",
|
"direct": "Directo - Solo para los usuarios mencionados.",
|
||||||
"private": "Solo-Seguidores - Solo tus seguidores leeran la publicación",
|
"private": "Solo-Seguidores - Solo tus seguidores leeran la publicación",
|
||||||
|
@ -127,6 +165,29 @@
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"app_name": "Nombre de la aplicación",
|
"app_name": "Nombre de la aplicación",
|
||||||
|
"security": "Seguridad",
|
||||||
|
"enter_current_password_to_confirm": "Introduce la contraseña actual para confirmar tu identidad",
|
||||||
|
"mfa": {
|
||||||
|
"otp" : "OTP",
|
||||||
|
"setup_otp" : "Configurar OTP",
|
||||||
|
"wait_pre_setup_otp" : "preconfiguración OTP",
|
||||||
|
"confirm_and_enable" : "Confirmar y habilitar OTP",
|
||||||
|
"title": "Autentificación de Doble Factor",
|
||||||
|
"generate_new_recovery_codes" : "Generar nuevos códigos de recuperación",
|
||||||
|
"warning_of_generate_new_codes" : "Cuando generas nuevos códigos de recuperación, los antiguos dejarán de funcionar.",
|
||||||
|
"recovery_codes" : "Códigos de recuperación.",
|
||||||
|
"waiting_a_recovery_codes": "Recibiendo códigos de respaldo",
|
||||||
|
"recovery_codes_warning" : "Anote los códigos o guárdelos en un lugar seguro, de lo contrario no los volverá a ver. Si pierde el acceso a su aplicación 2FA y los códigos de recuperación, su cuenta quedará bloqueada.",
|
||||||
|
"authentication_methods" : "Métodos de autentificación",
|
||||||
|
"scan": {
|
||||||
|
"title": "Escanear",
|
||||||
|
"desc": "Usando su aplicación de doble factor, escanee este código QR o ingrese la clave de texto:",
|
||||||
|
"secret_code": "Clave"
|
||||||
|
},
|
||||||
|
"verify": {
|
||||||
|
"desc": "Para habilitar la autenticación de doble factor, ingrese el código de su aplicación 2FA:"
|
||||||
|
}
|
||||||
|
},
|
||||||
"attachmentRadius": "Adjuntos",
|
"attachmentRadius": "Adjuntos",
|
||||||
"attachments": "Adjuntos",
|
"attachments": "Adjuntos",
|
||||||
"autoload": "Activar carga automática al llegar al final de la página",
|
"autoload": "Activar carga automática al llegar al final de la página",
|
||||||
|
@ -233,6 +294,7 @@
|
||||||
"reply_visibility_all": "Mostrar todas las réplicas",
|
"reply_visibility_all": "Mostrar todas las réplicas",
|
||||||
"reply_visibility_following": "Solo mostrar réplicas para mí o usuarios a los que sigo",
|
"reply_visibility_following": "Solo mostrar réplicas para mí o usuarios a los que sigo",
|
||||||
"reply_visibility_self": "Solo mostrar réplicas para mí",
|
"reply_visibility_self": "Solo mostrar réplicas para mí",
|
||||||
|
"autohide_floating_post_button": "Ocultar automáticamente el botón 'Nueva Publicación' (móvil)",
|
||||||
"saving_err": "Error al guardar los ajustes",
|
"saving_err": "Error al guardar los ajustes",
|
||||||
"saving_ok": "Ajustes guardados",
|
"saving_ok": "Ajustes guardados",
|
||||||
"search_user_to_block": "Buscar usuarios a bloquear",
|
"search_user_to_block": "Buscar usuarios a bloquear",
|
||||||
|
@ -265,6 +327,13 @@
|
||||||
"true": "sí"
|
"true": "sí"
|
||||||
},
|
},
|
||||||
"notifications": "Notificaciones",
|
"notifications": "Notificaciones",
|
||||||
|
"notification_setting": "Recibir notificaciones de:",
|
||||||
|
"notification_setting_follows": "Usuarios que sigues",
|
||||||
|
"notification_setting_non_follows": "Usuarios que no sigues",
|
||||||
|
"notification_setting_followers": "Usuarios que te siguen",
|
||||||
|
"notification_setting_non_followers": "Usuarios que no te siguen",
|
||||||
|
"notification_mutes": "Para dejar de recibir notificaciones de un usuario específico, siléncialo.",
|
||||||
|
"notification_blocks": "El bloqueo de un usuario detiene todas las notificaciones y también las cancela.",
|
||||||
"enable_web_push_notifications": "Habilitar las notificiaciones en el navegador",
|
"enable_web_push_notifications": "Habilitar las notificiaciones en el navegador",
|
||||||
"style": {
|
"style": {
|
||||||
"switcher": {
|
"switcher": {
|
||||||
|
@ -381,6 +450,40 @@
|
||||||
"frontend_version": "Versión del Frontend"
|
"frontend_version": "Versión del Frontend"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"time": {
|
||||||
|
"day": "{0} día",
|
||||||
|
"days": "{0} días",
|
||||||
|
"day_short": "{0}d",
|
||||||
|
"days_short": "{0}d",
|
||||||
|
"hour": "{0} hora",
|
||||||
|
"hours": "{0} horas",
|
||||||
|
"hour_short": "{0}h",
|
||||||
|
"hours_short": "{0}h",
|
||||||
|
"in_future": "en {0}",
|
||||||
|
"in_past": "hace {0}",
|
||||||
|
"minute": "{0} minuto",
|
||||||
|
"minutes": "{0} minutos",
|
||||||
|
"minute_short": "{0}min",
|
||||||
|
"minutes_short": "{0}min",
|
||||||
|
"month": "{0} mes",
|
||||||
|
"months": "{0} meses",
|
||||||
|
"month_short": "{0}m",
|
||||||
|
"months_short": "{0}m",
|
||||||
|
"now": "justo ahora",
|
||||||
|
"now_short": "ahora",
|
||||||
|
"second": "{0} segundo",
|
||||||
|
"seconds": "{0} segundos",
|
||||||
|
"second_short": "{0}s",
|
||||||
|
"seconds_short": "{0}s",
|
||||||
|
"week": "{0} semana",
|
||||||
|
"weeks": "{0} semana",
|
||||||
|
"week_short": "{0}sem",
|
||||||
|
"weeks_short": "{0}sem",
|
||||||
|
"year": "{0} año",
|
||||||
|
"years": "{0} años",
|
||||||
|
"year_short": "{0}a",
|
||||||
|
"years_short": "{0}a"
|
||||||
|
},
|
||||||
"timeline": {
|
"timeline": {
|
||||||
"collapse": "Colapsar",
|
"collapse": "Colapsar",
|
||||||
"conversation": "Conversación",
|
"conversation": "Conversación",
|
||||||
|
@ -396,6 +499,11 @@
|
||||||
"status": {
|
"status": {
|
||||||
"favorites": "Favoritos",
|
"favorites": "Favoritos",
|
||||||
"repeats": "Repetidos",
|
"repeats": "Repetidos",
|
||||||
|
"delete": "Eliminar publicación",
|
||||||
|
"pin": "Fijar en tu perfil",
|
||||||
|
"unpin": "Desclavar de tu perfil",
|
||||||
|
"pinned": "Fijado",
|
||||||
|
"delete_confirm": "¿Realmente quieres borrar la publicación?",
|
||||||
"reply_to": "Responder a",
|
"reply_to": "Responder a",
|
||||||
"replies_list": "Respuestas:"
|
"replies_list": "Respuestas:"
|
||||||
},
|
},
|
||||||
|
@ -422,6 +530,8 @@
|
||||||
"remote_follow": "Seguir",
|
"remote_follow": "Seguir",
|
||||||
"report": "Reportar",
|
"report": "Reportar",
|
||||||
"statuses": "Estados",
|
"statuses": "Estados",
|
||||||
|
"subscribe": "Suscribirse",
|
||||||
|
"unsubscribe": "Desuscribirse",
|
||||||
"unblock": "Desbloquear",
|
"unblock": "Desbloquear",
|
||||||
"unblock_progress": "Desbloqueando...",
|
"unblock_progress": "Desbloqueando...",
|
||||||
"block_progress": "Bloqueando...",
|
"block_progress": "Bloqueando...",
|
||||||
|
@ -486,5 +596,12 @@
|
||||||
"GiB": "GiB",
|
"GiB": "GiB",
|
||||||
"TiB": "TiB"
|
"TiB": "TiB"
|
||||||
}
|
}
|
||||||
|
},
|
||||||
|
"search": {
|
||||||
|
"people": "Personas",
|
||||||
|
"hashtags": "Hashtags",
|
||||||
|
"person_talking": "{count} personas hablando",
|
||||||
|
"people_talking": "{count} gente hablando",
|
||||||
|
"no_results": "Sin resultados"
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -27,7 +27,11 @@
|
||||||
"optional": "かかなくてもよい",
|
"optional": "かかなくてもよい",
|
||||||
"show_more": "つづきをみる",
|
"show_more": "つづきをみる",
|
||||||
"show_less": "たたむ",
|
"show_less": "たたむ",
|
||||||
"cancel": "キャンセル"
|
"cancel": "キャンセル",
|
||||||
|
"disable": "なし",
|
||||||
|
"enable": "あり",
|
||||||
|
"confirm": "たしかめる",
|
||||||
|
"verify": "たしかめる"
|
||||||
},
|
},
|
||||||
"image_cropper": {
|
"image_cropper": {
|
||||||
"crop_picture": "がぞうをきりぬく",
|
"crop_picture": "がぞうをきりぬく",
|
||||||
|
@ -48,7 +52,15 @@
|
||||||
"placeholder": "れい: lain",
|
"placeholder": "れい: lain",
|
||||||
"register": "はじめる",
|
"register": "はじめる",
|
||||||
"username": "ユーザーめい",
|
"username": "ユーザーめい",
|
||||||
"hint": "はなしあいにくわわるには、ログインしてください"
|
"hint": "はなしあいにくわわるには、ログインしてください",
|
||||||
|
"authentication_code": "にんしょうコード",
|
||||||
|
"enter_recovery_code": "リカバリーコードをいれてください",
|
||||||
|
"enter_two_factor_code": "2-ファクターコードをいれてください",
|
||||||
|
"recovery_code": "リカバリーコード",
|
||||||
|
"heading" : {
|
||||||
|
"totp" : "2-ファクターにんしょう",
|
||||||
|
"recovery" : "2-ファクターリカバリー"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"media_modal": {
|
"media_modal": {
|
||||||
"previous": "まえ",
|
"previous": "まえ",
|
||||||
|
@ -79,6 +91,20 @@
|
||||||
"repeated_you": "あなたのステータスがリピートされました",
|
"repeated_you": "あなたのステータスがリピートされました",
|
||||||
"no_more_notifications": "つうちはありません"
|
"no_more_notifications": "つうちはありません"
|
||||||
},
|
},
|
||||||
|
"polls": {
|
||||||
|
"add_poll": "いれふだをはじめる",
|
||||||
|
"add_option": "オプションをふやす",
|
||||||
|
"option": "オプション",
|
||||||
|
"votes": "いれふだ",
|
||||||
|
"vote": "ふだをいれる",
|
||||||
|
"type": "いれふだのかた",
|
||||||
|
"single_choice": "ひとつえらぶ",
|
||||||
|
"multiple_choices": "いくつでもえらべる",
|
||||||
|
"expiry": "いれふだのながさ",
|
||||||
|
"expires_in": "いれふだは {0} で、おわります",
|
||||||
|
"expired": "いれふだは {0} まえに、おわりました",
|
||||||
|
"not_enough_options": "ユニークなオプションが、たりません"
|
||||||
|
},
|
||||||
"interactions": {
|
"interactions": {
|
||||||
"favs_repeats": "リピートとおきにいり",
|
"favs_repeats": "リピートとおきにいり",
|
||||||
"follows": "あたらしいフォロー",
|
"follows": "あたらしいフォロー",
|
||||||
|
@ -139,6 +165,29 @@
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"app_name": "アプリのなまえ",
|
"app_name": "アプリのなまえ",
|
||||||
|
"security": "セキュリティ",
|
||||||
|
"enter_current_password_to_confirm": "あなたのアイデンティティをたしかめるため、あなたのいまのパスワードをかいてください",
|
||||||
|
"mfa": {
|
||||||
|
"otp" : "OTP",
|
||||||
|
"setup_otp" : "OTPをつくる",
|
||||||
|
"wait_pre_setup_otp" : "OTPをよういしています",
|
||||||
|
"confirm_and_enable" : "OTPをたしかめて、ゆうこうにする",
|
||||||
|
"title": "2-ファクターにんしょう",
|
||||||
|
"generate_new_recovery_codes" : "あたらしいリカバリーコードをつくる",
|
||||||
|
"warning_of_generate_new_codes" : "あたらしいリカバリーコードをつくったら、ふるいコードはつかえなくなります。",
|
||||||
|
"recovery_codes" : "リカバリーコード。",
|
||||||
|
"waiting_a_recovery_codes": "バックアップコードをうけとっています...",
|
||||||
|
"recovery_codes_warning" : "コードをかきうつすか、ひとにみられないところにセーブしてください。そうでなければ、あなたはこのコードをふたたびみることはできません。もしあなたが、2FAアプリのアクセスをうしなって、なおかつ、リカバリーコードもおもいだせないならば、あなたはあなたのアカウントから、しめだされます。",
|
||||||
|
"authentication_methods" : "にんしょうメソッド",
|
||||||
|
"scan": {
|
||||||
|
"title": "スキャン",
|
||||||
|
"desc": "あなたの2-ファクターアプリをつかって、このQRコードをスキャンするか、テキストキーをうちこんでください:",
|
||||||
|
"secret_code": "キー"
|
||||||
|
},
|
||||||
|
"verify": {
|
||||||
|
"desc": "2-ファクターにんしょうをつかうには、あなたの2-ファクターアプリのコードをいれてください:"
|
||||||
|
}
|
||||||
|
},
|
||||||
"attachmentRadius": "ファイル",
|
"attachmentRadius": "ファイル",
|
||||||
"attachments": "ファイル",
|
"attachments": "ファイル",
|
||||||
"autoload": "したにスクロールしたとき、じどうてきによみこむ。",
|
"autoload": "したにスクロールしたとき、じどうてきによみこむ。",
|
||||||
|
|
|
@ -27,7 +27,11 @@
|
||||||
"optional": "省略可",
|
"optional": "省略可",
|
||||||
"show_more": "もっと見る",
|
"show_more": "もっと見る",
|
||||||
"show_less": "たたむ",
|
"show_less": "たたむ",
|
||||||
"cancel": "キャンセル"
|
"cancel": "キャンセル",
|
||||||
|
"disable": "無効",
|
||||||
|
"enable": "有効",
|
||||||
|
"confirm": "確認",
|
||||||
|
"verify": "検査"
|
||||||
},
|
},
|
||||||
"image_cropper": {
|
"image_cropper": {
|
||||||
"crop_picture": "画像を切り抜く",
|
"crop_picture": "画像を切り抜く",
|
||||||
|
@ -48,7 +52,15 @@
|
||||||
"placeholder": "例: lain",
|
"placeholder": "例: lain",
|
||||||
"register": "登録",
|
"register": "登録",
|
||||||
"username": "ユーザー名",
|
"username": "ユーザー名",
|
||||||
"hint": "会話に加わるには、ログインしてください"
|
"hint": "会話に加わるには、ログインしてください",
|
||||||
|
"authentication_code": "認証コード",
|
||||||
|
"enter_recovery_code": "リカバリーコードを入力してください",
|
||||||
|
"enter_two_factor_code": "2段階認証コードを入力してください",
|
||||||
|
"recovery_code": "リカバリーコード",
|
||||||
|
"heading" : {
|
||||||
|
"totp" : "2段階認証",
|
||||||
|
"recovery" : "2段階リカバリー"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"media_modal": {
|
"media_modal": {
|
||||||
"previous": "前",
|
"previous": "前",
|
||||||
|
@ -79,6 +91,20 @@
|
||||||
"repeated_you": "あなたのステータスがリピートされました",
|
"repeated_you": "あなたのステータスがリピートされました",
|
||||||
"no_more_notifications": "通知はありません"
|
"no_more_notifications": "通知はありません"
|
||||||
},
|
},
|
||||||
|
"polls": {
|
||||||
|
"add_poll": "投票を追加",
|
||||||
|
"add_option": "選択肢を追加",
|
||||||
|
"option": "選択肢",
|
||||||
|
"votes": "票",
|
||||||
|
"vote": "投票",
|
||||||
|
"type": "投票の形式",
|
||||||
|
"single_choice": "択一式",
|
||||||
|
"multiple_choices": "複数選択式",
|
||||||
|
"expiry": "投票期間",
|
||||||
|
"expires_in": "投票は {0} で終了します",
|
||||||
|
"expired": "投票は {0} 前に終了しました",
|
||||||
|
"not_enough_options": "相異なる選択肢が不足しています"
|
||||||
|
},
|
||||||
"interactions": {
|
"interactions": {
|
||||||
"favs_repeats": "リピートとお気に入り",
|
"favs_repeats": "リピートとお気に入り",
|
||||||
"follows": "新しいフォロワー",
|
"follows": "新しいフォロワー",
|
||||||
|
@ -139,6 +165,29 @@
|
||||||
},
|
},
|
||||||
"settings": {
|
"settings": {
|
||||||
"app_name": "アプリの名称",
|
"app_name": "アプリの名称",
|
||||||
|
"security": "セキュリティ",
|
||||||
|
"enter_current_password_to_confirm": "あなたのアイデンティティを証明するため、現在のパスワードを入力してください",
|
||||||
|
"mfa": {
|
||||||
|
"otp" : "OTP",
|
||||||
|
"setup_otp" : "OTPのセットアップ",
|
||||||
|
"wait_pre_setup_otp" : "OTPのプリセット",
|
||||||
|
"confirm_and_enable" : "OTPの確認と有効化",
|
||||||
|
"title": "2段階認証",
|
||||||
|
"generate_new_recovery_codes" : "新しいリカバリーコードを生成",
|
||||||
|
"warning_of_generate_new_codes" : "新しいリカバリーコードを生成すると、古いコードは使用できなくなります。",
|
||||||
|
"recovery_codes" : "リカバリーコード。",
|
||||||
|
"waiting_a_recovery_codes": "バックアップコードを受信しています...",
|
||||||
|
"recovery_codes_warning" : "コードを紙に書くか、安全な場所に保存してください。そうでなければ、あなたはコードを再び見ることはできません。もし2段階認証アプリのアクセスを喪失し、なおかつ、リカバリーコードもないならば、あなたは自分のアカウントから閉め出されます。",
|
||||||
|
"authentication_methods" : "認証方法",
|
||||||
|
"scan": {
|
||||||
|
"title": "スキャン",
|
||||||
|
"desc": "あなたの2段階認証アプリを使って、このQRコードをスキャンするか、テキストキーを入力してください:",
|
||||||
|
"secret_code": "キー"
|
||||||
|
},
|
||||||
|
"verify": {
|
||||||
|
"desc": "2段階認証を有効にするには、あなたの2段階認証アプリのコードを入力してください:"
|
||||||
|
}
|
||||||
|
},
|
||||||
"attachmentRadius": "ファイル",
|
"attachmentRadius": "ファイル",
|
||||||
"attachments": "ファイル",
|
"attachments": "ファイル",
|
||||||
"autoload": "下にスクロールしたとき、自動的に読み込む。",
|
"autoload": "下にスクロールしたとき、自動的に読み込む。",
|
||||||
|
|
|
@ -26,6 +26,7 @@ import messages from './i18n/messages.js'
|
||||||
import VueChatScroll from 'vue-chat-scroll'
|
import VueChatScroll from 'vue-chat-scroll'
|
||||||
import VueClickOutside from 'v-click-outside'
|
import VueClickOutside from 'v-click-outside'
|
||||||
import PortalVue from 'portal-vue'
|
import PortalVue from 'portal-vue'
|
||||||
|
import VTooltip from 'v-tooltip'
|
||||||
|
|
||||||
import afterStoreSetup from './boot/after_store.js'
|
import afterStoreSetup from './boot/after_store.js'
|
||||||
|
|
||||||
|
@ -37,6 +38,7 @@ Vue.use(VueI18n)
|
||||||
Vue.use(VueChatScroll)
|
Vue.use(VueChatScroll)
|
||||||
Vue.use(VueClickOutside)
|
Vue.use(VueClickOutside)
|
||||||
Vue.use(PortalVue)
|
Vue.use(PortalVue)
|
||||||
|
Vue.use(VTooltip)
|
||||||
|
|
||||||
const i18n = new VueI18n({
|
const i18n = new VueI18n({
|
||||||
// By default, use the browser locale, we will update it if neccessary
|
// By default, use the browser locale, we will update it if neccessary
|
||||||
|
|
|
@ -70,6 +70,7 @@ const MASTODON_UNPIN_OWN_STATUS = id => `/api/v1/statuses/${id}/unpin`
|
||||||
const MASTODON_MUTE_CONVERSATION = id => `/api/v1/statuses/${id}/mute`
|
const MASTODON_MUTE_CONVERSATION = id => `/api/v1/statuses/${id}/mute`
|
||||||
const MASTODON_UNMUTE_CONVERSATION = id => `/api/v1/statuses/${id}/unmute`
|
const MASTODON_UNMUTE_CONVERSATION = id => `/api/v1/statuses/${id}/unmute`
|
||||||
const MASTODON_SEARCH_2 = `/api/v2/search`
|
const MASTODON_SEARCH_2 = `/api/v2/search`
|
||||||
|
const MASTODON_USER_SEARCH_URL = '/api/v1/accounts/search'
|
||||||
|
|
||||||
const oldfetch = window.fetch
|
const oldfetch = window.fetch
|
||||||
|
|
||||||
|
@ -865,6 +866,18 @@ const reportUser = ({ credentials, userId, statusIds, comment, forward }) => {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const searchUsers = ({ credentials, query }) => {
|
||||||
|
return promisedRequest({
|
||||||
|
url: MASTODON_USER_SEARCH_URL,
|
||||||
|
params: {
|
||||||
|
q: query,
|
||||||
|
resolve: true
|
||||||
|
},
|
||||||
|
credentials
|
||||||
|
})
|
||||||
|
.then((data) => data.map(parseUser))
|
||||||
|
}
|
||||||
|
|
||||||
const search2 = ({ credentials, q, resolve, limit, offset, following }) => {
|
const search2 = ({ credentials, q, resolve, limit, offset, following }) => {
|
||||||
let url = MASTODON_SEARCH_2
|
let url = MASTODON_SEARCH_2
|
||||||
let params = []
|
let params = []
|
||||||
|
@ -974,7 +987,8 @@ const apiService = {
|
||||||
fetchRebloggedByUsers,
|
fetchRebloggedByUsers,
|
||||||
reportUser,
|
reportUser,
|
||||||
updateNotificationSettings,
|
updateNotificationSettings,
|
||||||
search2
|
search2,
|
||||||
|
searchUsers
|
||||||
}
|
}
|
||||||
|
|
||||||
export default apiService
|
export default apiService
|
||||||
|
|
|
@ -152,6 +152,7 @@ const backendInteractorService = credentials => {
|
||||||
const unretweet = (id) => apiService.unretweet({ id, credentials })
|
const unretweet = (id) => apiService.unretweet({ id, credentials })
|
||||||
const search2 = ({ q, resolve, limit, offset, following }) =>
|
const search2 = ({ q, resolve, limit, offset, following }) =>
|
||||||
apiService.search2({ credentials, q, resolve, limit, offset, following })
|
apiService.search2({ credentials, q, resolve, limit, offset, following })
|
||||||
|
const searchUsers = (query) => apiService.searchUsers({ query, credentials })
|
||||||
|
|
||||||
const backendInteractorServiceInstance = {
|
const backendInteractorServiceInstance = {
|
||||||
fetchStatus,
|
fetchStatus,
|
||||||
|
@ -216,7 +217,8 @@ const backendInteractorService = credentials => {
|
||||||
retweet,
|
retweet,
|
||||||
unretweet,
|
unretweet,
|
||||||
updateNotificationSettings,
|
updateNotificationSettings,
|
||||||
search2
|
search2,
|
||||||
|
searchUsers
|
||||||
}
|
}
|
||||||
|
|
||||||
return backendInteractorServiceInstance
|
return backendInteractorServiceInstance
|
||||||
|
|
25
yarn.lock
25
yarn.lock
|
@ -5459,9 +5459,10 @@ pngjs@^3.3.0:
|
||||||
version "3.3.3"
|
version "3.3.3"
|
||||||
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.3.3.tgz#85173703bde3edac8998757b96e5821d0966a21b"
|
resolved "https://registry.yarnpkg.com/pngjs/-/pngjs-3.3.3.tgz#85173703bde3edac8998757b96e5821d0966a21b"
|
||||||
|
|
||||||
popper.js@^1.14.7:
|
popper.js@^1.15.0:
|
||||||
version "1.14.7"
|
version "1.15.0"
|
||||||
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.14.7.tgz#e31ec06cfac6a97a53280c3e55e4e0c860e7738e"
|
resolved "https://registry.yarnpkg.com/popper.js/-/popper.js-1.15.0.tgz#5560b99bbad7647e9faa475c6b8056621f5a4ff2"
|
||||||
|
integrity sha512-w010cY1oCUmI+9KwwlWki+r5jxKfTFDVoadl7MSrIujHU5MJ5OR6HTDj6Xo8aoR/QsA56x8jKjA59qGH4ELtrA==
|
||||||
|
|
||||||
portal-vue@^2.1.4:
|
portal-vue@^2.1.4:
|
||||||
version "2.1.4"
|
version "2.1.4"
|
||||||
|
@ -7198,6 +7199,15 @@ v-click-outside@^2.1.1:
|
||||||
version "2.1.3"
|
version "2.1.3"
|
||||||
resolved "https://registry.yarnpkg.com/v-click-outside/-/v-click-outside-2.1.3.tgz#b7297abe833a439dc0895e6418a494381e64b5e7"
|
resolved "https://registry.yarnpkg.com/v-click-outside/-/v-click-outside-2.1.3.tgz#b7297abe833a439dc0895e6418a494381e64b5e7"
|
||||||
|
|
||||||
|
v-tooltip@^2.0.2:
|
||||||
|
version "2.0.2"
|
||||||
|
resolved "https://registry.yarnpkg.com/v-tooltip/-/v-tooltip-2.0.2.tgz#8610d9eece2cc44fd66c12ef2f12eec6435cab9b"
|
||||||
|
integrity sha512-xQ+qzOFfywkLdjHknRPgMMupQNS8yJtf9Utd5Dxiu/0n4HtrxqsgDtN2MLZ0LKbburtSAQgyypuE/snM8bBZhw==
|
||||||
|
dependencies:
|
||||||
|
lodash "^4.17.11"
|
||||||
|
popper.js "^1.15.0"
|
||||||
|
vue-resize "^0.4.5"
|
||||||
|
|
||||||
validate-npm-package-license@^3.0.1:
|
validate-npm-package-license@^3.0.1:
|
||||||
version "3.0.4"
|
version "3.0.4"
|
||||||
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
|
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz#fc91f6b9c7ba15c857f4cb2c5defeec39d4f410a"
|
||||||
|
@ -7272,11 +7282,10 @@ vue-loader@^14.0.0:
|
||||||
vue-style-loader "^4.0.1"
|
vue-style-loader "^4.0.1"
|
||||||
vue-template-es2015-compiler "^1.6.0"
|
vue-template-es2015-compiler "^1.6.0"
|
||||||
|
|
||||||
vue-popperjs@^2.0.3:
|
vue-resize@^0.4.5:
|
||||||
version "2.0.3"
|
version "0.4.5"
|
||||||
resolved "https://registry.yarnpkg.com/vue-popperjs/-/vue-popperjs-2.0.3.tgz#7c446d0ba7c63170ccb33a02669d0df4efc3d8cd"
|
resolved "https://registry.yarnpkg.com/vue-resize/-/vue-resize-0.4.5.tgz#4777a23042e3c05620d9cbda01c0b3cc5e32dcea"
|
||||||
dependencies:
|
integrity sha512-bhP7MlgJQ8TIkZJXAfDf78uJO+mEI3CaLABLjv0WNzr4CcGRGPIAItyWYnP6LsPA4Oq0WE+suidNs6dgpO4RHg==
|
||||||
popper.js "^1.14.7"
|
|
||||||
|
|
||||||
vue-router@^3.0.1:
|
vue-router@^3.0.1:
|
||||||
version "3.0.2"
|
version "3.0.2"
|
||||||
|
|
Loading…
Reference in a new issue