Merge remote-tracking branch 'upstream/develop' into shigusegubu

* upstream/develop: (59 commits)
  Fix pipelines and clean up console output
  switch from method to computed property
  formatting
  add tags to data and to status component
  Remove auto-hyphenation
  make staff label visible
  move visibility-tray css in local scope
  refactor css
  make only screen name as link
  refactor css for visibility tray
  moved setting styles into common to avoid bug with shared styles
  hide three dot menu button if has no items
  Eliminate automatic zooming on mobile
  entity normalizer: add tooltip text to emojis
  rename for consistency's sake
  update admin api urls in accordance with new docs
  Line up rich text format picker with the status form
  fix lint
  Cleanup, little documentation, localization
  update api service functions
  ...
This commit is contained in:
Henry Jameson 2019-05-22 21:02:58 +03:00
commit 30a89201ca
53 changed files with 549 additions and 267 deletions

View file

@ -41,7 +41,8 @@ const conversation = {
props: [
'statusoid',
'collapsable',
'isPage'
'isPage',
'showPinned'
],
created () {
if (this.isPage) {

View file

@ -14,6 +14,7 @@
:inlineExpanded="collapsable && isExpanded"
:statusoid="status"
:expandable='!isExpanded'
:showPinned="showPinned"
:focused="focused(status.id)"
:inConversation="isExpanded"
:highlight="getHighlight()"

View file

@ -1,21 +0,0 @@
const DeleteButton = {
props: [ 'status' ],
methods: {
deleteStatus () {
const confirmed = window.confirm('Do you really want to delete this status?')
if (confirmed) {
this.$store.dispatch('deleteStatus', { id: this.status.id })
}
}
},
computed: {
currentUser () { return this.$store.state.users.currentUser },
canDelete () {
if (!this.currentUser) { return }
const superuser = this.currentUser.rights.moderator || this.currentUser.rights.admin
return superuser || this.status.user.id === this.currentUser.id
}
}
}
export default DeleteButton

View file

@ -1,21 +0,0 @@
<template>
<div v-if="canDelete">
<a href="#" v-on:click.prevent="deleteStatus()">
<i class='button-icon icon-cancel delete-status'></i>
</a>
</div>
</template>
<script src="./delete_button.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
.icon-cancel,.delete-status {
cursor: pointer;
&:hover {
color: $fallback--cRed;
color: var(--cRed, $fallback--cRed);
}
}
</style>

View file

@ -0,0 +1,64 @@
import Popper from 'vue-popperjs/src/component/popper.js.vue'
const ExtraButtons = {
props: [ 'status' ],
components: {
Popper
},
data () {
return {
showDropDown: false,
showPopper: true
}
},
methods: {
deleteStatus () {
this.refreshPopper()
const confirmed = window.confirm(this.$t('status.delete_confirm'))
if (confirmed) {
this.$store.dispatch('deleteStatus', { id: this.status.id })
}
},
toggleMenu () {
this.showDropDown = !this.showDropDown
},
pinStatus () {
this.refreshPopper()
this.$store.dispatch('pinStatus', this.status.id)
.then(() => this.$emit('onSuccess'))
.catch(err => this.$emit('onError', err.error.error))
},
unpinStatus () {
this.refreshPopper()
this.$store.dispatch('unpinStatus', this.status.id)
.then(() => this.$emit('onSuccess'))
.catch(err => this.$emit('onError', err.error.error))
},
refreshPopper () {
this.showPopper = false
this.showDropDown = false
setTimeout(() => {
this.showPopper = true
})
}
},
computed: {
currentUser () { return this.$store.state.users.currentUser },
canDelete () {
if (!this.currentUser) { return }
const superuser = this.currentUser.rights.moderator || this.currentUser.rights.admin
return superuser || this.status.user.id === this.currentUser.id
},
ownStatus () {
return this.status.user.id === this.currentUser.id
},
canPin () {
return this.ownStatus && (this.status.visibility === 'public' || this.status.visibility === 'unlisted')
},
enabled () {
return this.canPin || this.canDelete
}
}
}
export default ExtraButtons

View file

@ -0,0 +1,47 @@
<template>
<Popper
trigger="click"
@hide='showDropDown = false'
append-to-body
v-if="enabled && showPopper"
:options="{
placement: 'top',
modifiers: {
arrow: { enabled: true },
offset: { offset: '0, 5px' },
}
}"
>
<div class="popper-wrapper">
<div class="dropdown-menu">
<button class="dropdown-item dropdown-item-icon" @click.prevent="pinStatus" v-if="!status.pinned && canPin">
<i class="icon-pin"></i><span>{{$t("status.pin")}}</span>
</button>
<button class="dropdown-item dropdown-item-icon" @click.prevent="unpinStatus" v-if="status.pinned && canPin">
<i class="icon-pin"></i><span>{{$t("status.unpin")}}</span>
</button>
<button class="dropdown-item dropdown-item-icon" @click.prevent="deleteStatus" v-if="canDelete">
<i class="icon-cancel"></i><span>{{$t("status.delete")}}</span>
</button>
</div>
</div>
<div class="button-icon" slot="reference" @click="toggleMenu">
<i class='icon-ellipsis' :class="{'icon-clicked': showDropDown}"></i>
</div>
</Popper>
</template>
<script src="./extra_buttons.js" ></script>
<style lang="scss">
@import '../../_variables.scss';
.icon-ellipsis {
cursor: pointer;
&:hover, &.icon-clicked {
color: $fallback--text;
color: var(--text, $fallback--text);
}
}
</style>

View file

@ -0,0 +1,25 @@
import Notifications from '../notifications/notifications.vue'
const tabModeDict = {
mentions: ['mention'],
'likes+repeats': ['repeat', 'like'],
follows: ['follow']
}
const Interactions = {
data () {
return {
filterMode: tabModeDict['mentions']
}
},
methods: {
onModeSwitch (index, dataset) {
this.filterMode = tabModeDict[dataset.filter]
}
},
components: {
Notifications
}
}
export default Interactions

View file

@ -0,0 +1,25 @@
<template>
<div class="panel panel-default">
<div class="panel-heading">
<div class="title">
Interactions
</div>
</div>
<tab-switcher
ref="tabSwitcher"
:onSwitch="onModeSwitch"
>
<span data-tab-dummy data-filter="mentions" :label="$t('nav.mentions')"/>
<span data-tab-dummy data-filter="likes+repeats" :label="$t('interactions.favs_repeats')"/>
<span data-tab-dummy data-filter="follows" :label="$t('interactions.follows')"/>
</tab-switcher>
<Notifications
ref="notifications"
:noHeading="true"
:minimalMode="true"
:filterMode="filterMode"
/>
</div>
</template>
<script src="./interactions.js"></script>

View file

@ -1,5 +1,5 @@
<template>
<Timeline :title="$t('nav.mentions')" v-bind:timeline="timeline" v-bind:timeline-name="'mentions'"/>
<Timeline :title="$t('nav.interactions')" v-bind:timeline="timeline" v-bind:timeline-name="'mentions'"/>
</template>
<script src="./mentions.js"></script>

View file

@ -127,6 +127,14 @@
width: 100%;
height: 100%;
&-icon {
padding-left: 0.5rem;
i {
margin-right: 0.25rem;
}
}
&:hover {
// TODO: improve the look on breeze themes
background-color: $fallback--fg;

View file

@ -8,8 +8,8 @@
</router-link>
</li>
<li v-if='currentUser'>
<router-link :to="{ name: 'mentions', params: { username: currentUser.screen_name } }">
{{ $t("nav.mentions") }}
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
{{ $t("nav.interactions") }}
</router-link>
</li>
<li v-if='currentUser'>

View file

@ -7,15 +7,24 @@ import {
} from '../../services/notification_utils/notification_utils.js'
const Notifications = {
props: [
'noHeading'
],
props: {
// Disables display of panel header
noHeading: Boolean,
// Disables panel styles, unread mark, potentially other notification-related actions
// meant for "Interactions" timeline
minimalMode: Boolean,
// Custom filter mode, an array of strings, possible values 'mention', 'repeat', 'like', 'follow', used to override global filter for use in "Interactions" timeline
filterMode: Array
},
data () {
return {
bottomedOut: false
}
},
computed: {
mainClass () {
return this.minimalMode ? '' : 'panel panel-default'
},
notifications () {
return notificationsFromStore(this.$store)
},
@ -26,7 +35,8 @@ const Notifications = {
return unseenNotificationsFromStore(this.$store)
},
visibleNotifications () {
return visibleNotificationsFromStore(this.$store)
console.log(this.filterMode)
return visibleNotificationsFromStore(this.$store, this.filterMode)
},
unseenCount () {
return this.unseenNotifications.length

View file

@ -1,8 +1,10 @@
@import '../../_variables.scss';
.notifications {
// a bit of a hack to allow scrolling below notifications
padding-bottom: 15em;
&:not(.minimal) {
// a bit of a hack to allow scrolling below notifications
padding-bottom: 15em;
}
.loadmore-error {
color: $fallback--text;

View file

@ -1,6 +1,6 @@
<template>
<div class="notifications">
<div class="panel panel-default">
<div :class="{ minimal: minimalMode }" class="notifications">
<div :class="mainClass">
<div v-if="!noHeading" class="panel-heading">
<div class="title">
{{$t('notifications.notifications')}}
@ -12,7 +12,7 @@
<button v-if="unseenCount" @click.prevent="markAsSeen" class="read-button">{{$t('notifications.read')}}</button>
</div>
<div class="panel-body">
<div v-for="notification in visibleNotifications" :key="notification.id" class="notification" :class='{"unseen": !notification.seen}'>
<div v-for="notification in visibleNotifications" :key="notification.id" class="notification" :class='{"unseen": !minimalMode && !notification.seen}'>
<div class="notification-overlay"></div>
<notification :notification="notification"></notification>
</div>
@ -22,7 +22,9 @@
{{$t('notifications.no_more_notifications')}}
</div>
<a v-else-if="!loading" href="#" v-on:click.prevent="fetchOlderNotifications()">
<div class="new-status-notification text-center panel-footer">{{$t('notifications.load_older')}}</div>
<div class="new-status-notification text-center panel-footer">
{{ minimalMode ? $t('interactions.load_older') : $t('notifications.load_older')}}
</div>
</a>
<div v-else class="new-status-notification text-center panel-footer">
<i class="icon-spin3 animate-spin"/>

View file

@ -58,7 +58,7 @@
>
</textarea>
<div class="visibility-tray">
<span class="text-format" v-if="formattingOptionsEnabled">
<div class="text-format" v-if="formattingOptionsEnabled">
<label for="post-content-type" class="select">
<select id="post-content-type" v-model="newStatus.contentType" class="form-control">
<option v-for="postFormat in postFormats" :key="postFormat" :value="postFormat">
@ -67,7 +67,7 @@
</select>
<i class="icon-down-open"></i>
</label>
</span>
</div>
<scope-selector
:showAll="showAllScopes"
@ -152,6 +152,7 @@
display: flex;
justify-content: space-between;
flex-direction: row-reverse;
padding-top: 5px;
}
}
@ -250,7 +251,7 @@
.form-group {
display: flex;
flex-direction: column;
padding: 0.3em 0.5em 0.6em;
padding: 0.25em 0.5em 0.5em;
line-height:24px;
}

View file

@ -1,5 +1,5 @@
<template>
<div v-if="!showNothing">
<div v-if="!showNothing" class="scope-selector">
<i class="icon-mail-alt"
:class="css.direct"
:title="$t('post_status.scope.direct')"
@ -28,3 +28,19 @@
</template>
<script src="./scope_selector.js"></script>
<style lang="scss">
@import '../../_variables.scss';
.scope-selector {
i {
font-size: 1.2em;
cursor: pointer;
&.selected {
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
}
}
}
</style>

View file

@ -303,71 +303,3 @@
<script src="./settings.js">
</script>
<style lang="scss">
@import '../../_variables.scss';
.setting-item {
border-bottom: 2px solid var(--fg, $fallback--fg);
margin: 1em 1em 1.4em;
padding-bottom: 1.4em;
> div {
margin-bottom: .5em;
&:last-child {
margin-bottom: 0;
}
}
&:last-child {
border-bottom: none;
padding-bottom: 0;
margin-bottom: 1em;
}
select {
min-width: 10em;
}
textarea {
width: 100%;
max-width: 100%;
height: 100px;
}
.unavailable,
.unavailable i {
color: var(--cRed, $fallback--cRed);
color: $fallback--cRed;
}
.btn {
min-height: 28px;
min-width: 10em;
padding: 0 2em;
}
.number-input {
max-width: 6em;
}
}
.select-multiple {
display: flex;
.option-list {
margin: 0;
padding-left: .5em;
}
}
.setting-list,
.option-list{
list-style-type: none;
padding-left: 2em;
li {
margin-bottom: 0.5em;
}
.suboptions {
margin-top: 0.3em
}
}
</style>

View file

@ -26,6 +26,11 @@
{{ $t("nav.dms") }}
</router-link>
</li>
<li v-if="currentUser" @click="toggleDrawer">
<router-link :to="{ name: 'interactions', params: { username: currentUser.screen_name } }">
{{ $t("nav.interactions") }}
</router-link>
</li>
</ul>
<ul>
<li v-if="currentUser" @click="toggleDrawer">

View file

@ -1,7 +1,7 @@
import Attachment from '../attachment/attachment.vue'
import FavoriteButton from '../favorite_button/favorite_button.vue'
import RetweetButton from '../retweet_button/retweet_button.vue'
import DeleteButton from '../delete_button/delete_button.vue'
import ExtraButtons from '../extra_buttons/extra_buttons.vue'
import PostStatusForm from '../post_status_form/post_status_form.vue'
import UserCard from '../user_card/user_card.vue'
import UserAvatar from '../user_avatar/user_avatar.vue'
@ -26,7 +26,8 @@ const Status = {
'replies',
'isPreview',
'noHeading',
'inlineExpanded'
'inlineExpanded',
'showPinned'
],
data () {
return {
@ -37,6 +38,7 @@ const Status = {
showPreview: false,
showingTall: this.inConversation && this.focused,
showingLongSubject: false,
error: null,
expandingSubject: typeof this.$store.state.config.collapseMessageWithSubject === 'undefined'
? !this.$store.state.instance.collapseMessageWithSubject
: !this.$store.state.config.collapseMessageWithSubject,
@ -269,13 +271,19 @@ const Status = {
this.statusFromGlobalRepository.rebloggedBy
)
return uniqBy(combinedUsers, 'id')
},
ownStatus () {
return this.status.user.id === this.$store.state.users.currentUser.id
},
tags () {
return this.status.tags.filter(tagObj => tagObj.hasOwnProperty('name')).map(tagObj => tagObj.name).join(' ')
}
},
components: {
Attachment,
FavoriteButton,
RetweetButton,
DeleteButton,
ExtraButtons,
PostStatusForm,
UserCard,
UserAvatar,
@ -296,6 +304,12 @@ const Status = {
return 'icon-globe'
}
},
showError (error) {
this.error = error
},
clearError () {
this.error = undefined
},
linkClicked (event) {
let { target } = event
if (target.tagName === 'SPAN') {

View file

@ -1,5 +1,9 @@
<template>
<div class="status-el" v-if="!hideStatus" :class="[{ 'status-el_focused': isFocused }, { 'status-conversation': inlineExpanded }]">
<div v-if="error" class="alert error">
{{error}}
<i class="button-icon icon-cancel" @click="clearError"></i>
</div>
<template v-if="muted && !isPreview">
<div class="media status container muted">
<small>
@ -12,6 +16,10 @@
</div>
</template>
<template v-else>
<div v-if="showPinned && statusoid.pinned" class="status-pin">
<i class="fa icon-pin faint"></i>
<span class="faint">{{$t('status.pinned')}}</span>
</div>
<div v-if="retweet && !noHeading && !inConversation" :class="[repeaterClass, { highlighted: repeaterStyle }]" :style="[repeaterStyle]" class="media container retweet-info">
<UserAvatar class="media-left" v-if="retweet" :betterShadow="betterShadow" :user="statusoid.user"/>
<div class="media-body faint">
@ -24,7 +32,7 @@
</div>
</div>
<div :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet && !inConversation }]" :style="[ userStyle ]" class="media status">
<div :class="[userClass, { highlighted: userStyle, 'is-retweet': retweet && !inConversation }]" :style="[ userStyle ]" class="media status" :data-tags="tags">
<div v-if="!noHeading" class="media-left">
<router-link :to="userProfileLink" @click.stop.prevent.capture.native="toggleUserExpanded">
<UserAvatar :compact="compact" :betterShadow="betterShadow" :user="status.user"/>
@ -95,7 +103,7 @@
v-if="preview"
:isPreview="true"
:statusoid="preview"
:compact=true
:compact="true"
/>
<div v-else class="status-preview status-preview-loading">
<i class="icon-spin4 animate-spin"></i>
@ -157,18 +165,18 @@
</transition>
<div v-if="!noHeading && !isPreview" class='status-actions media-body'>
<div v-if="loggedIn">
<i class="button-icon icon-reply" v-on:click.prevent="toggleReplying" :title="$t('tool_tip.reply')" :class="{'icon-reply-active': replying}"></i>
<div>
<i class="button-icon icon-reply" v-on:click.prevent="toggleReplying" :title="$t('tool_tip.reply')" :class="{'button-icon-active': replying}" v-if="loggedIn"/>
<i class="button-icon button-icon-disabled icon-reply" :title="$t('tool_tip.reply')" v-else />
<span v-if="status.replies_count > 0">{{status.replies_count}}</span>
</div>
<retweet-button :visibility='status.visibility' :loggedIn='loggedIn' :status='status'></retweet-button>
<favorite-button :loggedIn='loggedIn' :status='status'></favorite-button>
<delete-button :status='status'></delete-button>
<extra-buttons :status="status" @onError="showError" @onSuccess="clearError"></extra-buttons>
</div>
</div>
</div>
<div class="container" v-if="replying">
<div class="reply-left"/>
<post-status-form class="reply-body" :reply-to="status.id" :attentions="status.attentions" :repliedUser="status.user" :copy-message-scope="status.visibility" :subject="replySubject" v-on:posted="toggleReplying"/>
</div>
</template>
@ -198,6 +206,13 @@ $status-margin: 0.75em;
max-width: 100%;
}
.status-pin {
padding: $status-margin $status-margin 0;
display: flex;
align-items: center;
justify-content: flex-end;
}
.status-preview {
position: absolute;
max-width: 95%;
@ -241,7 +256,6 @@ $status-margin: 0.75em;
}
.status-el {
hyphens: auto;
overflow-wrap: break-word;
word-wrap: break-word;
word-break: break-word;
@ -570,15 +584,13 @@ $status-margin: 0.75em;
}
}
.icon-reply:hover {
color: $fallback--cBlue;
color: var(--cBlue, $fallback--cBlue);
cursor: pointer;
}
.icon-reply.icon-reply-active {
color: $fallback--cBlue;
color: var(--cBlue, $fallback--cBlue);
.button-icon.icon-reply {
&:not(.button-icon-disabled):hover,
&.button-icon-active {
color: $fallback--cBlue;
color: var(--cBlue, $fallback--cBlue);
cursor: pointer;
}
}
.status:hover .animated.avatar {
@ -618,11 +630,6 @@ a.unmute {
margin-left: auto;
}
.reply-left {
flex: 0;
min-width: 48px;
}
.reply-body {
flex: 1;
}

View file

@ -4,15 +4,18 @@ import './tab_switcher.scss'
export default Vue.component('tab-switcher', {
name: 'TabSwitcher',
props: ['renderOnlyFocused'],
props: ['renderOnlyFocused', 'onSwitch'],
data () {
return {
active: this.$slots.default.findIndex(_ => _.tag)
}
},
methods: {
activateTab (index) {
activateTab (index, dataset) {
return () => {
if (typeof this.onSwitch === 'function') {
this.onSwitch.call(null, index, this.$slots.default[index].elm.dataset)
}
this.active = index
}
}
@ -37,7 +40,11 @@ export default Vue.component('tab-switcher', {
return (
<div class={ classesWrapper.join(' ')}>
<button disabled={slot.data.attrs.disabled} onClick={this.activateTab(index)} class={ classesTab.join(' ') }>{slot.data.attrs.label}</button>
<button
disabled={slot.data.attrs.disabled}
onClick={this.activateTab(index)}
class={classesTab.join(' ')}>
{slot.data.attrs.label}</button>
</div>
)
})

View file

@ -6,7 +6,7 @@
<router-link :to="userProfileLink(user)">
<UserAvatar :betterShadow="betterShadow" :user="user"/>
</router-link>
<div class="name-and-screen-name">
<div class="user-summary">
<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>
@ -18,12 +18,12 @@
</a>
</div>
<router-link class='user-screen-name' :to="userProfileLink(user)">
<span class="handle">@{{user.screen_name}}
<span class="alert staff" v-if="!hideBio && !!visibleRole">{{visibleRole}}</span>
</span><span v-if="user.locked"><i class="icon icon-lock"></i></span>
<div class="bottom-line">
<router-link class="user-screen-name" :to="userProfileLink(user)">@{{user.screen_name}}</router-link>
<span class="alert staff" v-if="!hideBio && !!visibleRole">{{visibleRole}}</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>
</div>
<div class="user-meta">
@ -232,7 +232,7 @@
opacity: .8;
}
.name-and-screen-name {
.user-summary {
display: block;
margin-left: 0.6em;
text-align: left;
@ -249,6 +249,7 @@
vertical-align: middle;
object-fit: contain
}
.top-line {
display: flex;
}
@ -269,15 +270,19 @@
}
}
.user-screen-name {
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
display: inline-block;
.bottom-line {
display: flex;
font-weight: light;
font-size: 15px;
padding-right: 0.1em;
width: 100%;
display: flex;
.user-screen-name {
min-width: 1px;
flex: 0 1 auto;
text-overflow: ellipsis;
overflow: hidden;
color: $fallback--lightText;
color: var(--lightText, $fallback--lightText);
}
.dailyAvg {
min-width: 1px;
@ -288,15 +293,9 @@
color: var(--text, $fallback--text);
}
.handle {
min-width: 1px;
flex: 0 1 auto;
text-overflow: ellipsis;
overflow: hidden;
}
// TODO use proper colors
.staff {
flex: none;
text-transform: capitalize;
color: $fallback--text;
color: var(--btnText, $fallback--text);

View file

@ -2,6 +2,7 @@ import get from 'lodash/get'
import UserCard from '../user_card/user_card.vue'
import FollowCard from '../follow_card/follow_card.vue'
import Timeline from '../timeline/timeline.vue'
import Conversation from '../conversation/conversation.vue'
import ModerationTools from '../moderation_tools/moderation_tools.vue'
import List from '../list/list.vue'
import withLoadMore from '../../hocs/with_load_more/with_load_more'
@ -95,6 +96,8 @@ const UserProfile = {
if (this.isUs) {
this.$store.dispatch('startFetchingTimeline', { timeline: 'favorites', userId })
}
// Fetch all pinned statuses immediately
this.$store.dispatch('fetchPinnedStatuses', userId)
},
cleanUp () {
this.$store.dispatch('stopFetching', 'user')
@ -128,7 +131,8 @@ const UserProfile = {
FollowerList,
FriendList,
ModerationTools,
FollowCard
FollowCard,
Conversation
}
}

View file

@ -3,16 +3,28 @@
<div v-if="user" class="user-profile panel panel-default">
<UserCard :user="user" :switcher="true" :selected="timeline.viewing" rounded="top"/>
<tab-switcher :renderOnlyFocused="true" ref="tabSwitcher">
<Timeline
:label="$t('user_card.statuses')"
:disabled="!user.statuses_count"
:count="user.statuses_count"
:embedded="true"
:title="$t('user_profile.timeline_title')"
:timeline="timeline"
:timeline-name="'user'"
:user-id="userId"
/>
<div :label="$t('user_card.statuses')" :disabled="!user.statuses_count">
<div class="timeline">
<template v-for="statusId in user.pinnedStatuseIds">
<Conversation
v-if="timeline.statusesObject[statusId]"
class="status-fadein"
:key="statusId"
:statusoid="timeline.statusesObject[statusId]"
:collapsable="true"
:showPinned="true"
/>
</template>
</div>
<Timeline
:count="user.statuses_count"
:embedded="true"
:title="$t('user_profile.timeline_title')"
:timeline="timeline"
:timeline-name="'user'"
:user-id="userId"
/>
</div>
<div :label="$t('user_card.followees')" v-if="followsTabVisible" :disabled="!user.friends_count">
<FriendList :userId="userId">
<template slot="item" slot-scope="{item}">

View file

@ -251,6 +251,10 @@
margin: 0;
}
.visibility-tray {
padding-top: 5px;
}
input[type=file] {
padding: 5px;
height: auto;