aboutsummaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/conversation/conversation.js19
-rw-r--r--src/components/follow_list/follow_list.js3
-rw-r--r--src/components/follow_list/follow_list.vue2
-rw-r--r--src/components/settings/settings.js3
-rw-r--r--src/components/settings/settings.vue2
-rw-r--r--src/components/status/status.js25
-rw-r--r--src/components/status/status.vue6
-rw-r--r--src/components/user_card/user_card.js29
-rw-r--r--src/components/user_card/user_card.vue117
-rw-r--r--src/components/user_card_content/user_card_content.js67
-rw-r--r--src/components/user_card_content/user_card_content.vue2
-rw-r--r--src/components/user_profile/user_profile.js2
-rw-r--r--src/components/user_settings/user_settings.vue6
13 files changed, 167 insertions, 116 deletions
diff --git a/src/components/conversation/conversation.js b/src/components/conversation/conversation.js
index c18781de..48b8aaaa 100644
--- a/src/components/conversation/conversation.js
+++ b/src/components/conversation/conversation.js
@@ -9,9 +9,9 @@ const sortById = (a, b) => {
if (isSeqA && isSeqB) {
return seqA < seqB ? -1 : 1
} else if (isSeqA && !isSeqB) {
- return 1
- } else if (!isSeqA && isSeqB) {
return -1
+ } else if (!isSeqA && isSeqB) {
+ return 1
} else {
return a.id < b.id ? -1 : 1
}
@@ -36,6 +36,13 @@ const conversation = {
status () {
return this.statusoid
},
+ statusId () {
+ if (this.statusoid.retweeted_status) {
+ return this.statusoid.retweeted_status.id
+ } else {
+ return this.statusoid.id
+ }
+ },
conversation () {
if (!this.status) {
return []
@@ -79,7 +86,7 @@ const conversation = {
const conversationId = this.status.statusnet_conversation_id
this.$store.state.api.backendInteractor.fetchConversation({id: conversationId})
.then((statuses) => this.$store.dispatch('addNewStatuses', { statuses }))
- .then(() => this.setHighlight(this.statusoid.id))
+ .then(() => this.setHighlight(this.statusId))
} else {
const id = this.$route.params.id
this.$store.state.api.backendInteractor.fetchStatus({id})
@@ -91,11 +98,7 @@ const conversation = {
return this.replies[id] || []
},
focused (id) {
- if (this.statusoid.retweeted_status) {
- return (id === this.statusoid.retweeted_status.id)
- } else {
- return (id === this.statusoid.id)
- }
+ return id === this.statusId
},
setHighlight (id) {
this.highlight = id
diff --git a/src/components/follow_list/follow_list.js b/src/components/follow_list/follow_list.js
index 6d00eb94..51327e2f 100644
--- a/src/components/follow_list/follow_list.js
+++ b/src/components/follow_list/follow_list.js
@@ -25,6 +25,9 @@ const FollowList = {
},
entries () {
return this.showFollowers ? this.user.followers : this.user.friends
+ },
+ showFollowsYou () {
+ return !this.showFollowers || (this.showFollowers && this.userId !== this.$store.state.users.currentUser.id)
}
},
methods: {
diff --git a/src/components/follow_list/follow_list.vue b/src/components/follow_list/follow_list.vue
index 24ab97d8..27102edf 100644
--- a/src/components/follow_list/follow_list.vue
+++ b/src/components/follow_list/follow_list.vue
@@ -3,7 +3,7 @@
<user-card
v-for="entry in entries"
:key="entry.id" :user="entry"
- :showFollows="true"
+ :noFollowsYou="!showFollowsYou"
/>
<div class="text-center panel-footer">
<a v-if="error" @click="fetchEntries" class="alert error">
diff --git a/src/components/settings/settings.js b/src/components/settings/settings.js
index 534a9839..23c1acdb 100644
--- a/src/components/settings/settings.js
+++ b/src/components/settings/settings.js
@@ -91,7 +91,8 @@ const settings = {
},
currentSaveStateNotice () {
return this.$store.state.interface.settings.currentSaveStateNotice
- }
+ },
+ instanceSpecificPanelPresent () { return this.$store.state.instance.showInstanceSpecificPanel }
},
watch: {
hideAttachmentsLocal (value) {
diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue
index dfb2e49d..e5f8fefb 100644
--- a/src/components/settings/settings.vue
+++ b/src/components/settings/settings.vue
@@ -27,7 +27,7 @@
<li>
<interface-language-switcher />
</li>
- <li>
+ <li v-if="instanceSpecificPanelPresent">
<input type="checkbox" id="hideISP" v-model="hideISPLocal">
<label for="hideISP">{{$t('settings.hide_isp')}}</label>
</li>
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 8181b0db..0273a5be 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -10,8 +10,8 @@ import LinkPreview from '../link-preview/link-preview.vue'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import fileType from 'src/services/file_type/file_type.service'
import { highlightClass, highlightStyle } from '../../services/user_highlighter/user_highlighter.js'
-import { mentionMatchesUrl } from 'src/services/mention_matcher/mention_matcher.js'
-import { filter, find } from 'lodash'
+import { mentionMatchesUrl, extractTagFromUrl } from 'src/services/matcher/matcher.service.js'
+import { filter, find, unescape } from 'lodash'
const Status = {
name: 'Status',
@@ -209,14 +209,15 @@ const Status = {
},
replySubject () {
if (!this.status.summary) return ''
+ const decodedSummary = unescape(this.status.summary)
const behavior = typeof this.$store.state.config.subjectLineBehavior === 'undefined'
? this.$store.state.instance.subjectLineBehavior
: this.$store.state.config.subjectLineBehavior
- const startsWithRe = this.status.summary.match(/^re[: ]/i)
+ const startsWithRe = decodedSummary.match(/^re[: ]/i)
if (behavior !== 'noop' && startsWithRe || behavior === 'masto') {
- return this.status.summary
+ return decodedSummary
} else if (behavior === 'email') {
- return 're: '.concat(this.status.summary)
+ return 're: '.concat(decodedSummary)
} else if (behavior === 'noop') {
return ''
}
@@ -281,7 +282,7 @@ const Status = {
}
if (target.tagName === 'A') {
if (target.className.match(/mention/)) {
- const href = target.getAttribute('href')
+ const href = target.href
const attn = this.status.attentions.find(attn => mentionMatchesUrl(attn, href))
if (attn) {
event.stopPropagation()
@@ -291,6 +292,15 @@ const Status = {
return
}
}
+ if (target.className.match(/hashtag/)) {
+ // Extract tag name from link url
+ const tag = extractTagFromUrl(target.href)
+ if (tag) {
+ const link = this.generateTagLink(tag)
+ this.$router.push(link)
+ return
+ }
+ }
window.open(target.href, '_blank')
}
},
@@ -347,6 +357,9 @@ const Status = {
generateUserProfileLink (id, name) {
return generateProfileLink(id, name, this.$store.state.instance.restrictedNicknames)
},
+ generateTagLink (tag) {
+ return `/tag/${tag}`
+ },
setMedia () {
const attachments = this.attachmentSize === 'hide' ? this.status.attachments : this.galleryAttachments
return () => this.$store.dispatch('setMedia', attachments)
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 5bc7c664..3fc5b486 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -56,7 +56,7 @@
</div>
<h4 class="replies" v-if="inConversation && !noReplyLinks">
<small v-if="replies.length">Replies:</small>
- <small class="reply-link" v-for="reply in replies">
+ <small class="reply-link" v-bind:key="reply.id" v-for="reply in replies">
<a href="#" @click.prevent="gotoOriginal(reply.id)" @mouseenter="replyEnter(reply.id, $event)" @mouseout="replyLeave()">{{reply.name}}&nbsp;</a>
</small>
</h4>
@@ -438,6 +438,8 @@
.user-name {
font-weight: bold;
+ overflow: hidden;
+ text-overflow: ellipsis;
img {
width: 14px;
@@ -552,7 +554,7 @@ a.unmute {
.timeline > {
.status-el:last-child {
- border-bottom-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;;
+ border-radius: 0 0 $fallback--panelRadius $fallback--panelRadius;
border-radius: 0 0 var(--panelRadius, $fallback--panelRadius) var(--panelRadius, $fallback--panelRadius);
border-bottom: none;
}
diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js
index ecc36a4d..28e22f09 100644
--- a/src/components/user_card/user_card.js
+++ b/src/components/user_card/user_card.js
@@ -1,16 +1,20 @@
import UserCardContent from '../user_card_content/user_card_content.vue'
import UserAvatar from '../user_avatar/user_avatar.vue'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
+import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate'
const UserCard = {
props: [
'user',
- 'showFollows',
+ 'noFollowsYou',
'showApproval'
],
data () {
return {
- userExpanded: false
+ userExpanded: false,
+ followRequestInProgress: false,
+ followRequestSent: false,
+ updated: false
}
},
components: {
@@ -18,7 +22,11 @@ const UserCard = {
UserAvatar
},
computed: {
- currentUser () { return this.$store.state.users.currentUser }
+ currentUser () { return this.$store.state.users.currentUser },
+ following () { return this.updated ? this.updated.following : this.user.following },
+ showFollow () {
+ return !this.showApproval && (!this.following || this.updated && !this.updated.following)
+ }
},
methods: {
toggleUserExpanded () {
@@ -34,6 +42,21 @@ const UserCard = {
},
userProfileLink (user) {
return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames)
+ },
+ followUser () {
+ this.followRequestInProgress = true
+ requestFollow(this.user, this.$store).then(({ sent, updated }) => {
+ this.followRequestInProgress = false
+ this.followRequestSent = sent
+ this.updated = updated
+ })
+ },
+ unfollowUser () {
+ this.followRequestInProgress = true
+ requestUnfollow(this.user, this.$store).then(({ updated }) => {
+ this.followRequestInProgress = false
+ this.updated = updated
+ })
}
}
}
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 7129430b..ce4edb3c 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -1,32 +1,57 @@
<template>
<div class="card">
<router-link :to="userProfileLink(user)">
- <UserAvatar class="avatar" :compact="true" @click.prevent.native="toggleUserExpanded" :src="user.profile_image_url"/>
+ <UserAvatar class="avatar" @click.prevent.native="toggleUserExpanded" :src="user.profile_image_url"/>
</router-link>
- <div class="usercard" v-if="userExpanded">
- <user-card-content :user="user" :switcher="false"></user-card-content>
- </div>
- <div class="name-and-screen-name" v-else>
- <div :title="user.name" v-if="user.name_html" class="user-name">
- <span v-html="user.name_html"></span>
- <span class="follows-you" v-if="!userExpanded && showFollows && user.follows_you">
- {{ currentUser.id == user.id ? $t('user_card.its_you') : $t('user_card.follows_you') }}
- </span>
+ <div class="user-card-main-content">
+ <div class="usercard" v-if="userExpanded">
+ <user-card-content :user="user" :switcher="false"></user-card-content>
</div>
- <div :title="user.name" v-else class="user-name">
- {{ user.name }}
- <span class="follows-you" v-if="!userExpanded && showFollows && user.follows_you">
+ <div class="name-and-screen-name" v-if="!userExpanded">
+ <div :title="user.name" class="user-name">
+ <span v-if="user.name_html" v-html="user.name_html"></span>
+ <span v-else>{{ user.name }}</span>
+ </div>
+ <div class="user-link-action">
+ <router-link class='user-screen-name' :to="userProfileLink(user)">
+ @{{user.screen_name}}
+ </router-link>
+ </div>
+ </div>
+ <div class="follow-box" v-if="!userExpanded">
+ <span class="faint" v-if="!noFollowsYou && user.follows_you">
{{ currentUser.id == user.id ? $t('user_card.its_you') : $t('user_card.follows_you') }}
</span>
+ <button
+ v-if="showFollow"
+ class="btn btn-default"
+ @click="followUser"
+ :disabled="followRequestInProgress"
+ :title="followRequestSent ? $t('user_card.follow_again') : ''"
+ >
+ <template v-if="followRequestInProgress">
+ {{ $t('user_card.follow_progress') }}
+ </template>
+ <template v-else-if="followRequestSent">
+ {{ $t('user_card.follow_sent') }}
+ </template>
+ <template v-else>
+ {{ $t('user_card.follow') }}
+ </template>
+ </button>
+ <button v-if="following" class="btn btn-default pressed" @click="unfollowUser" :disabled="followRequestInProgress">
+ <template v-if="followRequestInProgress">
+ {{ $t('user_card.follow_progress') }}
+ </template>
+ <template v-else>
+ {{ $t('user_card.follow_unfollow') }}
+ </template>
+ </button>
+ </div>
+ <div class="approval" v-if="showApproval">
+ <button class="btn btn-default" @click="approveUser">{{ $t('user_card.approve') }}</button>
+ <button class="btn btn-default" @click="denyUser">{{ $t('user_card.deny') }}</button>
</div>
-
- <router-link class='user-screen-name' :to="userProfileLink(user)">
- @{{user.screen_name}}
- </router-link>
- </div>
- <div class="approval" v-if="showApproval">
- <button class="btn btn-default" @click="approveUser">{{ $t('user_card.approve') }}</button>
- <button class="btn btn-default" @click="denyUser">{{ $t('user_card.deny') }}</button>
</div>
</div>
</template>
@@ -36,11 +61,18 @@
<style lang="scss">
@import '../../_variables.scss';
-.name-and-screen-name {
+.user-card-main-content {
+ display: flex;
+ flex-direction: column;
+ flex: 1 1 100%;
margin-left: 0.7em;
- margin-top:0.0em;
+ min-width: 0;
+}
+
+.name-and-screen-name {
text-align: left;
width: 100%;
+
.user-name {
img {
object-fit: contain;
@@ -49,13 +81,15 @@
vertical-align: middle;
}
}
-}
-.follows-you {
- margin-left: 2em;
- float: right;
+ .user-link-action {
+ display: flex;
+ align-items: flex-start;
+ justify-content: space-between;
+ }
}
+
.card {
display: flex;
flex: 1 0;
@@ -66,16 +100,31 @@
border-bottom: 1px solid;
margin: 0;
border-bottom-color: $fallback--border;
- border-bottom-color: var(--border, $fallback--border);
+ border-bottom-color: var(--border, $fallback--border);
.avatar {
padding: 0;
}
+
+ .follow-box {
+ text-align: center;
+ flex-shrink: 0;
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+ flex-wrap: wrap;
+ line-height: 1.5em;
+
+ .btn {
+ margin-top: 0.5em;
+ margin-left: auto;
+ width: 10em;
+ }
+ }
}
.usercard {
width: fill-available;
- margin: 0.2em 0 0 0.7em;
border-radius: $fallback--panelRadius;
border-radius: var(--panelRadius, $fallback--panelRadius);
border-style: solid;
@@ -96,9 +145,15 @@
}
.approval {
+ display: flex;
+ flex-direction: row;
+ flex-wrap: wrap;
button {
- width: 100%;
- margin-bottom: 0.5em;
+ margin-top: 0.5em;
+ margin-right: 0.5em;
+ flex: 1 1;
+ max-width: 12em;
+ min-width: 8em;
}
}
</style>
diff --git a/src/components/user_card_content/user_card_content.js b/src/components/user_card_content/user_card_content.js
index 1888f8c6..7a7b89d4 100644
--- a/src/components/user_card_content/user_card_content.js
+++ b/src/components/user_card_content/user_card_content.js
@@ -1,5 +1,6 @@
import UserAvatar from '../user_avatar/user_avatar.vue'
import { hex2rgb } from '../../services/color_convert/color_convert.js'
+import { requestFollow, requestUnfollow } from '../../services/follow_manipulate/follow_manipulate'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
export default {
@@ -92,69 +93,17 @@ export default {
},
methods: {
followUser () {
- const store = this.$store
this.followRequestInProgress = true
- store.state.api.backendInteractor.followUser(this.user.id)
- .then((followedUser) => store.commit('addNewUsers', [followedUser]))
- .then(() => {
- // For locked users we just mark it that we sent the follow request
- if (this.user.locked) {
- this.followRequestInProgress = false
- this.followRequestSent = true
- return
- }
-
- if (this.user.following) {
- // If we get result immediately, just stop.
- this.followRequestInProgress = false
- return
- }
-
- // But usually we don't get result immediately, so we ask server
- // for updated user profile to confirm if we are following them
- // Sometimes it takes several tries. Sometimes we end up not following
- // user anyway, probably because they locked themselves and we
- // don't know that yet.
- // Recursive Promise, it will call itself up to 3 times.
- const fetchUser = (attempt) => new Promise((resolve, reject) => {
- setTimeout(() => {
- store.state.api.backendInteractor.fetchUser({ id: this.user.id })
- .then((user) => store.commit('addNewUsers', [user]))
- .then(() => resolve([this.user.following, attempt]))
- .catch((e) => reject(e))
- }, 500)
- }).then(([following, attempt]) => {
- if (!following && attempt <= 3) {
- // If we BE reports that we still not following that user - retry,
- // increment attempts by one
- return fetchUser(++attempt)
- } else {
- // If we run out of attempts, just return whatever status is.
- return following
- }
- })
-
- return fetchUser(1)
- .then((following) => {
- if (following) {
- // We confirmed and everything its good.
- this.followRequestInProgress = false
- } else {
- // If after all the tries, just treat it as if user is locked
- this.followRequestInProgress = false
- this.followRequestSent = true
- }
- })
- })
+ requestFollow(this.user, this.$store).then(({sent}) => {
+ this.followRequestInProgress = false
+ this.followRequestSent = sent
+ })
},
unfollowUser () {
- const store = this.$store
this.followRequestInProgress = true
- store.state.api.backendInteractor.unfollowUser(this.user.id)
- .then((unfollowedUser) => store.commit('addNewUsers', [unfollowedUser]))
- .then(() => {
- this.followRequestInProgress = false
- })
+ requestUnfollow(this.user, this.$store).then(() => {
+ this.followRequestInProgress = false
+ })
},
blockUser () {
const store = this.$store
diff --git a/src/components/user_card_content/user_card_content.vue b/src/components/user_card_content/user_card_content.vue
index 7f9909c4..4d1950c5 100644
--- a/src/components/user_card_content/user_card_content.vue
+++ b/src/components/user_card_content/user_card_content.vue
@@ -386,6 +386,4 @@
}
}
-.floater {
-}
</style>
diff --git a/src/components/user_profile/user_profile.js b/src/components/user_profile/user_profile.js
index a22b8722..37179ce1 100644
--- a/src/components/user_profile/user_profile.js
+++ b/src/components/user_profile/user_profile.js
@@ -16,7 +16,7 @@ const UserProfile = {
}
},
destroyed () {
- this.cleanUp(this.userId)
+ this.cleanUp()
},
computed: {
timeline () {
diff --git a/src/components/user_settings/user_settings.vue b/src/components/user_settings/user_settings.vue
index ea5b3de5..d2381da2 100644
--- a/src/components/user_settings/user_settings.vue
+++ b/src/components/user_settings/user_settings.vue
@@ -178,7 +178,7 @@
}
.banner {
- max-width: 400px;
+ max-width: 100%;
}
.uploading {
@@ -189,5 +189,9 @@
.name-changer {
width: 100%;
}
+
+ .bg {
+ max-width: 100%;
+ }
}
</style>