Merge remote-tracking branch 'upstream/develop' into shigusegubu
* upstream/develop: (32 commits) [Debug] Avoid duplicates in the who to follow panel updated German translation * added theme settings * added various missing single strings Fix translation typo in registration.vue Update README Fix profiles without statuses not loading Fix conflicting styles Remove commented out back button Cleanup and remove divider element in side drawer New routes, notifications, other impovements in side drwaer Add "noAttachmentLinks" to src/modules/instance.js Make "noAttachmentLinks" configurable No attachment links Treat reserved users like external users in the frontend. User Card Content fixes and updates scopeCopy → true by default Restore old routes, enable user route as fallback. improve web push notifications fix Update japanese translation fix inconsistencies within who_to_follow_panel ...
This commit is contained in:
commit
1eea45cf6d
57 changed files with 1255 additions and 470 deletions
|
|
@ -1,6 +1,7 @@
|
|||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
|
||||
const chatPanel = {
|
||||
props: [ 'floating' ],
|
||||
data () {
|
||||
return {
|
||||
currentMessage: '',
|
||||
|
|
@ -22,7 +23,7 @@ const chatPanel = {
|
|||
this.collapsed = !this.collapsed
|
||||
},
|
||||
userProfileLink (user) {
|
||||
return generateProfileLink(user.id, user.screen_name)
|
||||
return generateProfileLink(user.id, user.username, this.$store.state.instance.restrictedNicknames)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
<template>
|
||||
<div class="chat-panel" v-if="!this.collapsed">
|
||||
<div class="chat-panel" v-if="!this.collapsed || !this.floating">
|
||||
<div class="panel panel-default">
|
||||
<div class="panel-heading timeline-heading chat-heading" @click.stop.prevent="togglePanel">
|
||||
<div class="panel-heading timeline-heading" :class="{ 'chat-heading': floating }" @click.stop.prevent="togglePanel">
|
||||
<div class="title">
|
||||
{{$t('chat.title')}}
|
||||
<i class="icon-cancel" style="float: right;"></i>
|
||||
<i class="icon-cancel" style="float: right;" v-if="floating"></i>
|
||||
</div>
|
||||
</div>
|
||||
<div class="chat-window" v-chat-scroll>
|
||||
|
|
@ -52,6 +52,7 @@
|
|||
right: 0px;
|
||||
bottom: 0px;
|
||||
z-index: 1000;
|
||||
max-width: 25em;
|
||||
}
|
||||
|
||||
.chat-heading {
|
||||
|
|
@ -63,10 +64,13 @@
|
|||
}
|
||||
|
||||
.chat-window {
|
||||
width: 345px;
|
||||
max-height: 40vh;
|
||||
overflow-y: auto;
|
||||
overflow-x: hidden;
|
||||
max-height: 20em;
|
||||
}
|
||||
|
||||
.chat-window-container {
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.chat-message {
|
||||
|
|
|
|||
|
|
@ -32,7 +32,7 @@ const LoginForm = {
|
|||
.then((result) => {
|
||||
this.$store.commit('setToken', result.access_token)
|
||||
this.$store.dispatch('loginUser', result.access_token)
|
||||
this.$router.push('/~/main/friends')
|
||||
this.$router.push({name: 'friends'})
|
||||
})
|
||||
})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
const NavPanel = {
|
||||
props: [ 'activatePanel' ],
|
||||
computed: {
|
||||
currentUser () {
|
||||
return this.$store.state.users.currentUser
|
||||
|
|
|
|||
|
|
@ -3,32 +3,32 @@
|
|||
<div class="panel panel-default">
|
||||
<ul>
|
||||
<li v-if='currentUser'>
|
||||
<router-link @click.native="activatePanel('timeline')" :to="{ name: 'friends' }">
|
||||
<router-link :to="{ name: 'friends' }">
|
||||
{{ $t("nav.timeline") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if='currentUser'>
|
||||
<router-link @click.native="activatePanel('timeline')" :to="{ name: 'mentions', params: { username: currentUser.screen_name } }">
|
||||
<router-link :to="{ name: 'mentions', params: { username: currentUser.screen_name } }">
|
||||
{{ $t("nav.mentions") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if='currentUser'>
|
||||
<router-link @click.native="activatePanel('timeline')" :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
|
||||
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
|
||||
{{ $t("nav.dms") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if='currentUser && currentUser.locked'>
|
||||
<router-link @click.native="activatePanel('timeline')" :to="{ name: 'friend-requests' }">
|
||||
<router-link :to="{ name: 'friend-requests' }">
|
||||
{{ $t("nav.friend_requests") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<router-link @click.native="activatePanel('timeline')" :to="{ name: 'public-timeline' }">
|
||||
<router-link :to="{ name: 'public-timeline' }">
|
||||
{{ $t("nav.public_tl") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li>
|
||||
<router-link @click.native="activatePanel('timeline')" :to="{ name: 'public-external-timeline' }">
|
||||
<router-link :to="{ name: 'public-external-timeline' }">
|
||||
{{ $t("nav.twkn") }}
|
||||
</router-link>
|
||||
</li>
|
||||
|
|
|
|||
|
|
@ -11,10 +11,7 @@ const Notification = {
|
|||
betterShadow: this.$store.state.interface.browserSupport.cssFilter
|
||||
}
|
||||
},
|
||||
props: [
|
||||
'notification',
|
||||
'activatePanel'
|
||||
],
|
||||
props: [ 'notification' ],
|
||||
components: {
|
||||
Status, StillImage, UserCardContent
|
||||
},
|
||||
|
|
@ -23,7 +20,7 @@ const Notification = {
|
|||
this.userExpanded = !this.userExpanded
|
||||
},
|
||||
userProfileLink (user) {
|
||||
return generateProfileLink(user.id, user.screen_name)
|
||||
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
<template>
|
||||
<status :activatePanel="activatePanel" 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>
|
||||
<a class='avatar-container' :href="notification.action.user.statusnet_profile_url" @click.stop.prevent.capture="toggleUserExpanded">
|
||||
<StillImage class='avatar-compact' :class="{'better-shadow': betterShadow}" :src="notification.action.user.profile_image_url_original"/>
|
||||
|
|
@ -25,15 +25,15 @@
|
|||
<small>{{$t('notifications.followed_you')}}</small>
|
||||
</span>
|
||||
</div>
|
||||
<small class="timeago"><router-link @click.native="activatePanel('timeline')" v-if="notification.status" :to="{ name: 'conversation', params: { id: notification.status.id } }"><timeago :since="notification.action.created_at" :auto-update="240"></timeago></router-link></small>
|
||||
<small class="timeago"><router-link v-if="notification.status" :to="{ name: 'conversation', params: { id: notification.status.id } }"><timeago :since="notification.action.created_at" :auto-update="240"></timeago></router-link></small>
|
||||
</span>
|
||||
<div class="follow-text" v-if="notification.type === 'follow'">
|
||||
<router-link @click.native="activatePanel('timeline')" :to="userProfileLink(notification.action.user)">
|
||||
<router-link :to="userProfileLink(notification.action.user)">
|
||||
@{{notification.action.user.screen_name}}
|
||||
</router-link>
|
||||
</div>
|
||||
<template v-else>
|
||||
<status :activatePanel="activatePanel" class="faint" :compact="true" :statusoid="notification.status" :noHeading="true"></status>
|
||||
<status class="faint" :compact="true" :statusoid="notification.status" :noHeading="true"></status>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -1,10 +1,12 @@
|
|||
import Notification from '../notification/notification.vue'
|
||||
import notificationsFetcher from '../../services/notifications_fetcher/notifications_fetcher.service.js'
|
||||
|
||||
import { sortBy, filter } from 'lodash'
|
||||
import {
|
||||
notificationsFromStore,
|
||||
visibleNotificationsFromStore,
|
||||
unseenNotificationsFromStore
|
||||
} from '../../services/notification_utils/notification_utils.js'
|
||||
|
||||
const Notifications = {
|
||||
props: [ 'activatePanel' ],
|
||||
created () {
|
||||
const store = this.$store
|
||||
const credentials = store.state.users.currentUser.credentials
|
||||
|
|
@ -12,28 +14,17 @@ const Notifications = {
|
|||
notificationsFetcher.startFetching({ store, credentials })
|
||||
},
|
||||
computed: {
|
||||
visibleTypes () {
|
||||
return [
|
||||
this.$store.state.config.notificationVisibility.likes && 'like',
|
||||
this.$store.state.config.notificationVisibility.mentions && 'mention',
|
||||
this.$store.state.config.notificationVisibility.repeats && 'repeat',
|
||||
this.$store.state.config.notificationVisibility.follows && 'follow'
|
||||
].filter(_ => _)
|
||||
},
|
||||
notifications () {
|
||||
return this.$store.state.statuses.notifications.data
|
||||
return notificationsFromStore(this.$store)
|
||||
},
|
||||
error () {
|
||||
return this.$store.state.statuses.notifications.error
|
||||
},
|
||||
unseenNotifications () {
|
||||
return filter(this.visibleNotifications, ({seen}) => !seen)
|
||||
return unseenNotificationsFromStore(this.$store)
|
||||
},
|
||||
visibleNotifications () {
|
||||
// Don't know why, but sortBy([seen, -action.id]) doesn't work.
|
||||
let sortedNotifications = sortBy(this.notifications, ({action}) => -action.id)
|
||||
sortedNotifications = sortBy(sortedNotifications, 'seen')
|
||||
return sortedNotifications.filter((notification) => this.visibleTypes.includes(notification.type))
|
||||
return visibleNotificationsFromStore(this.$store)
|
||||
},
|
||||
unseenCount () {
|
||||
return this.unseenNotifications.length
|
||||
|
|
|
|||
|
|
@ -14,7 +14,7 @@
|
|||
<div class="panel-body">
|
||||
<div v-for="notification in visibleNotifications" :key="notification.action.id" class="notification" :class='{"unseen": !notification.seen}'>
|
||||
<div class="notification-overlay"></div>
|
||||
<notification :activatePanel="activatePanel" :notification="notification"></notification>
|
||||
<notification :notification="notification"></notification>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-footer">
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ const oac = {
|
|||
}).then((result) => {
|
||||
this.$store.commit('setToken', result.access_token)
|
||||
this.$store.dispatch('loginUser', result.access_token)
|
||||
this.$router.push('/~/main/friends')
|
||||
this.$router.push({name: 'friends'})
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -249,6 +249,7 @@ const PostStatusForm = {
|
|||
}
|
||||
this.$emit('posted')
|
||||
let el = this.$el.querySelector('textarea')
|
||||
el.style.height = 'auto'
|
||||
el.style.height = undefined
|
||||
this.error = null
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ const registration = {
|
|||
},
|
||||
created () {
|
||||
if ((!this.registrationOpen && !this.token) || this.signedIn) {
|
||||
this.$router.push('/~/main/all')
|
||||
this.$router.push({name: 'root'})
|
||||
}
|
||||
|
||||
this.setCaptcha()
|
||||
|
|
@ -48,15 +48,17 @@ const registration = {
|
|||
async submit () {
|
||||
this.user.nickname = this.user.username
|
||||
this.user.token = this.token
|
||||
|
||||
this.user.captcha_solution = this.captcha.solution
|
||||
this.user.captcha_token = this.captcha.token
|
||||
this.user.captcha_answer_data = this.captcha.answer_data
|
||||
|
||||
this.$v.$touch()
|
||||
|
||||
if (!this.$v.$invalid) {
|
||||
try {
|
||||
await this.signUp(this.user)
|
||||
this.$router.push('/~/main/friends')
|
||||
this.$router.push({name: 'friends'})
|
||||
} catch (error) {
|
||||
console.warn('Registration failed: ' + error)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -76,15 +76,16 @@
|
|||
</div>
|
||||
|
||||
<div class="form-group" id="captcha-group" v-if="captcha.type != 'none'">
|
||||
<label class='form--label' for='captcha-label'>{{$t('captcha')}}</label>
|
||||
|
||||
<template v-if="captcha.type == 'kocaptcha'">
|
||||
<img v-bind:src="captcha.url" v-on:click="setCaptcha">
|
||||
|
||||
<sub>Click the image to get a new captcha</sub>
|
||||
<label class='form--label' for='captcha-label'>CAPTCHA</label>
|
||||
<sub>{{$t('registration.new_captcha')}}</sub>
|
||||
|
||||
<input :disabled="isPending"
|
||||
v-model='captcha.solution'
|
||||
class='form-control' id='captcha-answer' type='text'>
|
||||
class='form-control' id='captcha-answer' type='text' autocomplete="off">
|
||||
</template>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
48
src/components/side_drawer/side_drawer.js
Normal file
48
src/components/side_drawer/side_drawer.js
Normal file
|
|
@ -0,0 +1,48 @@
|
|||
import UserCardContent from '../user_card_content/user_card_content.vue'
|
||||
import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils'
|
||||
|
||||
// TODO: separate touch gesture stuff into their own utils if more components want them
|
||||
const deltaCoord = (oldCoord, newCoord) => [newCoord[0] - oldCoord[0], newCoord[1] - oldCoord[1]]
|
||||
|
||||
const touchEventCoord = e => ([e.touches[0].screenX, e.touches[0].screenY])
|
||||
|
||||
const SideDrawer = {
|
||||
props: [ 'logout' ],
|
||||
data: () => ({
|
||||
closed: true,
|
||||
touchCoord: [0, 0]
|
||||
}),
|
||||
components: { UserCardContent },
|
||||
computed: {
|
||||
currentUser () {
|
||||
return this.$store.state.users.currentUser
|
||||
},
|
||||
chat () { return this.$store.state.chat.channel.state === 'joined' },
|
||||
unseenNotifications () {
|
||||
return unseenNotificationsFromStore(this.$store)
|
||||
},
|
||||
unseenNotificationsCount () {
|
||||
return this.unseenNotifications.length
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggleDrawer () {
|
||||
this.closed = !this.closed
|
||||
},
|
||||
doLogout () {
|
||||
this.logout()
|
||||
this.toggleDrawer()
|
||||
},
|
||||
touchStart (e) {
|
||||
this.touchCoord = touchEventCoord(e)
|
||||
},
|
||||
touchMove (e) {
|
||||
const delta = deltaCoord(this.touchCoord, touchEventCoord(e))
|
||||
if (delta[0] < -30 && Math.abs(delta[1]) < Math.abs(delta[0]) && !this.closed) {
|
||||
this.toggleDrawer()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export default SideDrawer
|
||||
189
src/components/side_drawer/side_drawer.vue
Normal file
189
src/components/side_drawer/side_drawer.vue
Normal file
|
|
@ -0,0 +1,189 @@
|
|||
<template>
|
||||
<div class="side-drawer-container"
|
||||
:class="{ 'side-drawer-container-closed': closed, 'side-drawer-container-open': !closed }"
|
||||
>
|
||||
<div class="side-drawer"
|
||||
:class="{'side-drawer-closed': closed}"
|
||||
@touchstart="touchStart"
|
||||
@touchmove="touchMove"
|
||||
>
|
||||
<div class="side-drawer-heading" @click="toggleDrawer">
|
||||
<user-card-content :user="currentUser" :switcher="false" :hideBio="true" v-if="currentUser">
|
||||
</user-card-content>
|
||||
</div>
|
||||
<ul>
|
||||
<li v-if="currentUser" @click="toggleDrawer">
|
||||
<router-link :to="{ name: 'new-status', params: { username: currentUser.screen_name } }">
|
||||
{{ $t("post_status.new_status") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-else @click="toggleDrawer">
|
||||
<router-link :to="{ name: 'login' }">
|
||||
{{ $t("login.login") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="currentUser" @click="toggleDrawer">
|
||||
<router-link :to="{ name: 'notifications', params: { username: currentUser.screen_name } }">
|
||||
{{ $t("notifications.notifications") }} {{ unseenNotificationsCount > 0 ? `(${unseenNotificationsCount})` : '' }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="currentUser" @click="toggleDrawer">
|
||||
<router-link :to="{ name: 'dms', params: { username: currentUser.screen_name } }">
|
||||
{{ $t("nav.dms") }}
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li v-if="currentUser" @click="toggleDrawer">
|
||||
<router-link :to="{ name: 'friends' }">
|
||||
{{ $t("nav.timeline") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="currentUser && currentUser.locked" @click="toggleDrawer">
|
||||
<router-link to='/friend-requests'>
|
||||
{{ $t("nav.friend_requests") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li @click="toggleDrawer">
|
||||
<router-link to='/main/public'>
|
||||
{{ $t("nav.public_tl") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li @click="toggleDrawer">
|
||||
<router-link to='/main/all'>
|
||||
{{ $t("nav.twkn") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="currentUser && chat" @click="toggleDrawer">
|
||||
<router-link :to="{ name: 'chat' }">
|
||||
{{ $t("nav.chat") }}
|
||||
</router-link>
|
||||
</li>
|
||||
</ul>
|
||||
<ul>
|
||||
<li @click="toggleDrawer">
|
||||
<router-link :to="{ name: 'user-search'}">
|
||||
{{ $t("nav.user_search") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li @click="toggleDrawer">
|
||||
<router-link :to="{ name: 'settings'}">
|
||||
{{ $t("settings.settings") }}
|
||||
</router-link>
|
||||
</li>
|
||||
<li v-if="currentUser" @click="toggleDrawer">
|
||||
<a @click="doLogout" href="#">
|
||||
{{ $t("login.logout") }}
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="side-drawer-click-outside"
|
||||
@click.stop.prevent="toggleDrawer"
|
||||
:class="{'side-drawer-click-outside-closed': closed}"
|
||||
></div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./side_drawer.js" ></script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.side-drawer-container {
|
||||
position: fixed;
|
||||
z-index: 1000;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
.side-drawer-container-open {
|
||||
transition-delay: 0.0s;
|
||||
transition-property: left;
|
||||
}
|
||||
|
||||
.side-drawer-container-closed {
|
||||
left: -100%;
|
||||
transition-delay: 0.5s;
|
||||
transition-property: left;
|
||||
}
|
||||
|
||||
.side-drawer-click-outside {
|
||||
flex: 1 1 100%;
|
||||
}
|
||||
|
||||
.side-drawer {
|
||||
overflow-x: hidden;
|
||||
transition: 0.5s;
|
||||
transition-timing-function: cubic-bezier(0, 1, 0.5, 1);
|
||||
margin: 0 0 0 -100px;
|
||||
padding: 0 0 1em 100px;
|
||||
width: 80%;
|
||||
max-width: 20em;
|
||||
flex: 0 0 80%;
|
||||
box-shadow: 1px 1px 4px rgba(0, 0, 0, 0.6);
|
||||
box-shadow: var(--panelShadow);
|
||||
background-color: $fallback--bg;
|
||||
background-color: var(--bg, $fallback--bg);
|
||||
}
|
||||
|
||||
.side-drawer-click-outside-closed {
|
||||
flex: 0 0 0;
|
||||
}
|
||||
|
||||
.side-drawer-closed {
|
||||
margin: 0 0 0 calc(-100% - 100px);
|
||||
}
|
||||
|
||||
.side-drawer-heading {
|
||||
background: transparent;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
display: flex;
|
||||
min-height: 7em;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
.profile-panel-background {
|
||||
border-radius: 0;
|
||||
.panel-heading {
|
||||
background: transparent;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.side-drawer ul {
|
||||
list-style: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
|
||||
border-bottom: 1px solid;
|
||||
border-color: $fallback--border;
|
||||
border-color: var(--border, $fallback--border);
|
||||
margin: 0.2em 0;
|
||||
}
|
||||
|
||||
.side-drawer ul:last-child {
|
||||
border: 0;
|
||||
}
|
||||
|
||||
.side-drawer li {
|
||||
padding: 0;
|
||||
|
||||
a {
|
||||
display: block;
|
||||
padding: 0.5em 0.85em;
|
||||
|
||||
&:hover {
|
||||
background-color: $fallback--lightBg;
|
||||
background-color: var(--lightBg, $fallback--lightBg);
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
@ -21,8 +21,7 @@ const Status = {
|
|||
'replies',
|
||||
'noReplyLinks',
|
||||
'noHeading',
|
||||
'inlineExpanded',
|
||||
'activatePanel'
|
||||
'inlineExpanded'
|
||||
],
|
||||
data () {
|
||||
return {
|
||||
|
|
@ -291,7 +290,7 @@ const Status = {
|
|||
this.showPreview = false
|
||||
},
|
||||
userProfileLink (id, name) {
|
||||
return generateProfileLink(id, name)
|
||||
return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
<template v-if="muted && !noReplyLinks">
|
||||
<div class="media status container muted">
|
||||
<small>
|
||||
<router-link @click.native="activatePanel('timeline')" :to="userProfileLink(status.user.id, status.user.screen_name)">
|
||||
<router-link :to="userProfileLink(status.user.id, status.user.screen_name)">
|
||||
{{status.user.screen_name}}
|
||||
</router-link>
|
||||
</small>
|
||||
|
|
@ -38,12 +38,12 @@
|
|||
<h4 class="user-name" v-if="status.user.name_html" v-html="status.user.name_html"></h4>
|
||||
<h4 class="user-name" v-else>{{status.user.name}}</h4>
|
||||
<span class="links">
|
||||
<router-link @click.native="activatePanel('timeline')" :to="userProfileLink(status.user.id, status.user.screen_name)">
|
||||
<router-link :to="userProfileLink(status.user.id, status.user.screen_name)">
|
||||
{{status.user.screen_name}}
|
||||
</router-link>
|
||||
<span v-if="status.in_reply_to_screen_name" class="faint reply-info">
|
||||
<i class="icon-right-open"></i>
|
||||
<router-link @click.native="activatePanel('timeline')" :to="userProfileLink(status.in_reply_to_user_id, status.in_reply_to_screen_name)">
|
||||
<router-link :to="userProfileLink(status.in_reply_to_user_id, status.in_reply_to_screen_name)">
|
||||
{{status.in_reply_to_screen_name}}
|
||||
</router-link>
|
||||
</span>
|
||||
|
|
@ -60,7 +60,7 @@
|
|||
</h4>
|
||||
</div>
|
||||
<div class="media-heading-right">
|
||||
<router-link class="timeago" @click.native="activatePanel('timeline')" :to="{ name: 'conversation', params: { id: status.id } }">
|
||||
<router-link class="timeago" :to="{ name: 'conversation', params: { id: status.id } }">
|
||||
<timeago :since="status.created_at" :auto-update="60"></timeago>
|
||||
</router-link>
|
||||
<div class="button-icon visibility-icon" v-if="status.visibility">
|
||||
|
|
@ -79,7 +79,7 @@
|
|||
</div>
|
||||
|
||||
<div v-if="showPreview" class="status-preview-container">
|
||||
<status :activatePanel="activatePanel" class="status-preview" v-if="preview" :noReplyLinks="true" :statusoid="preview" :compact=true></status>
|
||||
<status class="status-preview" v-if="preview" :noReplyLinks="true" :statusoid="preview" :compact=true></status>
|
||||
<div class="status-preview status-preview-loading" v-else>
|
||||
<i class="icon-spin4 animate-spin"></i>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ const UserCard = {
|
|||
this.$store.dispatch('removeFollowRequest', this.user)
|
||||
},
|
||||
userProfileLink (user) {
|
||||
return generateProfileLink(user.id, user.screen_name)
|
||||
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@ import { hex2rgb } from '../../services/color_convert/color_convert.js'
|
|||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
|
||||
export default {
|
||||
props: [ 'user', 'switcher', 'selected', 'hideBio', 'activatePanel' ],
|
||||
props: [ 'user', 'switcher', 'selected', 'hideBio' ],
|
||||
data () {
|
||||
return {
|
||||
followRequestInProgress: false,
|
||||
|
|
@ -180,7 +180,7 @@ export default {
|
|||
}
|
||||
},
|
||||
userProfileLink (user) {
|
||||
return generateProfileLink(user.id, user.screen_name)
|
||||
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -2,22 +2,25 @@
|
|||
<div id="heading" class="profile-panel-background" :style="headingStyle">
|
||||
<div class="panel-heading text-center">
|
||||
<div class='user-info'>
|
||||
<router-link @click.native="activatePanel && activatePanel('timeline')" :to="{ name: 'user-settings' }" style="float: right; margin-top:16px;" v-if="!isOtherUser">
|
||||
<i class="button-icon icon-cog usersettings" :title="$t('tool_tip.user_settings')"></i>
|
||||
</router-link>
|
||||
<a :href="user.statusnet_profile_url" target="_blank" class="floater" v-if="isOtherUser">
|
||||
<i class="icon-link-ext usersettings"></i>
|
||||
</a>
|
||||
<div class='container'>
|
||||
<router-link @click.native="activatePanel && activatePanel('timeline')" :to="userProfileLink(user)">
|
||||
<router-link :to="userProfileLink(user)">
|
||||
<StillImage class="avatar" :class='{ "better-shadow": betterShadow }' :src="user.profile_image_url_original"/>
|
||||
</router-link>
|
||||
<div class="name-and-screen-name">
|
||||
<div :title="user.name" class='user-name' v-if="user.name_html" v-html="user.name_html"></div>
|
||||
<div :title="user.name" class='user-name' v-else>{{user.name}}</div>
|
||||
<router-link @click.native="activatePanel && activatePanel('timeline')" class='user-screen-name' :to="userProfileLink(user)">
|
||||
<span>@{{user.screen_name}}</span><span v-if="user.locked"><i class="icon icon-lock"></i></span>
|
||||
<span v-if="!hideUserStatsLocal" class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span>
|
||||
<div class="top-line">
|
||||
<div :title="user.name" class='user-name' v-if="user.name_html" v-html="user.name_html"></div>
|
||||
<div :title="user.name" class='user-name' v-else>{{user.name}}</div>
|
||||
<router-link :to="{ name: 'user-settings' }" v-if="!isOtherUser">
|
||||
<i class="button-icon icon-cog usersettings" :title="$t('tool_tip.user_settings')"></i>
|
||||
</router-link>
|
||||
<a :href="user.statusnet_profile_url" target="_blank" v-if="isOtherUser">
|
||||
<i class="icon-link-ext usersettings"></i>
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<router-link class='user-screen-name' :to="userProfileLink(user)">
|
||||
<span class="handle">@{{user.screen_name}}</span><span v-if="user.locked"><i class="icon icon-lock"></i></span>
|
||||
<span v-if="!hideUserStatsLocal && !hideBio" class="dailyAvg">{{dailyAvg}} {{ $t('user_card.per_day') }}</span>
|
||||
</router-link>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -25,7 +28,7 @@
|
|||
<div v-if="user.follows_you && loggedIn && isOtherUser" class="following">
|
||||
{{ $t('user_card.follows_you') }}
|
||||
</div>
|
||||
<div class="floater" v-if="isOtherUser && (loggedIn || !switcher)">
|
||||
<div class="highlighter" v-if="isOtherUser && (loggedIn || !switcher)">
|
||||
<!-- id's need to be unique, otherwise vue confuses which user-card checkbox belongs to -->
|
||||
<input class="userHighlightText" type="text" :id="'userHighlightColorTx'+user.id" v-if="userHighlightType !== 'disabled'" v-model="userHighlightColor"/>
|
||||
<input class="userHighlightCl" type="color" :id="'userHighlightColor'+user.id" v-if="userHighlightType !== 'disabled'" v-model="userHighlightColor"/>
|
||||
|
|
@ -139,7 +142,7 @@
|
|||
border-bottom-right-radius: 0;
|
||||
|
||||
.panel-heading {
|
||||
padding: 0.6em 0em;
|
||||
padding: .6em 0;
|
||||
text-align: center;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
|
@ -158,10 +161,10 @@
|
|||
.user-info {
|
||||
color: $fallback--lightText;
|
||||
color: var(--lightText, $fallback--lightText);
|
||||
padding: 0 16px;
|
||||
padding: 0 26px;
|
||||
|
||||
.container {
|
||||
padding: 16px 10px 6px 10px;
|
||||
padding: 16px 0 6px;
|
||||
display: flex;
|
||||
max-height: 56px;
|
||||
|
||||
|
|
@ -218,11 +221,15 @@
|
|||
vertical-align: middle;
|
||||
object-fit: contain
|
||||
}
|
||||
.top-line {
|
||||
display: flex;
|
||||
}
|
||||
}
|
||||
|
||||
.user-name{
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.user-screen-name {
|
||||
|
|
@ -232,27 +239,73 @@
|
|||
font-weight: light;
|
||||
font-size: 15px;
|
||||
padding-right: 0.1em;
|
||||
width: 100%;
|
||||
display: flex;
|
||||
|
||||
.dailyAvg {
|
||||
min-width: 1px;
|
||||
flex: 0 0 auto;
|
||||
}
|
||||
|
||||
.handle {
|
||||
min-width: 1px;
|
||||
flex: 0 1 auto;
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.user-meta {
|
||||
margin-bottom: .4em;
|
||||
margin-bottom: .15em;
|
||||
display: flex;
|
||||
align-items: baseline;
|
||||
font-size: 14px;
|
||||
line-height: 22px;
|
||||
flex-wrap: wrap;
|
||||
|
||||
.following {
|
||||
font-size: 14px;
|
||||
flex: 0 0 100%;
|
||||
flex: 1 0 auto;
|
||||
margin: 0;
|
||||
padding-left: 16px;
|
||||
margin-bottom: .25em;
|
||||
text-align: left;
|
||||
float: left;
|
||||
}
|
||||
.floater {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
&::after {
|
||||
display: block;
|
||||
content: '';
|
||||
clear: both;
|
||||
.highlighter {
|
||||
flex: 0 1 auto;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
margin-right: -.5em;
|
||||
align-self: start;
|
||||
|
||||
.userHighlightCl {
|
||||
padding: 2px 10px;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.userHighlightSel,
|
||||
.userHighlightSel.select {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
.userHighlightSel.select i {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.userHighlightText {
|
||||
width: 70px;
|
||||
flex: 1 0 auto;
|
||||
}
|
||||
|
||||
.userHighlightCl,
|
||||
.userHighlightText,
|
||||
.userHighlightSel,
|
||||
.userHighlightSel.select {
|
||||
height: 22px;
|
||||
vertical-align: top;
|
||||
margin-right: .5em;
|
||||
margin-bottom: .25em;
|
||||
}
|
||||
}
|
||||
}
|
||||
.user-interactions {
|
||||
|
|
@ -260,8 +313,13 @@
|
|||
flex-flow: row wrap;
|
||||
justify-content: space-between;
|
||||
|
||||
margin-right: -.75em;
|
||||
|
||||
div {
|
||||
flex: 1;
|
||||
flex: 1 0 0;
|
||||
margin-right: .75em;
|
||||
margin-bottom: .6em;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.mute {
|
||||
|
|
@ -280,8 +338,9 @@
|
|||
}
|
||||
|
||||
button {
|
||||
width: 92%;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.remote-button {
|
||||
|
|
@ -304,10 +363,11 @@
|
|||
justify-content: space-between;
|
||||
color: $fallback--lightText;
|
||||
color: var(--lightText, $fallback--lightText);
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.user-count {
|
||||
flex: 1;
|
||||
flex: 1 0 auto;
|
||||
padding: .5em 0 .5em 0;
|
||||
margin: 0 .5em;
|
||||
|
||||
|
|
@ -327,32 +387,5 @@
|
|||
color: #CCC;
|
||||
}
|
||||
.floater {
|
||||
float: right;
|
||||
margin-top: 16px;
|
||||
|
||||
.userHighlightCl {
|
||||
padding: 2px 10px;
|
||||
}
|
||||
.userHighlightSel,
|
||||
.userHighlightSel.select {
|
||||
padding-top: 0;
|
||||
padding-bottom: 0;
|
||||
}
|
||||
.userHighlightSel.select i {
|
||||
line-height: 22px;
|
||||
}
|
||||
|
||||
.userHighlightText {
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
.userHighlightCl,
|
||||
.userHighlightText,
|
||||
.userHighlightSel,
|
||||
.userHighlightSel.select {
|
||||
height: 22px;
|
||||
vertical-align: top;
|
||||
margin-right: 0
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -1,14 +1,16 @@
|
|||
<template>
|
||||
<div class="user-finder-container">
|
||||
<i class="icon-spin4 user-finder-icon animate-spin-slow" v-if="loading" />
|
||||
<a href="#" v-if="hidden" :title="$t('finder.find_user')"><i class="icon-user-plus user-finder-icon" @click.prevent.stop="toggleHidden" /></a>
|
||||
<template v-else>
|
||||
<input class="user-finder-input" @keyup.enter="findUser(username)" v-model="username" :placeholder="$t('finder.find_user')" id="user-finder-input" type="text"/>
|
||||
<button class="btn search-button" @click="findUser(username)">
|
||||
<i class="icon-search"/>
|
||||
</button>
|
||||
<i class="button-icon icon-cancel user-finder-icon" @click.prevent.stop="toggleHidden"/>
|
||||
</template>
|
||||
<div>
|
||||
<div class="user-finder-container">
|
||||
<i class="icon-spin4 user-finder-icon animate-spin-slow" v-if="loading" />
|
||||
<a href="#" v-if="hidden" :title="$t('finder.find_user')"><i class="icon-user-plus user-finder-icon" @click.prevent.stop="toggleHidden" /></a>
|
||||
<template v-else>
|
||||
<input class="user-finder-input" @keyup.enter="findUser(username)" v-model="username" :placeholder="$t('finder.find_user')" id="user-finder-input" type="text"/>
|
||||
<button class="btn search-button" @click="findUser(username)">
|
||||
<i class="icon-search"/>
|
||||
</button>
|
||||
<i class="button-icon icon-cancel user-finder-icon" @click.prevent.stop="toggleHidden"/>
|
||||
</template>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
|
|
|
|||
|
|
@ -3,7 +3,6 @@ import PostStatusForm from '../post_status_form/post_status_form.vue'
|
|||
import UserCardContent from '../user_card_content/user_card_content.vue'
|
||||
|
||||
const UserPanel = {
|
||||
props: [ 'activatePanel' ],
|
||||
computed: {
|
||||
user () { return this.$store.state.users.currentUser }
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="user-panel">
|
||||
<div v-if='user' class="panel panel-default" style="overflow: visible;">
|
||||
<user-card-content :activatePanel="activatePanel" :user="user" :switcher="false" :hideBio="true"></user-card-content>
|
||||
<user-card-content :user="user" :switcher="false" :hideBio="true"></user-card-content>
|
||||
<div class="panel-footer">
|
||||
<post-status-form v-if='user'></post-status-form>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -6,7 +6,7 @@ const UserProfile = {
|
|||
created () {
|
||||
this.$store.commit('clearTimeline', { timeline: 'user' })
|
||||
this.$store.dispatch('startFetching', ['user', this.fetchBy])
|
||||
if (!this.user) {
|
||||
if (!this.user.id) {
|
||||
this.$store.dispatch('fetchUser', this.fetchBy)
|
||||
}
|
||||
},
|
||||
|
|
@ -29,14 +29,20 @@ const UserProfile = {
|
|||
followers () {
|
||||
return this.user.followers
|
||||
},
|
||||
userInStore () {
|
||||
if (this.isExternal) {
|
||||
return this.$store.getters.userById(this.userId)
|
||||
}
|
||||
return this.$store.getters.userByName(this.userName)
|
||||
},
|
||||
user () {
|
||||
if (this.timeline.statuses[0]) {
|
||||
return this.timeline.statuses[0].user
|
||||
} else {
|
||||
return Object.values(this.$store.state.users.usersObject).filter(user => {
|
||||
return (this.isExternal ? user.id === this.userId : user.screen_name === this.userName)
|
||||
})[0] || {}
|
||||
}
|
||||
if (this.userInStore) {
|
||||
return this.userInStore
|
||||
}
|
||||
return {}
|
||||
},
|
||||
fetchBy () {
|
||||
return this.isExternal ? this.userId : this.userName
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@
|
|||
flex: 2;
|
||||
flex-basis: 500px;
|
||||
|
||||
.panel-heading {
|
||||
.profile-panel-background .panel-heading {
|
||||
background: transparent;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
|
|
|
|||
|
|
@ -9,6 +9,7 @@ const userSearch = {
|
|||
],
|
||||
data () {
|
||||
return {
|
||||
username: '',
|
||||
users: []
|
||||
}
|
||||
},
|
||||
|
|
@ -21,7 +22,14 @@ const userSearch = {
|
|||
}
|
||||
},
|
||||
methods: {
|
||||
newQuery (query) {
|
||||
this.$router.push({ name: 'user-search', query: { query } })
|
||||
},
|
||||
search (query) {
|
||||
if (!query) {
|
||||
this.users = []
|
||||
return
|
||||
}
|
||||
userSearchApi.search({query, store: this.$store})
|
||||
.then((res) => {
|
||||
this.users = res
|
||||
|
|
|
|||
|
|
@ -3,6 +3,12 @@
|
|||
<div class="panel-heading">
|
||||
{{$t('nav.user_search')}}
|
||||
</div>
|
||||
<div class="user-search-input-container">
|
||||
<input class="user-finder-input" @keyup.enter="newQuery(username)" v-model="username" :placeholder="$t('finder.find_user')"/>
|
||||
<button class="btn search-button" @click="newQuery(username)">
|
||||
<i class="icon-search"/>
|
||||
</button>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<user-card v-for="user in users" :key="user.id" :user="user" :showFollows="true"></user-card>
|
||||
</div>
|
||||
|
|
@ -10,3 +16,15 @@
|
|||
</template>
|
||||
|
||||
<script src="./user_search.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
.user-search-input-container {
|
||||
margin: 0.5em;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
||||
.search-button {
|
||||
margin-left: 0.5em;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
|||
|
|
@ -257,7 +257,7 @@ const UserSettings = {
|
|||
.then((res) => {
|
||||
if (res.status === 'success') {
|
||||
this.$store.dispatch('logout')
|
||||
this.$router.push('/~/main/all')
|
||||
this.$router.push({name: 'root'})
|
||||
} else {
|
||||
this.deleteAccountError = res.error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,63 +1,34 @@
|
|||
import apiService from '../../services/api/api.service.js'
|
||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
import _ from 'lodash'
|
||||
|
||||
function showWhoToFollow (panel, reply) {
|
||||
var users = reply
|
||||
var cn
|
||||
var index
|
||||
var step = 7
|
||||
cn = Math.floor(Math.random() * step)
|
||||
for (index = 0; index < 3; index++) {
|
||||
var user
|
||||
user = users[cn]
|
||||
var img
|
||||
if (user.avatar) {
|
||||
img = user.avatar
|
||||
} else {
|
||||
img = '/images/avi.png'
|
||||
}
|
||||
var name = user.acct
|
||||
if (index === 0) {
|
||||
panel.img1 = img
|
||||
panel.name1 = name
|
||||
panel.$store.state.api.backendInteractor.externalProfile(name)
|
||||
.then((externalUser) => {
|
||||
if (!externalUser.error) {
|
||||
panel.$store.commit('addNewUsers', [externalUser])
|
||||
panel.id1 = externalUser.id
|
||||
}
|
||||
})
|
||||
} else if (index === 1) {
|
||||
panel.img2 = img
|
||||
panel.name2 = name
|
||||
panel.$store.state.api.backendInteractor.externalProfile(name)
|
||||
.then((externalUser) => {
|
||||
if (!externalUser.error) {
|
||||
panel.$store.commit('addNewUsers', [externalUser])
|
||||
panel.id2 = externalUser.id
|
||||
}
|
||||
})
|
||||
} else if (index === 2) {
|
||||
panel.img3 = img
|
||||
panel.name3 = name
|
||||
panel.$store.state.api.backendInteractor.externalProfile(name)
|
||||
.then((externalUser) => {
|
||||
if (!externalUser.error) {
|
||||
panel.$store.commit('addNewUsers', [externalUser])
|
||||
panel.id3 = externalUser.id
|
||||
}
|
||||
})
|
||||
}
|
||||
cn = (cn + step) % users.length
|
||||
}
|
||||
_.shuffle(reply)
|
||||
|
||||
panel.usersToFollow.forEach((toFollow, index) => {
|
||||
let user = reply[index]
|
||||
let img = user.avatar || '/images/avi.png'
|
||||
let name = user.acct
|
||||
|
||||
toFollow.img = img
|
||||
toFollow.name = name
|
||||
|
||||
panel.$store.state.api.backendInteractor.externalProfile(name)
|
||||
.then((externalUser) => {
|
||||
if (!externalUser.error) {
|
||||
panel.$store.commit('addNewUsers', [externalUser])
|
||||
toFollow.id = externalUser.id
|
||||
}
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
function getWhoToFollow (panel) {
|
||||
var credentials = panel.$store.state.users.currentUser.credentials
|
||||
if (credentials) {
|
||||
panel.name1 = 'Loading...'
|
||||
panel.name2 = 'Loading...'
|
||||
panel.name3 = 'Loading...'
|
||||
panel.usersToFollow.forEach(toFollow => {
|
||||
toFollow.name = 'Loading...'
|
||||
})
|
||||
apiService.suggestions({credentials: credentials})
|
||||
.then((reply) => {
|
||||
showWhoToFollow(panel, reply)
|
||||
|
|
@ -67,27 +38,24 @@ function getWhoToFollow (panel) {
|
|||
|
||||
const WhoToFollowPanel = {
|
||||
data: () => ({
|
||||
img1: '/images/avi.png',
|
||||
name1: '',
|
||||
id1: 0,
|
||||
img2: '/images/avi.png',
|
||||
name2: '',
|
||||
id2: 0,
|
||||
img3: '/images/avi.png',
|
||||
name3: '',
|
||||
id3: 0
|
||||
usersToFollow: new Array(3).fill().map(x => (
|
||||
{
|
||||
img: '/images/avi.png',
|
||||
name: '',
|
||||
id: 0
|
||||
}
|
||||
))
|
||||
}),
|
||||
computed: {
|
||||
user: function () {
|
||||
return this.$store.state.users.currentUser.screen_name
|
||||
},
|
||||
moreUrl: function () {
|
||||
var host = window.location.hostname
|
||||
var user = this.user
|
||||
var suggestionsWeb = this.$store.state.instance.suggestionsWeb
|
||||
var url
|
||||
url = suggestionsWeb.replace(/{{host}}/g, encodeURIComponent(host))
|
||||
url = url.replace(/{{user}}/g, encodeURIComponent(user))
|
||||
const host = window.location.hostname
|
||||
const user = this.user
|
||||
const suggestionsWeb = this.$store.state.instance.suggestionsWeb
|
||||
const url = suggestionsWeb.replace(/{{host}}/g, encodeURIComponent(host))
|
||||
.replace(/{{user}}/g, encodeURIComponent(user))
|
||||
return url
|
||||
},
|
||||
suggestionsEnabled () {
|
||||
|
|
@ -96,7 +64,7 @@ const WhoToFollowPanel = {
|
|||
},
|
||||
methods: {
|
||||
userProfileLink (id, name) {
|
||||
return generateProfileLink(id, name)
|
||||
return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames)
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
|
|
|
|||
|
|
@ -7,12 +7,13 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="panel-body who-to-follow">
|
||||
<p>
|
||||
<img v-bind:src="img1"/> <router-link :to="userProfileLink(id1, name1)">{{ name1 }}</router-link><br>
|
||||
<img v-bind:src="img2"/> <router-link :to="userProfileLink(id2, name2)">{{ name2 }}</router-link><br>
|
||||
<img v-bind:src="img3"/> <router-link :to="userProfileLink(id3, name3)">{{ name3 }}</router-link><br>
|
||||
<img v-bind:src="$store.state.instance.logo"> <a v-bind:href="moreUrl" target="_blank">{{$t('who_to_follow.more')}}</a>
|
||||
</p>
|
||||
<span v-for="user in usersToFollow">
|
||||
<img v-bind:src="user.img" />
|
||||
<router-link v-bind:to="userProfileLink(user.id, user.name)">
|
||||
{{user.name}}
|
||||
</router-link><br />
|
||||
</span>
|
||||
<img v-bind:src="$store.state.instance.logo"> <a v-bind:href="moreUrl" target="_blank">{{$t('who_to_follow.more')}}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
@ -28,7 +29,9 @@
|
|||
width: 32px;
|
||||
height: 32px;
|
||||
}
|
||||
.who-to-follow p {
|
||||
.who-to-follow {
|
||||
padding: 0.5em 1em 0.5em 1em;
|
||||
margin: 0px;
|
||||
line-height: 40px;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue