diff --git a/app/javascript/mastodon/components/status/content.tsx b/app/javascript/mastodon/components/status/content.tsx index 29389c75bc7..c395b0b7633 100644 --- a/app/javascript/mastodon/components/status/content.tsx +++ b/app/javascript/mastodon/components/status/content.tsx @@ -17,7 +17,7 @@ import { EmojiHTML } from '../emoji/html'; import { Icon } from '../icon'; import { Poll } from '../poll'; -import { useElementHandledLink } from './handled_link'; +import { useHandlersForStatus } from './hooks'; const MAX_HEIGHT = 706; // 22px * 32 (+ 2px padding at the top) @@ -72,20 +72,7 @@ export const StatusContent: React.FC<{ [onClick], ); - const hrefToMention = useCallback( - (href: string) => status?.mentions.find((item) => item.url === href), - [status?.mentions], - ); - const hrefToCollectionId = useCallback( - (href: string) => - status?.tagged_collections.find((item) => item.url === href)?.id, - [status?.tagged_collections], - ); - const htmlHandlers = useElementHandledLink({ - hashtagAccountId: status?.account, - hrefToCollectionId, - hrefToMention, - }); + const htmlHandlers = useHandlersForStatus(status); if (!status) { return null; diff --git a/app/javascript/mastodon/components/status/hooks.ts b/app/javascript/mastodon/components/status/hooks.ts index 8ae8c48d027..893f22b98c2 100644 --- a/app/javascript/mastodon/components/status/hooks.ts +++ b/app/javascript/mastodon/components/status/hooks.ts @@ -11,12 +11,16 @@ import { openModal } from '@/mastodon/actions/modal'; import { toggleStatusSpoilers } from '@/mastodon/actions/statuses'; import { useExpandedStatus } from '@/mastodon/hooks/useStatus'; import { useToggle } from '@/mastodon/hooks/useToggle'; -import type { ExpandedStatusShape } from '@/mastodon/models/status'; +import type { + ExpandedStatusShape, + StatusShape, +} from '@/mastodon/models/status'; import { selectStatusFilters } from '@/mastodon/selectors/filters'; import { useAppSelector, useAppDispatch } from '@/mastodon/store'; import { FOCUS_TARGET } from '../navigation_focus_target'; +import { useElementHandledLink } from './handled_link'; import type { StatusContextType } from './types'; const messages = defineMessages({ @@ -260,3 +264,28 @@ export function useTextForScreenReader({ return values.join(', '); }, [intl, isQuote, reblogAcct, status]); } + +export function useHandlersForStatus( + status?: Pick< + StatusShape | ExpandedStatusShape, + 'account' | 'mentions' | 'tagged_collections' + > | null, +) { + const hrefToMention = useCallback( + (href: string) => status?.mentions.find((item) => item.url === href), + [status?.mentions], + ); + const hrefToCollectionId = useCallback( + (href: string) => + status?.tagged_collections.find((item) => item.url === href)?.id, + [status?.tagged_collections], + ); + return useElementHandledLink({ + hashtagAccountId: + typeof status?.account === 'string' + ? status.account + : status?.account.acct, + hrefToCollectionId, + hrefToMention, + }); +} diff --git a/app/javascript/mastodon/features/compose/redesign/index.tsx b/app/javascript/mastodon/features/compose/redesign/index.tsx index 2405ab95b35..a7b4615fe24 100644 --- a/app/javascript/mastodon/features/compose/redesign/index.tsx +++ b/app/javascript/mastodon/features/compose/redesign/index.tsx @@ -31,6 +31,7 @@ import type { OnEmojiPick } from './emoji'; import { ComposeFooter } from './footer'; import { ComposeFormHeader } from './header'; import { LanguageButton } from './language'; +import { ComposeReply } from './reply'; import { selectComposeCanSubmit, selectComposeSensitive, @@ -87,6 +88,8 @@ export const RedesignComposeForm: React.FC = ({ > + +
{type !== 'message' && } diff --git a/app/javascript/mastodon/features/compose/redesign/reply.tsx b/app/javascript/mastodon/features/compose/redesign/reply.tsx new file mode 100644 index 00000000000..edb27c77e20 --- /dev/null +++ b/app/javascript/mastodon/features/compose/redesign/reply.tsx @@ -0,0 +1,55 @@ +import { Link } from 'react-router-dom'; + +import { Avatar } from '@/mastodon/components/avatar'; +import { LinkedDisplayName } from '@/mastodon/components/display_name'; +import { EmojiHTML } from '@/mastodon/components/emoji/html'; +import { RelativeTimestamp } from '@/mastodon/components/relative_timestamp'; +import { useHandlersForStatus } from '@/mastodon/components/status/hooks'; +import { selectAccountStatus } from '@/mastodon/selectors/statuses'; +import { useAppSelector } from '@/mastodon/store'; + +import classes from './styles.module.scss'; + +export const ComposeReply: React.FC = () => { + const replyId = useAppSelector( + (state) => state.compose.get('in_reply_to') as null | string, + ); + const status = useAppSelector((state) => selectAccountStatus(state, replyId)); + + const htmlHandlers = useHandlersForStatus(status); + + if (!status) { + return; + } + + return ( +
+
+ + + + ·  + + + + +
+ + +
+ ); +}; diff --git a/app/javascript/mastodon/features/compose/redesign/styles.module.scss b/app/javascript/mastodon/features/compose/redesign/styles.module.scss index 0e3befc451b..5dae6ad8a90 100644 --- a/app/javascript/mastodon/features/compose/redesign/styles.module.scss +++ b/app/javascript/mastodon/features/compose/redesign/styles.module.scss @@ -187,6 +187,51 @@ } } +// Reply + +.reply { + border-inline-start: 0.5px solid var(--color-border-primary); + padding: 0 var(--space-md); +} + +.replyAccount { + display: flex; + margin-bottom: var(--space-2xs); + + a { + color: inherit; + text-decoration: none; + } +} + +.replyAvatar { + margin-inline-end: var(--space-xs); + border-radius: var(--radius-round); + overflow: hidden; +} + +.replyTime { + color: var(--color-text-tertiary); +} + +.replyText { + @include mixins.line-clamp(2); + @include mixins.type-body-compact; + + // Round two lines to the nearest 5px. + max-height: round(2lh, 5px); + + a { + color: var(--color-text-brand); + text-decoration: none; + + &:hover, + &:focus { + text-decoration: underline; + } + } +} + // Attachments .mediaSingle { diff --git a/app/javascript/styles/mastodon/_mixins.scss b/app/javascript/styles/mastodon/_mixins.scss index e836927d71f..38975e81709 100644 --- a/app/javascript/styles/mastodon/_mixins.scss +++ b/app/javascript/styles/mastodon/_mixins.scss @@ -156,3 +156,15 @@ color: var(--color-text-primary); } } + +/** + * Utilities + */ + +@mixin line-clamp($lines) { + overflow: hidden; + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: $lines; + line-clamp: $lines; +}