From 1387dfb889f8b59d7790cf794cb6498a0f308607 Mon Sep 17 00:00:00 2001 From: lain Date: Wed, 13 Mar 2019 11:29:45 +0100 Subject: Load persistedStated with async/await. --- src/main.js | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) (limited to 'src/main.js') diff --git a/src/main.js b/src/main.js index a3265e3a..9ffc3727 100644 --- a/src/main.js +++ b/src/main.js @@ -53,9 +53,10 @@ const persistedStateOptions = { 'users.lastLoginName', 'oauth' ] -} +}; -createPersistedState(persistedStateOptions).then((persistedState) => { +(async () => { + const persistedState = await createPersistedState(persistedStateOptions) const store = new Vuex.Store({ modules: { interface: interfaceModule, @@ -75,7 +76,7 @@ createPersistedState(persistedStateOptions).then((persistedState) => { }) afterStoreSetup({ store, i18n }) -}) +})() // These are inlined by webpack's DefinePlugin /* eslint-disable */ -- cgit v1.2.3-70-g09d2 From 21ea5adc8b4f8eb16026cdefd60a60c8952ae162 Mon Sep 17 00:00:00 2001 From: dave Date: Sun, 31 Mar 2019 21:59:18 -0400 Subject: #436 - apply patch and clean up --- src/components/notification/notification.js | 4 +- src/main.js | 5 +++ src/modules/statuses.js | 45 +++++++++++++++------- src/modules/users.js | 4 +- .../entity_normalizer/entity_normalizer.service.js | 15 +------- 5 files changed, 44 insertions(+), 29 deletions(-) (limited to 'src/main.js') diff --git a/src/components/notification/notification.js b/src/components/notification/notification.js index fe5b7018..4e6f46a6 100644 --- a/src/components/notification/notification.js +++ b/src/components/notification/notification.js @@ -25,11 +25,11 @@ const Notification = { }, computed: { userClass () { - return highlightClass(this.notification.action.user) + return highlightClass(this.notification.from_profile) }, userStyle () { const highlight = this.$store.state.config.highlight - const user = this.notification.action.user + const user = this.notification.from_profile return highlightStyle(highlight[user.screen_name]) } } diff --git a/src/main.js b/src/main.js index 9ffc3727..c80aea36 100644 --- a/src/main.js +++ b/src/main.js @@ -59,6 +59,11 @@ const persistedStateOptions = { const persistedState = await createPersistedState(persistedStateOptions) const store = new Vuex.Store({ modules: { + i18n: { + getters: { + i18n: () => i18n + } + }, interface: interfaceModule, instance: instanceModule, statuses: statusesModule, diff --git a/src/modules/statuses.js b/src/modules/statuses.js index 6e356be0..63af7ce2 100644 --- a/src/modules/statuses.js +++ b/src/modules/statuses.js @@ -25,7 +25,7 @@ export const defaultState = () => ({ allStatusesObject: {}, maxId: 0, notifications: { - desktopNotificationSilence: true, + desktopNotificationSilence: false, maxId: 0, minId: Number.POSITIVE_INFINITY, data: [], @@ -271,12 +271,14 @@ const addNewStatuses = (state, { statuses, showImmediately = false, timeline, us } } -const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes }) => { +const addNewNotifications = (state, { dispatch, notifications, older, visibleNotificationTypes, rootGetters }) => { const allStatuses = state.allStatuses const allStatusesObject = state.allStatusesObject each(notifications, (notification) => { - notification.action = mergeOrAdd(allStatuses, allStatusesObject, notification.action).item - notification.status = notification.status && mergeOrAdd(allStatuses, allStatusesObject, notification.status).item + if (notification.type !== 'follow') { + notification.action = mergeOrAdd(allStatuses, allStatusesObject, notification.action).item + notification.status = notification.status && mergeOrAdd(allStatuses, allStatusesObject, notification.status).item + } // Only add a new notification if we don't have one for the same action if (!state.notifications.idStore.hasOwnProperty(notification.id)) { @@ -292,15 +294,32 @@ const addNewNotifications = (state, { dispatch, notifications, older, visibleNot if ('Notification' in window && window.Notification.permission === 'granted') { const notifObj = {} - const action = notification.action - const title = action.user.name_html - notifObj.icon = action.user.profile_image_url - notifObj.body = action.text // there's a problem that it doesn't put a space before links tho + const status = notification.status + const title = notification.from_profile.name + notifObj.icon = notification.from_profile.profile_image_url + let i18nString + switch (notification.type) { + case 'like': + i18nString = 'favorited_you' + break + case 'repeat': + i18nString = 'repeated_you' + break + case 'follow': + i18nString = 'followed_you' + break + } + + if (i18nString) { + notifObj.body = rootGetters.i18n.t('notifications.' + i18nString) + } else { + notifObj.body = notification.status.text + } // Shows first attached non-nsfw image, if any. Should add configuration for this somehow... - if (action.attachments && action.attachments.length > 0 && !action.nsfw && - action.attachments[0].mimetype.startsWith('image/')) { - notifObj.image = action.attachments[0].url + if (status && status.attachments && status.attachments.length > 0 && !status.nsfw && + status.attachments[0].mimetype.startsWith('image/')) { + notifObj.image = status.attachments[0].url } if (!notification.seen && !state.notifications.desktopNotificationSilence && visibleNotificationTypes.includes(notification.type)) { @@ -413,8 +432,8 @@ const statuses = { addNewStatuses ({ rootState, commit }, { statuses, showImmediately = false, timeline = false, noIdUpdate = false, userId }) { commit('addNewStatuses', { statuses, showImmediately, timeline, noIdUpdate, user: rootState.users.currentUser, userId }) }, - addNewNotifications ({ rootState, commit, dispatch }, { notifications, older }) { - commit('addNewNotifications', { visibleNotificationTypes: visibleNotificationTypes(rootState), dispatch, notifications, older }) + addNewNotifications ({ rootState, commit, dispatch, rootGetters }, { notifications, older }) { + commit('addNewNotifications', { visibleNotificationTypes: visibleNotificationTypes(rootState), dispatch, notifications, older, rootGetters }) }, setError ({ rootState, commit }, { value }) { commit('setError', { value }) diff --git a/src/modules/users.js b/src/modules/users.js index 2c525526..1482de43 100644 --- a/src/modules/users.js +++ b/src/modules/users.js @@ -122,7 +122,9 @@ export const mutations = { status.user = state.usersObject[status.user.id] }, setUserForNotification (state, notification) { - notification.action.user = state.usersObject[notification.action.user.id] + if (notification.type !== 'follow') { + notification.action.user = state.usersObject[notification.action.user.id] + } notification.from_profile = state.usersObject[notification.from_profile.id] }, setColor (state, { user: { id }, highlighted }) { diff --git a/src/services/entity_normalizer/entity_normalizer.service.js b/src/services/entity_normalizer/entity_normalizer.service.js index 8e3cb066..923a7caf 100644 --- a/src/services/entity_normalizer/entity_normalizer.service.js +++ b/src/services/entity_normalizer/entity_normalizer.service.js @@ -39,7 +39,7 @@ export const parseUser = (data) => { return output } - // output.name = ??? missing + output.name = data.display_name output.name_html = addEmojis(data.display_name, data.emojis) // output.description = ??? missing @@ -260,17 +260,6 @@ export const parseStatus = (data) => { return output } -// This is for masto API only. -export const parseFollow = (data) => { - const output = {} - output.id = String(data.id) - output.visibility = true - output.created_at = new Date(data.created_at) - output.user = parseUser(data.account) - - return output -} - export const parseNotification = (data) => { const mastoDict = { 'favourite': 'like', @@ -283,7 +272,7 @@ export const parseNotification = (data) => { output.type = mastoDict[data.type] || data.type output.seen = data.pleroma.is_seen output.status = output.type === 'follow' - ? parseFollow(data) + ? null : parseStatus(data.status) output.action = output.status // TODO: Refactor, this is unneeded output.from_profile = parseUser(data.account) -- cgit v1.2.3-70-g09d2 From 787737c80d8b815209539f159449efee677bd5d9 Mon Sep 17 00:00:00 2001 From: taehoon Date: Tue, 2 Apr 2019 13:18:36 -0400 Subject: hide results on outside click --- package.json | 1 + src/components/user_autosuggest/user_autosuggest.js | 14 ++++++++++++-- src/components/user_autosuggest/user_autosuggest.vue | 4 ++-- src/main.js | 2 ++ yarn.lock | 4 ++++ 5 files changed, 21 insertions(+), 4 deletions(-) (limited to 'src/main.js') diff --git a/package.json b/package.json index c80e0f63..14937673 100644 --- a/package.json +++ b/package.json @@ -27,6 +27,7 @@ "popper.js": "^1.14.7", "sanitize-html": "^1.13.0", "sass-loader": "^4.0.2", + "v-click-outside": "^2.1.1", "vue": "^2.5.13", "vue-chat-scroll": "^1.2.1", "vue-compose": "^0.7.1", diff --git a/src/components/user_autosuggest/user_autosuggest.js b/src/components/user_autosuggest/user_autosuggest.js index eff6ef75..b99f61cc 100644 --- a/src/components/user_autosuggest/user_autosuggest.js +++ b/src/components/user_autosuggest/user_autosuggest.js @@ -11,7 +11,8 @@ export default { return { query: '', results: [], - timeout: null + timeout: null, + resultsVisible: false } }, watch: { @@ -26,9 +27,18 @@ export default { this.results = [] if (query) { userSearchApi.search({query, store: this.$store}) - .then((data) => { this.results = data }) + .then((data) => { + this.results = data + this.resultsVisible = true + }) } }, debounceMilliseconds) + }, + onInputClick () { + this.resultsVisible = true + }, + onClickOutside () { + this.resultsVisible = false } } } diff --git a/src/components/user_autosuggest/user_autosuggest.vue b/src/components/user_autosuggest/user_autosuggest.vue index 743d9eaf..eb5aa41b 100644 --- a/src/components/user_autosuggest/user_autosuggest.vue +++ b/src/components/user_autosuggest/user_autosuggest.vue @@ -1,7 +1,7 @@ diff --git a/src/components/checkbox/checkbox.js b/src/components/checkbox/checkbox.js new file mode 100644 index 00000000..324a7597 --- /dev/null +++ b/src/components/checkbox/checkbox.js @@ -0,0 +1,44 @@ +// TODO: Template-based functional component is supported in vue-loader 13.3.0+. +// Also, somehow, props are not provided through 'context' even though they are defined. +// Need to upgrade vue-loader + +import './checkbox.scss' + +export default { + functional: true, + name: 'Checkbox', + model: { + prop: 'checked', + event: 'change' + }, + render (createElement, { data, children }) { + const { props = {}, attrs = {}, on = {}, ...rest } = data + const { name, checked, disabled, readonly, ...restAttrs } = attrs + const { change, ...restListeners } = on + const wrapperProps = { + attrs: restAttrs, + on: restListeners, + ...rest + } + const inputProps = { + attrs: { + name, + checked, + disabled, + readonly, + ...props + }, + on: {} + } + if (change) { + inputProps.on.change = e => change(e.target.checked) + } + return ( + + ) + } +} diff --git a/src/components/checkbox/checkbox.scss b/src/components/checkbox/checkbox.scss new file mode 100644 index 00000000..07b3f39e --- /dev/null +++ b/src/components/checkbox/checkbox.scss @@ -0,0 +1,48 @@ +@import '../../_variables.scss'; + +.checkbox { + position: relative; + display: inline-block; + padding-left: 1.2em; + + input[type=checkbox] { + display: none; + + & + i::before { + position: absolute; + left: 0; + top: 0; + display: block; + content: '✔'; + transition: color 200ms; + width: 1.1em; + height: 1.1em; + border-radius: $fallback--checkboxRadius; + border-radius: var(--checkboxRadius, $fallback--checkboxRadius); + box-shadow: 0px 0px 2px black inset; + box-shadow: var(--inputShadow); + background-color: $fallback--fg; + background-color: var(--input, $fallback--fg); + vertical-align: top; + text-align: center; + line-height: 1.1em; + font-size: 1.1em; + color: transparent; + overflow: hidden; + box-sizing: border-box; + } + + &:checked + i::before { + color: $fallback--text; + color: var(--text, $fallback--text); + } + + &:disabled + i::before { + opacity: .5; + } + } + + & > span { + margin-left: .5em; + } +} \ No newline at end of file diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js index 1a100de3..7c6ffa89 100644 --- a/src/components/user_card/user_card.js +++ b/src/components/user_card/user_card.js @@ -151,6 +151,9 @@ export default { }, userProfileLink (user) { return generateProfileLink(user.id, user.screen_name, this.$store.state.instance.restrictedNicknames) + }, + reportUser () { + this.$store.dispatch('openUserReportingModal', this.user.id) } } } diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue index e62b384d..2d02ca03 100644 --- a/src/components/user_card/user_card.vue +++ b/src/components/user_card/user_card.vue @@ -99,8 +99,14 @@ - - +
+ + + +
+ diff --git a/src/components/user_reporting_modal/user_reporting_modal.js b/src/components/user_reporting_modal/user_reporting_modal.js new file mode 100644 index 00000000..fb9ea16d --- /dev/null +++ b/src/components/user_reporting_modal/user_reporting_modal.js @@ -0,0 +1,81 @@ + +import Status from '../status/status.vue' +import Checkbox from '../checkbox/checkbox.js' + +const UserReportingModal = { + components: { + Status, + Checkbox + }, + data () { + return { + comment: '', + forward: false, + statusIdsToReport: [] + } + }, + computed: { + isLoggedIn () { + return !!this.$store.state.users.currentUser + }, + isOpen () { + return this.isLoggedIn && this.$store.state.reports.modalActivated + }, + userId () { + return this.$store.state.reports.userId + }, + user () { + return this.$store.getters.findUser(this.userId) + }, + remoteInstance () { + return !this.user.is_local && this.user.screen_name.substr(this.user.screen_name.indexOf('@') + 1) + }, + statuses () { + return this.$store.state.reports.statuses + } + }, + watch: { + userId (value) { + this.statusIdsToReport = [] + } + }, + methods: { + closeModal () { + this.$store.dispatch('closeUserReportingModal') + }, + reportUser () { + const payload = { + comment: this.comment, + forward: this.forward, + statusIdsToReport: this.statusIdsToReport + } + this.$store.dispatch('reportUser', payload) + }, + isChecked (statusId) { + return this.statusIdsToReport.indexOf(statusId) !== -1 + }, + toggleStatus (checked, statusId) { + if (checked === this.isChecked(statusId)) { + return + } + + if (checked) { + this.statusIdsToReport.push(statusId) + } else { + this.statusIdsToReport.splice(this.statusIdsToReport.indexOf(statusId), 1) + } + }, + resize (e) { + const target = e.target || e + if (!(target instanceof window.Element)) { return } + // Auto is needed to make textbox shrink when removing lines + target.style.height = 'auto' + target.style.height = `${target.scrollHeight}px` + if (target.value === '') { + target.style.height = null + } + } + } +} + +export default UserReportingModal diff --git a/src/components/user_reporting_modal/user_reporting_modal.vue b/src/components/user_reporting_modal/user_reporting_modal.vue new file mode 100644 index 00000000..49839da3 --- /dev/null +++ b/src/components/user_reporting_modal/user_reporting_modal.vue @@ -0,0 +1,111 @@ +