Merge branch 'develop' into feature/mobile-improvements-2
This commit is contained in:
commit
5d55fc53ac
|
@ -169,6 +169,8 @@ const afterStoreSetup = ({ store, i18n }) => {
|
|||
store.dispatch('setInstanceOption', { name: 'chatAvailable', value: features.includes('chat') })
|
||||
store.dispatch('setInstanceOption', { name: 'gopherAvailable', value: features.includes('gopher') })
|
||||
|
||||
store.dispatch('setInstanceOption', { name: 'postFormats', value: metadata.postFormats })
|
||||
|
||||
store.dispatch('setInstanceOption', { name: 'restrictedNicknames', value: metadata.restrictedNicknames })
|
||||
|
||||
const suggestions = metadata.suggestions
|
||||
|
|
|
@ -160,6 +160,7 @@
|
|||
|
||||
.hider {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
white-space: nowrap;
|
||||
margin: 10px;
|
||||
padding: 5px;
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import UserCardContent from '../user_card_content/user_card_content.vue'
|
||||
import UserCard from '../user_card/user_card.vue'
|
||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
|
||||
|
@ -12,7 +12,7 @@ const BasicUserCard = {
|
|||
}
|
||||
},
|
||||
components: {
|
||||
UserCardContent,
|
||||
UserCard,
|
||||
UserAvatar
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -1,18 +1,18 @@
|
|||
<template>
|
||||
<div class="user-card">
|
||||
<div class="basic-user-card">
|
||||
<router-link :to="userProfileLink(user)">
|
||||
<UserAvatar class="avatar" @click.prevent.native="toggleUserExpanded" :src="user.profile_image_url"/>
|
||||
</router-link>
|
||||
<div class="user-card-expanded-content" v-if="userExpanded">
|
||||
<user-card-content :user="user" :switcher="false"></user-card-content>
|
||||
<div class="basic-user-card-expanded-content" v-if="userExpanded">
|
||||
<UserCard :user="user" :rounded="true" :bordered="true"/>
|
||||
</div>
|
||||
<div class="user-card-collapsed-content" v-else>
|
||||
<div :title="user.name" class="user-card-user-name">
|
||||
<div class="basic-user-card-collapsed-content" v-else>
|
||||
<div :title="user.name" class="basic-user-card-user-name">
|
||||
<span v-if="user.name_html" v-html="user.name_html"></span>
|
||||
<span v-else>{{ user.name }}</span>
|
||||
</div>
|
||||
<div>
|
||||
<router-link class="user-card-screen-name" :to="userProfileLink(user)">
|
||||
<router-link class="basic-user-card-screen-name" :to="userProfileLink(user)">
|
||||
@{{user.screen_name}}
|
||||
</router-link>
|
||||
</div>
|
||||
|
@ -26,15 +26,15 @@
|
|||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.user-card {
|
||||
.basic-user-card {
|
||||
display: flex;
|
||||
flex: 1 0;
|
||||
margin: 0;
|
||||
padding-top: 0.6em;
|
||||
padding-right: 1em;
|
||||
padding-bottom: 0.6em;
|
||||
padding-left: 1em;
|
||||
border-bottom: 1px solid;
|
||||
margin: 0;
|
||||
border-bottom-color: $fallback--border;
|
||||
border-bottom-color: var(--border, $fallback--border);
|
||||
|
||||
|
@ -57,23 +57,6 @@
|
|||
&-expanded-content {
|
||||
flex: 1;
|
||||
margin-left: 0.7em;
|
||||
border-radius: $fallback--panelRadius;
|
||||
border-radius: var(--panelRadius, $fallback--panelRadius);
|
||||
border-style: solid;
|
||||
border-color: $fallback--border;
|
||||
border-color: var(--border, $fallback--border);
|
||||
border-width: 1px;
|
||||
overflow: hidden;
|
||||
|
||||
.panel-heading {
|
||||
background: transparent;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import Status from '../status/status.vue'
|
||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||
import UserCardContent from '../user_card_content/user_card_content.vue'
|
||||
import UserCard from '../user_card/user_card.vue'
|
||||
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
|
||||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
|
||||
|
@ -13,7 +13,7 @@ const Notification = {
|
|||
},
|
||||
props: [ 'notification' ],
|
||||
components: {
|
||||
Status, UserAvatar, UserCardContent
|
||||
Status, UserAvatar, UserCard
|
||||
},
|
||||
methods: {
|
||||
toggleUserExpanded () {
|
||||
|
|
|
@ -5,9 +5,7 @@
|
|||
<UserAvatar :compact="true" :betterShadow="betterShadow" :src="notification.action.user.profile_image_url_original"/>
|
||||
</a>
|
||||
<div class='notification-right'>
|
||||
<div class="usercard notification-usercard" v-if="userExpanded">
|
||||
<user-card-content :user="notification.action.user" :switcher="false"></user-card-content>
|
||||
</div>
|
||||
<UserCard :user="notification.action.user" :rounded="true" :bordered="true" v-if="userExpanded"/>
|
||||
<span class="notification-details">
|
||||
<div class="name-and-action">
|
||||
<span class="username" v-if="!!notification.action.user.name_html" :title="'@'+notification.action.user.screen_name" v-html="notification.action.user.name_html"></span>
|
||||
|
|
|
@ -11,7 +11,8 @@ const Notifications = {
|
|||
const store = this.$store
|
||||
const credentials = store.state.users.currentUser.credentials
|
||||
|
||||
notificationsFetcher.startFetching({ store, credentials })
|
||||
const fetcherId = notificationsFetcher.startFetching({ store, credentials })
|
||||
this.$store.commit('setNotificationFetcher', { fetcherId })
|
||||
},
|
||||
data () {
|
||||
return {
|
||||
|
|
|
@ -45,10 +45,6 @@
|
|||
}
|
||||
}
|
||||
|
||||
.notification-usercard {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.non-mention {
|
||||
display: flex;
|
||||
flex: 1;
|
||||
|
|
|
@ -171,6 +171,9 @@ const PostStatusForm = {
|
|||
},
|
||||
formattingOptionsEnabled () {
|
||||
return this.$store.state.instance.formattingOptionsEnabled
|
||||
},
|
||||
postFormats () {
|
||||
return this.$store.state.instance.postFormats || []
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
|
|
|
@ -38,9 +38,9 @@
|
|||
<span 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 value="text/plain">{{$t('post_status.content_type.plain_text')}}</option>
|
||||
<option value="text/html">HTML</option>
|
||||
<option value="text/markdown">Markdown</option>
|
||||
<option v-for="postFormat in postFormats" :key="postFormat" :value="postFormat">
|
||||
{{$t(`post_status.content_type["${postFormat}"]`)}}
|
||||
</option>
|
||||
</select>
|
||||
<i class="icon-down-open"></i>
|
||||
</label>
|
||||
|
|
|
@ -93,6 +93,9 @@ const settings = {
|
|||
currentSaveStateNotice () {
|
||||
return this.$store.state.interface.settings.currentSaveStateNotice
|
||||
},
|
||||
postFormats () {
|
||||
return this.$store.state.instance.postFormats || []
|
||||
},
|
||||
instanceSpecificPanelPresent () { return this.$store.state.instance.showInstanceSpecificPanel }
|
||||
},
|
||||
watch: {
|
||||
|
|
|
@ -105,17 +105,9 @@
|
|||
{{$t('settings.post_status_content_type')}}
|
||||
<label for="postContentType" class="select">
|
||||
<select id="postContentType" v-model="postContentTypeLocal">
|
||||
<option value="text/plain">
|
||||
{{$t('settings.status_content_type_plain')}}
|
||||
{{postContentTypeDefault == 'text/plain' ? $t('settings.instance_default_simple') : ''}}
|
||||
</option>
|
||||
<option value="text/html">
|
||||
HTML
|
||||
{{postContentTypeDefault == 'text/html' ? $t('settings.instance_default_simple') : ''}}
|
||||
</option>
|
||||
<option value="text/markdown">
|
||||
Markdown
|
||||
{{postContentTypeDefault == 'text/markdown' ? $t('settings.instance_default_simple') : ''}}
|
||||
<option v-for="postFormat in postFormats" :key="postFormat" :value="postFormat">
|
||||
{{$t(`post_status.content_type["${postFormat}"]`)}}
|
||||
{{postContentTypeDefault === postFormat ? $t('settings.instance_default_simple') : ''}}
|
||||
</option>
|
||||
</select>
|
||||
<i class="icon-down-open"/>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import UserCardContent from '../user_card_content/user_card_content.vue'
|
||||
import UserCard from '../user_card/user_card.vue'
|
||||
import { unseenNotificationsFromStore } from '../../services/notification_utils/notification_utils'
|
||||
|
||||
// TODO: separate touch gesture stuff into their own utils if more components want them
|
||||
|
@ -12,7 +12,7 @@ const SideDrawer = {
|
|||
closed: true,
|
||||
touchCoord: [0, 0]
|
||||
}),
|
||||
components: { UserCardContent },
|
||||
components: { UserCard },
|
||||
computed: {
|
||||
currentUser () {
|
||||
return this.$store.state.users.currentUser
|
||||
|
|
|
@ -8,7 +8,7 @@
|
|||
@touchmove="touchMove"
|
||||
>
|
||||
<div class="side-drawer-heading" @click="toggleDrawer">
|
||||
<user-card-content :user="currentUser" :switcher="false" :hideBio="true" v-if="currentUser"/>
|
||||
<UserCard :user="currentUser" :hideBio="true" v-if="currentUser"/>
|
||||
<div class="side-drawer-logo-wrapper" v-else>
|
||||
<img :src="logo"/>
|
||||
<span>{{sitename}}</span>
|
||||
|
@ -176,15 +176,6 @@
|
|||
display: flex;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
.profile-panel-background {
|
||||
border-radius: 0;
|
||||
.panel-heading {
|
||||
background: transparent;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.side-drawer ul {
|
||||
|
|
|
@ -3,7 +3,7 @@ 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 PostStatusForm from '../post_status_form/post_status_form.vue'
|
||||
import UserCardContent from '../user_card_content/user_card_content.vue'
|
||||
import UserCard from '../user_card/user_card.vue'
|
||||
import UserAvatar from '../user_avatar/user_avatar.vue'
|
||||
import Gallery from '../gallery/gallery.vue'
|
||||
import LinkPreview from '../link-preview/link-preview.vue'
|
||||
|
@ -259,7 +259,7 @@ const Status = {
|
|||
RetweetButton,
|
||||
DeleteButton,
|
||||
PostStatusForm,
|
||||
UserCardContent,
|
||||
UserCard,
|
||||
UserAvatar,
|
||||
Gallery,
|
||||
LinkPreview
|
||||
|
|
|
@ -31,9 +31,7 @@
|
|||
</router-link>
|
||||
</div>
|
||||
<div class="status-body">
|
||||
<div class="usercard" v-if="userExpanded">
|
||||
<user-card-content :user="status.user" :switcher="false"></user-card-content>
|
||||
</div>
|
||||
<UserCard :user="status.user" :rounded="true" :bordered="true" class="status-usercard" v-if="userExpanded"/>
|
||||
<div v-if="!noHeading" class="media-heading">
|
||||
<div class="heading-name-row">
|
||||
<div class="name-and-account-name">
|
||||
|
@ -248,8 +246,7 @@ $status-margin: 0.75em;
|
|||
padding: 0;
|
||||
}
|
||||
|
||||
.usercard {
|
||||
margin: 0;
|
||||
.status-usercard {
|
||||
margin-bottom: $status-margin;
|
||||
}
|
||||
|
||||
|
|
|
@ -132,7 +132,9 @@ const Timeline = {
|
|||
}
|
||||
if (count > 0) {
|
||||
// only 'stream' them when you're scrolled to the top
|
||||
if (window.pageYOffset < 15 &&
|
||||
const doc = document.documentElement
|
||||
const top = (window.pageYOffset || doc.scrollTop) - (doc.clientTop || 0)
|
||||
if (top < 15 &&
|
||||
!this.paused &&
|
||||
!(this.unfocused && this.$store.state.config.pauseOnUnfocused)
|
||||
) {
|
||||
|
|
|
@ -4,7 +4,7 @@ import { requestFollow, requestUnfollow } from '../../services/follow_manipulate
|
|||
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
|
||||
|
||||
export default {
|
||||
props: [ 'user', 'switcher', 'selected', 'hideBio' ],
|
||||
props: [ 'user', 'switcher', 'selected', 'hideBio', 'rounded', 'bordered' ],
|
||||
data () {
|
||||
return {
|
||||
followRequestInProgress: false,
|
||||
|
@ -16,7 +16,14 @@ export default {
|
|||
}
|
||||
},
|
||||
computed: {
|
||||
headingStyle () {
|
||||
classes () {
|
||||
return [{
|
||||
'user-card-rounded-t': this.rounded === 'top', // set border-top-left-radius and border-top-right-radius
|
||||
'user-card-rounded': this.rounded === true, // set border-radius for all sides
|
||||
'user-card-bordered': this.bordered === true // set border for all sides
|
||||
}]
|
||||
},
|
||||
style () {
|
||||
const color = this.$store.state.config.customTheme.colors
|
||||
? this.$store.state.config.customTheme.colors.bg // v2
|
||||
: this.$store.state.config.colors.bg // v1
|
||||
|
@ -93,22 +100,30 @@ export default {
|
|||
},
|
||||
methods: {
|
||||
followUser () {
|
||||
const store = this.$store
|
||||
this.followRequestInProgress = true
|
||||
requestFollow(this.user, this.$store).then(({sent}) => {
|
||||
requestFollow(this.user, store).then(({sent}) => {
|
||||
this.followRequestInProgress = false
|
||||
this.followRequestSent = sent
|
||||
})
|
||||
},
|
||||
unfollowUser () {
|
||||
const store = this.$store
|
||||
this.followRequestInProgress = true
|
||||
requestUnfollow(this.user, this.$store).then(() => {
|
||||
requestUnfollow(this.user, store).then(() => {
|
||||
this.followRequestInProgress = false
|
||||
store.commit('removeStatus', { timeline: 'friends', userId: this.user.id })
|
||||
})
|
||||
},
|
||||
blockUser () {
|
||||
const store = this.$store
|
||||
store.state.api.backendInteractor.blockUser(this.user.id)
|
||||
.then((blockedUser) => store.commit('addNewUsers', [blockedUser]))
|
||||
.then((blockedUser) => {
|
||||
store.commit('addNewUsers', [blockedUser])
|
||||
store.commit('removeStatus', { timeline: 'friends', userId: this.user.id })
|
||||
store.commit('removeStatus', { timeline: 'public', userId: this.user.id })
|
||||
store.commit('removeStatus', { timeline: 'publicAndExternal', userId: this.user.id })
|
||||
})
|
||||
},
|
||||
unblockUser () {
|
||||
const store = this.$store
|
|
@ -1,6 +1,6 @@
|
|||
<template>
|
||||
<div id="heading" class="profile-panel-background" :style="headingStyle">
|
||||
<div class="panel-heading text-center">
|
||||
<div class="user-card" :class="classes" :style="style">
|
||||
<div class="panel-heading">
|
||||
<div class='user-info'>
|
||||
<div class='container'>
|
||||
<router-link :to="userProfileLink(user)">
|
||||
|
@ -108,7 +108,7 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="panel-body profile-panel-body" v-if="!hideBio">
|
||||
<div class="panel-body" v-if="!hideBio">
|
||||
<div v-if="!hideUserStatsLocal && switcher" class="user-counts">
|
||||
<div class="user-count" v-on:click.prevent="setProfileView('statuses')">
|
||||
<h5>{{ $t('user_card.statuses') }}</h5>
|
||||
|
@ -123,41 +123,64 @@
|
|||
<span>{{user.followers_count}}</span>
|
||||
</div>
|
||||
</div>
|
||||
<p @click.prevent="linkClicked" v-if="!hideBio && user.description_html" class="profile-bio" v-html="user.description_html"></p>
|
||||
<p v-else-if="!hideBio" class="profile-bio">{{ user.description }}</p>
|
||||
<p @click.prevent="linkClicked" v-if="!hideBio && user.description_html" class="user-card-bio" v-html="user.description_html"></p>
|
||||
<p v-else-if="!hideBio" class="user-card-bio">{{ user.description }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script src="./user_card_content.js"></script>
|
||||
<script src="./user_card.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
@import '../../_variables.scss';
|
||||
|
||||
.profile-panel-background {
|
||||
.user-card {
|
||||
background-size: cover;
|
||||
border-radius: $fallback--panelRadius;
|
||||
border-radius: var(--panelRadius, $fallback--panelRadius);
|
||||
overflow: hidden;
|
||||
|
||||
border-bottom-left-radius: 0;
|
||||
border-bottom-right-radius: 0;
|
||||
|
||||
.panel-heading {
|
||||
padding: .5em 0;
|
||||
text-align: center;
|
||||
box-shadow: none;
|
||||
background: transparent;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
|
||||
.profile-panel-body {
|
||||
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), var(--bg, $fallback--bg) 80%);
|
||||
.panel-body {
|
||||
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), var(--bg, $fallback--bg) 80%);
|
||||
}
|
||||
|
||||
.profile-bio {
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
&-bio {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
// Modifiers
|
||||
|
||||
&-rounded-t {
|
||||
border-top-left-radius: $fallback--panelRadius;
|
||||
border-top-left-radius: var(--panelRadius, $fallback--panelRadius);
|
||||
border-top-right-radius: $fallback--panelRadius;
|
||||
border-top-right-radius: var(--panelRadius, $fallback--panelRadius);
|
||||
}
|
||||
|
||||
&-rounded {
|
||||
border-radius: $fallback--panelRadius;
|
||||
border-radius: var(--panelRadius, $fallback--panelRadius);
|
||||
}
|
||||
|
||||
&-bordered {
|
||||
border-width: 1px;
|
||||
border-style: solid;
|
||||
border-color: $fallback--border;
|
||||
border-color: var(--border, $fallback--border);
|
||||
}
|
||||
}
|
||||
|
||||
.user-info {
|
||||
|
@ -393,25 +416,4 @@
|
|||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
|
||||
.usercard {
|
||||
width: fill-available;
|
||||
border-radius: $fallback--panelRadius;
|
||||
border-radius: var(--panelRadius, $fallback--panelRadius);
|
||||
border-style: solid;
|
||||
border-color: $fallback--border;
|
||||
border-color: var(--border, $fallback--border);
|
||||
border-width: 1px;
|
||||
overflow: hidden;
|
||||
|
||||
.panel-heading {
|
||||
background: transparent;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
|
||||
p {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
}
|
||||
</style>
|
|
@ -1,6 +1,6 @@
|
|||
import LoginForm from '../login_form/login_form.vue'
|
||||
import PostStatusForm from '../post_status_form/post_status_form.vue'
|
||||
import UserCardContent from '../user_card_content/user_card_content.vue'
|
||||
import UserCard from '../user_card/user_card.vue'
|
||||
|
||||
const UserPanel = {
|
||||
computed: {
|
||||
|
@ -9,7 +9,7 @@ const UserPanel = {
|
|||
components: {
|
||||
LoginForm,
|
||||
PostStatusForm,
|
||||
UserCardContent
|
||||
UserCard
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
<template>
|
||||
<div class="user-panel">
|
||||
<div v-if='user' class="panel panel-default" style="overflow: visible;">
|
||||
<user-card-content :user="user" :switcher="false" :hideBio="true"></user-card-content>
|
||||
<UserCard :user="user" :hideBio="true" rounded="top"/>
|
||||
<div class="panel-footer">
|
||||
<post-status-form v-if='user'></post-status-form>
|
||||
</div>
|
||||
|
@ -11,13 +11,3 @@
|
|||
</template>
|
||||
|
||||
<script src="./user_panel.js"></script>
|
||||
|
||||
<style lang="scss">
|
||||
.user-panel {
|
||||
.profile-panel-background .panel-heading {
|
||||
background: transparent;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
import { compose } from 'vue-compose'
|
||||
import get from 'lodash/get'
|
||||
import UserCardContent from '../user_card_content/user_card_content.vue'
|
||||
import UserCard from '../user_card/user_card.vue'
|
||||
import FollowCard from '../follow_card/follow_card.vue'
|
||||
import Timeline from '../timeline/timeline.vue'
|
||||
import withLoadMore from '../../hocs/with_load_more/with_load_more'
|
||||
|
@ -147,7 +147,7 @@ const UserProfile = {
|
|||
}
|
||||
},
|
||||
components: {
|
||||
UserCardContent,
|
||||
UserCard,
|
||||
Timeline,
|
||||
FollowerList,
|
||||
FriendList
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
<template>
|
||||
<div>
|
||||
<div v-if="user.id" class="user-profile panel panel-default">
|
||||
<user-card-content
|
||||
:user="user"
|
||||
:switcher="true"
|
||||
:selected="timeline.viewing"
|
||||
/>
|
||||
<UserCard :user="user" :switcher="true" :selected="timeline.viewing" rounded="top"/>
|
||||
<tab-switcher :renderOnlyFocused="true" ref="tabSwitcher">
|
||||
<Timeline
|
||||
:label="$t('user_card.statuses')"
|
||||
|
@ -64,11 +60,6 @@
|
|||
flex: 2;
|
||||
flex-basis: 500px;
|
||||
|
||||
.profile-panel-background .panel-heading {
|
||||
background: transparent;
|
||||
flex-direction: column;
|
||||
align-items: stretch;
|
||||
}
|
||||
.userlist-placeholder {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
|
|
|
@ -71,7 +71,9 @@
|
|||
"account_not_locked_warning_link": "locked",
|
||||
"attachments_sensitive": "Mark attachments as sensitive",
|
||||
"content_type": {
|
||||
"plain_text": "Plain text"
|
||||
"text/plain": "Plain text",
|
||||
"text/html": "HTML",
|
||||
"text/markdown": "Markdown"
|
||||
},
|
||||
"content_warning": "Subject (optional)",
|
||||
"default": "Just landed in L.A.",
|
||||
|
@ -221,7 +223,6 @@
|
|||
"subject_line_mastodon": "Like mastodon: copy as is",
|
||||
"subject_line_noop": "Do not copy",
|
||||
"post_status_content_type": "Post status content type",
|
||||
"status_content_type_plain": "Plain text",
|
||||
"stop_gifs": "Play-on-hover GIFs",
|
||||
"streaming": "Enable automatic streaming of new posts when scrolled to the top",
|
||||
"text": "Text",
|
||||
|
|
|
@ -221,7 +221,6 @@
|
|||
"subject_line_mastodon": "Kiel Mastodon: kopii senŝanĝe",
|
||||
"subject_line_noop": "Ne kopii",
|
||||
"post_status_content_type": "Afiŝi specon de la enhavo de la stato",
|
||||
"status_content_type_plain": "Plata teksto",
|
||||
"stop_gifs": "Movi GIF-bildojn dum musa ŝvebo",
|
||||
"streaming": "Ŝalti memfaran fluigon de novaj afiŝoj ĉe la supro de la paĝo",
|
||||
"text": "Teksto",
|
||||
|
|
|
@ -202,7 +202,6 @@
|
|||
"subject_line_mastodon": "Tipo mastodon: copiar como es",
|
||||
"subject_line_noop": "No copiar",
|
||||
"post_status_content_type": "Formato de publicación",
|
||||
"status_content_type_plain": "Texto plano",
|
||||
"stop_gifs": "Iniciar GIFs al pasar el ratón",
|
||||
"streaming": "Habilite la transmisión automática de nuevas publicaciones cuando se desplaza hacia la parte superior",
|
||||
"text": "Texto",
|
||||
|
|
|
@ -202,7 +202,6 @@
|
|||
"subject_line_mastodon": "マストドンふう: そのままコピー",
|
||||
"subject_line_noop": "コピーしない",
|
||||
"post_status_content_type": "とうこうのコンテントタイプ",
|
||||
"status_content_type_plain": "プレーンテキスト",
|
||||
"stop_gifs": "カーソルをかさねたとき、GIFをうごかす",
|
||||
"streaming": "うえまでスクロールしたとき、じどうてきにストリーミングする",
|
||||
"text": "もじ",
|
||||
|
|
|
@ -221,7 +221,6 @@
|
|||
"subject_line_mastodon": "Coma mastodon : copiar tal coma es",
|
||||
"subject_line_noop": "Copiar pas",
|
||||
"post_status_content_type": "Publicar lo tipe de contengut dels estatuts",
|
||||
"status_content_type_plain": "Tèxte brut",
|
||||
"stop_gifs": "Lançar los GIFs al subrevòl",
|
||||
"streaming": "Activar lo cargament automatic dels novèls estatus en anar amont",
|
||||
"text": "Tèxt",
|
||||
|
|
|
@ -221,7 +221,6 @@
|
|||
"subject_line_mastodon": "Como o Mastodon: copiar como está",
|
||||
"subject_line_noop": "Não copiar",
|
||||
"post_status_content_type": "Postar tipo de conteúdo do status",
|
||||
"status_content_type_plain": "Texto puro",
|
||||
"stop_gifs": "Reproduzir GIFs ao passar o cursor em cima",
|
||||
"streaming": "Habilitar o fluxo automático de postagens quando ao topo da página",
|
||||
"text": "Texto",
|
||||
|
|
|
@ -37,6 +37,7 @@ const defaultState = {
|
|||
emoji: [],
|
||||
customEmoji: [],
|
||||
restrictedNicknames: [],
|
||||
postFormats: [],
|
||||
|
||||
// Feature-set, apparently, not everything here is reported...
|
||||
mediaProxyAvailable: false,
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
import { remove, slice, each, find, maxBy, minBy, merge, last, isArray } from 'lodash'
|
||||
import { remove, slice, each, find, maxBy, minBy, merge, first, last, isArray } from 'lodash'
|
||||
import apiService from '../services/api/api.service.js'
|
||||
// import parse from '../services/status_parser/status_parser.js'
|
||||
|
||||
|
@ -19,7 +19,7 @@ const emptyTl = (userId = 0) => ({
|
|||
flushMarker: 0
|
||||
})
|
||||
|
||||
export const defaultState = {
|
||||
export const defaultState = () => ({
|
||||
allStatuses: [],
|
||||
allStatusesObject: {},
|
||||
maxId: 0,
|
||||
|
@ -30,7 +30,8 @@ export const defaultState = {
|
|||
data: [],
|
||||
idStore: {},
|
||||
loading: false,
|
||||
error: false
|
||||
error: false,
|
||||
fetcherId: null
|
||||
},
|
||||
favorites: new Set(),
|
||||
error: false,
|
||||
|
@ -45,7 +46,7 @@ export const defaultState = {
|
|||
tag: emptyTl(),
|
||||
dms: emptyTl()
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
export const prepareStatus = (status) => {
|
||||
// Set deleted flag
|
||||
|
@ -312,9 +313,20 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot
|
|||
})
|
||||
}
|
||||
|
||||
const removeStatus = (state, { timeline, userId }) => {
|
||||
const timelineObject = state.timelines[timeline]
|
||||
if (userId) {
|
||||
remove(timelineObject.statuses, { user: { id: userId } })
|
||||
remove(timelineObject.visibleStatuses, { user: { id: userId } })
|
||||
timelineObject.minVisibleId = timelineObject.visibleStatuses.length > 0 ? last(timelineObject.visibleStatuses).id : 0
|
||||
timelineObject.maxId = timelineObject.statuses.length > 0 ? first(timelineObject.statuses).id : 0
|
||||
}
|
||||
}
|
||||
|
||||
export const mutations = {
|
||||
addNewStatuses,
|
||||
addNewNotifications,
|
||||
removeStatus,
|
||||
showNewStatuses (state, { timeline }) {
|
||||
const oldTimeline = (state.timelines[timeline])
|
||||
|
||||
|
@ -324,6 +336,15 @@ export const mutations = {
|
|||
oldTimeline.visibleStatusesObject = {}
|
||||
each(oldTimeline.visibleStatuses, (status) => { oldTimeline.visibleStatusesObject[status.id] = status })
|
||||
},
|
||||
setNotificationFetcher (state, { fetcherId }) {
|
||||
state.notifications.fetcherId = fetcherId
|
||||
},
|
||||
resetStatuses (state) {
|
||||
const emptyState = defaultState()
|
||||
Object.entries(emptyState).forEach(([key, value]) => {
|
||||
state[key] = value
|
||||
})
|
||||
},
|
||||
clearTimeline (state, { timeline }) {
|
||||
state.timelines[timeline] = emptyTl(state.timelines[timeline].userId)
|
||||
},
|
||||
|
@ -374,7 +395,7 @@ export const mutations = {
|
|||
}
|
||||
|
||||
const statuses = {
|
||||
state: defaultState,
|
||||
state: defaultState(),
|
||||
actions: {
|
||||
addNewStatuses ({ rootState, commit }, { statuses, showImmediately = false, timeline = false, noIdUpdate = false, userId }) {
|
||||
commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId })
|
||||
|
@ -394,6 +415,12 @@ const statuses = {
|
|||
setNotificationsSilence ({ rootState, commit }, { value }) {
|
||||
commit('setNotificationsSilence', { value })
|
||||
},
|
||||
stopFetchingNotifications ({ rootState, commit }) {
|
||||
if (rootState.statuses.notifications.fetcherId) {
|
||||
window.clearInterval(rootState.statuses.notifications.fetcherId)
|
||||
}
|
||||
commit('setNotificationFetcher', { fetcherId: null })
|
||||
},
|
||||
deleteStatus ({ rootState, commit }, status) {
|
||||
commit('setDeleted', { status })
|
||||
apiService.deleteStatus({ id: status.id, credentials: rootState.users.currentUser.credentials })
|
||||
|
|
|
@ -295,6 +295,8 @@ const users = {
|
|||
store.commit('setToken', false)
|
||||
store.dispatch('stopFetching', 'friends')
|
||||
store.commit('setBackendInteractor', backendInteractorService())
|
||||
store.dispatch('stopFetchingNotifications')
|
||||
store.commit('resetStatuses')
|
||||
},
|
||||
loginUser (store, accessToken) {
|
||||
return new Promise((resolve, reject) => {
|
||||
|
|
|
@ -24,7 +24,7 @@ describe('routes', () => {
|
|||
|
||||
const matchedComponents = router.getMatchedComponents()
|
||||
|
||||
expect(matchedComponents[0].components.hasOwnProperty('UserCardContent')).to.eql(true)
|
||||
expect(matchedComponents[0].components.hasOwnProperty('UserCard')).to.eql(true)
|
||||
})
|
||||
|
||||
it('user\'s profile at /users', () => {
|
||||
|
@ -32,6 +32,6 @@ describe('routes', () => {
|
|||
|
||||
const matchedComponents = router.getMatchedComponents()
|
||||
|
||||
expect(matchedComponents[0].components.hasOwnProperty('UserCardContent')).to.eql(true)
|
||||
expect(matchedComponents[0].components.hasOwnProperty('UserCard')).to.eql(true)
|
||||
})
|
||||
})
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import { cloneDeep } from 'lodash'
|
||||
import { defaultState, mutations, prepareStatus } from '../../../../src/modules/statuses.js'
|
||||
|
||||
// eslint-disable-next-line camelcase
|
||||
|
@ -24,7 +23,7 @@ describe('Statuses.prepareStatus', () => {
|
|||
|
||||
describe('The Statuses module', () => {
|
||||
it('adds the status to allStatuses and to the given timeline', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const status = makeMockStatus({id: '1'})
|
||||
|
||||
mutations.addNewStatuses(state, { statuses: [status], timeline: 'public' })
|
||||
|
@ -36,7 +35,7 @@ describe('The Statuses module', () => {
|
|||
})
|
||||
|
||||
it('counts the status as new if it has not been seen on this timeline', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const status = makeMockStatus({id: '1'})
|
||||
|
||||
mutations.addNewStatuses(state, { statuses: [status], timeline: 'public' })
|
||||
|
@ -54,7 +53,7 @@ describe('The Statuses module', () => {
|
|||
})
|
||||
|
||||
it('add the statuses to allStatuses if no timeline is given', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const status = makeMockStatus({id: '1'})
|
||||
|
||||
mutations.addNewStatuses(state, { statuses: [status] })
|
||||
|
@ -66,7 +65,7 @@ describe('The Statuses module', () => {
|
|||
})
|
||||
|
||||
it('adds the status to allStatuses and to the given timeline, directly visible', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const status = makeMockStatus({id: '1'})
|
||||
|
||||
mutations.addNewStatuses(state, { statuses: [status], showImmediately: true, timeline: 'public' })
|
||||
|
@ -78,7 +77,7 @@ describe('The Statuses module', () => {
|
|||
})
|
||||
|
||||
it('removes statuses by tag on deletion', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const status = makeMockStatus({id: '1'})
|
||||
const otherStatus = makeMockStatus({id: '3'})
|
||||
status.uri = 'xxx'
|
||||
|
@ -96,7 +95,7 @@ describe('The Statuses module', () => {
|
|||
})
|
||||
|
||||
it('does not update the maxId when the noIdUpdate flag is set', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const status = makeMockStatus({id: '1'})
|
||||
const secondStatus = makeMockStatus({id: '2'})
|
||||
|
||||
|
@ -110,7 +109,7 @@ describe('The Statuses module', () => {
|
|||
})
|
||||
|
||||
it('keeps a descending by id order in timeline.visibleStatuses and timeline.statuses', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const nonVisibleStatus = makeMockStatus({id: '1'})
|
||||
const status = makeMockStatus({id: '3'})
|
||||
const statusTwo = makeMockStatus({id: '2'})
|
||||
|
@ -130,7 +129,7 @@ describe('The Statuses module', () => {
|
|||
})
|
||||
|
||||
it('splits retweets from their status and links them', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const status = makeMockStatus({id: '1'})
|
||||
const retweet = makeMockStatus({id: '2', type: 'retweet'})
|
||||
const modStatus = makeMockStatus({id: '1', text: 'something else'})
|
||||
|
@ -155,7 +154,7 @@ describe('The Statuses module', () => {
|
|||
})
|
||||
|
||||
it('replaces existing statuses with the same id', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const status = makeMockStatus({id: '1'})
|
||||
const modStatus = makeMockStatus({id: '1', text: 'something else'})
|
||||
|
||||
|
@ -172,7 +171,7 @@ describe('The Statuses module', () => {
|
|||
})
|
||||
|
||||
it('replaces existing statuses with the same id, coming from a retweet', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const status = makeMockStatus({id: '1'})
|
||||
const modStatus = makeMockStatus({id: '1', text: 'something else'})
|
||||
const retweet = makeMockStatus({id: '2', type: 'retweet'})
|
||||
|
@ -193,7 +192,7 @@ describe('The Statuses module', () => {
|
|||
})
|
||||
|
||||
it('handles favorite actions', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const status = makeMockStatus({id: '1'})
|
||||
|
||||
const favorite = {
|
||||
|
@ -241,7 +240,7 @@ describe('The Statuses module', () => {
|
|||
})
|
||||
|
||||
it('keeps userId when clearing user timeline', () => {
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
state.timelines.user.userId = 123
|
||||
|
||||
mutations.clearTimeline(state, { timeline: 'user' })
|
||||
|
@ -252,7 +251,7 @@ describe('The Statuses module', () => {
|
|||
describe('notifications', () => {
|
||||
it('removes a notification when the notice gets removed', () => {
|
||||
const user = { id: '1' }
|
||||
const state = cloneDeep(defaultState)
|
||||
const state = defaultState()
|
||||
const status = makeMockStatus({id: '1'})
|
||||
const otherStatus = makeMockStatus({id: '3'})
|
||||
const mentionedStatus = makeMockStatus({id: '2'})
|
||||
|
|
Loading…
Reference in New Issue