From 1d53d9d7e78f3a4aedfbac95a7acc75038363254 Mon Sep 17 00:00:00 2001 From: Echo Date: Fri, 11 Sep 2026 16:04:15 +0000 Subject: [PATCH] Status redesign: Hashtags (#40466) --- .../components/button/redesign.module.scss | 23 ++++++-- .../mastodon/components/button/redesign.tsx | 7 +++ .../components/status/hashtag_bar.tsx | 58 +++++++++++++++++++ .../mastodon/components/status/status.tsx | 5 +- .../components/status/styles.module.scss | 30 ++++++++++ 5 files changed, 115 insertions(+), 8 deletions(-) create mode 100644 app/javascript/mastodon/components/status/hashtag_bar.tsx diff --git a/app/javascript/mastodon/components/button/redesign.module.scss b/app/javascript/mastodon/components/button/redesign.module.scss index 278b24c6fe6..720232c7313 100644 --- a/app/javascript/mastodon/components/button/redesign.module.scss +++ b/app/javascript/mastodon/components/button/redesign.module.scss @@ -4,6 +4,9 @@ --bg: transparent; --bg-hover: color-mix(in srgb, var(--bg) 90%, var(--fg)); --fg: var(--color-text-primary); + --inline-padding: var(--space-xs); + + @include mixins.type-label-lg; background-color: var(--bg); border-radius: var(--radius-round); @@ -19,8 +22,7 @@ justify-content: center; align-items: center; column-gap: var(--space-2xs); - @include mixins.type-label-lg; - + padding-inline: var(--inline-padding); box-sizing: border-box; &:hover:not( @@ -68,22 +70,27 @@ a.base { // Sizes .xs { - padding-inline: var(--space-xs); min-height: 20px; } .sm { - padding: var(--space-2xs) var(--space-sm); + --inline-padding: var(--space-sm); + + padding-block: var(--space-2xs); min-height: 32px; } .md { - padding: var(--space-xs) var(--space-md); + --inline-padding: var(--space-md); + + padding-block: var(--space-xs); min-height: 40px; } .lg { - padding: var(--space-sm) var(--space-lg); + --inline-padding: var(--space-lg); + + padding-block: var(--space-sm); min-height: 48px; } @@ -225,3 +232,7 @@ a.base { .loading { color: inherit; } + +.clipPadding { + margin-inline-start: calc(-1 * var(--inline-padding)); +} diff --git a/app/javascript/mastodon/components/button/redesign.tsx b/app/javascript/mastodon/components/button/redesign.tsx index 412b82789e3..bc23c0037da 100644 --- a/app/javascript/mastodon/components/button/redesign.tsx +++ b/app/javascript/mastodon/components/button/redesign.tsx @@ -29,6 +29,11 @@ interface ButtonPropsBase { * or `aria-pressed` are used. */ noActiveHighlight?: boolean; + /** + * Adds a negative margin to a button to align the text + * with the starting edge of its parent. + */ + clipPadding?: boolean; children: ReactNode; } @@ -50,6 +55,7 @@ const BaseButton: React.FC = ({ className, onClick, loading, + clipPadding, noActiveHighlight, 'aria-disabled': ariaDisabled, 'aria-live': ariaLive, @@ -85,6 +91,7 @@ const BaseButton: React.FC = ({ classes[size], classes[color], classes[variant], + clipPadding && classes.clipPadding, noActiveHighlight && classes.noActiveHighlight, )} onClick={handleClick} diff --git a/app/javascript/mastodon/components/status/hashtag_bar.tsx b/app/javascript/mastodon/components/status/hashtag_bar.tsx new file mode 100644 index 00000000000..346470b15d1 --- /dev/null +++ b/app/javascript/mastodon/components/status/hashtag_bar.tsx @@ -0,0 +1,58 @@ +import { FormattedMessage } from 'react-intl'; + +import classNames from 'classnames'; + +import { useOverflowButton } from '@/mastodon/hooks/useOverflow'; +import { useToggle } from '@/mastodon/hooks/useToggle'; + +import { Button } from '../button/redesign'; + +import classes from './styles.module.scss'; + +export const StatusHashtagBar: React.FC<{ + hashtags: string[]; + accountId: string; +}> = ({ hashtags, accountId }) => { + const [showOverflow, { onTrue: onShowOverflow }] = useToggle(); + const { hiddenCount, wrapperRef, listRef, hiddenIndex, maxWidth } = + useOverflowButton(); + + if (hashtags.length === 0) { + return null; + } + + return ( +
+
+ {hashtags.map((hashtag, index) => ( + + ))} +
+ {hiddenCount > 0 && !showOverflow && ( + + )} +
+ ); +}; diff --git a/app/javascript/mastodon/components/status/status.tsx b/app/javascript/mastodon/components/status/status.tsx index d3de820b8ec..f2057d54ffe 100644 --- a/app/javascript/mastodon/components/status/status.tsx +++ b/app/javascript/mastodon/components/status/status.tsx @@ -10,13 +10,14 @@ import { createAppSelector, useAppSelector } from '@/mastodon/store'; import { ContentWarning } from '../content_warning'; import { FilterWarning } from '../filter_warning'; -import { computeHashtagBarForStatus, HashtagBar } from '../hashtag_bar'; +import { computeHashtagBarForStatus } from '../hashtag_bar'; import { Hotkeys } from '../hotkeys'; import { Poll } from '../poll'; import { StatusActionBar } from './action_bar'; import { StatusAttachments } from './attachments'; import { StatusContent } from './content'; +import { StatusHashtagBar } from './hashtag_bar'; import type { StatusHandlers } from './hooks'; import { StatusContext, @@ -210,7 +211,7 @@ export const StatusRedesign: React.FC = ({ {showFooter && (