aboutsummaryrefslogtreecommitdiff
path: root/src/components
diff options
context:
space:
mode:
Diffstat (limited to 'src/components')
-rw-r--r--src/components/bookmark_timeline/bookmark_timeline.js17
-rw-r--r--src/components/bookmark_timeline/bookmark_timeline.vue9
-rw-r--r--src/components/extra_buttons/extra_buttons.js10
-rw-r--r--src/components/extra_buttons/extra_buttons.vue16
-rw-r--r--src/components/global_notice_list/global_notice_list.js15
-rw-r--r--src/components/global_notice_list/global_notice_list.vue77
-rw-r--r--src/components/nav_panel/nav_panel.vue5
-rw-r--r--src/components/notifications/notifications.js10
-rw-r--r--src/components/post_status_form/post_status_form.js9
-rw-r--r--src/components/settings_modal/settings_modal.scss2
-rw-r--r--src/components/settings_modal/tabs/filtering_tab.js3
-rw-r--r--src/components/side_drawer/side_drawer.vue8
-rw-r--r--src/components/status/status.js33
-rw-r--r--src/components/status/status.vue13
-rw-r--r--src/components/status_content/status_content.js12
-rw-r--r--src/components/status_content/status_content.vue119
-rw-r--r--src/components/status_popover/status_popover.js4
-rw-r--r--src/components/timeline/timeline.js14
-rw-r--r--src/components/timeline/timeline.vue6
19 files changed, 280 insertions, 102 deletions
diff --git a/src/components/bookmark_timeline/bookmark_timeline.js b/src/components/bookmark_timeline/bookmark_timeline.js
new file mode 100644
index 00000000..64b69e5d
--- /dev/null
+++ b/src/components/bookmark_timeline/bookmark_timeline.js
@@ -0,0 +1,17 @@
+import Timeline from '../timeline/timeline.vue'
+
+const Bookmarks = {
+ computed: {
+ timeline () {
+ return this.$store.state.statuses.timelines.bookmarks
+ }
+ },
+ components: {
+ Timeline
+ },
+ destroyed () {
+ this.$store.commit('clearTimeline', { timeline: 'bookmarks' })
+ }
+}
+
+export default Bookmarks
diff --git a/src/components/bookmark_timeline/bookmark_timeline.vue b/src/components/bookmark_timeline/bookmark_timeline.vue
new file mode 100644
index 00000000..8da6884b
--- /dev/null
+++ b/src/components/bookmark_timeline/bookmark_timeline.vue
@@ -0,0 +1,9 @@
+<template>
+ <Timeline
+ :title="$t('nav.bookmarks')"
+ :timeline="timeline"
+ :timeline-name="'bookmarks'"
+ />
+</template>
+
+<script src="./bookmark_timeline.js"></script>
diff --git a/src/components/extra_buttons/extra_buttons.js b/src/components/extra_buttons/extra_buttons.js
index e4b19d01..5e0c36bb 100644
--- a/src/components/extra_buttons/extra_buttons.js
+++ b/src/components/extra_buttons/extra_buttons.js
@@ -34,6 +34,16 @@ const ExtraButtons = {
navigator.clipboard.writeText(this.statusLink)
.then(() => this.$emit('onSuccess'))
.catch(err => this.$emit('onError', err.error.error))
+ },
+ bookmarkStatus () {
+ this.$store.dispatch('bookmark', { id: this.status.id })
+ .then(() => this.$emit('onSuccess'))
+ .catch(err => this.$emit('onError', err.error.error))
+ },
+ unbookmarkStatus () {
+ this.$store.dispatch('unbookmark', { id: this.status.id })
+ .then(() => this.$emit('onSuccess'))
+ .catch(err => this.$emit('onError', err.error.error))
}
},
computed: {
diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue
index 68db6fd8..7a4e8642 100644
--- a/src/components/extra_buttons/extra_buttons.vue
+++ b/src/components/extra_buttons/extra_buttons.vue
@@ -41,6 +41,22 @@
<i class="icon-pin" /><span>{{ $t("status.unpin") }}</span>
</button>
<button
+ v-if="!status.bookmarked"
+ class="dropdown-item dropdown-item-icon"
+ @click.prevent="bookmarkStatus"
+ @click="close"
+ >
+ <i class="icon-bookmark-empty" /><span>{{ $t("status.bookmark") }}</span>
+ </button>
+ <button
+ v-if="status.bookmarked"
+ class="dropdown-item dropdown-item-icon"
+ @click.prevent="unbookmarkStatus"
+ @click="close"
+ >
+ <i class="icon-bookmark" /><span>{{ $t("status.unbookmark") }}</span>
+ </button>
+ <button
v-if="canDelete"
class="dropdown-item dropdown-item-icon"
@click.prevent="deleteStatus"
diff --git a/src/components/global_notice_list/global_notice_list.js b/src/components/global_notice_list/global_notice_list.js
new file mode 100644
index 00000000..3af29c23
--- /dev/null
+++ b/src/components/global_notice_list/global_notice_list.js
@@ -0,0 +1,15 @@
+
+const GlobalNoticeList = {
+ computed: {
+ notices () {
+ return this.$store.state.interface.globalNotices
+ }
+ },
+ methods: {
+ closeNotice (notice) {
+ this.$store.dispatch('removeGlobalNotice', notice)
+ }
+ }
+}
+
+export default GlobalNoticeList
diff --git a/src/components/global_notice_list/global_notice_list.vue b/src/components/global_notice_list/global_notice_list.vue
new file mode 100644
index 00000000..0e4285cc
--- /dev/null
+++ b/src/components/global_notice_list/global_notice_list.vue
@@ -0,0 +1,77 @@
+<template>
+ <div class="global-notice-list">
+ <div
+ v-for="(notice, index) in notices"
+ :key="index"
+ class="alert global-notice"
+ :class="{ ['global-' + notice.level]: true }"
+ >
+ <div class="notice-message">
+ {{ $t(notice.messageKey, notice.messageArgs) }}
+ </div>
+ <i
+ class="button-icon icon-cancel"
+ @click="closeNotice(notice)"
+ />
+ </div>
+ </div>
+</template>
+
+<script src="./global_notice_list.js"></script>
+
+<style lang="scss">
+@import '../../_variables.scss';
+
+.global-notice-list {
+ position: fixed;
+ top: 50px;
+ width: 100%;
+ pointer-events: none;
+ z-index: 1001;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+
+ .global-notice {
+ pointer-events: auto;
+ text-align: center;
+ width: 40em;
+ max-width: calc(100% - 3em);
+ display: flex;
+ padding-left: 1.5em;
+ line-height: 2em;
+ .notice-message {
+ flex: 1 1 100%;
+ }
+ i {
+ flex: 0 0;
+ width: 1.5em;
+ cursor: pointer;
+ }
+ }
+
+ .global-error {
+ background-color: var(--alertPopupError, $fallback--cRed);
+ color: var(--alertPopupErrorText, $fallback--text);
+ i {
+ color: var(--alertPopupErrorText, $fallback--text);
+ }
+ }
+
+ .global-warning {
+ background-color: var(--alertPopupWarning, $fallback--cOrange);
+ color: var(--alertPopupWarningText, $fallback--text);
+ i {
+ color: var(--alertPopupWarningText, $fallback--text);
+ }
+ }
+
+ .global-info {
+ background-color: var(--alertPopupNeutral, $fallback--fg);
+ color: var(--alertPopupNeutralText, $fallback--text);
+ i {
+ color: var(--alertPopupNeutralText, $fallback--text);
+ }
+ }
+}
+</style>
diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue
index 8cd04dc7..f164b2b0 100644
--- a/src/components/nav_panel/nav_panel.vue
+++ b/src/components/nav_panel/nav_panel.vue
@@ -17,6 +17,11 @@
<i class="button-icon icon-mail-alt" /> {{ $t("nav.dms") }}
</router-link>
</li>
+ <li v-if="currentUser">
+ <router-link :to="{ name: 'bookmarks'}">
+ <i class="button-icon icon-bookmark" /> {{ $t("nav.bookmarks") }}
+ </router-link>
+ </li>
<li v-if="currentUser && currentUser.locked">
<router-link :to="{ name: 'friend-requests' }">
<i class="button-icon icon-user-plus" /> {{ $t("nav.friend_requests") }}
diff --git a/src/components/notifications/notifications.js b/src/components/notifications/notifications.js
index 26ffbab6..d8a327b0 100644
--- a/src/components/notifications/notifications.js
+++ b/src/components/notifications/notifications.js
@@ -27,6 +27,11 @@ const Notifications = {
seenToDisplayCount: DEFAULT_SEEN_TO_DISPLAY_COUNT
}
},
+ created () {
+ const store = this.$store
+ const credentials = store.state.users.currentUser.credentials
+ notificationsFetcher.fetchAndUpdate({ store, credentials })
+ },
computed: {
mainClass () {
return this.minimalMode ? '' : 'panel panel-default'
@@ -56,11 +61,6 @@ const Notifications = {
components: {
Notification
},
- created () {
- const { dispatch } = this.$store
-
- dispatch('fetchAndUpdateNotifications')
- },
watch: {
unseenCount (count) {
if (count > 0) {
diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js
index 732691e7..1bf5dae3 100644
--- a/src/components/post_status_form/post_status_form.js
+++ b/src/components/post_status_form/post_status_form.js
@@ -171,7 +171,7 @@ const PostStatusForm = {
return !!this.preview || this.previewLoading
},
emptyStatus () {
- return this.newStatus.status === '' && this.newStatus.files.length === 0
+ return this.newStatus.status.trim() === '' && this.newStatus.files.length === 0
},
...mapGetters(['mergedConfig'])
},
@@ -182,6 +182,9 @@ const PostStatusForm = {
} else if (this.preview) {
this.previewStatus(this.newStatus)
}
+ },
+ 'newStatus.spoilerText': function () {
+ this.autoPreview()
}
},
methods: {
@@ -236,7 +239,7 @@ const PostStatusForm = {
})
},
previewStatus () {
- if (this.emptyStatus) {
+ if (this.emptyStatus && this.newStatus.spoilerText.trim() === '') {
this.preview = { error: this.$t('status.preview_empty') }
this.previewLoading = false
return
@@ -269,7 +272,7 @@ const PostStatusForm = {
this.previewLoading = false
})
},
- debouncePreviewStatus: debounce(function () { this.previewStatus() }, 750),
+ debouncePreviewStatus: debounce(function () { this.previewStatus() }, 500),
autoPreview () {
if (!this.preview) return
this.previewLoading = true
diff --git a/src/components/settings_modal/settings_modal.scss b/src/components/settings_modal/settings_modal.scss
index 833ff89a..0da4d9a8 100644
--- a/src/components/settings_modal/settings_modal.scss
+++ b/src/components/settings_modal/settings_modal.scss
@@ -30,7 +30,7 @@
height: 100vh;
}
- .panel-body {
+ >.panel-body {
height: 100%;
overflow-y: hidden;
diff --git a/src/components/settings_modal/tabs/filtering_tab.js b/src/components/settings_modal/tabs/filtering_tab.js
index 224a7f47..3b2df556 100644
--- a/src/components/settings_modal/tabs/filtering_tab.js
+++ b/src/components/settings_modal/tabs/filtering_tab.js
@@ -37,6 +37,9 @@ const FilteringTab = {
})
},
deep: true
+ },
+ replyVisibility () {
+ this.$store.dispatch('queueFlushAll')
}
}
}
diff --git a/src/components/side_drawer/side_drawer.vue b/src/components/side_drawer/side_drawer.vue
index f253742d..0ac53b34 100644
--- a/src/components/side_drawer/side_drawer.vue
+++ b/src/components/side_drawer/side_drawer.vue
@@ -66,6 +66,14 @@
</router-link>
</li>
<li
+ v-if="currentUser"
+ @click="toggleDrawer"
+ >
+ <router-link :to="{ name: 'bookmarks'}">
+ <i class="button-icon icon-bookmark" /> {{ $t("nav.bookmarks") }}
+ </router-link>
+ </li>
+ <li
v-if="currentUser && currentUser.locked"
@click="toggleDrawer"
>
diff --git a/src/components/status/status.js b/src/components/status/status.js
index 73382521..ad0b72a9 100644
--- a/src/components/status/status.js
+++ b/src/components/status/status.js
@@ -141,7 +141,7 @@ const Status = {
return this.mergedConfig.hideFilteredStatuses
},
hideStatus () {
- return (this.hideReply || this.deleted) || (this.muted && this.hideFilteredStatuses)
+ return this.deleted || (this.muted && this.hideFilteredStatuses)
},
isFocused () {
// retweet or root of an expanded conversation
@@ -164,37 +164,6 @@ const Status = {
return user && user.screen_name
}
},
- hideReply () {
- if (this.mergedConfig.replyVisibility === 'all') {
- return false
- }
- if (this.inConversation || !this.isReply) {
- return false
- }
- if (this.status.user.id === this.currentUser.id) {
- return false
- }
- if (this.status.type === 'retweet') {
- return false
- }
- const checkFollowing = this.mergedConfig.replyVisibility === 'following'
- for (var i = 0; i < this.status.attentions.length; ++i) {
- if (this.status.user.id === this.status.attentions[i].id) {
- continue
- }
- // There's zero guarantee of this working. If we happen to have that user and their
- // relationship in store then it will work, but there's kinda little chance of having
- // them for people you're not following.
- const relationship = this.$store.state.users.relationships[this.status.attentions[i].id]
- if (checkFollowing && relationship && relationship.following) {
- return false
- }
- if (this.status.attentions[i].id === this.currentUser.id) {
- return false
- }
- }
- return this.status.attentions.length > 0
- },
replySubject () {
if (!this.status.summary) return ''
const decodedSummary = unescape(this.status.summary)
diff --git a/src/components/status/status.vue b/src/components/status/status.vue
index 1c36d883..f6b5dd6f 100644
--- a/src/components/status/status.vue
+++ b/src/components/status/status.vue
@@ -197,7 +197,7 @@
>
<StatusPopover
v-if="!isPreview"
- :status-id="status.in_reply_to_status_id"
+ :status-id="status.parent_visible && status.in_reply_to_status_id"
class="reply-to-popover"
style="min-width: 0"
>
@@ -208,7 +208,12 @@
@click.prevent="gotoOriginal(status.in_reply_to_status_id)"
>
<i class="button-icon icon-reply" />
- <span class="faint-link reply-to-text">{{ $t('status.reply_to') }}</span>
+ <span
+ class="faint-link reply-to-text"
+ :class="{ 'strikethrough': !status.parent_visible }"
+ >
+ {{ $t('status.reply_to') }}
+ </span>
</a>
</StatusPopover>
<span
@@ -523,6 +528,10 @@ $status-margin: 0.75em;
margin: 0 0.4em 0 0.2em;
}
+ .strikethrough {
+ text-decoration: line-through;
+ }
+
.replies-separator {
margin-left: 0.4em;
}
diff --git a/src/components/status_content/status_content.js b/src/components/status_content/status_content.js
index c0a71e8f..09ea3a20 100644
--- a/src/components/status_content/status_content.js
+++ b/src/components/status_content/status_content.js
@@ -44,14 +44,14 @@ const StatusContent = {
return lengthScore > 20
},
longSubject () {
- return this.status.summary.length > 900
+ return this.status.summary.length > 240
},
// When a status has a subject and is also tall, we should only have one show more/less button. If the default is to collapse statuses with subjects, we just treat it like a status with a subject; otherwise, we just treat it like a tall status.
mightHideBecauseSubject () {
- return this.status.summary && (!this.tallStatus || this.localCollapseSubjectDefault)
+ return !!this.status.summary && this.localCollapseSubjectDefault
},
mightHideBecauseTall () {
- return this.tallStatus && (!this.status.summary || !this.localCollapseSubjectDefault)
+ return this.tallStatus && !(this.status.summary && this.localCollapseSubjectDefault)
},
hideSubjectStatus () {
return this.mightHideBecauseSubject && !this.expandingSubject
@@ -142,12 +142,6 @@ const StatusContent = {
return html
}
},
- contentHtml () {
- if (!this.status.summary_html) {
- return this.postBodyHtml
- }
- return this.status.summary_html + '<br />' + this.postBodyHtml
- },
...mapGetters(['mergedConfig']),
...mapState({
betterShadow: state => state.interface.browserSupport.cssFilter,
diff --git a/src/components/status_content/status_content.vue b/src/components/status_content/status_content.vue
index 373802af..40c28b5c 100644
--- a/src/components/status_content/status_content.vue
+++ b/src/components/status_content/status_content.vue
@@ -3,45 +3,32 @@
<div class="status-body">
<slot name="header" />
<div
- v-if="longSubject"
- class="status-content-wrapper"
- :class="{ 'tall-status': !showingLongSubject }"
+ v-if="status.summary_html"
+ class="summary-wrapper"
+ :class="{ 'tall-subject': (longSubject && !showingLongSubject) }"
>
- <a
- v-if="!showingLongSubject"
- class="tall-status-hider"
- :class="{ 'tall-status-hider_focused': focused }"
- href="#"
- @click.prevent="showingLongSubject=true"
- >
- {{ $t("general.show_more") }}
- <span
- v-if="hasImageAttachments"
- class="icon-picture"
- />
- <span
- v-if="hasVideoAttachments"
- class="icon-video"
- />
- <span
- v-if="status.card"
- class="icon-link"
- />
- </a>
<div
- class="status-content media-body"
+ class="media-body summary"
@click.prevent="linkClicked"
- v-html="contentHtml"
+ v-html="status.summary_html"
/>
<a
- v-if="showingLongSubject"
+ v-if="longSubject && showingLongSubject"
href="#"
- class="status-unhider"
+ class="tall-subject-hider"
@click.prevent="showingLongSubject=false"
- >{{ $t("general.show_less") }}</a>
+ >{{ $t("status.hide_full_subject") }}</a>
+ <a
+ v-else-if="longSubject"
+ class="tall-subject-hider"
+ :class="{ 'tall-subject-hider_focused': focused }"
+ href="#"
+ @click.prevent="showingLongSubject=true"
+ >
+ {{ $t("status.show_full_subject") }}
+ </a>
</div>
<div
- v-else
:class="{'tall-status': hideTallStatus}"
class="status-content-wrapper"
>
@@ -51,31 +38,43 @@
:class="{ 'tall-status-hider_focused': focused }"
href="#"
@click.prevent="toggleShowMore"
- >{{ $t("general.show_more") }}</a>
+ >
+ {{ $t("general.show_more") }}
+ </a>
<div
v-if="!hideSubjectStatus"
class="status-content media-body"
@click.prevent="linkClicked"
- v-html="contentHtml"
- />
- <div
- v-else
- class="status-content media-body"
- @click.prevent="linkClicked"
- v-html="status.summary_html"
+ v-html="postBodyHtml"
/>
<a
v-if="hideSubjectStatus"
href="#"
class="cw-status-hider"
@click.prevent="toggleShowMore"
- >{{ $t("general.show_more") }}</a>
+ >
+ {{ $t("status.show_content") }}
+ <span
+ v-if="hasImageAttachments"
+ class="icon-picture"
+ />
+ <span
+ v-if="hasVideoAttachments"
+ class="icon-video"
+ />
+ <span
+ v-if="status.card"
+ class="icon-link"
+ />
+ </a>
<a
v-if="showingMore"
href="#"
class="status-unhider"
@click.prevent="toggleShowMore"
- >{{ $t("general.show_less") }}</a>
+ >
+ {{ tallStatus ? $t("general.show_less") : $t("status.hide_content") }}
+ </a>
</div>
<div v-if="status.poll && status.poll.options">
@@ -129,6 +128,12 @@ $status-margin: 0.75em;
flex: 1;
min-width: 0;
+ .status-content-wrapper {
+ display: flex;
+ flex-direction: column;
+ flex-wrap: nowrap;
+ }
+
.tall-status {
position: relative;
height: 220px;
@@ -136,7 +141,7 @@ $status-margin: 0.75em;
overflow-y: hidden;
z-index: 1;
.status-content {
- height: 100%;
+ min-height: 0;
mask: linear-gradient(to top, white, transparent) bottom/100% 70px no-repeat,
linear-gradient(to top, white, white);
/* Autoprefixed seem to ignore this one, and also syntax is different */
@@ -176,6 +181,38 @@ $status-margin: 0.75em;
}
}
+ .summary-wrapper {
+ margin-bottom: 0.5em;
+ border-style: solid;
+ border-width: 0 0 1px 0;
+ border-color: var(--border, $fallback--border);
+ flex-grow: 0;
+ }
+
+ .summary {
+ font-style: italic;
+ padding-bottom: 0.5em;
+ }
+
+ .tall-subject {
+ position: relative;
+ .summary {
+ max-height: 2em;
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+ }
+ }
+
+ .tall-subject-hider {
+ display: inline-block;
+ word-break: break-all;
+ // position: absolute;
+ width: 100%;
+ text-align: center;
+ padding-bottom: 0.5em;
+ }
+
.status-content {
font-family: var(--postFont, sans-serif);
line-height: 1.4em;
diff --git a/src/components/status_popover/status_popover.js b/src/components/status_popover/status_popover.js
index 159132a9..51e7680c 100644
--- a/src/components/status_popover/status_popover.js
+++ b/src/components/status_popover/status_popover.js
@@ -22,6 +22,10 @@ const StatusPopover = {
methods: {
enter () {
if (!this.status) {
+ if (!this.statusId) {
+ this.error = true
+ return
+ }
this.$store.dispatch('fetchStatus', this.statusId)
.then(data => (this.error = false))
.catch(e => (this.error = true))
diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js
index 9a53acd6..bac73022 100644
--- a/src/components/timeline/timeline.js
+++ b/src/components/timeline/timeline.js
@@ -45,11 +45,15 @@ const Timeline = {
newStatusCount () {
return this.timeline.newStatusCount
},
- newStatusCountStr () {
+ showLoadButton () {
+ if (this.timelineError || this.errorData) return false
+ return this.timeline.newStatusCount > 0 || this.timeline.flushMarker !== 0
+ },
+ loadButtonString () {
if (this.timeline.flushMarker !== 0) {
- return ''
+ return this.$t('timeline.reload')
} else {
- return ` (${this.newStatusCount})`
+ return `${this.$t('timeline.show_new')} (${this.newStatusCount})`
}
},
classes () {
@@ -112,8 +116,6 @@ const Timeline = {
if (e.key === '.') this.showNewStatuses()
},
showNewStatuses () {
- if (this.newStatusCount === 0) return
-
if (this.timeline.flushMarker !== 0) {
this.$store.commit('clearTimeline', { timeline: this.timelineName, excludeUserId: true })
this.$store.commit('queueFlush', { timeline: this.timelineName, id: 0 })
@@ -135,7 +137,7 @@ const Timeline = {
showImmediately: true,
userId: this.userId,
tag: this.tag
- }).then(statuses => {
+ }).then(({ statuses }) => {
store.commit('setLoading', { timeline: this.timelineName, value: false })
if (statuses && statuses.length === 0) {
this.bottomedOut = true
diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue
index 9777bd0c..111c0976 100644
--- a/src/components/timeline/timeline.vue
+++ b/src/components/timeline/timeline.vue
@@ -19,14 +19,14 @@
{{ errorData.statusText }}
</div>
<button
- v-if="timeline.newStatusCount > 0 && !timelineError && !errorData"
+ v-else-if="showLoadButton"
class="loadmore-button"
@click.prevent="showNewStatuses"
>
- {{ $t('timeline.show_new') }}{{ newStatusCountStr }}
+ {{ loadButtonString }}
</button>
<div
- v-if="!timeline.newStatusCount > 0 && !timelineError && !errorData"
+ v-else
class="loadmore-text faint"
@click.prevent
>