extraButtons implementation
This commit is contained in:
parent
08f8b975b6
commit
eb7406c663
5 changed files with 182 additions and 51 deletions
|
@ -166,7 +166,6 @@
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
<template #trigger>
|
<template #trigger>
|
||||||
<span class="button-unstyled popover-trigger">
|
|
||||||
<FALayers class="fa-old-padding-layer">
|
<FALayers class="fa-old-padding-layer">
|
||||||
<FAIcon
|
<FAIcon
|
||||||
class="fa-scale-110 "
|
class="fa-scale-110 "
|
||||||
|
@ -185,7 +184,6 @@
|
||||||
icon="times"
|
icon="times"
|
||||||
/>
|
/>
|
||||||
</FALayers>
|
</FALayers>
|
||||||
</span>
|
|
||||||
<teleport to="#modal">
|
<teleport to="#modal">
|
||||||
<ConfirmModal
|
<ConfirmModal
|
||||||
v-if="showingDeleteDialog"
|
v-if="showingDeleteDialog"
|
||||||
|
|
|
@ -264,13 +264,11 @@
|
||||||
.status-actions {
|
.status-actions {
|
||||||
position: relative;
|
position: relative;
|
||||||
width: 100%;
|
width: 100%;
|
||||||
display: flex;
|
display: grid;
|
||||||
|
grid-template-columns: 1fr;
|
||||||
|
grid-auto-columns: 1fr;
|
||||||
|
grid-auto-flow: column;
|
||||||
margin-top: var(--status-margin);
|
margin-top: var(--status-margin);
|
||||||
|
|
||||||
> * {
|
|
||||||
max-width: 4em;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.muted {
|
.muted {
|
||||||
|
|
|
@ -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 { library } from '@fortawesome/fontawesome-svg-core'
|
||||||
import {
|
import {
|
||||||
faRetweet,
|
|
||||||
faPlus,
|
faPlus,
|
||||||
faMinus,
|
faMinus,
|
||||||
faCheck
|
faCheck,
|
||||||
|
faTimes,
|
||||||
|
|
||||||
|
faReply,
|
||||||
|
faRetweet,
|
||||||
|
faStar,
|
||||||
|
faSmileBeam,
|
||||||
|
|
||||||
|
faEllipsisH,
|
||||||
|
faBookmark,
|
||||||
|
faEyeSlash,
|
||||||
|
faThumbtack,
|
||||||
|
faShareAlt,
|
||||||
|
faExternalLinkAlt,
|
||||||
|
faHistory
|
||||||
} from '@fortawesome/free-solid-svg-icons'
|
} from '@fortawesome/free-solid-svg-icons'
|
||||||
|
import {
|
||||||
|
faStar as faStarRegular
|
||||||
|
} from '@fortawesome/free-regular-svg-icons'
|
||||||
|
|
||||||
library.add(
|
library.add(
|
||||||
faRetweet,
|
|
||||||
faPlus,
|
faPlus,
|
||||||
faMinus,
|
faMinus,
|
||||||
faCheck
|
faCheck,
|
||||||
|
faTimes,
|
||||||
|
|
||||||
|
faReply,
|
||||||
|
faRetweet,
|
||||||
|
faStar,
|
||||||
|
faStarRegular,
|
||||||
|
faSmileBeam,
|
||||||
|
|
||||||
|
faEllipsisH,
|
||||||
|
faBookmark,
|
||||||
|
faEyeSlash,
|
||||||
|
faThumbtack,
|
||||||
|
faShareAlt,
|
||||||
|
faExternalLinkAlt,
|
||||||
|
faHistory
|
||||||
)
|
)
|
||||||
const PRIVATE_SCOPES = new Set(['private', 'direct'])
|
const PRIVATE_SCOPES = new Set(['private', 'direct'])
|
||||||
const PUBLIC_SCOPES = new Set(['public', 'unlisted'])
|
const PUBLIC_SCOPES = new Set(['public', 'unlisted'])
|
||||||
|
@ -27,6 +62,8 @@ const BUTTONS = [{
|
||||||
anon: true,
|
anon: true,
|
||||||
anonLink: true,
|
anonLink: true,
|
||||||
toggleable: true,
|
toggleable: true,
|
||||||
|
closeIndicator: 'times',
|
||||||
|
activeIndicator: 'none',
|
||||||
action ({ emit }) {
|
action ({ emit }) {
|
||||||
emit('toggleReplying')
|
emit('toggleReplying')
|
||||||
return Promise.resolve()
|
return Promise.resolve()
|
||||||
|
@ -230,7 +267,10 @@ const BUTTONS = [{
|
||||||
}
|
}
|
||||||
}].map(button => {
|
}].map(button => {
|
||||||
return Object.fromEntries(
|
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: '',
|
currentConfirmTitle: '',
|
||||||
currentConfirmOkText: '',
|
currentConfirmOkText: '',
|
||||||
currentConfirmCancelText: '',
|
currentConfirmCancelText: '',
|
||||||
currentConfirmAction: () => {}
|
currentConfirmAction: () => {},
|
||||||
|
randomSeed: genRandomSeed()
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
components: {
|
components: {
|
||||||
|
Popover,
|
||||||
ConfirmModal
|
ConfirmModal
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
|
...mapState({
|
||||||
|
pinnedItems: state => new Set(state.serverSideStorage.prefsStorage.collections.pinnedStatusActions)
|
||||||
|
}),
|
||||||
buttons () {
|
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 () {
|
funcArg () {
|
||||||
return {
|
return {
|
||||||
|
@ -265,6 +316,15 @@ const StatusActionButtons = {
|
||||||
currentUser: this.$store.state.users.currentUser,
|
currentUser: this.$store.state.users.currentUser,
|
||||||
loggedIn: !!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: {
|
methods: {
|
||||||
|
@ -272,7 +332,7 @@ const StatusActionButtons = {
|
||||||
this.doActionReal(button)
|
this.doActionReal(button)
|
||||||
},
|
},
|
||||||
doActionReal (button) {
|
doActionReal (button) {
|
||||||
button.action(this.funcArg(button))
|
button.action(this.funcArg)
|
||||||
.then(() => this.$emit('onSuccess'))
|
.then(() => this.$emit('onSuccess'))
|
||||||
.catch(err => this.$emit('onError', err.error.error))
|
.catch(err => this.$emit('onError', err.error.error))
|
||||||
},
|
},
|
||||||
|
@ -287,8 +347,8 @@ const StatusActionButtons = {
|
||||||
},
|
},
|
||||||
getClass (button) {
|
getClass (button) {
|
||||||
return {
|
return {
|
||||||
[button.name() + '-button']: true,
|
[button.name + '-button']: true,
|
||||||
'-active': button.active?.(this.funcArg()),
|
'-active': button.active?.(this.funcArg),
|
||||||
'-interactive': !!this.$store.state.users.currentUser
|
'-interactive': !!this.$store.state.users.currentUser
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
<span class="quick-action-buttons">
|
<span class="quick-action-buttons">
|
||||||
<span
|
<span
|
||||||
class="quick-action"
|
class="quick-action"
|
||||||
v-for="button in buttons"
|
v-for="button in quickButtons"
|
||||||
:key="button.name"
|
:key="button.name"
|
||||||
>
|
>
|
||||||
<component
|
<component
|
||||||
|
@ -23,16 +23,22 @@
|
||||||
/>
|
/>
|
||||||
<template v-if="button.toggleable?.(funcArg) && button.active">
|
<template v-if="button.toggleable?.(funcArg) && button.active">
|
||||||
<FAIcon
|
<FAIcon
|
||||||
v-show="!button.active(funcArg)"
|
v-if="button.active(funcArg)"
|
||||||
class="focus-marker"
|
class="active-marker"
|
||||||
transform="shrink-6 up-9 right-17"
|
transform="shrink-6 up-9 right-12"
|
||||||
icon="plus"
|
:icon="button.activeIndicator?.(funcArg) || 'check'"
|
||||||
/>
|
/>
|
||||||
<FAIcon
|
<FAIcon
|
||||||
v-show="button.active(funcArg)"
|
v-if="!button.active(funcArg)"
|
||||||
class="focus-marker"
|
class="focus-marker"
|
||||||
transform="shrink-6 up-9 right-17"
|
transform="shrink-6 up-9 right-12"
|
||||||
icon="times"
|
:icon="button.openIndicator?.(funcArg) || 'plus'"
|
||||||
|
/>
|
||||||
|
<FAIcon
|
||||||
|
v-else
|
||||||
|
class="focus-marker"
|
||||||
|
transform="shrink-6 up-9 right-12"
|
||||||
|
:icon="button.closeIndicator?.(funcArg) || 'minus'"
|
||||||
/>
|
/>
|
||||||
</template>
|
</template>
|
||||||
</FALayers>
|
</FALayers>
|
||||||
|
@ -44,7 +50,55 @@
|
||||||
{{ button.counter?.(funcArg) }}
|
{{ button.counter?.(funcArg) }}
|
||||||
</span>
|
</span>
|
||||||
</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>
|
</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">
|
<teleport to="#modal">
|
||||||
<confirm-modal
|
<confirm-modal
|
||||||
v-if="showingConfirmDialog"
|
v-if="showingConfirmDialog"
|
||||||
|
@ -66,11 +120,7 @@
|
||||||
@import "../../mixins";
|
@import "../../mixins";
|
||||||
|
|
||||||
.StatusActionButtons {
|
.StatusActionButtons {
|
||||||
width: 100%;
|
|
||||||
|
|
||||||
.quick-action-buttons {
|
.quick-action-buttons {
|
||||||
position: relative;
|
|
||||||
width: 100%;
|
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr;
|
grid-template-columns: 1fr;
|
||||||
grid-auto-flow: column;
|
grid-auto-flow: column;
|
||||||
|
@ -121,12 +171,20 @@
|
||||||
.focus-marker {
|
.focus-marker {
|
||||||
visibility: hidden;
|
visibility: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.active-marker {
|
||||||
|
visibility: visible;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@include focused-style {
|
@include focused-style {
|
||||||
.focus-marker {
|
.focus-marker {
|
||||||
visibility: visible;
|
visibility: visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.active-marker {
|
||||||
|
visibility: hidden;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,17 @@
|
||||||
import { toRaw } from 'vue'
|
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'
|
import { CURRENT_UPDATE_COUNTER } from 'src/components/update_notification/update_notification.js'
|
||||||
|
|
||||||
export const VERSION = 1
|
export const VERSION = 1
|
||||||
|
@ -26,6 +38,7 @@ export const defaultState = {
|
||||||
collapseNav: false
|
collapseNav: false
|
||||||
},
|
},
|
||||||
collections: {
|
collections: {
|
||||||
|
pinnedStatusActions: ['reply', 'retweet', 'favorite', 'emoji'],
|
||||||
pinnedNavItems: ['home', 'dms', 'chats']
|
pinnedNavItems: ['home', 'dms', 'chats']
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -110,7 +123,11 @@ export const _getRecentData = (cache, live) => {
|
||||||
console.debug('Both sources are invalid, start from scratch')
|
console.debug('Both sources are invalid, start from scratch')
|
||||||
result.needUpload = true
|
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) => {
|
export const _getAllFlags = (recent, stale) => {
|
||||||
|
|
Loading…
Add table
Reference in a new issue