logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe
commit: ccba92a27cc96d6db9b28d456f6fff6cb6804a52
parent: 61bb02ef0631b534e1a80a3b08f0e27c1a1c8e66
Author: Shpuld Shpludson <shp@cock.li>
Date:   Wed, 25 Sep 2019 06:41:26 +0000

Merge branch '639-2' into 'develop'

Add "Mention user" button to user card

Closes #639

See merge request pleroma/pleroma-fe!955

Diffstat:

Msrc/App.js8+++++---
Msrc/App.vue3++-
Asrc/components/mobile_post_status_button/mobile_post_status_button.js93+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Asrc/components/mobile_post_status_button/mobile_post_status_button.vue55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Dsrc/components/mobile_post_status_modal/mobile_post_status_modal.js108-------------------------------------------------------------------------------
Dsrc/components/mobile_post_status_modal/mobile_post_status_modal.vue89-------------------------------------------------------------------------------
Msrc/components/post_status_form/post_status_form.js2+-
Asrc/components/post_status_modal/post_status_modal.js32++++++++++++++++++++++++++++++++
Asrc/components/post_status_modal/post_status_modal.vue43+++++++++++++++++++++++++++++++++++++++++++
Msrc/components/user_card/user_card.js3+++
Msrc/components/user_card/user_card.vue9+++++++++
Msrc/components/user_panel/user_panel.vue2+-
Msrc/i18n/en.json1+
Msrc/main.js4+++-
Asrc/modules/postStatus.js25+++++++++++++++++++++++++
15 files changed, 273 insertions(+), 204 deletions(-)

