abstraction, made popover optional, initial markup for better mute options
This commit is contained in:
parent
5a085d8e36
commit
b831f34c06
9 changed files with 248 additions and 265 deletions
83
src/components/status_action_buttons/action_button.js
Normal file
83
src/components/status_action_buttons/action_button.js
Normal file
|
@ -0,0 +1,83 @@
|
|||
import StatusBookmarkFolderMenu from 'src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue'
|
||||
import Popover from 'src/components/popover/popover.vue'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faPlus,
|
||||
faMinus,
|
||||
faCheck,
|
||||
faTimes,
|
||||
faWrench,
|
||||
|
||||
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(
|
||||
faPlus,
|
||||
faMinus,
|
||||
faCheck,
|
||||
faTimes,
|
||||
faWrench,
|
||||
|
||||
faReply,
|
||||
faRetweet,
|
||||
faStar,
|
||||
faStarRegular,
|
||||
faSmileBeam,
|
||||
|
||||
faEllipsisH,
|
||||
faBookmark,
|
||||
faEyeSlash,
|
||||
faThumbtack,
|
||||
faShareAlt,
|
||||
faExternalLinkAlt,
|
||||
faHistory
|
||||
)
|
||||
|
||||
export default {
|
||||
props: [
|
||||
'button',
|
||||
'extra',
|
||||
'status',
|
||||
'funcArg',
|
||||
'animationState',
|
||||
'getClass',
|
||||
'getComponent',
|
||||
'doAction',
|
||||
'close'
|
||||
],
|
||||
components: {
|
||||
StatusBookmarkFolderMenu,
|
||||
Popover
|
||||
},
|
||||
computed: {
|
||||
buttonClass () {
|
||||
if (!this.extra) console.log(this.button.name)
|
||||
return [
|
||||
this.button.name + '-button',
|
||||
{
|
||||
'main-button': this.extra,
|
||||
'button-unstyled': !this.extra,
|
||||
'-extra': this.extra,
|
||||
'-quick': !this.extra,
|
||||
'-active': this.button.active?.(this.funcArg),
|
||||
disabled: this.button.interactive ? !this.button.interactive(this.funcArg) : false
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,12 @@
|
|||
/* stylelint-disable declaration-no-important */
|
||||
|
||||
.action-button {
|
||||
display: grid;
|
||||
|
||||
&.-with-extra {
|
||||
grid-template-columns: 1fr calc(var(--__line-height) + 2 * var(--__horizontal-gap));
|
||||
}
|
||||
|
||||
&.-quick {
|
||||
display: grid;
|
||||
grid-template-columns: max-content auto;
|
||||
|
|
|
@ -1,8 +1,11 @@
|
|||
<template>
|
||||
<div>
|
||||
<div
|
||||
class="action-button"
|
||||
:class="{ '-with-extra': button.name === 'bookmark' }"
|
||||
>
|
||||
<component
|
||||
:is="getComponent(button)"
|
||||
class="main-button action-button"
|
||||
class="action-button-inner"
|
||||
:class="buttonClass"
|
||||
role="menuitem"
|
||||
:tabindex="0"
|
||||
|
@ -38,90 +41,48 @@
|
|||
:icon="button.closeIndicator?.(funcArg) || 'minus'"
|
||||
/>
|
||||
</template>
|
||||
</FALayers><span>{{ $t(button.label(funcArg)) }}</span>
|
||||
</FALayers>
|
||||
<span
|
||||
v-if="extra"
|
||||
class="action-label"
|
||||
>
|
||||
{{ $t(button.label(funcArg)) }}
|
||||
</span>
|
||||
<span
|
||||
v-if="!extra && button.counter?.(funcArg) > 0"
|
||||
class="action-counter"
|
||||
>
|
||||
{{ button.counter?.(funcArg) }}
|
||||
</span>
|
||||
<FAIcon
|
||||
v-if="button.name === 'mute'"
|
||||
v-if="button.dropdown?.()"
|
||||
class="chevron-icon"
|
||||
size="lg"
|
||||
icon="chevron-right"
|
||||
fixed-width
|
||||
/>
|
||||
</component>
|
||||
<Popover
|
||||
trigger="hover"
|
||||
placement="right"
|
||||
:trigger-attrs="{ class: 'extra-button' }"
|
||||
v-if="button.name === 'bookmark'"
|
||||
>
|
||||
<template #trigger>
|
||||
<FAIcon
|
||||
class="chevron-icon"
|
||||
size="lg"
|
||||
icon="chevron-right"
|
||||
fixed-width
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<StatusBookmarkFolderMenu v-if="button.name === 'bookmark'" :status="$attrs.status" />
|
||||
</template>
|
||||
</Popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faPlus,
|
||||
faMinus,
|
||||
faCheck,
|
||||
faTimes,
|
||||
faWrench,
|
||||
|
||||
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(
|
||||
faPlus,
|
||||
faMinus,
|
||||
faCheck,
|
||||
faTimes,
|
||||
faWrench,
|
||||
|
||||
faReply,
|
||||
faRetweet,
|
||||
faStar,
|
||||
faStarRegular,
|
||||
faSmileBeam,
|
||||
|
||||
faEllipsisH,
|
||||
faBookmark,
|
||||
faEyeSlash,
|
||||
faThumbtack,
|
||||
faShareAlt,
|
||||
faExternalLinkAlt,
|
||||
faHistory
|
||||
)
|
||||
|
||||
export default {
|
||||
props: [
|
||||
'button',
|
||||
'extra',
|
||||
'status',
|
||||
'funcArg',
|
||||
'animationState',
|
||||
'getClass',
|
||||
'getComponent',
|
||||
'doAction',
|
||||
'close'
|
||||
],
|
||||
computed: {
|
||||
buttonClass () {
|
||||
return {
|
||||
[this.button.name + '-button']: true,
|
||||
'-extra': this.extra,
|
||||
'-quick': !this.extra,
|
||||
'-active': this.button.active?.(this.funcArg),
|
||||
disabled: this.button.interactive ? !this.button.interactive(this.funcArg) : false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<script src="./action_button.js"/>
|
||||
|
||||
<style lang="scss" src="./action_button.scss"/>
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
import ActionButton from './action_button.vue'
|
||||
import Popover from 'src/components/popover/popover.vue'
|
||||
|
||||
import { library } from '@fortawesome/fontawesome-svg-core'
|
||||
import {
|
||||
faUser,
|
||||
faGlobe,
|
||||
faFolderTree
|
||||
} from '@fortawesome/free-solid-svg-icons'
|
||||
|
||||
library.add(
|
||||
faUser,
|
||||
faGlobe,
|
||||
faFolderTree
|
||||
)
|
||||
|
||||
export default {
|
||||
components: {
|
||||
ActionButton,
|
||||
Popover
|
||||
},
|
||||
props: ['button']
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
<template>
|
||||
<Popover
|
||||
trigger="hover"
|
||||
placement="right"
|
||||
v-if="button.dropdown?.()"
|
||||
>
|
||||
<template #trigger>
|
||||
{{ props }}
|
||||
<ActionButton
|
||||
:button="button"
|
||||
v-bind="$attrs"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<div
|
||||
v-if="button.name === 'mute'"
|
||||
class="dropdown-menu"
|
||||
:id="`popup-menu-${randomSeed}`"
|
||||
role="menu"
|
||||
>
|
||||
<div class="menu-item dropdown-item extra-action -icon">
|
||||
<button
|
||||
class="main-button"
|
||||
@click="() => {}"
|
||||
>
|
||||
<FAIcon icon="user" fixed-width />
|
||||
{{ $t('status.mute_user') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="menu-item dropdown-item extra-action -icon">
|
||||
<button
|
||||
class="main-button"
|
||||
@click="() => {}"
|
||||
>
|
||||
<FAIcon icon="folder-tree" fixed-width />
|
||||
{{ $t('status.mute_conversation') }}
|
||||
</button>
|
||||
</div>
|
||||
<div class="menu-item dropdown-item extra-action -icon">
|
||||
<button
|
||||
class="main-button"
|
||||
@click="() => {}"
|
||||
>
|
||||
<FAIcon icon="globe" fixed-width />
|
||||
{{ $t('status.mute_domain') }}
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
</Popover>
|
||||
<ActionButton
|
||||
v-else
|
||||
:button="button"
|
||||
v-bind="$attrs"
|
||||
/>
|
||||
</template>
|
||||
|
||||
<script src="./action_button_container.js"/>
|
|
@ -1,8 +1,7 @@
|
|||
import { mapState } from 'vuex'
|
||||
|
||||
import ConfirmModal from 'src/components/confirm_modal/confirm_modal.vue'
|
||||
import ActionButton from './action_button.vue'
|
||||
import StatusBookmarkFolderMenu from 'src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue'
|
||||
import ActionButtonContainer from './action_button_container.vue'
|
||||
import Popover from 'src/components/popover/popover.vue'
|
||||
import genRandomSeed from 'src/services/random_seed/random_seed.service.js'
|
||||
|
||||
|
@ -136,22 +135,21 @@ const BUTTONS = [{
|
|||
popover: 'emoji-picker'
|
||||
}, {
|
||||
// =========
|
||||
// MUTE CONVERSATION, my beloved
|
||||
// MUTE
|
||||
// =========
|
||||
name: 'mute',
|
||||
icon: 'eye-slash',
|
||||
label: ({ status }) => status.thread_muted
|
||||
? 'status.unmute_conversation'
|
||||
: 'status.mute_conversation',
|
||||
label: 'status.mute_ellipsis',
|
||||
if: ({ loggedIn }) => loggedIn,
|
||||
toggleable: true,
|
||||
action ({ status, dispatch, emit }) {
|
||||
if (status.thread_muted) {
|
||||
return dispatch('unmuteConversation', { id: status.id })
|
||||
} else {
|
||||
return dispatch('muteConversation', { id: status.id })
|
||||
}
|
||||
}
|
||||
dropdown: true
|
||||
// action ({ status, dispatch, emit }) {
|
||||
// if (status.thread_muted) {
|
||||
// return dispatch('unmuteConversation', { id: status.id })
|
||||
// } else {
|
||||
// return dispatch('muteConversation', { id: status.id })
|
||||
// }
|
||||
// }
|
||||
}, {
|
||||
// =========
|
||||
// PIN STATUS
|
||||
|
@ -287,6 +285,7 @@ const StatusActionButtons = {
|
|||
emits: ['toggleReplying'],
|
||||
data () {
|
||||
return {
|
||||
Popover,
|
||||
animationState: {
|
||||
retweet: false,
|
||||
favorite: false
|
||||
|
@ -303,8 +302,7 @@ const StatusActionButtons = {
|
|||
components: {
|
||||
Popover,
|
||||
ConfirmModal,
|
||||
ActionButton,
|
||||
StatusBookmarkFolderMenu
|
||||
ActionButtonContainer
|
||||
},
|
||||
computed: {
|
||||
...mapState({
|
||||
|
|
|
@ -8,84 +8,12 @@
|
|||
grid-auto-columns: 1fr;
|
||||
grid-gap: 1em;
|
||||
margin-top: var(--status-margin);
|
||||
|
||||
.quick-action {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr auto;
|
||||
|
||||
&.-pin {
|
||||
margin: calc(-2px - 0.25em);
|
||||
padding: 0.25em;
|
||||
border: 2px dashed var(--icon);
|
||||
border-radius: var(--roundness);
|
||||
}
|
||||
|
||||
&.-pin,
|
||||
&.-dropdown {
|
||||
grid-template-columns: 1fr max-content;
|
||||
}
|
||||
|
||||
.reply-button:not(.disabled) {
|
||||
&:hover,
|
||||
&.-active {
|
||||
.svg-inline--fa {
|
||||
color: var(--cBlue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.retweet-button:not(.disabled) {
|
||||
&:hover,
|
||||
&.-active {
|
||||
.svg-inline--fa {
|
||||
color: var(--cGreen);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.favorite-button:not(.disabled) {
|
||||
&:hover,
|
||||
&.-active {
|
||||
.svg-inline--fa {
|
||||
color: var(--cOrange);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
> button,
|
||||
> a {
|
||||
padding: 0.5em;
|
||||
margin: -0.5em;
|
||||
|
||||
@include unfocused-style {
|
||||
.focus-marker {
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.active-marker {
|
||||
visibility: visible;
|
||||
}
|
||||
}
|
||||
|
||||
@include focused-style {
|
||||
.focus-marker {
|
||||
visibility: visible;
|
||||
}
|
||||
|
||||
.active-marker {
|
||||
visibility: hidden;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// popover
|
||||
/* stylelint-disable no-descending-specificity */
|
||||
.extra-action-buttons {
|
||||
.extra-action {
|
||||
display: grid;
|
||||
grid-template-columns: 1fr;
|
||||
grid-auto-flow: column;
|
||||
grid-auto-columns: auto;
|
||||
grid-gap: 1em;
|
||||
|
|
|
@ -7,50 +7,17 @@
|
|||
v-for="button in quickButtons"
|
||||
:key="button.name"
|
||||
>
|
||||
<component
|
||||
:is="getComponent(button)"
|
||||
class="button-unstyled action-button"
|
||||
:class="getClass(button)"
|
||||
:disabled="getClass(button).disabled"
|
||||
role="button"
|
||||
:tabindex="0"
|
||||
:title="$t(button.label(funcArg))"
|
||||
@click.stop="getComponent(button) === 'button' && doAction(button)"
|
||||
:href="getComponent(button) == 'a' ? button.link?.(funcArg) || getRemoteInteractionLink : undefined"
|
||||
>
|
||||
<FALayers>
|
||||
<FAIcon
|
||||
class="fa-scale-110"
|
||||
:icon="button.icon(funcArg)"
|
||||
/>
|
||||
<template v-if="!getClass(button).disabled && button.toggleable?.(funcArg) && button.active">
|
||||
<FAIcon
|
||||
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-12"
|
||||
:icon="button.openIndicator?.(funcArg) || 'plus'"
|
||||
/>
|
||||
<FAIcon
|
||||
v-else
|
||||
class="focus-marker"
|
||||
transform="shrink-6 up-9 right-12"
|
||||
:icon="button.closeIndicator?.(funcArg) || 'minus'"
|
||||
/>
|
||||
</template>
|
||||
</FALayers>
|
||||
<span
|
||||
class="action-counter"
|
||||
v-if="button.counter?.(funcArg) > 0"
|
||||
>
|
||||
{{ button.counter?.(funcArg) }}
|
||||
</span>
|
||||
</component>
|
||||
<ActionButtonContainer
|
||||
:button="button"
|
||||
:status="status"
|
||||
:extra="false"
|
||||
:funcArg="funcArg"
|
||||
:get-class="getClass"
|
||||
:get-component="getComponent"
|
||||
:animation-state="animationState"
|
||||
:close="close"
|
||||
:do-action="doAction"
|
||||
/>
|
||||
<button
|
||||
v-if="showPin && currentUser"
|
||||
type="button"
|
||||
|
@ -111,63 +78,17 @@
|
|||
:disabled="getClass(button).disabled"
|
||||
:class="{ disabled: getClass(button).disabled }"
|
||||
>
|
||||
<Popover
|
||||
v-if="getComponent(button) === 'button'"
|
||||
trigger="hover"
|
||||
placement="right"
|
||||
>
|
||||
<template #trigger>
|
||||
<ActionButton
|
||||
:button="button"
|
||||
:status="status"
|
||||
:extra="true"
|
||||
:funcArg="funcArg"
|
||||
:get-class="getClass"
|
||||
:get-component="getComponent"
|
||||
:animation-state="animationState"
|
||||
:close="close"
|
||||
:do-action="doAction"
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<template v-if="button.name === 'mute'">
|
||||
<div
|
||||
v-for="folder in folders"
|
||||
:key="folder.id"
|
||||
class="menu-item dropdown-item -icon"
|
||||
>
|
||||
<button
|
||||
class="main-button"
|
||||
@click="toggleFolder(folder.id)"
|
||||
>
|
||||
<span
|
||||
class="input menu-checkbox -radio"
|
||||
:class="{ 'menu-checkbox-checked': status.bookmark_folder_id == folder.id }"
|
||||
/>
|
||||
{{ folder.name }}
|
||||
</button>
|
||||
</div>
|
||||
</template>
|
||||
</template>
|
||||
</Popover>
|
||||
<Popover
|
||||
trigger="hover"
|
||||
placement="right"
|
||||
:trigger-attrs="{ class: 'extra-button' }"
|
||||
v-if="button.name === 'bookmark'"
|
||||
>
|
||||
<template #trigger>
|
||||
<FAIcon
|
||||
class="chevron-icon"
|
||||
size="lg"
|
||||
icon="chevron-right"
|
||||
fixed-width
|
||||
/>
|
||||
</template>
|
||||
<template #content>
|
||||
<StatusBookmarkFolderMenu v-if="button.name === 'bookmark'" :status="funcArg.status" />
|
||||
</template>
|
||||
</Popover>
|
||||
<ActionButtonContainer
|
||||
:button="button"
|
||||
:status="status"
|
||||
:extra="true"
|
||||
:funcArg="funcArg"
|
||||
:get-class="getClass"
|
||||
:get-component="getComponent"
|
||||
:animation-state="animationState"
|
||||
:close="close"
|
||||
:do-action="doAction"
|
||||
/>
|
||||
<button
|
||||
v-if="showPin && currentUser"
|
||||
type="button"
|
||||
|
|
|
@ -1238,6 +1238,11 @@
|
|||
"mentions": "Mentions",
|
||||
"replies_list": "Replies:",
|
||||
"replies_list_with_others": "Replies (+{numReplies} other): | Replies (+{numReplies} others):",
|
||||
"mute_ellipsis": "Mute…",
|
||||
"mute_user": "Mute user",
|
||||
"unmute_user": "Unmute user",
|
||||
"mute_domain": "Mute domain",
|
||||
"unmute_domain": "Unmute domain",
|
||||
"mute_conversation": "Mute conversation",
|
||||
"unmute_conversation": "Unmute conversation",
|
||||
"status_unavailable": "Status unavailable",
|
||||
|
|
Loading…
Add table
Reference in a new issue