Skip to content

Commit

Permalink
Change status content markup to match upstream (#2923)
Browse files Browse the repository at this point in the history
* Remove option to have media outside of CWs

Upstream adopted the media-in-CW design glitch-soc originally had.

* Move poll to StatusContent

* Refactor status media icons

* Rename `forceFilter` to `showDespiteFilter` for consistency with upstream

* Change media and status content markup to match upstream's

* Add mention placeholders back
  • Loading branch information
ClearlyClaire authored Dec 29, 2024
1 parent 5e65586 commit b7afca0
Show file tree
Hide file tree
Showing 11 changed files with 232 additions and 330 deletions.
12 changes: 10 additions & 2 deletions app/javascript/flavours/glitch/components/content_warning.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,25 @@
import type { IconName } from './media_icon';
import { MediaIcon } from './media_icon';
import { StatusBanner, BannerVariant } from './status_banner';

export const ContentWarning: React.FC<{
text: string;
expanded?: boolean;
onClick?: () => void;
icons?: React.ReactNode[];
icons?: IconName[];
}> = ({ text, expanded, onClick, icons }) => (
<StatusBanner
expanded={expanded}
onClick={onClick}
variant={BannerVariant.Warning}
>
{icons}
{icons?.map((icon) => (
<MediaIcon
className='status__content__spoiler-icon'
icon={icon}
key={`icon-${icon}`}
/>
))}
<p dangerouslySetInnerHTML={{ __html: text }} />
</StatusBanner>
);
55 changes: 55 additions & 0 deletions app/javascript/flavours/glitch/components/media_icon.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
import { defineMessages, useIntl } from 'react-intl';

import ImageIcon from '@/material-icons/400-24px/image.svg?react';
import InsertChartIcon from '@/material-icons/400-24px/insert_chart.svg?react';
import LinkIcon from '@/material-icons/400-24px/link.svg?react';
import MovieIcon from '@/material-icons/400-24px/movie.svg?react';
import MusicNoteIcon from '@/material-icons/400-24px/music_note.svg?react';
import { Icon } from 'flavours/glitch/components/icon';

const messages = defineMessages({
link: {
id: 'status.has_preview_card',
defaultMessage: 'Features an attached preview card',
},
'picture-o': {
id: 'status.has_pictures',
defaultMessage: 'Features attached pictures',
},
tasks: { id: 'status.is_poll', defaultMessage: 'This toot is a poll' },
'video-camera': {
id: 'status.has_video',
defaultMessage: 'Features attached videos',
},
music: {
id: 'status.has_audio',
defaultMessage: 'Features attached audio files',
},
});

const iconComponents = {
link: LinkIcon,
'picture-o': ImageIcon,
tasks: InsertChartIcon,
'video-camera': MovieIcon,
music: MusicNoteIcon,
};

export type IconName = keyof typeof iconComponents;

export const MediaIcon: React.FC<{
className?: string;
icon: IconName;
}> = ({ className, icon }) => {
const intl = useIntl();

return (
<Icon
className={className}
id={icon}
icon={iconComponents[icon]}
title={intl.formatMessage(messages[icon])}
aria-hidden='true'
/>
);
};
29 changes: 29 additions & 0 deletions app/javascript/flavours/glitch/components/mentions_placeholder.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import ImmutablePropTypes from 'react-immutable-proptypes';

import { Permalink } from 'flavours/glitch/components/permalink';

export const MentionsPlaceholder = ({ status }) => {
if (status.get('spoiler_text').length === 0 || !status.get('mentions')) {
return null;
}

return (
<div className='status__content'>
{status.get('mentions').map(item => (
<Permalink
to={`/@${item.get('acct')}`}
href={item.get('url')}
key={item.get('id')}
className='mention'
>
@<span>{item.get('username')}</span>
</Permalink>
)).reduce((aggregate, item) => [...aggregate, item, ' '], [])}
</div>
);
};

MentionsPlaceholder.propTypes = {
status: ImmutablePropTypes.map.isRequired,
};

84 changes: 40 additions & 44 deletions app/javascript/flavours/glitch/components/status.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ import ImmutablePureComponent from 'react-immutable-pure-component';

import { HotKeys } from 'react-hotkeys';

import { ContentWarning } from 'flavours/glitch/components/content_warning';
import PictureInPicturePlaceholder from 'flavours/glitch/components/picture_in_picture_placeholder';
import PollContainer from 'flavours/glitch/containers/poll_container';
import NotificationOverlayContainer from 'flavours/glitch/features/notifications/containers/overlay_container';
import { autoUnfoldCW } from 'flavours/glitch/utils/content_warning';
import { withOptionalRouter, WithOptionalRouterPropTypes } from 'flavours/glitch/utils/react_router';
Expand All @@ -28,6 +28,7 @@ import { Avatar } from './avatar';
import { AvatarOverlay } from './avatar_overlay';
import { DisplayName } from './display_name';
import { getHashtagBarForStatus } from './hashtag_bar';
import { MentionsPlaceholder } from './mentions_placeholder';
import { Permalink } from './permalink';
import StatusActionBar from './status_action_bar';
import StatusContent from './status_content';
Expand Down Expand Up @@ -134,7 +135,7 @@ class Status extends ImmutablePureComponent {
showMedia: defaultMediaVisibility(this.props.status, this.props.settings) && !(this.context?.hideMediaByDefault),
revealBehindCW: undefined,
showCard: false,
forceFilter: undefined,
showDespiteFilter: undefined,
};

// Avoid checking props that are functions (and whose equality will always
Expand All @@ -158,7 +159,7 @@ class Status extends ImmutablePureComponent {
updateOnStates = [
'isExpanded',
'showMedia',
'forceFilter',
'showDespiteFilter',
];

static getDerivedStateFromProps(nextProps, prevState) {
Expand Down Expand Up @@ -242,7 +243,7 @@ class Status extends ImmutablePureComponent {
if (this.props.status?.get('id') !== prevProps.status?.get('id')) {
this.setState({
showMedia: defaultMediaVisibility(this.props.status, this.props.settings) && !(this.context?.hideMediaByDefault),
forceFilter: undefined,
showDespiteFilter: undefined,
});
}
}
Expand Down Expand Up @@ -399,12 +400,12 @@ class Status extends ImmutablePureComponent {
};

handleUnfilterClick = e => {
this.setState({ forceFilter: false });
this.setState({ showDespiteFilter: false });
e.preventDefault();
};

handleFilterClick = () => {
this.setState({ forceFilter: true });
this.setState({ showDespiteFilter: true });
};

handleRef = c => {
Expand Down Expand Up @@ -448,27 +449,16 @@ class Status extends ImmutablePureComponent {
} = this.props;
let attachments = null;

// Depending on user settings, some media are considered as parts of the
// contents (affected by CW) while other will be displayed outside of the
// CW.
let contentMedia = [];
let contentMediaIcons = [];
let extraMedia = [];
let extraMediaIcons = [];
let media = contentMedia;
let mediaIcons = contentMediaIcons;
let media = [];
let mediaIcons = [];
let statusAvatar;

if (settings.getIn(['content_warnings', 'media_outside'])) {
media = extraMedia;
mediaIcons = extraMediaIcons;
}

if (status === null) {
return null;
}

const isExpanded = settings.getIn(['content_warnings', 'shared_state']) ? !status.get('hidden') : this.state.isExpanded;
const expanded = isExpanded || status.get('spoiler_text').length === 0;

const handlers = {
reply: this.handleHotkeyReply,
Expand Down Expand Up @@ -498,13 +488,13 @@ class Status extends ImmutablePureComponent {
<div ref={this.handleRef} className='status focusable' tabIndex={unfocusable ? null : 0}>
<span>{status.getIn(['account', 'display_name']) || status.getIn(['account', 'username'])}</span>
{status.get('spoiler_text').length > 0 && (<span>{status.get('spoiler_text')}</span>)}
{isExpanded && <span>{status.get('content')}</span>}
{expanded && <span>{status.get('content')}</span>}
</div>
</HotKeys>
);
}

if (this.state.forceFilter === undefined ? matchedFilters : this.state.forceFilter) {
if (this.state.showDespiteFilter === undefined ? matchedFilters : this.state.showDespiteFilter) {
const minHandlers = this.props.muted ? {} : {
moveUp: this.handleHotkeyMoveUp,
moveDown: this.handleHotkeyMoveDown,
Expand Down Expand Up @@ -552,7 +542,7 @@ class Status extends ImmutablePureComponent {
sensitive={status.get('sensitive')}
letterbox={settings.getIn(['media', 'letterbox'])}
fullwidth={!rootId && settings.getIn(['media', 'fullwidth'])}
hidden={!isExpanded}
hidden={!expanded}
onOpenMedia={this.handleOpenMedia}
cacheWidth={this.props.cacheMediaWidth}
defaultWidth={this.props.cachedMediaWidth}
Expand Down Expand Up @@ -609,7 +599,7 @@ class Status extends ImmutablePureComponent {
sensitive={status.get('sensitive')}
letterbox={settings.getIn(['media', 'letterbox'])}
fullwidth={!rootId && settings.getIn(['media', 'fullwidth'])}
preventPlayback={!isExpanded}
preventPlayback={!expanded}
onOpenVideo={this.handleOpenVideo}
deployPictureInPicture={pictureInPicture.get('available') ? this.handleDeployPictureInPicture : undefined}
visible={this.state.showMedia}
Expand All @@ -631,9 +621,7 @@ class Status extends ImmutablePureComponent {
}

if (status.get('poll')) {
const language = status.getIn(['translation', 'language']) || status.get('language');
contentMedia.push(<PollContainer pollId={status.get('poll')} status={status} lang={language} />);
contentMediaIcons.push('tasks');
mediaIcons.push('tasks');
}

// Here we prepare extra data-* attributes for CSS selectors.
Expand Down Expand Up @@ -672,7 +660,6 @@ class Status extends ImmutablePureComponent {
}

const {statusContentProps, hashtagBar} = getHashtagBarForStatus(status);
contentMedia.push(hashtagBar);

return (
<HotKeys handlers={handlers} tabIndex={unfocusable ? null : -1}>
Expand Down Expand Up @@ -704,26 +691,35 @@ class Status extends ImmutablePureComponent {
</Permalink>
<StatusIcons
status={status}
mediaIcons={contentMediaIcons.concat(extraMediaIcons)}
mediaIcons={mediaIcons}
settings={settings.get('status_icons')}
/>
</header>
)}
<StatusContent
status={status}
onClick={this.handleClick}
onTranslate={this.handleTranslate}
collapsible
media={contentMedia}
extraMedia={extraMedia}
mediaIcons={contentMediaIcons}
expanded={isExpanded}
onExpandedToggle={this.handleExpandedToggle}
onCollapsedToggle={this.handleCollapsedToggle}
tagLinks={settings.get('tag_misleading_links')}
rewriteMentions={settings.get('rewrite_mentions')}
{...statusContentProps}
/>

{status.get('spoiler_text').length > 0 && <ContentWarning text={status.getIn(['translation', 'spoilerHtml']) || status.get('spoilerHtml')} expanded={expanded} onClick={this.handleExpandedToggle} icons={mediaIcons} />}

{expanded && (
<>
<StatusContent
status={status}
onClick={this.handleClick}
onTranslate={this.handleTranslate}
collapsible
media={media}
onCollapsedToggle={this.handleCollapsedToggle}
tagLinks={settings.get('tag_misleading_links')}
rewriteMentions={settings.get('rewrite_mentions')}
{...statusContentProps}
/>

{media}
{hashtagBar}
</>
)}

{/* This is a glitch-soc addition to have a placeholder */}
{!expanded && <MentionsPlaceholder status={status} />}

<StatusActionBar
status={status}
Expand Down
Loading

0 comments on commit b7afca0

Please sign in to comment.