Move RSS button to account menu

Signed-off-by: marcin mikołajczak <git@mkljczk.pl>
toast-story
marcin mikołajczak 2022-11-21 21:03:35 +01:00
rodzic 8be2ee918d
commit fe50acf0c3
4 zmienionych plików z 56 dodań i 73 usunięć

Wyświetl plik

@ -21,12 +21,12 @@ import { HStack, IconButton, Menu, MenuButton, MenuItem, MenuList, MenuLink, Men
import SvgIcon from 'soapbox/components/ui/icon/svg-icon'; import SvgIcon from 'soapbox/components/ui/icon/svg-icon';
import MovedNote from 'soapbox/features/account-timeline/components/moved-note'; import MovedNote from 'soapbox/features/account-timeline/components/moved-note';
import ActionButton from 'soapbox/features/ui/components/action-button'; import ActionButton from 'soapbox/features/ui/components/action-button';
import FeedButton from 'soapbox/features/ui/components/feed-button';
import SubscriptionButton from 'soapbox/features/ui/components/subscription-button'; import SubscriptionButton from 'soapbox/features/ui/components/subscription-button';
import { useAppDispatch, useFeatures, useOwnAccount } from 'soapbox/hooks'; import { useAppDispatch, useAppSelector, useFeatures, useOwnAccount } from 'soapbox/hooks';
import { normalizeAttachment } from 'soapbox/normalizers'; import { normalizeAttachment } from 'soapbox/normalizers';
import { Account } from 'soapbox/types/entities'; import { Account } from 'soapbox/types/entities';
import { isRemote } from 'soapbox/utils/accounts'; import { isLocal, isRemote } from 'soapbox/utils/accounts';
import { MASTODON, parseVersion } from 'soapbox/utils/features';
import type { Menu as MenuType } from 'soapbox/components/dropdown-menu'; import type { Menu as MenuType } from 'soapbox/components/dropdown-menu';
@ -68,6 +68,7 @@ const messages = defineMessages({
userEndorsed: { id: 'account.endorse.success', defaultMessage: 'You are now featuring @{acct} on your profile' }, 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}' }, userUnendorsed: { id: 'account.unendorse.success', defaultMessage: 'You are no longer featuring @{acct}' },
profileExternal: { id: 'account.profile_external', defaultMessage: 'View profile on {domain}' }, profileExternal: { id: 'account.profile_external', defaultMessage: 'View profile on {domain}' },
subscribeFeed: { id: 'account.rss_feed', defaultMessage: 'Subscribe to RSS feed' },
}); });
interface IHeader { interface IHeader {
@ -82,6 +83,8 @@ const Header: React.FC<IHeader> = ({ account }) => {
const features = useFeatures(); const features = useFeatures();
const ownAccount = useOwnAccount(); const ownAccount = useOwnAccount();
const { software } = useAppSelector((state) => parseVersion(state.instance.version));
if (!account) { if (!account) {
return ( return (
<div className='-mt-4 -mx-4'> <div className='-mt-4 -mx-4'>
@ -243,6 +246,10 @@ const Header: React.FC<IHeader> = ({ account }) => {
} }
}; };
const handleRssFeedClick = () => {
window.open(software === MASTODON ? `${account.url}.rss` : `${account.url}/feed.rss`, '_blank');
};
const handleShare = () => { const handleShare = () => {
navigator.share({ navigator.share({
text: `@${account.acct}`, text: `@${account.acct}`,
@ -255,20 +262,43 @@ const Header: React.FC<IHeader> = ({ account }) => {
const makeMenu = () => { const makeMenu = () => {
const menu: MenuType = []; const menu: MenuType = [];
if (!account || !ownAccount) { if (!account) {
return []; return [];
} }
if (features.rssFeeds && isLocal(account)) {
menu.push({
text: intl.formatMessage(messages.subscribeFeed),
action: handleRssFeedClick,
icon: require('@tabler/icons/rss.svg'),
});
}
if ('share' in navigator) { if ('share' in navigator) {
menu.push({ menu.push({
text: intl.formatMessage(messages.share, { name: account.username }), text: intl.formatMessage(messages.share, { name: account.username }),
action: handleShare, action: handleShare,
icon: require('@tabler/icons/upload.svg'), icon: require('@tabler/icons/upload.svg'),
}); });
}
if (features.federating && isRemote(account)) {
const domain = account.fqn.split('@')[1];
menu.push({
text: intl.formatMessage(messages.profileExternal, { domain }),
action: () => onProfileExternal(account.url),
icon: require('@tabler/icons/external-link.svg'),
});
}
if (!ownAccount) return menu;
if (menu.length) {
menu.push(null); menu.push(null);
} }
if (account.id === ownAccount?.id) { if (account.id === ownAccount.id) {
menu.push({ menu.push({
text: intl.formatMessage(messages.edit_profile), text: intl.formatMessage(messages.edit_profile),
to: '/settings/profile', to: '/settings/profile',
@ -427,17 +457,9 @@ const Header: React.FC<IHeader> = ({ account }) => {
icon: require('@tabler/icons/ban.svg'), icon: require('@tabler/icons/ban.svg'),
}); });
} }
if (features.federating) {
menu.push({
text: intl.formatMessage(messages.profileExternal, { domain }),
action: () => onProfileExternal(account.url),
icon: require('@tabler/icons/external-link.svg'),
});
}
} }
if (ownAccount?.staff) { if (ownAccount.staff) {
menu.push(null); menu.push(null);
menu.push({ menu.push({
@ -455,7 +477,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
if (!account || !ownAccount) return info; if (!account || !ownAccount) return info;
if (ownAccount?.id !== account.id && account.relationship?.followed_by) { if (ownAccount.id !== account.id && account.relationship?.followed_by) {
info.push( info.push(
<Badge <Badge
key='followed_by' key='followed_by'
@ -463,7 +485,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
title={<FormattedMessage id='account.follows_you' defaultMessage='Follows you' />} title={<FormattedMessage id='account.follows_you' defaultMessage='Follows you' />}
/>, />,
); );
} else if (ownAccount?.id !== account.id && account.relationship?.blocking) { } else if (ownAccount.id !== account.id && account.relationship?.blocking) {
info.push( info.push(
<Badge <Badge
key='blocked' key='blocked'
@ -473,7 +495,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
); );
} }
if (ownAccount?.id !== account.id && account.relationship?.muting) { if (ownAccount.id !== account.id && account.relationship?.muting) {
info.push( info.push(
<Badge <Badge
key='muted' key='muted'
@ -481,7 +503,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
title={<FormattedMessage id='account.muted' defaultMessage='Muted' />} title={<FormattedMessage id='account.muted' defaultMessage='Muted' />}
/>, />,
); );
} else if (ownAccount?.id !== account.id && account.relationship?.domain_blocking) { } else if (ownAccount.id !== account.id && account.relationship?.domain_blocking) {
info.push( info.push(
<Badge <Badge
key='domain_blocked' key='domain_blocked'
@ -495,7 +517,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
}; };
// const renderMessageButton = () => { // const renderMessageButton = () => {
// if (!ownAccount || !account || account.id === ownAccount?.id) { // if (!ownAccount || !account || account.id === ownAccount.id) {
// return null; // return null;
// } // }
@ -587,7 +609,7 @@ const Header: React.FC<IHeader> = ({ account }) => {
<div className='mt-10 flex flex-row space-y-0 space-x-2'> <div className='mt-10 flex flex-row space-y-0 space-x-2'>
<SubscriptionButton account={account} /> <SubscriptionButton account={account} />
{ownAccount ? ( {menu.length > 0 && (
<Menu> <Menu>
<MenuButton <MenuButton
as={IconButton} as={IconButton}
@ -621,8 +643,6 @@ const Header: React.FC<IHeader> = ({ account }) => {
})} })}
</MenuList> </MenuList>
</Menu> </Menu>
) : (
<FeedButton account={account} />
)} )}
{renderShareButton()} {renderShareButton()}

Wyświetl plik

@ -157,6 +157,7 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
onClick={handleRemoteFollow} onClick={handleRemoteFollow}
icon={require('@tabler/icons/plus.svg')} icon={require('@tabler/icons/plus.svg')}
text={intl.formatMessage(messages.follow)} text={intl.formatMessage(messages.follow)}
size='sm'
/> />
); );
// Pleroma's classic remote follow form. // Pleroma's classic remote follow form.
@ -165,7 +166,11 @@ const ActionButton: React.FC<IActionButton> = ({ account, actionType, small }) =
<form method='POST' action='/main/ostatus'> <form method='POST' action='/main/ostatus'>
<input type='hidden' name='nickname' value={account.acct} /> <input type='hidden' name='nickname' value={account.acct} />
<input type='hidden' name='profile' value='' /> <input type='hidden' name='profile' value='' />
<Button text={intl.formatMessage(messages.remote_follow)} type='submit' /> <Button
text={intl.formatMessage(messages.remote_follow)}
type='submit'
size='sm'
/>
</form> </form>
); );
} }

Wyświetl plik

@ -1,50 +0,0 @@
import React from 'react';
import { defineMessages, useIntl } from 'react-intl';
import { IconButton } from 'soapbox/components/ui';
import { useAppSelector, useSoapboxConfig } from 'soapbox/hooks';
import { isLocal } from 'soapbox/utils/accounts';
import { parseVersion, MASTODON, PLEROMA } from 'soapbox/utils/features';
import type { Account as AccountEntity } from 'soapbox/types/entities';
const messages = defineMessages({
subscribeFeed: { id: 'account.rss_feed', defaultMessage: 'Subscribe to RSS feed' },
});
interface IFeedButton {
account: AccountEntity
}
const FeedButton = ({ account }: IFeedButton) => {
const intl = useIntl();
const { featureFeeds } = useSoapboxConfig();
const { software } = useAppSelector((state) => parseVersion(state.instance.version));
let feedUrl: string | undefined;
switch (software) {
case MASTODON:
feedUrl = `${account.url}.rss`;
break;
case PLEROMA:
feedUrl = `${account.url}/feed.rss`;
break;
}
if (!featureFeeds || !feedUrl || !isLocal(account)) return null;
return (
<IconButton
src={require('@tabler/icons/rss.svg')}
onClick={() => window.open(feedUrl, '_blank')}
title={intl.formatMessage(messages.subscribeFeed)}
theme='outlined'
className='px-[10px]'
iconClassName='w-4 h-4'
/>
);
};
export default FeedButton;

Wyświetl plik

@ -543,6 +543,14 @@ const getInstanceFeatures = (instance: Instance) => {
v.software === PLEROMA, v.software === PLEROMA,
]), ]),
/**
* Ability to follow account feeds using RSS.
*/
rssFeeds: any([
v.software === MASTODON,
v.software === PLEROMA,
]),
/** /**
* Can schedule statuses to be posted at a later time. * Can schedule statuses to be posted at a later time.
* @see POST /api/v1/statuses * @see POST /api/v1/statuses