pl-fe: Split StatusActionBar into separate components
Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
This commit is contained in:
parent
618f5f5f25
commit
492a4214a5
1 changed files with 449 additions and 247 deletions
|
@ -43,6 +43,7 @@ import type { UnauthorizedModalAction } from 'pl-fe/features/ui/components/modal
|
|||
import type { Account } from 'pl-fe/normalizers/account';
|
||||
import type { Group } from 'pl-fe/normalizers/group';
|
||||
import type { SelectedStatus } from 'pl-fe/selectors';
|
||||
import type { Me } from 'pl-fe/types/pl-fe';
|
||||
|
||||
const messages = defineMessages({
|
||||
adminAccount: { id: 'status.admin_account', defaultMessage: 'Moderate @{name}' },
|
||||
|
@ -110,29 +111,358 @@ const messages = defineMessages({
|
|||
hideTranslation: { id: 'status.hide_translation', defaultMessage: 'Hide translation' },
|
||||
});
|
||||
|
||||
interface IStatusActionBar {
|
||||
status: SelectedStatus;
|
||||
interface IActionButton extends Pick<IStatusActionBar, 'status' | 'statusActionButtonTheme' | 'withLabels'> {
|
||||
me: Me;
|
||||
onOpenUnauthorizedModal: (action?: UnauthorizedModalAction) => void;
|
||||
}
|
||||
|
||||
interface IReplyButton extends IActionButton {
|
||||
rebloggedBy?: Account;
|
||||
withLabels?: boolean;
|
||||
}
|
||||
|
||||
const ReplyButton: React.FC<IReplyButton> = ({
|
||||
status,
|
||||
statusActionButtonTheme,
|
||||
withLabels,
|
||||
me,
|
||||
onOpenUnauthorizedModal,
|
||||
rebloggedBy,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
|
||||
const { groupRelationship } = useGroupRelationship(status.group_id || undefined);
|
||||
|
||||
let replyTitle;
|
||||
let replyDisabled = false;
|
||||
const replyCount = status.replies_count;
|
||||
|
||||
if ((status.group as Group)?.membership_required && !groupRelationship?.member) {
|
||||
replyDisabled = true;
|
||||
replyTitle = intl.formatMessage(messages.replies_disabled_group);
|
||||
}
|
||||
|
||||
if (!status.in_reply_to_id) {
|
||||
replyTitle = intl.formatMessage(messages.reply);
|
||||
} else {
|
||||
replyTitle = intl.formatMessage(messages.replyAll);
|
||||
}
|
||||
|
||||
const handleReplyClick: React.MouseEventHandler = (e) => {
|
||||
if (me) {
|
||||
dispatch(replyCompose(status, rebloggedBy));
|
||||
} else {
|
||||
onOpenUnauthorizedModal('REPLY');
|
||||
}
|
||||
};
|
||||
|
||||
const replyButton = (
|
||||
<StatusActionButton
|
||||
title={replyTitle}
|
||||
icon={require('@tabler/icons/outline/message-circle.svg')}
|
||||
onClick={handleReplyClick}
|
||||
count={replyCount}
|
||||
text={withLabels ? intl.formatMessage(messages.reply) : undefined}
|
||||
disabled={replyDisabled}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
);
|
||||
|
||||
return status.group ? (
|
||||
<GroupPopover
|
||||
group={status.group}
|
||||
isEnabled={replyDisabled}
|
||||
>
|
||||
{replyButton}
|
||||
</GroupPopover>
|
||||
) : replyButton;
|
||||
};
|
||||
|
||||
interface IReblogButton extends IActionButton {
|
||||
publicStatus: boolean;
|
||||
}
|
||||
|
||||
const ReblogButton: React.FC<IReblogButton> = ({
|
||||
status,
|
||||
statusActionButtonTheme,
|
||||
withLabels,
|
||||
me,
|
||||
onOpenUnauthorizedModal,
|
||||
publicStatus,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const features = useFeatures();
|
||||
const intl = useIntl();
|
||||
|
||||
const { boostModal } = useSettings();
|
||||
const { openModal } = useModalsStore();
|
||||
|
||||
let reblogIcon = require('@tabler/icons/outline/repeat.svg');
|
||||
|
||||
if (status.visibility === 'direct') {
|
||||
reblogIcon = require('@tabler/icons/outline/mail.svg');
|
||||
} else if (status.visibility === 'private' || status.visibility === 'mutuals_only') {
|
||||
reblogIcon = require('@tabler/icons/outline/lock.svg');
|
||||
}
|
||||
|
||||
const handleReblogClick: React.EventHandler<React.MouseEvent> = e => {
|
||||
if (me) {
|
||||
const modalReblog = () => dispatch(toggleReblog(status));
|
||||
if ((e && e.shiftKey) || !boostModal) {
|
||||
modalReblog();
|
||||
} else {
|
||||
openModal('BOOST', { statusId: status.id, onReblog: modalReblog });
|
||||
}
|
||||
} else {
|
||||
onOpenUnauthorizedModal('REBLOG');
|
||||
}
|
||||
};
|
||||
|
||||
const handleReblogLongPress = status.reblogs_count ? () => {
|
||||
openModal('REBLOGS', { statusId: status.id });
|
||||
} : undefined;
|
||||
|
||||
const reblogButton = (
|
||||
<StatusActionButton
|
||||
icon={reblogIcon}
|
||||
color='success'
|
||||
disabled={!publicStatus}
|
||||
title={!publicStatus ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)}
|
||||
active={status.reblogged}
|
||||
onClick={handleReblogClick}
|
||||
onLongPress={handleReblogLongPress}
|
||||
count={status.reblogs_count + status.quotes_count}
|
||||
text={withLabels ? intl.formatMessage(messages.reblog) : undefined}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
);
|
||||
|
||||
if (!features.quotePosts || !me) return reblogButton;
|
||||
|
||||
const handleQuoteClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (me) {
|
||||
dispatch(quoteCompose(status));
|
||||
} else {
|
||||
onOpenUnauthorizedModal('REBLOG');
|
||||
}
|
||||
};
|
||||
|
||||
const reblogMenu = [{
|
||||
text: intl.formatMessage(status.reblogged ? messages.cancel_reblog_private : messages.reblog),
|
||||
action: handleReblogClick,
|
||||
icon: require('@tabler/icons/outline/repeat.svg'),
|
||||
}, {
|
||||
text: intl.formatMessage(messages.quotePost),
|
||||
action: handleQuoteClick,
|
||||
icon: require('@tabler/icons/outline/quote.svg'),
|
||||
}];
|
||||
|
||||
return (
|
||||
<DropdownMenu
|
||||
items={reblogMenu}
|
||||
disabled={!publicStatus}
|
||||
onShiftClick={handleReblogClick}
|
||||
>
|
||||
{reblogButton}
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
|
||||
const FavouriteButton: React.FC<IActionButton> = ({
|
||||
status,
|
||||
statusActionButtonTheme,
|
||||
me,
|
||||
withLabels,
|
||||
onOpenUnauthorizedModal,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const features = useFeatures();
|
||||
const intl = useIntl();
|
||||
|
||||
const { openModal } = useModalsStore();
|
||||
|
||||
const handleFavouriteClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (me) {
|
||||
dispatch(toggleFavourite(status));
|
||||
} else {
|
||||
onOpenUnauthorizedModal('FAVOURITE');
|
||||
}
|
||||
};
|
||||
|
||||
const handleFavouriteLongPress = status.favourites_count ? () => {
|
||||
openModal('FAVOURITES', { statusId: status.id });
|
||||
} : undefined;
|
||||
|
||||
return (
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.favourite)}
|
||||
icon={features.statusDislikes ? require('@tabler/icons/outline/thumb-up.svg') : require('@tabler/icons/outline/heart.svg')}
|
||||
color='accent'
|
||||
filled
|
||||
onClick={handleFavouriteClick}
|
||||
onLongPress={handleFavouriteLongPress}
|
||||
active={status.favourited}
|
||||
count={status.favourites_count}
|
||||
text={withLabels ? intl.formatMessage(messages.favourite) : undefined}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const DislikeButton: React.FC<IActionButton> = ({
|
||||
status,
|
||||
statusActionButtonTheme,
|
||||
withLabels,
|
||||
me,
|
||||
onOpenUnauthorizedModal,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const features = useFeatures();
|
||||
const intl = useIntl();
|
||||
|
||||
const { openModal } = useModalsStore();
|
||||
|
||||
if (!features.statusDislikes) return;
|
||||
|
||||
const handleDislikeClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (me) {
|
||||
dispatch(toggleDislike(status));
|
||||
} else {
|
||||
onOpenUnauthorizedModal('DISLIKE');
|
||||
}
|
||||
};
|
||||
|
||||
const handleDislikeLongPress = status.dislikes_count ? () => {
|
||||
openModal('DISLIKES', { statusId: status.id });
|
||||
} : undefined;
|
||||
|
||||
return (
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.disfavourite)}
|
||||
icon={require('@tabler/icons/outline/thumb-down.svg')}
|
||||
color='accent'
|
||||
filled
|
||||
onClick={handleDislikeClick}
|
||||
onLongPress={handleDislikeLongPress}
|
||||
active={status.disliked}
|
||||
count={status.dislikes_count}
|
||||
text={withLabels ? intl.formatMessage(messages.disfavourite) : undefined}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const WrenchButton: React.FC<IActionButton> = ({
|
||||
status,
|
||||
statusActionButtonTheme,
|
||||
withLabels,
|
||||
me,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
const intl = useIntl();
|
||||
const features = useFeatures();
|
||||
|
||||
const { openModal } = useModalsStore();
|
||||
const { showWrenchButton } = useSettings();
|
||||
|
||||
if (!me || withLabels || !features.emojiReacts || !showWrenchButton) return;
|
||||
|
||||
const wrenches = showWrenchButton && status.emoji_reactions.find(emoji => emoji.name === '🔧') || undefined;
|
||||
|
||||
const handleWrenchClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (wrenches?.me) {
|
||||
dispatch(unEmojiReact(status, '🔧'));
|
||||
} else {
|
||||
dispatch(emojiReact(status, '🔧'));
|
||||
}
|
||||
};
|
||||
|
||||
const handleWrenchLongPress = wrenches?.count ? () => {
|
||||
openModal('REACTIONS', { statusId: status.id, reaction: wrenches.name });
|
||||
} : undefined;
|
||||
|
||||
return (
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.wrench)}
|
||||
icon={require('@tabler/icons/outline/tool.svg')}
|
||||
color='accent'
|
||||
filled
|
||||
onClick={handleWrenchClick}
|
||||
onLongPress={handleWrenchLongPress}
|
||||
active={wrenches?.me}
|
||||
count={wrenches?.count || undefined}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const EmojiPickerButton: React.FC<Omit<IActionButton, 'onOpenUnauthorizedModal'>> = ({
|
||||
status,
|
||||
statusActionButtonTheme,
|
||||
withLabels,
|
||||
me,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const features = useFeatures();
|
||||
|
||||
const handlePickEmoji = (emoji: EmojiType) => {
|
||||
dispatch(emojiReact(status, emoji.custom ? emoji.id : emoji.native, emoji.custom ? emoji.imageUrl : undefined));
|
||||
};
|
||||
|
||||
return me && !withLabels && features.emojiReacts && (
|
||||
<EmojiPickerDropdown
|
||||
onPickEmoji={handlePickEmoji}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
const ShareButton: React.FC<Pick<IActionButton, 'status' | 'statusActionButtonTheme'>> = ({
|
||||
status,
|
||||
statusActionButtonTheme,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
|
||||
const handleShareClick = () => {
|
||||
navigator.share({
|
||||
text: status.search_index,
|
||||
url: status.uri,
|
||||
}).catch((e) => {
|
||||
if (e.name !== 'AbortError') console.error(e);
|
||||
});
|
||||
};
|
||||
|
||||
const canShare = ('share' in navigator) && (status.visibility === 'public' || status.visibility === 'group');
|
||||
|
||||
return canShare && (
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.share)}
|
||||
icon={require('@tabler/icons/outline/upload.svg')}
|
||||
onClick={handleShareClick}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
);
|
||||
};
|
||||
|
||||
interface IMenuButton extends IActionButton {
|
||||
expandable?: boolean;
|
||||
space?: 'sm' | 'md' | 'lg';
|
||||
statusActionButtonTheme?: 'default' | 'inverse';
|
||||
fromBookmarks?: boolean;
|
||||
}
|
||||
|
||||
const StatusActionBar: React.FC<IStatusActionBar> = ({
|
||||
const MenuButton: React.FC<IMenuButton> = ({
|
||||
status,
|
||||
withLabels = false,
|
||||
statusActionButtonTheme,
|
||||
withLabels,
|
||||
me,
|
||||
expandable,
|
||||
space = 'sm',
|
||||
statusActionButtonTheme = 'default',
|
||||
fromBookmarks = false,
|
||||
rebloggedBy,
|
||||
fromBookmarks,
|
||||
}) => {
|
||||
const intl = useIntl();
|
||||
const history = useHistory();
|
||||
const dispatch = useAppDispatch();
|
||||
const match = useRouteMatch<{ groupId: string }>('/groups/:groupId');
|
||||
const { boostModal } = useSettings();
|
||||
|
||||
const { openModal } = useModalsStore();
|
||||
const { group } = useGroup((status.group as Group)?.id as string);
|
||||
|
@ -140,13 +470,10 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
const blockGroupMember = useBlockGroupMember(group as Group, status.account);
|
||||
const { getOrCreateChatByAccountId } = useChats();
|
||||
|
||||
const me = useAppSelector(state => state.me);
|
||||
const { groupRelationship } = useGroupRelationship(status.group_id || undefined);
|
||||
const features = useFeatures();
|
||||
const instance = useInstance();
|
||||
const { autoTranslate, boostModal, deleteModal, knownLanguages, showWrenchButton } = useSettings();
|
||||
|
||||
const wrenches = showWrenchButton && status.emoji_reactions.find(emoji => emoji.name === '🔧') || undefined;
|
||||
const { autoTranslate, deleteModal, knownLanguages } = useSettings();
|
||||
|
||||
const { translationLanguages } = useTranslationLanguages();
|
||||
|
||||
|
@ -166,76 +493,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
const isStaff = account ? account.is_admin || account.is_moderator : false;
|
||||
const isAdmin = account ? account.is_admin : false;
|
||||
|
||||
if (!status) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const onOpenUnauthorizedModal = (action?: UnauthorizedModalAction) => {
|
||||
openModal('UNAUTHORIZED', {
|
||||
action,
|
||||
ap_id: status.url,
|
||||
});
|
||||
};
|
||||
|
||||
const handleReplyClick: React.MouseEventHandler = (e) => {
|
||||
if (me) {
|
||||
dispatch(replyCompose(status, rebloggedBy));
|
||||
} else {
|
||||
onOpenUnauthorizedModal('REPLY');
|
||||
}
|
||||
};
|
||||
|
||||
const handleShareClick = () => {
|
||||
navigator.share({
|
||||
text: status.search_index,
|
||||
url: status.uri,
|
||||
}).catch((e) => {
|
||||
if (e.name !== 'AbortError') console.error(e);
|
||||
});
|
||||
};
|
||||
|
||||
const handleFavouriteClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (me) {
|
||||
dispatch(toggleFavourite(status));
|
||||
} else {
|
||||
onOpenUnauthorizedModal('FAVOURITE');
|
||||
}
|
||||
};
|
||||
|
||||
const handleFavouriteLongPress = status.favourites_count ? () => {
|
||||
openModal('FAVOURITES', { statusId: status.id });
|
||||
} : undefined;
|
||||
|
||||
const handleDislikeClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (me) {
|
||||
dispatch(toggleDislike(status));
|
||||
} else {
|
||||
onOpenUnauthorizedModal('DISLIKE');
|
||||
}
|
||||
};
|
||||
|
||||
const handleWrenchClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (!me) {
|
||||
onOpenUnauthorizedModal('DISLIKE');
|
||||
} else if (wrenches?.me) {
|
||||
dispatch(unEmojiReact(status, '🔧'));
|
||||
} else {
|
||||
dispatch(emojiReact(status, '🔧'));
|
||||
}
|
||||
};
|
||||
|
||||
const handleDislikeLongPress = status.dislikes_count ? () => {
|
||||
openModal('DISLIKES', { statusId: status.id });
|
||||
} : undefined;
|
||||
|
||||
const handleWrenchLongPress = wrenches?.count ? () => {
|
||||
openModal('REACTIONS', { statusId: status.id, reaction: wrenches.name });
|
||||
} : undefined;
|
||||
|
||||
const handlePickEmoji = (emoji: EmojiType) => {
|
||||
dispatch(emojiReact(status, emoji.custom ? emoji.id : emoji.native, emoji.custom ? emoji.imageUrl : undefined));
|
||||
};
|
||||
|
||||
const handleBookmarkClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
dispatch(toggleBookmark(status));
|
||||
};
|
||||
|
@ -246,31 +503,6 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
});
|
||||
};
|
||||
|
||||
const handleReblogClick: React.EventHandler<React.MouseEvent> = e => {
|
||||
if (me) {
|
||||
const modalReblog = () => dispatch(toggleReblog(status));
|
||||
if ((e && e.shiftKey) || !boostModal) {
|
||||
modalReblog();
|
||||
} else {
|
||||
openModal('BOOST', { statusId: status.id, onReblog: modalReblog });
|
||||
}
|
||||
} else {
|
||||
onOpenUnauthorizedModal('REBLOG');
|
||||
}
|
||||
};
|
||||
|
||||
const handleReblogLongPress = status.reblogs_count ? () => {
|
||||
openModal('REBLOGS', { statusId: status.id });
|
||||
} : undefined;
|
||||
|
||||
const handleQuoteClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
if (me) {
|
||||
dispatch(quoteCompose(status));
|
||||
} else {
|
||||
onOpenUnauthorizedModal('REBLOG');
|
||||
}
|
||||
};
|
||||
|
||||
const doDeleteStatus = (withRedraft = false) => {
|
||||
if (!deleteModal) {
|
||||
dispatch(deleteStatus(status.id, withRedraft));
|
||||
|
@ -301,6 +533,15 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
dispatch(togglePin(status));
|
||||
};
|
||||
|
||||
const handleReblogClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
const modalReblog = () => dispatch(toggleReblog(status));
|
||||
if ((e && e.shiftKey) || !boostModal) {
|
||||
modalReblog();
|
||||
} else {
|
||||
openModal('BOOST', { statusId: status.id, onReblog: modalReblog });
|
||||
}
|
||||
};
|
||||
|
||||
const handleMentionClick: React.EventHandler<React.MouseEvent> = (e) => {
|
||||
dispatch(mentionCompose(status.account));
|
||||
};
|
||||
|
@ -669,71 +910,55 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
|
||||
const publicStatus = ['public', 'unlisted', 'group'].includes(status.visibility);
|
||||
|
||||
const replyCount = status.replies_count;
|
||||
const reblogCount = status.reblogs_count;
|
||||
const quoteCount = status.quotes_count;
|
||||
const favouriteCount = status.favourites_count;
|
||||
|
||||
const menu = _makeMenu(publicStatus);
|
||||
let reblogIcon = require('@tabler/icons/outline/repeat.svg');
|
||||
let replyTitle;
|
||||
let replyDisabled = false;
|
||||
|
||||
if (status.visibility === 'direct') {
|
||||
reblogIcon = require('@tabler/icons/outline/mail.svg');
|
||||
} else if (status.visibility === 'private' || status.visibility === 'mutuals_only') {
|
||||
reblogIcon = require('@tabler/icons/outline/lock.svg');
|
||||
}
|
||||
|
||||
if ((status.group as Group)?.membership_required && !groupRelationship?.member) {
|
||||
replyDisabled = true;
|
||||
replyTitle = intl.formatMessage(messages.replies_disabled_group);
|
||||
}
|
||||
|
||||
const replyButton = (
|
||||
<StatusActionButton
|
||||
title={replyTitle}
|
||||
icon={require('@tabler/icons/outline/message-circle.svg')}
|
||||
onClick={handleReplyClick}
|
||||
count={replyCount}
|
||||
text={withLabels ? intl.formatMessage(messages.reply) : undefined}
|
||||
disabled={replyDisabled}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
return (
|
||||
<DropdownMenu items={menu}>
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.more)}
|
||||
icon={require('@tabler/icons/outline/dots.svg')}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
</DropdownMenu>
|
||||
);
|
||||
};
|
||||
|
||||
const reblogMenu = [{
|
||||
text: intl.formatMessage(status.reblogged ? messages.cancel_reblog_private : messages.reblog),
|
||||
action: handleReblogClick,
|
||||
icon: require('@tabler/icons/outline/repeat.svg'),
|
||||
}, {
|
||||
text: intl.formatMessage(messages.quotePost),
|
||||
action: handleQuoteClick,
|
||||
icon: require('@tabler/icons/outline/quote.svg'),
|
||||
}];
|
||||
interface IStatusActionBar {
|
||||
status: SelectedStatus;
|
||||
rebloggedBy?: Account;
|
||||
withLabels?: boolean;
|
||||
expandable?: boolean;
|
||||
space?: 'sm' | 'md' | 'lg';
|
||||
statusActionButtonTheme?: 'default' | 'inverse';
|
||||
fromBookmarks?: boolean;
|
||||
}
|
||||
|
||||
const reblogButton = (
|
||||
<StatusActionButton
|
||||
icon={reblogIcon}
|
||||
color='success'
|
||||
disabled={!publicStatus}
|
||||
title={!publicStatus ? intl.formatMessage(messages.cannot_reblog) : intl.formatMessage(messages.reblog)}
|
||||
active={status.reblogged}
|
||||
onClick={handleReblogClick}
|
||||
onLongPress={handleReblogLongPress}
|
||||
count={reblogCount + quoteCount}
|
||||
text={withLabels ? intl.formatMessage(messages.reblog) : undefined}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
);
|
||||
const StatusActionBar: React.FC<IStatusActionBar> = ({
|
||||
status,
|
||||
withLabels = false,
|
||||
expandable,
|
||||
space = 'sm',
|
||||
statusActionButtonTheme = 'default',
|
||||
fromBookmarks = false,
|
||||
rebloggedBy,
|
||||
}) => {
|
||||
|
||||
if (!status.in_reply_to_id) {
|
||||
replyTitle = intl.formatMessage(messages.reply);
|
||||
} else {
|
||||
replyTitle = intl.formatMessage(messages.replyAll);
|
||||
const { openModal } = useModalsStore();
|
||||
|
||||
const me = useAppSelector(state => state.me);
|
||||
|
||||
if (!status) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const canShare = ('share' in navigator) && (status.visibility === 'public' || status.visibility === 'group');
|
||||
const onOpenUnauthorizedModal = (action?: UnauthorizedModalAction) => {
|
||||
openModal('UNAUTHORIZED', {
|
||||
action,
|
||||
ap_id: status.url,
|
||||
});
|
||||
};
|
||||
|
||||
const publicStatus = ['public', 'unlisted', 'group'].includes(status.visibility);
|
||||
|
||||
const spacing: {
|
||||
[key: string]: React.ComponentProps<typeof HStack>['space'];
|
||||
|
@ -752,92 +977,69 @@ const StatusActionBar: React.FC<IStatusActionBar> = ({
|
|||
onClick={e => e.stopPropagation()}
|
||||
alignItems='center'
|
||||
>
|
||||
{status.group ? (
|
||||
<GroupPopover
|
||||
group={status.group}
|
||||
isEnabled={replyDisabled}
|
||||
>
|
||||
{replyButton}
|
||||
</GroupPopover>
|
||||
) : replyButton}
|
||||
|
||||
{(features.quotePosts && me) ? (
|
||||
<DropdownMenu
|
||||
items={reblogMenu}
|
||||
disabled={!publicStatus}
|
||||
onShiftClick={handleReblogClick}
|
||||
>
|
||||
{reblogButton}
|
||||
</DropdownMenu>
|
||||
) : (
|
||||
reblogButton
|
||||
)}
|
||||
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.favourite)}
|
||||
icon={features.statusDislikes ? require('@tabler/icons/outline/thumb-up.svg') : require('@tabler/icons/outline/heart.svg')}
|
||||
color='accent'
|
||||
filled
|
||||
onClick={handleFavouriteClick}
|
||||
onLongPress={handleFavouriteLongPress}
|
||||
active={status.favourited}
|
||||
count={favouriteCount}
|
||||
text={withLabels ? intl.formatMessage(messages.favourite) : undefined}
|
||||
theme={statusActionButtonTheme}
|
||||
<ReplyButton
|
||||
status={status}
|
||||
statusActionButtonTheme={statusActionButtonTheme}
|
||||
withLabels={withLabels}
|
||||
me={me}
|
||||
onOpenUnauthorizedModal={onOpenUnauthorizedModal}
|
||||
rebloggedBy={rebloggedBy}
|
||||
/>
|
||||
|
||||
{features.statusDislikes && (
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.disfavourite)}
|
||||
icon={require('@tabler/icons/outline/thumb-down.svg')}
|
||||
color='accent'
|
||||
filled
|
||||
onClick={handleDislikeClick}
|
||||
onLongPress={handleDislikeLongPress}
|
||||
active={status.disliked}
|
||||
count={status.dislikes_count}
|
||||
text={withLabels ? intl.formatMessage(messages.disfavourite) : undefined}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
)}
|
||||
<ReblogButton
|
||||
status={status}
|
||||
statusActionButtonTheme={statusActionButtonTheme}
|
||||
withLabels={withLabels}
|
||||
me={me}
|
||||
onOpenUnauthorizedModal={onOpenUnauthorizedModal}
|
||||
publicStatus={publicStatus}
|
||||
/>
|
||||
|
||||
{me && !withLabels && features.emojiReacts && showWrenchButton && (
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.wrench)}
|
||||
icon={require('@tabler/icons/outline/tool.svg')}
|
||||
color='accent'
|
||||
filled
|
||||
onClick={handleWrenchClick}
|
||||
onLongPress={handleWrenchLongPress}
|
||||
active={wrenches?.me}
|
||||
count={wrenches?.count || undefined}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
)}
|
||||
<FavouriteButton
|
||||
status={status}
|
||||
statusActionButtonTheme={statusActionButtonTheme}
|
||||
withLabels={withLabels}
|
||||
me={me}
|
||||
onOpenUnauthorizedModal={onOpenUnauthorizedModal}
|
||||
/>
|
||||
|
||||
{me && !withLabels && features.emojiReacts && (
|
||||
<EmojiPickerDropdown
|
||||
onPickEmoji={handlePickEmoji}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
)}
|
||||
<DislikeButton
|
||||
status={status}
|
||||
statusActionButtonTheme={statusActionButtonTheme}
|
||||
withLabels={withLabels}
|
||||
me={me}
|
||||
onOpenUnauthorizedModal={onOpenUnauthorizedModal}
|
||||
/>
|
||||
|
||||
{canShare && (
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.share)}
|
||||
icon={require('@tabler/icons/outline/upload.svg')}
|
||||
onClick={handleShareClick}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
)}
|
||||
<WrenchButton
|
||||
status={status}
|
||||
statusActionButtonTheme={statusActionButtonTheme}
|
||||
withLabels={withLabels}
|
||||
me={me}
|
||||
onOpenUnauthorizedModal={onOpenUnauthorizedModal}
|
||||
/>
|
||||
|
||||
<DropdownMenu items={menu}>
|
||||
<StatusActionButton
|
||||
title={intl.formatMessage(messages.more)}
|
||||
icon={require('@tabler/icons/outline/dots.svg')}
|
||||
theme={statusActionButtonTheme}
|
||||
/>
|
||||
</DropdownMenu>
|
||||
<EmojiPickerButton
|
||||
status={status}
|
||||
statusActionButtonTheme={statusActionButtonTheme}
|
||||
withLabels={withLabels}
|
||||
me={me}
|
||||
/>
|
||||
|
||||
<ShareButton
|
||||
status={status}
|
||||
statusActionButtonTheme={statusActionButtonTheme}
|
||||
/>
|
||||
|
||||
<MenuButton
|
||||
status={status}
|
||||
statusActionButtonTheme={statusActionButtonTheme}
|
||||
withLabels={withLabels}
|
||||
me={me}
|
||||
onOpenUnauthorizedModal={onOpenUnauthorizedModal}
|
||||
expandable={expandable}
|
||||
fromBookmarks={fromBookmarks}
|
||||
/>
|
||||
</HStack>
|
||||
</HStack>
|
||||
);
|
||||
|
|
Loading…
Reference in a new issue