Merge branch 'main' into glitch-soc/merge-upstream
commit
5de49e74d4
|
@ -34,11 +34,11 @@ class Api::V2::SearchController < Api::BaseController
|
||||||
params[:q],
|
params[:q],
|
||||||
current_account,
|
current_account,
|
||||||
limit_param(RESULTS_LIMIT),
|
limit_param(RESULTS_LIMIT),
|
||||||
search_params.merge(resolve: truthy_param?(:resolve), exclude_unreviewed: truthy_param?(:exclude_unreviewed))
|
search_params.merge(resolve: truthy_param?(:resolve), exclude_unreviewed: truthy_param?(:exclude_unreviewed), following: truthy_param?(:following))
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
def search_params
|
def search_params
|
||||||
params.permit(:type, :offset, :min_id, :max_id, :account_id)
|
params.permit(:type, :offset, :min_id, :max_id, :account_id, :following)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -130,6 +130,10 @@ class Poll extends ImmutablePureComponent {
|
||||||
this.props.refresh();
|
this.props.refresh();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
handleReveal = () => {
|
||||||
|
this.setState({ revealed: true });
|
||||||
|
}
|
||||||
|
|
||||||
renderOption (option, optionIndex, showResults) {
|
renderOption (option, optionIndex, showResults) {
|
||||||
const { poll, lang, disabled, intl } = this.props;
|
const { poll, lang, disabled, intl } = this.props;
|
||||||
const pollVotesCount = poll.get('voters_count') || poll.get('votes_count');
|
const pollVotesCount = poll.get('voters_count') || poll.get('votes_count');
|
||||||
|
@ -205,14 +209,14 @@ class Poll extends ImmutablePureComponent {
|
||||||
|
|
||||||
render () {
|
render () {
|
||||||
const { poll, intl } = this.props;
|
const { poll, intl } = this.props;
|
||||||
const { expired } = this.state;
|
const { revealed, expired } = this.state;
|
||||||
|
|
||||||
if (!poll) {
|
if (!poll) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
const timeRemaining = expired ? intl.formatMessage(messages.closed) : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />;
|
const timeRemaining = expired ? intl.formatMessage(messages.closed) : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />;
|
||||||
const showResults = poll.get('voted') || expired;
|
const showResults = poll.get('voted') || revealed || expired;
|
||||||
const disabled = this.props.disabled || Object.entries(this.state.selected).every(item => !item);
|
const disabled = this.props.disabled || Object.entries(this.state.selected).every(item => !item);
|
||||||
|
|
||||||
let votesCount = null;
|
let votesCount = null;
|
||||||
|
@ -231,9 +235,10 @@ class Poll extends ImmutablePureComponent {
|
||||||
|
|
||||||
<div className='poll__footer'>
|
<div className='poll__footer'>
|
||||||
{!showResults && <button className='button button-secondary' disabled={disabled || !this.context.identity.signedIn} onClick={this.handleVote}><FormattedMessage id='poll.vote' defaultMessage='Vote' /></button>}
|
{!showResults && <button className='button button-secondary' disabled={disabled || !this.context.identity.signedIn} onClick={this.handleVote}><FormattedMessage id='poll.vote' defaultMessage='Vote' /></button>}
|
||||||
{showResults && !this.props.disabled && <span><button className='poll__link' onClick={this.handleRefresh}><FormattedMessage id='poll.refresh' defaultMessage='Refresh' /></button> · </span>}
|
{!showResults && <><button className='poll__link' onClick={this.handleReveal}><FormattedMessage id='poll.reveal' defaultMessage='See results' /></button> · </>}
|
||||||
|
{showResults && !this.props.disabled && <><button className='poll__link' onClick={this.handleRefresh}><FormattedMessage id='poll.refresh' defaultMessage='Refresh' /></button> · </>}
|
||||||
{votesCount}
|
{votesCount}
|
||||||
{poll.get('expires_at') && <span> · {timeRemaining}</span>}
|
{poll.get('expires_at') && <> · {timeRemaining}</>}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -104,7 +104,7 @@ class StatusContent extends PureComponent {
|
||||||
|
|
||||||
if (mention) {
|
if (mention) {
|
||||||
link.addEventListener('click', this.onMentionClick.bind(this, mention), false);
|
link.addEventListener('click', this.onMentionClick.bind(this, mention), false);
|
||||||
link.setAttribute('title', mention.get('acct'));
|
link.setAttribute('title', `@${mention.get('acct')}`);
|
||||||
link.setAttribute('href', `/@${mention.get('acct')}`);
|
link.setAttribute('href', `/@${mention.get('acct')}`);
|
||||||
} else if (link.textContent[0] === '#' || (link.previousSibling && link.previousSibling.textContent && link.previousSibling.textContent[link.previousSibling.textContent.length - 1] === '#')) {
|
} else if (link.textContent[0] === '#' || (link.previousSibling && link.previousSibling.textContent && link.previousSibling.textContent[link.previousSibling.textContent.length - 1] === '#')) {
|
||||||
link.addEventListener('click', this.onHashtagClick.bind(this, link.text), false);
|
link.addEventListener('click', this.onHashtagClick.bind(this, link.text), false);
|
||||||
|
|
|
@ -476,6 +476,7 @@ class Header extends ImmutablePureComponent {
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{titleFromAccount(account)}</title>
|
<title>{titleFromAccount(account)}</title>
|
||||||
<meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} />
|
<meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} />
|
||||||
|
<link rel='canonical' href={account.get('url')} />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -84,7 +84,7 @@ const Firehose = ({ feedType, multiColumn }) => {
|
||||||
(maxId) => {
|
(maxId) => {
|
||||||
switch(feedType) {
|
switch(feedType) {
|
||||||
case 'community':
|
case 'community':
|
||||||
dispatch(expandCommunityTimeline({ onlyMedia }));
|
dispatch(expandCommunityTimeline({ maxId, onlyMedia }));
|
||||||
break;
|
break;
|
||||||
case 'public':
|
case 'public':
|
||||||
dispatch(expandPublicTimeline({ maxId, onlyMedia }));
|
dispatch(expandPublicTimeline({ maxId, onlyMedia }));
|
||||||
|
@ -135,12 +135,13 @@ const Firehose = ({ feedType, multiColumn }) => {
|
||||||
/>
|
/>
|
||||||
</DismissableBanner>
|
</DismissableBanner>
|
||||||
) : (
|
) : (
|
||||||
<DismissableBanner id='public_timeline'>
|
<DismissableBanner id='public_timeline'>
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='dismissable_banner.public_timeline'
|
id='dismissable_banner.public_timeline'
|
||||||
defaultMessage='These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.'
|
defaultMessage='These are the most recent public posts from people on the social web that people on {domain} follow.'
|
||||||
/>
|
values={{ domain }}
|
||||||
</DismissableBanner>
|
/>
|
||||||
|
</DismissableBanner>
|
||||||
);
|
);
|
||||||
|
|
||||||
const emptyMessage = feedType === 'community' ? (
|
const emptyMessage = feedType === 'community' ? (
|
||||||
|
@ -149,10 +150,10 @@ const Firehose = ({ feedType, multiColumn }) => {
|
||||||
defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!'
|
defaultMessage='The local timeline is empty. Write something publicly to get the ball rolling!'
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<FormattedMessage
|
<FormattedMessage
|
||||||
id='empty_column.public'
|
id='empty_column.public'
|
||||||
defaultMessage='There is nothing here! Write something publicly, or manually follow users from other servers to fill it up'
|
defaultMessage='There is nothing here! Write something publicly, or manually follow users from other servers to fill it up'
|
||||||
/>
|
/>
|
||||||
);
|
);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -171,11 +172,11 @@ const Firehose = ({ feedType, multiColumn }) => {
|
||||||
<div className='scrollable scrollable--flex'>
|
<div className='scrollable scrollable--flex'>
|
||||||
<div className='account__section-headline'>
|
<div className='account__section-headline'>
|
||||||
<NavLink exact to='/public/local'>
|
<NavLink exact to='/public/local'>
|
||||||
<FormattedMessage tagName='div' id='firehose.local' defaultMessage='Local' />
|
<FormattedMessage tagName='div' id='firehose.local' defaultMessage='This server' />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
<NavLink exact to='/public/remote'>
|
<NavLink exact to='/public/remote'>
|
||||||
<FormattedMessage tagName='div' id='firehose.remote' defaultMessage='Remote' />
|
<FormattedMessage tagName='div' id='firehose.remote' defaultMessage='Other servers' />
|
||||||
</NavLink>
|
</NavLink>
|
||||||
|
|
||||||
<NavLink exact to='/public'>
|
<NavLink exact to='/public'>
|
||||||
|
|
|
@ -8,6 +8,7 @@ import { Helmet } from 'react-helmet';
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
|
|
||||||
import DismissableBanner from 'mastodon/components/dismissable_banner';
|
import DismissableBanner from 'mastodon/components/dismissable_banner';
|
||||||
|
import { domain } from 'mastodon/initial_state';
|
||||||
|
|
||||||
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
import { addColumn, removeColumn, moveColumn } from '../../actions/columns';
|
||||||
import { connectPublicStream } from '../../actions/streaming';
|
import { connectPublicStream } from '../../actions/streaming';
|
||||||
|
@ -143,7 +144,7 @@ class PublicTimeline extends PureComponent {
|
||||||
</ColumnHeader>
|
</ColumnHeader>
|
||||||
|
|
||||||
<StatusListContainer
|
<StatusListContainer
|
||||||
prepend={<DismissableBanner id='public_timeline'><FormattedMessage id='dismissable_banner.public_timeline' defaultMessage='These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.' /></DismissableBanner>}
|
prepend={<DismissableBanner id='public_timeline'><FormattedMessage id='dismissable_banner.public_timeline' defaultMessage='These are the most recent public posts from people on the social web that people on {domain} follow.' values={{ domain }} /></DismissableBanner>}
|
||||||
timelineId={`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`}
|
timelineId={`public${onlyRemote ? ':remote' : ''}${onlyMedia ? ':media' : ''}`}
|
||||||
onLoadMore={this.handleLoadMore}
|
onLoadMore={this.handleLoadMore}
|
||||||
trackScroll={!pinned}
|
trackScroll={!pinned}
|
||||||
|
|
|
@ -713,6 +713,7 @@ class Status extends ImmutablePureComponent {
|
||||||
<Helmet>
|
<Helmet>
|
||||||
<title>{titleFromStatus(intl, status)}</title>
|
<title>{titleFromStatus(intl, status)}</title>
|
||||||
<meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} />
|
<meta name='robots' content={(isLocal && isIndexable) ? 'all' : 'noindex'} />
|
||||||
|
<link rel='canonical' href={status.get('url')} />
|
||||||
</Helmet>
|
</Helmet>
|
||||||
</Column>
|
</Column>
|
||||||
);
|
);
|
||||||
|
|
|
@ -202,7 +202,7 @@
|
||||||
"dismissable_banner.explore_links": "These are news stories being shared the most on the social web today. Newer news stories posted by more different people are ranked higher.",
|
"dismissable_banner.explore_links": "These are news stories being shared the most on the social web today. Newer news stories posted by more different people are ranked higher.",
|
||||||
"dismissable_banner.explore_statuses": "These are posts from across the social web that are gaining traction today. Newer posts with more boosts and favourites are ranked higher.",
|
"dismissable_banner.explore_statuses": "These are posts from across the social web that are gaining traction today. Newer posts with more boosts and favourites are ranked higher.",
|
||||||
"dismissable_banner.explore_tags": "These are hashtags that are gaining traction on the social web today. Hashtags that are used by more different people are ranked higher.",
|
"dismissable_banner.explore_tags": "These are hashtags that are gaining traction on the social web today. Hashtags that are used by more different people are ranked higher.",
|
||||||
"dismissable_banner.public_timeline": "These are the most recent public posts from people on this and other servers of the decentralized network that this server knows about.",
|
"dismissable_banner.public_timeline": "These are the most recent public posts from people on the social web that people on {domain} follow.",
|
||||||
"embed.instructions": "Embed this post on your website by copying the code below.",
|
"embed.instructions": "Embed this post on your website by copying the code below.",
|
||||||
"embed.preview": "Here is what it will look like:",
|
"embed.preview": "Here is what it will look like:",
|
||||||
"emoji_button.activity": "Activity",
|
"emoji_button.activity": "Activity",
|
||||||
|
@ -269,8 +269,8 @@
|
||||||
"filter_modal.select_filter.title": "Filter this post",
|
"filter_modal.select_filter.title": "Filter this post",
|
||||||
"filter_modal.title.status": "Filter a post",
|
"filter_modal.title.status": "Filter a post",
|
||||||
"firehose.all": "All",
|
"firehose.all": "All",
|
||||||
"firehose.local": "Local",
|
"firehose.local": "This server",
|
||||||
"firehose.remote": "Remote",
|
"firehose.remote": "Other servers",
|
||||||
"follow_request.authorize": "Authorize",
|
"follow_request.authorize": "Authorize",
|
||||||
"follow_request.reject": "Reject",
|
"follow_request.reject": "Reject",
|
||||||
"follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.",
|
"follow_requests.unlocked_explanation": "Even though your account is not locked, the {domain} staff thought you might want to review follow requests from these accounts manually.",
|
||||||
|
@ -487,6 +487,7 @@
|
||||||
"picture_in_picture.restore": "Put it back",
|
"picture_in_picture.restore": "Put it back",
|
||||||
"poll.closed": "Closed",
|
"poll.closed": "Closed",
|
||||||
"poll.refresh": "Refresh",
|
"poll.refresh": "Refresh",
|
||||||
|
"poll.reveal": "See results",
|
||||||
"poll.total_people": "{count, plural, one {# person} other {# people}}",
|
"poll.total_people": "{count, plural, one {# person} other {# people}}",
|
||||||
"poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
|
"poll.total_votes": "{count, plural, one {# vote} other {# votes}}",
|
||||||
"poll.vote": "Vote",
|
"poll.vote": "Vote",
|
||||||
|
|
|
@ -5,19 +5,6 @@ html {
|
||||||
scrollbar-color: $ui-base-color rgba($ui-base-color, 0.25);
|
scrollbar-color: $ui-base-color rgba($ui-base-color, 0.25);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Change the colors of button texts
|
|
||||||
.button {
|
|
||||||
color: $white;
|
|
||||||
|
|
||||||
&.button-alternative-2 {
|
|
||||||
color: $white;
|
|
||||||
}
|
|
||||||
|
|
||||||
&.button-tertiary {
|
|
||||||
color: $highlight-text-color;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.simple_form .button.button-tertiary {
|
.simple_form .button.button-tertiary {
|
||||||
color: $highlight-text-color;
|
color: $highlight-text-color;
|
||||||
}
|
}
|
||||||
|
@ -436,26 +423,6 @@ html {
|
||||||
color: $white;
|
color: $white;
|
||||||
}
|
}
|
||||||
|
|
||||||
.button.button-tertiary {
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
color: $white;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.button.button-secondary {
|
|
||||||
border-color: $darker-text-color;
|
|
||||||
color: $darker-text-color;
|
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
border-color: darken($darker-text-color, 8%);
|
|
||||||
color: darken($darker-text-color, 8%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
.flash-message.warning {
|
.flash-message.warning {
|
||||||
color: lighten($gold-star, 16%);
|
color: lighten($gold-star, 16%);
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,12 @@ $classic-primary-color: #9baec8;
|
||||||
$classic-secondary-color: #d9e1e8;
|
$classic-secondary-color: #d9e1e8;
|
||||||
$classic-highlight-color: #6364ff;
|
$classic-highlight-color: #6364ff;
|
||||||
|
|
||||||
|
$blurple-600: #563acc; // Iris
|
||||||
|
$blurple-500: #6364ff; // Brand purple
|
||||||
|
$blurple-300: #858afa; // Faded Blue
|
||||||
|
$grey-600: #4e4c5a; // Trout
|
||||||
|
$grey-100: #dadaf3; // Topaz
|
||||||
|
|
||||||
// Differences
|
// Differences
|
||||||
$success-green: lighten(#3c754d, 8%);
|
$success-green: lighten(#3c754d, 8%);
|
||||||
|
|
||||||
|
@ -19,6 +25,13 @@ $ui-primary-color: #9bcbed;
|
||||||
$ui-secondary-color: $classic-base-color !default;
|
$ui-secondary-color: $classic-base-color !default;
|
||||||
$ui-highlight-color: $classic-highlight-color !default;
|
$ui-highlight-color: $classic-highlight-color !default;
|
||||||
|
|
||||||
|
$ui-button-secondary-color: $grey-600 !default;
|
||||||
|
$ui-button-secondary-border-color: $grey-600 !default;
|
||||||
|
$ui-button-secondary-focus-color: $white !default;
|
||||||
|
|
||||||
|
$ui-button-tertiary-color: $blurple-500 !default;
|
||||||
|
$ui-button-tertiary-border-color: $blurple-500 !default;
|
||||||
|
|
||||||
$primary-text-color: $black !default;
|
$primary-text-color: $black !default;
|
||||||
$darker-text-color: $classic-base-color !default;
|
$darker-text-color: $classic-base-color !default;
|
||||||
$highlight-text-color: darken($ui-highlight-color, 8%) !default;
|
$highlight-text-color: darken($ui-highlight-color, 8%) !default;
|
||||||
|
|
|
@ -128,7 +128,6 @@ $content-width: 840px;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.selected {
|
&.selected {
|
||||||
background: darken($ui-base-color, 2%);
|
|
||||||
border-radius: 4px 0 0;
|
border-radius: 4px 0 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -146,13 +145,9 @@ $content-width: 840px;
|
||||||
|
|
||||||
.simple-navigation-active-leaf a {
|
.simple-navigation-active-leaf a {
|
||||||
color: $primary-text-color;
|
color: $primary-text-color;
|
||||||
background-color: darken($ui-highlight-color, 2%);
|
background-color: $ui-highlight-color;
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
border-radius: 0;
|
border-radius: 0;
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: $ui-highlight-color;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -246,12 +241,6 @@ $content-width: 840px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: $primary-text-color;
|
color: $primary-text-color;
|
||||||
background: $ui-highlight-color;
|
background: $ui-highlight-color;
|
||||||
|
|
||||||
&:hover,
|
|
||||||
&:focus,
|
|
||||||
&:active {
|
|
||||||
background: lighten($ui-highlight-color, 4%);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,11 +47,11 @@
|
||||||
}
|
}
|
||||||
|
|
||||||
.button {
|
.button {
|
||||||
background-color: darken($ui-highlight-color, 2%);
|
background-color: $ui-button-background-color;
|
||||||
border: 10px none;
|
border: 10px none;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
box-sizing: border-box;
|
box-sizing: border-box;
|
||||||
color: $primary-text-color;
|
color: $ui-button-color;
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
display: inline-block;
|
display: inline-block;
|
||||||
font-family: inherit;
|
font-family: inherit;
|
||||||
|
@ -71,14 +71,14 @@
|
||||||
&:active,
|
&:active,
|
||||||
&:focus,
|
&:focus,
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $ui-highlight-color;
|
background-color: $ui-button-focus-background-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
&--destructive {
|
&--destructive {
|
||||||
&:active,
|
&:active,
|
||||||
&:focus,
|
&:focus,
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $error-red;
|
background-color: $ui-button-destructive-focus-background-color;
|
||||||
transition: none;
|
transition: none;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,39 +108,18 @@
|
||||||
outline: 0 !important;
|
outline: 0 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
&.button-alternative {
|
|
||||||
color: $inverted-text-color;
|
|
||||||
background: $ui-primary-color;
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:focus,
|
|
||||||
&:hover {
|
|
||||||
background-color: lighten($ui-primary-color, 4%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.button-alternative-2 {
|
|
||||||
background: $ui-base-lighter-color;
|
|
||||||
|
|
||||||
&:active,
|
|
||||||
&:focus,
|
|
||||||
&:hover {
|
|
||||||
background-color: lighten($ui-base-lighter-color, 4%);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
&.button-secondary {
|
&.button-secondary {
|
||||||
color: $darker-text-color;
|
color: $ui-button-secondary-color;
|
||||||
background: transparent;
|
background: transparent;
|
||||||
padding: 6px 17px;
|
padding: 6px 17px;
|
||||||
border: 1px solid lighten($ui-base-color, 12%);
|
border: 1px solid $ui-button-secondary-border-color;
|
||||||
|
|
||||||
&:active,
|
&:active,
|
||||||
&:focus,
|
&:focus,
|
||||||
&:hover {
|
&:hover {
|
||||||
background: lighten($ui-base-color, 4%);
|
border-color: $ui-button-secondary-focus-background-color;
|
||||||
border-color: lighten($ui-base-color, 16%);
|
color: $ui-button-secondary-focus-color;
|
||||||
color: lighten($darker-text-color, 4%);
|
background-color: $ui-button-secondary-focus-background-color;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -152,14 +131,14 @@
|
||||||
&.button-tertiary {
|
&.button-tertiary {
|
||||||
background: transparent;
|
background: transparent;
|
||||||
padding: 6px 17px;
|
padding: 6px 17px;
|
||||||
color: $highlight-text-color;
|
color: $ui-button-tertiary-color;
|
||||||
border: 1px solid $highlight-text-color;
|
border: 1px solid $ui-button-tertiary-border-color;
|
||||||
|
|
||||||
&:active,
|
&:active,
|
||||||
&:focus,
|
&:focus,
|
||||||
&:hover {
|
&:hover {
|
||||||
background: $ui-highlight-color;
|
background-color: $ui-button-tertiary-focus-background-color;
|
||||||
color: $primary-text-color;
|
color: $ui-button-tertiary-focus-color;
|
||||||
border: 0;
|
border: 0;
|
||||||
padding: 7px 18px;
|
padding: 7px 18px;
|
||||||
}
|
}
|
||||||
|
@ -1148,6 +1127,8 @@ body > [data-popper-placement] {
|
||||||
}
|
}
|
||||||
|
|
||||||
&--in-thread {
|
&--in-thread {
|
||||||
|
$thread-margin: 46px + 10px;
|
||||||
|
|
||||||
border-bottom: 0;
|
border-bottom: 0;
|
||||||
|
|
||||||
.status__content,
|
.status__content,
|
||||||
|
@ -1158,8 +1139,12 @@ body > [data-popper-placement] {
|
||||||
.attachment-list,
|
.attachment-list,
|
||||||
.picture-in-picture-placeholder,
|
.picture-in-picture-placeholder,
|
||||||
.status-card {
|
.status-card {
|
||||||
margin-inline-start: 46px + 10px;
|
margin-inline-start: $thread-margin;
|
||||||
width: calc(100% - (46px + 10px));
|
width: calc(100% - ($thread-margin));
|
||||||
|
}
|
||||||
|
|
||||||
|
.status__content__read-more-button {
|
||||||
|
margin-inline-start: $thread-margin;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5810,15 +5795,15 @@ a.status-card.compact:hover {
|
||||||
}
|
}
|
||||||
|
|
||||||
.button.button-secondary {
|
.button.button-secondary {
|
||||||
border-color: $inverted-text-color;
|
border-color: $ui-button-secondary-border-color;
|
||||||
color: $inverted-text-color;
|
color: $ui-button-secondary-color;
|
||||||
flex: 0 0 auto;
|
flex: 0 0 auto;
|
||||||
|
|
||||||
&:hover,
|
&:hover,
|
||||||
&:focus,
|
&:focus,
|
||||||
&:active {
|
&:active {
|
||||||
border-color: lighten($inverted-text-color, 15%);
|
border-color: $ui-button-secondary-focus-background-color;
|
||||||
color: lighten($inverted-text-color, 15%);
|
color: $ui-button-secondary-focus-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -81,7 +81,7 @@
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: baseline;
|
align-items: baseline;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: darken($ui-highlight-color, 2%);
|
background: $ui-button-background-color;
|
||||||
color: $primary-text-color;
|
color: $primary-text-color;
|
||||||
transition: all 100ms ease-in;
|
transition: all 100ms ease-in;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
|
@ -94,7 +94,7 @@
|
||||||
&:active,
|
&:active,
|
||||||
&:focus,
|
&:focus,
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $ui-highlight-color;
|
background-color: $ui-button-focus-background-color;
|
||||||
transition: all 200ms ease-out;
|
transition: all 200ms ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -511,8 +511,8 @@ code {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
border: 0;
|
border: 0;
|
||||||
border-radius: 4px;
|
border-radius: 4px;
|
||||||
background: darken($ui-highlight-color, 2%);
|
background: $ui-button-background-color;
|
||||||
color: $primary-text-color;
|
color: $ui-button-color;
|
||||||
font-size: 18px;
|
font-size: 18px;
|
||||||
line-height: inherit;
|
line-height: inherit;
|
||||||
height: auto;
|
height: auto;
|
||||||
|
@ -534,7 +534,7 @@ code {
|
||||||
&:active,
|
&:active,
|
||||||
&:focus,
|
&:focus,
|
||||||
&:hover {
|
&:hover {
|
||||||
background-color: $ui-highlight-color;
|
background-color: $ui-button-focus-background-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
&:disabled:hover {
|
&:disabled:hover {
|
||||||
|
@ -542,15 +542,12 @@ code {
|
||||||
}
|
}
|
||||||
|
|
||||||
&.negative {
|
&.negative {
|
||||||
background: $error-value-color;
|
background: $ui-button-destructive-background-color;
|
||||||
|
|
||||||
&:hover {
|
|
||||||
background-color: lighten($error-value-color, 5%);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
&:hover,
|
||||||
&:active,
|
&:active,
|
||||||
&:focus {
|
&:focus {
|
||||||
background-color: darken($error-value-color, 5%);
|
background-color: $ui-button-destructive-focus-background-color;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,16 @@
|
||||||
// Commonly used web colors
|
// Commonly used web colors
|
||||||
$black: #000000; // Black
|
$black: #000000; // Black
|
||||||
$white: #ffffff; // White
|
$white: #ffffff; // White
|
||||||
|
$red-600: #b7253d !default; // Deep Carmine
|
||||||
|
$red-500: #df405a !default; // Cerise
|
||||||
|
$blurple-600: #563acc; // Iris
|
||||||
|
$blurple-500: #6364ff; // Brand purple
|
||||||
|
$blurple-300: #858afa; // Faded Blue
|
||||||
|
$grey-600: #4e4c5a; // Trout
|
||||||
|
$grey-100: #dadaf3; // Topaz
|
||||||
|
|
||||||
$success-green: #79bd9a !default; // Padua
|
$success-green: #79bd9a !default; // Padua
|
||||||
$error-red: #df405a !default; // Cerise
|
$error-red: $red-500 !default; // Cerise
|
||||||
$warning-red: #ff5050 !default; // Sunset Orange
|
$warning-red: #ff5050 !default; // Sunset Orange
|
||||||
$gold-star: #ca8f04 !default; // Dark Goldenrod
|
$gold-star: #ca8f04 !default; // Dark Goldenrod
|
||||||
|
|
||||||
|
@ -31,6 +39,22 @@ $ui-base-lighter-color: lighten(
|
||||||
$ui-primary-color: $classic-primary-color !default; // Lighter
|
$ui-primary-color: $classic-primary-color !default; // Lighter
|
||||||
$ui-secondary-color: $classic-secondary-color !default; // Lightest
|
$ui-secondary-color: $classic-secondary-color !default; // Lightest
|
||||||
$ui-highlight-color: $classic-highlight-color !default;
|
$ui-highlight-color: $classic-highlight-color !default;
|
||||||
|
$ui-button-color: $white !default;
|
||||||
|
$ui-button-background-color: $blurple-500 !default;
|
||||||
|
$ui-button-focus-background-color: $blurple-600 !default;
|
||||||
|
|
||||||
|
$ui-button-secondary-color: $grey-100 !default;
|
||||||
|
$ui-button-secondary-border-color: $grey-100 !default;
|
||||||
|
$ui-button-secondary-focus-background-color: $grey-600 !default;
|
||||||
|
$ui-button-secondary-focus-color: $white !default;
|
||||||
|
|
||||||
|
$ui-button-tertiary-color: $blurple-300 !default;
|
||||||
|
$ui-button-tertiary-border-color: $blurple-300 !default;
|
||||||
|
$ui-button-tertiary-focus-background-color: $blurple-600 !default;
|
||||||
|
$ui-button-tertiary-focus-color: $white !default;
|
||||||
|
|
||||||
|
$ui-button-destructive-background-color: $red-500 !default;
|
||||||
|
$ui-button-destructive-focus-background-color: $red-600 !default;
|
||||||
|
|
||||||
// Variables for texts
|
// Variables for texts
|
||||||
$primary-text-color: $white !default;
|
$primary-text-color: $white !default;
|
||||||
|
@ -39,6 +63,7 @@ $dark-text-color: $ui-base-lighter-color !default;
|
||||||
$secondary-text-color: $ui-secondary-color !default;
|
$secondary-text-color: $ui-secondary-color !default;
|
||||||
$highlight-text-color: lighten($ui-highlight-color, 8%) !default;
|
$highlight-text-color: lighten($ui-highlight-color, 8%) !default;
|
||||||
$action-button-color: $ui-base-lighter-color !default;
|
$action-button-color: $ui-base-lighter-color !default;
|
||||||
|
$action-button-focus-color: lighten($ui-base-lighter-color, 4%) !default;
|
||||||
$passive-text-color: $gold-star !default;
|
$passive-text-color: $gold-star !default;
|
||||||
$active-passive-text-color: $success-green !default;
|
$active-passive-text-color: $success-green !default;
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
# frozen_string_literal: true
|
# frozen_string_literal: true
|
||||||
|
|
||||||
class ScopeParser < Parslet::Parser
|
class ScopeParser < Parslet::Parser
|
||||||
rule(:term) { match('[a-z]').repeat(1).as(:term) }
|
rule(:term) { match('[a-z_]').repeat(1).as(:term) }
|
||||||
rule(:colon) { str(':') }
|
rule(:colon) { str(':') }
|
||||||
rule(:access) { (str('write') | str('read')).as(:access) }
|
rule(:access) { (str('write') | str('read')).as(:access) }
|
||||||
rule(:namespace) { str('admin').as(:namespace) }
|
rule(:namespace) { str('admin').as(:namespace) }
|
||||||
|
|
|
@ -2,12 +2,13 @@
|
||||||
|
|
||||||
class SearchService < BaseService
|
class SearchService < BaseService
|
||||||
def call(query, account, limit, options = {})
|
def call(query, account, limit, options = {})
|
||||||
@query = query&.strip
|
@query = query&.strip
|
||||||
@account = account
|
@account = account
|
||||||
@options = options
|
@options = options
|
||||||
@limit = limit.to_i
|
@limit = limit.to_i
|
||||||
@offset = options[:type].blank? ? 0 : options[:offset].to_i
|
@offset = options[:type].blank? ? 0 : options[:offset].to_i
|
||||||
@resolve = options[:resolve] || false
|
@resolve = options[:resolve] || false
|
||||||
|
@following = options[:following] || false
|
||||||
|
|
||||||
default_results.tap do |results|
|
default_results.tap do |results|
|
||||||
next if @query.blank? || @limit.zero?
|
next if @query.blank? || @limit.zero?
|
||||||
|
@ -31,7 +32,8 @@ class SearchService < BaseService
|
||||||
limit: @limit,
|
limit: @limit,
|
||||||
resolve: @resolve,
|
resolve: @resolve,
|
||||||
offset: @offset,
|
offset: @offset,
|
||||||
use_searchable_text: true
|
use_searchable_text: true,
|
||||||
|
following: @following
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,12 @@ class AccountDeletionWorker
|
||||||
sidekiq_options queue: 'pull', lock: :until_executed
|
sidekiq_options queue: 'pull', lock: :until_executed
|
||||||
|
|
||||||
def perform(account_id, options = {})
|
def perform(account_id, options = {})
|
||||||
|
account = Account.find(account_id)
|
||||||
|
return unless account.suspended?
|
||||||
|
|
||||||
reserve_username = options.with_indifferent_access.fetch(:reserve_username, true)
|
reserve_username = options.with_indifferent_access.fetch(:reserve_username, true)
|
||||||
skip_activitypub = options.with_indifferent_access.fetch(:skip_activitypub, false)
|
skip_activitypub = options.with_indifferent_access.fetch(:skip_activitypub, false)
|
||||||
DeleteAccountService.new.call(Account.find(account_id), reserve_username: reserve_username, skip_activitypub: skip_activitypub, reserve_email: false)
|
DeleteAccountService.new.call(account, reserve_username: reserve_username, skip_activitypub: skip_activitypub, reserve_email: false)
|
||||||
rescue ActiveRecord::RecordNotFound
|
rescue ActiveRecord::RecordNotFound
|
||||||
true
|
true
|
||||||
end
|
end
|
||||||
|
|
|
@ -13,6 +13,7 @@ Rails.application.routes.draw do
|
||||||
/home
|
/home
|
||||||
/public
|
/public
|
||||||
/public/local
|
/public/local
|
||||||
|
/public/remote
|
||||||
/conversations
|
/conversations
|
||||||
/lists/(*any)
|
/lists/(*any)
|
||||||
/notifications
|
/notifications
|
||||||
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddSuperappIndexToApplications < ActiveRecord::Migration[6.1]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def change
|
||||||
|
add_index :oauth_applications, :superapp, where: 'superapp = true', algorithm: :concurrently
|
||||||
|
end
|
||||||
|
end
|
|
@ -0,0 +1,9 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
class AddIndexUserOnUnconfirmedEmail < ActiveRecord::Migration[6.1]
|
||||||
|
disable_ddl_transaction!
|
||||||
|
|
||||||
|
def change
|
||||||
|
add_index :users, :unconfirmed_email, where: 'unconfirmed_email IS NOT NULL', algorithm: :concurrently
|
||||||
|
end
|
||||||
|
end
|
|
@ -10,7 +10,7 @@
|
||||||
#
|
#
|
||||||
# It's strongly recommended that you check this file into your version control system.
|
# It's strongly recommended that you check this file into your version control system.
|
||||||
|
|
||||||
ActiveRecord::Schema.define(version: 2023_06_30_145300) do
|
ActiveRecord::Schema.define(version: 2023_07_02_151753) do
|
||||||
|
|
||||||
# These are extensions that must be enabled in order to support this database
|
# These are extensions that must be enabled in order to support this database
|
||||||
enable_extension "plpgsql"
|
enable_extension "plpgsql"
|
||||||
|
@ -700,6 +700,7 @@ ActiveRecord::Schema.define(version: 2023_06_30_145300) do
|
||||||
t.bigint "owner_id"
|
t.bigint "owner_id"
|
||||||
t.boolean "confidential", default: true, null: false
|
t.boolean "confidential", default: true, null: false
|
||||||
t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type"
|
t.index ["owner_id", "owner_type"], name: "index_oauth_applications_on_owner_id_and_owner_type"
|
||||||
|
t.index ["superapp"], name: "index_oauth_applications_on_superapp", where: "(superapp = true)"
|
||||||
t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true
|
t.index ["uid"], name: "index_oauth_applications_on_uid", unique: true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -1099,6 +1100,7 @@ ActiveRecord::Schema.define(version: 2023_06_30_145300) do
|
||||||
t.index ["email"], name: "index_users_on_email", unique: true
|
t.index ["email"], name: "index_users_on_email", unique: true
|
||||||
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, opclass: :text_pattern_ops, where: "(reset_password_token IS NOT NULL)"
|
t.index ["reset_password_token"], name: "index_users_on_reset_password_token", unique: true, opclass: :text_pattern_ops, where: "(reset_password_token IS NOT NULL)"
|
||||||
t.index ["role_id"], name: "index_users_on_role_id", where: "(role_id IS NOT NULL)"
|
t.index ["role_id"], name: "index_users_on_role_id", where: "(role_id IS NOT NULL)"
|
||||||
|
t.index ["unconfirmed_email"], name: "index_users_on_unconfirmed_email", where: "(unconfirmed_email IS NOT NULL)"
|
||||||
end
|
end
|
||||||
|
|
||||||
create_table "web_push_subscriptions", force: :cascade do |t|
|
create_table "web_push_subscriptions", force: :cascade do |t|
|
||||||
|
|
|
@ -14,13 +14,40 @@ RSpec.describe Api::V2::SearchController do
|
||||||
end
|
end
|
||||||
|
|
||||||
describe 'GET #index' do
|
describe 'GET #index' do
|
||||||
before do
|
let!(:bob) { Fabricate(:account, username: 'bob_test') }
|
||||||
get :index, params: { q: 'test' }
|
let!(:ana) { Fabricate(:account, username: 'ana_test') }
|
||||||
end
|
let!(:tom) { Fabricate(:account, username: 'tom_test') }
|
||||||
|
let(:params) { { q: 'test' } }
|
||||||
|
|
||||||
it 'returns http success' do
|
it 'returns http success' do
|
||||||
|
get :index, params: params
|
||||||
|
|
||||||
expect(response).to have_http_status(200)
|
expect(response).to have_http_status(200)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
context 'when searching accounts' do
|
||||||
|
let(:params) { { q: 'test', type: 'accounts' } }
|
||||||
|
|
||||||
|
it 'returns all matching accounts' do
|
||||||
|
get :index, params: params
|
||||||
|
|
||||||
|
expect(body_as_json[:accounts].pluck(:id)).to contain_exactly(bob.id.to_s, ana.id.to_s, tom.id.to_s)
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with following=true' do
|
||||||
|
let(:params) { { q: 'test', type: 'accounts', following: 'true' } }
|
||||||
|
|
||||||
|
before do
|
||||||
|
user.account.follow!(ana)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'returns only the followed accounts' do
|
||||||
|
get :index, params: params
|
||||||
|
|
||||||
|
expect(body_as_json[:accounts].pluck(:id)).to contain_exactly(ana.id.to_s)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -68,7 +68,7 @@ describe SearchService, type: :service do
|
||||||
allow(AccountSearchService).to receive(:new).and_return(service)
|
allow(AccountSearchService).to receive(:new).and_return(service)
|
||||||
|
|
||||||
results = subject.call(query, nil, 10)
|
results = subject.call(query, nil, 10)
|
||||||
expect(service).to have_received(:call).with(query, nil, limit: 10, offset: 0, resolve: false, use_searchable_text: true)
|
expect(service).to have_received(:call).with(query, nil, limit: 10, offset: 0, resolve: false, use_searchable_text: true, following: false)
|
||||||
expect(results).to eq empty_results.merge(accounts: [account])
|
expect(results).to eq empty_results.merge(accounts: [account])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
Loading…
Reference in New Issue