mirror of
https://github.com/mastodon/mastodon.git
synced 2026-09-28 12:22:32 -05:00
Redesign: Design tweaks for new navigation (#40565)
This commit is contained in:
@@ -104,10 +104,10 @@ export const AccountMenuItems: React.FC<{
|
||||
<>
|
||||
{context === 'mobile' && <ProfileMenuItem />}
|
||||
|
||||
<MenuItemLink to='/profile/edit' icon={UserIcon}>
|
||||
<MenuItemLink to={accountBasePath} icon={UserIcon}>
|
||||
<FormattedMessage
|
||||
id='account.edit_profile'
|
||||
defaultMessage='Edit profile'
|
||||
id='account.view_profile'
|
||||
defaultMessage='View profile'
|
||||
/>
|
||||
</MenuItemLink>
|
||||
|
||||
|
||||
@@ -2,6 +2,8 @@ import { useCallback, useEffect } from 'react';
|
||||
|
||||
import { defineMessages, FormattedMessage, useIntl } from 'react-intl';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
PenNibIcon,
|
||||
HouseIcon,
|
||||
@@ -10,6 +12,7 @@ import {
|
||||
BellIcon,
|
||||
ChatCircleDotsIcon,
|
||||
BookmarkSimpleIcon,
|
||||
PlusIcon,
|
||||
} from '@phosphor-icons/react';
|
||||
|
||||
import FediIcon from '@/images/icons/icon_fediverse.svg?react';
|
||||
@@ -162,31 +165,44 @@ export const RedesignNavigationPanel: React.FC<{
|
||||
defaultMessage='Custom Feeds'
|
||||
/>
|
||||
}
|
||||
action={{
|
||||
label: (
|
||||
<FormattedMessage
|
||||
id='tabs_bar.create_custom_feed'
|
||||
defaultMessage='Create'
|
||||
/>
|
||||
),
|
||||
link: '/lists/new',
|
||||
}}
|
||||
emptyMessage={
|
||||
<FormattedMessage
|
||||
id='tabs_bar.custom_feeds_empty'
|
||||
defaultMessage='You have no custom feeds yet.'
|
||||
/>
|
||||
<>
|
||||
<FormattedMessage
|
||||
id='tabs_bar.custom_feeds_empty'
|
||||
defaultMessage='You have no custom feeds yet.'
|
||||
/>{' '}
|
||||
<Link to='/lists/new'>
|
||||
<FormattedMessage
|
||||
id='tabs_bar.create_custom_feed'
|
||||
defaultMessage='Create feed'
|
||||
/>
|
||||
</Link>
|
||||
</>
|
||||
}
|
||||
>
|
||||
{customFeeds.map((feed) => (
|
||||
<NavigationLink
|
||||
key={feed.id}
|
||||
to={`/lists/${feed.id}`}
|
||||
iconComponent={RssSimpleIcon}
|
||||
>
|
||||
{feed.title}
|
||||
</NavigationLink>
|
||||
))}
|
||||
{customFeeds.length > 0 && (
|
||||
<>
|
||||
<NavigationLink
|
||||
key='new'
|
||||
to='/lists/new'
|
||||
iconComponent={PlusIcon}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='tabs_bar.create_custom_feed'
|
||||
defaultMessage='Create feed'
|
||||
/>
|
||||
</NavigationLink>
|
||||
{customFeeds.map((feed) => (
|
||||
<NavigationLink
|
||||
key={feed.id}
|
||||
to={`/lists/${feed.id}`}
|
||||
iconComponent={RssSimpleIcon}
|
||||
>
|
||||
{feed.title}
|
||||
</NavigationLink>
|
||||
))}
|
||||
</>
|
||||
)}
|
||||
</ListSection>
|
||||
|
||||
{followedHashtags.length > 0 && (
|
||||
|
||||
@@ -1,45 +1,42 @@
|
||||
@use '@/styles/mastodon/mixins';
|
||||
@use './navigation_link.module.scss' as navigation-link;
|
||||
|
||||
.root {
|
||||
&:not(:last-child) {
|
||||
margin-bottom: var(--space-md);
|
||||
}
|
||||
}
|
||||
|
||||
.titleWrapper {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding-inline: var(--space-xs);
|
||||
padding-block: calc(var(--space-xs) - var(--space-3xs));
|
||||
:any-link {
|
||||
color: inherit;
|
||||
|
||||
&:hover,
|
||||
&:focus-visible {
|
||||
text-decoration: none;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.title {
|
||||
@include mixins.type-label-sm;
|
||||
@include navigation-link.link-base;
|
||||
|
||||
min-height: 32px;
|
||||
padding: var(--space-2xs) var(--space-xs);
|
||||
margin-bottom: var(--space-3xs);
|
||||
|
||||
@include mixins.type-label-md;
|
||||
|
||||
color: var(--color-text-secondary);
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.toggleButton {
|
||||
// Compensate for the button's outer spacing
|
||||
--button-padding: calc(var(--space-xs) - var(--space-3xs));
|
||||
|
||||
margin: calc(-1 * var(--button-padding));
|
||||
margin-inline-end: var(--button-padding);
|
||||
|
||||
--fg: var(--color-text-tertiary);
|
||||
|
||||
svg {
|
||||
transition: rotate 100ms ease-in;
|
||||
}
|
||||
|
||||
&[aria-expanded='false'] svg {
|
||||
rotate: -90deg;
|
||||
}
|
||||
}
|
||||
|
||||
.action {
|
||||
.toggleIcon {
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-inline-start: auto;
|
||||
transition: rotate 100ms ease-in;
|
||||
|
||||
.title[aria-expanded='true'] & {
|
||||
rotate: -180deg;
|
||||
}
|
||||
}
|
||||
|
||||
.emptyState {
|
||||
|
||||
@@ -1,12 +1,8 @@
|
||||
import { useCallback } from 'react';
|
||||
import type { ReactNode } from 'react';
|
||||
|
||||
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 { useStorageState } from '@/mastodon/hooks/useStorage';
|
||||
import { useIdentity } from '@/mastodon/identity_context';
|
||||
import { hasReactChildren } from '@/mastodon/utils/has_react_children';
|
||||
@@ -15,10 +11,6 @@ import classes from './list_section.module.scss';
|
||||
|
||||
export const ListSection: React.FC<{
|
||||
title: ReactNode;
|
||||
action?: {
|
||||
label: ReactNode;
|
||||
link: MastodonLocationDescriptor;
|
||||
};
|
||||
/**
|
||||
* Unique identifier of this section, used for storing the
|
||||
* open/close state of the section in localStorage
|
||||
@@ -26,7 +18,7 @@ export const ListSection: React.FC<{
|
||||
id: string;
|
||||
children: ReactNode;
|
||||
emptyMessage?: ReactNode;
|
||||
}> = ({ title, action, id, children, emptyMessage }) => {
|
||||
}> = ({ title, id, children, emptyMessage }) => {
|
||||
const hasContent = hasReactChildren(children);
|
||||
|
||||
const { accountId } = useIdentity();
|
||||
@@ -39,33 +31,18 @@ export const ListSection: React.FC<{
|
||||
return (
|
||||
<li className={classes.root}>
|
||||
<div className={classes.titleWrapper}>
|
||||
{hasContent && (
|
||||
<IconButton
|
||||
size='sm'
|
||||
variant='ghost'
|
||||
icon={CaretDownIcon}
|
||||
onClick={toggleIsOpen}
|
||||
noActiveHighlight
|
||||
{hasContent ? (
|
||||
<button
|
||||
type='button'
|
||||
aria-expanded={isOpen}
|
||||
className={classes.toggleButton}
|
||||
className={classes.title}
|
||||
onClick={toggleIsOpen}
|
||||
>
|
||||
<FormattedMessage
|
||||
id='tabs_bar.open_section'
|
||||
defaultMessage='Open {title} menu'
|
||||
values={{ title }}
|
||||
/>
|
||||
</IconButton>
|
||||
)}
|
||||
<span className={classes.title}>{title}</span>
|
||||
{action && (
|
||||
<Button
|
||||
as='link'
|
||||
to={action.link}
|
||||
size='xs'
|
||||
className={classes.action}
|
||||
>
|
||||
{action.label}
|
||||
</Button>
|
||||
{title}
|
||||
<CaretDownIcon className={classes.toggleIcon} />
|
||||
</button>
|
||||
) : (
|
||||
<span className={classes.title}>{title}</span>
|
||||
)}
|
||||
</div>
|
||||
{hasContent
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
padding-bottom: var(--space-md);
|
||||
}
|
||||
|
||||
.link {
|
||||
@mixin link-base {
|
||||
--icon-size: 20px;
|
||||
--border-radius: var(--radius-sm);
|
||||
|
||||
@@ -18,38 +18,23 @@
|
||||
display: flex;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
min-height: 40px;
|
||||
padding: var(--space-xs);
|
||||
column-gap: var(--space-sm);
|
||||
border-radius: var(--border-radius);
|
||||
border: none;
|
||||
color: inherit;
|
||||
color: var(--color-text-primary);
|
||||
background-color: transparent;
|
||||
|
||||
@include mixins.type-body-compact;
|
||||
|
||||
transition: background-color 200ms;
|
||||
text-decoration: none;
|
||||
text-align: start;
|
||||
|
||||
&:not(:where(.linkStacked, .linkMobile)) {
|
||||
color: var(--color-text-secondary);
|
||||
}
|
||||
|
||||
@media (width < variables.$mobile-menu-breakpoint) {
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
&:hover,
|
||||
&:where(button, a):hover,
|
||||
&:focus-visible,
|
||||
&[aria-current='page'] {
|
||||
background-color: var(--color-bg-highlight);
|
||||
text-decoration: none;
|
||||
}
|
||||
|
||||
&[aria-current='page'] {
|
||||
color: var(--color-text-primary);
|
||||
}
|
||||
|
||||
&:focus-visible {
|
||||
outline: var(--outline-focus-default);
|
||||
}
|
||||
@@ -60,6 +45,21 @@
|
||||
}
|
||||
}
|
||||
|
||||
.link {
|
||||
@include link-base;
|
||||
|
||||
min-height: 40px;
|
||||
@include mixins.type-body;
|
||||
|
||||
@media (width < variables.$mobile-menu-breakpoint) {
|
||||
min-height: 48px;
|
||||
}
|
||||
|
||||
&[aria-current='page']:not(:where(.linkStacked, .linkMobile)) {
|
||||
@include mixins.type-body-strong;
|
||||
}
|
||||
}
|
||||
|
||||
.linkStacked {
|
||||
--icon-size: 24px;
|
||||
|
||||
|
||||
@@ -147,6 +147,7 @@
|
||||
"account.unmute": "Unmute @{name}",
|
||||
"account.unmute_notifications_short": "Unmute notifications",
|
||||
"account.unmute_short": "Unmute",
|
||||
"account.view_profile": "View profile",
|
||||
"account_edit.advanced_settings.bot_hint": "Signal to others that the account mainly performs automated actions and might not be monitored",
|
||||
"account_edit.advanced_settings.bot_label": "Automated account",
|
||||
"account_edit.advanced_settings.title": "Advanced settings",
|
||||
@@ -1465,7 +1466,7 @@
|
||||
"subscribed_languages.target": "Change subscribed languages for {target}",
|
||||
"tab_bar.messages": "Messages",
|
||||
"tabs_bar.account_settings": "Account settings",
|
||||
"tabs_bar.create_custom_feed": "Create",
|
||||
"tabs_bar.create_custom_feed": "Create feed",
|
||||
"tabs_bar.custom_feeds": "Custom Feeds",
|
||||
"tabs_bar.custom_feeds_empty": "You have no custom feeds yet.",
|
||||
"tabs_bar.explore": "Explore",
|
||||
@@ -1476,7 +1477,6 @@
|
||||
"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