r.name === emoji)
- if (existingReaction && existingReaction.me) {
- this.$store.dispatch('unreactWithEmoji', { id: this.status.id, emoji })
- } else {
- this.$store.dispatch('reactWithEmoji', { id: this.status.id, emoji })
- }
- },
- doActionWrap (button) {
- if (button.name === 'emoji') {
- this.$refs.picker.showPicker()
- } else {
- this.getComponent(button) === 'button' && this.doAction(button)
- }
- }
- }
-}
diff --git a/src/components/status_action_buttons/action_button.scss b/src/components/status_action_buttons/action_button.scss
deleted file mode 100644
index fe4983946..000000000
--- a/src/components/status_action_buttons/action_button.scss
+++ /dev/null
@@ -1,92 +0,0 @@
-@import "../../mixins";
-/* stylelint-disable declaration-no-important */
-
-.quick-action {
- display: grid;
- grid-template-columns: max-content;
- grid-gap: 0.25em;
-
- &.-pin {
- margin: calc(-2px - 0.25em);
- padding: 0.25em;
- border: 2px dashed var(--icon);
- border-radius: var(--roundness);
- grid-template-columns: 1fr auto;
- }
-
- .action-button-inner,
- .extra-button {
- margin: -0.5em;
- padding: 0.5em;
- }
-
- .separator {
- width: 0.5em;
-
- &::before {
- content: "";
- display: block;
- width: 1px;
- height: 1.5em;
- background-color: var(--icon);
- }
- }
-
- .action-button-inner {
- display: grid;
- grid-gap: 1em;
- grid-template-columns: max-content max-content;
- grid-auto-flow: column;
- grid-auto-columns: max-content;
- align-items: center;
- }
-}
-
-.action-button {
- display: grid;
- grid-auto-flow: column;
- padding: 0;
-
- .action-button-inner {
- &:hover,
- &.-active {
- &.reply-button:not(.disabled) {
- .svg-inline--fa {
- color: var(--cBlue);
- }
- }
-
- &.retweet-button:not(.disabled) {
- .svg-inline--fa {
- color: var(--cGreen);
- }
- }
-
- &.favorite-button:not(.disabled) {
- .svg-inline--fa {
- color: var(--cOrange);
- }
- }
- }
- }
-
- @include unfocused-style {
- .focus-marker {
- visibility: hidden;
- }
-
- .active-marker {
- visibility: visible;
- }
- }
-
- @include focused-style {
- .focus-marker {
- visibility: visible;
- }
-
- .active-marker {
- visibility: hidden;
- }
- }
-}
diff --git a/src/components/status_action_buttons/action_button.vue b/src/components/status_action_buttons/action_button.vue
deleted file mode 100644
index 40d3397c5..000000000
--- a/src/components/status_action_buttons/action_button.vue
+++ /dev/null
@@ -1,102 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/components/status_action_buttons/action_button_container.js b/src/components/status_action_buttons/action_button_container.js
deleted file mode 100644
index 6bd3fde54..000000000
--- a/src/components/status_action_buttons/action_button_container.js
+++ /dev/null
@@ -1,89 +0,0 @@
-import ActionButton from './action_button.vue'
-import Popover from 'src/components/popover/popover.vue'
-import MuteConfirm from 'src/components/confirm_modal/mute_confirm.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,
- MuteConfirm
- },
- props: ['button', 'status'],
- mounted () {
- if (this.button.name === 'mute') {
- this.$store.dispatch('fetchDomainMutes')
- }
- },
- computed: {
- buttonClass () {
- return [
- this.button.name + '-button',
- {
- '-with-extra': this.button.name === 'bookmark',
- '-extra': this.extra,
- '-quick': !this.extra
- }
- ]
- },
- user () {
- return this.status.user
- },
- userIsMuted () {
- return this.$store.getters.relationship(this.user.id).muting
- },
- conversationIsMuted () {
- return this.status.thread_muted
- },
- domain () {
- return this.user.fqn.split('@')[1]
- },
- domainIsMuted () {
- return new Set(this.$store.state.users.currentUser.domainMutes).has(this.domain)
- }
- },
- methods: {
- unmuteUser () {
- return this.$store.dispatch('unmuteUser', this.user.id)
- },
- unmuteThread () {
- return this.$store.dispatch('unmuteConversation', this.user.id)
- },
- unmuteDomain () {
- return this.$store.dispatch('unmuteDomain', this.user.id)
- },
- toggleUserMute () {
- if (this.userIsMuted) {
- this.unmuteUser()
- } else {
- this.$refs.confirmUser.optionallyPrompt()
- }
- },
- toggleConversationMute () {
- if (this.conversationIsMuted) {
- this.unmuteConversation()
- } else {
- this.$refs.confirmConversation.optionallyPrompt()
- }
- },
- toggleDomainMute () {
- if (this.domainIsMuted) {
- this.unmuteDomain()
- } else {
- this.$refs.confirmDomain.optionallyPrompt()
- }
- }
- }
-}
diff --git a/src/components/status_action_buttons/action_button_container.vue b/src/components/status_action_buttons/action_button_container.vue
deleted file mode 100644
index 0cde21efc..000000000
--- a/src/components/status_action_buttons/action_button_container.vue
+++ /dev/null
@@ -1,94 +0,0 @@
-
-
-
-
- {{ props }}
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/src/components/status_action_buttons/buttons_definitions.js b/src/components/status_action_buttons/buttons_definitions.js
deleted file mode 100644
index 9013981c0..000000000
--- a/src/components/status_action_buttons/buttons_definitions.js
+++ /dev/null
@@ -1,228 +0,0 @@
-const PRIVATE_SCOPES = new Set(['private', 'direct'])
-const PUBLIC_SCOPES = new Set(['public', 'unlisted'])
-export const BUTTONS = [{
- // =========
- // REPLY
- // =========
- name: 'reply',
- label: 'tool_tip.reply',
- icon: 'reply',
- active: ({ replying }) => replying,
- counter: ({ status }) => status.replies_count,
- anon: true,
- anonLink: true,
- toggleable: true,
- closeIndicator: 'times',
- activeIndicator: 'none',
- action ({ emit }) {
- emit('toggleReplying')
- return Promise.resolve()
- }
-}, {
- // =========
- // REPEAT
- // =========
- name: 'retweet',
- label: ({ status }) => status.repeated
- ? 'tool_tip.unrepeat'
- : 'tool_tip.repeat',
- icon ({ status }) {
- if (PRIVATE_SCOPES.has(status.visibility)) {
- return 'lock'
- }
- return 'retweet'
- },
- animated: true,
- active: ({ status }) => status.repeated,
- counter: ({ status }) => status.repeat_num,
- anonLink: true,
- interactive: ({ status, loggedIn }) => loggedIn && !PRIVATE_SCOPES.has(status.visibility),
- toggleable: true,
- confirm: ({ status, getters }) => !status.repeated && getters.mergedConfig.modalOnRepeat,
- confirmStrings: {
- title: 'status.repeat_confirm_title',
- body: 'status.repeat_confirm',
- confirm: 'status.repeat_confirm_accept_button',
- cancel: 'status.repeat_confirm_cancel_button'
- },
- action ({ status, dispatch }) {
- if (!status.repeated) {
- return dispatch('retweet', { id: status.id })
- } else {
- return dispatch('unretweet', { id: status.id })
- }
- }
-}, {
- // =========
- // FAVORITE
- // =========
- name: 'favorite',
- label: ({ status }) => status.favorited
- ? 'tool_tip.unfavorite'
- : 'tool_tip.favorite',
- icon: ({ status }) => status.favorited
- ? ['fas', 'star']
- : ['far', 'star'],
- animated: true,
- active: ({ status }) => status.favorited,
- counter: ({ status }) => status.fave_num,
- anonLink: true,
- toggleable: true,
- action ({ status, dispatch }) {
- if (!status.favorited) {
- return dispatch('favorite', { id: status.id })
- } else {
- return dispatch('unfavorite', { id: status.id })
- }
- }
-}, {
- // =========
- // EMOJI REACTIONS
- // =========
- name: 'emoji',
- label: 'tool_tip.add_reaction',
- icon: ['far', 'smile-beam'],
- anonLink: true
-}, {
- // =========
- // MUTE
- // =========
- name: 'mute',
- icon: 'eye-slash',
- label: 'status.mute_ellipsis',
- if: ({ loggedIn }) => loggedIn,
- toggleable: true,
- dropdown: true
- // action ({ status, dispatch, emit }) {
- // }
-}, {
- // =========
- // PIN STATUS
- // =========
- name: 'pin',
- icon: 'thumbtack',
- label: ({ status }) => status.pinned
- ? 'status.unpin'
- : 'status.pin',
- if ({ status, loggedIn, currentUser }) {
- return loggedIn &&
- status.user.id === currentUser.id &&
- PUBLIC_SCOPES.has(status.visibility)
- },
- action ({ status, dispatch, emit }) {
- if (status.pinned) {
- return dispatch('unpinStatus', { id: status.id })
- } else {
- return dispatch('pinStatus', { id: status.id })
- }
- }
-}, {
- // =========
- // BOOKMARK
- // =========
- name: 'bookmark',
- icon: ({ status }) => status.bookmarked
- ? ['fas', 'bookmark']
- : ['far', 'bookmark'],
- toggleable: true,
- active: ({ status }) => status.bookmarked,
- label: ({ status }) => status.bookmarked
- ? 'status.unbookmark'
- : 'status.bookmark',
- if: ({ loggedIn }) => loggedIn,
- action ({ status, dispatch, emit }) {
- if (status.bookmarked) {
- return dispatch('unbookmark', { id: status.id })
- } else {
- return dispatch('bookmark', { id: status.id })
- }
- }
-}, {
- // =========
- // EDIT
- // =========
- name: 'edit',
- icon: 'pen',
- label: 'status.edit',
- if ({ status, loggedIn, currentUser, state }) {
- return loggedIn &&
- state.instance.editingAvailable &&
- status.user.id === currentUser.id
- },
- action ({ dispatch, status }) {
- return dispatch('fetchStatusSource', { id: status.id })
- .then(data => dispatch('openEditStatusModal', {
- statusId: status.id,
- subject: data.spoiler_text,
- statusText: data.text,
- statusIsSensitive: status.nsfw,
- statusPoll: status.poll,
- statusFiles: [...status.attachments],
- visibility: status.visibility,
- statusContentType: data.content_type
- }))
- }
-}, {
- // =========
- // DELETE
- // =========
- name: 'delete',
- icon: 'times',
- label: 'status.delete',
- if ({ status, loggedIn, currentUser }) {
- return loggedIn && (
- status.user.id === currentUser.id ||
- currentUser.privileges.includes('messages_delete')
- )
- },
- confirm: ({ status, getters }) => getters.mergedConfig.modalOnDelete,
- confirmStrings: {
- title: 'status.delete_confirm_title',
- body: 'status.delete_confirm',
- confirm: 'status.delete_confirm_accept_button',
- cancel: 'status.delete_confirm_cancel_button'
- },
- action ({ dispatch, status }) {
- return dispatch('deleteStatus', { id: status.id })
- }
-}, {
- // =========
- // SHARE/COPY
- // =========
- name: 'share',
- icon: 'share-alt',
- label: 'status.copy_link',
- action ({ state, status, router }) {
- navigator.clipboard.writeText([
- state.instance.server,
- router.resolve({ name: 'conversation', params: { id: status.id } }).href
- ].join(''))
- return Promise.resolve()
- }
-}, {
- // =========
- // EXTERNAL
- // =========
- name: 'external',
- icon: 'external-link-alt',
- label: 'status.external_source',
- link: ({ status }) => status.external_url
-}, {
- // =========
- // REPORT
- // =========
- name: 'report',
- icon: 'flag',
- label: 'user_card.report',
- if: ({ loggedIn }) => loggedIn,
- action ({ dispatch, status }) {
- dispatch('openUserReportingModal', { userId: status.user.id, statusIds: [status.id] })
- }
-}].map(button => {
- return Object.fromEntries(
- Object.entries(button).map(([k, v]) => [
- k,
- (typeof v === 'function' || k === 'name') ? v : () => v
- ])
- )
-})
diff --git a/src/components/status_action_buttons/status_action_buttons.js b/src/components/status_action_buttons/status_action_buttons.js
deleted file mode 100644
index 45dac0dc1..000000000
--- a/src/components/status_action_buttons/status_action_buttons.js
+++ /dev/null
@@ -1,143 +0,0 @@
-import { mapState } from 'vuex'
-
-import ConfirmModal from 'src/components/confirm_modal/confirm_modal.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'
-
-import { BUTTONS } from './buttons_definitions.js'
-
-import { library } from '@fortawesome/fontawesome-svg-core'
-import {
- faEllipsisH
-} from '@fortawesome/free-solid-svg-icons'
-
-library.add(
- faEllipsisH
-)
-
-const StatusActionButtons = {
- props: ['status', 'replying'],
- emits: ['toggleReplying'],
- data () {
- return {
- Popover,
- animationState: {
- retweet: false,
- favorite: false
- },
- showPin: false,
- showingConfirmDialog: false,
- currentConfirmTitle: '',
- currentConfirmOkText: '',
- currentConfirmCancelText: '',
- currentConfirmAction: () => {},
- randomSeed: genRandomSeed()
- }
- },
- components: {
- Popover,
- ConfirmModal,
- ActionButtonContainer
- },
- computed: {
- ...mapState({
- pinnedItems: state => new Set(state.serverSideStorage.prefsStorage.collections.pinnedStatusActions)
- }),
- buttons () {
- 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))
- },
- currentUser () {
- return this.$store.state.users.currentUser
- },
- hideCustomEmoji () {
- return !this.$store.state.instance.pleromaCustomEmojiReactionsAvailable
- },
- funcArg () {
- return {
- status: this.status,
- replying: this.replying,
- emit: this.$emit,
- dispatch: this.$store.dispatch,
- state: this.$store.state,
- getters: this.$store.getters,
- router: this.$router,
- currentUser: this.currentUser,
- loggedIn: !!this.currentUser
- }
- },
- triggerAttrs () {
- return {
- title: this.$t('status.more_actions'),
- 'aria-controls': `popup-menu-${this.randomSeed}`,
- 'aria-expanded': this.expanded,
- 'aria-haspopup': 'menu'
- }
- }
- },
- methods: {
- doAction (button) {
- if (button.confirm?.(this.funcArg)) {
- // TODO move to action_button
- this.currentConfirmTitle = this.$t(button.confirmStrings(this.funcArg).title)
- this.currentConfirmOkText = this.$t(button.confirmStrings(this.funcArg).confirm)
- this.currentConfirmCancelText = this.$t(button.confirmStrings(this.funcArg).cancel)
- this.currentConfirmBody = this.$t(button.confirmStrings(this.funcArg).body)
- this.currentConfirmAction = () => {
- this.showingConfirmDialog = false
- this.doActionReal(button)
- }
- this.showingConfirmDialog = true
- } else {
- this.doActionReal(button)
- }
- },
- doActionReal (button) {
- this.animationState[button.name] = true
- button.action(this.funcArg)
- .then(() => this.$emit('onSuccess'))
- .catch(err => this.$emit('onError', err.error.error))
- .finally(() => setTimeout(() => { this.animationState[button.name] = false }))
- },
- isPinned (button) {
- return this.pinnedItems.has(button.name)
- },
- unpin (button) {
- this.$store.commit('removeCollectionPreference', { path: 'collections.pinnedStatusActions', value: button.name })
- this.$store.dispatch('pushServerSideStorage')
- },
- pin (button) {
- this.$store.commit('addCollectionPreference', { path: 'collections.pinnedStatusActions', value: button.name })
- this.$store.dispatch('pushServerSideStorage')
- },
- getComponent (button) {
- if (!this.$store.state.users.currentUser && button.anonLink) {
- return 'a'
- } else if (button.action == null && button.link != null) {
- return 'a'
- } else {
- return 'button'
- }
- },
- getClass (button) {
- return {
- [button.name + '-button']: true,
- disabled: button.interactive ? !button.interactive(this.funcArg) : false,
- '-pin-edit': this.showPin,
- '-dropdown': button.dropdown?.(),
- '-active': button.active?.(this.funcArg)
- }
- },
- getRemoteInteractionLink () {
- return this.$store.getters.remoteInteractionLink({ statusId: this.status.id })
- }
- }
-}
-
-export default StatusActionButtons
diff --git a/src/components/status_action_buttons/status_action_buttons.scss b/src/components/status_action_buttons/status_action_buttons.scss
deleted file mode 100644
index e18083513..000000000
--- a/src/components/status_action_buttons/status_action_buttons.scss
+++ /dev/null
@@ -1,21 +0,0 @@
-@import "../../mixins";
-
-.StatusActionButtons {
- .quick-action-buttons {
- display: grid;
- grid-template-columns: repeat(var(--_actionsColumnCount, 6), 1fr);
- grid-auto-flow: row dense;
- grid-auto-rows: 1fr;
- grid-gap: 1.25em 1em;
- margin-top: var(--status-margin);
- }
-}
-// popover
-.extra-action-buttons {
- .extra-action {
- margin: 0;
- padding-top: 0;
- padding-bottom: 0;
- padding-right: 0;
- }
-}
diff --git a/src/components/status_action_buttons/status_action_buttons.vue b/src/components/status_action_buttons/status_action_buttons.vue
deleted file mode 100644
index a3b50975a..000000000
--- a/src/components/status_action_buttons/status_action_buttons.vue
+++ /dev/null
@@ -1,132 +0,0 @@
-
-
-
-
-
-
-
diff --git a/src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue b/src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue
index 75f389946..70baa60d8 100644
--- a/src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue
+++ b/src/components/status_bookmark_folder_menu/status_bookmark_folder_menu.vue
@@ -1,21 +1,39 @@
-
diff --git a/src/components/user_card/user_card.js b/src/components/user_card/user_card.js
index 3c97b1664..1d2e19467 100644
--- a/src/components/user_card/user_card.js
+++ b/src/components/user_card/user_card.js
@@ -1,3 +1,4 @@
+import { unitToSeconds } from 'src/services/date_utils/date_utils.js'
import UserAvatar from '../user_avatar/user_avatar.vue'
import RemoteFollow from '../remote_follow/remote_follow.vue'
import ProgressButton from '../progress_button/progress_button.vue'
@@ -8,7 +9,7 @@ import UserNote from '../user_note/user_note.vue'
import Select from '../select/select.vue'
import UserLink from '../user_link/user_link.vue'
import RichContent from 'src/components/rich_content/rich_content.jsx'
-import MuteConfirm from '../confirm_modal/mute_confirm.vue'
+import ConfirmModal from '../confirm_modal/confirm_modal.vue'
import generateProfileLink from 'src/services/user_profile_link_generator/user_profile_link_generator'
import { mapGetters } from 'vuex'
import { library } from '@fortawesome/fontawesome-svg-core'
@@ -47,6 +48,7 @@ export default {
data () {
return {
followRequestInProgress: false,
+ showingConfirmMute: false,
muteExpiryAmount: 0,
muteExpiryUnit: 'minutes'
}
@@ -139,6 +141,12 @@ export default {
supportsNote () {
return 'note' in this.relationship
},
+ shouldConfirmMute () {
+ return this.mergedConfig.modalOnMute
+ },
+ muteExpiryUnits () {
+ return ['minutes', 'hours', 'days']
+ },
...mapGetters(['mergedConfig'])
},
components: {
@@ -152,11 +160,28 @@ export default {
RichContent,
UserLink,
UserNote,
- MuteConfirm
+ ConfirmModal
},
methods: {
+ showConfirmMute () {
+ this.showingConfirmMute = true
+ },
+ hideConfirmMute () {
+ this.showingConfirmMute = false
+ },
muteUser () {
- this.$refs.confirmation.optionallyPrompt()
+ if (!this.shouldConfirmMute) {
+ this.doMuteUser()
+ } else {
+ this.showConfirmMute()
+ }
+ },
+ doMuteUser () {
+ this.$store.dispatch('muteUser', {
+ id: this.user.id,
+ expiresIn: this.shouldConfirmMute ? unitToSeconds(this.muteExpiryUnit, this.muteExpiryAmount) : 0
+ })
+ this.hideConfirmMute()
},
unmuteUser () {
this.$store.dispatch('unmuteUser', this.user.id)
diff --git a/src/components/user_card/user_card.scss b/src/components/user_card/user_card.scss
index 13ef610c6..70a76d54c 100644
--- a/src/components/user_card/user_card.scss
+++ b/src/components/user_card/user_card.scss
@@ -292,10 +292,6 @@
}
}
-#sidebar {
- --_actionsColumnCount: 4;
-}
-
.sidebar .edit-profile-button {
display: none;
}
@@ -325,3 +321,8 @@
text-decoration: none;
}
}
+
+.mute-expiry {
+ display: flex;
+ flex-direction: row;
+}
diff --git a/src/components/user_card/user_card.vue b/src/components/user_card/user_card.vue
index 50abe9fff..ed5401589 100644
--- a/src/components/user_card/user_card.vue
+++ b/src/components/user_card/user_card.vue
@@ -311,11 +311,51 @@
/>