diff --git a/build/webpack.base.conf.js b/build/webpack.base.conf.js index 68e75972..7bba3a10 100644 --- a/build/webpack.base.conf.js +++ b/build/webpack.base.conf.js @@ -33,6 +33,7 @@ module.exports = { fallback: [path.join(__dirname, '../node_modules')] }, module: { + noParse: /node_modules\/localforage\/dist\/localforage.js/, preLoaders: [ { test: /\.vue$/, diff --git a/src/components/conversation/conversation.vue b/src/components/conversation/conversation.vue index 33a43e15..331cce99 100644 --- a/src/components/conversation/conversation.vue +++ b/src/components/conversation/conversation.vue @@ -8,7 +8,7 @@ </div> <div class="panel-body"> <div class="timeline"> - <status v-for="status in conversation" :key="status.id" v-bind:statusoid="status":expandable='false':focused="focused(status.id)"></status> + <status v-for="status in conversation" :key="status.id" :statusoid="status" :expandable='false' :focused="focused(status.id)" :inConversation='true'></status> </div> </div> </div> diff --git a/src/components/mentions/mentions.js b/src/components/mentions/mentions.js index 46a1c63e..841d5aa4 100644 --- a/src/components/mentions/mentions.js +++ b/src/components/mentions/mentions.js @@ -2,25 +2,12 @@ import Timeline from '../timeline/timeline.vue' const Mentions = { computed: { - username () { - return this.$route.params.username - }, timeline () { return this.$store.state.statuses.timelines.mentions } }, components: { Timeline - }, - created () { - this.$store.state.api.backendInteractor.fetchMentions({username: this.username}) - .then((mentions) => { - this.$store.dispatch('addNewStatuses', { - statuses: mentions, - timeline: 'mentions', - showImmediately: true - }) - }) } } diff --git a/src/components/nav_panel/nav_panel.vue b/src/components/nav_panel/nav_panel.vue index 1d96f4d6..b62b4148 100644 --- a/src/components/nav_panel/nav_panel.vue +++ b/src/components/nav_panel/nav_panel.vue @@ -1,7 +1,7 @@ <template> <div class="nav-panel"> <div class="panel panel-default base02-background"> - <ul> + <ul class="base03-border"> <li v-if='currentUser'> <router-link class="base01-background" to='/main/friends'> Timeline @@ -38,6 +38,7 @@ .nav-panel li { border-bottom: 1px solid; + border-color: inherit; padding: 0; &:first-child a { border-top-right-radius: 10px; diff --git a/src/components/notifications/notifications.scss b/src/components/notifications/notifications.scss index 6ad7ec1e..5cce7a73 100644 --- a/src/components/notifications/notifications.scss +++ b/src/components/notifications/notifications.scss @@ -33,7 +33,8 @@ // which does not happen with 10px vs 4px + 6px. padding: 0.4em 0 0 10px; display: flex; - border-bottom: 1px solid silver; + border-bottom: 1px solid; + border-bottom-color: inherit; .text { @@ -72,7 +73,8 @@ } &:last-child { - border: none + border-bottom: none; + border-radius: 0 0 10px 10px; } } diff --git a/src/components/notifications/notifications.vue b/src/components/notifications/notifications.vue index 91f6cfdc..661d842c 100644 --- a/src/components/notifications/notifications.vue +++ b/src/components/notifications/notifications.vue @@ -6,7 +6,7 @@ Notifications <button @click.prevent="markAsSeen" class="base06 base02-background read-button">Read!</button> </div> - <div class="panel-body"> + <div class="panel-body base03-border"> <div v-for="notification in visibleNotifications" class="notification" :class='{"unseen": !notification.seen}'> <a :href="notification.action.user.statusnet_profile_url"> <img class='avatar' :src="notification.action.user.profile_image_url_original"> diff --git a/src/components/settings/settings.js b/src/components/settings/settings.js index c1b88f82..3d373283 100644 --- a/src/components/settings/settings.js +++ b/src/components/settings/settings.js @@ -4,6 +4,7 @@ const settings = { data () { return { hideAttachmentsLocal: this.$store.state.config.hideAttachments, + hideAttachmentsInConvLocal: this.$store.state.config.hideAttachmentsInConv, hideNsfwLocal: this.$store.state.config.hideNsfw } }, @@ -14,6 +15,9 @@ const settings = { hideAttachmentsLocal (value) { this.$store.dispatch('setOption', { name: 'hideAttachments', value }) }, + hideAttachmentsInConvLocal (value) { + this.$store.dispatch('setOption', { name: 'hideAttachmentsInConv', value }) + }, hideNsfwLocal (value) { this.$store.dispatch('setOption', { name: 'hideNsfw', value }) } diff --git a/src/components/settings/settings.vue b/src/components/settings/settings.vue index 89b89a39..478d761a 100644 --- a/src/components/settings/settings.vue +++ b/src/components/settings/settings.vue @@ -10,10 +10,20 @@ </div> <div class="setting-item"> <h2>Attachments</h2> - <input type="checkbox" id="hideAttachments" v-model="hideAttachmentsLocal"> - <label for="hideAttachments">Hide Attachments</label> - <input type="checkbox" id="hideNsfw" v-model="hideNsfwLocal"> - <label for="hideNsfw">Enable clickthrough NSFW attachment hiding</label> + <ul class="setting-list"> + <li> + <input type="checkbox" id="hideAttachments" v-model="hideAttachmentsLocal"> + <label for="hideAttachments">Hide attachments in timeline</label> + </li> + <li> + <input type="checkbox" id="hideAttachmentsInConv" v-model="hideAttachmentsInConvLocal"> + <label for="hideAttachmentsInConv">Hide attachments in conversations</label> + </li> + <li> + <input type="checkbox" id="hideNsfw" v-model="hideNsfwLocal"> + <label for="hideNsfw">Enable clickthrough NSFW attachment hiding</label> + </li> + </ul> </div> </div> </div> @@ -26,4 +36,7 @@ .setting-item { margin: 1em 1em 1.4em; } + .setting-list { + list-style-type: none; + } </style> diff --git a/src/components/status/status.js b/src/components/status/status.js index bc9d6e6c..87fff879 100644 --- a/src/components/status/status.js +++ b/src/components/status/status.js @@ -9,6 +9,7 @@ const Status = { props: [ 'statusoid', 'expandable', + 'inConversation', 'focused' ], data: () => ({ @@ -18,7 +19,10 @@ const Status = { userExpanded: false }), computed: { - hideAttachments () { return this.$store.state.config.hideAttachments }, + hideAttachments () { + return (this.$store.state.config.hideAttachments && !this.inConversation) || + (this.$store.state.config.hideAttachmentsInConv && this.inConversation) + }, retweet () { return !!this.statusoid.retweeted_status }, retweeter () { return this.statusoid.user.name }, status () { @@ -32,7 +36,12 @@ const Status = { return !!this.$store.state.users.currentUser }, muted () { return !this.unmuted && this.status.user.muted }, - isReply () { return !!this.status.in_reply_to_status_id } + isReply () { return !!this.status.in_reply_to_status_id }, + borderColor () { + return { + borderBottomColor: this.$store.state.config.colors['base02'] + } + } }, components: { Attachment, diff --git a/src/components/status/status.vue b/src/components/status/status.vue index 6476e1e5..62a55505 100644 --- a/src/components/status/status.vue +++ b/src/components/status/status.vue @@ -1,5 +1,5 @@ <template> - <div class="status-el base00-background" v-if="!status.deleted" v-bind:class="[{ 'expanded-status': !expandable }, { 'base01-background': focused }]"> + <div class="status-el base00-background base03-border" v-if="!status.deleted" v-bind:class="[{ 'base01-background': focused }, { 'status-conversation': inConversation }]" > <template v-if="muted"> <div class="media status container muted"> <small><router-link :to="{ name: 'user-profile', params: { id: status.user.id } }">{{status.user.screen_name}}</router-link></small> @@ -73,18 +73,20 @@ <div class='status-actions'> <div> <a href="#" v-on:click.prevent="toggleReplying"> - <i class='fa icon-reply'></i> + <i class="fa icon-reply" :class="{'icon-reply-active': replying}"></i> </a> </div> <retweet-button :status=status></retweet-button> <favorite-button :status=status></favorite-button> <delete-button :status=status></delete-button> </div> - - <post-status-form v-if="replying" :reply-to="status.id" :attentions="status.attentions" :repliedUser="status.user" v-on:posted="toggleReplying"></post-status-form> </div> </div> </div> + <div class="status base00-background container" v-if="replying"> + <div class="reply-left"/> + <post-status-form class="reply-body" :reply-to="status.id" :attentions="status.attentions" :repliedUser="status.user" v-on:posted="toggleReplying"/> + </div> </template> </div> </template> @@ -98,6 +100,7 @@ overflow-wrap: break-word; word-wrap: break-word; word-break: break-word; + border-left-width: 0px; .user-content { min-height: 52px; @@ -128,8 +131,8 @@ } } - .expanded-status { - border-left: 4px solid rgba(255, 48, 16, 0.65); + .status-conversation { + border-left-style: solid; } .status-actions { @@ -140,6 +143,10 @@ color: $blue; } + .icon-reply-active { + color: $blue; + } + .status .avatar { width: 48px; } @@ -151,6 +158,9 @@ .status { padding: 0.65em 0.7em 0.8em 0.8em; border-bottom: 1px solid; + border-bottom-color: inherit; + border-left: 4px rgba(255, 48, 16, 0.65); + border-left-style: inherit; } .muted button { margin-left: auto; @@ -168,4 +178,14 @@ margin-bottom: 1em; margin-top: 0.2em; } + + .reply-left { + flex: 0; + min-width: 48px; + } + + .reply-body { + flex: 1; + } + </style> diff --git a/src/components/status_or_conversation/status_or_conversation.vue b/src/components/status_or_conversation/status_or_conversation.vue index 4aaaf2ff..9647d5eb 100644 --- a/src/components/status_or_conversation/status_or_conversation.vue +++ b/src/components/status_or_conversation/status_or_conversation.vue @@ -1,7 +1,7 @@ <template> <div> <conversation v-if="expanded" @toggleExpanded="toggleExpanded" :collapsable="true" :statusoid="statusoid"></conversation> - <status v-if="!expanded" @toggleExpanded="toggleExpanded" :expandable="true" :statusoid="statusoid" :focused="false"></status> + <status v-if="!expanded" @toggleExpanded="toggleExpanded" :expandable="true" :inConversation="false" :focused="false" :statusoid="statusoid"></status> </div> </template> diff --git a/src/components/timeline/timeline.js b/src/components/timeline/timeline.js index b4e80fe1..d5a9adcc 100644 --- a/src/components/timeline/timeline.js +++ b/src/components/timeline/timeline.js @@ -8,6 +8,9 @@ const Timeline = { 'timelineName', 'title' ], + computed: { + timelineError () { return this.$store.state.statuses.error } + }, components: { Status, StatusOrConversation diff --git a/src/components/timeline/timeline.vue b/src/components/timeline/timeline.vue index ac074f3c..84defac7 100644 --- a/src/components/timeline/timeline.vue +++ b/src/components/timeline/timeline.vue @@ -4,13 +4,13 @@ <div class="title"> {{title}} </div> - <button @click.prevent="showNewStatuses" class="base06 base02-background loadmore-button" v-if="timeline.newStatusCount > 0 && !timeline.error"> + <button @click.prevent="showNewStatuses" class="base06 base02-background loadmore-button" v-if="timeline.newStatusCount > 0 && !timelineError"> Show new ({{timeline.newStatusCount}}) </button> - <button @click.prevent class="base06 error no-press loadmore-button" v-if="timeline.error"> + <button @click.prevent class="base06 error no-press loadmore-button" v-if="timelineError"> Error fetching updates </button> - <button @click.prevent class="base04 base01-background no-press loadmore-button" v-if="!timeline.newStatusCount > 0 && !timeline.error"> + <button @click.prevent class="base04 base01-background no-press loadmore-button" v-if="!timeline.newStatusCount > 0 && !timelineError"> Up-to-date </button> </div> @@ -18,9 +18,9 @@ <div class="timeline"> <status-or-conversation v-for="status in timeline.visibleStatuses" :key="status.id" v-bind:statusoid="status"></status-or-conversation> <a href="#" v-on:click.prevent='fetchOlderStatuses()' v-if="!timeline.loading"> - <div class="base01-background base05-border new-status-notification text-center">Load older statuses.</div> + <div class="base01-background base03-border new-status-notification text-center">Load older statuses.</div> </a> - <div class="base01-background base05-border new-status-notification text-center" v-else>...</div> + <div class="base01-background base03-border new-status-notification text-center" v-else>...</div> </div> </div> </div> diff --git a/src/main.js b/src/main.js index 9a3406e3..105e8d88 100644 --- a/src/main.js +++ b/src/main.js @@ -31,6 +31,7 @@ Vue.use(VueTimeago, { const persistedStateOptions = { paths: [ 'config.hideAttachments', + 'config.hideAttachmentsInConv', 'config.hideNsfw', 'statuses.notifications', 'users.users' diff --git a/src/modules/config.js b/src/modules/config.js index 896a6978..05b4ab3b 100644 --- a/src/modules/config.js +++ b/src/modules/config.js @@ -5,6 +5,7 @@ const defaultState = { name: 'Pleroma FE', colors: {}, hideAttachments: false, + hideAttachmentsInConv: false, hideNsfw: true } diff --git a/src/modules/statuses.js b/src/modules/statuses.js index e4528520..051ec71b 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -8,6 +8,7 @@ export const defaultState = { maxId: 0, notifications: [], favorites: new Set(), + error: false, timelines: { mentions: { statuses: [], @@ -18,8 +19,7 @@ export const defaultState = { newStatusCount: 0, maxId: 0, minVisibleId: 0, - loading: false, - error: false + loading: false }, public: { statuses: [], @@ -30,8 +30,7 @@ export const defaultState = { newStatusCount: 0, maxId: 0, minVisibleId: 0, - loading: false, - error: false + loading: false }, publicAndExternal: { statuses: [], @@ -42,8 +41,7 @@ export const defaultState = { newStatusCount: 0, maxId: 0, minVisibleId: 0, - loading: false, - error: false + loading: false }, friends: { statuses: [], @@ -54,8 +52,7 @@ export const defaultState = { newStatusCount: 0, maxId: 0, minVisibleId: 0, - loading: false, - error: false + loading: false } } } @@ -298,8 +295,8 @@ export const mutations = { const newStatus = state.allStatusesObject[id] newStatus.nsfw = nsfw }, - setError (state, { timeline, value }) { - state.timelines[timeline].error = value + setError (state, { value }) { + state.error = value }, markNotificationsAsSeen (state, notifications) { each(notifications, (notification) => { @@ -314,8 +311,8 @@ const statuses = { addNewStatuses ({ rootState, commit }, { statuses, showImmediately = false, timeline = false, noIdUpdate = false }) { commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser }) }, - setError ({ rootState, commit }, { timeline, value }) { - commit('setError', { timeline, value }) + setError ({ rootState, commit }, { value }) { + commit('setError', { value }) }, deleteStatus ({ rootState, commit }, status) { commit('setDeleted', { status }) diff --git a/src/services/api/api.service.js b/src/services/api/api.service.js index f172f769..4dfc0a02 100644 --- a/src/services/api/api.service.js +++ b/src/services/api/api.service.js @@ -62,12 +62,6 @@ const fetchAllFollowing = ({username, credentials}) => { .then((data) => data.json()) } -const fetchMentions = ({username, sinceId = 0, credentials}) => { - let url = `${MENTIONS_URL}?since_id=${sinceId}&screen_name=${username}` - return fetch(url, { headers: authHeaders(credentials) }) - .then((data) => data.json()) -} - const fetchConversation = ({id, credentials}) => { let url = `${CONVERSATION_URL}/${id}.json?count=100` return fetch(url, { headers: authHeaders(credentials) }) @@ -100,6 +94,7 @@ const fetchTimeline = ({timeline, credentials, since = false, until = false}) => const timelineUrls = { public: PUBLIC_TIMELINE_URL, friends: FRIENDS_TIMELINE_URL, + mentions: MENTIONS_URL, 'publicAndExternal': PUBLIC_AND_EXTERNAL_TIMELINE_URL } @@ -192,7 +187,6 @@ const apiService = { fetchTimeline, fetchConversation, fetchStatus, - fetchMentions, fetchFriends, followUser, unfollowUser, diff --git a/src/services/backend_interactor_service/backend_interactor_service.js b/src/services/backend_interactor_service/backend_interactor_service.js index d379e602..bc68d02c 100644 --- a/src/services/backend_interactor_service/backend_interactor_service.js +++ b/src/services/backend_interactor_service/backend_interactor_service.js @@ -10,10 +10,6 @@ const backendInteractorService = (credentials) => { return apiService.fetchConversation({id, credentials}) } - const fetchMentions = ({sinceId, username}) => { - return apiService.fetchMentions({sinceId, username, credentials}) - } - const fetchFriends = () => { return apiService.fetchFriends({credentials}) } @@ -43,7 +39,6 @@ const backendInteractorService = (credentials) => { const backendInteractorServiceInstance = { fetchStatus, fetchConversation, - fetchMentions, fetchFriends, followUser, unfollowUser, diff --git a/src/services/style_setter/style_setter.js b/src/services/style_setter/style_setter.js index 7129852d..59d5a7de 100644 --- a/src/services/style_setter/style_setter.js +++ b/src/services/style_setter/style_setter.js @@ -45,6 +45,7 @@ const setStyle = (href, commit) => { styleSheet.insertRule(`a { color: ${colors['base08']}`, 'index-max') styleSheet.insertRule(`body { color: ${colors['base05']}`, 'index-max') styleSheet.insertRule(`.base05-border { border-color: ${colors['base05']}`, 'index-max') + styleSheet.insertRule(`.base03-border { border-color: ${colors['base03']}`, 'index-max') body.style.display = 'initial' } cssEl.addEventListener('load', setDynamic) diff --git a/src/services/timeline_fetcher/timeline_fetcher.service.js b/src/services/timeline_fetcher/timeline_fetcher.service.js index e684a170..24aef069 100644 --- a/src/services/timeline_fetcher/timeline_fetcher.service.js +++ b/src/services/timeline_fetcher/timeline_fetcher.service.js @@ -5,7 +5,7 @@ import apiService from '../api/api.service.js' const update = ({store, statuses, timeline, showImmediately}) => { const ccTimeline = camelCase(timeline) - setError({store, timeline, value: false}) + store.dispatch('setError', { value: false }) store.dispatch('addNewStatuses', { timeline: ccTimeline, @@ -14,15 +14,6 @@ const update = ({store, statuses, timeline, showImmediately}) => { }) } -const setError = ({store, timeline, value}) => { - const ccTimeline = camelCase(timeline) - - store.dispatch('setError', { - timeline: ccTimeline, - value - }) -} - const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false, showImmediately = false}) => { const args = { timeline, credentials } const rootState = store.rootState || store.state @@ -36,7 +27,7 @@ const fetchAndUpdate = ({store, credentials, timeline = 'friends', older = false return apiService.fetchTimeline(args) .then((statuses) => update({store, statuses, timeline, showImmediately}), - () => setError({store, timeline, value: true})) + () => store.dispatch('setError', { value: true })) } const startFetching = ({ timeline = 'friends', credentials, store }) => {