From 2f6bea7ad8e42cb2b43ec001a763f029f3b652b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?nicole=20miko=C5=82ajczyk?= Date: Fri, 27 Feb 2026 02:02:59 +0100 Subject: [PATCH] nicolium: split account header into two files MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: nicole mikołajczyk --- .../account/components/account-menu.tsx | 563 ++++++++++++++++++ .../features/account/components/header.tsx | 516 +--------------- packages/nicolium/src/styles/new/layout.scss | 4 +- 3 files changed, 568 insertions(+), 515 deletions(-) create mode 100644 packages/nicolium/src/features/account/components/account-menu.tsx diff --git a/packages/nicolium/src/features/account/components/account-menu.tsx b/packages/nicolium/src/features/account/components/account-menu.tsx new file mode 100644 index 000000000..f4d3c9883 --- /dev/null +++ b/packages/nicolium/src/features/account/components/account-menu.tsx @@ -0,0 +1,563 @@ +import { useMutation } from '@tanstack/react-query'; +import { GOTOSOCIAL, MASTODON } from 'pl-api'; +import React from 'react'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; + +import { initReport, ReportableEntities } from '@/actions/reports'; +import DropdownMenu, { type Menu } from '@/components/dropdown-menu'; +import IconButton from '@/components/ui/icon-button'; +import { useClient } from '@/hooks/use-client'; +import { useFeatures } from '@/hooks/use-features'; +import { useOwnAccount } from '@/hooks/use-own-account'; +import { + useFollowAccountMutation, + usePinAccountMutation, + useRemoveAccountFromFollowersMutation, + useUnblockAccountMutation, + useUnmuteAccountMutation, + useUnpinAccountMutation, + useUpdateAccountNoteMutation, +} from '@/queries/accounts/use-relationship'; +import { + blockDomainMutationOptions, + unblockDomainMutationOptions, +} from '@/queries/settings/domain-blocks'; +import { useComposeActions } from '@/stores/compose'; +import { useModalsActions } from '@/stores/modals'; +import { useSettings } from '@/stores/settings'; +import toast from '@/toast'; +import copy from '@/utils/copy'; + +import type { Account } from 'pl-api'; + +const messages = defineMessages({ + editProfile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, + mention: { id: 'account.mention', defaultMessage: 'Mention' }, + direct: { id: 'account.direct', defaultMessage: 'Direct message @{name}' }, + unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' }, + block: { id: 'account.block', defaultMessage: 'Block @{name}' }, + unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' }, + mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' }, + report: { id: 'account.report', defaultMessage: 'Report @{name}' }, + copy: { id: 'account.copy', defaultMessage: 'Copy link to profile' }, + media: { id: 'account.media', defaultMessage: 'Media' }, + blockDomain: { id: 'account.block_domain', defaultMessage: 'Hide everything from {domain}' }, + unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' }, + hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide reposts from @{name}' }, + showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show reposts from @{name}' }, + preferences: { id: 'column.preferences', defaultMessage: 'Preferences' }, + blocks: { id: 'column.blocks', defaultMessage: 'Blocks' }, + mutes: { id: 'column.mutes', defaultMessage: 'Mutes' }, + endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' }, + unendorse: { id: 'account.unendorse', defaultMessage: "Don't feature on profile" }, + bite: { id: 'account.bite', defaultMessage: 'Bite @{name}' }, + removeFromFollowers: { + id: 'account.remove_from_followers', + defaultMessage: 'Remove this follower', + }, + adminAccount: { id: 'status.admin_account', defaultMessage: 'Moderate @{name}' }, + addOrRemoveFromList: { + id: 'account.add_or_remove_from_list', + defaultMessage: 'Add or remove from lists', + }, + search: { id: 'account.search', defaultMessage: 'Search from @{name}' }, + searchSelf: { id: 'account.search_self', defaultMessage: 'Search your posts' }, + unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' }, + blockDomainConfirm: { + id: 'confirmations.domain_block.confirm', + defaultMessage: 'Hide entire domain', + }, + removeFromFollowersConfirm: { + id: 'confirmations.remove_from_followers.confirm', + defaultMessage: 'Remove', + }, + userEndorsed: { + id: 'account.endorse.success', + defaultMessage: 'You are now featuring @{acct} on your profile', + }, + userUnendorsed: { + id: 'account.unendorse.success', + defaultMessage: 'You are no longer featuring @{acct}', + }, + userBit: { id: 'account.bite.success', defaultMessage: 'You have bit @{acct}' }, + userBiteFail: { id: 'account.bite.fail', defaultMessage: 'Failed to bite @{acct}' }, + profileExternal: { id: 'account.profile_external', defaultMessage: 'View profile on {domain}' }, + loadActivities: { id: 'account.load_activities', defaultMessage: 'Fetch latest posts' }, + loadActivitiesSuccess: { + id: 'account.load_activities.success', + defaultMessage: 'Scheduled fetching latest posts', + }, + loadActivitiesFail: { + id: 'account.load_activities.fail', + defaultMessage: 'Failed to fetch latest posts', + }, + note: { id: 'account_note.modal_header', defaultMessage: 'Edit note for @{name}' }, + notePlaceholder: { id: 'account_note.placeholder', defaultMessage: 'Add a note' }, + noteSaved: { id: 'account_note.success', defaultMessage: 'Note saved' }, + noteSaveFailed: { id: 'account_note.fail', defaultMessage: 'Failed to save note' }, + share: { id: 'account.share', defaultMessage: "Share @{name}'s profile" }, + subscribeFeed: { id: 'account.rss_feed', defaultMessage: 'Subscribe to RSS feed' }, +}); + +interface IAccountMenu { + account: Account; +} + +const AccountMenu: React.FC = ({ account }) => { + const intl = useIntl(); + const { mentionCompose, directCompose } = useComposeActions(); + const client = useClient(); + + const features = useFeatures(); + const { data: ownAccount } = useOwnAccount(); + const { mutate: followAccount } = useFollowAccountMutation(account?.id!); + const { mutate: unblockAccount } = useUnblockAccountMutation(account?.id!); + const { mutate: unmuteAccount } = useUnmuteAccountMutation(account?.id!); + const { mutate: pinAccount } = usePinAccountMutation(account?.id!); + const { mutate: unpinAccount } = useUnpinAccountMutation(account?.id!); + const { mutate: removeFromFollowers } = useRemoveAccountFromFollowersMutation(account?.id!); + const { mutate: updateAccountNote } = useUpdateAccountNoteMutation(account?.id!); + const { openModal } = useModalsActions(); + const settings = useSettings(); + + const { software } = features.version; + + const { mutate: blockDomain } = useMutation(blockDomainMutationOptions); + const { mutate: unblockDomain } = useMutation(unblockDomainMutationOptions); + + const onBlock = () => { + if (account.relationship?.blocking) { + unblockAccount(); + } else { + openModal('BLOCK_MUTE', { accountId: account.id, action: 'BLOCK' }); + } + }; + + const onMention = () => { + mentionCompose(account); + }; + + const onDirect = () => { + directCompose(account); + }; + + const onReblogToggle = () => { + if (account.relationship?.showing_reblogs) { + followAccount({ reblogs: false }); + } else { + followAccount({ reblogs: true }); + } + }; + + const onEndorseToggle = () => { + if (account.relationship?.endorsed) { + unpinAccount(undefined, { + onSuccess: () => { + toast.success(intl.formatMessage(messages.userUnendorsed, { acct: account.acct })); + }, + }); + } else { + pinAccount(undefined, { + onSuccess: () => { + toast.success(intl.formatMessage(messages.userEndorsed, { acct: account.acct })); + }, + }); + } + }; + + const onBite = () => { + client.accounts + .biteAccount(account.id) + .then(() => { + toast.success(intl.formatMessage(messages.userBit, { acct: account.acct })); + }) + .catch(() => { + toast.error(intl.formatMessage(messages.userBiteFail, { acct: account.acct })); + }); + }; + + const onLoadActivities = () => { + client.accounts + .loadActivities(account.id) + .then(() => { + toast.success(intl.formatMessage(messages.loadActivitiesSuccess)); + }) + .catch(() => { + toast.error(intl.formatMessage(messages.loadActivitiesFail)); + }); + }; + + const onEditNote = () => { + openModal('TEXT_FIELD', { + heading: ( + + ), + placeholder: intl.formatMessage(messages.notePlaceholder), + confirm: , + onConfirm: (value) => { + updateAccountNote(value, { + onSuccess: () => { + toast.success(messages.noteSaved); + }, + onError: () => { + toast.error(messages.noteSaveFailed); + }, + }); + }, + text: account.relationship?.note ?? '', + }); + }; + + const onReport = () => { + initReport(ReportableEntities.ACCOUNT, account); + }; + + const onMute = () => { + if (account.relationship?.muting) { + unmuteAccount(); + } else { + openModal('BLOCK_MUTE', { accountId: account.id, action: 'MUTE' }); + } + }; + + const onBlockDomain = (domain: string) => { + openModal('CONFIRM', { + heading: ( + + ), + message: ( + {domain} }} + /> + ), + confirm: intl.formatMessage(messages.blockDomainConfirm), + onConfirm: () => { + blockDomain(domain); + }, + }); + }; + + const onUnblockDomain = (domain: string) => { + unblockDomain(domain); + }; + + const onAddToList = () => { + openModal('LIST_ADDER', { + accountId: account.id, + }); + }; + + const onRemoveFromFollowers = () => { + const unfollowModal = settings.unfollowModal; + if (unfollowModal) { + openModal('CONFIRM', { + heading: ( + @{account.acct} }} + /> + ), + message: ( + @{account.acct} }} + /> + ), + confirm: intl.formatMessage(messages.removeFromFollowersConfirm), + onConfirm: () => { + removeFromFollowers(); + }, + }); + } else { + removeFromFollowers(); + } + }; + + const handleShare = () => { + navigator + .share({ + text: `@${account.acct}`, + url: account.url, + }) + .catch((e) => { + if (e.name !== 'AbortError') console.error(e); + }); + }; + + const handleCopy: React.EventHandler = () => { + copy(account.url); + }; + + const makeMenu = () => { + const menu: Menu = []; + + if (!account) { + return []; + } + + if (features.rssFeeds && account.local && (software !== GOTOSOCIAL || account.enable_rss)) { + menu.push({ + text: intl.formatMessage(messages.subscribeFeed), + icon: require('@phosphor-icons/core/regular/rss.svg'), + href: software === MASTODON ? `${account.url}.rss` : `${account.url}/feed.rss`, + target: '_blank', + }); + } + + if ('share' in navigator) { + menu.push({ + text: intl.formatMessage(messages.share, { name: account.username }), + action: handleShare, + icon: require('@phosphor-icons/core/regular/export.svg'), + }); + } + + if (features.federating && !account.local) { + const domain = account.fqn.split('@')[1]; + + menu.push({ + text: intl.formatMessage(messages.profileExternal, { domain }), + href: account.url, + icon: require('@phosphor-icons/core/regular/arrow-square-out.svg'), + }); + } + + menu.push({ + text: intl.formatMessage(messages.copy), + action: handleCopy, + icon: require('@phosphor-icons/core/regular/clipboard.svg'), + }); + + if (!ownAccount) return menu; + + if (features.searchFromAccount) { + menu.push({ + text: intl.formatMessage( + account.id === ownAccount.id ? messages.searchSelf : messages.search, + { name: account.username }, + ), + to: '/search', + search: { type: 'statuses', accountId: account.id }, + icon: require('@phosphor-icons/core/regular/magnifying-glass.svg'), + }); + } + + if (menu.length) { + menu.push(null); + } + + if (account.id === ownAccount.id) { + menu.push({ + text: intl.formatMessage(messages.editProfile), + to: '/settings/profile', + icon: require('@phosphor-icons/core/regular/user.svg'), + }); + menu.push({ + text: intl.formatMessage(messages.preferences), + to: '/settings', + icon: require('@phosphor-icons/core/regular/sliders-horizontal.svg'), + }); + menu.push(null); + menu.push({ + text: intl.formatMessage(messages.mutes), + to: '/mutes', + icon: require('@phosphor-icons/core/regular/speaker-simple-x.svg'), + }); + menu.push({ + text: intl.formatMessage(messages.blocks), + to: '/blocks', + icon: require('@phosphor-icons/core/regular/prohibit.svg'), + }); + } else { + menu.push({ + text: intl.formatMessage(messages.mention, { name: account.username }), + action: onMention, + icon: require('@phosphor-icons/core/regular/at.svg'), + }); + + if (features.privacyScopes) { + menu.push({ + text: intl.formatMessage(messages.direct, { name: account.username }), + action: onDirect, + icon: require('@phosphor-icons/core/regular/envelope-simple.svg'), + }); + } + + if (account.relationship?.following) { + if (account.relationship?.showing_reblogs) { + menu.push({ + text: intl.formatMessage(messages.hideReblogs, { name: account.username }), + action: onReblogToggle, + icon: require('@phosphor-icons/core/regular/repeat.svg'), + }); + } else { + menu.push({ + text: intl.formatMessage(messages.showReblogs, { name: account.username }), + action: onReblogToggle, + icon: require('@phosphor-icons/core/regular/repeat.svg'), + }); + } + + if (features.lists) { + menu.push({ + text: intl.formatMessage(messages.addOrRemoveFromList), + action: onAddToList, + icon: require('@phosphor-icons/core/regular/list-bullets.svg'), + }); + } + + if (features.accountEndorsements) { + menu.push({ + text: intl.formatMessage( + account.relationship?.endorsed ? messages.unendorse : messages.endorse, + ), + action: onEndorseToggle, + icon: account.relationship?.endorsed + ? require('@phosphor-icons/core/regular/user-minus.svg') + : require('@phosphor-icons/core/regular/user-check.svg'), + }); + } + } else if (features.lists && features.unrestrictedLists) { + menu.push({ + text: intl.formatMessage(messages.addOrRemoveFromList), + action: onAddToList, + icon: require('@phosphor-icons/core/regular/list-bullets.svg'), + }); + } + + if (features.bites) { + menu.push({ + text: intl.formatMessage(messages.bite, { name: account.username }), + action: onBite, + icon: require('@phosphor-icons/core/regular/tooth.svg'), + }); + } + + if (features.loadActivities && !account.local) { + menu.push({ + text: intl.formatMessage(messages.loadActivities), + action: onLoadActivities, + icon: require('@phosphor-icons/core/regular/arrows-clockwise.svg'), + }); + } + + if (account.relationship && features.notes) { + menu.push({ + text: intl.formatMessage(messages.note, { name: account.acct }), + action: onEditNote, + icon: require('@phosphor-icons/core/regular/note-pencil.svg'), + }); + } + + menu.push(null); + + if (features.removeFromFollowers && account.relationship?.followed_by) { + menu.push({ + text: intl.formatMessage(messages.removeFromFollowers), + action: onRemoveFromFollowers, + icon: require('@phosphor-icons/core/regular/user-minus.svg'), + }); + } + + if (account.relationship?.muting) { + menu.push({ + text: intl.formatMessage(messages.unmute, { name: account.username }), + action: onMute, + icon: require('@phosphor-icons/core/regular/speaker-simple-x.svg'), + }); + } else { + menu.push({ + text: intl.formatMessage(messages.mute, { name: account.username }), + action: onMute, + icon: require('@phosphor-icons/core/regular/speaker-simple-x.svg'), + }); + } + + if (account.relationship?.blocking) { + menu.push({ + text: intl.formatMessage(messages.unblock, { name: account.username }), + action: onBlock, + icon: require('@phosphor-icons/core/regular/prohibit.svg'), + }); + } else { + menu.push({ + text: intl.formatMessage(messages.block, { name: account.username }), + action: onBlock, + icon: require('@phosphor-icons/core/regular/prohibit.svg'), + }); + } + + menu.push({ + text: intl.formatMessage(messages.report, { name: account.username }), + action: onReport, + icon: require('@phosphor-icons/core/regular/flag.svg'), + }); + } + + if (!account.local) { + const domain = account.fqn.split('@')[1]; + + menu.push(null); + + if (account.relationship?.domain_blocking) { + menu.push({ + text: intl.formatMessage(messages.unblockDomain, { domain }), + action: () => { + onUnblockDomain(domain); + }, + icon: require('@phosphor-icons/core/regular/prohibit.svg'), + }); + } else { + menu.push({ + text: intl.formatMessage(messages.blockDomain, { domain }), + action: () => { + onBlockDomain(domain); + }, + icon: require('@phosphor-icons/core/regular/prohibit.svg'), + }); + } + } + + if (ownAccount.is_admin || ownAccount.is_moderator) { + menu.push(null); + + menu.push({ + text: intl.formatMessage(messages.adminAccount, { name: account.username }), + to: '/pl-fe/admin/accounts/$accountId', + params: { accountId: account.id }, + icon: require('@phosphor-icons/core/regular/gavel.svg'), + }); + } + + return menu; + }; + + const menu = makeMenu(); + + if (!menu.length) return null; + + return ( + + + + ); +}; + +export { AccountMenu }; diff --git a/packages/nicolium/src/features/account/components/header.tsx b/packages/nicolium/src/features/account/components/header.tsx index f53932602..c18ab6c61 100644 --- a/packages/nicolium/src/features/account/components/header.tsx +++ b/packages/nicolium/src/features/account/components/header.tsx @@ -6,11 +6,9 @@ import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; import * as v from 'valibot'; -import { initReport, ReportableEntities } from '@/actions/reports'; import Account from '@/components/accounts/account'; import VerificationBadge from '@/components/accounts/verification-badge'; import Badge from '@/components/badge'; -import DropdownMenu, { type Menu } from '@/components/dropdown-menu'; import Icon from '@/components/icon'; import AltIndicator from '@/components/media/alt-indicator'; import StillImage from '@/components/still-image'; @@ -23,103 +21,25 @@ import Text from '@/components/ui/text'; import Emojify from '@/features/emoji/emojify'; import ActionButton from '@/features/ui/components/action-button'; import SubscriptionButton from '@/features/ui/components/subscription-button'; -import { useClient } from '@/hooks/use-client'; import { useFeatures } from '@/hooks/use-features'; import { useOwnAccount } from '@/hooks/use-own-account'; -import { - useFollowAccountMutation, - usePinAccountMutation, - useRemoveAccountFromFollowersMutation, - useUnblockAccountMutation, - useUnmuteAccountMutation, - useUnpinAccountMutation, - useUpdateAccountNoteMutation, -} from '@/queries/accounts/use-relationship'; import { useChats } from '@/queries/chats'; import { queryClient } from '@/queries/client'; import { queryKeys } from '@/queries/keys'; -import { - blockDomainMutationOptions, - unblockDomainMutationOptions, -} from '@/queries/settings/domain-blocks'; -import { useComposeActions } from '@/stores/compose'; import { useModalsActions } from '@/stores/modals'; import { useSettings } from '@/stores/settings'; import toast from '@/toast'; -import copy from '@/utils/copy'; + +import { AccountMenu } from './account-menu'; import type { PlfeResponse } from '@/api'; import type { Account as AccountEntity } from 'pl-api'; const messages = defineMessages({ - editProfile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, - mention: { id: 'account.mention', defaultMessage: 'Mention' }, chat: { id: 'account.chat', defaultMessage: 'Chat with @{name}' }, - direct: { id: 'account.direct', defaultMessage: 'Direct message @{name}' }, - unmute: { id: 'account.unmute', defaultMessage: 'Unmute @{name}' }, - block: { id: 'account.block', defaultMessage: 'Block @{name}' }, - unblock: { id: 'account.unblock', defaultMessage: 'Unblock @{name}' }, - mute: { id: 'account.mute', defaultMessage: 'Mute @{name}' }, - report: { id: 'account.report', defaultMessage: 'Report @{name}' }, - copy: { id: 'account.copy', defaultMessage: 'Copy link to profile' }, share: { id: 'account.share', defaultMessage: "Share @{name}'s profile" }, - media: { id: 'account.media', defaultMessage: 'Media' }, - blockDomain: { id: 'account.block_domain', defaultMessage: 'Hide everything from {domain}' }, - unblockDomain: { id: 'account.unblock_domain', defaultMessage: 'Unhide {domain}' }, - hideReblogs: { id: 'account.hide_reblogs', defaultMessage: 'Hide reposts from @{name}' }, - showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show reposts from @{name}' }, - preferences: { id: 'column.preferences', defaultMessage: 'Preferences' }, - blocks: { id: 'column.blocks', defaultMessage: 'Blocks' }, - mutes: { id: 'column.mutes', defaultMessage: 'Mutes' }, - endorse: { id: 'account.endorse', defaultMessage: 'Feature on profile' }, - unendorse: { id: 'account.unendorse', defaultMessage: "Don't feature on profile" }, - bite: { id: 'account.bite', defaultMessage: 'Bite @{name}' }, - removeFromFollowers: { - id: 'account.remove_from_followers', - defaultMessage: 'Remove this follower', - }, - adminAccount: { id: 'status.admin_account', defaultMessage: 'Moderate @{name}' }, - addOrRemoveFromList: { - id: 'account.add_or_remove_from_list', - defaultMessage: 'Add or remove from lists', - }, - search: { id: 'account.search', defaultMessage: 'Search from @{name}' }, - searchSelf: { id: 'account.search_self', defaultMessage: 'Search your posts' }, - unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' }, - blockDomainConfirm: { - id: 'confirmations.domain_block.confirm', - defaultMessage: 'Hide entire domain', - }, - removeFromFollowersConfirm: { - id: 'confirmations.remove_from_followers.confirm', - defaultMessage: 'Remove', - }, - userEndorsed: { - id: 'account.endorse.success', - defaultMessage: 'You are now featuring @{acct} on your profile', - }, - userUnendorsed: { - id: 'account.unendorse.success', - defaultMessage: 'You are no longer featuring @{acct}', - }, - userBit: { id: 'account.bite.success', defaultMessage: 'You have bit @{acct}' }, - userBiteFail: { id: 'account.bite.fail', defaultMessage: 'Failed to bite @{acct}' }, - profileExternal: { id: 'account.profile_external', defaultMessage: 'View profile on {domain}' }, header: { id: 'account.header.alt', defaultMessage: 'Profile header' }, subscribeFeed: { id: 'account.rss_feed', defaultMessage: 'Subscribe to RSS feed' }, - loadActivities: { id: 'account.load_activities', defaultMessage: 'Fetch latest posts' }, - loadActivitiesSuccess: { - id: 'account.load_activities.success', - defaultMessage: 'Scheduled fetching latest posts', - }, - loadActivitiesFail: { - id: 'account.load_activities.fail', - defaultMessage: 'Failed to fetch latest posts', - }, - note: { id: 'account_note.modal_header', defaultMessage: 'Edit note for @{name}' }, - notePlaceholder: { id: 'account_note.placeholder', defaultMessage: 'Add a note' }, - noteSaved: { id: 'account_note.success', defaultMessage: 'Note saved' }, - noteSaveFailed: { id: 'account_note.fail', defaultMessage: 'Failed to save note' }, headerAlt: { id: 'account.header.alt.popover', defaultMessage: 'Show profile header alt text' }, }); @@ -165,18 +85,9 @@ interface IHeader { const Header: React.FC = ({ account }) => { const intl = useIntl(); const navigate = useNavigate(); - const { mentionCompose, directCompose } = useComposeActions(); - const client = useClient(); const features = useFeatures(); const { data: ownAccount } = useOwnAccount(); - const { mutate: followAccount } = useFollowAccountMutation(account?.id!); - const { mutate: unblockAccount } = useUnblockAccountMutation(account?.id!); - const { mutate: unmuteAccount } = useUnmuteAccountMutation(account?.id!); - const { mutate: pinAccount } = usePinAccountMutation(account?.id!); - const { mutate: unpinAccount } = useUnpinAccountMutation(account?.id!); - const { mutate: removeFromFollowers } = useRemoveAccountFromFollowersMutation(account?.id!); - const { mutate: updateAccountNote } = useUpdateAccountNoteMutation(account?.id!); const { openModal } = useModalsActions(); const settings = useSettings(); @@ -184,9 +95,6 @@ const Header: React.FC = ({ account }) => { const { getOrCreateChatByAccountId } = useChats(); - const { mutate: blockDomain } = useMutation(blockDomainMutationOptions); - const { mutate: unblockDomain } = useMutation(unblockDomainMutationOptions); - const createAndNavigateToChat = useMutation({ mutationFn: (accountId: string) => getOrCreateChatByAccountId(accountId), onError: (error: { response: PlfeResponse }) => { @@ -219,166 +127,6 @@ const Header: React.FC = ({ account }) => { ); } - const onBlock = () => { - if (account.relationship?.blocking) { - unblockAccount(); - } else { - openModal('BLOCK_MUTE', { accountId: account.id, action: 'BLOCK' }); - } - }; - - const onMention = () => { - mentionCompose(account); - }; - - const onDirect = () => { - directCompose(account); - }; - - const onReblogToggle = () => { - if (account.relationship?.showing_reblogs) { - followAccount({ reblogs: false }); - } else { - followAccount({ reblogs: true }); - } - }; - - const onEndorseToggle = () => { - if (account.relationship?.endorsed) { - unpinAccount(undefined, { - onSuccess: () => { - toast.success(intl.formatMessage(messages.userUnendorsed, { acct: account.acct })); - }, - }); - } else { - pinAccount(undefined, { - onSuccess: () => { - toast.success(intl.formatMessage(messages.userEndorsed, { acct: account.acct })); - }, - }); - } - }; - - const onBite = () => { - client.accounts - .biteAccount(account.id) - .then(() => { - toast.success(intl.formatMessage(messages.userBit, { acct: account.acct })); - }) - .catch(() => { - toast.error(intl.formatMessage(messages.userBiteFail, { acct: account.acct })); - }); - }; - - const onLoadActivities = () => { - client.accounts - .loadActivities(account.id) - .then(() => { - toast.success(intl.formatMessage(messages.loadActivitiesSuccess)); - }) - .catch(() => { - toast.error(intl.formatMessage(messages.loadActivitiesFail)); - }); - }; - - const onEditNote = () => { - openModal('TEXT_FIELD', { - heading: ( - - ), - placeholder: intl.formatMessage(messages.notePlaceholder), - confirm: , - onConfirm: (value) => { - updateAccountNote(value, { - onSuccess: () => { - toast.success(messages.noteSaved); - }, - onError: () => { - toast.error(messages.noteSaveFailed); - }, - }); - }, - text: account.relationship?.note ?? '', - }); - }; - - const onReport = () => { - initReport(ReportableEntities.ACCOUNT, account); - }; - - const onMute = () => { - if (account.relationship?.muting) { - unmuteAccount(); - } else { - openModal('BLOCK_MUTE', { accountId: account.id, action: 'MUTE' }); - } - }; - - const onBlockDomain = (domain: string) => { - openModal('CONFIRM', { - heading: ( - - ), - message: ( - {domain} }} - /> - ), - confirm: intl.formatMessage(messages.blockDomainConfirm), - onConfirm: () => { - blockDomain(domain); - }, - }); - }; - - const onUnblockDomain = (domain: string) => { - unblockDomain(domain); - }; - - const onAddToList = () => { - openModal('LIST_ADDER', { - accountId: account.id, - }); - }; - - const onRemoveFromFollowers = () => { - const unfollowModal = settings.unfollowModal; - if (unfollowModal) { - openModal('CONFIRM', { - heading: ( - @{account.acct} }} - /> - ), - message: ( - @{account.acct} }} - /> - ), - confirm: intl.formatMessage(messages.removeFromFollowersConfirm), - onConfirm: () => { - removeFromFollowers(); - }, - }); - } else { - removeFromFollowers(); - } - }; - const onAvatarClick = () => { const avatar = v.parse(mediaAttachmentSchema, { id: '', @@ -421,254 +169,6 @@ const Header: React.FC = ({ account }) => { }); }; - const handleCopy: React.EventHandler = () => { - copy(account.url); - }; - - const makeMenu = () => { - const menu: Menu = []; - - if (!account) { - return []; - } - - if (features.rssFeeds && account.local && (software !== GOTOSOCIAL || account.enable_rss)) { - menu.push({ - text: intl.formatMessage(messages.subscribeFeed), - icon: require('@phosphor-icons/core/regular/rss.svg'), - href: software === MASTODON ? `${account.url}.rss` : `${account.url}/feed.rss`, - target: '_blank', - }); - } - - if ('share' in navigator) { - menu.push({ - text: intl.formatMessage(messages.share, { name: account.username }), - action: handleShare, - icon: require('@phosphor-icons/core/regular/export.svg'), - }); - } - - if (features.federating && !account.local) { - const domain = account.fqn.split('@')[1]; - - menu.push({ - text: intl.formatMessage(messages.profileExternal, { domain }), - href: account.url, - icon: require('@phosphor-icons/core/regular/arrow-square-out.svg'), - }); - } - - menu.push({ - text: intl.formatMessage(messages.copy), - action: handleCopy, - icon: require('@phosphor-icons/core/regular/clipboard.svg'), - }); - - if (!ownAccount) return menu; - - if (features.searchFromAccount) { - menu.push({ - text: intl.formatMessage( - account.id === ownAccount.id ? messages.searchSelf : messages.search, - { name: account.username }, - ), - to: '/search', - search: { type: 'statuses', accountId: account.id }, - icon: require('@phosphor-icons/core/regular/magnifying-glass.svg'), - }); - } - - if (menu.length) { - menu.push(null); - } - - if (account.id === ownAccount.id) { - menu.push({ - text: intl.formatMessage(messages.editProfile), - to: '/settings/profile', - icon: require('@phosphor-icons/core/regular/user.svg'), - }); - menu.push({ - text: intl.formatMessage(messages.preferences), - to: '/settings', - icon: require('@phosphor-icons/core/regular/sliders-horizontal.svg'), - }); - menu.push(null); - menu.push({ - text: intl.formatMessage(messages.mutes), - to: '/mutes', - icon: require('@phosphor-icons/core/regular/speaker-simple-x.svg'), - }); - menu.push({ - text: intl.formatMessage(messages.blocks), - to: '/blocks', - icon: require('@phosphor-icons/core/regular/prohibit.svg'), - }); - } else { - menu.push({ - text: intl.formatMessage(messages.mention, { name: account.username }), - action: onMention, - icon: require('@phosphor-icons/core/regular/at.svg'), - }); - - if (features.privacyScopes) { - menu.push({ - text: intl.formatMessage(messages.direct, { name: account.username }), - action: onDirect, - icon: require('@phosphor-icons/core/regular/envelope-simple.svg'), - }); - } - - if (account.relationship?.following) { - if (account.relationship?.showing_reblogs) { - menu.push({ - text: intl.formatMessage(messages.hideReblogs, { name: account.username }), - action: onReblogToggle, - icon: require('@phosphor-icons/core/regular/repeat.svg'), - }); - } else { - menu.push({ - text: intl.formatMessage(messages.showReblogs, { name: account.username }), - action: onReblogToggle, - icon: require('@phosphor-icons/core/regular/repeat.svg'), - }); - } - - if (features.lists) { - menu.push({ - text: intl.formatMessage(messages.addOrRemoveFromList), - action: onAddToList, - icon: require('@phosphor-icons/core/regular/list-bullets.svg'), - }); - } - - if (features.accountEndorsements) { - menu.push({ - text: intl.formatMessage( - account.relationship?.endorsed ? messages.unendorse : messages.endorse, - ), - action: onEndorseToggle, - icon: account.relationship?.endorsed - ? require('@phosphor-icons/core/regular/user-minus.svg') - : require('@phosphor-icons/core/regular/user-check.svg'), - }); - } - } else if (features.lists && features.unrestrictedLists) { - menu.push({ - text: intl.formatMessage(messages.addOrRemoveFromList), - action: onAddToList, - icon: require('@phosphor-icons/core/regular/list-bullets.svg'), - }); - } - - if (features.bites) { - menu.push({ - text: intl.formatMessage(messages.bite, { name: account.username }), - action: onBite, - icon: require('@phosphor-icons/core/regular/tooth.svg'), - }); - } - - if (features.loadActivities && !account.local) { - menu.push({ - text: intl.formatMessage(messages.loadActivities), - action: onLoadActivities, - icon: require('@phosphor-icons/core/regular/arrows-clockwise.svg'), - }); - } - - if (account.relationship && features.notes) { - menu.push({ - text: intl.formatMessage(messages.note, { name: account.acct }), - action: onEditNote, - icon: require('@phosphor-icons/core/regular/note-pencil.svg'), - }); - } - - menu.push(null); - - if (features.removeFromFollowers && account.relationship?.followed_by) { - menu.push({ - text: intl.formatMessage(messages.removeFromFollowers), - action: onRemoveFromFollowers, - icon: require('@phosphor-icons/core/regular/user-minus.svg'), - }); - } - - if (account.relationship?.muting) { - menu.push({ - text: intl.formatMessage(messages.unmute, { name: account.username }), - action: onMute, - icon: require('@phosphor-icons/core/regular/speaker-simple-x.svg'), - }); - } else { - menu.push({ - text: intl.formatMessage(messages.mute, { name: account.username }), - action: onMute, - icon: require('@phosphor-icons/core/regular/speaker-simple-x.svg'), - }); - } - - if (account.relationship?.blocking) { - menu.push({ - text: intl.formatMessage(messages.unblock, { name: account.username }), - action: onBlock, - icon: require('@phosphor-icons/core/regular/prohibit.svg'), - }); - } else { - menu.push({ - text: intl.formatMessage(messages.block, { name: account.username }), - action: onBlock, - icon: require('@phosphor-icons/core/regular/prohibit.svg'), - }); - } - - menu.push({ - text: intl.formatMessage(messages.report, { name: account.username }), - action: onReport, - icon: require('@phosphor-icons/core/regular/flag.svg'), - }); - } - - if (!account.local) { - const domain = account.fqn.split('@')[1]; - - menu.push(null); - - if (account.relationship?.domain_blocking) { - menu.push({ - text: intl.formatMessage(messages.unblockDomain, { domain }), - action: () => { - onUnblockDomain(domain); - }, - icon: require('@phosphor-icons/core/regular/prohibit.svg'), - }); - } else { - menu.push({ - text: intl.formatMessage(messages.blockDomain, { domain }), - action: () => { - onBlockDomain(domain); - }, - icon: require('@phosphor-icons/core/regular/prohibit.svg'), - }); - } - } - - if (ownAccount.is_admin || ownAccount.is_moderator) { - menu.push(null); - - menu.push({ - text: intl.formatMessage(messages.adminAccount, { name: account.username }), - to: '/pl-fe/admin/accounts/$accountId', - params: { accountId: account.id }, - icon: require('@phosphor-icons/core/regular/gavel.svg'), - }); - } - - return menu; - }; - const makeInfo = () => { const info: React.ReactNode[] = []; @@ -832,7 +332,6 @@ const Header: React.FC = ({ account }) => { }; const info = makeInfo(); - const menu = makeMenu(); return (
@@ -888,16 +387,7 @@ const Header: React.FC = ({ account }) => { {renderMessageButton()} {renderShareButton()} - {menu.length > 0 && ( - - - - )} + {renderRssButton()} diff --git a/packages/nicolium/src/styles/new/layout.scss b/packages/nicolium/src/styles/new/layout.scss index 00943dd64..17116b3bc 100644 --- a/packages/nicolium/src/styles/new/layout.scss +++ b/packages/nicolium/src/styles/new/layout.scss @@ -5,8 +5,8 @@ html { height: 100%; --font-sans: - nicolium i18n, 'Inter', ui-sans-serif, system-ui, -apple-system, 'BlinkMacSystemFont', 'Segoe UI', - 'Roboto', 'Helvetica Neue', 'Arial', 'Noto Sans', sans-serif, 'Apple Color Emoji', + nicolium i18n, 'Inter', ui-sans-serif, system-ui, -apple-system, 'BlinkMacSystemFont', + 'Segoe UI', 'Roboto', 'Helvetica Neue', 'Arial', 'Noto Sans', sans-serif, 'Apple Color Emoji', 'Segoe UI Emoji', 'Segoe UI Symbol', 'Noto Color Emoji'; --font-mono: 'Roboto Mono', ui-monospace, monospace; }