diff --git a/src/App.js b/src/App.js @@ -8,9 +8,10 @@ import WhoToFollowPanel from './components/who_to_follow_panel/who_to_follow_pan import ChatPanel from './components/chat_panel/chat_panel.vue' import MediaModal from './components/media_modal/media_modal.vue' import SideDrawer from './components/side_drawer/side_drawer.vue' -import MobilePostStatusModal from './components/mobile_post_status_modal/mobile_post_status_modal.vue' +import MobilePostStatusButton from './components/mobile_post_status_button/mobile_post_status_button.vue' import MobileNav from './components/mobile_nav/mobile_nav.vue' import UserReportingModal from './components/user_reporting_modal/user_reporting_modal.vue' +import PostStatusModal from './components/post_status_modal/post_status_modal.vue' import { windowWidth } from './services/window_utils/window_utils' export default { @@ -26,9 +27,10 @@ export default { ChatPanel, MediaModal, SideDrawer, - MobilePostStatusModal, + MobilePostStatusButton, MobileNav, - UserReportingModal + UserReportingModal, + PostStatusModal }, data: () => ({ mobileActivePanel: 'timeline', diff --git a/src/App.vue b/src/App.vue @@ -107,8 +107,9 @@ :floating="true" class="floating-chat mobile-hidden" /> - <MobilePostStatusModal /> + <MobilePostStatusButton /> <UserReportingModal /> + <PostStatusModal /> <portal-target name="modal" /> </div> </template> diff --git a/src/components/mobile_post_status_button/mobile_post_status_button.js b/src/components/mobile_post_status_button/mobile_post_status_button.js @@ -0,0 +1,93 @@ +import { debounce } from 'lodash' + +const MobilePostStatusButton = { + data () { + return { + hidden: false, + scrollingDown: false, + inputActive: false, + oldScrollPos: 0, + amountScrolled: 0 + } + }, + created () { + if (this.autohideFloatingPostButton) { + this.activateFloatingPostButtonAutohide() + } + window.addEventListener('resize', this.handleOSK) + }, + destroyed () { + if (this.autohideFloatingPostButton) { + this.deactivateFloatingPostButtonAutohide() + } + window.removeEventListener('resize', this.handleOSK) + }, + computed: { + isLoggedIn () { + return !!this.$store.state.users.currentUser + }, + isHidden () { + return this.autohideFloatingPostButton && (this.hidden || this.inputActive) + }, + autohideFloatingPostButton () { + return !!this.$store.state.config.autohideFloatingPostButton + } + }, + watch: { + autohideFloatingPostButton: function (isEnabled) { + if (isEnabled) { + this.activateFloatingPostButtonAutohide() + } else { + this.deactivateFloatingPostButtonAutohide() + } + } + }, + methods: { + activateFloatingPostButtonAutohide () { + window.addEventListener('scroll', this.handleScrollStart) + window.addEventListener('scroll', this.handleScrollEnd) + }, + deactivateFloatingPostButtonAutohide () { + window.removeEventListener('scroll', this.handleScrollStart) + window.removeEventListener('scroll', this.handleScrollEnd) + }, + openPostForm () { + this.$store.dispatch('openPostStatusModal') + }, + handleOSK () { + // This is a big hack: we're guessing from changed window sizes if the + // on-screen keyboard is active or not. This is only really important + // for phones in portrait mode and it's more important to show the button + // in normal scenarios on all phones, than it is to hide it when the + // keyboard is active. + // Guesswork based on https://www.mydevice.io/#compare-devices + + // for example, iphone 4 and android phones from the same time period + const smallPhone = window.innerWidth < 350 + const smallPhoneKbOpen = smallPhone && window.innerHeight < 345 + + const biggerPhone = !smallPhone && window.innerWidth < 450 + const biggerPhoneKbOpen = biggerPhone && window.innerHeight < 560 + if (smallPhoneKbOpen || biggerPhoneKbOpen) { + this.inputActive = true + } else { + this.inputActive = false + } + }, + handleScrollStart: debounce(function () { + if (window.scrollY > this.oldScrollPos) { + this.hidden = true + } else { + this.hidden = false + } + this.oldScrollPos = window.scrollY + }, 100, { leading: true, trailing: false }), + + handleScrollEnd: debounce(function () { + this.hidden = false + this.oldScrollPos = window.scrollY + }, 100, { leading: false, trailing: true }) + } +} + +export default MobilePostStatusButton diff --git a/src/components/mobile_post_status_button/mobile_post_status_button.vue b/src/components/mobile_post_status_button/mobile_post_status_button.vue @@ -0,0 +1,55 @@ +<template> + <div v-if="isLoggedIn"> + <button + class="new-status-button" + :class="{ 'hidden': isHidden }" + @click="openPostForm" + > + <i class="icon-edit" /> + </button> + </div> +</template> + +<script src="./mobile_post_status_button.js"></script> + +<style lang="scss"> +@import '../../_variables.scss'; + +.new-status-button { + width: 5em; + height: 5em; + border-radius: 100%; + position: fixed; + bottom: 1.5em; + right: 1.5em; + // TODO: this needs its own color, it has to stand out enough and link color + // is not very optimal for this particular use. + background-color: $fallback--fg; + background-color: var(--btn, $fallback--fg); + display: flex; + justify-content: center; + align-items: center; + box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3), 0px 4px 6px rgba(0, 0, 0, 0.3); + z-index: 10; + + transition: 0.35s transform; + transition-timing-function: cubic-bezier(0, 1, 0.5, 1); + + &.hidden { + transform: translateY(150%); + } + + i { + font-size: 1.5em; + color: $fallback--text; + color: var(--text, $fallback--text); + } +} + +@media all and (min-width: 801px) { + .new-status-button { + display: none; + } +} + +</style> diff --git a/src/components/mobile_post_status_modal/mobile_post_status_modal.js b/src/components/mobile_post_status_modal/mobile_post_status_modal.js @@ -1,108 +0,0 @@ -import PostStatusForm from '../post_status_form/post_status_form.vue' -import { debounce } from 'lodash' - -const MobilePostStatusModal = { - components: { - PostStatusForm - }, - data () { - return { - hidden: false, - postFormOpen: false, - scrollingDown: false, - inputActive: false, - oldScrollPos: 0, - amountScrolled: 0 - } - }, - created () { - if (this.autohideFloatingPostButton) { - this.activateFloatingPostButtonAutohide() - } - window.addEventListener('resize', this.handleOSK) - }, - destroyed () { - if (this.autohideFloatingPostButton) { - this.deactivateFloatingPostButtonAutohide() - } - window.removeEventListener('resize', this.handleOSK) - }, - computed: { - currentUser () { - return this.$store.state.users.currentUser - }, - isHidden () { - return this.autohideFloatingPostButton && (this.hidden || this.inputActive) - }, - autohideFloatingPostButton () { - return !!this.$store.state.config.autohideFloatingPostButton - } - }, - watch: { - autohideFloatingPostButton: function (isEnabled) { - if (isEnabled) { - this.activateFloatingPostButtonAutohide() - } else { - this.deactivateFloatingPostButtonAutohide() - } - } - }, - methods: { - activateFloatingPostButtonAutohide () { - window.addEventListener('scroll', this.handleScrollStart) - window.addEventListener('scroll', this.handleScrollEnd) - }, - deactivateFloatingPostButtonAutohide () { - window.removeEventListener('scroll', this.handleScrollStart) - window.removeEventListener('scroll', this.handleScrollEnd) - }, - openPostForm () { - this.postFormOpen = true - this.hidden = true - - const el = this.$el.querySelector('textarea') - this.$nextTick(function () { - el.focus() - }) - }, - closePostForm () { - this.postFormOpen = false - this.hidden = false - }, - handleOSK () { - // This is a big hack: we're guessing from changed window sizes if the - // on-screen keyboard is active or not. This is only really important - // for phones in portrait mode and it's more important to show the button - // in normal scenarios on all phones, than it is to hide it when the - // keyboard is active. - // Guesswork based on https://www.mydevice.io/#compare-devices - - // for example, iphone 4 and android phones from the same time period - const smallPhone = window.innerWidth < 350 - const smallPhoneKbOpen = smallPhone && window.innerHeight < 345 - - const biggerPhone = !smallPhone && window.innerWidth < 450 - const biggerPhoneKbOpen = biggerPhone && window.innerHeight < 560 - if (smallPhoneKbOpen || biggerPhoneKbOpen) { - this.inputActive = true - } else { - this.inputActive = false - } - }, - handleScrollStart: debounce(function () { - if (window.scrollY > this.oldScrollPos) { - this.hidden = true - } else { - this.hidden = false - } - this.oldScrollPos = window.scrollY - }, 100, { leading: true, trailing: false }), - - handleScrollEnd: debounce(function () { - this.hidden = false - this.oldScrollPos = window.scrollY - }, 100, { leading: false, trailing: true }) - } -} - -export default MobilePostStatusModal diff --git a/src/components/mobile_post_status_modal/mobile_post_status_modal.vue b/src/components/mobile_post_status_modal/mobile_post_status_modal.vue @@ -1,89 +0,0 @@ -<template> - <div v-if="currentUser"> - <div - v-show="postFormOpen" - class="post-form-modal-view modal-view" - @click="closePostForm" - > - <div - class="post-form-modal-panel panel" - @click.stop="" - > - <div class="panel-heading"> - {{ $t('post_status.new_status') }} - </div> - <PostStatusForm - class="panel-body" - @posted="closePostForm" - /> - </div> - </div> - <button - class="new-status-button" - :class="{ 'hidden': isHidden }" - @click="openPostForm" - > - <i class="icon-edit" /> - </button> - </div> -</template> - -<script src="./mobile_post_status_modal.js"></script> - -<style lang="scss"> -@import '../../_variables.scss'; - -.post-form-modal-view { - align-items: flex-start; -} - -.post-form-modal-panel { - flex-shrink: 0; - margin-top: 25%; - margin-bottom: 2em; - width: 100%; - max-width: 700px; - - @media (orientation: landscape) { - margin-top: 8%; - } -} - -.new-status-button { - width: 5em; - height: 5em; - border-radius: 100%; - position: fixed; - bottom: 1.5em; - right: 1.5em; - // TODO: this needs its own color, it has to stand out enough and link color - // is not very optimal for this particular use. - background-color: $fallback--fg; - background-color: var(--btn, $fallback--fg); - display: flex; - justify-content: center; - align-items: center; - box-shadow: 0px 2px 2px rgba(0, 0, 0, 0.3), 0px 4px 6px rgba(0, 0, 0, 0.3); - z-index: 10; - - transition: 0.35s transform; - transition-timing-function: cubic-bezier(0, 1, 0.5, 1); - - &.hidden { - transform: translateY(150%); - } - - i { - font-size: 1.5em; - color: $fallback--text; - color: var(--text, $fallback--text); - } -} - -@media all and (min-width: 801px) { - .new-status-button { - display: none; - } -} - -</style> diff --git a/src/components/post_status_form/post_status_form.js b/src/components/post_status_form/post_status_form.js @@ -8,7 +8,7 @@ import fileTypeService from '../../services/file_type/file_type.service.js' import { reject, map, uniqBy } from 'lodash' import suggestor from '../emoji-input/suggestor.js' -const buildMentionsString = ({ user, attentions }, currentUser) => { +const buildMentionsString = ({ user, attentions = [] }, currentUser) => { let allAttentions = [...attentions] allAttentions.unshift(user) diff --git a/src/components/post_status_modal/post_status_modal.js b/src/components/post_status_modal/post_status_modal.js @@ -0,0 +1,32 @@ +import PostStatusForm from '../post_status_form/post_status_form.vue' + +const PostStatusModal = { + components: { + PostStatusForm + }, + computed: { + isLoggedIn () { + return !!this.$store.state.users.currentUser + }, + isOpen () { + return this.isLoggedIn && this.$store.state.postStatus.modalActivated + }, + params () { + return this.$store.state.postStatus.params || {} + } + }, + watch: { + isOpen (val) { + if (val) { + this.$nextTick(() => this.$el.querySelector('textarea').focus()) + } + } + }, + methods: { + closeModal () { + this.$store.dispatch('closePostStatusModal') + } + } +} + +export default PostStatusModal diff --git a/src/components/post_status_modal/post_status_modal.vue b/src/components/post_status_modal/post_status_modal.vue @@ -0,0 +1,43 @@ +<template> + <div + v-if="isOpen" + class="post-form-modal-view modal-view" + @click="closeModal" + > + <div + class="post-form-modal-panel panel" + @click.stop="" + > + <div class="panel-heading"> + {{ $t('post_status.new_status') }} + </div> + <PostStatusForm + class="panel-body" + v-bind="params" + @posted="closeModal" + /> + </div> + </div> +</template> + +<script src="./post_status_modal.js"></script> + +<style lang="scss"> +@import '../../_variables.scss'; + +.post-form-modal-view { + align-items: flex-start; +} + +.post-form-modal-panel { + flex-shrink: 0; + margin-top: 25%; + margin-bottom: 2em; + width: 100%; + max-width: 700px; + + @media (orientation: landscape) { + margin-top: 8%; + } +} +</style> diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js @@ -168,6 +168,9 @@ export default { } this.$store.dispatch('setMedia', [attachment]) this.$store.dispatch('setCurrent', attachment) + }, + mentionUser () { + this.$store.dispatch('openPostStatusModal', { replyTo: true, repliedUser: this.user }) } } } diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue @@ -190,6 +190,15 @@ <div> <button + class="btn btn-default btn-block" + @click="mentionUser" + > + {{ $t('user_card.mention') }} + </button> + </div> + + <div> + <button v-if="user.muted" class="btn btn-default btn-block pressed" @click="unmuteUser" diff --git a/src/components/user_panel/user_panel.vue b/src/components/user_panel/user_panel.vue @@ -11,7 +11,7 @@ rounded="top" /> <div class="panel-footer"> - <post-status-form v-if="user" /> + <post-status-form /> </div> </div> <auth-form diff --git a/src/i18n/en.json b/src/i18n/en.json @@ -529,6 +529,7 @@ "follows_you": "Follows you!", "its_you": "It's you!", "media": "Media", + "mention": "Mention", "mute": "Mute", "muted": "Muted", "per_day": "per day", diff --git a/src/main.js b/src/main.js @@ -15,6 +15,7 @@ import mediaViewerModule from './modules/media_viewer.js' import oauthTokensModule from './modules/oauth_tokens.js' import reportsModule from './modules/reports.js' import pollsModule from './modules/polls.js' +import postStatusModule from './modules/postStatus.js' import VueI18n from 'vue-i18n' @@ -76,7 +77,8 @@ const persistedStateOptions = { mediaViewer: mediaViewerModule, oauthTokens: oauthTokensModule, reports: reportsModule, - polls: pollsModule + polls: pollsModule, + postStatus: postStatusModule }, plugins: [persistedState, pushNotifications], strict: false // Socket modifies itself, let's ignore this for now. diff --git a/src/modules/postStatus.js b/src/modules/postStatus.js @@ -0,0 +1,25 @@ +const postStatus = { + state: { + params: null, + modalActivated: false + }, + mutations: { + openPostStatusModal (state, params) { + state.params = params + state.modalActivated = true + }, + closePostStatusModal (state) { + state.modalActivated = false + } + }, + actions: { + openPostStatusModal ({ commit }, params) { + commit('openPostStatusModal', params) + }, + closePostStatusModal ({ commit }) { + commit('closePostStatusModal') + } + } +} + +export default postStatus