Merge pull request 'nas_dev' (#2) from gitea/nas:nas_dev into releases/18
Reviewed-on: #2
|
@ -7,7 +7,7 @@ class Api::V1::Trends::TagsController < Api::BaseController
|
|||
|
||||
after_action :insert_pagination_headers
|
||||
|
||||
DEFAULT_TAGS_LIMIT = 10
|
||||
DEFAULT_TAGS_LIMIT = (ENV['MAX_TRENDING_TAGS'] || 10).to_i
|
||||
|
||||
deprecate_api '2022-03-30', only: :index, if: -> { request.path == '/api/v1/trends' }
|
||||
|
||||
|
|
BIN
app/javascript/icons/android-chrome-144x144.png
Executable file → Normal file
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 5.7 KiB |
BIN
app/javascript/icons/android-chrome-192x192.png
Executable file → Normal file
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 8.5 KiB |
BIN
app/javascript/icons/android-chrome-256x256.png
Executable file → Normal file
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 12 KiB |
BIN
app/javascript/icons/android-chrome-36x36.png
Executable file → Normal file
Before Width: | Height: | Size: 1.8 KiB After Width: | Height: | Size: 950 B |
BIN
app/javascript/icons/android-chrome-384x384.png
Executable file → Normal file
Before Width: | Height: | Size: 24 KiB After Width: | Height: | Size: 21 KiB |
BIN
app/javascript/icons/android-chrome-48x48.png
Executable file → Normal file
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 1.4 KiB |
BIN
app/javascript/icons/android-chrome-512x512.png
Executable file → Normal file
Before Width: | Height: | Size: 37 KiB After Width: | Height: | Size: 31 KiB |
BIN
app/javascript/icons/android-chrome-72x72.png
Executable file → Normal file
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
app/javascript/icons/android-chrome-96x96.png
Executable file → Normal file
Before Width: | Height: | Size: 6 KiB After Width: | Height: | Size: 3.2 KiB |
BIN
app/javascript/icons/apple-touch-icon-1024x1024.png
Executable file → Normal file
Before Width: | Height: | Size: 112 KiB After Width: | Height: | Size: 76 KiB |
BIN
app/javascript/icons/apple-touch-icon-114x114.png
Executable file → Normal file
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 4 KiB |
BIN
app/javascript/icons/apple-touch-icon-120x120.png
Executable file → Normal file
Before Width: | Height: | Size: 7.3 KiB After Width: | Height: | Size: 4.3 KiB |
BIN
app/javascript/icons/apple-touch-icon-144x144.png
Executable file → Normal file
Before Width: | Height: | Size: 8.6 KiB After Width: | Height: | Size: 5.7 KiB |
BIN
app/javascript/icons/apple-touch-icon-152x152.png
Executable file → Normal file
Before Width: | Height: | Size: 8.9 KiB After Width: | Height: | Size: 6 KiB |
BIN
app/javascript/icons/apple-touch-icon-167x167.png
Executable file → Normal file
Before Width: | Height: | Size: 9.8 KiB After Width: | Height: | Size: 6.9 KiB |
BIN
app/javascript/icons/apple-touch-icon-180x180.png
Executable file → Normal file
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 7.5 KiB |
BIN
app/javascript/icons/apple-touch-icon-192x192.png
Normal file
After Width: | Height: | Size: 8.5 KiB |
BIN
app/javascript/icons/apple-touch-icon-256x256.png
Normal file
After Width: | Height: | Size: 12 KiB |
BIN
app/javascript/icons/apple-touch-icon-36x36.png
Normal file
After Width: | Height: | Size: 950 B |
BIN
app/javascript/icons/apple-touch-icon-384x384.png
Normal file
After Width: | Height: | Size: 21 KiB |
BIN
app/javascript/icons/apple-touch-icon-48x48.png
Normal file
After Width: | Height: | Size: 1.4 KiB |
BIN
app/javascript/icons/apple-touch-icon-512x512.png
Normal file
After Width: | Height: | Size: 31 KiB |
BIN
app/javascript/icons/apple-touch-icon-57x57.png
Executable file → Normal file
Before Width: | Height: | Size: 3.7 KiB After Width: | Height: | Size: 1.6 KiB |
BIN
app/javascript/icons/apple-touch-icon-60x60.png
Executable file → Normal file
Before Width: | Height: | Size: 3.9 KiB After Width: | Height: | Size: 1.7 KiB |
BIN
app/javascript/icons/apple-touch-icon-72x72.png
Executable file → Normal file
Before Width: | Height: | Size: 4.6 KiB After Width: | Height: | Size: 2.2 KiB |
BIN
app/javascript/icons/apple-touch-icon-76x76.png
Executable file → Normal file
Before Width: | Height: | Size: 4.8 KiB After Width: | Height: | Size: 2.3 KiB |
BIN
app/javascript/icons/apple-touch-icon-96x96.png
Normal file
After Width: | Height: | Size: 3.2 KiB |
BIN
app/javascript/icons/favicon-16x16.png
Executable file → Normal file
Before Width: | Height: | Size: 986 B After Width: | Height: | Size: 6 KiB |
BIN
app/javascript/icons/favicon-32x32.png
Executable file → Normal file
Before Width: | Height: | Size: 1.7 KiB After Width: | Height: | Size: 6 KiB |
BIN
app/javascript/icons/favicon-48x48.png
Executable file → Normal file
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 6 KiB |
|
@ -42,7 +42,7 @@ class ServerBanner extends PureComponent {
|
|||
return (
|
||||
<div className='server-banner'>
|
||||
<div className='server-banner__introduction'>
|
||||
<FormattedMessage id='server_banner.is_one_of_many' defaultMessage='{domain} is one of the many independent Mastodon servers you can use to participate in the fediverse.' values={{ domain: <strong>{domain}</strong>, mastodon: <a href='https://joinmastodon.org' target='_blank' rel='noopener'>Mastodon</a> }} />
|
||||
<FormattedMessage id='server_banner.is_one_of_many' defaultMessage='{domain} is one of the many independent servers you can use to participate in the fediverse.' values={{ domain: <strong>{domain}</strong>, mastodon: <a href='https://joinmastodon.org' target='_blank' rel='noopener'>Mastodon</a> }} />
|
||||
</div>
|
||||
|
||||
<Link to='/about'>
|
||||
|
|
|
@ -40,6 +40,10 @@ const messages = defineMessages({
|
|||
enabled: { id: 'about.enabled', defaultMessage: 'Enabled' },
|
||||
disabled: { id: 'about.disabled', defaultMessage: 'Disabled' },
|
||||
capabilities: { id: 'about.kmyblue_capabilities', defaultMessage: 'Features available in this server' },
|
||||
joinFediverse: {
|
||||
id: 'about.join_fediverse',
|
||||
defaultMessage: "Join the Fediverse, become part of a community, and break free from Big Tech™'s stranglehold on public discourse."
|
||||
},
|
||||
});
|
||||
|
||||
const severityMessages = {
|
||||
|
@ -59,14 +63,13 @@ const severityMessages = {
|
|||
},
|
||||
};
|
||||
|
||||
const mapStateToProps = state => ({
|
||||
const mapStateToProps = (state) => ({
|
||||
server: state.getIn(['server', 'server']),
|
||||
extendedDescription: state.getIn(['server', 'extendedDescription']),
|
||||
domainBlocks: state.getIn(['server', 'domainBlocks']),
|
||||
});
|
||||
|
||||
class Section extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
title: PropTypes.string,
|
||||
children: PropTypes.node,
|
||||
|
@ -85,27 +88,37 @@ class Section extends PureComponent {
|
|||
this.setState({ collapsed: !collapsed }, () => onOpen && onOpen());
|
||||
};
|
||||
|
||||
handleKeyDown = (e) => {
|
||||
if (e.key === 'Enter' || e.key === ' ') {
|
||||
e.preventDefault();
|
||||
this.handleClick();
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { title, children } = this.props;
|
||||
const { collapsed } = this.state;
|
||||
|
||||
return (
|
||||
<div className={classNames('about__section', { active: !collapsed })}>
|
||||
<div className='about__section__title' role='button' tabIndex={0} onClick={this.handleClick}>
|
||||
<div
|
||||
className="about__section__title"
|
||||
role="button"
|
||||
tabIndex={0}
|
||||
onClick={this.handleClick}
|
||||
onKeyDown={this.handleKeyDown}
|
||||
aria-expanded={!collapsed}
|
||||
>
|
||||
<Icon id={collapsed ? 'chevron-right' : 'chevron-down'} icon={collapsed ? ChevronRightIcon : ExpandMoreIcon} /> {title}
|
||||
</div>
|
||||
|
||||
{!collapsed && (
|
||||
<div className='about__section__body'>{children}</div>
|
||||
)}
|
||||
{!collapsed && <div className="about__section__body">{children}</div>}
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
class CapabilityIcon extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
intl: PropTypes.object.isRequired,
|
||||
state: PropTypes.bool,
|
||||
|
@ -116,18 +129,23 @@ class CapabilityIcon extends PureComponent {
|
|||
|
||||
if (state) {
|
||||
return (
|
||||
<span className='capability-icon enabled'><Icon id='check' icon={EnabledIcon} title={intl.formatMessage(messages.enabled)} />{intl.formatMessage(messages.enabled)}</span>
|
||||
<span className="capability-icon enabled">
|
||||
<Icon id="check" icon={EnabledIcon} title={intl.formatMessage(messages.enabled)} />
|
||||
{intl.formatMessage(messages.enabled)}
|
||||
</span>
|
||||
);
|
||||
} else {
|
||||
return (
|
||||
<span className='capability-icon disabled'><Icon id='times' icon={DisabledIcon} title={intl.formatMessage(messages.disabled)} />{intl.formatMessage(messages.disabled)}</span>
|
||||
<span className="capability-icon disabled">
|
||||
<Icon id="times" icon={DisabledIcon} title={intl.formatMessage(messages.disabled)} />
|
||||
{intl.formatMessage(messages.disabled)}
|
||||
</span>
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class About extends PureComponent {
|
||||
|
||||
static propTypes = {
|
||||
server: ImmutablePropTypes.map,
|
||||
extendedDescription: ImmutablePropTypes.map,
|
||||
|
@ -156,7 +174,7 @@ class About extends PureComponent {
|
|||
const { multiColumn, intl, server, extendedDescription, domainBlocks } = this.props;
|
||||
const isLoading = server.get('isLoading');
|
||||
|
||||
const fedibirdCapabilities = server.get('fedibird_capabilities') || []; // thinking about isLoading is true
|
||||
const fedibirdCapabilities = server.get('fedibird_capabilities') || [];
|
||||
const isPublicUnlistedVisibility = fedibirdCapabilities.includes('kmyblue_visibility_public_unlisted');
|
||||
const isPublicVisibility = !fedibirdCapabilities.includes('kmyblue_no_public_visibility');
|
||||
const isEmojiReaction = fedibirdCapabilities.includes('emoji_reaction');
|
||||
|
@ -169,59 +187,88 @@ class About extends PureComponent {
|
|||
|
||||
return (
|
||||
<Column bindToDocument={!multiColumn} label={intl.formatMessage(messages.title)}>
|
||||
<div className='scrollable about'>
|
||||
<div className='about__header'>
|
||||
<ServerHeroImage blurhash={server.getIn(['thumbnail', 'blurhash'])} src={server.getIn(['thumbnail', 'url'])} srcSet={server.getIn(['thumbnail', 'versions'])?.map((value, key) => `${value} ${key.replace('@', '')}`).join(', ')} className='about__header__hero' />
|
||||
<h1>{isLoading ? <Skeleton width='10ch' /> : server.get('domain')}</h1>
|
||||
<p><FormattedMessage id='about.powered_by' defaultMessage='Decentralized social media powered by {mastodon}' values={{ mastodon: <a href='https://joinmastodon.org' className='about__mail' target='_blank' rel='noopener'>Mastodon</a> }} /></p>
|
||||
<div className="scrollable about">
|
||||
<div className="about__header">
|
||||
<ServerHeroImage
|
||||
blurhash={server.getIn(['thumbnail', 'blurhash'])}
|
||||
src={server.getIn(['thumbnail', 'url'])}
|
||||
srcSet={server
|
||||
.getIn(['thumbnail', 'versions'])
|
||||
?.map((value, key) => `${value} ${key.replace('@', '')}`)
|
||||
.join(', ')}
|
||||
className="about__header__hero"
|
||||
/>
|
||||
<h1>{isLoading ? <Skeleton width="10ch" /> : server.get('domain')}</h1>
|
||||
<p>
|
||||
<FormattedMessage id="about.powered_by" defaultMessage="Social media powered by You!" />
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<div className='about__meta'>
|
||||
<div className='about__meta__column'>
|
||||
<h4><FormattedMessage id='server_banner.administered_by' defaultMessage='Administered by:' /></h4>
|
||||
<div className="about__meta">
|
||||
<div className="about__meta__column">
|
||||
<h4>
|
||||
<FormattedMessage id="server_banner.administered_by" defaultMessage="Administered by:" />
|
||||
</h4>
|
||||
|
||||
<Account id={server.getIn(['contact', 'account', 'id'])} size={36} minimal />
|
||||
</div>
|
||||
|
||||
<hr className='about__meta__divider' />
|
||||
<hr className="about__meta__divider" />
|
||||
|
||||
<div className='about__meta__column'>
|
||||
<h4><FormattedMessage id='about.contact' defaultMessage='Contact:' /></h4>
|
||||
<div className="about__meta__column">
|
||||
<h4>
|
||||
<FormattedMessage id="about.contact" defaultMessage="Contact:" />
|
||||
</h4>
|
||||
|
||||
{isLoading ? <Skeleton width='10ch' /> : <a className='about__mail' href={emailLink}>{server.getIn(['contact', 'email'])}</a>}
|
||||
{isLoading ? (
|
||||
<Skeleton width="10ch" />
|
||||
) : (
|
||||
<a className="about__mail" href={emailLink}>
|
||||
{server.getIn(['contact', 'email'])}
|
||||
</a>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Section open title={intl.formatMessage(messages.title)}>
|
||||
{extendedDescription.get('isLoading') ? (
|
||||
<>
|
||||
<Skeleton width='100%' />
|
||||
<Skeleton width="100%" />
|
||||
<br />
|
||||
<Skeleton width='100%' />
|
||||
<Skeleton width="100%" />
|
||||
<br />
|
||||
<Skeleton width='100%' />
|
||||
<Skeleton width="100%" />
|
||||
<br />
|
||||
<Skeleton width='70%' />
|
||||
<Skeleton width="70%" />
|
||||
</>
|
||||
) : (extendedDescription.get('content')?.length > 0 ? (
|
||||
<div
|
||||
className='prose'
|
||||
dangerouslySetInnerHTML={{ __html: extendedDescription.get('content') }}
|
||||
/>
|
||||
) : extendedDescription.get('content')?.length > 0 ? (
|
||||
<div className="prose" dangerouslySetInnerHTML={{ __html: extendedDescription.get('content') }} />
|
||||
) : (
|
||||
<p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p>
|
||||
))}
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="about.not_available"
|
||||
defaultMessage="This information has not been made available on this server."
|
||||
/>
|
||||
</p>
|
||||
)}
|
||||
</Section>
|
||||
|
||||
<Section title={intl.formatMessage(messages.rules)}>
|
||||
{!isLoading && (server.get('rules', ImmutableList()).isEmpty() ? (
|
||||
<p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="about.not_available"
|
||||
defaultMessage="This information has not been made available on this server."
|
||||
/>
|
||||
</p>
|
||||
) : (
|
||||
<ol className='rules-list'>
|
||||
{server.get('rules').map(rule => (
|
||||
<ol className="rules-list">
|
||||
{server.get('rules').map((rule) => (
|
||||
<li key={rule.get('id')}>
|
||||
<div className='rules-list__text'>{rule.get('text')}</div>
|
||||
{rule.get('hint').length > 0 && (<div className='rules-list__hint'>{rule.get('hint')}</div>)}
|
||||
<div className="rules-list__text">{rule.get('text')}</div>
|
||||
{!!rule.get('hint') && rule.get('hint').length > 0 && (
|
||||
<div className="rules-list__hint">{rule.get('hint')}</div>
|
||||
)}
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
|
@ -229,23 +276,38 @@ class About extends PureComponent {
|
|||
</Section>
|
||||
|
||||
<Section title={intl.formatMessage(messages.capabilities)}>
|
||||
<p><FormattedMessage id='about.kmyblue_capability' defaultMessage='This server is using kmyblue, a fork of Mastodon. On this server, kmyblues unique features are configured as follows.' /></p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="about.kmyblue_capability"
|
||||
defaultMessage="This server is using unique features are configured as follows."
|
||||
/>
|
||||
</p>
|
||||
{!isLoading && (
|
||||
<ol className='rules-list'>
|
||||
<ol className="rules-list">
|
||||
<li>
|
||||
<span className='rules-list__text'>{intl.formatMessage(messages.emojiReaction)}: <CapabilityIcon state={isEmojiReaction} intl={intl} /></span>
|
||||
<span className="rules-list__text">
|
||||
{intl.formatMessage(messages.emojiReaction)}: <CapabilityIcon state={isEmojiReaction} intl={intl} />
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className='rules-list__text'>{intl.formatMessage(messages.publicVisibility)}: <CapabilityIcon state={isPublicVisibility} intl={intl} /></span>
|
||||
<span className="rules-list__text">
|
||||
{intl.formatMessage(messages.publicVisibility)}: <CapabilityIcon state={isPublicVisibility} intl={intl} />
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className='rules-list__text'>{intl.formatMessage(messages.publicUnlistedVisibility)}: <CapabilityIcon state={isPublicUnlistedVisibility} intl={intl} /></span>
|
||||
<span className="rules-list__text">
|
||||
{intl.formatMessage(messages.publicUnlistedVisibility)}: <CapabilityIcon state={isPublicUnlistedVisibility} intl={intl} />
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className='rules-list__text'>{intl.formatMessage(messages.localTimeline)}: <CapabilityIcon state={isLocalTimeline} intl={intl} /></span>
|
||||
<span className="rules-list__text">
|
||||
{intl.formatMessage(messages.localTimeline)}: <CapabilityIcon state={isLocalTimeline} intl={intl} />
|
||||
</span>
|
||||
</li>
|
||||
<li>
|
||||
<span className='rules-list__text'>{intl.formatMessage(messages.fullTextSearch)}: <CapabilityIcon state={isFullTextSearch} intl={intl} /></span>
|
||||
<span className="rules-list__text">
|
||||
{intl.formatMessage(messages.fullTextSearch)}: <CapabilityIcon state={isFullTextSearch} intl={intl} />
|
||||
</span>
|
||||
</li>
|
||||
</ol>
|
||||
)}
|
||||
|
@ -254,49 +316,75 @@ class About extends PureComponent {
|
|||
<Section title={intl.formatMessage(messages.blocks)} onOpen={this.handleDomainBlocksOpen}>
|
||||
{domainBlocks.get('isLoading') ? (
|
||||
<>
|
||||
<Skeleton width='100%' />
|
||||
<Skeleton width="100%" />
|
||||
<br />
|
||||
<Skeleton width='70%' />
|
||||
<Skeleton width="70%" />
|
||||
</>
|
||||
) : (domainBlocks.get('isAvailable') ? (
|
||||
) : domainBlocks.get('isAvailable') ? (
|
||||
<>
|
||||
<p><FormattedMessage id='about.domain_blocks.preamble' defaultMessage='Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server.' /></p>
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="about.domain_blocks.preamble"
|
||||
defaultMessage="Mastodon generally allows you to view content from and interact with users from any other server in the fediverse. These are the exceptions that have been made on this particular server."
|
||||
/>
|
||||
</p>
|
||||
|
||||
{domainBlocks.get('items').size > 0 && (
|
||||
<div className='about__domain-blocks'>
|
||||
{domainBlocks.get('items').map(block => (
|
||||
<div className='about__domain-blocks__domain' key={block.get('domain')}>
|
||||
<div className='about__domain-blocks__domain__header'>
|
||||
<h6><span title={`SHA-256: ${block.get('digest')}`}>{block.get('domain')}</span></h6>
|
||||
<span className='about__domain-blocks__domain__type' title={intl.formatMessage(severityMessages[block.get('severity')].explanation)}>{intl.formatMessage(severityMessages[block.get('severity_ex') || block.get('severity')].title)}</span>
|
||||
<div className="about__domain-blocks">
|
||||
{domainBlocks.get('items').map((block) => (
|
||||
<div className="about__domain-blocks__domain" key={block.get('domain')}>
|
||||
<div className="about__domain-blocks__domain__header">
|
||||
<h6>
|
||||
<span title={`SHA-256: ${block.get('digest')}`}>{block.get('domain')}</span>
|
||||
</h6>
|
||||
<span
|
||||
className="about__domain-blocks__domain__type"
|
||||
title={intl.formatMessage(severityMessages[block.get('severity')].explanation)}
|
||||
>
|
||||
{intl.formatMessage(
|
||||
severityMessages[block.get('severity_ex') || block.get('severity')].title
|
||||
)}
|
||||
</span>
|
||||
</div>
|
||||
|
||||
<p>{(block.get('comment') || '').length > 0 ? block.get('comment') : <FormattedMessage id='about.domain_blocks.no_reason_available' defaultMessage='Reason not available' />}</p>
|
||||
<p>
|
||||
{(block.get('comment') || '').length > 0 ? (
|
||||
block.get('comment')
|
||||
) : (
|
||||
<FormattedMessage id="about.domain_blocks.no_reason_available" defaultMessage="Reason not available" />
|
||||
)}
|
||||
</p>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
</>
|
||||
) : (
|
||||
<p><FormattedMessage id='about.not_available' defaultMessage='This information has not been made available on this server.' /></p>
|
||||
))}
|
||||
<p>
|
||||
<FormattedMessage
|
||||
id="about.not_available"
|
||||
defaultMessage="This information has not been made available on this server."
|
||||
/>
|
||||
</p>
|
||||
)}
|
||||
</Section>
|
||||
|
||||
<LinkFooter />
|
||||
|
||||
<div className='about__footer'>
|
||||
<p><FormattedMessage id='about.disclaimer' defaultMessage='Mastodon is free, open-source software, and a trademark of Mastodon gGmbH.' /></p>
|
||||
<div className="about__footer">
|
||||
<p>
|
||||
<FormattedMessage {...messages.joinFediverse} />
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<Helmet>
|
||||
<title>{intl.formatMessage(messages.title)}</title>
|
||||
<meta name='robots' content='all' />
|
||||
<meta name="robots" content="all" />
|
||||
</Helmet>
|
||||
</Column>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default connect(mapStateToProps)(injectIntl(About));
|
||||
|
|
|
@ -14,6 +14,8 @@ import AlternateEmailIcon from '@/material-icons/400-24px/alternate_email.svg?re
|
|||
import BookmarksIcon from '@/material-icons/400-24px/bookmarks-fill.svg?react';
|
||||
import ExploreIcon from '@/material-icons/400-24px/explore.svg?react';
|
||||
import ModerationIcon from '@/material-icons/400-24px/gavel.svg?react';
|
||||
import HashtagIcon from '@/material-icons/400-24px/tag.svg?react';
|
||||
import Directory from '@/material-icons/400-24px/group.svg?react';
|
||||
import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
|
||||
import HomeIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
||||
import ListAltIcon from '@/material-icons/400-24px/list_alt.svg?react';
|
||||
|
@ -42,6 +44,8 @@ const messages = defineMessages({
|
|||
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
|
||||
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
|
||||
public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
|
||||
followed_tags: { id: 'navigation_bar.followed_tags', defaultMessage: 'Followed Hashtags' },
|
||||
directory: { id: 'navigation_bar.directory', defaultMessage: 'Profile directory' },
|
||||
settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' },
|
||||
community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
|
||||
deep_timeline: { id: 'navigation_bar.deep_timeline', defaultMessage: 'Deep timeline' },
|
||||
|
@ -144,6 +148,7 @@ class GettingStarted extends ImmutablePureComponent {
|
|||
<ColumnLink key='direct' icon='at' iconComponent={AlternateEmailIcon} text={intl.formatMessage(messages.direct)} to='/conversations' />,
|
||||
<ColumnLink key='bookmark' icon='bookmarks' iconComponent={BookmarksIcon} text={intl.formatMessage(messages.bookmarks)} to='/bookmark_categories' />,
|
||||
<ColumnLink key='favourites' icon='star' iconComponent={StarIcon} text={intl.formatMessage(messages.favourites)} to='/favourites' />,
|
||||
<ColumnLink key='followed_tags' icon='tag' iconComponent={followed_tagsIcon} text={intl.formatMessage(messages.followed_tags)} to='/followed_tags' />,
|
||||
<ColumnLink key='lists' icon='list-ul' iconComponent={ListAltIcon} text={intl.formatMessage(messages.lists)} to='/lists' />,
|
||||
<ColumnLink key='antennas' icon='wifi' iconComponent={AntennaIcon} text={intl.formatMessage(messages.antennas)} to='/antennas' />,
|
||||
<ColumnLink key='circles' icon='user-circle' iconComponent={CirclesIcon} text={intl.formatMessage(messages.circles)} to='/circles' />,
|
||||
|
|
|
@ -1,101 +1,63 @@
|
|||
import { FormattedMessage } from 'react-intl';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import {
|
||||
domain,
|
||||
version,
|
||||
source_url,
|
||||
statusPageUrl,
|
||||
profile_directory as canProfileDirectory,
|
||||
termsOfServiceEnabled,
|
||||
} from 'mastodon/initial_state';
|
||||
|
||||
const DividingCircle: React.FC = () => <span aria-hidden>{' · '}</span>;
|
||||
const DividingCircle: React.FC = () => <span aria-hidden={true}>{' · '}</span>;
|
||||
|
||||
export const LinkFooter: React.FC<{
|
||||
multiColumn: boolean;
|
||||
}> = ({ multiColumn }) => {
|
||||
export const LinkFooter: React.FC<{ multiColumn: boolean }> = ({ multiColumn }) => {
|
||||
return (
|
||||
<div className='link-footer'>
|
||||
<footer className='link-footer' role='contentinfo'>
|
||||
<p>
|
||||
<strong>{domain}</strong>:{' '}
|
||||
<Link to='/about' target={multiColumn ? '_blank' : undefined}>
|
||||
<FormattedMessage id='footer.about' defaultMessage='About' />
|
||||
</Link>
|
||||
|
||||
{statusPageUrl && (
|
||||
<>
|
||||
<DividingCircle />
|
||||
<a href={statusPageUrl} target='_blank' rel='noopener'>
|
||||
<a href={statusPageUrl} target='_blank' rel='noopener noreferrer'>
|
||||
<FormattedMessage id='footer.status' defaultMessage='Status' />
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
{canProfileDirectory && (
|
||||
<>
|
||||
|
||||
<DividingCircle />
|
||||
<Link to='/directory'>
|
||||
<FormattedMessage
|
||||
id='footer.directory'
|
||||
defaultMessage='Profiles directory'
|
||||
/>
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
<DividingCircle />
|
||||
<Link
|
||||
to='/privacy-policy'
|
||||
target={multiColumn ? '_blank' : undefined}
|
||||
rel='privacy-policy'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='footer.privacy_policy'
|
||||
defaultMessage='Privacy policy'
|
||||
/>
|
||||
<Link to='/privacy-policy' target={multiColumn ? '_blank' : undefined}>
|
||||
<FormattedMessage id='footer.privacy_policy' defaultMessage='Privacy policy' />
|
||||
</Link>
|
||||
|
||||
{termsOfServiceEnabled && (
|
||||
<>
|
||||
<DividingCircle />
|
||||
<Link
|
||||
to='/terms-of-service'
|
||||
target={multiColumn ? '_blank' : undefined}
|
||||
rel='terms-of-service'
|
||||
>
|
||||
<FormattedMessage
|
||||
id='footer.terms_of_service'
|
||||
defaultMessage='Terms of service'
|
||||
/>
|
||||
<Link to='/terms-of-service' target={multiColumn ? '_blank' : undefined}>
|
||||
<FormattedMessage id='footer.terms_of_service' defaultMessage='Terms of service' />
|
||||
</Link>
|
||||
</>
|
||||
)}
|
||||
|
||||
<DividingCircle />
|
||||
<Link to='/keyboard-shortcuts'>
|
||||
<FormattedMessage id='footer.keyboard_shortcuts' defaultMessage='Keyboard shortcuts' />
|
||||
</Link>
|
||||
|
||||
<DividingCircle />
|
||||
<a href={source_url} rel='noopener noreferrer' target='_blank'>
|
||||
<FormattedMessage id='footer.source_code' defaultMessage='View source code' />
|
||||
</a>
|
||||
</p>
|
||||
|
||||
<p>
|
||||
<strong>Mastodon</strong>:{' '}
|
||||
<a href='https://joinmastodon.org' target='_blank' rel='noopener'>
|
||||
<FormattedMessage id='footer.about' defaultMessage='About' />
|
||||
</a>
|
||||
<DividingCircle />
|
||||
<a href='https://joinmastodon.org/apps' target='_blank' rel='noopener'>
|
||||
<FormattedMessage id='footer.get_app' defaultMessage='Get the app' />
|
||||
</a>
|
||||
<DividingCircle />
|
||||
<Link to='/keyboard-shortcuts'>
|
||||
<FormattedMessage
|
||||
id='footer.keyboard_shortcuts'
|
||||
defaultMessage='Keyboard shortcuts'
|
||||
/>
|
||||
</Link>
|
||||
<DividingCircle />
|
||||
<a href={source_url} rel='noopener' target='_blank'>
|
||||
<FormattedMessage
|
||||
id='footer.source_code'
|
||||
defaultMessage='View source code'
|
||||
/>
|
||||
</a>
|
||||
<DividingCircle />
|
||||
<span className='version'>v{version}</span>
|
||||
<span title="Crafted with love for the fediverse">
|
||||
Made with <span aria-label='heart' role='img'>❤️</span>
|
||||
</span>
|
||||
</p>
|
||||
</div>
|
||||
</footer>
|
||||
);
|
||||
};
|
||||
|
|
|
@ -1,10 +1,7 @@
|
|||
import PropTypes from 'prop-types';
|
||||
import { Component, useEffect } from 'react';
|
||||
|
||||
import { defineMessages, injectIntl, useIntl } from 'react-intl';
|
||||
|
||||
import { Link } from 'react-router-dom';
|
||||
|
||||
import { useSelector, useDispatch } from 'react-redux';
|
||||
|
||||
import CirclesIcon from '@/material-icons/400-24px/account_circle-fill.svg?react';
|
||||
|
@ -13,6 +10,8 @@ import BookmarksActiveIcon from '@/material-icons/400-24px/bookmarks-fill.svg?re
|
|||
import BookmarksIcon from '@/material-icons/400-24px/bookmarks.svg?react';
|
||||
import ExploreActiveIcon from '@/material-icons/400-24px/explore-fill.svg?react';
|
||||
import ExploreIcon from '@/material-icons/400-24px/explore.svg?react';
|
||||
import HashtagIcon from '@/material-icons/400-24px/tag.svg?react';
|
||||
import DirectoryIcon from '@/material-icons/400-24px/group.svg?react';
|
||||
import ModerationIcon from '@/material-icons/400-24px/gavel.svg?react';
|
||||
import PeopleIcon from '@/material-icons/400-24px/group.svg?react';
|
||||
import HomeActiveIcon from '@/material-icons/400-24px/home-fill.svg?react';
|
||||
|
@ -31,6 +30,7 @@ import SettingsIcon from '@/material-icons/400-24px/settings.svg?react';
|
|||
import StarActiveIcon from '@/material-icons/400-24px/star-fill.svg?react';
|
||||
import StarIcon from '@/material-icons/400-24px/star.svg?react';
|
||||
import AntennaIcon from '@/material-icons/400-24px/wifi.svg?react';
|
||||
|
||||
import { fetchFollowRequests } from 'mastodon/actions/accounts';
|
||||
import { IconWithBadge } from 'mastodon/components/icon_with_badge';
|
||||
import { WordmarkLogo } from 'mastodon/components/logo';
|
||||
|
@ -50,6 +50,8 @@ const messages = defineMessages({
|
|||
home: { id: 'tabs_bar.home', defaultMessage: 'Home' },
|
||||
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
|
||||
explore: { id: 'explore.title', defaultMessage: 'Explore' },
|
||||
followed_tags: { id: 'navigation_bar.followed_tags', defaultMessage: 'Followed hashtags' },
|
||||
directory: { id: 'navigation_bar.directory', defaultMessage: 'Profiles directory' },
|
||||
local: { id: 'column.local', defaultMessage: 'Local' },
|
||||
deepLocal: { id: 'column.deep_local', defaultMessage: 'Deep' },
|
||||
firehose: { id: 'column.firehose', defaultMessage: 'Live feeds' },
|
||||
|
@ -71,7 +73,6 @@ const messages = defineMessages({
|
|||
});
|
||||
|
||||
const NotificationsLink = () => {
|
||||
|
||||
const count = useSelector(selectUnreadNotificationGroupsCount);
|
||||
const intl = useIntl();
|
||||
|
||||
|
@ -129,25 +130,20 @@ class NavigationPanel extends Component {
|
|||
const { intl } = this.props;
|
||||
const { signedIn, disabledAccountId, permissions } = this.props.identity;
|
||||
|
||||
const explorer = (trendsEnabled ? (
|
||||
const explorer = trendsEnabled ? (
|
||||
<ColumnLink transparent to='/explore' icon='explore' iconComponent={ExploreIcon} activeIconComponent={ExploreActiveIcon} text={intl.formatMessage(messages.explore)} />
|
||||
) : (
|
||||
<ColumnLink transparent to='/search' icon='search' iconComponent={SearchIcon} text={intl.formatMessage(messages.search)} />
|
||||
));
|
||||
);
|
||||
|
||||
let banner = undefined;
|
||||
|
||||
if (transientSingleColumn) {
|
||||
banner = (
|
||||
const banner = transientSingleColumn ? (
|
||||
<div className='switch-to-advanced'>
|
||||
{intl.formatMessage(messages.openedInClassicInterface)}
|
||||
{" "}
|
||||
{intl.formatMessage(messages.openedInClassicInterface)}{' '}
|
||||
<a href={`/deck${location.pathname}`} className='switch-to-advanced__toggle'>
|
||||
{intl.formatMessage(messages.advancedInterface)}
|
||||
</a>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
) : null;
|
||||
|
||||
return (
|
||||
<div className='navigation-panel'>
|
||||
|
@ -155,90 +151,59 @@ class NavigationPanel extends Component {
|
|||
<Link to='/' className='column-link column-link--logo'><WordmarkLogo /></Link>
|
||||
</div>
|
||||
|
||||
{banner &&
|
||||
<div className='navigation-panel__banner'>
|
||||
{banner}
|
||||
</div>
|
||||
}
|
||||
{banner && <div className='navigation-panel__banner'>{banner}</div>}
|
||||
|
||||
<div className='navigation-panel__menu'>
|
||||
{signedIn && (
|
||||
<>
|
||||
<ColumnLink transparent to='/home' icon='home' iconComponent={HomeIcon} activeIconComponent={HomeActiveIcon} text={intl.formatMessage(messages.home)} />
|
||||
<NotificationsLink />
|
||||
</>
|
||||
)}
|
||||
|
||||
{signedIn && enableLocalTimeline && (
|
||||
<ColumnLink transparent to='/public/local/fixed' icon='users' iconComponent={PeopleIcon} text={intl.formatMessage(messages.local)} />
|
||||
)}
|
||||
|
||||
{signedIn && enableDtlMenu && dtlTag && (
|
||||
<ColumnLink transparent to={`/tags/${dtlTag}`} icon='users' iconComponent={PeopleIcon} text={intl.formatMessage(messages.deepLocal)} />
|
||||
)}
|
||||
|
||||
{!signedIn && explorer}
|
||||
|
||||
{signedIn && (
|
||||
{enableLocalTimeline && <ColumnLink transparent to='/public/local/fixed' icon='users' iconComponent={PeopleIcon} text={intl.formatMessage(messages.local)} />}
|
||||
{enableDtlMenu && dtlTag && <ColumnLink transparent to={`/tags/${dtlTag}`} icon='users' iconComponent={PeopleIcon} text={intl.formatMessage(messages.deepLocal)} />}
|
||||
<ColumnLink transparent to='/public' isActive={this.isFirehoseActive} icon='globe' iconComponent={PublicIcon} text={intl.formatMessage(messages.firehose)} />
|
||||
)}
|
||||
|
||||
{(!signedIn && timelinePreview) && (
|
||||
<ColumnLink transparent to={enableLocalTimeline ? '/public/local' : '/public'} isActive={this.isFirehoseActive} icon='globe' iconComponent={PublicIcon} text={intl.formatMessage(messages.firehose)} />
|
||||
)}
|
||||
|
||||
{signedIn && (
|
||||
<>
|
||||
<ListPanel />
|
||||
<hr />
|
||||
</>
|
||||
)}
|
||||
|
||||
{signedIn && (
|
||||
<>
|
||||
<ColumnLink transparent to='/lists' icon='list-ul' iconComponent={ListAltIcon} activeIconComponent={ListAltActiveIcon} text={intl.formatMessage(messages.lists)} />
|
||||
<ColumnLink transparent to='/antennas' icon='wifi' iconComponent={AntennaIcon} text={intl.formatMessage(messages.antennas)} isActive={this.isAntennasActive} />
|
||||
<ColumnLink transparent to='/circles' icon='user-circle' iconComponent={CirclesIcon} text={intl.formatMessage(messages.circles)} />
|
||||
<ColumnLink transparent to='/followed_tags' icon='tag' iconComponent={HashtagIcon} text={intl.formatMessage(messages.followed_tags)} />
|
||||
<ColumnLink transparent to='/directory' icon='group' iconComponent={DirectoryIcon} text={intl.formatMessage(messages.directory)} />
|
||||
<FollowRequestsLink />
|
||||
<ColumnLink transparent to='/conversations' icon='at' iconComponent={AlternateEmailIcon} text={intl.formatMessage(messages.direct)} />
|
||||
</>
|
||||
)}
|
||||
|
||||
{signedIn && explorer}
|
||||
|
||||
{signedIn && (
|
||||
<>
|
||||
{explorer}
|
||||
<ColumnLink transparent to='/bookmark_categories' icon='bookmarks' iconComponent={BookmarksIcon} activeIconComponent={BookmarksActiveIcon} text={intl.formatMessage(messages.bookmarks)} />
|
||||
{!isHideItem('favourite_menu') && <ColumnLink transparent to='/favourites' icon='star' iconComponent={StarIcon} activeIconComponent={StarActiveIcon} text={intl.formatMessage(messages.favourites)} />}
|
||||
<hr />
|
||||
|
||||
<ColumnLink transparent href='/settings/preferences' icon='cog' iconComponent={SettingsIcon} text={intl.formatMessage(messages.preferences)} />
|
||||
|
||||
{canManageReports(permissions) && <ColumnLink transparent href='/admin/reports' icon='flag' iconComponent={ModerationIcon} text={intl.formatMessage(messages.moderation)} />}
|
||||
{canViewAdminDashboard(permissions) && <ColumnLink transparent href='/admin/dashboard' icon='tachometer' iconComponent={AdministrationIcon} text={intl.formatMessage(messages.administration)} />}
|
||||
</>
|
||||
)}
|
||||
|
||||
{!signedIn && (
|
||||
<>
|
||||
{explorer}
|
||||
{(timelinePreview || enableLocalTimeline) && (
|
||||
<ColumnLink transparent to={enableLocalTimeline ? '/public/local' : '/public'} isActive={this.isFirehoseActive} icon='globe' iconComponent={PublicIcon} text={intl.formatMessage(messages.firehose)} />
|
||||
)}
|
||||
<div className='navigation-panel__sign-in-banner'>
|
||||
<hr />
|
||||
{disabledAccountId ? <DisabledAccountBanner /> : <SignInBanner />}
|
||||
</div>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
|
||||
<div className='navigation-panel__legal'>
|
||||
<hr />
|
||||
<ColumnLink transparent to='/about' icon='ellipsis-h' iconComponent={MoreHorizIcon} text={intl.formatMessage(messages.about)} />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className='flex-spacer' />
|
||||
|
||||
<NavigationPortal />
|
||||
</div>
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
export default injectIntl(withIdentity(NavigationPanel));
|
||||
|
|
|
@ -22,7 +22,7 @@ const SignInBanner = () => {
|
|||
if (sso_redirect) {
|
||||
return (
|
||||
<div className='sign-in-banner'>
|
||||
<p><strong><FormattedMessage id='sign_in_banner.mastodon_is' defaultMessage="Mastodon is the best way to keep up with what's happening." /></strong></p>
|
||||
<p><strong><FormattedMessage id='sign_in_banner.mastodon_is' defaultMessage="Join the Fediverse, become part of a community, and break free from Big Tech™'s stranglehold on public discourse." /></strong></p>
|
||||
<p><FormattedMessage id='sign_in_banner.follow_anyone' defaultMessage='Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.' /></p>
|
||||
<a href={sso_redirect} data-method='post' className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.sso_redirect' defaultMessage='Login or Register' /></a>
|
||||
</div>
|
||||
|
@ -45,7 +45,7 @@ const SignInBanner = () => {
|
|||
|
||||
return (
|
||||
<div className='sign-in-banner'>
|
||||
<p><strong><FormattedMessage id='sign_in_banner.mastodon_is' defaultMessage="Mastodon is the best way to keep up with what's happening." /></strong></p>
|
||||
<p><strong><FormattedMessage id='sign_in_banner.mastodon_is' defaultMessage="Join the Fediverse, become part of a community, and break free from Big Tech™'s stranglehold on public discourse." /></strong></p>
|
||||
<p><FormattedMessage id='sign_in_banner.follow_anyone' defaultMessage='Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.' /></p>
|
||||
{signupButton}
|
||||
<a href='/auth/sign_in' className='button button--block button-tertiary'><FormattedMessage id='sign_in_banner.sign_in' defaultMessage='Login' /></a>
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"about.blocks": "Moderated servers",
|
||||
"about.contact": "Contact:",
|
||||
"about.disclaimer": "Mastodon is free, open-source software, and a trademark of Mastodon gGmbH.",
|
||||
"about.disclaimer": "Join the Fediverse, become part of a community, and break free from Big Tech™'s stranglehold on public discourse.",
|
||||
"about.domain_blocks.no_reason_available": "Reason not available",
|
||||
"about.domain_blocks.preamble": "Mastodon generally allows you to view content from and interact with users from any other server in the Fediverse. These are the exceptions that have been made on this particular server.",
|
||||
"about.domain_blocks.silenced.explanation": "You will generally not see profiles and content from this server, unless you explicitly look it up or opt into it by following.",
|
||||
|
@ -802,11 +802,11 @@
|
|||
"server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)",
|
||||
"server_banner.active_users": "active users",
|
||||
"server_banner.administered_by": "Administered by:",
|
||||
"server_banner.is_one_of_many": "{domain} is one of the many independent Mastodon servers you can use to participate in the fediverse.",
|
||||
"server_banner.is_one_of_many": "{domain} is one of the many independent servers you can use to participate in the fediverse.",
|
||||
"server_banner.server_stats": "Server stats:",
|
||||
"sign_in_banner.create_account": "Create account",
|
||||
"sign_in_banner.follow_anyone": "Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.",
|
||||
"sign_in_banner.mastodon_is": "Mastodon is the best way to keep up with what's happening.",
|
||||
"sign_in_banner.mastodon_is": "Join the Fediverse, become part of a community, and break free from Big Tech™'s stranglehold on public discourse.",
|
||||
"sign_in_banner.sign_in": "Sign in",
|
||||
"sign_in_banner.sso_redirect": "Login or Register",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"about.blocks": "Moderated servers",
|
||||
"about.contact": "Contact:",
|
||||
"about.disabled": "Disabled",
|
||||
"about.disclaimer": "Mastodon is free, open-source software, and a trademark of Mastodon gGmbH.",
|
||||
"about.disclaimer": "Join the Fediverse, become part of a community, and break free from Big Tech™'s stranglehold on public discourse.",
|
||||
"about.domain_blocks.no_reason_available": "Reason not available",
|
||||
"about.domain_blocks.noop.explanation": "This server is limited partically.",
|
||||
"about.domain_blocks.noop.title": "Soft limited",
|
||||
|
@ -14,9 +14,9 @@
|
|||
"about.enabled": "Enabled",
|
||||
"about.full_text_search": "Full text search",
|
||||
"about.kmyblue_capabilities": "Features available in this server",
|
||||
"about.kmyblue_capability": "This server is using kmyblue, a fork of Mastodon. On this server, kmyblues unique features are configured as follows.",
|
||||
"about.kmyblue_capability": "Server unique features are configured as follows.",
|
||||
"about.not_available": "This information has not been made available on this server.",
|
||||
"about.powered_by": "Decentralized social media powered by {mastodon}",
|
||||
"about.powered_by": "Social media powered by You!",
|
||||
"about.public_visibility": "Public visibility",
|
||||
"about.rules": "Server rules",
|
||||
"account.account_note_header": "Personal note",
|
||||
|
@ -1000,11 +1000,11 @@
|
|||
"server_banner.about_active_users": "People using this server during the last 30 days (Monthly Active Users)",
|
||||
"server_banner.active_users": "active users",
|
||||
"server_banner.administered_by": "Administered by:",
|
||||
"server_banner.is_one_of_many": "{domain} is one of the many independent Mastodon servers you can use to participate in the fediverse.",
|
||||
"server_banner.is_one_of_many": "{domain} is one of the many independent servers you can use to participate in the fediverse.",
|
||||
"server_banner.server_stats": "Server stats:",
|
||||
"sign_in_banner.create_account": "Create account",
|
||||
"sign_in_banner.follow_anyone": "Follow anyone across the fediverse and see it all in chronological order. No algorithms, ads, or clickbait in sight.",
|
||||
"sign_in_banner.mastodon_is": "Mastodon is the best way to keep up with what's happening.",
|
||||
"sign_in_banner.mastodon_is": "Join the Fediverse, become part of a community, and break free from Big Tech™'s stranglehold on public discourse.",
|
||||
"sign_in_banner.sign_in": "Login",
|
||||
"sign_in_banner.sso_redirect": "Login or Register",
|
||||
"status.admin_account": "Open moderation interface for @{name}",
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"about.blocks": "Moderatit servers",
|
||||
"about.contact": "Contack:",
|
||||
"about.disclaimer": "Mastodon is free, open-soorced saftware, an a trademairk o Mastodon gGmbH.",
|
||||
"about.disclaimer": "Join the Fediverse, become part of a community, and break free from Big Tech™'s stranglehold on public discourse.",
|
||||
"about.domain_blocks.no_reason_available": "Raison no available",
|
||||
"about.domain_blocks.preamble": "On the hail, Mastodon lats ye view content frae an interack wi uisers fae onie ither server in the fediverse.",
|
||||
"about.domain_blocks.silenced.explanation": "Ye'll generally no see profiles an content frae this server, unless ye explicitly luik it up or opt intae it bi follaein.",
|
||||
|
|
7
app/javascript/styles/modern-contrast.scss
Normal file
|
@ -0,0 +1,7 @@
|
|||
// Mastodon Modern theme by Freeplay! Check the original repo for more info: https://git.gay/freeplay/Mastodon-Modern
|
||||
// Everything in the "modern" directory is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License: http://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
@use 'contrast/variables';
|
||||
@use 'application';
|
||||
@use 'modern/style';
|
||||
@use 'contrast/diff';
|
6
app/javascript/styles/modern-dark.scss
Normal file
|
@ -0,0 +1,6 @@
|
|||
// Mastodon Modern theme by Freeplay! Check the original repo for more info: https://git.gay/freeplay/Mastodon-Modern
|
||||
// Everything in the "modern" directory is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License: http://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
@use 'mastodon/variables';
|
||||
@use 'application';
|
||||
@use 'modern/style';
|
8
app/javascript/styles/modern-light.scss
Normal file
|
@ -0,0 +1,8 @@
|
|||
// Mastodon Modern theme by Freeplay! Check the original repo for more info: https://git.gay/freeplay/Mastodon-Modern
|
||||
// Everything in the "modern" directory is licensed under a Creative Commons Attribution-ShareAlike 4.0 International License: http://creativecommons.org/licenses/by-sa/4.0/
|
||||
|
||||
@use 'mastodon-light/variables';
|
||||
@use 'mastodon-light/css_variables';
|
||||
@use 'application';
|
||||
@use 'modern/style';
|
||||
@use 'mastodon-light/diff';
|
2859
app/javascript/styles/modern/style.scss
Normal file
|
@ -1,7 +1,7 @@
|
|||
# frozen_string_literal: true
|
||||
|
||||
class StatusLengthValidator < ActiveModel::Validator
|
||||
MAX_CHARS = 500
|
||||
MAX_CHARS = (ENV['MAX_CHARS'] || 500).to_i
|
||||
URL_PLACEHOLDER_CHARS = 23
|
||||
URL_PLACEHOLDER = 'x' * 23
|
||||
|
||||
|
|
|
@ -2280,7 +2280,10 @@ en:
|
|||
themes:
|
||||
contrast: Mastodon (High contrast)
|
||||
default: Mastodon (Dark)
|
||||
full-dark: フルダーク
|
||||
modern-dark: Modern Dark
|
||||
modern-light: Modern Light
|
||||
modern-contrast: Modern Contrast
|
||||
full-dark: Full Dark
|
||||
mastodon-light: Mastodon (Light)
|
||||
system: Automatic (use system theme)
|
||||
time:
|
||||
|
|
|
@ -66,18 +66,18 @@ en:
|
|||
setting_custom_css_lead: 'Be sure to remember: In the unlikely event that you make a mistake in entering your custom CSS and the screen does not display properly, you can disable your custom CSS from the link at the bottom of the sign-in screen. Open the sign-in screen in private mode of your browser, for example, and disable it.'
|
||||
setting_default_searchability: On kmyblue and Fedibird, the search is based on the search permission setting; on Misskey, all public, local public, and non-public posts are searched regardless of this setting; on Mastodon and Firefish, instead of search permission, the "Make public posts freely searchable on other servers" setting in the profile settings is applied. In Mastodon and Firefish, the "Make public posts freely searchable on other servers" setting in the profile settings is applied instead of the search permission.
|
||||
setting_default_sensitive: Sensitive media is hidden by default and can be revealed with a click
|
||||
setting_disallow_unlisted_public_searchability: この設定を有効にすると、非収載投稿と検索範囲「誰でも」は両立できず不特定多数からの検索が不可になります。Fedibirdと同じ挙動になります
|
||||
setting_disallow_unlisted_public_searchability: If you enable this setting, unlisted posts and the “everyone” search scope cannot coexist, making it impossible for unspecified users to search your posts.
|
||||
setting_display_media_default: Hide media marked as sensitive
|
||||
setting_display_media_hide_all: Always hide media
|
||||
setting_display_media_show_all: Always show media
|
||||
setting_dtl_force_searchability: 'With using #%{tag} tag, your post settings will be changed forcibly'
|
||||
setting_dtl_force_visibility: 'With using #%{tag} tag, your post settings will be changed forcibly'
|
||||
setting_emoji_reaction_policy: Even with this setting, users on non-kmyblue servers are free to put their emoji reaction on the post and share it within the same server. If you simply want to remove the emoji reaction from your own screen, you can disable it from the appearance settings
|
||||
setting_emoji_reaction_streaming_notify_impl2: 当該サーバーの独自機能に対応したアプリを利用時に、絵文字リアクション機能を利用できます。動作確認していないため(そもそもそのようなアプリ自体を確認できていないため)正しく動かない場合があります
|
||||
setting_emoji_reaction_streaming_notify_impl2: You can use the emoji reaction feature when using an app that supports this server’s unique functionality. However, since this has not been tested (and such apps have not even been identified), it may not work correctly.
|
||||
setting_enable_emoji_reaction: If turn off, other users still can react your posts
|
||||
setting_enabled_visibilities: If turn off, you cannot select and post the privacy.
|
||||
setting_hide_network: フォローとフォロワーの情報がプロフィールページで見られないようにします
|
||||
setting_public_post_to_unlisted: 未対応のサードパーティアプリからもローカル公開で投稿できますが、公開投稿はWeb以外できなくなります
|
||||
setting_hide_network: It will hide the following and follower information from the profile page.
|
||||
setting_public_post_to_unlisted: You can still post with local visibility using unsupported third-party apps, but public posts will no longer be possible outside of the web interface.
|
||||
setting_reject_send_limited_to_suspects: This applies to "Mutual Only" posts. Circle posts will be delivered without exception. Some Misskey servers have independently supported limited posting, but this is a setting for those who are concerned about it, as mutual-only posting exposes some of the users you are mutual with to Misskey users!
|
||||
setting_reject_unlisted_subscription: Misskey and its forks can **subscribe and search** for "non-following" posts from accounts they do not follow. This differs from kmyblue's behavior. It delivers posts in the specified public range to such servers as "followers only". Please understand, however, that due to its structure, it is difficult to handle perfectly and will occasionally be delivered as non-subscribed.
|
||||
setting_reverse_search_quote: Double-quotes will result in a search with a wider range of notation, which is the opposite of Mastodon's default behavior.
|
||||
|
@ -121,10 +121,10 @@ en:
|
|||
peers_api_enabled: A list of domain names this server has encountered in the fediverse. No data is included here about whether you federate with a given server, just that your server knows about it. This is used by services that collect statistics on federation in a general sense.
|
||||
profile_directory: The profile directory lists all users who have opted-in to be discoverable.
|
||||
receive_other_servers_emoji_reaction: It can cause load. It is recommended to enable it only when there are few people.
|
||||
registrations_end_hour: 新規登録が承認なしで可能な時間帯の開始時間を指定します。これより前の時間に登録することはできません。終了時間より後にすることはできません。この時間帯から外れた新規登録には、別途承認が必要となります。
|
||||
registrations_limit: 現在のユーザー数がこれを超過すると、管理者がこの数値を増やさない限り新規登録できません。0を指定すると、この制限を無効化します。
|
||||
registrations_limit_per_day: 本日登録されたユーザー数がこれを超過すると、UTC時刻で翌日0時にならない限り新規登録できません。0を指定すると、この制限を無効化します。
|
||||
registrations_start_hour: 新規登録が承認なしで可能な時間帯の終了時間を指定します。これより後の時間に登録することはできません。開始時間より前にすることはできません。この時間帯から外れた新規登録には、別途承認が必要となります。
|
||||
registrations_end_hour: Specifies the end of the time window during which new registrations can be made without approval. Registrations cannot be made before the start time or after this end time. Registrations outside this time window will require separate approval.
|
||||
registrations_limit: If the current number of users exceeds this value, new registrations will not be possible unless the administrator increases the limit. Setting this to 0 disables the restriction.
|
||||
registrations_limit_per_day: If the number of users registered today exceeds this value, no new registrations will be allowed until 00:00 UTC the next day. Setting this to 0 disables the restriction.
|
||||
registrations_start_hour: Specifies the start of the time window during which new registrations can be made without approval. Registrations cannot be made before this time or after the end time. Registrations outside this time window will require separate approval.
|
||||
require_invite_text: When sign-ups require manual approval, make the “Why do you want to join?” text input mandatory rather than optional
|
||||
site_contact_email: How people can reach you for legal or support inquiries.
|
||||
site_contact_username: How people can reach you on Mastodon.
|
||||
|
@ -201,8 +201,8 @@ en:
|
|||
discoverable: Feature profile and posts in discovery algorithms
|
||||
fields:
|
||||
examples:
|
||||
name_1: 例) GitHub
|
||||
value_1: 例) https://github.com/xxxxxx
|
||||
name_1: Example Gitea
|
||||
value_1: Example https://giteahub.com
|
||||
name: Label
|
||||
value: Content
|
||||
indexable: Include public posts in search results
|
||||
|
|
|
@ -1,4 +1,10 @@
|
|||
default: styles/application.scss
|
||||
contrast: styles/contrast.scss
|
||||
mastodon-light: styles/mastodon-light.scss
|
||||
modern-dark: styles/modern-dark.scss
|
||||
modern-light: styles/modern-light.scss
|
||||
modern-contrast: styles/modern-contrast.scss
|
||||
full-dark: styles/full-dark.scss
|
||||
|
||||
|
||||
|
||||
|
|
Before Width: | Height: | Size: 2.8 KiB After Width: | Height: | Size: 2.4 KiB |
BIN
public/favicon.ico
Executable file → Normal file
Before Width: | Height: | Size: 9.4 KiB After Width: | Height: | Size: 6 KiB |