mirror of
https://github.com/mastodon/mastodon.git
synced 2026-09-12 00:46:13 -05:00
Redesign: Make navigation sections collapsible (#40431)
This commit is contained in:
@@ -59,8 +59,8 @@ a.base {
|
||||
|
||||
@mixin active {
|
||||
&:active,
|
||||
&[aria-pressed='true'],
|
||||
&[aria-expanded='true'] {
|
||||
&[aria-pressed='true']:not(.noActiveHighlight),
|
||||
&[aria-expanded='true']:not(.noActiveHighlight) {
|
||||
@content;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,11 @@ interface ButtonPropsBase<As extends 'a' | 'button'> {
|
||||
As extends 'button' ? HTMLButtonElement : HTMLAnchorElement
|
||||
>;
|
||||
loading?: boolean;
|
||||
/**
|
||||
* Prevents visual highlight on the button when `aria-expanded`
|
||||
* or `aria-pressed` are used.
|
||||
*/
|
||||
noActiveHighlight?: boolean;
|
||||
children: ReactNode;
|
||||
}
|
||||
|
||||
@@ -45,6 +50,7 @@ const BaseButton: React.FC<BaseButtonProps> = ({
|
||||
className,
|
||||
onClick,
|
||||
loading,
|
||||
noActiveHighlight,
|
||||
'aria-disabled': ariaDisabled,
|
||||
'aria-live': ariaLive,
|
||||
...props
|
||||
@@ -79,6 +85,7 @@ const BaseButton: React.FC<BaseButtonProps> = ({
|
||||
classes[size],
|
||||
classes[color],
|
||||
classes[variant],
|
||||
noActiveHighlight && classes.noActiveHighlight,
|
||||
)}
|
||||
onClick={handleClick}
|
||||
// Disabled buttons can't have focus, so we don't really
|
||||
|
||||
@@ -20,6 +20,23 @@
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.toggleButton {
|
||||
// Compensate for the button's outer spacing, subtracting a mystery
|
||||
// pixel that I can't explain, but is needed for proper alignment.
|
||||
--button-padding: calc(var(--space-xs) - 1px);
|
||||
|
||||
margin: calc(-1 * var(--button-padding));
|
||||
margin-inline-end: var(--button-padding);
|
||||
|
||||
svg {
|
||||
transition: rotate 100ms ease-in;
|
||||
}
|
||||
|
||||
&[aria-expanded='false'] svg {
|
||||
rotate: -90deg;
|
||||
}
|
||||
}
|
||||
|
||||
.action {
|
||||
margin-inline-start: auto;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,12 @@
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
import { Button } from '@/mastodon/components/button/redesign';
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { CaretDownIcon } from '@phosphor-icons/react';
|
||||
|
||||
import { Button, IconButton } from '@/mastodon/components/button/redesign';
|
||||
import type { MastodonLocationDescriptor } from '@/mastodon/components/router';
|
||||
import { useToggle } from '@/mastodon/hooks/useToggle';
|
||||
import { hasReactChildren } from '@/mastodon/utils/has_react_children';
|
||||
|
||||
import classes from './list_section.module.scss';
|
||||
@@ -16,10 +21,28 @@ export const ListSection: React.FC<{
|
||||
emptyMessage?: ReactNode;
|
||||
}> = ({ title, action, children, emptyMessage }) => {
|
||||
const hasContent = hasReactChildren(children);
|
||||
const [isOpen, { onToggle }] = useToggle(true);
|
||||
|
||||
return (
|
||||
<li className={classes.root}>
|
||||
<div className={classes.titleWrapper}>
|
||||
{hasContent && (
|
||||
<IconButton
|
||||
size='sm'
|
||||
variant='ghost'
|
||||
icon={CaretDownIcon}
|
||||
onClick={onToggle}
|
||||
noActiveHighlight
|
||||
aria-expanded={isOpen}
|
||||
className={classes.toggleButton}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='tabs_bar.open_section'
|
||||
defaultMessage='Open {title} menu'
|
||||
values={{ title }}
|
||||
/>
|
||||
</IconButton>
|
||||
)}
|
||||
<span className={classes.title}>{title}</span>
|
||||
{action && (
|
||||
<Button
|
||||
@@ -32,11 +55,11 @@ export const ListSection: React.FC<{
|
||||
</Button>
|
||||
)}
|
||||
</div>
|
||||
{hasContent ? (
|
||||
<ul>{children}</ul>
|
||||
) : (
|
||||
emptyMessage && <div className={classes.emptyState}>{emptyMessage}</div>
|
||||
)}
|
||||
{hasContent
|
||||
? isOpen && <ul>{children}</ul>
|
||||
: emptyMessage && (
|
||||
<div className={classes.emptyState}>{emptyMessage}</div>
|
||||
)}
|
||||
</li>
|
||||
);
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
min-height: 40px;
|
||||
padding: var(--space-xs);
|
||||
column-gap: var(--space-sm);
|
||||
border-radius: var(--border-radius);
|
||||
|
||||
@@ -1458,6 +1458,7 @@
|
||||
"tabs_bar.menu": "Menu",
|
||||
"tabs_bar.messages": "Messages",
|
||||
"tabs_bar.notifications": "Notifications",
|
||||
"tabs_bar.open_section": "Open {title} menu",
|
||||
"tabs_bar.publish": "New Post",
|
||||
"tabs_bar.quick_links": "Quick links",
|
||||
"tabs_bar.saved": "Saved",
|
||||
|
||||
Reference in New Issue
Block a user