diff --git a/app/javascript/mastodon/features/account_timeline/components/account_name.tsx b/app/javascript/mastodon/features/account_timeline/components/account_name.tsx index c90f5012de..a0296b5ed9 100644 --- a/app/javascript/mastodon/features/account_timeline/components/account_name.tsx +++ b/app/javascript/mastodon/features/account_timeline/components/account_name.tsx @@ -8,13 +8,16 @@ import classNames from 'classnames'; import Overlay from 'react-overlays/esm/Overlay'; import FollowerIcon from '@/images/icons/icon_follower.svg?react'; +import { showAlert } from '@/mastodon/actions/alerts'; import { Badge } from '@/mastodon/components/badge'; +import { Button } from '@/mastodon/components/button'; import { DisplayName } from '@/mastodon/components/display_name'; import { Icon } from '@/mastodon/components/icon'; import { useAccount } from '@/mastodon/hooks/useAccount'; import { useRelationship } from '@/mastodon/hooks/useRelationship'; -import { useAppSelector } from '@/mastodon/store'; +import { useAppDispatch, 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'; import DomainIcon from '@/material-icons/400-24px/language.svg?react'; @@ -30,6 +33,10 @@ const messages = defineMessages({ id: 'account.name_info', defaultMessage: 'What does this mean?', }, + copied: { + id: 'copy_icon_button.copied', + defaultMessage: 'Copied to clipboard', + }, }); export const AccountName: FC<{ accountId: string }> = ({ accountId }) => { @@ -64,14 +71,12 @@ export const AccountName: FC<{ accountId: string }> = ({ accountId }) => { /> )} -

- @{username}@{domain} - -

+ + ); }; @@ -90,6 +95,19 @@ const AccountNameHelp: FC<{ setOpen((prev) => !prev); }, []); + 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]); + return ( <> )} diff --git a/app/javascript/mastodon/features/account_timeline/components/redesign.module.scss b/app/javascript/mastodon/features/account_timeline/components/redesign.module.scss index 84f102cf06..0a4c5ebea8 100644 --- a/app/javascript/mastodon/features/account_timeline/components/redesign.module.scss +++ b/app/javascript/mastodon/features/account_timeline/components/redesign.module.scss @@ -43,30 +43,22 @@ color: var(--color-text-secondary); } -.username { - display: flex; - font-size: 13px; - color: var(--color-text-secondary); - align-items: center; - user-select: all; - margin-top: 4px; -} - .handleHelpButton { - appearance: none; - border: none; - background: none; + display: flex; + gap: 2px; padding: 0; - color: inherit; - font-size: 1em; - margin-left: 2px; - width: 16px; - height: 16px; + margin-top: 4px; + align-items: center; + appearance: none; + background: none; + border: none; + color: var(--color-text-secondary); + font-size: 13px; transition: color 0.2s ease-in-out; > svg { - width: 100%; - height: 100%; + width: 16px; + height: 16px; } &:hover, @@ -84,6 +76,10 @@ max-width: 400px; box-sizing: border-box; + [data-color-scheme='dark'] & { + border: 1px solid var(--color-border-primary); + } + > h3 { font-size: 17px; font-weight: 600; @@ -101,15 +97,15 @@ &:first-child { margin-bottom: 12px; } - } - svg { - background: var(--color-bg-brand-softest); - width: 28px; - height: 28px; - padding: 5px; - border-radius: 9999px; - box-sizing: border-box; + > svg { + background: var(--color-bg-brand-softest); + width: 28px; + height: 28px; + padding: 5px; + border-radius: 9999px; + box-sizing: border-box; + } } strong { @@ -132,6 +128,26 @@ $button-fallback-breakpoint: $button-breakpoint + 55px; } } +.handleCopy { + border: 1px solid var(--color-border-primary); + border-radius: 8px; + box-sizing: border-box; + padding: 4px 8px; + background-color: var(--color-bg-primary); + color: var(--color-text-primary); + font-size: 13px; + transition: + color 0.2s ease-in-out, + background-color 0.2s ease-in-out; + margin-top: 12px; + + &:active, + &:focus, + &:hover { + background-color: var(--color-bg-brand-softest); + } +} + .buttonsMobile { position: sticky; bottom: var(--mobile-bottom-nav-height); @@ -336,7 +352,7 @@ $button-fallback-breakpoint: $button-breakpoint + 55px; .tabs { display: flex; - gap: 12px; + gap: 16px; padding: 0 16px; @container (width < 500px) { @@ -350,7 +366,7 @@ $button-fallback-breakpoint: $button-breakpoint + 55px; display: block; font-size: 15px; font-weight: 500; - padding: 18px 4px; + padding: 18px 0; text-decoration: none; color: var(--color-text-primary); border-radius: 0; diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index c77ffc6a91..7299b4dfb7 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -102,6 +102,7 @@ "account.muted": "Muted", "account.muting": "Muting", "account.mutual": "You follow each other", + "account.name.copy": "Copy handle", "account.name.help.domain": "{domain} is the server that hosts the user’s profile and posts.", "account.name.help.domain_self": "{domain} is your server that hosts your profile and posts.", "account.name.help.footer": "Just like you can send emails to people using different email clients, you can interact with people on other Mastodon servers – and with anyone on other social apps powered by the same set of rules as Mastodon uses (the ActivityPub protocol).",