Compare commits

...

1 Commits

Author SHA1 Message Date
diondiondion
69b51aea74 Allow logged-out users to copy account handles on collection page 2026-05-04 17:21:13 +02:00
3 changed files with 67 additions and 16 deletions

View File

@@ -7,10 +7,10 @@ import classNames from 'classnames';
import Overlay from 'react-overlays/esm/Overlay';
import { showAlert } from '@/mastodon/actions/alerts';
import { useAccount } from '@/mastodon/hooks/useAccount';
import { useCopyToClipboard } from '@/mastodon/hooks/useCopyToClipboard';
import { useRelationship } from '@/mastodon/hooks/useRelationship';
import { useAppDispatch, useAppSelector } from '@/mastodon/store';
import { useAppSelector } from '@/mastodon/store';
import AtIcon from '@/material-icons/400-24px/alternate_email.svg?react';
import ContentCopyIcon from '@/material-icons/400-24px/content_copy.svg?react';
import HelpIcon from '@/material-icons/400-24px/help.svg?react';
@@ -90,16 +90,7 @@ const AccountNameHelp: FC<{
const handle = `@${username}@${domain}`;
const dispatch = useAppDispatch();
const [copied, setCopied] = useState(false);
const handleCopy = useCallback(() => {
void navigator.clipboard.writeText(handle);
setCopied(true);
dispatch(showAlert({ message: messages.copied }));
setTimeout(() => {
setCopied(false);
}, 700);
}, [handle, dispatch]);
const { wasCopied, copyToClipboard } = useCopyToClipboard(handle);
return (
<>
@@ -182,15 +173,15 @@ const AccountNameHelp: FC<{
tagName='p'
/>
<Button onClick={handleCopy} className={classes.handleCopy}>
<Button onClick={copyToClipboard} className={classes.handleCopy}>
<Icon id='copy' icon={ContentCopyIcon} />
{!copied && (
{!wasCopied && (
<FormattedMessage
id='account.name.copy'
defaultMessage='Copy handle'
/>
)}
{copied && (
{wasCopied && (
<FormattedMessage
id='copypaste.copied'
defaultMessage='Copied'

View File

@@ -3,6 +3,9 @@ import { useCallback, useMemo, useRef, useState } from 'react';
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
import { PendingBadge } from '@/mastodon/components/badge';
import { useAccountHandle } from '@/mastodon/components/display_name/default';
import { useAccount } from '@/mastodon/hooks/useAccount';
import { useCopyToClipboard } from '@/mastodon/hooks/useCopyToClipboard';
import VisibilityOffIcon from '@/material-icons/400-24px/visibility_off.svg?react';
import type {
ApiCollectionJSON,
@@ -21,7 +24,7 @@ import {
} from 'mastodon/components/scrollable_list/components';
import type { TruncatedListItemInfo } from 'mastodon/components/truncated_list';
import { TruncatedListItems } from 'mastodon/components/truncated_list';
import { me } from 'mastodon/initial_state';
import { domain, me } from 'mastodon/initial_state';
import type { Account } from 'mastodon/models/account';
import { createAppSelector, useAppSelector } from 'mastodon/store';
@@ -98,6 +101,27 @@ const getCollectionItems = createAppSelector(
),
);
const CopyHandleButton: React.FC<{ accountId?: string }> = ({ accountId }) => {
const account = useAccount(accountId);
const handle = useAccountHandle(account, domain);
const { copyToClipboard, wasCopied } = useCopyToClipboard(handle);
if (!accountId || !handle) {
return null;
}
return (
<Button secondary compact onClick={copyToClipboard}>
{wasCopied ? (
<FormattedMessage id='copypaste.copied' defaultMessage='Copied' />
) : (
<FormattedMessage id='account.name.copy' defaultMessage='Copy handle' />
)}
</Button>
);
};
export const CollectionAccountsList: React.FC<{
collection: ApiCollectionJSON;
}> = ({ collection }) => {
@@ -138,6 +162,10 @@ export const CollectionAccountsList: React.FC<{
const renderAccountItemButton = useCallback(
({ relationship, accountId }: RenderButtonOptions) => {
if (!me) {
return <CopyHandleButton accountId={accountId} />;
}
// When viewing your own collection, only show the Follow button
// for accounts you're not following anymore.
const withoutButton =

View File

@@ -0,0 +1,32 @@
import { useCallback, useState } from 'react';
import { useIntl } from 'react-intl';
import { showAlert } from 'mastodon/actions/alerts';
import { useAppDispatch } from 'mastodon/store';
export function useCopyToClipboard(text: string | null | undefined) {
const intl = useIntl();
const dispatch = useAppDispatch();
const [wasCopied, setWasCopied] = useState(false);
const copyToClipboard = useCallback(() => {
if (text) {
void navigator.clipboard.writeText(text);
setWasCopied(true);
dispatch(
showAlert({
message: intl.formatMessage({
id: 'copy_icon_button.copied',
defaultMessage: 'Copied to clipboard',
}),
}),
);
setTimeout(() => {
setWasCopied(false);
}, 1000);
}
}, [dispatch, text, intl]);
return { wasCopied, copyToClipboard };
}