[Glitch] Profile redesign: Handle + tab changes

Port ed6ceda71d9037598dfe518bb311c6643b5f7ca0 to glitch-soc

Signed-off-by: Claire <claire.github-309c@sitedethib.com>
This commit is contained in:
Echo 2026-04-07 13:21:39 +02:00 committed by Claire
parent 6ddebfdd04
commit bd18207c65
2 changed files with 90 additions and 38 deletions

View File

@ -7,14 +7,17 @@ import classNames from 'classnames';
import Overlay from 'react-overlays/esm/Overlay';
import { showAlert } from '@/flavours/glitch/actions/alerts';
import { Badge } from '@/flavours/glitch/components/badge';
import { Button } from '@/flavours/glitch/components/button';
import { DisplayName } from '@/flavours/glitch/components/display_name';
import { Icon } from '@/flavours/glitch/components/icon';
import { useAccount } from '@/flavours/glitch/hooks/useAccount';
import { useRelationship } from '@/flavours/glitch/hooks/useRelationship';
import { useAppSelector } from '@/flavours/glitch/store';
import { useAppDispatch, useAppSelector } from '@/flavours/glitch/store';
import FollowerIcon from '@/images/icons/icon_follower.svg?react';
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 }) => {
/>
)}
</div>
<p className={classes.username}>
@{username}@{domain}
<AccountNameHelp
username={username}
domain={domain}
isSelf={account.id === me}
/>
</p>
<AccountNameHelp
username={username}
domain={domain}
isSelf={account.id === me}
/>
</div>
);
};
@ -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 (
<>
<button
@ -100,6 +118,8 @@ const AccountNameHelp: FC<{
aria-expanded={open}
aria-controls={accessibilityId}
>
{handle}
<Icon
id='help'
icon={HelpIcon}
@ -169,6 +189,22 @@ const AccountNameHelp: FC<{
defaultMessage='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).'
tagName='p'
/>
<Button onClick={handleCopy} className={classes.handleCopy}>
<Icon id='copy' icon={ContentCopyIcon} />
{!copied && (
<FormattedMessage
id='account.name.copy'
defaultMessage='Copy handle'
/>
)}
{copied && (
<FormattedMessage
id='copypaste.copied'
defaultMessage='Copied'
/>
)}
</Button>
</div>
)}
</Overlay>

View File

@ -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;