From 26fce0f2f9e36ea0e0c2b03b7f57d1b1ea58ed1c Mon Sep 17 00:00:00 2001 From: diondiondion Date: Tue, 8 Sep 2026 16:50:48 +0000 Subject: [PATCH] Redesign: Make navigation sections collapsible (#40431) --- .../components/button/redesign.module.scss | 4 +-- .../mastodon/components/button/redesign.tsx | 7 ++++ .../redesign/list_section.module.scss | 17 +++++++++ .../redesign/list_section.tsx | 35 +++++++++++++++---- .../redesign/navigation_link.module.scss | 1 + app/javascript/mastodon/locales/en.json | 1 + 6 files changed, 57 insertions(+), 8 deletions(-) diff --git a/app/javascript/mastodon/components/button/redesign.module.scss b/app/javascript/mastodon/components/button/redesign.module.scss index 325bf95f2dd..5c6f6408222 100644 --- a/app/javascript/mastodon/components/button/redesign.module.scss +++ b/app/javascript/mastodon/components/button/redesign.module.scss @@ -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; } } diff --git a/app/javascript/mastodon/components/button/redesign.tsx b/app/javascript/mastodon/components/button/redesign.tsx index cdc8b71db34..b1edd0a32af 100644 --- a/app/javascript/mastodon/components/button/redesign.tsx +++ b/app/javascript/mastodon/components/button/redesign.tsx @@ -24,6 +24,11 @@ interface ButtonPropsBase { 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 = ({ className, onClick, loading, + noActiveHighlight, 'aria-disabled': ariaDisabled, 'aria-live': ariaLive, ...props @@ -79,6 +85,7 @@ const BaseButton: React.FC = ({ classes[size], classes[color], classes[variant], + noActiveHighlight && classes.noActiveHighlight, )} onClick={handleClick} // Disabled buttons can't have focus, so we don't really diff --git a/app/javascript/mastodon/features/navigation_panel/redesign/list_section.module.scss b/app/javascript/mastodon/features/navigation_panel/redesign/list_section.module.scss index 07cdd9b8c76..7e07cd4f7b7 100644 --- a/app/javascript/mastodon/features/navigation_panel/redesign/list_section.module.scss +++ b/app/javascript/mastodon/features/navigation_panel/redesign/list_section.module.scss @@ -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; } diff --git a/app/javascript/mastodon/features/navigation_panel/redesign/list_section.tsx b/app/javascript/mastodon/features/navigation_panel/redesign/list_section.tsx index d4527b2208b..a5f50759f7a 100644 --- a/app/javascript/mastodon/features/navigation_panel/redesign/list_section.tsx +++ b/app/javascript/mastodon/features/navigation_panel/redesign/list_section.tsx @@ -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 (
  • + {hasContent && ( + + + + )} {title} {action && (
    - {hasContent ? ( -
      {children}
    - ) : ( - emptyMessage &&
    {emptyMessage}
    - )} + {hasContent + ? isOpen &&
      {children}
    + : emptyMessage && ( +
    {emptyMessage}
    + )}
  • ); }; diff --git a/app/javascript/mastodon/features/navigation_panel/redesign/navigation_link.module.scss b/app/javascript/mastodon/features/navigation_panel/redesign/navigation_link.module.scss index 3873a53c480..4febbf834e4 100644 --- a/app/javascript/mastodon/features/navigation_panel/redesign/navigation_link.module.scss +++ b/app/javascript/mastodon/features/navigation_panel/redesign/navigation_link.module.scss @@ -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); diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index e8854094096..eafe7d98635 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -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",