Merge commit 'cd0ca4b99473f54464e5134f91b7b1c8d5544011' into glitch-soc/merge-upstream
This commit is contained in:
commit
68000956f4
30 files changed
+398
-185
No files matched your search
@@ -316,8 +316,8 @@ function loaded() {
|
||||
|
||||
const message =
|
||||
statusEl.dataset.spoiler === 'expanded'
|
||||
? localeData['status.show_less'] ?? 'Show less'
|
||||
: localeData['status.show_more'] ?? 'Show more';
|
||||
? (localeData['status.show_less'] ?? 'Show less')
|
||||
: (localeData['status.show_more'] ?? 'Show more');
|
||||
spoilerLink.textContent = new IntlMessageFormat(
|
||||
message,
|
||||
locale,
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { browserHistory } from 'mastodon/components/router';
|
||||
|
||||
import api, { getLinks } from '../api';
|
||||
|
||||
import {
|
||||
@@ -676,3 +678,13 @@ export const updateAccount = ({ displayName, note, avatar, header, discoverable,
|
||||
dispatch(importFetchedAccount(response.data));
|
||||
});
|
||||
};
|
||||
|
||||
export const navigateToProfile = (accountId) => {
|
||||
return (_dispatch, getState) => {
|
||||
const acct = getState().accounts.getIn([accountId, 'acct']);
|
||||
|
||||
if (acct) {
|
||||
browserHistory.push(`/@${acct}`);
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -122,6 +122,18 @@ export function replyCompose(status) {
|
||||
};
|
||||
}
|
||||
|
||||
export function replyComposeById(statusId) {
|
||||
return (dispatch, getState) => {
|
||||
const state = getState();
|
||||
const status = state.statuses.get(statusId);
|
||||
|
||||
if (status) {
|
||||
const account = state.accounts.get(status.get('account'));
|
||||
dispatch(replyCompose(status.set('account', account)));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function cancelReplyCompose() {
|
||||
return {
|
||||
type: COMPOSE_REPLY_CANCEL,
|
||||
@@ -154,6 +166,12 @@ export function mentionCompose(account) {
|
||||
};
|
||||
}
|
||||
|
||||
export function mentionComposeById(accountId) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch(mentionCompose(getState().accounts.get(accountId)));
|
||||
};
|
||||
}
|
||||
|
||||
export function directCompose(account) {
|
||||
return (dispatch, getState) => {
|
||||
dispatch({
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
import { browserHistory } from 'mastodon/components/router';
|
||||
|
||||
import api from '../api';
|
||||
|
||||
import { ensureComposeIsVisible, setComposeToStatus } from './compose';
|
||||
@@ -363,3 +365,15 @@ export const undoStatusTranslation = (id, pollId) => ({
|
||||
id,
|
||||
pollId,
|
||||
});
|
||||
|
||||
export const navigateToStatus = (statusId) => {
|
||||
return (_dispatch, getState) => {
|
||||
const state = getState();
|
||||
const accountId = state.statuses.getIn([statusId, 'account']);
|
||||
const acct = state.accounts.getIn([accountId, 'acct']);
|
||||
|
||||
if (acct) {
|
||||
browserHistory.push(`/@${acct}/${statusId}`);
|
||||
}
|
||||
};
|
||||
};
|
||||
@@ -119,6 +119,7 @@ class Status extends ImmutablePureComponent {
|
||||
skipPrepend: PropTypes.bool,
|
||||
avatarSize: PropTypes.number,
|
||||
deployPictureInPicture: PropTypes.func,
|
||||
unfocusable: PropTypes.bool,
|
||||
pictureInPicture: ImmutablePropTypes.contains({
|
||||
inUse: PropTypes.bool,
|
||||
available: PropTypes.bool,
|
||||
@@ -355,7 +356,7 @@ class Status extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
render () {
|
||||
const { intl, hidden, featured, unread, showThread, scrollKey, pictureInPicture, previousId, nextInReplyToId, rootId, skipPrepend, avatarSize = 46 } = this.props;
|
||||
const { intl, hidden, featured, unfocusable, unread, showThread, scrollKey, pictureInPicture, previousId, nextInReplyToId, rootId, skipPrepend, avatarSize = 46 } = this.props;
|
||||
|
||||
let { status, account, ...other } = this.props;
|
||||
|
||||
@@ -381,8 +382,8 @@ class Status extends ImmutablePureComponent {
|
||||
|
||||
if (hidden) {
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
<div ref={this.handleRef} className={classNames('status__wrapper', { focusable: !this.props.muted })} tabIndex={0}>
|
||||
<HotKeys handlers={handlers} tabIndex={unfocusable ? null : -1}>
|
||||
<div ref={this.handleRef} className={classNames('status__wrapper', { focusable: !this.props.muted })} tabIndex={unfocusable ? null : 0}>
|
||||
<span>{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}</span>
|
||||
<span>{status.get('content')}</span>
|
||||
</div>
|
||||
@@ -402,8 +403,8 @@ class Status extends ImmutablePureComponent {
|
||||
};
|
||||
|
||||
return (
|
||||
<HotKeys handlers={minHandlers}>
|
||||
<div className='status__wrapper status__wrapper--filtered focusable' tabIndex={0} ref={this.handleRef}>
|
||||
<HotKeys handlers={minHandlers} tabIndex={unfocusable ? null : -1}>
|
||||
<div className='status__wrapper status__wrapper--filtered focusable' tabIndex={unfocusable ? null : 0} ref={this.handleRef}>
|
||||
<FormattedMessage id='status.filtered' defaultMessage='Filtered' />: {matchedFilters.join(', ')}.
|
||||
{' '}
|
||||
<button className='status__wrapper--filtered__button' onClick={this.handleUnfilterClick}>
|
||||
@@ -550,8 +551,8 @@ class Status extends ImmutablePureComponent {
|
||||
const expanded = !status.get('hidden') || status.get('spoiler_text').length === 0;
|
||||
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), unread, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef} data-nosnippet={status.getIn(['account', 'noindex'], true) || undefined}>
|
||||
<HotKeys handlers={handlers} tabIndex={unfocusable ? null : -1}>
|
||||
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), unread, focusable: !this.props.muted })} tabIndex={this.props.muted || unfocusable ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef} data-nosnippet={status.getIn(['account', 'noindex'], true) || undefined}>
|
||||
{!skipPrepend && prepend}
|
||||
|
||||
<div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), 'status--in-thread': !!rootId, 'status--first-in-thread': previousId && (!connectUp || connectToRoot), muted: this.props.muted })} data-id={status.get('id')}>
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { useCallback } from 'react';
|
||||
import { useCallback, useRef } from 'react';
|
||||
|
||||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
@@ -22,6 +22,7 @@ export const EmbeddedStatus: React.FC<{ statusId: string }> = ({
|
||||
statusId,
|
||||
}) => {
|
||||
const history = useHistory();
|
||||
const clickCoordinatesRef = useRef<[number, number] | null>();
|
||||
|
||||
const status = useAppSelector(
|
||||
(state) => state.statuses.get(statusId) as Status | undefined,
|
||||
@@ -31,11 +32,69 @@ export const EmbeddedStatus: React.FC<{ statusId: string }> = ({
|
||||
state.accounts.get(status?.get('account') as string),
|
||||
);
|
||||
|
||||
const handleClick = useCallback(() => {
|
||||
if (!account) return;
|
||||
const handleMouseDown = useCallback<React.MouseEventHandler<HTMLDivElement>>(
|
||||
({ clientX, clientY }) => {
|
||||
clickCoordinatesRef.current = [clientX, clientY];
|
||||
},
|
||||
[clickCoordinatesRef],
|
||||
);
|
||||
|
||||
history.push(`/@${account.acct}/${statusId}`);
|
||||
}, [statusId, account, history]);
|
||||
const handleMouseUp = useCallback<React.MouseEventHandler<HTMLDivElement>>(
|
||||
({ clientX, clientY, target, button }) => {
|
||||
const [startX, startY] = clickCoordinatesRef.current ?? [0, 0];
|
||||
const [deltaX, deltaY] = [
|
||||
Math.abs(clientX - startX),
|
||||
Math.abs(clientY - startY),
|
||||
];
|
||||
|
||||
let element: HTMLDivElement | null = target as HTMLDivElement;
|
||||
|
||||
while (element) {
|
||||
if (
|
||||
element.localName === 'button' ||
|
||||
element.localName === 'a' ||
|
||||
element.localName === 'label'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
element = element.parentNode as HTMLDivElement | null;
|
||||
}
|
||||
|
||||
if (deltaX + deltaY < 5 && button === 0 && account) {
|
||||
history.push(`/@${account.acct}/${statusId}`);
|
||||
}
|
||||
|
||||
clickCoordinatesRef.current = null;
|
||||
},
|
||||
[clickCoordinatesRef, statusId, account, history],
|
||||
);
|
||||
|
||||
const handleMouseEnter = useCallback<React.MouseEventHandler<HTMLDivElement>>(
|
||||
({ currentTarget }) => {
|
||||
const emojis =
|
||||
currentTarget.querySelectorAll<HTMLImageElement>('.custom-emoji');
|
||||
|
||||
for (const emoji of emojis) {
|
||||
const newSrc = emoji.getAttribute('data-original');
|
||||
if (newSrc) emoji.src = newSrc;
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const handleMouseLeave = useCallback<React.MouseEventHandler<HTMLDivElement>>(
|
||||
({ currentTarget }) => {
|
||||
const emojis =
|
||||
currentTarget.querySelectorAll<HTMLImageElement>('.custom-emoji');
|
||||
|
||||
for (const emoji of emojis) {
|
||||
const newSrc = emoji.getAttribute('data-static');
|
||||
if (newSrc) emoji.src = newSrc;
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
if (!status) {
|
||||
return null;
|
||||
@@ -51,7 +110,15 @@ export const EmbeddedStatus: React.FC<{ statusId: string }> = ({
|
||||
).size;
|
||||
|
||||
return (
|
||||
<div className='notification-group__embedded-status'>
|
||||
<div
|
||||
className='notification-group__embedded-status'
|
||||
role='button'
|
||||
tabIndex={-1}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseUp={handleMouseUp}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<div className='notification-group__embedded-status__account'>
|
||||
<Avatar account={account} size={16} />
|
||||
<DisplayName account={account} />
|
||||
@@ -62,7 +129,6 @@ export const EmbeddedStatus: React.FC<{ statusId: string }> = ({
|
||||
content={contentHtml}
|
||||
language={language}
|
||||
mentions={mentions}
|
||||
onClick={handleClick}
|
||||
/>
|
||||
|
||||
{(poll || mediaAttachmentsSize > 0) && (
|
||||
|
||||
+2
-74
@@ -1,4 +1,4 @@
|
||||
import { useCallback, useRef } from 'react';
|
||||
import { useCallback } from 'react';
|
||||
|
||||
import { useHistory } from 'react-router-dom';
|
||||
|
||||
@@ -34,76 +34,10 @@ export const EmbeddedStatusContent: React.FC<{
|
||||
content: string;
|
||||
mentions: List<Mention>;
|
||||
language: string;
|
||||
onClick?: () => void;
|
||||
className?: string;
|
||||
}> = ({ content, mentions, language, onClick, className }) => {
|
||||
const clickCoordinatesRef = useRef<[number, number] | null>();
|
||||
}> = ({ content, mentions, language, className }) => {
|
||||
const history = useHistory();
|
||||
|
||||
const handleMouseDown = useCallback<React.MouseEventHandler<HTMLDivElement>>(
|
||||
({ clientX, clientY }) => {
|
||||
clickCoordinatesRef.current = [clientX, clientY];
|
||||
},
|
||||
[clickCoordinatesRef],
|
||||
);
|
||||
|
||||
const handleMouseUp = useCallback<React.MouseEventHandler<HTMLDivElement>>(
|
||||
({ clientX, clientY, target, button }) => {
|
||||
const [startX, startY] = clickCoordinatesRef.current ?? [0, 0];
|
||||
const [deltaX, deltaY] = [
|
||||
Math.abs(clientX - startX),
|
||||
Math.abs(clientY - startY),
|
||||
];
|
||||
|
||||
let element: HTMLDivElement | null = target as HTMLDivElement;
|
||||
|
||||
while (element) {
|
||||
if (
|
||||
element.localName === 'button' ||
|
||||
element.localName === 'a' ||
|
||||
element.localName === 'label'
|
||||
) {
|
||||
return;
|
||||
}
|
||||
|
||||
element = element.parentNode as HTMLDivElement | null;
|
||||
}
|
||||
|
||||
if (deltaX + deltaY < 5 && button === 0 && onClick) {
|
||||
onClick();
|
||||
}
|
||||
|
||||
clickCoordinatesRef.current = null;
|
||||
},
|
||||
[clickCoordinatesRef, onClick],
|
||||
);
|
||||
|
||||
const handleMouseEnter = useCallback<React.MouseEventHandler<HTMLDivElement>>(
|
||||
({ currentTarget }) => {
|
||||
const emojis =
|
||||
currentTarget.querySelectorAll<HTMLImageElement>('.custom-emoji');
|
||||
|
||||
for (const emoji of emojis) {
|
||||
const newSrc = emoji.getAttribute('data-original');
|
||||
if (newSrc) emoji.src = newSrc;
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const handleMouseLeave = useCallback<React.MouseEventHandler<HTMLDivElement>>(
|
||||
({ currentTarget }) => {
|
||||
const emojis =
|
||||
currentTarget.querySelectorAll<HTMLImageElement>('.custom-emoji');
|
||||
|
||||
for (const emoji of emojis) {
|
||||
const newSrc = emoji.getAttribute('data-static');
|
||||
if (newSrc) emoji.src = newSrc;
|
||||
}
|
||||
},
|
||||
[],
|
||||
);
|
||||
|
||||
const handleContentRef = useCallback(
|
||||
(node: HTMLDivElement | null) => {
|
||||
if (!node) {
|
||||
@@ -150,16 +84,10 @@ export const EmbeddedStatusContent: React.FC<{
|
||||
|
||||
return (
|
||||
<div
|
||||
role='button'
|
||||
tabIndex={0}
|
||||
className={className}
|
||||
ref={handleContentRef}
|
||||
lang={language}
|
||||
dangerouslySetInnerHTML={{ __html: content }}
|
||||
onMouseDown={handleMouseDown}
|
||||
onMouseUp={handleMouseUp}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
/>
|
||||
);
|
||||
};
|
||||
+19
-2
@@ -2,8 +2,10 @@ import { useMemo } from 'react';
|
||||
|
||||
import { HotKeys } from 'react-hotkeys';
|
||||
|
||||
import { navigateToProfile } from 'mastodon/actions/accounts';
|
||||
import { mentionComposeById } from 'mastodon/actions/compose';
|
||||
import type { NotificationGroup as NotificationGroupModel } from 'mastodon/models/notification_group';
|
||||
import { useAppSelector } from 'mastodon/store';
|
||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import { NotificationAdminReport } from './notification_admin_report';
|
||||
import { NotificationAdminSignUp } from './notification_admin_sign_up';
|
||||
@@ -30,6 +32,13 @@ export const NotificationGroup: React.FC<{
|
||||
),
|
||||
);
|
||||
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const accountId =
|
||||
notificationGroup?.type === 'gap'
|
||||
? undefined
|
||||
: notificationGroup?.sampleAccountIds[0];
|
||||
|
||||
const handlers = useMemo(
|
||||
() => ({
|
||||
moveUp: () => {
|
||||
@@ -39,8 +48,16 @@ export const NotificationGroup: React.FC<{
|
||||
moveDown: () => {
|
||||
onMoveDown(notificationGroupId);
|
||||
},
|
||||
|
||||
openProfile: () => {
|
||||
if (accountId) dispatch(navigateToProfile(accountId));
|
||||
},
|
||||
|
||||
mention: () => {
|
||||
if (accountId) dispatch(mentionComposeById(accountId));
|
||||
},
|
||||
}),
|
||||
[notificationGroupId, onMoveUp, onMoveDown],
|
||||
[dispatch, notificationGroupId, accountId, onMoveUp, onMoveDown],
|
||||
);
|
||||
|
||||
if (!notificationGroup || notificationGroup.type === 'gap') return null;
|
||||
|
||||
+51
-29
@@ -2,9 +2,14 @@ import { useMemo } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { HotKeys } from 'react-hotkeys';
|
||||
|
||||
import { replyComposeById } from 'mastodon/actions/compose';
|
||||
import { navigateToStatus } from 'mastodon/actions/statuses';
|
||||
import type { IconProp } from 'mastodon/components/icon';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import { RelativeTimestamp } from 'mastodon/components/relative_timestamp';
|
||||
import { useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import { AvatarGroup } from './avatar_group';
|
||||
import { EmbeddedStatus } from './embedded_status';
|
||||
@@ -39,6 +44,8 @@ export const NotificationGroupWithStatus: React.FC<{
|
||||
type,
|
||||
unread,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const label = useMemo(
|
||||
() =>
|
||||
labelRenderer({
|
||||
@@ -53,39 +60,54 @@ export const NotificationGroupWithStatus: React.FC<{
|
||||
[labelRenderer, accountIds, count, labelSeeMoreHref],
|
||||
);
|
||||
|
||||
const handlers = useMemo(
|
||||
() => ({
|
||||
open: () => {
|
||||
dispatch(navigateToStatus(statusId));
|
||||
},
|
||||
|
||||
reply: () => {
|
||||
dispatch(replyComposeById(statusId));
|
||||
},
|
||||
}),
|
||||
[dispatch, statusId],
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
role='button'
|
||||
className={classNames(
|
||||
`notification-group focusable notification-group--${type}`,
|
||||
{ 'notification-group--unread': unread },
|
||||
)}
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className='notification-group__icon'>
|
||||
<Icon icon={icon} id={iconId} />
|
||||
</div>
|
||||
|
||||
<div className='notification-group__main'>
|
||||
<div className='notification-group__main__header'>
|
||||
<div className='notification-group__main__header__wrapper'>
|
||||
<AvatarGroup accountIds={accountIds} />
|
||||
|
||||
{actions}
|
||||
</div>
|
||||
|
||||
<div className='notification-group__main__header__label'>
|
||||
{label}
|
||||
{timestamp && <RelativeTimestamp timestamp={timestamp} />}
|
||||
</div>
|
||||
<HotKeys handlers={handlers}>
|
||||
<div
|
||||
role='button'
|
||||
className={classNames(
|
||||
`notification-group focusable notification-group--${type}`,
|
||||
{ 'notification-group--unread': unread },
|
||||
)}
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className='notification-group__icon'>
|
||||
<Icon icon={icon} id={iconId} />
|
||||
</div>
|
||||
|
||||
{statusId && (
|
||||
<div className='notification-group__main__status'>
|
||||
<EmbeddedStatus statusId={statusId} />
|
||||
<div className='notification-group__main'>
|
||||
<div className='notification-group__main__header'>
|
||||
<div className='notification-group__main__header__wrapper'>
|
||||
<AvatarGroup accountIds={accountIds} />
|
||||
|
||||
{actions}
|
||||
</div>
|
||||
|
||||
<div className='notification-group__main__header__label'>
|
||||
{label}
|
||||
{timestamp && <RelativeTimestamp timestamp={timestamp} />}
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{statusId && (
|
||||
<div className='notification-group__main__status'>
|
||||
<EmbeddedStatus statusId={statusId} />
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</HotKeys>
|
||||
);
|
||||
};
|
||||
+66
-28
@@ -2,10 +2,18 @@ import { useMemo } from 'react';
|
||||
|
||||
import classNames from 'classnames';
|
||||
|
||||
import { HotKeys } from 'react-hotkeys';
|
||||
|
||||
import { replyComposeById } from 'mastodon/actions/compose';
|
||||
import { toggleReblog, toggleFavourite } from 'mastodon/actions/interactions';
|
||||
import {
|
||||
navigateToStatus,
|
||||
toggleStatusSpoilers,
|
||||
} from 'mastodon/actions/statuses';
|
||||
import type { IconProp } from 'mastodon/components/icon';
|
||||
import { Icon } from 'mastodon/components/icon';
|
||||
import Status from 'mastodon/containers/status_container';
|
||||
import { useAppSelector } from 'mastodon/store';
|
||||
import { useAppSelector, useAppDispatch } from 'mastodon/store';
|
||||
|
||||
import { NamesList } from './names_list';
|
||||
import type { LabelRenderer } from './notification_group_with_status';
|
||||
@@ -29,6 +37,8 @@ export const NotificationWithStatus: React.FC<{
|
||||
type,
|
||||
unread,
|
||||
}) => {
|
||||
const dispatch = useAppDispatch();
|
||||
|
||||
const label = useMemo(
|
||||
() =>
|
||||
labelRenderer({
|
||||
@@ -41,33 +51,61 @@ export const NotificationWithStatus: React.FC<{
|
||||
(state) => state.statuses.getIn([statusId, 'visibility']) === 'direct',
|
||||
);
|
||||
|
||||
return (
|
||||
<div
|
||||
role='button'
|
||||
className={classNames(
|
||||
`notification-ungrouped focusable notification-ungrouped--${type}`,
|
||||
{
|
||||
'notification-ungrouped--unread': unread,
|
||||
'notification-ungrouped--direct': isPrivateMention,
|
||||
},
|
||||
)}
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className='notification-ungrouped__header'>
|
||||
<div className='notification-ungrouped__header__icon'>
|
||||
<Icon icon={icon} id={iconId} />
|
||||
</div>
|
||||
{label}
|
||||
</div>
|
||||
const handlers = useMemo(
|
||||
() => ({
|
||||
open: () => {
|
||||
dispatch(navigateToStatus(statusId));
|
||||
},
|
||||
|
||||
<Status
|
||||
// @ts-expect-error -- <Status> is not yet typed
|
||||
id={statusId}
|
||||
contextType='notifications'
|
||||
withDismiss
|
||||
skipPrepend
|
||||
avatarSize={40}
|
||||
/>
|
||||
</div>
|
||||
reply: () => {
|
||||
dispatch(replyComposeById(statusId));
|
||||
},
|
||||
|
||||
boost: () => {
|
||||
dispatch(toggleReblog(statusId));
|
||||
},
|
||||
|
||||
favourite: () => {
|
||||
dispatch(toggleFavourite(statusId));
|
||||
},
|
||||
|
||||
toggleHidden: () => {
|
||||
dispatch(toggleStatusSpoilers(statusId));
|
||||
},
|
||||
}),
|
||||
[dispatch, statusId],
|
||||
);
|
||||
|
||||
return (
|
||||
<HotKeys handlers={handlers}>
|
||||
<div
|
||||
role='button'
|
||||
className={classNames(
|
||||
`notification-ungrouped focusable notification-ungrouped--${type}`,
|
||||
{
|
||||
'notification-ungrouped--unread': unread,
|
||||
'notification-ungrouped--direct': isPrivateMention,
|
||||
},
|
||||
)}
|
||||
tabIndex={0}
|
||||
>
|
||||
<div className='notification-ungrouped__header'>
|
||||
<div className='notification-ungrouped__header__icon'>
|
||||
<Icon icon={icon} id={iconId} />
|
||||
</div>
|
||||
{label}
|
||||
</div>
|
||||
|
||||
<Status
|
||||
// @ts-expect-error -- <Status> is not yet typed
|
||||
id={statusId}
|
||||
contextType='notifications'
|
||||
withDismiss
|
||||
skipPrepend
|
||||
avatarSize={40}
|
||||
unfocusable
|
||||
/>
|
||||
</div>
|
||||
</HotKeys>
|
||||
);
|
||||
};
|
||||
@@ -10457,6 +10457,8 @@ noscript {
|
||||
}
|
||||
|
||||
&__embedded-status {
|
||||
cursor: pointer;
|
||||
|
||||
&__account {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
@@ -10478,7 +10480,6 @@ noscript {
|
||||
font-size: 15px;
|
||||
line-height: 22px;
|
||||
color: $dark-text-color;
|
||||
cursor: pointer;
|
||||
-webkit-line-clamp: 4;
|
||||
-webkit-box-orient: vertical;
|
||||
max-height: 4 * 22px;
|
||||
|
||||
Reference in new issue
Block a user