th: live from new york it's friday night
various critical fixes (pls don't report this to NVD)
This commit is contained in:
parent
e9dbe31776
commit
c1910db65f
14 changed files with 973 additions and 951 deletions
873
.yarn/releases/yarn-3.4.1.cjs
vendored
873
.yarn/releases/yarn-3.4.1.cjs
vendored
File diff suppressed because one or more lines are too long
893
.yarn/releases/yarn-4.1.0.cjs
vendored
Executable file
893
.yarn/releases/yarn-4.1.0.cjs
vendored
Executable file
File diff suppressed because one or more lines are too long
10
.yarnrc.yml
10
.yarnrc.yml
|
@ -1,9 +1,9 @@
|
||||||
enableGlobalCache: true
|
enableGlobalCache: true
|
||||||
|
|
||||||
nodeLinker: node-modules
|
|
||||||
|
|
||||||
yarnPath: .yarn/releases/yarn-3.4.1.cjs
|
|
||||||
|
|
||||||
logFilters:
|
logFilters:
|
||||||
- code: YN0013
|
- code: YN0013
|
||||||
level: ${YARN_NOISE_LOG_CODE_LEVEL:-info}
|
level: "${YARN_NOISE_LOG_CODE_LEVEL:-info}"
|
||||||
|
|
||||||
|
nodeLinker: node-modules
|
||||||
|
|
||||||
|
yarnPath: .yarn/releases/yarn-4.1.0.cjs
|
||||||
|
|
|
@ -189,7 +189,7 @@ RUN \
|
||||||
--mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
|
--mount=type=cache,id=corepack-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/corepack,sharing=locked \
|
||||||
--mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
|
--mount=type=cache,id=yarn-cache-${TARGETPLATFORM},target=/usr/local/share/.cache/yarn,sharing=locked \
|
||||||
# Install Node packages
|
# Install Node packages
|
||||||
yarn workspaces focus --production @mastodon/mastodon;
|
yarn workspaces focus --production @mastodon/mastodon
|
||||||
|
|
||||||
# Create temporary assets build layer from build layer
|
# Create temporary assets build layer from build layer
|
||||||
FROM build as precompiler
|
FROM build as precompiler
|
||||||
|
|
|
@ -363,8 +363,7 @@ class StatusActionBar extends ImmutablePureComponent {
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon={reblogIcon} iconComponent={reblogIconComponent} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
|
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} active={status.get('reblogged')} title={reblogTitle} icon={reblogIcon} iconComponent={reblogIconComponent} onClick={this.handleReblogClick} counter={withCounters ? status.get('reblogs_count') : undefined} />
|
||||||
{/* FIXME: this is hilariously broken :( */}
|
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={!publicStatus && !reblogPrivate} /* active={status.get('reblogged')} */ title={quoteTitle} icon={quoteIcon} iconComponent={quoteIconComponent} onClick={this.handleQuoteClick} />
|
||||||
<IconButton className={classNames('status__action-bar-button', { reblogPrivate })} disabled={true /* !publicStatus && !reblogPrivate */} /* active={status.get('reblogged')} */ title={quoteTitle} icon={quoteIcon} iconComponent={quoteIconComponent} onClick={this.handleQuoteClick} />
|
|
||||||
|
|
||||||
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
|
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' iconComponent={status.get('favourited') ? StarIcon : StarBorderIcon} onClick={this.handleFavouriteClick} counter={withCounters ? status.get('favourites_count') : undefined} />
|
||||||
<IconButton className='status__action-bar-button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} />
|
<IconButton className='status__action-bar-button bookmark-icon' disabled={!signedIn} active={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' iconComponent={status.get('bookmarked') ? BookmarkIcon : BookmarkBorderIcon} onClick={this.handleBookmarkClick} />
|
||||||
|
|
|
@ -372,17 +372,17 @@ class StatusContent extends PureComponent {
|
||||||
let quoteStatusDisplayName = { __html: quoteStatusAccount.get('display_name_html') };
|
let quoteStatusDisplayName = { __html: quoteStatusAccount.get('display_name_html') };
|
||||||
|
|
||||||
quote = (
|
quote = (
|
||||||
<div class="status__quote">
|
<div className='status__quote'>
|
||||||
<blockquote>
|
<blockquote>
|
||||||
<bdi>
|
<bdi>
|
||||||
<span class="quote-display-name">
|
<span className='quote-display-name'>
|
||||||
<Icon
|
<Icon
|
||||||
fixedWidth
|
fixedWidth
|
||||||
icon='quote-right'
|
icon='quote-right'
|
||||||
id='quote-right'
|
id='quote-right'
|
||||||
aria-hidden='true'
|
aria-hidden='true'
|
||||||
key='icon-quote-right' />
|
key='icon-quote-right' />
|
||||||
<strong class="display-name__html">
|
<strong className='display-name__html'>
|
||||||
<a onClick={this.handleAccountClick} href={quoteStatus.getIn(['account', 'url'])} dangerouslySetInnerHTML={quoteStatusDisplayName} />
|
<a onClick={this.handleAccountClick} href={quoteStatus.getIn(['account', 'url'])} dangerouslySetInnerHTML={quoteStatusDisplayName} />
|
||||||
</strong>
|
</strong>
|
||||||
</span>
|
</span>
|
||||||
|
|
|
@ -1,15 +1,20 @@
|
||||||
// Package imports.
|
// Package imports.
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
import React from 'react';
|
|
||||||
import ImmutablePropTypes from 'react-immutable-proptypes';
|
|
||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
|
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
// Components.
|
|
||||||
import AccountContainer from 'flavours/glitch/containers/account_container';
|
import CloseIcon from '@/material-icons/400-24px/close.svg?react';
|
||||||
import { Icon } from 'flavours/glitch/components/icon';
|
|
||||||
import { IconButton } from 'flavours/glitch/components/icon_button';
|
|
||||||
import AttachmentList from 'flavours/glitch/components/attachment_list';
|
import AttachmentList from 'flavours/glitch/components/attachment_list';
|
||||||
|
import { WithOptionalRouterPropTypes, withOptionalRouter } from 'flavours/glitch/utils/react_router';
|
||||||
|
|
||||||
|
import { Avatar } from '../../../components/avatar';
|
||||||
|
import { DisplayName } from '../../../components/display_name';
|
||||||
|
import { Icon } from '../../../components/icon';
|
||||||
|
import { IconButton } from '../../../components/icon_button';
|
||||||
|
|
||||||
// Messages.
|
// Messages.
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
|
@ -19,19 +24,23 @@ const messages = defineMessages({
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
class QuoteIndicator extends ImmutablePureComponent {
|
class QuoteIndicator extends ImmutablePureComponent {
|
||||||
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
status: ImmutablePropTypes.map,
|
status: ImmutablePropTypes.map,
|
||||||
intl: PropTypes.object.isRequired,
|
|
||||||
onCancel: PropTypes.func,
|
onCancel: PropTypes.func,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
...WithOptionalRouterPropTypes,
|
||||||
};
|
};
|
||||||
|
|
||||||
handleClick = () => {
|
handleClick = () => {
|
||||||
const { onCancel } = this.props;
|
this.props.onCancel();
|
||||||
if (onCancel) {
|
};
|
||||||
onCancel();
|
|
||||||
|
handleAccountClick = (e) => {
|
||||||
|
if (e.button === 0 && !(e.ctrlKey || e.metaKey)) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.history?.push(`/@${this.props.status.getIn(['account', 'acct'])}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -43,40 +52,28 @@ class QuoteIndicator extends ImmutablePureComponent {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const account = status.get('account');
|
const content = { __html: status.get('contentHtml') };
|
||||||
const content = status.get('content');
|
|
||||||
const attachments = status.get('media_attachments');
|
|
||||||
|
|
||||||
// The result.
|
// The result.
|
||||||
return (
|
return (
|
||||||
<article className='quote-indicator'>
|
<article className='quote-indicator'>
|
||||||
<header className='quote-indicator__header'>
|
<header className='quote-indicator__header'>
|
||||||
<IconButton
|
<div className='quote-indicator__cancel'>
|
||||||
className='quote-indicator__cancel'
|
<IconButton title={intl.formatMessage(messages.cancel)} icon='times' iconComponent={CloseIcon} onClick={this.handleClick} inverted />
|
||||||
icon='times'
|
</div>
|
||||||
onClick={this.handleClick}
|
|
||||||
title={intl.formatMessage(messages.cancel)}
|
<a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='quote-indicator__display-name' target='_blank' rel='noopener noreferrer'>
|
||||||
inverted
|
<div className='quote-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div>
|
||||||
/>
|
<DisplayName account={status.get('account')} inline />
|
||||||
<Icon
|
</a>
|
||||||
className='quote-indicator__cancel icon-button inverted'
|
|
||||||
icon='quote-right'
|
|
||||||
id='quote-right' />
|
|
||||||
{account && (
|
|
||||||
<AccountContainer
|
|
||||||
id={account}
|
|
||||||
small
|
|
||||||
/>
|
|
||||||
)}
|
|
||||||
</header>
|
</header>
|
||||||
<div
|
|
||||||
className='quote-indicator__content icon-button translate'
|
<div className='quote-indicator__content translate' dangerouslySetInnerHTML={content} />
|
||||||
dangerouslySetInnerHTML={{ __html: content || '' }}
|
|
||||||
/>
|
{status.get('media_attachments').size > 0 && (
|
||||||
{attachments.size > 0 && (
|
|
||||||
<AttachmentList
|
<AttachmentList
|
||||||
compact
|
compact
|
||||||
media={attachments}
|
media={status.get('media_attachments')}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
</article>
|
</article>
|
||||||
|
@ -85,4 +82,4 @@ class QuoteIndicator extends ImmutablePureComponent {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default injectIntl(QuoteIndicator)
|
export default withOptionalRouter(injectIntl(QuoteIndicator));
|
||||||
|
|
|
@ -54,9 +54,6 @@ class ReplyIndicator extends ImmutablePureComponent {
|
||||||
<div className='reply-indicator__cancel'>
|
<div className='reply-indicator__cancel'>
|
||||||
<IconButton title={intl.formatMessage(messages.cancel)} icon='times' iconComponent={CloseIcon} onClick={this.handleClick} inverted />
|
<IconButton title={intl.formatMessage(messages.cancel)} icon='times' iconComponent={CloseIcon} onClick={this.handleClick} inverted />
|
||||||
</div>
|
</div>
|
||||||
<div className='quote-indicator__cancel'>
|
|
||||||
<Icon className='icon-button inverted' id='reply' />
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='reply-indicator__display-name' target='_blank' rel='noopener noreferrer'>
|
<a href={status.getIn(['account', 'url'])} onClick={this.handleAccountClick} className='reply-indicator__display-name' target='_blank' rel='noopener noreferrer'>
|
||||||
<div className='reply-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div>
|
<div className='reply-indicator__display-avatar'><Avatar account={status.get('account')} size={24} /></div>
|
||||||
|
|
|
@ -1,14 +1,18 @@
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import { cancelQuoteCompose } from 'flavours/glitch/actions/compose';
|
import { cancelQuoteCompose } from 'flavours/glitch/actions/compose';
|
||||||
|
import { makeGetStatus } from '../../../selectors';
|
||||||
import QuoteIndicator from '../components/quote_indicator';
|
import QuoteIndicator from '../components/quote_indicator';
|
||||||
|
|
||||||
const makeMapStateToProps = () => {
|
const makeMapStateToProps = () => {
|
||||||
|
const getStatus = makeGetStatus();
|
||||||
|
|
||||||
const mapStateToProps = state => {
|
const mapStateToProps = state => {
|
||||||
const statusId = state.getIn(['compose', 'quote_id']);
|
const statusId = state.getIn(['compose', 'quote_id'], null);
|
||||||
const editing = false;
|
const editing = false;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
status: state.getIn(['statuses', statusId]),
|
status: getStatus(state, { id: statusId }),
|
||||||
editing,
|
editing,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m228-240 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T458-480L320-240h-92Zm360 0 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T818-480L680-240h-92Z"/></svg>
|
After Width: | Height: | Size: 322 B |
1
app/javascript/material-icons/400-24px/format_quote.svg
Normal file
1
app/javascript/material-icons/400-24px/format_quote.svg
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<svg xmlns="http://www.w3.org/2000/svg" height="24" viewBox="0 -960 960 960" width="24"><path d="m228-240 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T458-480L320-240h-92Zm360 0 92-160q-66 0-113-47t-47-113q0-66 47-113t113-47q66 0 113 47t47 113q0 23-5.5 42.5T818-480L680-240h-92ZM320-500q25 0 42.5-17.5T380-560q0-25-17.5-42.5T320-620q-25 0-42.5 17.5T260-560q0 25 17.5 42.5T320-500Zm360 0q25 0 42.5-17.5T740-560q0-25-17.5-42.5T680-620q-25 0-42.5 17.5T620-560q0 25 17.5 42.5T680-500Zm0-60Zm-360 0Z"/></svg>
|
After Width: | Height: | Size: 538 B |
|
@ -180,11 +180,11 @@ class Status < ApplicationRecord
|
||||||
quote: [
|
quote: [
|
||||||
:application,
|
:application,
|
||||||
:tags,
|
:tags,
|
||||||
:preview_cards,
|
|
||||||
:media_attachments,
|
:media_attachments,
|
||||||
:conversation,
|
:conversation,
|
||||||
:status_stat,
|
:status_stat,
|
||||||
:preloadable_poll,
|
:preloadable_poll,
|
||||||
|
preview_cards_status: [:preview_card],
|
||||||
account: [:account_stat, :user],
|
account: [:account_stat, :user],
|
||||||
active_mentions: { account: :account_stat },
|
active_mentions: { account: :account_stat },
|
||||||
],
|
],
|
||||||
|
|
|
@ -1,35 +1,38 @@
|
||||||
.status.quote-status{ dataurl: ActivityPub::TagManager.instance.url_for(status) }
|
.status.quote-status{ dataurl: ActivityPub::TagManager.instance.url_for(status) }
|
||||||
= link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener' do
|
= link_to ActivityPub::TagManager.instance.url_for(status.account), class: 'status__display-name u-url', target: stream_link_target, rel: 'noopener noreferrer' do
|
||||||
.status__avatar
|
.status__avatar
|
||||||
%div
|
%div
|
||||||
= image_tag status.account.avatar_static_url, width: 18, height: 18, alt: '', class: 'u-photo account__avatar'
|
- if prefers_autoplay?
|
||||||
|
= image_tag status.account.avatar_original_url, alt: '', class: 'u-photo account__avatar'
|
||||||
|
- else
|
||||||
|
= image_tag status.account.avatar_static_url, alt: '', class: 'u-photo account__avatar'
|
||||||
%span.display-name
|
%span.display-name
|
||||||
%bdi
|
%bdi
|
||||||
%strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true)
|
%strong.display-name__html.p-name.emojify= display_name(status.account, custom_emojify: true, autoplay: prefers_autoplay?)
|
||||||
|
|
||||||
%span.display-name__account
|
%span.display-name__account
|
||||||
= acct(status.account)
|
= acct(status.account)
|
||||||
= fa_icon('lock') if status.account.locked?
|
= fa_icon('lock') if status.account.locked?
|
||||||
|
|
||||||
.status__content.emojify<
|
.status__content.emojify{ data: ({ spoiler: current_account&.user&.setting_expand_spoilers ? 'expanded' : 'folded' } if status.spoiler_text?) }<
|
||||||
- if status.spoiler_text?
|
|
||||||
%p{ style: ('margin-bottom: 0' unless current_account&.user&.setting_expand_spoilers) }<
|
|
||||||
%span.p-summary> #{Formatter.instance.format_spoiler(status)}
|
|
||||||
%button.status__content__spoiler-link= t('statuses.show_more')
|
|
||||||
.e-content{ lang: status.language, style: "display: #{!current_account&.user&.setting_expand_spoilers && status.spoiler_text? ? 'none' : 'block'}" }
|
|
||||||
= Formatter.instance.format_in_quote(status, custom_emojify: true)
|
|
||||||
|
|
||||||
- if !status.media_attachments.empty?
|
- if status.spoiler_text?
|
||||||
- if status.media_attachments.first.video?
|
%p<
|
||||||
- video = status.media_attachments.first
|
%span.p-summary> #{prerender_custom_emojis(h(status.spoiler_text), status.emojis)}
|
||||||
= react_component :video, src: video.file.url(:original), preview: video.file.url(:small), blurhash: video.blurhash, sensitive: (!current_account&.user&.show_all_media? && status.sensitive?) || current_account&.user&.hide_all_media?, width: 610, height: 343, inline: true, alt: video.description, quote: true do
|
%button.status__content__spoiler-link= t('statuses.show_more')
|
||||||
= render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
|
.e-content{ lang: status.language }<
|
||||||
- elsif status.media_attachments.first.audio?
|
= prerender_custom_emojis(status_content_format(status), status.emojis)
|
||||||
- audio = status.media_attachments.first
|
|
||||||
= react_component :audio, src: audio.file.url(:original), height: 60, alt: audio.description, duration: audio.file.meta.dig(:original, :duration) do
|
- if status.preloadable_poll
|
||||||
= render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
|
= render_poll_component(status)
|
||||||
|
|
||||||
|
- if !status.ordered_media_attachments.empty?
|
||||||
|
- if status.ordered_media_attachments.first.video?
|
||||||
|
= render_video_component(status, width: 610, height: 343)
|
||||||
|
- elsif status.ordered_media_attachments.first.audio?
|
||||||
|
= render_audio_component(status, width: 610, height: 343)
|
||||||
- else
|
- else
|
||||||
= react_component :media_gallery, height: 343, sensitive: (!current_account&.user&.show_all_media? && status.sensitive?) || current_account&.user&.hide_all_media?, autoPlayGif: current_account&.user&.setting_auto_play_gif, media: status.media_attachments.map { |a| ActiveModelSerializers::SerializableResource.new(a, serializer: REST::MediaAttachmentSerializer).as_json }, quote: true do
|
= render_media_gallery_component(status, height: 343)
|
||||||
= render partial: 'statuses/attachment_list', locals: { attachments: status.media_attachments }
|
|
||||||
- elsif status.preview_card
|
- elsif status.preview_card
|
||||||
= react_component :card, maxDescription: 10, card: ActiveModelSerializers::SerializableResource.new(status.preview_card, serializer: REST::PreviewCardSerializer).as_json, quote: true
|
= render_card_component(status)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
{
|
{
|
||||||
"name": "@mastodon/mastodon",
|
"name": "@mastodon/mastodon",
|
||||||
"license": "AGPL-3.0-or-later",
|
"license": "AGPL-3.0-or-later",
|
||||||
"packageManager": "yarn@4.0.2",
|
"packageManager": "yarn@4.1.0",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=18"
|
"node": ">=18"
|
||||||
},
|
},
|
||||||
|
|
Loading…
Reference in a new issue