logo

pleroma-fe

My custom branche(s) on git.pleroma.social/pleroma/pleroma-fe git clone https://anongit.hacktivis.me/git/pleroma-fe.git/
commit: eb7406c6635e476f633163bbfbcff26e6cb1964d
parent 08f8b975b68212dc2ff7616c1b3c163402327a6a
Author: Henry Jameson <me@hjkos.com>
Date:   Sat, 11 Jan 2025 20:02:53 +0200

extraButtons implementation

Diffstat:

Msrc/components/extra_buttons/extra_buttons.vue38++++++++++++++++++--------------------
Msrc/components/status/status.scss10++++------
Msrc/components/status_action_buttons/status_action_buttons.js82++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/components/status_action_buttons/status_action_buttons.vue80++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------
Msrc/modules/serverSideStorage.js21+++++++++++++++++++--
5 files changed, 181 insertions(+), 50 deletions(-)

diff --git a/src/components/extra_buttons/extra_buttons.vue b/src/components/extra_buttons/extra_buttons.vue @@ -166,26 +166,24 @@ </div> </template> <template #trigger> - <span class="button-unstyled popover-trigger"> - <FALayers class="fa-old-padding-layer"> - <FAIcon - class="fa-scale-110 " - icon="ellipsis-h" - /> - <FAIcon - v-show="!expanded" - class="focus-marker" - transform="shrink-6 up-8 right-16" - icon="plus" - /> - <FAIcon - v-show="expanded" - class="focus-marker" - transform="shrink-6 up-8 right-16" - icon="times" - /> - </FALayers> - </span> + <FALayers class="fa-old-padding-layer"> + <FAIcon + class="fa-scale-110 " + icon="ellipsis-h" + /> + <FAIcon + v-show="!expanded" + class="focus-marker" + transform="shrink-6 up-8 right-16" + icon="plus" + /> + <FAIcon + v-show="expanded" + class="focus-marker" + transform="shrink-6 up-8 right-16" + icon="times" + /> + </FALayers> <teleport to="#modal"> <ConfirmModal v-if="showingDeleteDialog" diff --git a/src/components/status/status.scss b/src/components/status/status.scss @@ -264,13 +264,11 @@ .status-actions { position: relative; width: 100%; - display: flex; + display: grid; + grid-template-columns: 1fr; + grid-auto-columns: 1fr; + grid-auto-flow: column; margin-top: var(--status-margin); - - > * { - max-width: 4em; - flex: 1; - } } .muted { diff --git a/src/components/status_action_buttons/status_action_buttons.js b/src/components/status_action_buttons/status_action_buttons.js @@ -1,17 +1,52 @@ -import ConfirmModal from '../confirm_modal/confirm_modal.vue' +import { mapState } from 'vuex' + +import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue' +import Popover from 'src/components/popover/popover.vue' +import genRandomSeed from 'src/services/random_seed/random_seed.service.js' + import { library } from '@fortawesome/fontawesome-svg-core' import { - faRetweet, faPlus, faMinus, - faCheck + faCheck, + faTimes, + + faReply, + faRetweet, + faStar, + faSmileBeam, + + faEllipsisH, + faBookmark, + faEyeSlash, + faThumbtack, + faShareAlt, + faExternalLinkAlt, + faHistory } from '@fortawesome/free-solid-svg-icons' +import { + faStar as faStarRegular +} from '@fortawesome/free-regular-svg-icons' library.add( - faRetweet, faPlus, faMinus, - faCheck + faCheck, + faTimes, + + faReply, + faRetweet, + faStar, + faStarRegular, + faSmileBeam, + + faEllipsisH, + faBookmark, + faEyeSlash, + faThumbtack, + faShareAlt, + faExternalLinkAlt, + faHistory ) const PRIVATE_SCOPES = new Set(['private', 'direct']) const PUBLIC_SCOPES = new Set(['public', 'unlisted']) @@ -27,6 +62,8 @@ const BUTTONS = [{ anon: true, anonLink: true, toggleable: true, + closeIndicator: 'times', + activeIndicator: 'none', action ({ emit }) { emit('toggleReplying') return Promise.resolve() @@ -230,7 +267,10 @@ const BUTTONS = [{ } }].map(button => { return Object.fromEntries( - Object.entries(button).map(([k, v]) => [k, typeof v === 'function' ? v : () => v]) + Object.entries(button).map(([k, v]) => [ + k, + (typeof v === 'function' || k === 'name') ? v : () => v + ]) ) }) @@ -243,15 +283,26 @@ const StatusActionButtons = { currentConfirmTitle: '', currentConfirmOkText: '', currentConfirmCancelText: '', - currentConfirmAction: () => {} + currentConfirmAction: () => {}, + randomSeed: genRandomSeed() } }, components: { + Popover, ConfirmModal }, computed: { + ...mapState({ + pinnedItems: state => new Set(state.serverSideStorage.prefsStorage.collections.pinnedStatusActions) + }), buttons () { - return BUTTONS.filter(x => x.if(this.funcArg)) + return BUTTONS.filter(x => x.if ? x.if(this.funcArg) : true) + }, + quickButtons () { + return this.buttons.filter(x => this.pinnedItems.has(x.name)) + }, + extraButtons () { + return this.buttons.filter(x => !this.pinnedItems.has(x.name)) }, funcArg () { return { @@ -265,6 +316,15 @@ const StatusActionButtons = { currentUser: this.$store.state.users.currentUser, loggedIn: !!this.$store.state.users.currentUser } + }, + triggerAttrs () { + return { + title: this.$t('status.more_actions'), + id: `popup-trigger-${this.randomSeed}`, + 'aria-controls': `popup-menu-${this.randomSeed}`, + 'aria-expanded': this.expanded, + 'aria-haspopup': 'menu' + } } }, methods: { @@ -272,7 +332,7 @@ const StatusActionButtons = { this.doActionReal(button) }, doActionReal (button) { - button.action(this.funcArg(button)) + button.action(this.funcArg) .then(() => this.$emit('onSuccess')) .catch(err => this.$emit('onError', err.error.error)) }, @@ -287,8 +347,8 @@ const StatusActionButtons = { }, getClass (button) { return { - [button.name() + '-button']: true, - '-active': button.active?.(this.funcArg()), + [button.name + '-button']: true, + '-active': button.active?.(this.funcArg), '-interactive': !!this.$store.state.users.currentUser } }, diff --git a/src/components/status_action_buttons/status_action_buttons.vue b/src/components/status_action_buttons/status_action_buttons.vue @@ -3,7 +3,7 @@ <span class="quick-action-buttons"> <span class="quick-action" - v-for="button in buttons" + v-for="button in quickButtons" :key="button.name" > <component @@ -23,16 +23,22 @@ /> <template v-if="button.toggleable?.(funcArg) && button.active"> <FAIcon - v-show="!button.active(funcArg)" + v-if="button.active(funcArg)" + class="active-marker" + transform="shrink-6 up-9 right-12" + :icon="button.activeIndicator?.(funcArg) || 'check'" + /> + <FAIcon + v-if="!button.active(funcArg)" class="focus-marker" - transform="shrink-6 up-9 right-17" - icon="plus" + transform="shrink-6 up-9 right-12" + :icon="button.openIndicator?.(funcArg) || 'plus'" /> <FAIcon - v-show="button.active(funcArg)" + v-else class="focus-marker" - transform="shrink-6 up-9 right-17" - icon="times" + transform="shrink-6 up-9 right-12" + :icon="button.closeIndicator?.(funcArg) || 'minus'" /> </template> </FALayers> @@ -44,7 +50,55 @@ {{ button.counter?.(funcArg) }} </span> </span> + <Popover + trigger="click" + :trigger-attrs="triggerAttrs" + :tabindex="0" + placement="top" + :offset="{ y: 5 }" + :bound-to="{ x: 'container2' }" + remove-padding + @show="onShow" + @close="onClose" + > + <template #trigger> + <span class="popover-trigger"> + <FALayers class="fa-old-padding-layer"> + <FAIcon + class="fa-scale-110 " + icon="ellipsis-h" + /> + </FALayers> + </span> + </template> + <template #content="{close}"> + <div + :id="`popup-menu-${randomSeed}`" + class="dropdown-menu" + role="menu" + > + <component + v-for="button in extraButtons" + :key="button.name" + :is="component(button)" + class="menu-item dropdown-item dropdown-item-icon" + role="menuitem" + :class="getClass(button)" + :tabindex="0" + @click.stop="component(button) === 'button' && doAction(button)" + @click="close" + :href="component(button) == 'a' ? button.link?.(funcArg) || getRemoteInteractionLink : undefined" + > + <FAIcon + class="fa-scale-110" + :icon="button.icon(funcArg)" + /><span>{{ $t(button.label(funcArg)) }}</span> + </component> + </div> + </template> + </Popover> </span> + <teleport to="#modal"> <confirm-modal v-if="showingConfirmDialog" @@ -66,11 +120,7 @@ @import "../../mixins"; .StatusActionButtons { - width: 100%; - .quick-action-buttons { - position: relative; - width: 100%; display: grid; grid-template-columns: 1fr; grid-auto-flow: column; @@ -121,12 +171,20 @@ .focus-marker { visibility: hidden; } + + .active-marker { + visibility: visible; + } } @include focused-style { .focus-marker { visibility: visible; } + + .active-marker { + visibility: hidden; + } } } } diff --git a/src/modules/serverSideStorage.js b/src/modules/serverSideStorage.js @@ -1,5 +1,17 @@ import { toRaw } from 'vue' -import { isEqual, cloneDeep, set, get, clamp, flatten, groupBy, findLastIndex, takeRight, uniqWith } from 'lodash' +import { + isEqual, + cloneDeep, + set, + get, + clamp, + flatten, + groupBy, + findLastIndex, + takeRight, + uniqWith, + merge +} from 'lodash' import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js' export const VERSION = 1 @@ -26,6 +38,7 @@ export const defaultState = { collapseNav: false }, collections: { + pinnedStatusActions: ['reply', 'retweet', 'favorite', 'emoji'], pinnedNavItems: ['home', 'dms', 'chats'] } }, @@ -110,7 +123,11 @@ export const _getRecentData = (cache, live) => { console.debug('Both sources are invalid, start from scratch') result.needUpload = true } - return result + + result.recent = merge(defaultState, result.recent) + result.stale = merge(defaultState, result.stale) + + return merge(defaultState, result) } export const _getAllFlags = (recent, stale) => {