Merge tag 'v1.0.5+3.2.0' into hometown-v1.0.5+3.3.0

This commit is contained in:
Darius Kazemi 2021-04-22 16:37:11 -07:00
commit 4fe7cfc4be
126 changed files with 2708 additions and 366 deletions

View File

@ -346,7 +346,9 @@ GEM
mime-types (3.3.1) mime-types (3.3.1)
mime-types-data (~> 3.2015) mime-types-data (~> 3.2015)
mime-types-data (3.2020.0512) mime-types-data (3.2020.0512)
mimemagic (0.3.5) mimemagic (0.3.10)
nokogiri (~> 1)
rake
mini_mime (1.0.2) mini_mime (1.0.2)
mini_portile2 (2.4.0) mini_portile2 (2.4.0)
minitest (5.14.2) minitest (5.14.2)
@ -808,3 +810,9 @@ DEPENDENCIES
webpacker (~> 5.2) webpacker (~> 5.2)
webpush webpush
xorcist (~> 1.1) xorcist (~> 1.1)
RUBY VERSION
ruby 2.6.5p114
BUNDLED WITH
1.17.2

108
README.md
View File

@ -1,88 +1,90 @@
![Mastodon](https://i.imgur.com/NhZc40l.png) # Hometown: a Mastodon fork
========
[![GitHub release](https://img.shields.io/github/release/tootsuite/mastodon.svg)][releases] <img width="300" src="https://live.staticflickr.com/7005/26777339042_b32cef4e1f_b.jpg" alt="photo of a village of stone huts nestled in a lush green valley">
[![Build Status](https://img.shields.io/circleci/project/github/tootsuite/mastodon.svg)][circleci]
[![Code Climate](https://img.shields.io/codeclimate/maintainability/tootsuite/mastodon.svg)][code_climate]
[![Crowdin](https://d322cqt584bo4o.cloudfront.net/mastodon/localized.svg)][crowdin]
[![Docker Pulls](https://img.shields.io/docker/pulls/tootsuite/mastodon.svg)][docker]
[releases]: https://github.com/tootsuite/mastodon/releases Photo by [Joana Mujollari](https://www.flickr.com/photos/141654969@N04/26777339042/), CC0 / Public Domain.
[circleci]: https://circleci.com/gh/tootsuite/mastodon
[code_climate]: https://codeclimate.com/github/tootsuite/mastodon
[crowdin]: https://crowdin.com/project/mastodon
[docker]: https://hub.docker.com/r/tootsuite/mastodon/
Mastodon is a **free, open-source social network server** based on ActivityPub where users can follow friends and discover new ones. On Mastodon, users can publish anything they want: links, pictures, text, video. All Mastodon servers are interoperable as a federated network (users on one server can seamlessly communicate with users from another one, including non-Mastodon software that implements ActivityPub)! Mastodon is a **free, open-source social network server** based on ActivityPub. This is *not* the official version of Mastodon; this is a separate version (i.e. a fork) maintained by [Darius Kazemi](https://friend.camp/@darius). For more information on Mastodon, you can see the [official website](https://joinmastodon.org) and the [upstream repo](https://github.com/tootsuite/mastodon).
Click below to **learn more** in a video: __Hometown__ is a light weight fork of Mastodon. This fork is based on the principle of: minimum code change for maximum user experience change. By our best understanding, our major changes are not wanted by the Mastodon project, hence maintaining this fork instead of trying to commit the changes to Mastodon.
[![Screenshot](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/ezgif-2-60f1b00403.gif)][youtube_demo] Please [check out our wiki](https://github.com/hometown-fork/hometown/wiki) for a list of Hometown-exclusive features. Some but not all of these are covered in this document.
[youtube_demo]: https://www.youtube.com/watch?v=IPSbNdBmWKE You can also find [a list of running Hometown instances](https://github.com/hometown-fork/hometown/wiki/Hometown-servers), don't hesitate to open an issue to add yours!
## Navigation ## Support this project
- [Project homepage 🐘](https://joinmastodon.org) Please consider [supporting Hometown by pledging to my Patreon](https://www.patreon.com/tinysubversions), which supports all my open source projects including this one!
- [Support the development via Patreon][patreon]
- [View sponsors](https://joinmastodon.org/sponsors)
- [Blog](https://blog.joinmastodon.org)
- [Documentation](https://docs.joinmastodon.org)
- [Browse Mastodon servers](https://joinmastodon.org/#getting-started)
- [Browse Mastodon apps](https://joinmastodon.org/apps)
[patreon]: https://www.patreon.com/mastodon Of course this project couldn't exist without Mastodon so maybe [support the Mastodon project Patreon](https://www.patreon.com/mastodon) too.
## Features ## Migrating from Mastodon to Hometown
<img src="https://docs.joinmastodon.org/elephant.svg" align="right" width="30%" /> Please see [this article in the wiki](https://github.com/hometown-fork/hometown/wiki/Initial-migration) for directions on migration from Mastodon to Hometown.
**No vendor lock-in: Fully interoperable with any conforming platform** ## Local only posting
It doesn't have to be Mastodon, whatever implements ActivityPub is part of the social network! [Learn more](https://blog.joinmastodon.org/2018/06/why-activitypub-is-the-future/) Mastodon right now is designed to get your messages out to the entire fediverse. This is great, but there is a huge need for more private communities. And in a federated network I think it makes the most sense for your home server to be that community (hence "Hometown").
**Real-time, chronological timeline updates** **In the context of Hometown, local only posting is a per-post security option that lets you set whether that post can federate out to other servers or not.**
See the updates of people you're following appear in real-time in the UI via WebSockets. There's a firehose view as well! I've been running Friend Camp, a Mastodon fork with local only posting, for about a year. Being able to have conversations with people on your server that don't federate is a hugely liberating thing. It allows inside jokes to develop. It allows people the freedom to complain about things that they wouldn't necessarily feel comfortable leaving a trusted server (cops, employers, etc). It also lets us do things like have a server-wide movie night where we flood the local timeline with posts about the movie, and it doesn't pollute the rest of the Fediverse.
**Media attachments like images and short videos** This feature is based on [the work of Renato Lond](https://github.com/tootsuite/mastodon/pull/8427), which is itself based on a feature in the [Mastodon Glitch Edition](https://glitch-soc.github.io/docs/) fork.
Upload and view images and WebM/MP4 videos attached to the updates. Videos with no audio track are treated like GIFs; normal videos are looped - like vines! ## Reading more content types
**Safety and moderation tools** Mastodon is microblogging software, meant for Twitter-style shortform posting.
Private posts, locked accounts, phrase filtering, muting, blocking and all sorts of other features, along with a reporting and moderation system. [Learn more](https://blog.joinmastodon.org/2018/07/cage-the-mastodon/) Hometown is microblogging for _writing_, but its goal is to accept many content types for _reading_. So while I don't plan to let Hometown users publish massive blog posts, I would like your Hometown instance to be your one-stop shop for viewing all sorts of things on the Fediverse.
**OAuth2 and a straightforward REST API** For Hometown this means if you subscribe to a service that sends out `Article` objects over ActivityPub (such as a blog on [Write As](https://write.as)), then those full articles render in your home timeline, behind a cut for length. Also, Hometown will render a variety of rich text like _italic_ and **bold**.
Mastodon acts as an OAuth2 provider so 3rd party apps can use the REST and Streaming APIs, resulting in a rich app ecosystem with a lot of choices! Click on this GIF for a brief video demo:
## Deployment <img src="http://tinysubversions.com/pics/hometown-article.gif" alt="Video demo of someone clicking 'read article' on an incoming article post, which then renders a full article.">
**Tech stack:** This is based on rich text work by [Thibaut Girka](https://sitedethib.com), and my own work on `Article` support.
- **Ruby on Rails** powers the REST API and other web pages ### It's more than just reading more stuff
- **React.js** and Redux are used for the dynamic parts of the interface
- **Node.js** powers the streaming API
**Requirements:** Reading more content types also helps make the fediverse better. ActivityPub supports all kinds of content, but most ActivityPub servers shoehorn all their content into `Note` because that's the type that Mastodon treats as first-class. This has important implications for the fediverse and also on your day to do user experience.
- **PostgreSQL** 9.5+ Take the "quote tweet" debate for example.
- **Redis** 4+
- **Ruby** 2.5+
- **Node.js** 10.13+
The repository includes deployment configurations for **Docker and docker-compose**, but also a few specific platforms like **Heroku**, **Scalingo**, and **Nanobox**. The [**stand-alone** installation guide](https://docs.joinmastodon.org/admin/install/) is available in the documentation. Twitter has a feature called "quote tweeting" that lets you embed what someone else tweets, with your own comment right next to it. It's really useful for provide commentary in context, like this, where I point people to a sale and they can read both my comment on the sale and the original tweet about the sale in one post:
A **Vagrant** configuration is included for development purposes. <img width="600" src="http://tinysubversions.com/pics/quote-tweet.png" alt="An example of a quote tweet from Twitter.">
## Contributing But it's also open to abuse with people quote-tweeting things they disagree with to encourage a pile-on from their followers. There's been a lot of debate among Mastodon users as to whether the good of this feature outweighs the bad. So far, Mastodon has avoided implementing quoting.
Mastodon is **free, open-source software** licensed under **AGPLv3**. What does this have to do with content types? Well, if we support an `Article` content type and a `Note` content type, we can support quoting for an `Article` but not for a `Note`. In practice this means that you can quote blog posts and news articles, but you can't quote a quick personal microblog note.
You can open issues for bugs you've found or features you think are missing. You can also submit pull requests to this repository, or submit translations using Crowdin. To get started, take a look at [CONTRIBUTING.md](CONTRIBUTING.md). If your contributions are accepted into Mastodon, you can request to be paid through [our OpenCollective](https://opencollective.com/mastodon). > Hometown doesn't support quoting articles yet... but it will.
**IRC channel**: #mastodon on irc.freenode.net ## Better list management
If Hometown is going to be a universal reader, you're going to need better control over organizing your feeds than mainline Mastodon provides.
I've introduced a new kind of [exclusive list](https://github.com/hometown-fork/hometown/wiki/Exclusive-lists). In vanilla Mastodon, if you add an account to your "friends I like" list, posts from people on that list appear on that list. But they also appear on your home timeline, and maybe you don't want that! You'd rather treat your "friends I like" list as your "real" home timeline, and then check your home timeline when you're bored. Check out [more details about exclusive lists on the wiki](https://github.com/hometown-fork/hometown/wiki/Exclusive-lists).
## Better accessibility defaults
Look, right now this pretty much just means that we underline hyperlinks by default. I'm of course open to implementing other obviously beneficial accessibilty defaults that Mastodon itself doesn't implement.
## Hometown is still 99.999% Mastodon
I don't intend to stray very far from mainline Mastodon with this fork. If you want something that provides a ton of new features and widgets and stuff, the [Mastodon Glitch Edition](https://glitch-soc.github.io/docs/) fork is a wondrous kitchen sink of major and minor tweaks.
Part of why I don't want to stray far from mainline Mastodon is that this project is going to be just me for the foreseeable future, and I'd like to keep it up to date with new Mastodon versions as easily as possible. The less code I change from Mastodon, the easier that is. Hence the principle of "minimum code change for maximum user experience change."
## Versioning
Hometown uses [semantic versioning](https://semver.org) and follows a versioning convention like `v1.0.0+2.9.3`. The 1.0.0 part is the actual Hometown version number, and then the 2.9.3 after the + sign is what's known in semantic versioning as "build metadata". It just means that a particular release is synchronized with Mastodon version 2.9.3, so for example an upgrade from `v1.0.0+2.9.2` to `v1.0.0+2.9.3` would upgrade _Mastodon_ but not provide any new Hometown features or fixes.
## Contributing to Hometown
Setting up your Hometown development environment is [exactly like setting up your Mastodon development environment](https://docs.joinmastodon.org/dev/overview/). Pull requests should be made to the `hometown-dev` branch, which is our default branch in Github.
## License ## License

View File

@ -28,7 +28,11 @@ class AccountsController < ApplicationController
return return
end end
@pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses? if current_user.nil?
@pinned_statuses = cache_collection(@account.pinned_statuses.without_local_only, Status) if show_pinned_statuses?
else
@pinned_statuses = cache_collection(@account.pinned_statuses, Status) if show_pinned_statuses?
end
@statuses = cached_filtered_status_page @statuses = cached_filtered_status_page
@rss_url = rss_url @rss_url = rss_url

View File

@ -38,6 +38,6 @@ class Api::V1::ListsController < Api::BaseController
end end
def list_params def list_params
params.permit(:title, :replies_policy) params.permit(:title, :replies_policy, :is_exclusive)
end end
end end

View File

@ -99,10 +99,6 @@ module AccountsHelper
end end
def svg_logo def svg_logo
content_tag(:svg, tag(:use, 'xlink:href' => '#mastodon-svg-logo'), 'viewBox' => '0 0 216.4144 232.00976') content_tag(:svg, tag(:use, 'xlink:href' => '#hometownlogo'), 'viewBox' => '0 0 216.4144 232.00976')
end
def svg_logo_full
content_tag(:svg, tag(:use, 'xlink:href' => '#mastodon-svg-logo-full'), 'viewBox' => '0 0 713.35878 175.8678')
end end
end end

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 5.9 KiB

View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" id="hometownlogo" x="0px" y="0px" viewBox="25 40 50 20" width="100%" height="100%"><g><path d="M55.9,53.9H35.3c-0.7,0-1.3,0.6-1.3,1.3s0.6,1.3,1.3,1.3h20.6c0.7,0,1.3-0.6,1.3-1.3S56.6,53.9,55.9,53.9z"/><path d="M55.9,58.2H35.3c-0.7,0-1.3,0.6-1.3,1.3s0.6,1.3,1.3,1.3h20.6c0.7,0,1.3-0.6,1.3-1.3S56.6,58.2,55.9,58.2z"/><path d="M55.9,62.6H35.3c-0.7,0-1.3,0.6-1.3,1.3s0.6,1.3,1.3,1.3h20.6c0.7,0,1.3-0.6,1.3-1.3S56.6,62.6,55.9,62.6z"/><path d="M64.8,53.9c-0.7,0-1.3,0.6-1.3,1.3v8.8c0,0.7,0.6,1.3,1.3,1.3s1.3-0.6,1.3-1.3v-8.8C66,54.4,65.4,53.9,64.8,53.9z"/><path d="M60.4,53.9c-0.7,0-1.3,0.6-1.3,1.3v8.8c0,0.7,0.6,1.3,1.3,1.3s1.3-0.6,1.3-1.3v-8.8C61.6,54.4,61.1,53.9,60.4,53.9z"/><path d="M63.7,48.3c1.3-0.7,2-2.5,2-5.6c0-3.6-0.9-7.8-3.3-7.8s-3.3,4.2-3.3,7.8c0,3.1,0.7,4.9,2,5.6v2.4c0,0.7,0.6,1.3,1.3,1.3 s1.3-0.6,1.3-1.3V48.3z M62.4,37.8c0.4,0.8,0.8,2.5,0.8,4.9c0,2.5-0.5,3.4-0.8,3.4s-0.8-0.9-0.8-3.4C61.7,40.3,62.1,38.6,62.4,37.8 z"/><path d="M57,42.7c0-0.1-0.1-0.1-0.1-0.2l-3.2-4.1c-0.2-0.3-0.6-0.5-1-0.5h-1.6v-1.9c0-0.7-0.6-1.3-1.3-1.3s-1.3,0.6-1.3,1.3V38 h-3.9h-1.1h-5.2c-0.4,0-0.7,0.2-1,0.5l-3.2,4.1c0,0.1-0.1,0.1-0.1,0.2c0,0-0.1,0.1-0.1,0.1C34,43,34,43.2,34,43.3v7.4 c0,0.7,0.6,1.3,1.3,1.3h5.2h7.4h8c0.7,0,1.3-0.6,1.3-1.3v-7.4c0-0.2,0-0.3-0.1-0.4C57,42.8,57,42.8,57,42.7z M41.7,49.5h-5.2v-4.9 h10.2v4.9H41.7z M48.5,42.1l-1.2-1.6h4.8l1.2,1.6H48.5z M44.1,40.5l1.2,1.6h-7.5l1.2-1.6H44.1z M49.2,44.6h5.5v4.9h-5.5V44.6z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -10,9 +10,10 @@ export const LISTS_FETCH_REQUEST = 'LISTS_FETCH_REQUEST';
export const LISTS_FETCH_SUCCESS = 'LISTS_FETCH_SUCCESS'; export const LISTS_FETCH_SUCCESS = 'LISTS_FETCH_SUCCESS';
export const LISTS_FETCH_FAIL = 'LISTS_FETCH_FAIL'; export const LISTS_FETCH_FAIL = 'LISTS_FETCH_FAIL';
export const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE'; export const LIST_EDITOR_TITLE_CHANGE = 'LIST_EDITOR_TITLE_CHANGE';
export const LIST_EDITOR_RESET = 'LIST_EDITOR_RESET'; export const LIST_EDITOR_IS_EXCLUSIVE_CHANGE = 'LIST_EDITOR_IS_EXCLUSIVE_CHANGE';
export const LIST_EDITOR_SETUP = 'LIST_EDITOR_SETUP'; export const LIST_EDITOR_RESET = 'LIST_EDITOR_RESET';
export const LIST_EDITOR_SETUP = 'LIST_EDITOR_SETUP';
export const LIST_CREATE_REQUEST = 'LIST_CREATE_REQUEST'; export const LIST_CREATE_REQUEST = 'LIST_CREATE_REQUEST';
export const LIST_CREATE_SUCCESS = 'LIST_CREATE_SUCCESS'; export const LIST_CREATE_SUCCESS = 'LIST_CREATE_SUCCESS';
@ -100,13 +101,14 @@ export const fetchListsFail = error => ({
}); });
export const submitListEditor = shouldReset => (dispatch, getState) => { export const submitListEditor = shouldReset => (dispatch, getState) => {
const listId = getState().getIn(['listEditor', 'listId']); const listId = getState().getIn(['listEditor', 'listId']);
const title = getState().getIn(['listEditor', 'title']); const title = getState().getIn(['listEditor', 'title']);
const isExclusive = getState().getIn(['listEditor', 'isExclusive']);
if (listId === null) { if (listId === null) {
dispatch(createList(title, shouldReset)); dispatch(createList(title, shouldReset));
} else { } else {
dispatch(updateList(listId, title, shouldReset)); dispatch(updateList(listId, title, shouldReset, isExclusive));
} }
}; };
@ -124,6 +126,11 @@ export const changeListEditorTitle = value => ({
value, value,
}); });
export const changeListEditorIsExclusive = value => ({
type: LIST_EDITOR_IS_EXCLUSIVE_CHANGE,
value,
});
export const createList = (title, shouldReset) => (dispatch, getState) => { export const createList = (title, shouldReset) => (dispatch, getState) => {
dispatch(createListRequest()); dispatch(createListRequest());
@ -150,10 +157,10 @@ export const createListFail = error => ({
error, error,
}); });
export const updateList = (id, title, shouldReset, replies_policy) => (dispatch, getState) => { export const updateList = (id, title, shouldReset, replies_policy, isExclusive) => (dispatch, getState) => {
dispatch(updateListRequest(id)); dispatch(updateListRequest(id));
api(getState).put(`/api/v1/lists/${id}`, { title, replies_policy }).then(({ data }) => { api(getState).put(`/api/v1/lists/${id}`, { title, replies_policy, is_exclusive: !!isExclusive }).then(({ data }) => {
dispatch(updateListSuccess(data)); dispatch(updateListSuccess(data));
if (shouldReset) { if (shouldReset) {

View File

@ -461,7 +461,7 @@ class Status extends ImmutablePureComponent {
return ( return (
<HotKeys handlers={handlers}> <HotKeys handlers={handlers}>
<div className={classNames('status__wrapper', `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), unread, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef}> <div className={classNames('status__wrapper', `status__wrapper-type-${status.get('activity_pub_type') || 'none'}` , `status__wrapper-${status.get('visibility')}`, { 'status__wrapper-reply': !!status.get('in_reply_to_id'), unread, focusable: !this.props.muted })} tabIndex={this.props.muted ? null : 0} data-featured={featured ? 'true' : null} aria-label={textForScreenReader(intl, status, rebloggedByText)} ref={this.handleRef}>
{prepend} {prepend}
<div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted })} data-id={status.get('id')}> <div className={classNames('status', `status-${status.get('visibility')}`, { 'status-reply': !!status.get('in_reply_to_id'), muted: this.props.muted })} data-id={status.get('id')}>

View File

@ -315,7 +315,7 @@ class StatusActionBar extends ImmutablePureComponent {
reblogTitle = intl.formatMessage(messages.cannot_reblog); reblogTitle = intl.formatMessage(messages.cannot_reblog);
} }
const shareButton = ('share' in navigator) && publicStatus && ( const shareButton = ('share' in navigator) && publicStatus && federated && (
<IconButton className='status__action-bar-button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} /> <IconButton className='status__action-bar-button' title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShareClick} />
); );
@ -326,6 +326,7 @@ class StatusActionBar extends ImmutablePureComponent {
<IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} /> <IconButton className='status__action-bar-button star-icon' animate active={status.get('favourited')} pressed={status.get('favourited')} title={intl.formatMessage(messages.favourite)} icon='star' onClick={this.handleFavouriteClick} />
{shareButton} {shareButton}
<IconButton className='status__action-bar-button bookmark-icon' disabled={anonymousAccess} active={status.get('bookmarked')} pressed={status.get('bookmarked')} title={intl.formatMessage(messages.bookmark)} icon='bookmark' onClick={this.handleBookmarkClick} />
<div className='status__action-bar-dropdown'> <div className='status__action-bar-dropdown'>
<DropdownMenuContainer <DropdownMenuContainer

View File

@ -203,6 +203,12 @@ export default class StatusContent extends React.PureComponent {
</button> </button>
); );
const readArticleButton = (
<button className='status__content__read-more-button' onClick={this.props.onClick} key='read-more'>
<FormattedMessage id='status.read_article' defaultMessage='Read article' /><Icon id='angle-right' fixedWidth />
</button>
);
if (status.get('spoiler_text').length > 0) { if (status.get('spoiler_text').length > 0) {
let mentionsPlaceholder = ''; let mentionsPlaceholder = '';
@ -218,12 +224,12 @@ export default class StatusContent extends React.PureComponent {
mentionsPlaceholder = <div>{mentionLinks}</div>; mentionsPlaceholder = <div>{mentionLinks}</div>;
} }
return ( const output = [
<div className={classNames} ref={this.setRef} tabIndex='0' onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}> <div className={classNames} ref={this.setRef} tabIndex='0' onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp}>
<p style={{ marginBottom: hidden && status.get('mentions').isEmpty() ? '0px' : null }}> <p style={{ marginBottom: hidden && status.get('mentions').isEmpty() ? '0px' : null }}>
<span dangerouslySetInnerHTML={spoilerContent} /> <span dangerouslySetInnerHTML={spoilerContent} />
{' '} {' '}
<button tabIndex='0' className={`status__content__spoiler-link ${hidden ? 'status__content__spoiler-link--show-more' : 'status__content__spoiler-link--show-less'}`} onClick={this.handleSpoilerClick}>{toggleText}</button> {status.get('activity_pub_type') === 'Article' ? '' : <span class="show_more_button"><button tabIndex='0' className={`status__content__spoiler-link ${hidden ? 'status__content__spoiler-link--show-more' : 'status__content__spoiler-link--show-less'}`} onClick={this.handleSpoilerClick}>{toggleText}</button></span>}
</p> </p>
{mentionsPlaceholder} {mentionsPlaceholder}
@ -231,10 +237,15 @@ export default class StatusContent extends React.PureComponent {
<div tabIndex={!hidden ? 0 : null} className={`status__content__text ${!hidden ? 'status__content__text--visible' : ''}`} dangerouslySetInnerHTML={content} /> <div tabIndex={!hidden ? 0 : null} className={`status__content__text ${!hidden ? 'status__content__text--visible' : ''}`} dangerouslySetInnerHTML={content} />
{!hidden && !!status.get('poll') && <PollContainer pollId={status.get('poll')} />} {!hidden && !!status.get('poll') && <PollContainer pollId={status.get('poll')} />}
{renderViewThread && showThreadButton} {renderViewThread && showThreadButton}
</div> </div>,
); ];
if (status.get('activity_pub_type') === 'Article' && !this.props.expanded) {
output.push(readArticleButton);
}
return output;
} else if (this.props.onClick) { } else if (this.props.onClick) {
const output = [ const output = [
<div className={classNames} ref={this.setRef} tabIndex='0' onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} key='status-content'> <div className={classNames} ref={this.setRef} tabIndex='0' onMouseDown={this.handleMouseDown} onMouseUp={this.handleMouseUp} key='status-content'>

View File

@ -38,7 +38,7 @@ const messages = defineMessages({
showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' }, showReblogs: { id: 'account.show_reblogs', defaultMessage: 'Show boosts from @{name}' },
enableNotifications: { id: 'account.enable_notifications', defaultMessage: 'Notify me when @{name} posts' }, enableNotifications: { id: 'account.enable_notifications', defaultMessage: 'Notify me when @{name} posts' },
disableNotifications: { id: 'account.disable_notifications', defaultMessage: 'Stop notifying me when @{name} posts' }, disableNotifications: { id: 'account.disable_notifications', defaultMessage: 'Stop notifying me when @{name} posts' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' }, pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' }, favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },

View File

@ -123,8 +123,8 @@ export default class Header extends ImmutablePureComponent {
{!hideTabs && ( {!hideTabs && (
<div className='account__section-headline'> <div className='account__section-headline'>
<NavLink exact to={`/accounts/${account.get('id')}`}><FormattedMessage id='account.posts' defaultMessage='Toots' /></NavLink> <NavLink exact to={`/accounts/${account.get('id')}`}><FormattedMessage id='account.posts' defaultMessage='Posts' /></NavLink>
<NavLink exact to={`/accounts/${account.get('id')}/with_replies`}><FormattedMessage id='account.posts_with_replies' defaultMessage='Toots and replies' /></NavLink> <NavLink exact to={`/accounts/${account.get('id')}/with_replies`}><FormattedMessage id='account.posts_with_replies' defaultMessage='Posts and replies' /></NavLink>
<NavLink exact to={`/accounts/${account.get('id')}/media`}><FormattedMessage id='account.media' defaultMessage='Media' /></NavLink> <NavLink exact to={`/accounts/${account.get('id')}/media`}><FormattedMessage id='account.media' defaultMessage='Media' /></NavLink>
</div> </div>
)} )}

View File

@ -37,7 +37,7 @@ const mapStateToProps = (state, { params: { accountId }, withReplies = false })
}; };
const RemoteHint = ({ url }) => ( const RemoteHint = ({ url }) => (
<TimelineHint url={url} resource={<FormattedMessage id='timeline_hint.resources.statuses' defaultMessage='Older toots' />} /> <TimelineHint url={url} resource={<FormattedMessage id='timeline_hint.resources.statuses' defaultMessage='Older posts' />} />
); );
RemoteHint.propTypes = { RemoteHint.propTypes = {
@ -143,7 +143,7 @@ class AccountTimeline extends ImmutablePureComponent {
} else if (remote && statusIds.isEmpty()) { } else if (remote && statusIds.isEmpty()) {
emptyMessage = <RemoteHint url={remoteUrl} />; emptyMessage = <RemoteHint url={remoteUrl} />;
} else { } else {
emptyMessage = <FormattedMessage id='empty_column.account_timeline' defaultMessage='No toots here!' />; emptyMessage = <FormattedMessage id='empty_column.account_timeline' defaultMessage='No posts here!' />;
} }
const remoteMessage = remote ? <RemoteHint url={remoteUrl} /> : null; const remoteMessage = remote ? <RemoteHint url={remoteUrl} /> : null;

View File

@ -6,7 +6,7 @@ import { defineMessages, injectIntl } from 'react-intl';
const messages = defineMessages({ const messages = defineMessages({
edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' }, edit_profile: { id: 'account.edit_profile', defaultMessage: 'Edit profile' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' }, pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' },
favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' }, favourites: { id: 'navigation_bar.favourites', defaultMessage: 'Favourites' },

View File

@ -21,13 +21,14 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { length } from 'stringz'; import { length } from 'stringz';
import { countableText } from '../util/counter'; import { countableText } from '../util/counter';
import Icon from 'mastodon/components/icon'; import Icon from 'mastodon/components/icon';
import { maxChars } from '../../../initial_state';
const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d'; const allowedAroundShortCode = '><\u0085\u0020\u00a0\u1680\u2000\u2001\u2002\u2003\u2004\u2005\u2006\u2007\u2008\u2009\u200a\u202f\u205f\u3000\u2028\u2029\u0009\u000a\u000b\u000c\u000d';
const messages = defineMessages({ const messages = defineMessages({
placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' }, placeholder: { id: 'compose_form.placeholder', defaultMessage: 'What is on your mind?' },
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' }, spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },
publish: { id: 'compose_form.publish', defaultMessage: 'Toot' }, publish: { id: 'compose_form.publish', defaultMessage: 'Post' },
publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}!' }, publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}!' },
}); });
@ -88,7 +89,7 @@ class ComposeForm extends ImmutablePureComponent {
const fulltext = this.getFulltextForCharacterCounting(); const fulltext = this.getFulltextForCharacterCounting();
const isOnlyWhitespace = fulltext.length !== 0 && fulltext.trim().length === 0; const isOnlyWhitespace = fulltext.length !== 0 && fulltext.trim().length === 0;
return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia)); return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > maxChars || (isOnlyWhitespace && !anyMedia));
} }
handleSubmit = () => { handleSubmit = () => {
@ -252,7 +253,7 @@ class ComposeForm extends ImmutablePureComponent {
<SpoilerButtonContainer /> <SpoilerButtonContainer />
<FederationDropdownContainer /> <FederationDropdownContainer />
</div> </div>
<div className='character-counter__wrapper'><CharacterCounter max={500} text={this.getFulltextForCharacterCounting()} /></div> <div className='character-counter__wrapper'><CharacterCounter max={maxChars} text={this.getFulltextForCharacterCounting()} /></div>
</div> </div>
<div className='compose-form__publish'> <div className='compose-form__publish'>

View File

@ -359,11 +359,11 @@ class EmojiPickerDropdown extends React.PureComponent {
return ( return (
<div className='emoji-picker-dropdown' onKeyDown={this.handleKeyDown}> <div className='emoji-picker-dropdown' onKeyDown={this.handleKeyDown}>
<div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}> <div ref={this.setTargetRef} className='emoji-button' title={title} aria-label={title} aria-expanded={active} role='button' onClick={this.onToggle} onKeyDown={this.onToggle} tabIndex={0}>
{button || <img <img
className={classNames('emojione', { 'pulse-loading': active && loading })} className={classNames('emojione', { 'pulse-loading': active && loading })}
alt='🙂' alt='🙂'
src={`${assetHost}/emoji/1f602.svg`} src={`${assetHost}/emoji/1f600.svg`}
/>} />
</div> </div>
<Overlay show={active} placement={placement} target={this.findTarget}> <Overlay show={active} placement={placement} target={this.findTarget}>

View File

@ -10,9 +10,9 @@ import classNames from 'classnames';
const messages = defineMessages({ const messages = defineMessages({
federate_short: { id: 'federation.federated.short', defaultMessage: 'Federated' }, federate_short: { id: 'federation.federated.short', defaultMessage: 'Federated' },
federate_long: { id: 'federation.federated.long', defaultMessage: 'Allow toot to reach other instances' }, federate_long: { id: 'federation.federated.long', defaultMessage: 'Allow post to reach other instances' },
local_only_short: { id: 'federation.local_only.short', defaultMessage: 'Local-only' }, local_only_short: { id: 'federation.local_only.short', defaultMessage: 'Local-only' },
local_only_long: { id: 'federation.local_only.long', defaultMessage: 'Restrict this toot only to my instance' }, local_only_long: { id: 'federation.local_only.long', defaultMessage: 'Restrict this post only to my instance' },
change_federation: { id: 'federation.change', defaultMessage: 'Adjust status federation' }, change_federation: { id: 'federation.change', defaultMessage: 'Adjust status federation' },
}); });

View File

@ -85,7 +85,7 @@ class SearchResults extends ImmutablePureComponent {
count += results.get('statuses').size; count += results.get('statuses').size;
statuses = ( statuses = (
<div className='search-results__section'> <div className='search-results__section'>
<h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5> <h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></h5>
{results.get('statuses').map(statusId => <StatusContainer key={statusId} id={statusId} />)} {results.get('statuses').map(statusId => <StatusContainer key={statusId} id={statusId} />)}
@ -95,10 +95,10 @@ class SearchResults extends ImmutablePureComponent {
} else if(results.get('statuses') && results.get('statuses').size === 0 && !searchEnabled && !(searchTerm.startsWith('@') || searchTerm.startsWith('#') || searchTerm.includes(' '))) { } else if(results.get('statuses') && results.get('statuses').size === 0 && !searchEnabled && !(searchTerm.startsWith('@') || searchTerm.startsWith('#') || searchTerm.includes(' '))) {
statuses = ( statuses = (
<div className='search-results__section'> <div className='search-results__section'>
<h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Toots' /></h5> <h5><Icon id='quote-right' fixedWidth /><FormattedMessage id='search_results.statuses' defaultMessage='Posts' /></h5>
<div className='search-results__info'> <div className='search-results__info'>
<FormattedMessage id='search_results.statuses_fts_disabled' defaultMessage='Searching toots by their content is not enabled on this Mastodon server.' /> <FormattedMessage id='search_results.statuses_fts_disabled' defaultMessage='Searching posts by their content is not enabled on this server.' />
</div> </div>
</div> </div>
); );

View File

@ -42,7 +42,7 @@ const WarningWrapper = ({ needsLockWarning, hashtagWarning, directMessageWarning
} }
if (hashtagWarning) { if (hashtagWarning) {
return <Warning message={<FormattedMessage id='compose_form.hashtag_warning' defaultMessage="This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag." />} />; return <Warning message={<FormattedMessage id='compose_form.hashtag_warning' defaultMessage="This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag." />} />;
} }
if (directMessageWarning) { if (directMessageWarning) {

View File

@ -26,7 +26,7 @@ const messages = defineMessages({
community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' }, community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' }, logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new toot' }, compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new post' },
logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' }, logoutMessage: { id: 'confirmations.logout.message', defaultMessage: 'Are you sure you want to log out?' },
logoutConfirm: { id: 'confirmations.logout.confirm', defaultMessage: 'Log out' }, logoutConfirm: { id: 'confirmations.logout.confirm', defaultMessage: 'Log out' },
}); });
@ -36,6 +36,25 @@ const mapStateToProps = (state, ownProps) => ({
showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : ownProps.isSearchPage, showSearch: ownProps.multiColumn ? state.getIn(['search', 'submitted']) && !state.getIn(['search', 'hidden']) : ownProps.isSearchPage,
}); });
let instanceMascot;
if (mascot) {
instanceMascot = <img alt='' draggable='false' src={mascot} />;
} else {
instanceMascot = <svg id='hometownlogo' width="2400" height="460" viewBox="0 0 2400 460" xmlns="http://www.w3.org/2000/svg" preserveAspectRatio="xMidYMid meet">
<g>
<g>
<path d="m326.20431,287.85649l-302.73044,0c-10.28698,0 -19.10436,8.81738 -19.10436,19.10436s8.81738,19.10436 19.10436,19.10436l302.73044,0c10.28698,0 19.10436,-8.81738 19.10436,-19.10436s-8.81738,-19.10436 -19.10436,-19.10436z"/>
<path d="m326.20431,351.04783l-302.73044,0c-10.28698,0 -19.10436,8.81738 -19.10436,19.10436s8.81738,19.10436 19.10436,19.10436l302.73044,0c10.28698,0 19.10436,-8.81738 19.10436,-19.10436s-8.81738,-19.10436 -19.10436,-19.10436z"/>
<path d="m326.20431,415.70867l-302.73044,0c-10.28698,0 -19.10436,8.81738 -19.10436,19.10436s8.81738,19.10436 19.10436,19.10436l302.73044,0c10.28698,0 19.10436,-8.81738 19.10436,-19.10436s-8.81738,-19.10436 -19.10436,-19.10436z"/>
<path d="m456.99565,287.85649c-10.28698,0 -19.10436,8.81738 -19.10436,19.10436l0,129.32173c0,10.28698 8.81738,19.10436 19.10436,19.10436s19.10436,-8.81738 19.10436,-19.10436l0,-129.32173c-1.46955,-11.75653 -10.28698,-19.10436 -19.10436,-19.10436z"/>
<path d="m392.33476,287.85649c-10.28698,0 -19.10436,8.81738 -19.10436,19.10436l0,129.32173c0,10.28698 8.81738,19.10436 19.10436,19.10436s19.10436,-8.81738 19.10436,-19.10436l0,-129.32173c-1.46955,-11.75653 -8.81738,-19.10436 -19.10436,-19.10436z"/>
<path d="m440.83045,205.56085c19.10436,-10.28698 29.39129,-36.73911 29.39129,-82.29564c0,-52.90436 -13.22609,-114.62609 -48.49564,-114.62609s-48.49564,61.72173 -48.49564,114.62609c0,45.55653 10.28698,72.00871 29.39129,82.29564l0,35.26955c0,10.28698 8.81738,19.10436 19.10436,19.10436s19.10436,-8.81738 19.10436,-19.10436l0,-35.26955l-0.00002,0zm-19.10436,-154.30436c5.87827,11.75653 11.75653,36.73911 11.75653,72.00871c0,36.73911 -7.34782,49.9652 -11.75653,49.9652s-11.75653,-13.22609 -11.75653,-49.9652c1.46955,-35.26955 7.34782,-60.25218 11.75653,-72.00871z"/>
<path d="m342.36956,123.26521c0,-1.46955 -1.46955,-1.46955 -1.46955,-2.93911l-47.02609,-60.25218c-2.93911,-4.40871 -8.81738,-7.34782 -14.69564,-7.34782l-23.51307,0l0,-27.92173c0,-10.28698 -8.81738,-19.10436 -19.10436,-19.10436s-19.10436,8.81738 -19.10436,19.10436l0,29.39129l-57.31307,0l-16.1652,0l-76.41738,0c-5.87827,0 -10.28698,2.93911 -14.69564,7.34782l-47.02609,60.25218c0,1.46955 -1.46955,1.46955 -1.46955,2.93911c0,0 -1.46955,1.46955 -1.46955,1.46955c1.46955,1.46955 1.46955,4.40871 1.46955,5.87827l0,108.74782c0,10.28698 8.81738,19.10436 19.10436,19.10436l76.41738,0l108.74782,0l117.56525,0c10.28698,0 19.10436,-8.81738 19.10436,-19.10436l0,-108.74782c0,-2.93911 0,-4.40871 -1.46955,-5.87827c-1.46955,-1.46955 -1.46955,-1.46955 -1.46955,-2.93911l-0.00005,0l-0.00002,0zm-224.84351,99.93045l-76.41738,0l0,-72.00871l149.89564,0l0,72.00871l-73.47827,0l0.00001,0zm99.93045,-108.74782l-17.6348,-23.51307l70.53916,0l17.6348,23.51307l-70.53916,0zm-64.66089,-23.51307l17.6348,23.51307l-110.21738,0l17.6348,-23.51307l74.94782,0l-0.00005,0l0.00001,0zm74.94782,60.25218l80.82609,0l0,72.00871l-80.82609,0l0,-72.00871z"/>
</g>
</g>
</svg>;
}
export default @connect(mapStateToProps) export default @connect(mapStateToProps)
@injectIntl @injectIntl
class Compose extends React.PureComponent { class Compose extends React.PureComponent {
@ -129,7 +148,7 @@ class Compose extends React.PureComponent {
<ComposeFormContainer /> <ComposeFormContainer />
<div className='drawer__inner__mastodon'> <div className='drawer__inner__mastodon'>
<img alt='' draggable='false' src={mascot || elephantUIPlane} /> {instanceMascot}
</div> </div>
</div>} </div>}

View File

@ -71,7 +71,7 @@ class Favourites extends ImmutablePureComponent {
const { intl, shouldUpdateScroll, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props; const { intl, shouldUpdateScroll, statusIds, columnId, multiColumn, hasMore, isLoading } = this.props;
const pinned = !!columnId; const pinned = !!columnId;
const emptyMessage = <FormattedMessage id='empty_column.favourited_statuses' defaultMessage="You don't have any favourite toots yet. When you favourite one, it will show up here." />; const emptyMessage = <FormattedMessage id='empty_column.favourited_statuses' defaultMessage="You don't have any favourite posts yet. When you favourite one, it will show up here." />;
return ( return (
<Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.heading)}> <Column bindToDocument={!multiColumn} ref={this.setRef} label={intl.formatMessage(messages.heading)}>

View File

@ -60,7 +60,7 @@ class Favourites extends ImmutablePureComponent {
); );
} }
const emptyMessage = <FormattedMessage id='empty_column.favourites' defaultMessage='No one has favourited this toot yet. When someone does, they will show up here.' />; const emptyMessage = <FormattedMessage id='empty_column.favourites' defaultMessage='No one has favourited this post yet. When someone does, they will show up here.' />;
return ( return (
<Column bindToDocument={!multiColumn}> <Column bindToDocument={!multiColumn}>

View File

@ -29,7 +29,7 @@ const messages = defineMessages({
blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' }, blocks: { id: 'navigation_bar.blocks', defaultMessage: 'Blocked users' },
domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' }, domain_blocks: { id: 'navigation_bar.domain_blocks', defaultMessage: 'Hidden domains' },
mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' }, mutes: { id: 'navigation_bar.mutes', defaultMessage: 'Muted users' },
pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned toots' }, pins: { id: 'navigation_bar.pins', defaultMessage: 'Pinned posts' },
lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' }, lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
discover: { id: 'navigation_bar.discover', defaultMessage: 'Discover' }, discover: { id: 'navigation_bar.discover', defaultMessage: 'Discover' },
personal: { id: 'navigation_bar.personal', defaultMessage: 'Personal' }, personal: { id: 'navigation_bar.personal', defaultMessage: 'Personal' },

View File

@ -75,22 +75,22 @@ const FrameInteractions = ({ onNext }) => (
<div className='introduction__text introduction__text--columnized'> <div className='introduction__text introduction__text--columnized'>
<div> <div>
<h3><FormattedMessage id='introduction.interactions.reply.headline' defaultMessage='Reply' /></h3> <h3><FormattedMessage id='introduction.interactions.reply.headline' defaultMessage='Reply' /></h3>
<p><FormattedMessage id='introduction.interactions.reply.text' defaultMessage="You can reply to other people's and your own toots, which will chain them together in a conversation." /></p> <p><FormattedMessage id='introduction.interactions.reply.text' defaultMessage="You can reply to other people's and your own posts, which will chain them together in a conversation." /></p>
</div> </div>
<div> <div>
<h3><FormattedMessage id='introduction.interactions.reblog.headline' defaultMessage='Boost' /></h3> <h3><FormattedMessage id='introduction.interactions.reblog.headline' defaultMessage='Boost' /></h3>
<p><FormattedMessage id='introduction.interactions.reblog.text' defaultMessage="You can share other people's toots with your followers by boosting them." /></p> <p><FormattedMessage id='introduction.interactions.reblog.text' defaultMessage="You can share other people's posts with your followers by boosting them." /></p>
</div> </div>
<div> <div>
<h3><FormattedMessage id='introduction.interactions.favourite.headline' defaultMessage='Favourite' /></h3> <h3><FormattedMessage id='introduction.interactions.favourite.headline' defaultMessage='Favourite' /></h3>
<p><FormattedMessage id='introduction.interactions.favourite.text' defaultMessage='You can save a toot for later, and let the author know that you liked it, by favouriting it.' /></p> <p><FormattedMessage id='introduction.interactions.favourite.text' defaultMessage='You can save a post for later, and let the author know that you liked it, by favouriting it.' /></p>
</div> </div>
</div> </div>
<div className='introduction__action'> <div className='introduction__action'>
<button className='button' onClick={onNext}><FormattedMessage id='introduction.interactions.action' defaultMessage='Finish toot-orial!' /></button> <button className='button' onClick={onNext}><FormattedMessage id='introduction.interactions.action' defaultMessage='Finish tutorial!' /></button>
</div> </div>
</div> </div>
); );

View File

@ -86,7 +86,7 @@ class KeyboardShortcuts extends ImmutablePureComponent {
</tr> </tr>
<tr> <tr>
<td><kbd>alt</kbd>+<kbd>n</kbd></td> <td><kbd>alt</kbd>+<kbd>n</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.toot' defaultMessage='to start a brand new toot' /></td> <td><FormattedMessage id='keyboard_shortcuts.toot' defaultMessage='to start a brand new post' /></td>
</tr> </tr>
<tr> <tr>
<td><kbd>alt</kbd>+<kbd>x</kbd></td> <td><kbd>alt</kbd>+<kbd>x</kbd></td>
@ -134,7 +134,7 @@ class KeyboardShortcuts extends ImmutablePureComponent {
</tr> </tr>
<tr> <tr>
<td><kbd>g</kbd>+<kbd>p</kbd></td> <td><kbd>g</kbd>+<kbd>p</kbd></td>
<td><FormattedMessage id='keyboard_shortcuts.pinned' defaultMessage='to open pinned toots list' /></td> <td><FormattedMessage id='keyboard_shortcuts.pinned' defaultMessage='to open pinned posts list' /></td>
</tr> </tr>
<tr> <tr>
<td><kbd>g</kbd>+<kbd>u</kbd></td> <td><kbd>g</kbd>+<kbd>u</kbd></td>

View File

@ -1,9 +1,10 @@
import React from 'react'; import React from 'react';
import { connect } from 'react-redux'; import { connect } from 'react-redux';
import PropTypes from 'prop-types'; import PropTypes from 'prop-types';
import { changeListEditorTitle, submitListEditor } from '../../../actions/lists'; import { changeListEditorTitle, changeListEditorIsExclusive, submitListEditor } from '../../../actions/lists';
import IconButton from '../../../components/icon_button'; import IconButton from '../../../components/icon_button';
import { defineMessages, injectIntl } from 'react-intl'; import { FormattedMessage, defineMessages, injectIntl } from 'react-intl';
import Toggle from 'react-toggle';
const messages = defineMessages({ const messages = defineMessages({
title: { id: 'lists.edit.submit', defaultMessage: 'Change title' }, title: { id: 'lists.edit.submit', defaultMessage: 'Change title' },
@ -17,6 +18,7 @@ const mapStateToProps = state => ({
const mapDispatchToProps = dispatch => ({ const mapDispatchToProps = dispatch => ({
onChange: value => dispatch(changeListEditorTitle(value)), onChange: value => dispatch(changeListEditorTitle(value)),
onSubmit: () => dispatch(submitListEditor(false)), onSubmit: () => dispatch(submitListEditor(false)),
onToggle: value => dispatch(changeListEditorIsExclusive(value)),
}); });
export default @connect(mapStateToProps, mapDispatchToProps) export default @connect(mapStateToProps, mapDispatchToProps)
@ -26,6 +28,7 @@ class ListForm extends React.PureComponent {
static propTypes = { static propTypes = {
value: PropTypes.string.isRequired, value: PropTypes.string.isRequired,
disabled: PropTypes.bool, disabled: PropTypes.bool,
isExclusive: PropTypes.bool,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
onChange: PropTypes.func.isRequired, onChange: PropTypes.func.isRequired,
onSubmit: PropTypes.func.isRequired, onSubmit: PropTypes.func.isRequired,
@ -44,8 +47,12 @@ class ListForm extends React.PureComponent {
this.props.onSubmit(); this.props.onSubmit();
} }
handleToggle = e => {
this.props.onToggle(e.target.checked);
}
render () { render () {
const { value, disabled, intl } = this.props; const { value, disabled, intl, isExclusive, hello } = this.props;
const title = intl.formatMessage(messages.title); const title = intl.formatMessage(messages.title);
@ -57,6 +64,11 @@ class ListForm extends React.PureComponent {
onChange={this.handleChange} onChange={this.handleChange}
/> />
<label htmlFor='is-exclusive-checkbox'>
<Toggle className='is-exclusive-checkbox' defaultChecked={isExclusive} onChange={this.handleToggle}/>
<FormattedMessage id='lists.is-exclusive' defaultMessage='Exclusive?' />
</label>
<IconButton <IconButton
disabled={disabled} disabled={disabled}
icon='check' icon='check'

View File

@ -28,6 +28,7 @@ class ListEditor extends ImmutablePureComponent {
static propTypes = { static propTypes = {
listId: PropTypes.string.isRequired, listId: PropTypes.string.isRequired,
isExclusive: PropTypes.bool.isRequired,
onClose: PropTypes.func.isRequired, onClose: PropTypes.func.isRequired,
intl: PropTypes.object.isRequired, intl: PropTypes.object.isRequired,
onInitialize: PropTypes.func.isRequired, onInitialize: PropTypes.func.isRequired,
@ -53,7 +54,7 @@ class ListEditor extends ImmutablePureComponent {
return ( return (
<div className='modal-root__modal list-editor'> <div className='modal-root__modal list-editor'>
<EditListForm /> <EditListForm isExclusive={this.props.isExclusive} />
<Search /> <Search />

View File

@ -113,7 +113,7 @@ class ListTimeline extends React.PureComponent {
} }
handleEditClick = () => { handleEditClick = () => {
this.props.dispatch(openModal('LIST_EDITOR', { listId: this.props.params.id })); this.props.dispatch(openModal('LIST_EDITOR', { listId: this.props.params.id, isExclusive: this.props.list.get('is_exclusive') }));
} }
handleDeleteClick = () => { handleDeleteClick = () => {

View File

@ -10,7 +10,7 @@ import { defineMessages, injectIntl } from 'react-intl';
import ImmutablePureComponent from 'react-immutable-pure-component'; import ImmutablePureComponent from 'react-immutable-pure-component';
const messages = defineMessages({ const messages = defineMessages({
heading: { id: 'column.pins', defaultMessage: 'Pinned toot' }, heading: { id: 'column.pins', defaultMessage: 'Pinned post' },
}); });
const mapStateToProps = state => ({ const mapStateToProps = state => ({

View File

@ -60,7 +60,7 @@ class Reblogs extends ImmutablePureComponent {
); );
} }
const emptyMessage = <FormattedMessage id='status.reblogs.empty' defaultMessage='No one has boosted this toot yet. When someone does, they will show up here.' />; const emptyMessage = <FormattedMessage id='status.reblogs.empty' defaultMessage='No one has boosted this post yet. When someone does, they will show up here.' />;
return ( return (
<Column bindToDocument={!multiColumn}> <Column bindToDocument={!multiColumn}>

View File

@ -18,6 +18,7 @@ const messages = defineMessages({
reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost with original visibility' }, reblog_private: { id: 'status.reblog_private', defaultMessage: 'Boost with original visibility' },
cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' }, cancel_reblog_private: { id: 'status.cancel_reblog_private', defaultMessage: 'Unboost' },
cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' }, cannot_reblog: { id: 'status.cannot_reblog', defaultMessage: 'This post cannot be boosted' },
local_only: { id: 'status.local_only', defaultMessage: 'This post is only visible by other users of your instance' },
favourite: { id: 'status.favourite', defaultMessage: 'Favourite' }, favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' }, bookmark: { id: 'status.bookmark', defaultMessage: 'Bookmark' },
more: { id: 'status.more', defaultMessage: 'More' }, more: { id: 'status.more', defaultMessage: 'More' },
@ -189,6 +190,7 @@ class ActionBar extends React.PureComponent {
const publicStatus = ['public', 'unlisted'].includes(status.get('visibility')); const publicStatus = ['public', 'unlisted'].includes(status.get('visibility'));
const mutingConversation = status.get('muted'); const mutingConversation = status.get('muted');
const federated = !status.get('local_only');
const account = status.get('account'); const account = status.get('account');
let menu = []; let menu = [];
@ -247,7 +249,7 @@ class ActionBar extends React.PureComponent {
} }
} }
const shareButton = ('share' in navigator) && publicStatus && ( const shareButton = ('share' in navigator) && publicStatus && federated && (
<div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShare} /></div> <div className='detailed-status__button'><IconButton title={intl.formatMessage(messages.share)} icon='share-alt' onClick={this.handleShare} /></div>
); );

View File

@ -251,7 +251,7 @@ class DetailedStatus extends ImmutablePureComponent {
<DisplayName account={status.get('account')} localDomain={this.props.domain} /> <DisplayName account={status.get('account')} localDomain={this.props.domain} />
</a> </a>
<StatusContent status={status} expanded={!status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} /> <StatusContent status={status} expanded={status.get('activity_pub_type') === 'Article' || !status.get('hidden')} onExpandedToggle={this.handleExpandedToggle} />
{media} {media}

View File

@ -50,7 +50,7 @@ const componentMap = {
}; };
const messages = defineMessages({ const messages = defineMessages({
publish: { id: 'compose_form.publish', defaultMessage: 'Toot' }, publish: { id: 'compose_form.publish', defaultMessage: 'Post' },
}); });
const shouldHideFAB = path => path.match(/^\/statuses\/|^\/search|^\/getting-started/); const shouldHideFAB = path => path.match(/^\/statuses\/|^\/search|^\/getting-started/);

View File

@ -64,6 +64,11 @@ class LinkFooter extends React.PureComponent {
defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.' defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.'
values={{ github: <span><a href={source_url} rel='noopener noreferrer' target='_blank'>{repository}</a> (v{version})</span> }} values={{ github: <span><a href={source_url} rel='noopener noreferrer' target='_blank'>{repository}</a> (v{version})</span> }}
/> />
<FormattedMessage
id='getting_started.hometown_open_source_notice'
defaultMessage='Hometown is also open source, at {hometown} (v1.0.5).'
values={{ hometown: <span><a href='https://github.com/hometown-fork/hometown' rel='noopener' target='_blank'>hometown-fork/hometown</a></span> }}
/>
</p> </p>
</div> </div>
); );

View File

@ -61,7 +61,7 @@ import { previewState as previewVideoState } from './components/video_modal';
import '../../components/status'; import '../../components/status';
const messages = defineMessages({ const messages = defineMessages({
beforeUnload: { id: 'ui.beforeunload', defaultMessage: 'Your draft will be lost if you leave Mastodon.' }, beforeUnload: { id: 'ui.beforeunload', defaultMessage: 'Your draft will be lost if you leave.' },
}); });
const mapStateToProps = state => ({ const mapStateToProps = state => ({

View File

@ -12,6 +12,7 @@ export const boostModal = getMeta('boost_modal');
export const deleteModal = getMeta('delete_modal'); export const deleteModal = getMeta('delete_modal');
export const me = getMeta('me'); export const me = getMeta('me');
export const searchEnabled = getMeta('search_enabled'); export const searchEnabled = getMeta('search_enabled');
export const maxChars = (initialState && initialState.max_toot_chars) || 500;
export const invitesEnabled = getMeta('invites_enabled'); export const invitesEnabled = getMeta('invites_enabled');
export const repository = getMeta('repository'); export const repository = getMeta('repository');
export const source_url = getMeta('source_url'); export const source_url = getMeta('source_url');

View File

@ -86,7 +86,7 @@
"community.column_settings.remote_only": "Remote only", "community.column_settings.remote_only": "Remote only",
"compose_form.direct_message_warning": "Esti barritu namái va unviase a los usuarios mentaos.", "compose_form.direct_message_warning": "Esti barritu namái va unviase a los usuarios mentaos.",
"compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.",
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
"compose_form.lock_disclaimer.lock": "locked", "compose_form.lock_disclaimer.lock": "locked",
"compose_form.placeholder": "¿En qué pienses?", "compose_form.placeholder": "¿En qué pienses?",
@ -219,7 +219,7 @@
"introduction.interactions.favourite.headline": "Favourite", "introduction.interactions.favourite.headline": "Favourite",
"introduction.interactions.favourite.text": "Pues guardar un barritu pa dempués y facer que l'autor sepa que te prestó marcándolu como favoritu.", "introduction.interactions.favourite.text": "Pues guardar un barritu pa dempués y facer que l'autor sepa que te prestó marcándolu como favoritu.",
"introduction.interactions.reblog.headline": "Boost", "introduction.interactions.reblog.headline": "Boost",
"introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", "introduction.interactions.reblog.text": "You can share other people's posts with your followers by boosting them.",
"introduction.interactions.reply.headline": "Reply", "introduction.interactions.reply.headline": "Reply",
"introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", "introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.",
"introduction.welcome.action": "¡Vamos!", "introduction.welcome.action": "¡Vamos!",

View File

@ -86,7 +86,7 @@
"community.column_settings.remote_only": "Remote only", "community.column_settings.remote_only": "Remote only",
"compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.", "compose_form.direct_message_warning": "This toot will only be visible to all the mentioned users.",
"compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", "compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.",
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
"compose_form.lock_disclaimer.lock": "locked", "compose_form.lock_disclaimer.lock": "locked",
"compose_form.placeholder": "Какво си мислиш?", "compose_form.placeholder": "Какво си мислиш?",
@ -157,8 +157,8 @@
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
"empty_column.domain_blocks": "There are no hidden domains yet.", "empty_column.domain_blocks": "There are no hidden domains yet.",
"empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", "empty_column.favourited_statuses": "You don't have any favourite posts yet. When you favourite one, it will show up here.",
"empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", "empty_column.favourites": "No one has favourited this post yet. When someone does, they will show up here.",
"empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
"empty_column.hashtag": "There is nothing in this hashtag yet.", "empty_column.hashtag": "There is nothing in this hashtag yet.",
"empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.",
@ -219,12 +219,12 @@
"introduction.interactions.favourite.headline": "Favourite", "introduction.interactions.favourite.headline": "Favourite",
"introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", "introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.",
"introduction.interactions.reblog.headline": "Boost", "introduction.interactions.reblog.headline": "Boost",
"introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", "introduction.interactions.reblog.text": "You can share other people's posts with your followers by boosting them.",
"introduction.interactions.reply.headline": "Reply", "introduction.interactions.reply.headline": "Reply",
"introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", "introduction.interactions.reply.text": "You can reply to other people's and your own posts, which will chain them together in a conversation.",
"introduction.welcome.action": "Let's go!", "introduction.welcome.action": "Let's go!",
"introduction.welcome.headline": "First steps", "introduction.welcome.headline": "First steps",
"introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.", "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special it hosts your profile, so remember its name.",
"keyboard_shortcuts.back": "to navigate back", "keyboard_shortcuts.back": "to navigate back",
"keyboard_shortcuts.blocked": "to open blocked users list", "keyboard_shortcuts.blocked": "to open blocked users list",
"keyboard_shortcuts.boost": "to boost", "keyboard_shortcuts.boost": "to boost",
@ -247,7 +247,7 @@
"keyboard_shortcuts.my_profile": "to open your profile", "keyboard_shortcuts.my_profile": "to open your profile",
"keyboard_shortcuts.notifications": "to open notifications column", "keyboard_shortcuts.notifications": "to open notifications column",
"keyboard_shortcuts.open_media": "to open media", "keyboard_shortcuts.open_media": "to open media",
"keyboard_shortcuts.pinned": "to open pinned toots list", "keyboard_shortcuts.pinned": "to open pinned posts list",
"keyboard_shortcuts.profile": "to open author's profile", "keyboard_shortcuts.profile": "to open author's profile",
"keyboard_shortcuts.reply": "to reply", "keyboard_shortcuts.reply": "to reply",
"keyboard_shortcuts.requests": "to open follow requests list", "keyboard_shortcuts.requests": "to open follow requests list",
@ -304,7 +304,7 @@
"navigation_bar.logout": "Излизане", "navigation_bar.logout": "Излизане",
"navigation_bar.mutes": "Muted users", "navigation_bar.mutes": "Muted users",
"navigation_bar.personal": "Personal", "navigation_bar.personal": "Personal",
"navigation_bar.pins": "Pinned toots", "navigation_bar.pins": "Pinned posts",
"navigation_bar.preferences": "Предпочитания", "navigation_bar.preferences": "Предпочитания",
"navigation_bar.public_timeline": "Публичен канал", "navigation_bar.public_timeline": "Публичен канал",
"navigation_bar.security": "Security", "navigation_bar.security": "Security",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.", "error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.",
"errors.unexpected_crash.copy_stacktrace": "স্টেকট্রেস ক্লিপবোর্ডে কপি করুন", "errors.unexpected_crash.copy_stacktrace": "স্টেকট্রেস ক্লিপবোর্ডে কপি করুন",
"errors.unexpected_crash.report_issue": "সমস্যার প্রতিবেদন করুন", "errors.unexpected_crash.report_issue": "সমস্যার প্রতিবেদন করুন",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "অনুমতি দিন", "follow_request.authorize": "অনুমতি দিন",
"follow_request.reject": "প্রত্যাখ্যান করুন", "follow_request.reject": "প্রত্যাখ্যান করুন",
"follow_requests.unlocked_explanation": "আপনার অ্যাকাউন্টটি লক না থাকলেও, {domain} কর্মীরা ভেবেছিলেন যে আপনি এই অ্যাকাউন্টগুলি থেকে ম্যানুয়ালি অনুসরণের অনুরোধগুলি পর্যালোচনা করতে চাইতে পারেন।", "follow_requests.unlocked_explanation": "আপনার অ্যাকাউন্টটি লক না থাকলেও, {domain} কর্মীরা ভেবেছিলেন যে আপনি এই অ্যাকাউন্টগুলি থেকে ম্যানুয়ালি অনুসরণের অনুরোধগুলি পর্যালোচনা করতে চাইতে পারেন।",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.", "error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.",
"errors.unexpected_crash.copy_stacktrace": "Copïo'r olrhain stac i'r clipfwrdd", "errors.unexpected_crash.copy_stacktrace": "Copïo'r olrhain stac i'r clipfwrdd",
"errors.unexpected_crash.report_issue": "Rhoi gwybod am broblem", "errors.unexpected_crash.report_issue": "Rhoi gwybod am broblem",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Caniatau", "follow_request.authorize": "Caniatau",
"follow_request.reject": "Gwrthod", "follow_request.reject": "Gwrthod",
"follow_requests.unlocked_explanation": "Er nid yw eich cyfrif wedi'i gloi, oedd y staff {domain} yn meddwl efallai hoffech adolygu ceisiadau dilyn o'r cyfrifau rhain wrth law.", "follow_requests.unlocked_explanation": "Er nid yw eich cyfrif wedi'i gloi, oedd y staff {domain} yn meddwl efallai hoffech adolygu ceisiadau dilyn o'r cyfrifau rhain wrth law.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.", "error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.",
"errors.unexpected_crash.copy_stacktrace": "Kopiér stack trace til udklipsholderen", "errors.unexpected_crash.copy_stacktrace": "Kopiér stack trace til udklipsholderen",
"errors.unexpected_crash.report_issue": "Rapportér problem", "errors.unexpected_crash.report_issue": "Rapportér problem",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Godkend", "follow_request.authorize": "Godkend",
"follow_request.reject": "Afvis", "follow_request.reject": "Afvis",
"follow_requests.unlocked_explanation": "Selvom din konto ikke er låst, troede {domain} -personalet, at du måske vil gennemgå dine anmodninger manuelt.", "follow_requests.unlocked_explanation": "Selvom din konto ikke er låst, troede {domain} -personalet, at du måske vil gennemgå dine anmodninger manuelt.",

View File

@ -568,7 +568,7 @@
"id": "status.filtered" "id": "status.filtered"
}, },
{ {
"defaultMessage": "Pinned toot", "defaultMessage": "Pinned post",
"id": "status.pinned" "id": "status.pinned"
}, },
{ {
@ -670,11 +670,11 @@
{ {
"descriptors": [ "descriptors": [
{ {
"defaultMessage": "Toots", "defaultMessage": "Posts",
"id": "account.posts" "id": "account.posts"
}, },
{ {
"defaultMessage": "Toots and replies", "defaultMessage": "Posts and replies",
"id": "account.posts_with_replies" "id": "account.posts_with_replies"
}, },
{ {
@ -729,7 +729,7 @@
"id": "empty_column.account_unavailable" "id": "empty_column.account_unavailable"
}, },
{ {
"defaultMessage": "No toots here!", "defaultMessage": "No posts here!",
"id": "empty_column.account_timeline" "id": "empty_column.account_timeline"
} }
], ],
@ -843,7 +843,7 @@
"id": "account.disable_notifications" "id": "account.disable_notifications"
}, },
{ {
"defaultMessage": "Pinned toots", "defaultMessage": "Pinned posts",
"id": "navigation_bar.pins" "id": "navigation_bar.pins"
}, },
{ {
@ -997,7 +997,7 @@
"id": "account.edit_profile" "id": "account.edit_profile"
}, },
{ {
"defaultMessage": "Pinned toots", "defaultMessage": "Pinned posts",
"id": "navigation_bar.pins" "id": "navigation_bar.pins"
}, },
{ {
@ -1054,7 +1054,7 @@
"id": "compose_form.spoiler_placeholder" "id": "compose_form.spoiler_placeholder"
}, },
{ {
"defaultMessage": "Toot", "defaultMessage": "Post",
"id": "compose_form.publish" "id": "compose_form.publish"
}, },
{ {
@ -1132,7 +1132,7 @@
"id": "federation.federated.short" "id": "federation.federated.short"
}, },
{ {
"defaultMessage": "Allow toot to reach other instances", "defaultMessage": "Allow post to reach other instances",
"id": "federation.federated.long" "id": "federation.federated.long"
}, },
{ {
@ -1140,7 +1140,7 @@
"id": "federation.local_only.short" "id": "federation.local_only.short"
}, },
{ {
"defaultMessage": "Restrict this toot only to my instance", "defaultMessage": "Restrict this post only to my instance",
"id": "federation.local_only.long" "id": "federation.local_only.long"
}, },
{ {
@ -1278,7 +1278,7 @@
"id": "search_results.accounts" "id": "search_results.accounts"
}, },
{ {
"defaultMessage": "Toots", "defaultMessage": "Posts",
"id": "search_results.statuses" "id": "search_results.statuses"
}, },
{ {
@ -1414,11 +1414,11 @@
"id": "compose_form.lock_disclaimer.lock" "id": "compose_form.lock_disclaimer.lock"
}, },
{ {
"defaultMessage": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", "defaultMessage": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.",
"id": "compose_form.hashtag_warning" "id": "compose_form.hashtag_warning"
}, },
{ {
"defaultMessage": "This toot will only be sent to all the mentioned users.", "defaultMessage": "This post will only be sent to all the mentioned users.",
"id": "compose_form.direct_message_warning" "id": "compose_form.direct_message_warning"
}, },
{ {
@ -1459,7 +1459,7 @@
"id": "navigation_bar.logout" "id": "navigation_bar.logout"
}, },
{ {
"defaultMessage": "Compose new toot", "defaultMessage": "Compose new post",
"id": "navigation_bar.compose" "id": "navigation_bar.compose"
}, },
{ {
@ -1634,7 +1634,7 @@
"id": "column.favourites" "id": "column.favourites"
}, },
{ {
"defaultMessage": "You don't have any favourite toots yet. When you favourite one, it will show up here.", "defaultMessage": "You don't have any favourite posts yet. When you favourite one, it will show up here.",
"id": "empty_column.favourited_statuses" "id": "empty_column.favourited_statuses"
} }
], ],
@ -1802,7 +1802,7 @@
"id": "navigation_bar.mutes" "id": "navigation_bar.mutes"
}, },
{ {
"defaultMessage": "Pinned toots", "defaultMessage": "Pinned posts",
"id": "navigation_bar.pins" "id": "navigation_bar.pins"
}, },
{ {
@ -1975,7 +1975,7 @@
"id": "introduction.interactions.reply.headline" "id": "introduction.interactions.reply.headline"
}, },
{ {
"defaultMessage": "You can reply to other people's and your own toots, which will chain them together in a conversation.", "defaultMessage": "You can reply to other people's and your own posts, which will chain them together in a conversation.",
"id": "introduction.interactions.reply.text" "id": "introduction.interactions.reply.text"
}, },
{ {
@ -1983,7 +1983,7 @@
"id": "introduction.interactions.reblog.headline" "id": "introduction.interactions.reblog.headline"
}, },
{ {
"defaultMessage": "You can share other people's toots with your followers by boosting them.", "defaultMessage": "You can share other people's posts with your followers by boosting them.",
"id": "introduction.interactions.reblog.text" "id": "introduction.interactions.reblog.text"
}, },
{ {
@ -1991,11 +1991,11 @@
"id": "introduction.interactions.favourite.headline" "id": "introduction.interactions.favourite.headline"
}, },
{ {
"defaultMessage": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", "defaultMessage": "You can save a post for later, and let the author know that you liked it, by favouriting it.",
"id": "introduction.interactions.favourite.text" "id": "introduction.interactions.favourite.text"
}, },
{ {
"defaultMessage": "Finish toot-orial!", "defaultMessage": "Finish tutorial!",
"id": "introduction.interactions.action" "id": "introduction.interactions.action"
} }
], ],
@ -2068,7 +2068,7 @@
"id": "keyboard_shortcuts.compose" "id": "keyboard_shortcuts.compose"
}, },
{ {
"defaultMessage": "to start a brand new toot", "defaultMessage": "to start a brand new post",
"id": "keyboard_shortcuts.toot" "id": "keyboard_shortcuts.toot"
}, },
{ {
@ -2116,7 +2116,7 @@
"id": "keyboard_shortcuts.favourites" "id": "keyboard_shortcuts.favourites"
}, },
{ {
"defaultMessage": "to open pinned toots list", "defaultMessage": "to open pinned posts list",
"id": "keyboard_shortcuts.pinned" "id": "keyboard_shortcuts.pinned"
}, },
{ {
@ -2548,7 +2548,7 @@
{ {
"descriptors": [ "descriptors": [
{ {
"defaultMessage": "Pinned toot", "defaultMessage": "Pinned post",
"id": "column.pins" "id": "column.pins"
} }
], ],
@ -2587,7 +2587,7 @@
"id": "refresh" "id": "refresh"
}, },
{ {
"defaultMessage": "No one has boosted this toot yet. When someone does, they will show up here.", "defaultMessage": "No one has boosted this post yet. When someone does, they will show up here.",
"id": "status.reblogs.empty" "id": "status.reblogs.empty"
} }
], ],
@ -2712,6 +2712,10 @@
}, },
{ {
"descriptors": [ "descriptors": [
{
"defaultMessage": "This post is only visible by other users of your instance",
"id": "status.local_only"
},
{ {
"defaultMessage": "Sensitive content", "defaultMessage": "Sensitive content",
"id": "status.sensitive_warning" "id": "status.sensitive_warning"
@ -2913,7 +2917,7 @@
{ {
"descriptors": [ "descriptors": [
{ {
"defaultMessage": "Toot", "defaultMessage": "Post",
"id": "compose_form.publish" "id": "compose_form.publish"
} }
], ],

View File

@ -32,13 +32,13 @@
"account.mute_notifications": "Mute notifications from @{name}", "account.mute_notifications": "Mute notifications from @{name}",
"account.muted": "Muted", "account.muted": "Muted",
"account.never_active": "Never", "account.never_active": "Never",
"account.posts": "Toots", "account.posts": "Posts",
"account.posts_with_replies": "Toots and replies", "account.posts_with_replies": "Posts and replies",
"account.report": "Report @{name}", "account.report": "Report @{name}",
"account.requested": "Awaiting approval. Click to cancel follow request", "account.requested": "Awaiting approval. Click to cancel follow request",
"account.share": "Share @{name}'s profile", "account.share": "Share @{name}'s profile",
"account.show_reblogs": "Show boosts from @{name}", "account.show_reblogs": "Show boosts from @{name}",
"account.statuses_counter": "{count, plural, one {{counter} Toot} other {{counter} Toots}}", "account.statuses_counter": "{count, plural, one {{counter} Post} other {{counter} Posts}}",
"account.unblock": "Unblock @{name}", "account.unblock": "Unblock @{name}",
"account.unblock_domain": "Unblock domain {domain}", "account.unblock_domain": "Unblock domain {domain}",
"account.unendorse": "Don't feature on profile", "account.unendorse": "Don't feature on profile",
@ -71,7 +71,7 @@
"column.lists": "Lists", "column.lists": "Lists",
"column.mutes": "Muted users", "column.mutes": "Muted users",
"column.notifications": "Notifications", "column.notifications": "Notifications",
"column.pins": "Pinned toots", "column.pins": "Pinned posts",
"column.public": "Federated timeline", "column.public": "Federated timeline",
"column_back_button.label": "Back", "column_back_button.label": "Back",
"column_header.hide_settings": "Hide settings", "column_header.hide_settings": "Hide settings",
@ -84,9 +84,9 @@
"community.column_settings.local_only": "Local only", "community.column_settings.local_only": "Local only",
"community.column_settings.media_only": "Media Only", "community.column_settings.media_only": "Media Only",
"community.column_settings.remote_only": "Remote only", "community.column_settings.remote_only": "Remote only",
"compose_form.direct_message_warning": "This toot will only be sent to the mentioned users.", "compose_form.direct_message_warning": "This post will only be sent to the mentioned users.",
"compose_form.direct_message_warning_learn_more": "Learn more", "compose_form.direct_message_warning_learn_more": "Learn more",
"compose_form.hashtag_warning": "This toot won't be listed under any hashtag as it is unlisted. Only public toots can be searched by hashtag.", "compose_form.hashtag_warning": "This post won't be listed under any hashtag as it is unlisted. Only public posts can be searched by hashtag.",
"compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.", "compose_form.lock_disclaimer": "Your account is not {locked}. Anyone can follow you to view your follower-only posts.",
"compose_form.lock_disclaimer.lock": "locked", "compose_form.lock_disclaimer.lock": "locked",
"compose_form.placeholder": "What's on your mind?", "compose_form.placeholder": "What's on your mind?",
@ -96,7 +96,7 @@
"compose_form.poll.remove_option": "Remove this choice", "compose_form.poll.remove_option": "Remove this choice",
"compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices", "compose_form.poll.switch_to_multiple": "Change poll to allow multiple choices",
"compose_form.poll.switch_to_single": "Change poll to allow for a single choice", "compose_form.poll.switch_to_single": "Change poll to allow for a single choice",
"compose_form.publish": "Toot", "compose_form.publish": "Post",
"compose_form.publish_loud": "{publish}!", "compose_form.publish_loud": "{publish}!",
"compose_form.sensitive.hide": "{count, plural, one {Mark media as sensitive} other {Mark media as sensitive}}", "compose_form.sensitive.hide": "{count, plural, one {Mark media as sensitive} other {Mark media as sensitive}}",
"compose_form.sensitive.marked": "{count, plural, one {Media is marked as sensitive} other {Media is marked as sensitive}}", "compose_form.sensitive.marked": "{count, plural, one {Media is marked as sensitive} other {Media is marked as sensitive}}",
@ -109,7 +109,7 @@
"confirmations.block.confirm": "Block", "confirmations.block.confirm": "Block",
"confirmations.block.message": "Are you sure you want to block {name}?", "confirmations.block.message": "Are you sure you want to block {name}?",
"confirmations.delete.confirm": "Delete", "confirmations.delete.confirm": "Delete",
"confirmations.delete.message": "Are you sure you want to delete this toot?", "confirmations.delete.message": "Are you sure you want to delete this post?",
"confirmations.delete_list.confirm": "Delete", "confirmations.delete_list.confirm": "Delete",
"confirmations.delete_list.message": "Are you sure you want to permanently delete this list?", "confirmations.delete_list.message": "Are you sure you want to permanently delete this list?",
"confirmations.domain_block.confirm": "Block entire domain", "confirmations.domain_block.confirm": "Block entire domain",
@ -120,7 +120,7 @@
"confirmations.mute.explanation": "This will hide posts from them and posts mentioning them, but it will still allow them to see your posts and follow you.", "confirmations.mute.explanation": "This will hide posts from them and posts mentioning them, but it will still allow them to see your posts and follow you.",
"confirmations.mute.message": "Are you sure you want to mute {name}?", "confirmations.mute.message": "Are you sure you want to mute {name}?",
"confirmations.redraft.confirm": "Delete & redraft", "confirmations.redraft.confirm": "Delete & redraft",
"confirmations.redraft.message": "Are you sure you want to delete this toot and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.", "confirmations.redraft.message": "Are you sure you want to delete this post and re-draft it? Favourites and boosts will be lost, and replies to the original post will be orphaned.",
"confirmations.reply.confirm": "Reply", "confirmations.reply.confirm": "Reply",
"confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?", "confirmations.reply.message": "Replying now will overwrite the message you are currently composing. Are you sure you want to proceed?",
"confirmations.unfollow.confirm": "Unfollow", "confirmations.unfollow.confirm": "Unfollow",
@ -133,7 +133,7 @@
"directory.local": "From {domain} only", "directory.local": "From {domain} only",
"directory.new_arrivals": "New arrivals", "directory.new_arrivals": "New arrivals",
"directory.recently_active": "Recently active", "directory.recently_active": "Recently active",
"embed.instructions": "Embed this toot 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",
"emoji_button.custom": "Custom", "emoji_button.custom": "Custom",
@ -150,20 +150,20 @@
"emoji_button.symbols": "Symbols", "emoji_button.symbols": "Symbols",
"emoji_button.travel": "Travel & Places", "emoji_button.travel": "Travel & Places",
"empty_column.account_suspended": "Account suspended", "empty_column.account_suspended": "Account suspended",
"empty_column.account_timeline": "No toots here!", "empty_column.account_timeline": "No posts here!",
"empty_column.account_unavailable": "Profile unavailable", "empty_column.account_unavailable": "Profile unavailable",
"empty_column.blocks": "You haven't blocked any users yet.", "empty_column.blocks": "You haven't blocked any users yet.",
"empty_column.bookmarked_statuses": "You don't have any bookmarked toots yet. When you bookmark one, it will show up here.", "empty_column.bookmarked_statuses": "You don't have any bookmarked posts yet. When you bookmark one, it will show up here.",
"empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!",
"empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.", "empty_column.direct": "You don't have any direct messages yet. When you send or receive one, it will show up here.",
"empty_column.domain_blocks": "There are no blocked domains yet.", "empty_column.domain_blocks": "There are no blocked domains yet.",
"empty_column.favourited_statuses": "You don't have any favourite toots yet. When you favourite one, it will show up here.", "empty_column.favourited_statuses": "You don't have any favourite posts yet. When you favourite one, it will show up here.",
"empty_column.favourites": "No one has favourited this toot yet. When someone does, they will show up here.", "empty_column.favourites": "No one has favourited this post yet. When someone does, they will show up here.",
"empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.", "empty_column.follow_requests": "You don't have any follow requests yet. When you receive one, it will show up here.",
"empty_column.hashtag": "There is nothing in this hashtag yet.", "empty_column.hashtag": "There is nothing in this hashtag yet.",
"empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.", "empty_column.home": "Your home timeline is empty! Visit {public} or use search to get started and meet other users.",
"empty_column.home.public_timeline": "the public timeline", "empty_column.home.public_timeline": "the public timeline",
"empty_column.list": "There is nothing in this list yet. When members of this list post new toots, they will appear here.", "empty_column.list": "There is nothing in this list yet. When members of this list post new posts, they will appear here.",
"empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.", "empty_column.lists": "You don't have any lists yet. When you create one, it will show up here.",
"empty_column.mutes": "You haven't muted any users yet.", "empty_column.mutes": "You haven't muted any users yet.",
"empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.",
@ -175,9 +175,9 @@
"errors.unexpected_crash.copy_stacktrace": "Copy stacktrace to clipboard", "errors.unexpected_crash.copy_stacktrace": "Copy stacktrace to clipboard",
"errors.unexpected_crash.report_issue": "Report issue", "errors.unexpected_crash.report_issue": "Report issue",
"federation.change": "Adjust status federation", "federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances", "federation.federated.long": "Allow post to reach other instances",
"federation.federated.short": "Federated", "federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance", "federation.local_only.long": "Restrict this post only to my instance",
"federation.local_only.short": "Local-only", "federation.local_only.short": "Local-only",
"follow_request.authorize": "Authorize", "follow_request.authorize": "Authorize",
"follow_request.reject": "Reject", "follow_request.reject": "Reject",
@ -187,6 +187,7 @@
"getting_started.directory": "Profile directory", "getting_started.directory": "Profile directory",
"getting_started.documentation": "Documentation", "getting_started.documentation": "Documentation",
"getting_started.heading": "Getting started", "getting_started.heading": "Getting started",
"getting_started.hometown_open_source_notice": "Hometown is also open source, at {hometown} (v1.0.5).",
"getting_started.invite": "Invite people", "getting_started.invite": "Invite people",
"getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.", "getting_started.open_source_notice": "Mastodon is open source software. You can contribute or report issues on GitHub at {github}.",
"getting_started.security": "Account settings", "getting_started.security": "Account settings",
@ -217,23 +218,23 @@
"introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.", "introduction.federation.local.text": "Public posts from people on the same server as you will appear in the local timeline.",
"introduction.interactions.action": "Finish tutorial!", "introduction.interactions.action": "Finish tutorial!",
"introduction.interactions.favourite.headline": "Favourite", "introduction.interactions.favourite.headline": "Favourite",
"introduction.interactions.favourite.text": "You can save a toot for later, and let the author know that you liked it, by favouriting it.", "introduction.interactions.favourite.text": "You can save a post for later, and let the author know that you liked it, by favouriting it.",
"introduction.interactions.reblog.headline": "Boost", "introduction.interactions.reblog.headline": "Boost",
"introduction.interactions.reblog.text": "You can share other people's toots with your followers by boosting them.", "introduction.interactions.reblog.text": "You can share other people's posts with your followers by boosting them.",
"introduction.interactions.reply.headline": "Reply", "introduction.interactions.reply.headline": "Reply",
"introduction.interactions.reply.text": "You can reply to other people's and your own toots, which will chain them together in a conversation.", "introduction.interactions.reply.text": "You can reply to other people's and your own posts, which will chain them together in a conversation.",
"introduction.welcome.action": "Let's go!", "introduction.welcome.action": "Let's go!",
"introduction.welcome.headline": "First steps", "introduction.welcome.headline": "First steps",
"introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.", "introduction.welcome.text": "Welcome to the fediverse! In a few moments, you'll be able to broadcast messages and talk to your friends across a wide variety of servers. But this server, {domain}, is special—it hosts your profile, so remember its name.",
"keyboard_shortcuts.back": "to navigate back", "keyboard_shortcuts.back": "to navigate back",
"keyboard_shortcuts.blocked": "to open blocked users list", "keyboard_shortcuts.blocked": "to open blocked users list",
"keyboard_shortcuts.boost": "to boost", "keyboard_shortcuts.boost": "to boost",
"keyboard_shortcuts.column": "to focus a toot in one of the columns", "keyboard_shortcuts.column": "to focus a post in one of the columns",
"keyboard_shortcuts.compose": "to focus the compose textarea", "keyboard_shortcuts.compose": "to focus the compose textarea",
"keyboard_shortcuts.description": "Description", "keyboard_shortcuts.description": "Description",
"keyboard_shortcuts.direct": "to open direct messages column", "keyboard_shortcuts.direct": "to open direct messages column",
"keyboard_shortcuts.down": "to move down in the list", "keyboard_shortcuts.down": "to move down in the list",
"keyboard_shortcuts.enter": "to open toot", "keyboard_shortcuts.enter": "to open post",
"keyboard_shortcuts.favourite": "to favourite", "keyboard_shortcuts.favourite": "to favourite",
"keyboard_shortcuts.favourites": "to open favourites list", "keyboard_shortcuts.favourites": "to open favourites list",
"keyboard_shortcuts.federated": "to open federated timeline", "keyboard_shortcuts.federated": "to open federated timeline",
@ -247,7 +248,7 @@
"keyboard_shortcuts.my_profile": "to open your profile", "keyboard_shortcuts.my_profile": "to open your profile",
"keyboard_shortcuts.notifications": "to open notifications column", "keyboard_shortcuts.notifications": "to open notifications column",
"keyboard_shortcuts.open_media": "to open media", "keyboard_shortcuts.open_media": "to open media",
"keyboard_shortcuts.pinned": "to open pinned toots list", "keyboard_shortcuts.pinned": "to open pinned posts list",
"keyboard_shortcuts.profile": "to open author's profile", "keyboard_shortcuts.profile": "to open author's profile",
"keyboard_shortcuts.reply": "to reply", "keyboard_shortcuts.reply": "to reply",
"keyboard_shortcuts.requests": "to open follow requests list", "keyboard_shortcuts.requests": "to open follow requests list",
@ -256,7 +257,7 @@
"keyboard_shortcuts.start": "to open \"get started\" column", "keyboard_shortcuts.start": "to open \"get started\" column",
"keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW", "keyboard_shortcuts.toggle_hidden": "to show/hide text behind CW",
"keyboard_shortcuts.toggle_sensitivity": "to show/hide media", "keyboard_shortcuts.toggle_sensitivity": "to show/hide media",
"keyboard_shortcuts.toot": "to start a brand new toot", "keyboard_shortcuts.toot": "to start a brand new post",
"keyboard_shortcuts.unfocus": "to un-focus compose textarea/search", "keyboard_shortcuts.unfocus": "to un-focus compose textarea/search",
"keyboard_shortcuts.up": "to move up in the list", "keyboard_shortcuts.up": "to move up in the list",
"lightbox.close": "Close", "lightbox.close": "Close",
@ -289,7 +290,7 @@
"navigation_bar.blocks": "Blocked users", "navigation_bar.blocks": "Blocked users",
"navigation_bar.bookmarks": "Bookmarks", "navigation_bar.bookmarks": "Bookmarks",
"navigation_bar.community_timeline": "Local timeline", "navigation_bar.community_timeline": "Local timeline",
"navigation_bar.compose": "Compose new toot", "navigation_bar.compose": "Compose new post",
"navigation_bar.direct": "Direct messages", "navigation_bar.direct": "Direct messages",
"navigation_bar.discover": "Discover", "navigation_bar.discover": "Discover",
"navigation_bar.domain_blocks": "Blocked domains", "navigation_bar.domain_blocks": "Blocked domains",
@ -304,17 +305,17 @@
"navigation_bar.logout": "Logout", "navigation_bar.logout": "Logout",
"navigation_bar.mutes": "Muted users", "navigation_bar.mutes": "Muted users",
"navigation_bar.personal": "Personal", "navigation_bar.personal": "Personal",
"navigation_bar.pins": "Pinned toots", "navigation_bar.pins": "Pinned posts",
"navigation_bar.preferences": "Preferences", "navigation_bar.preferences": "Preferences",
"navigation_bar.public_timeline": "Federated timeline", "navigation_bar.public_timeline": "Federated timeline",
"navigation_bar.security": "Security", "navigation_bar.security": "Security",
"notification.favourite": "{name} favourited your toot", "notification.favourite": "{name} favourited your post",
"notification.follow": "{name} followed you", "notification.follow": "{name} followed you",
"notification.follow_request": "{name} has requested to follow you", "notification.follow_request": "{name} has requested to follow you",
"notification.mention": "{name} mentioned you", "notification.mention": "{name} mentioned you",
"notification.own_poll": "Your poll has ended", "notification.own_poll": "Your poll has ended",
"notification.poll": "A poll you have voted in has ended", "notification.poll": "A poll you have voted in has ended",
"notification.reblog": "{name} boosted your toot", "notification.reblog": "{name} boosted your post",
"notification.status": "{name} just posted", "notification.status": "{name} just posted",
"notifications.clear": "Clear notifications", "notifications.clear": "Clear notifications",
"notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?", "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?",
@ -357,7 +358,7 @@
"poll.voted": "You voted for this answer", "poll.voted": "You voted for this answer",
"poll_button.add_poll": "Add a poll", "poll_button.add_poll": "Add a poll",
"poll_button.remove_poll": "Remove poll", "poll_button.remove_poll": "Remove poll",
"privacy.change": "Adjust toot privacy", "privacy.change": "Adjust post privacy",
"privacy.direct.long": "Visible for mentioned users only", "privacy.direct.long": "Visible for mentioned users only",
"privacy.direct.short": "Direct", "privacy.direct.short": "Direct",
"privacy.private.long": "Visible for followers only", "privacy.private.long": "Visible for followers only",
@ -384,23 +385,23 @@
"report.target": "Reporting {target}", "report.target": "Reporting {target}",
"search.placeholder": "Search", "search.placeholder": "Search",
"search_popout.search_format": "Advanced search format", "search_popout.search_format": "Advanced search format",
"search_popout.tips.full_text": "Simple text returns toots you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.", "search_popout.tips.full_text": "Simple text returns posts you have written, favourited, boosted, or have been mentioned in, as well as matching usernames, display names, and hashtags.",
"search_popout.tips.hashtag": "hashtag", "search_popout.tips.hashtag": "hashtag",
"search_popout.tips.status": "toot", "search_popout.tips.status": "post",
"search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags",
"search_popout.tips.user": "user", "search_popout.tips.user": "user",
"search_results.accounts": "People", "search_results.accounts": "People",
"search_results.hashtags": "Hashtags", "search_results.hashtags": "Hashtags",
"search_results.statuses": "Toots", "search_results.statuses": "Posts",
"search_results.statuses_fts_disabled": "Searching toots by their content is not enabled on this Mastodon server.", "search_results.statuses_fts_disabled": "Searching posts by their content is not enabled on this Mastodon server.",
"search_results.total": "{count, number} {count, plural, one {result} other {results}}", "search_results.total": "{count, number} {count, plural, one {result} other {results}}",
"status.admin_account": "Open moderation interface for @{name}", "status.admin_account": "Open moderation interface for @{name}",
"status.admin_status": "Open this toot in the moderation interface", "status.admin_status": "Open this post in the moderation interface",
"status.block": "Block @{name}", "status.block": "Block @{name}",
"status.bookmark": "Bookmark", "status.bookmark": "Bookmark",
"status.cancel_reblog_private": "Unboost", "status.cancel_reblog_private": "Unboost",
"status.cannot_reblog": "This post cannot be boosted", "status.cannot_reblog": "This post cannot be boosted",
"status.copy": "Copy link to toot", "status.copy": "Copy link to post",
"status.delete": "Delete", "status.delete": "Delete",
"status.detailed_status": "Detailed conversation view", "status.detailed_status": "Detailed conversation view",
"status.direct": "Direct message @{name}", "status.direct": "Direct message @{name}",
@ -414,14 +415,14 @@
"status.more": "More", "status.more": "More",
"status.mute": "Mute @{name}", "status.mute": "Mute @{name}",
"status.mute_conversation": "Mute conversation", "status.mute_conversation": "Mute conversation",
"status.open": "Expand this toot", "status.open": "Expand this post",
"status.pin": "Pin on profile", "status.pin": "Pin on profile",
"status.pinned": "Pinned toot", "status.pinned": "Pinned post",
"status.read_more": "Read more", "status.read_more": "Read more",
"status.reblog": "Boost", "status.reblog": "Boost",
"status.reblog_private": "Boost with original visibility", "status.reblog_private": "Boost with original visibility",
"status.reblogged_by": "{name} boosted", "status.reblogged_by": "{name} boosted",
"status.reblogs.empty": "No one has boosted this toot yet. When someone does, they will show up here.", "status.reblogs.empty": "No one has boosted this post yet. When someone does, they will show up here.",
"status.redraft": "Delete & re-draft", "status.redraft": "Delete & re-draft",
"status.remove_bookmark": "Remove bookmark", "status.remove_bookmark": "Remove bookmark",
"status.reply": "Reply", "status.reply": "Reply",
@ -452,7 +453,7 @@
"timeline_hint.remote_resource_not_displayed": "{resource} from other servers are not displayed.", "timeline_hint.remote_resource_not_displayed": "{resource} from other servers are not displayed.",
"timeline_hint.resources.followers": "Followers", "timeline_hint.resources.followers": "Followers",
"timeline_hint.resources.follows": "Follows", "timeline_hint.resources.follows": "Follows",
"timeline_hint.resources.statuses": "Older toots", "timeline_hint.resources.statuses": "Older posts",
"trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} talking", "trends.counter_by_accounts": "{count, plural, one {{counter} person} other {{counter} people}} talking",
"trends.trending_now": "Trending now", "trends.trending_now": "Trending now",
"ui.beforeunload": "Your draft will be lost if you leave Mastodon.", "ui.beforeunload": "Your draft will be lost if you leave Mastodon.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "لطفاً از کارشان انداخته و صفحه را نوسازی کنید. اگر کمکی نکرد، شاید همچنان بتوانید با مرورگری دیگر یا با کاره‌ای بومی از ماستودون استفاده کنید.", "error.unexpected_crash.next_steps_addons": "لطفاً از کارشان انداخته و صفحه را نوسازی کنید. اگر کمکی نکرد، شاید همچنان بتوانید با مرورگری دیگر یا با کاره‌ای بومی از ماستودون استفاده کنید.",
"errors.unexpected_crash.copy_stacktrace": "رونوشت از جزئیات اشکال", "errors.unexpected_crash.copy_stacktrace": "رونوشت از جزئیات اشکال",
"errors.unexpected_crash.report_issue": "گزارش مشکل", "errors.unexpected_crash.report_issue": "گزارش مشکل",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "اجازه دهید", "follow_request.authorize": "اجازه دهید",
"follow_request.reject": "رد کنید", "follow_request.reject": "رد کنید",
"follow_requests.unlocked_explanation": "با این که حسابتان قفل نیست، کارکنان {domain} فکر کردند که ممکن است بخواهید درخواست‌ها از این حساب‌ها را به صورت دستی بازبینی کنید.", "follow_requests.unlocked_explanation": "با این که حسابتان قفل نیست، کارکنان {domain} فکر کردند که ممکن است بخواهید درخواست‌ها از این حساب‌ها را به صورت دستی بازبینی کنید.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Essayez de les désactiver et de rafraîchir la page. Si cela ne vous aide pas, vous pouvez toujours utiliser Mastodon via un autre navigateur ou une application native.", "error.unexpected_crash.next_steps_addons": "Essayez de les désactiver et de rafraîchir la page. Si cela ne vous aide pas, vous pouvez toujours utiliser Mastodon via un autre navigateur ou une application native.",
"errors.unexpected_crash.copy_stacktrace": "Copier la trace d'appels dans le presse-papier", "errors.unexpected_crash.copy_stacktrace": "Copier la trace d'appels dans le presse-papier",
"errors.unexpected_crash.report_issue": "Signaler le problème", "errors.unexpected_crash.report_issue": "Signaler le problème",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Accepter", "follow_request.authorize": "Accepter",
"follow_request.reject": "Rejeter", "follow_request.reject": "Rejeter",
"follow_requests.unlocked_explanation": "Même si votre compte nest pas verrouillé, léquipe de {domain} a pensé que vous pourriez vouloir consulter manuellement les demandes de suivi de ces comptes.", "follow_requests.unlocked_explanation": "Même si votre compte nest pas verrouillé, léquipe de {domain} a pensé que vous pourriez vouloir consulter manuellement les demandes de suivi de ces comptes.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Intenta desactivalas e actualiza a páxina. Se isto non funciona, podes seguir usando Mastodon nun navegador diferente ou aplicación nativa.", "error.unexpected_crash.next_steps_addons": "Intenta desactivalas e actualiza a páxina. Se isto non funciona, podes seguir usando Mastodon nun navegador diferente ou aplicación nativa.",
"errors.unexpected_crash.copy_stacktrace": "Copiar trazas (stacktrace) ó portapapeis", "errors.unexpected_crash.copy_stacktrace": "Copiar trazas (stacktrace) ó portapapeis",
"errors.unexpected_crash.report_issue": "Informar sobre un problema", "errors.unexpected_crash.report_issue": "Informar sobre un problema",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Autorizar", "follow_request.authorize": "Autorizar",
"follow_request.reject": "Rexeitar", "follow_request.reject": "Rexeitar",
"follow_requests.unlocked_explanation": "Malia que a túa conta non é privada, a administración de {domain} pensou que quizabes terías que revisar de xeito manual as solicitudes de seguiminto.", "follow_requests.unlocked_explanation": "Malia que a túa conta non é privada, a administración de {domain} pensou que quizabes terías que revisar de xeito manual as solicitudes de seguiminto.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.", "error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.",
"errors.unexpected_crash.copy_stacktrace": "स्टैकट्रेस को क्लिपबोर्ड पर कॉपी करें", "errors.unexpected_crash.copy_stacktrace": "स्टैकट्रेस को क्लिपबोर्ड पर कॉपी करें",
"errors.unexpected_crash.report_issue": "समस्या सूचित करें", "errors.unexpected_crash.report_issue": "समस्या सूचित करें",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "अधिकार दें", "follow_request.authorize": "अधिकार दें",
"follow_request.reject": "अस्वीकार करें", "follow_request.reject": "अस्वीकार करें",
"follow_requests.unlocked_explanation": "हालाँकि आपका खाता लॉक नहीं है, फिर भी {domain} डोमेन स्टाफ ने सोचा कि आप इन खातों के मैन्युअल अनुरोधों की समीक्षा करना चाहते हैं।", "follow_requests.unlocked_explanation": "हालाँकि आपका खाता लॉक नहीं है, फिर भी {domain} डोमेन स्टाफ ने सोचा कि आप इन खातों के मैन्युअल अनुरोधों की समीक्षा करना चाहते हैं।",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Próbáld letiltani őket és frissíteni az oldalt. Ha ez nem segít, egy másik böngészőn vagy appon keresztül még mindig használhatod a Mastodont.", "error.unexpected_crash.next_steps_addons": "Próbáld letiltani őket és frissíteni az oldalt. Ha ez nem segít, egy másik böngészőn vagy appon keresztül még mindig használhatod a Mastodont.",
"errors.unexpected_crash.copy_stacktrace": "Veremkiíratás vágólapra másolása", "errors.unexpected_crash.copy_stacktrace": "Veremkiíratás vágólapra másolása",
"errors.unexpected_crash.report_issue": "Probléma jelentése", "errors.unexpected_crash.report_issue": "Probléma jelentése",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Engedélyezés", "follow_request.authorize": "Engedélyezés",
"follow_request.reject": "Elutasítás", "follow_request.reject": "Elutasítás",
"follow_requests.unlocked_explanation": "Bár a fiókod nincs zárolva, a(z) {domain} csapata úgy gondolta, hogy talán kézzel szeretnéd ellenőrizni a fiók követési kéréseit.", "follow_requests.unlocked_explanation": "Bár a fiókod nincs zárolva, a(z) {domain} csapata úgy gondolta, hogy talán kézzel szeretnéd ellenőrizni a fiók követési kéréseit.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Փորձիր անջատել յաւելուածները եւ թարմացնել էջը։ Եթե դա չօգնի, կարող ես օգտուել Մաստադոնից այլ դիտարկիչով կամ յաւելուածով։", "error.unexpected_crash.next_steps_addons": "Փորձիր անջատել յաւելուածները եւ թարմացնել էջը։ Եթե դա չօգնի, կարող ես օգտուել Մաստադոնից այլ դիտարկիչով կամ յաւելուածով։",
"errors.unexpected_crash.copy_stacktrace": "Պատճենել սթաքթրեյսը սեղմատախտակին", "errors.unexpected_crash.copy_stacktrace": "Պատճենել սթաքթրեյսը սեղմատախտակին",
"errors.unexpected_crash.report_issue": "Զեկուցել խնդրի մասին", "errors.unexpected_crash.report_issue": "Զեկուցել խնդրի մասին",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Վաւերացնել", "follow_request.authorize": "Վաւերացնել",
"follow_request.reject": "Մերժել", "follow_request.reject": "Մերժել",
"follow_requests.unlocked_explanation": "Այս հարցումը ուղարկուած է հաշուից, որի համար {domain}-ի անձնակազմը միացրել է ձեռքով ստուգում։", "follow_requests.unlocked_explanation": "Այս հարցումը ուղարկուած է հաշուից, որի համար {domain}-ի անձնակազմը միացրել է ձեռքով ստուգում։",
@ -403,6 +408,7 @@
"status.favourite": "Հաւանել", "status.favourite": "Հաւանել",
"status.filtered": "Զտուած", "status.filtered": "Զտուած",
"status.load_more": "Բեռնել աւելին", "status.load_more": "Բեռնել աւելին",
"status.local_only": "This post is only visible by other users of your instance",
"status.media_hidden": "մեդիաբովանդակութիւնը թաքցուած է", "status.media_hidden": "մեդիաբովանդակութիւնը թաքցուած է",
"status.mention": "Նշել @{name}֊ին", "status.mention": "Նշել @{name}֊ին",
"status.more": "Աւելին", "status.more": "Աւելին",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Prova a disabilitarli e ad aggiornare la pagina. Se questo non funziona, potresti ancora essere in grado di utilizzare Mastodon attraverso un browser o un'app diversi.", "error.unexpected_crash.next_steps_addons": "Prova a disabilitarli e ad aggiornare la pagina. Se questo non funziona, potresti ancora essere in grado di utilizzare Mastodon attraverso un browser o un'app diversi.",
"errors.unexpected_crash.copy_stacktrace": "Copia stacktrace negli appunti", "errors.unexpected_crash.copy_stacktrace": "Copia stacktrace negli appunti",
"errors.unexpected_crash.report_issue": "Segnala il problema", "errors.unexpected_crash.report_issue": "Segnala il problema",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Autorizza", "follow_request.authorize": "Autorizza",
"follow_request.reject": "Rifiuta", "follow_request.reject": "Rifiuta",
"follow_requests.unlocked_explanation": "Anche se il tuo account non è bloccato, lo staff di {domain} ha pensato che potresti voler esaminare manualmente le richieste di seguirti di questi account.", "follow_requests.unlocked_explanation": "Anche se il tuo account non è bloccato, lo staff di {domain} ha pensato che potresti voler esaminare manualmente le richieste di seguirti di questi account.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.", "error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.",
"errors.unexpected_crash.copy_stacktrace": "Жиынтықты көшіріп ал клипбордқа", "errors.unexpected_crash.copy_stacktrace": "Жиынтықты көшіріп ал клипбордқа",
"errors.unexpected_crash.report_issue": "Мәселені хабарла", "errors.unexpected_crash.report_issue": "Мәселені хабарла",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Авторизация", "follow_request.authorize": "Авторизация",
"follow_request.reject": "Қабылдамау", "follow_request.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.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.", "error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.",
"errors.unexpected_crash.copy_stacktrace": "Kopier stacktrace-en til utklippstavlen", "errors.unexpected_crash.copy_stacktrace": "Kopier stacktrace-en til utklippstavlen",
"errors.unexpected_crash.report_issue": "Rapporter en feil", "errors.unexpected_crash.report_issue": "Rapporter en feil",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Autorisér", "follow_request.authorize": "Autorisér",
"follow_request.reject": "Avvis", "follow_request.reject": "Avvis",
"follow_requests.unlocked_explanation": "Selv om kontoen din ikke er låst, tror {domain} ansatte at du kanskje vil gjennomgå forespørsler fra disse kontoene manuelt.", "follow_requests.unlocked_explanation": "Selv om kontoen din ikke er låst, tror {domain} ansatte at du kanskje vil gjennomgå forespørsler fra disse kontoene manuelt.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Tente desabilitá-los e atualizar a página. Se isso não ajudar, você ainda poderá usar o Mastodon por meio de um navegador diferente ou de um aplicativo nativo.", "error.unexpected_crash.next_steps_addons": "Tente desabilitá-los e atualizar a página. Se isso não ajudar, você ainda poderá usar o Mastodon por meio de um navegador diferente ou de um aplicativo nativo.",
"errors.unexpected_crash.copy_stacktrace": "Copiar stacktrace para área de transferência", "errors.unexpected_crash.copy_stacktrace": "Copiar stacktrace para área de transferência",
"errors.unexpected_crash.report_issue": "Denunciar problema", "errors.unexpected_crash.report_issue": "Denunciar problema",
"federation.change": "Ajustar federação do toot",
"federation.federated.long": "Permitir que o toot chegue a outras instâncias",
"federation.federated.short": "Federado",
"federation.local_only.long": "Restringir o toot somente à minha instância",
"federation.local_only.short": "Somente local",
"follow_request.authorize": "Aprovar", "follow_request.authorize": "Aprovar",
"follow_request.reject": "Vetar", "follow_request.reject": "Vetar",
"follow_requests.unlocked_explanation": "Embora sua conta não esteja trancada, o staff de {domain} achou que você podia querer revisar pedidos para te seguir destas contas manualmente.", "follow_requests.unlocked_explanation": "Embora sua conta não esteja trancada, o staff de {domain} achou que você podia querer revisar pedidos para te seguir destas contas manualmente.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Tente desabilitá-los e atualizar a página. Se isso não ajudar, você ainda poderá usar o Mastodon por meio de um navegador diferente ou de um aplicativo nativo.", "error.unexpected_crash.next_steps_addons": "Tente desabilitá-los e atualizar a página. Se isso não ajudar, você ainda poderá usar o Mastodon por meio de um navegador diferente ou de um aplicativo nativo.",
"errors.unexpected_crash.copy_stacktrace": "Copiar a stacktrace para o clipboard", "errors.unexpected_crash.copy_stacktrace": "Copiar a stacktrace para o clipboard",
"errors.unexpected_crash.report_issue": "Reportar problema", "errors.unexpected_crash.report_issue": "Reportar problema",
"federation.change": "Ajustar federação do toot",
"federation.federated.long": "Permitir que o toot chegue a outras instâncias",
"federation.federated.short": "Federado",
"federation.local_only.long": "Restringir o toot somente à minha instância",
"federation.local_only.short": "Somente local",
"follow_request.authorize": "Autorizar", "follow_request.authorize": "Autorizar",
"follow_request.reject": "Rejeitar", "follow_request.reject": "Rejeitar",
"follow_requests.unlocked_explanation": "Apesar de a sua não estar bloqueada, a administração de {domain} pensa que poderá querer rever os pedidos dessas contas manualmente.", "follow_requests.unlocked_explanation": "Apesar de a sua não estar bloqueada, a administração de {domain} pensa que poderá querer rever os pedidos dessas contas manualmente.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.", "error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.",
"errors.unexpected_crash.copy_stacktrace": "Copiați stiva în clipboard", "errors.unexpected_crash.copy_stacktrace": "Copiați stiva în clipboard",
"errors.unexpected_crash.report_issue": "Raportați o problemă", "errors.unexpected_crash.report_issue": "Raportați o problemă",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Autorizează", "follow_request.authorize": "Autorizează",
"follow_request.reject": "Respinge", "follow_request.reject": "Respinge",
"follow_requests.unlocked_explanation": "Chiar dacă contul dvs nu este blocat, personalul {domain} a crezut că ați putea dori să revizuiți cererile de la aceste conturi în mod manual.", "follow_requests.unlocked_explanation": "Chiar dacă contul dvs nu este blocat, personalul {domain} a crezut că ați putea dori să revizuiți cererile de la aceste conturi în mod manual.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Provoni ti çaktivizoni dhe të rifreskoni faqen. Nëse kjo sbën punë, mundeni prapë të jeni në gjendje të përdorni Mastodon-in përmes një shfletuesi tjetër, apo një aplikacioni prej Mastodon-it.", "error.unexpected_crash.next_steps_addons": "Provoni ti çaktivizoni dhe të rifreskoni faqen. Nëse kjo sbën punë, mundeni prapë të jeni në gjendje të përdorni Mastodon-in përmes një shfletuesi tjetër, apo një aplikacioni prej Mastodon-it.",
"errors.unexpected_crash.copy_stacktrace": "Kopjo stacktrace-in në të papastër", "errors.unexpected_crash.copy_stacktrace": "Kopjo stacktrace-in në të papastër",
"errors.unexpected_crash.report_issue": "Raportoni problemin", "errors.unexpected_crash.report_issue": "Raportoni problemin",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Autorizoje", "follow_request.authorize": "Autorizoje",
"follow_request.reject": "Hidhe tej", "follow_request.reject": "Hidhe tej",
"follow_requests.unlocked_explanation": "Edhe pse llogaria juaj sështë e kyçur, ekipi i {domain} mendoi se mund të donit të shqyrtonit dorazi kërkesa ndjekjeje prej këtyre llogarive.", "follow_requests.unlocked_explanation": "Edhe pse llogaria juaj sështë e kyçur, ekipi i {domain} mendoi se mund të donit të shqyrtonit dorazi kërkesa ndjekjeje prej këtyre llogarive.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.", "error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.",
"errors.unexpected_crash.copy_stacktrace": "Копирај \"stacktrace\" у клипборд", "errors.unexpected_crash.copy_stacktrace": "Копирај \"stacktrace\" у клипборд",
"errors.unexpected_crash.report_issue": "Пријави проблем", "errors.unexpected_crash.report_issue": "Пријави проблем",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Одобри", "follow_request.authorize": "Одобри",
"follow_request.reject": "Одбиј", "follow_request.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.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.", "error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.",
"errors.unexpected_crash.copy_stacktrace": "Stacktrace-ஐ clipboard-ல் நகலெடு", "errors.unexpected_crash.copy_stacktrace": "Stacktrace-ஐ clipboard-ல் நகலெடு",
"errors.unexpected_crash.report_issue": "புகாரளி", "errors.unexpected_crash.report_issue": "புகாரளி",
"federation.change": "Adjust status federation",
"federation.federated.short": "Federated",
"federation.federated.long": "Allow toot to reach other instances",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "அனுமதியளி", "follow_request.authorize": "அனுமதியளி",
"follow_request.reject": "நிராகரி", "follow_request.reject": "நிராகரி",
"follow_requests.unlocked_explanation": "உங்கள் கணக்கு பூட்டப்படவில்லை என்றாலும், இந்தக் கணக்குகளிலிருந்து உங்களைப் பின்தொடர விரும்பும் கோரிக்கைகளை நீங்கள் பரீசீலிப்பது நலம் என்று {domain} ஊழியர் எண்ணுகிறார்.", "follow_requests.unlocked_explanation": "உங்கள் கணக்கு பூட்டப்படவில்லை என்றாலும், இந்தக் கணக்குகளிலிருந்து உங்களைப் பின்தொடர விரும்பும் கோரிக்கைகளை நீங்கள் பரீசீலிப்பது நலம் என்று {domain} ஊழியர் எண்ணுகிறார்.",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.", "error.unexpected_crash.next_steps_addons": "Try disabling them and refreshing the page. If that does not help, you may still be able to use Mastodon through a different browser or native app.",
"errors.unexpected_crash.copy_stacktrace": "Скопіювати трасування стека у буфер обміну", "errors.unexpected_crash.copy_stacktrace": "Скопіювати трасування стека у буфер обміну",
"errors.unexpected_crash.report_issue": "Повідомити про проблему", "errors.unexpected_crash.report_issue": "Повідомити про проблему",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "Авторизувати", "follow_request.authorize": "Авторизувати",
"follow_request.reject": "Відмовити", "follow_request.reject": "Відмовити",
"follow_requests.unlocked_explanation": "Хоча ваш обліковий запис не заблоковано, працівники {domain} припускають, що, можливо, ви хотіли б переглянути ці запити на підписку.", "follow_requests.unlocked_explanation": "Хоча ваш обліковий запис не заблоковано, працівники {domain} припускають, що, можливо, ви хотіли б переглянути ці запити на підписку.",
@ -403,6 +408,7 @@
"status.favourite": "Подобається", "status.favourite": "Подобається",
"status.filtered": "Відфільтровано", "status.filtered": "Відфільтровано",
"status.load_more": "Завантажити більше", "status.load_more": "Завантажити більше",
"status.local_only": "This post is only visible by other users of your instance",
"status.media_hidden": "Медіа приховано", "status.media_hidden": "Медіа приховано",
"status.mention": "Згадати @{name}", "status.mention": "Згадати @{name}",
"status.more": "Більше", "status.more": "Більше",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "请尝试禁用它们并刷新页面。如果没有帮助,你仍可以尝试使用其他浏览器或原生应用来使用 Mastodon。", "error.unexpected_crash.next_steps_addons": "请尝试禁用它们并刷新页面。如果没有帮助,你仍可以尝试使用其他浏览器或原生应用来使用 Mastodon。",
"errors.unexpected_crash.copy_stacktrace": "把堆栈跟踪信息复制到剪贴板", "errors.unexpected_crash.copy_stacktrace": "把堆栈跟踪信息复制到剪贴板",
"errors.unexpected_crash.report_issue": "报告问题", "errors.unexpected_crash.report_issue": "报告问题",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "同意", "follow_request.authorize": "同意",
"follow_request.reject": "拒绝", "follow_request.reject": "拒绝",
"follow_requests.unlocked_explanation": "虽说你没有锁嘟,但是 {domain} 的工作人员觉得你可能想手工审核关注请求。", "follow_requests.unlocked_explanation": "虽说你没有锁嘟,但是 {domain} 的工作人员觉得你可能想手工审核关注请求。",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "請嘗試停止使用這些附加元件然後重新載入頁面。如果問題沒有解決,你仍然可以使用不同的瀏覽器或 Mastodon 應用程式來檢視。", "error.unexpected_crash.next_steps_addons": "請嘗試停止使用這些附加元件然後重新載入頁面。如果問題沒有解決,你仍然可以使用不同的瀏覽器或 Mastodon 應用程式來檢視。",
"errors.unexpected_crash.copy_stacktrace": "複製 stacktrace 到剪貼簿", "errors.unexpected_crash.copy_stacktrace": "複製 stacktrace 到剪貼簿",
"errors.unexpected_crash.report_issue": "舉報問題", "errors.unexpected_crash.report_issue": "舉報問題",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "批准", "follow_request.authorize": "批准",
"follow_request.reject": "拒絕", "follow_request.reject": "拒絕",
"follow_requests.unlocked_explanation": "即使您的帳戶未上鎖,{domain} 的工作人員認為您可能想手動審核來自這些帳戶的關注請求。", "follow_requests.unlocked_explanation": "即使您的帳戶未上鎖,{domain} 的工作人員認為您可能想手動審核來自這些帳戶的關注請求。",

View File

@ -174,6 +174,11 @@
"error.unexpected_crash.next_steps_addons": "請嘗試關閉他們然後重新整理頁面。如果狀況沒有改善,您可以使用不同的瀏覽器或應用程式來檢視來使用 Mastodon。", "error.unexpected_crash.next_steps_addons": "請嘗試關閉他們然後重新整理頁面。如果狀況沒有改善,您可以使用不同的瀏覽器或應用程式來檢視來使用 Mastodon。",
"errors.unexpected_crash.copy_stacktrace": "複製 stacktrace 到剪貼簿", "errors.unexpected_crash.copy_stacktrace": "複製 stacktrace 到剪貼簿",
"errors.unexpected_crash.report_issue": "回報問題", "errors.unexpected_crash.report_issue": "回報問題",
"federation.change": "Adjust status federation",
"federation.federated.long": "Allow toot to reach other instances",
"federation.federated.short": "Federated",
"federation.local_only.long": "Restrict this toot only to my instance",
"federation.local_only.short": "Local-only",
"follow_request.authorize": "授權", "follow_request.authorize": "授權",
"follow_request.reject": "拒絕", "follow_request.reject": "拒絕",
"follow_requests.unlocked_explanation": "即便您的帳號未被鎖定,{domain} 的員工認為您可能想要自己審核這些帳號的追蹤請求。", "follow_requests.unlocked_explanation": "即便您的帳號未被鎖定,{domain} 的員工認為您可能想要自己審核這些帳號的追蹤請求。",

View File

@ -9,6 +9,7 @@ import {
LIST_EDITOR_RESET, LIST_EDITOR_RESET,
LIST_EDITOR_SETUP, LIST_EDITOR_SETUP,
LIST_EDITOR_TITLE_CHANGE, LIST_EDITOR_TITLE_CHANGE,
LIST_EDITOR_IS_EXCLUSIVE_CHANGE,
LIST_ACCOUNTS_FETCH_REQUEST, LIST_ACCOUNTS_FETCH_REQUEST,
LIST_ACCOUNTS_FETCH_SUCCESS, LIST_ACCOUNTS_FETCH_SUCCESS,
LIST_ACCOUNTS_FETCH_FAIL, LIST_ACCOUNTS_FETCH_FAIL,
@ -52,6 +53,11 @@ export default function listEditorReducer(state = initialState, action) {
map.set('title', action.value); map.set('title', action.value);
map.set('isChanged', true); map.set('isChanged', true);
}); });
case LIST_EDITOR_IS_EXCLUSIVE_CHANGE:
return state.withMutations(map => {
map.set('isExclusive', action.value);
map.set('isChanged', true);
});
case LIST_CREATE_REQUEST: case LIST_CREATE_REQUEST:
case LIST_UPDATE_REQUEST: case LIST_UPDATE_REQUEST:
return state.withMutations(map => { return state.withMutations(map => {

View File

@ -0,0 +1,21 @@
export function svgSelect(light, dark) {
var svgbg = window.getComputedStyle(document.getElementsByClassName("drawer__inner")[0], null).getPropertyValue("background-color");
var rgbArray = ((svgbg.replace(/[^0-9,]/g, "")).split(",")).map(Number).map(x => x/255);
for ( var i = 0; i < rgbArray.length; ++i ) {
if ( rgbArray[i] <= 0.03928 ) {
rgbArray[i] = rgbArray[i] / 12.92
} else {
rgbArray[i] = Math.pow( ( rgbArray[i] + 0.055 ) / 1.055, 2.4);
}
}
var luminance = 0.2126 * rgbArray[0] + 0.7152 * rgbArray[1] + 0.0722 * rgbArray[2];
if ( luminance <= 0.179 ) {
return light;
} else {
return dark;
}
}

View File

@ -0,0 +1,3 @@
@import 'fairy-floss/variables';
@import 'application';
@import 'fairy-floss/diff'

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,70 @@
// FAIRY FLOSS VARIABLES
// Purples
$purple1: #2e2b3b;
$purple2: #504b68;
$purple3: #5f5676;
$purple4: #c8c4d4;
$purple5: #474059;
$purpleicon: #ada6bf;
$purpleborder: #5f5676;
$purplescrollbar: #5a5475;
$mint: #c2ffdf;
$pink: #ffb8d1;
$lemon: #fff683;
$coral: #ff857f;
// Commonly used web colors
$black: #000000; // Black
$white: #ffffff; // White
$success-green: #79bd9a !default; // Padua
$error-red: #df405a !default; // Cerise
$warning-red: #ff5050 !default; // Sunset Orange
$gold-star: #ca8f04 !default; // Dark Goldenrod
// Values from the classic Mastodon UI
$classic-base-color: $purple1; // Midnight Express
$classic-primary-color: $purple4; // Echo Blue
$classic-secondary-color: #d9e1e8; // Pattens Blue
$classic-highlight-color: #ff857f; // Summer Sky
// Variables for defaults in UI
$base-shadow-color: $black !default;
$base-overlay-background: $black !default;
$base-border-color: $white !default;
$simple-background-color: $white !default;
$valid-value-color: $success-green !default;
$error-value-color: $error-red !default;
// Tell UI to use selected colors
$ui-base-color: $classic-base-color !default; // Darkest
$ui-base-lighter-color: lighten($ui-base-color, 26%) !default; // Lighter darkest
$ui-primary-color: $classic-primary-color !default; // Lighter
$ui-secondary-color: $classic-secondary-color !default; // Lightest
$ui-highlight-color: $classic-highlight-color !default;
// Variables for texts
$primary-text-color: $white !default;
$darker-text-color: $ui-primary-color !default;
$dark-text-color: $purpleicon !default;
$secondary-text-color: $ui-secondary-color !default;
$highlight-text-color: $ui-highlight-color !default;
$action-button-color: $purpleicon !default;
// For texts on inverted backgrounds
$inverted-text-color: $ui-base-color !default;
$lighter-text-color: $ui-base-lighter-color !default;
$light-text-color: $ui-primary-color !default;
// Language codes that uses CJK fonts
$cjk-langs: ja, ko, zh-CN, zh-HK, zh-TW;
// Variables for components
$media-modal-media-max-width: 100%;
// put margins on top and bottom of image to avoid the screen covered by image.
$media-modal-media-max-height: 80%;
$no-gap-breakpoint: 415px;
$font-sans-serif: 'mastodon-font-sans-serif' !default;
$font-display: 'mastodon-font-display' !default;
$font-monospace: 'mastodon-font-monospace' !default;

View File

@ -0,0 +1,3 @@
@import 'macaron/variables';
@import 'application';
@import 'macaron/diff';

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
// Dependent colors
$black: #000000;
$white: #ffffff;
$purple: #c8c4dd;
$blue: #c8dbee;
$green: #dff6eb;
$pink: #ffcbcb;
$blueberry: #5971ad;
$cream: #fffdef;
$bilberry: #ad599c;
$classic-base-color: #282c37;
$classic-primary-color: #9baec8;
$classic-secondary-color: $green;
$classic-highlight-color: #2b90d9;
// Differences
$success-green: #3c754d;
$base-overlay-background: $white !default;
$valid-value-color: $success-green !default;
$ui-base-color: $classic-secondary-color !default;
$ui-base-lighter-color: $cream;
$ui-primary-color: #9bcbed;
$ui-secondary-color: $classic-base-color !default;
$ui-highlight-color: $blueberry;
$primary-text-color: $black !default;
$darker-text-color: $classic-base-color !default;
$dark-text-color: #444b5d;
$action-button-color: #606984;
$inverted-text-color: $black !default;
$lighter-text-color: $classic-base-color !default;
$light-text-color: #444b5d;
//Newly added colors
$account-background-color: $white !default;
//Invert darkened and lightened colors
@function darken($color, $amount) {
@return hsl(hue($color), saturation($color), lightness($color) + $amount);
}
@function lighten($color, $amount) {
@return hsl(hue($color), saturation($color), lightness($color) - $amount);
}

View File

@ -228,6 +228,11 @@ h1 {
line-height: 36px; line-height: 36px;
} }
.column-cell a h1 {
margin: 0 8px 10px;
line-height: 26px;
}
h2 { h2 {
font-size: 23px; font-size: 23px;
line-height: 30px; line-height: 30px;

View File

@ -195,7 +195,7 @@ html {
} }
.drawer__inner__mastodon { .drawer__inner__mastodon {
background: $white url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-color)}"/></svg>') no-repeat bottom / 100% auto; background: $white;
} }
// Change the colors used in compose-form // Change the colors used in compose-form

View File

@ -579,7 +579,7 @@ $small-breakpoint: 960px;
bottom: 25px; bottom: 25px;
img { img {
height: 190px; height: 155px;
width: auto; width: auto;
} }
} }
@ -688,6 +688,8 @@ $small-breakpoint: 960px;
justify-content: center; justify-content: center;
align-items: center; align-items: center;
padding: 50px; padding: 50px;
font-family: $font-display, sans-serif;
font-weight: bold;
svg { svg {
fill: $primary-text-color; fill: $primary-text-color;
@ -864,6 +866,22 @@ $small-breakpoint: 960px;
.brand { .brand {
position: relative; position: relative;
text-decoration: none; text-decoration: none;
color: $secondary-text-color;
}
a.brand {
color: $primary-text-color;
}
h1 a.brand {
color: $secondary-text-color;
font-size: 3.8em;
}
.originalmascotimg svg {
width: 200px;
fill: $secondary-text-color;
margin-top: -25px;
} }
.brand__tagline { .brand__tagline {
@ -883,4 +901,3 @@ $small-breakpoint: 960px;
color: $dark-text-color; color: $dark-text-color;
} }
} }

View File

@ -46,6 +46,12 @@ $content-width: 840px;
position: relative; position: relative;
bottom: -2px; bottom: -2px;
} }
h2 {
height: 20px;
position: relative;
bottom: -2px;
}
} }
&__icon { &__icon {
@ -68,15 +74,32 @@ $content-width: 840px;
.logo { .logo {
display: block; display: block;
margin: 40px auto; margin: 60px 0 0 20px;
width: 100px;
height: 100px; height: 100px;
h2 .brand {
color: $primary-text-color;
display: block;
font-size: 24px;
line-height: 28px;
font-weight: 400;
padding-bottom: 40px;
border-bottom: 1px solid lighten($ui-base-color, 8%);
}
} }
@media screen and (max-width: $no-columns-breakpoint) { @media screen and (max-width: $no-columns-breakpoint) {
& > a:first-child { & > a:first-child {
display: none; display: none;
} }
.logo,
.logo h2,
.logo h2 .brand {
display: none;
}
} }
ul { ul {

View File

@ -138,6 +138,12 @@ body {
height: auto; height: auto;
margin-top: -120px; margin-top: -120px;
} }
h1 {
a.brand {
font-size: 36px;
}
}
} }
h1 { h1 {

View File

@ -406,12 +406,6 @@
color: $lighter-text-color; color: $lighter-text-color;
font-weight: 500; font-weight: 500;
text-decoration: underline; text-decoration: underline;
&:hover,
&:active,
&:focus {
text-decoration: none;
}
} }
} }
@ -821,10 +815,6 @@
&.status__content--with-spoiler { &.status__content--with-spoiler {
white-space: normal; white-space: normal;
.status__content__text {
white-space: pre-wrap;
}
} }
.emojione { .emojione {
@ -832,11 +822,82 @@
height: 20px; height: 20px;
margin: -3px 0 0; margin: -3px 0 0;
} }
.status__content__text {
p,
pre,
blockquote {
margin-bottom: 20px;
white-space: pre-wrap;
unicode-bidi: plaintext;
p { &:last-child {
margin-bottom: 20px; margin-bottom: 2px;
white-space: pre-wrap; }
unicode-bidi: plaintext; }
h1,
h2,
h3,
h4,
h5 {
margin-top: 20px;
margin-bottom: 20px;
}
h1 {
font-weight: 700;
font-size: 22px;
}
h2 {
font-weight: 700;
font-size: 20px;
}
h3,
h4,
h5 {
font-weight: 500;
}
blockquote {
padding-left: 10px;
border-left: 3px solid $darker-text-color;
color: $darker-text-color;
white-space: normal;
p:last-child {
margin-bottom: 0;
}
}
b,
strong {
font-weight: 700;
}
em,
i {
font-style: italic;
}
ul,
ol {
margin-left: 1em;
margin-bottom: 1em;
p {
margin: 0;
}
}
ul {
list-style-type: disc;
}
ol {
list-style-type: decimal;
}
&:last-child { &:last-child {
margin-bottom: 0; margin-bottom: 0;
@ -845,7 +906,7 @@
a { a {
color: $secondary-text-color; color: $secondary-text-color;
text-decoration: none; text-decoration: underline;
unicode-bidi: isolate; unicode-bidi: isolate;
&:hover { &:hover {
@ -857,13 +918,9 @@
} }
&.mention { &.mention {
&:hover {
text-decoration: none;
span { span {
text-decoration: underline; text-decoration: underline;
} }
}
} }
.fa { .fa {
@ -901,6 +958,10 @@
display: block; display: block;
} }
} }
.article-type img {
max-width: 95%;
}
} }
.announcements__item__content { .announcements__item__content {
@ -1177,6 +1238,7 @@
.status__action-bar-dropdown { .status__action-bar-dropdown {
height: 23.15px; height: 23.15px;
width: 23.15px; width: 23.15px;
margin-right: 18px;
} }
.detailed-status__action-bar-dropdown { .detailed-status__action-bar-dropdown {
@ -2027,6 +2089,13 @@ a.account__display-name {
width: 285px; width: 285px;
pointer-events: auto; pointer-events: auto;
height: 100%; height: 100%;
@media screen and (max-width: 1550px) {
overflow-y: scroll;
overflow-x: hidden;
padding-right: 10px;
}
} }
} }
@ -2467,6 +2536,12 @@ a.account__display-name {
height: calc(100% - 10px); height: calc(100% - 10px);
overflow-y: hidden; overflow-y: hidden;
@media screen and (max-width: 1550px) {
height: auto;
min-height: calc(100% - 10px);
overflow-y: visible;
}
.navigation-bar { .navigation-bar {
padding-top: 20px; padding-top: 20px;
padding-bottom: 20px; padding-bottom: 20px;
@ -2493,6 +2568,11 @@ a.account__display-name {
background-color: $white; background-color: $white;
border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0;
flex: 0 1 auto; flex: 0 1 auto;
@media screen and (max-width: 1550px) {
overflow-y: visible;
}
} }
.autosuggest-textarea__textarea { .autosuggest-textarea__textarea {
@ -2558,12 +2638,12 @@ a.account__display-name {
} }
.drawer__inner__mastodon { .drawer__inner__mastodon {
background: lighten($ui-base-color, 13%) url('data:image/svg+xml;utf8,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 234.80078 31.757813" width="234.80078" height="31.757812"><path d="M19.599609 0c-1.05 0-2.10039.375-2.90039 1.125L0 16.925781v14.832031h234.80078V17.025391l-16.5-15.900391c-1.6-1.5-4.20078-1.5-5.80078 0l-13.80078 13.099609c-1.6 1.5-4.19883 1.5-5.79883 0L179.09961 1.125c-1.6-1.5-4.19883-1.5-5.79883 0L159.5 14.224609c-1.6 1.5-4.20078 1.5-5.80078 0L139.90039 1.125c-1.6-1.5-4.20078-1.5-5.80078 0l-13.79883 13.099609c-1.6 1.5-4.20078 1.5-5.80078 0L100.69922 1.125c-1.600001-1.5-4.198829-1.5-5.798829 0l-13.59961 13.099609c-1.6 1.5-4.200781 1.5-5.800781 0L61.699219 1.125c-1.6-1.5-4.198828-1.5-5.798828 0L42.099609 14.224609c-1.6 1.5-4.198828 1.5-5.798828 0L22.5 1.125C21.7.375 20.649609 0 19.599609 0z" fill="#{hex-color($ui-base-color)}"/></svg>') no-repeat bottom / 100% auto; background: lighten($ui-base-color, 13%);
flex: 1; flex: 1;
min-height: 47px; min-height: 47px;
display: none; display: none;
> img { > img, svg {
display: block; display: block;
object-fit: contain; object-fit: contain;
object-position: bottom left; object-position: bottom left;
@ -2575,7 +2655,7 @@ a.account__display-name {
} }
@media screen and (min-height: 640px) { @media screen and (min-height: 640px) {
display: block; display: flex;
} }
} }
@ -2801,6 +2881,15 @@ a.account__display-name {
border-color: $ui-highlight-color; border-color: $ui-highlight-color;
} }
label[for="is-exclusive-checkbox"] {
margin-left: 20px;
}
.is-exclusive-checkbox {
transform: scale(0.7);
transform-origin: bottom;
}
.column-link { .column-link {
background: lighten($ui-base-color, 8%); background: lighten($ui-base-color, 8%);
color: $primary-text-color; color: $primary-text-color;
@ -3301,7 +3390,7 @@ a.status-card.compact:hover {
} }
&__label { &__label {
margin-top: 30px; margin-top: 0px;
strong { strong {
display: block; display: block;
@ -7257,3 +7346,21 @@ noscript {
text-align: center; text-align: center;
} }
} }
.drawer__inner__mastodon svg#hometownlogo {
box-sizing: border-box;
fill: $secondary-text-color;
margin: 0 0 10px 10px;
align-self: flex-end;
}
div.status__content,
div.status__content--with-action,
div.status__content--with-spoiler {
p {
span.show_more_button {
display: block;
margin: 0.25rem 0 0 0;
}
}
}

View File

@ -257,6 +257,29 @@
} }
} }
.originalhero {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
align-content: space-between;
svg {
fill: $secondary-text-color;
height: 200px;
}
h1 {
flex-grow: 2;
text-align: center;
white-space: nowrap;
font-family: $font-display, sans-serif;
font-size: 0.6rem;
}
}
.public-layout { .public-layout {
@media screen and (max-width: $no-gap-breakpoint) { @media screen and (max-width: $no-gap-breakpoint) {
padding-top: 48px; padding-top: 48px;
@ -322,6 +345,7 @@
.brand { .brand {
display: block; display: block;
padding: 15px; padding: 15px;
white-space: nowrap;
svg { svg {
display: block; display: block;
@ -476,8 +500,42 @@
border-radius: 4px 4px 0 0; border-radius: 4px 4px 0 0;
} }
.originalheader {
width: 100%;
display: flex;
flex-direction: row;
flex-wrap: nowrap;
justify-content: center;
align-items: center;
align-content: space-between;
svg {
fill: $secondary-text-color;
height: 300px;
}
h1 {
flex-grow: 2;
text-align: center;
white-space: nowrap;
font-family: $font-display, sans-serif;
}
}
@media screen and (max-width: 600px) { @media screen and (max-width: 600px) {
height: 200px; height: 200px;
.originalheader {
svg {
height: 200px;
}
h1 {
font-size: 0.5rem;
}
}
} }
} }

View File

@ -15,7 +15,6 @@
> * { > * {
flex: 1; flex: 1;
max-height: 235px; max-height: 235px;
background: url('../images/elephant_ui_plane.svg') no-repeat left bottom / contain;
} }
} }

View File

@ -4,8 +4,8 @@ class ActivityPub::Activity
include JsonLdHelper include JsonLdHelper
include Redisable include Redisable
SUPPORTED_TYPES = %w(Note Question).freeze SUPPORTED_TYPES = %w(Note Question Article).freeze
CONVERTED_TYPES = %w(Image Audio Video Article Page Event).freeze CONVERTED_TYPES = %w(Image Audio Video Page Event).freeze
def initialize(json, account, **options) def initialize(json, account, **options)
@json = json @json = json

View File

@ -77,6 +77,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
@mentions = [] @mentions = []
@params = {} @params = {}
process_inline_images if @object['content'].present? && @object['type'] == 'Article'
process_status_params process_status_params
process_tags process_tags
process_audience process_audience
@ -107,7 +108,7 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
account: @account, account: @account,
text: text_from_content || '', text: text_from_content || '',
language: detected_language, language: detected_language,
spoiler_text: converted_object_type? ? '' : (text_from_summary || ''), spoiler_text: converted_object_type? ? '' : (text_from_summary || (@object['type'] == 'Article' && text_from_name) || ''),
created_at: @object['published'], created_at: @object['published'],
override_timestamps: @options[:override_timestamps], override_timestamps: @options[:override_timestamps],
reply: @object['inReplyTo'].present?, reply: @object['inReplyTo'].present?,
@ -117,10 +118,61 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
conversation: conversation_from_uri(@object['conversation']), conversation: conversation_from_uri(@object['conversation']),
media_attachment_ids: process_attachments.take(4).map(&:id), media_attachment_ids: process_attachments.take(4).map(&:id),
poll: process_poll, poll: process_poll,
activity_pub_type: @object['type']
} }
end end
end end
class Handler < ::Ox::Sax
attr_reader :srcs
attr_reader :alts
def initialize(block)
@stack = []
@srcs = []
@alts = {}
end
def start_element(element_name)
@stack << [element_name, {}]
end
def end_element(element_name)
self_name, self_attributes = @stack[-1]
if self_name == :img && !self_attributes[:src].nil?
@srcs << self_attributes[:src]
@alts[self_attributes[:src]] = self_attributes[:alt]
end
@stack.pop
end
def attr(attribute_name, attribute_value)
_name, attributes = @stack.last
attributes[attribute_name] = attribute_value
end
end
def process_inline_images
proc = Proc.new { |name| puts name }
handler = Handler.new(proc)
Ox.sax_parse(handler, @object['content'])
handler.srcs.each do |src|
if skip_download?
@object['content'].gsub!(src, '')
next
end
media_attachment = MediaAttachment.create(account: @account, remote_url: src, description: handler.alts[src], focus: nil)
media_attachment.file_remote_url = src
media_attachment.save
if unsupported_media_type?(media_attachment.file.content_type)
@object['content'].gsub!(src, '')
media_attachment.delete
else
@object['content'].gsub!(src, media_attachment.file.url(:small))
end
end
end
def process_audience def process_audience
(audience_to + audience_cc).uniq.each do |audience| (audience_to + audience_cc).uniq.each do |audience|
next if audience == ActivityPub::TagManager::COLLECTIONS[:public] next if audience == ActivityPub::TagManager::COLLECTIONS[:public]
@ -391,6 +443,8 @@ class ActivityPub::Activity::Create < ActivityPub::Activity
def text_from_content def text_from_content
return Formatter.instance.linkify([[text_from_name, text_from_summary.presence].compact.join("\n\n"), object_url || object_uri].join(' ')) if converted_object_type? return Formatter.instance.linkify([[text_from_name, text_from_summary.presence].compact.join("\n\n"), object_url || object_uri].join(' ')) if converted_object_type?
return Formatter.instance.format_article(@object['content']) if @object['content'].present? && @object['type'] == 'Article'
if @object['content'].present? if @object['content'].present?
@object['content'] @object['content']
elsif content_language_map? elsif content_language_map?

View File

@ -40,9 +40,9 @@ class FeedManager
def filter?(timeline_type, status, receiver) def filter?(timeline_type, status, receiver)
case timeline_type case timeline_type
when :home when :home
filter_from_home?(status, receiver.id, build_crutches(receiver.id, [status])) filter_from_home?(status, receiver.id, build_crutches(receiver.id, [status]), :home)
when :list when :list
filter_from_list?(status, receiver) || filter_from_home?(status, receiver.account_id, build_crutches(receiver.account_id, [status])) filter_from_list?(status, receiver) || filter_from_home?(status, receiver.account_id, build_crutches(receiver.account_id, [status]), :list)
when :mentions when :mentions
filter_from_mentions?(status, receiver.id) filter_from_mentions?(status, receiver.id)
else else
@ -315,10 +315,17 @@ class FeedManager
# @param [Integer] receiver_id # @param [Integer] receiver_id
# @param [Hash] crutches # @param [Hash] crutches
# @return [Boolean] # @return [Boolean]
def filter_from_home?(status, receiver_id, crutches) def filter_from_home?(status, receiver_id, crutches, timeline_type=:home)
return false if receiver_id == status.account_id return false if receiver_id == status.account_id
return true if status.reply? && (status.in_reply_to_id.nil? || status.in_reply_to_account_id.nil?) return true if status.reply? && (status.in_reply_to_id.nil? || status.in_reply_to_account_id.nil?)
return true if phrase_filtered?(status, receiver_id, :home) return true if phrase_filtered?(status, receiver_id, :home)
# hometown: exclusive list rules
unless timeline_type == :list
# find all exclusive lists
@list = List.where(account: Account.find(receiver_id), is_exclusive: true)
# is there a list the receiver owns with this account on it? if so, return true
return true if ListAccount.where(list: @list, account_id: status.account_id).exists?
end
check_for_blocks = crutches[:active_mentions][status.id] || [] check_for_blocks = crutches[:active_mentions][status.id] || []
check_for_blocks.concat([status.account_id]) check_for_blocks.concat([status.account_id])

View File

@ -91,6 +91,12 @@ class Formatter
html.html_safe # rubocop:disable Rails/OutputSafety html.html_safe # rubocop:disable Rails/OutputSafety
end end
def format_article(text)
text = text.gsub(/>\n+</, "><")
text = "<span class='article-type'>#{text}</span>"
text.html_safe # rubocop:disable Rails/OutputSafety
end
def linkify(text) def linkify(text)
html = encode_and_link_urls(text) html = encode_and_link_urls(text)
html = simple_format(html, {}, sanitize: false) html = simple_format(html, {}, sanitize: false)

View File

@ -71,11 +71,14 @@ class Sanitize
end end
MASTODON_STRICT ||= freeze_config( MASTODON_STRICT ||= freeze_config(
elements: %w(p br span a), elements: %w(p br span a abbr del pre blockquote code b strong i em h1 h2 h3 h4 h5 ul ol li img),
attributes: { attributes: {
'a' => %w(href rel class), 'a' => %w(href rel class title),
'span' => %w(class), 'span' => %w(class),
'abbr' => %w(title),
'blockquote' => %w(cite),
'img' => %w(src alt),
}, },
add_attributes: { add_attributes: {
@ -83,9 +86,15 @@ class Sanitize
'rel' => 'nofollow noopener noreferrer', 'rel' => 'nofollow noopener noreferrer',
'target' => '_blank', 'target' => '_blank',
}, },
'span' => {
'class' => 'article-type',
},
}, },
protocols: {}, protocols: {
'a' => { 'href' => HTTP_PROTOCOLS },
'blockquote' => { 'cite' => HTTP_PROTOCOLS },
},
transformers: [ transformers: [
CLASS_WHITELIST_TRANSFORMER, CLASS_WHITELIST_TRANSFORMER,

View File

@ -19,7 +19,7 @@ class UserMailer < Devise::Mailer
I18n.with_locale(@resource.locale || I18n.default_locale) do I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.unconfirmed_email.presence || @resource.email, mail to: @resource.unconfirmed_email.presence || @resource.email,
subject: I18n.t(@resource.pending_reconfirmation? ? 'devise.mailer.reconfirmation_instructions.subject' : 'devise.mailer.confirmation_instructions.subject', instance: @instance), subject: I18n.t(@resource.pending_reconfirmation? ? 'devise.mailer.reconfirmation_instructions.subject' : 'devise.mailer.confirmation_instructions.subject', instance: @instance, title: Setting.site_title),
template_name: @resource.pending_reconfirmation? ? 'reconfirmation_instructions' : 'confirmation_instructions' template_name: @resource.pending_reconfirmation? ? 'reconfirmation_instructions' : 'confirmation_instructions'
end end
end end
@ -32,7 +32,7 @@ class UserMailer < Devise::Mailer
return unless @resource.active_for_authentication? return unless @resource.active_for_authentication?
I18n.with_locale(@resource.locale || I18n.default_locale) do I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.reset_password_instructions.subject') mail to: @resource.email, subject: I18n.t('devise.mailer.reset_password_instructions.subject', title: Setting.site_title)
end end
end end
@ -43,7 +43,7 @@ class UserMailer < Devise::Mailer
return unless @resource.active_for_authentication? return unless @resource.active_for_authentication?
I18n.with_locale(@resource.locale || I18n.default_locale) do I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.password_change.subject') mail to: @resource.email, subject: I18n.t('devise.mailer.password_change.subject', title: Setting.site_title)
end end
end end
@ -54,7 +54,7 @@ class UserMailer < Devise::Mailer
return unless @resource.active_for_authentication? return unless @resource.active_for_authentication?
I18n.with_locale(@resource.locale || I18n.default_locale) do I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('devise.mailer.email_changed.subject') mail to: @resource.email, subject: I18n.t('devise.mailer.email_changed.subject', title: Setting.site_title)
end end
end end
@ -144,7 +144,7 @@ class UserMailer < Devise::Mailer
return unless @resource.active_for_authentication? return unless @resource.active_for_authentication?
I18n.with_locale(@resource.locale || I18n.default_locale) do I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('user_mailer.welcome.subject') mail to: @resource.email, subject: I18n.t('user_mailer.welcome.subject', title: Setting.site_title)
end end
end end
@ -156,7 +156,7 @@ class UserMailer < Devise::Mailer
return unless @resource.active_for_authentication? return unless @resource.active_for_authentication?
I18n.with_locale(@resource.locale || I18n.default_locale) do I18n.with_locale(@resource.locale || I18n.default_locale) do
mail to: @resource.email, subject: I18n.t('user_mailer.backup_ready.subject') mail to: @resource.email, subject: I18n.t('user_mailer.backup_ready.subject', title: Setting.site_title)
end end
end end

View File

@ -9,6 +9,7 @@
# created_at :datetime not null # created_at :datetime not null
# updated_at :datetime not null # updated_at :datetime not null
# replies_policy :integer default("list"), not null # replies_policy :integer default("list"), not null
# is_exclusive :boolean default(FALSE)
# #
class List < ApplicationRecord class List < ApplicationRecord

View File

@ -24,6 +24,7 @@
# poll_id :bigint(8) # poll_id :bigint(8)
# deleted_at :datetime # deleted_at :datetime
# local_only :boolean # local_only :boolean
# activity_pub_type :string
# #
class Status < ApplicationRecord class Status < ApplicationRecord

View File

@ -2,10 +2,15 @@
class InitialStateSerializer < ActiveModel::Serializer class InitialStateSerializer < ActiveModel::Serializer
attributes :meta, :compose, :accounts, attributes :meta, :compose, :accounts,
:media_attachments, :settings :media_attachments, :settings,
:max_toot_chars
has_one :push_subscription, serializer: REST::WebPushSubscriptionSerializer has_one :push_subscription, serializer: REST::WebPushSubscriptionSerializer
def max_toot_chars
StatusLengthValidator::MAX_CHARS
end
def meta def meta
store = { store = {
streaming_api_base_url: Rails.configuration.x.streaming_api_base_url, streaming_api_base_url: Rails.configuration.x.streaming_api_base_url,

View File

@ -4,7 +4,7 @@ class REST::InstanceSerializer < ActiveModel::Serializer
include RoutingHelper include RoutingHelper
attributes :uri, :title, :short_description, :description, :email, attributes :uri, :title, :short_description, :description, :email,
:version, :urls, :stats, :thumbnail, :version, :urls, :stats, :thumbnail, :max_toot_chars,
:languages, :registrations, :approval_required, :invites_enabled :languages, :registrations, :approval_required, :invites_enabled
has_one :contact_account, serializer: REST::AccountSerializer has_one :contact_account, serializer: REST::AccountSerializer
@ -39,6 +39,10 @@ class REST::InstanceSerializer < ActiveModel::Serializer
instance_presenter.thumbnail ? full_asset_url(instance_presenter.thumbnail.file.url) : full_pack_url('media/images/preview.jpg') instance_presenter.thumbnail ? full_asset_url(instance_presenter.thumbnail.file.url) : full_pack_url('media/images/preview.jpg')
end end
def max_toot_chars
StatusLengthValidator::MAX_CHARS
end
def stats def stats
{ {
user_count: instance_presenter.user_count, user_count: instance_presenter.user_count,

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class REST::ListSerializer < ActiveModel::Serializer class REST::ListSerializer < ActiveModel::Serializer
attributes :id, :title, :replies_policy attributes :id, :title, :replies_policy, :is_exclusive
def id def id
object.id.to_s object.id.to_s

View File

@ -4,7 +4,7 @@ class REST::StatusSerializer < ActiveModel::Serializer
attributes :id, :created_at, :in_reply_to_id, :in_reply_to_account_id, attributes :id, :created_at, :in_reply_to_id, :in_reply_to_account_id,
:sensitive, :spoiler_text, :visibility, :language, :sensitive, :spoiler_text, :visibility, :language,
:uri, :url, :replies_count, :reblogs_count, :uri, :url, :replies_count, :reblogs_count,
:favourites_count, :local_only :favourites_count, :local_only, :activity_pub_type
attribute :favourited, if: :current_user? attribute :favourited, if: :current_user?
attribute :reblogged, if: :current_user? attribute :reblogged, if: :current_user?
@ -70,6 +70,10 @@ class REST::StatusSerializer < ActiveModel::Serializer
ActivityPub::TagManager.instance.uri_for(object) ActivityPub::TagManager.instance.uri_for(object)
end end
def activity_pub_type
object.activity_pub_type.to_s
end
def content def content
Formatter.instance.format(object) Formatter.instance.format(object)
end end

View File

@ -87,9 +87,21 @@ class PostStatusService < BaseService
end end
end end
def local_only_option(local_only, in_reply_to, federation_setting) def local_only_option(local_only, in_reply_to, federation_setting, text)
return in_reply_to&.local_only? if local_only.nil? # XXX temporary, just until clients implement to avoid leaking local_only posts # This is intended for third party clients. The admin can set a custom :local_only:
return federation_setting if local_only.nil? # emoji that users can append to force a post to be local only.
if text.include? ":local_only:"
return true
end
if local_only.nil?
if in_reply_to && in_reply_to.local_only
return true
end
if in_reply_to && !in_reply_to.local_only
return false
end
return !federation_setting
end
local_only local_only
end end
@ -172,7 +184,7 @@ class PostStatusService < BaseService
language: language_from_option(@options[:language]) || @account.user&.setting_default_language&.presence || LanguageDetector.instance.detect(@text, @account), language: language_from_option(@options[:language]) || @account.user&.setting_default_language&.presence || LanguageDetector.instance.detect(@text, @account),
application: @options[:application], application: @options[:application],
rate_limit: @options[:with_rate_limit], rate_limit: @options[:with_rate_limit],
local_only: local_only_option(@options[:local_only], @in_reply_to, @account.user&.setting_default_federation), local_only: local_only_option(@options[:local_only], @in_reply_to, @account.user&.setting_default_federation, @text),
}.compact }.compact
end end

View File

@ -1,7 +1,7 @@
# frozen_string_literal: true # frozen_string_literal: true
class StatusLengthValidator < ActiveModel::Validator class StatusLengthValidator < ActiveModel::Validator
MAX_CHARS = 500 MAX_CHARS = (ENV['MAX_TOOT_CHARS'] || 500).to_i
def validate(status) def validate(status)
return unless status.local? && !status.reblog? return unless status.local? && !status.reblog?

View File

@ -1,6 +1,6 @@
.simple_form__overlay-area{ class: (closed_registrations? && @instance_presenter.closed_registrations_message.present?) ? 'simple_form__overlay-area__blurred' : '' } .simple_form__overlay-area{ class: (closed_registrations? && @instance_presenter.closed_registrations_message.present?) ? 'simple_form__overlay-area__blurred' : '' }
= simple_form_for(new_user, url: user_registration_path, namespace: 'registration', html: { novalidate: false }) do |f| = simple_form_for(new_user, url: user_registration_path, namespace: 'registration', html: { novalidate: false }) do |f|
%p.lead= t('about.federation_hint_html', instance: content_tag(:strong, site_hostname)) %p.lead= t('about.federation_hint_html', instance: content_tag(:strong, site_title))
.fields-group .fields-group
= f.simple_fields_for :account do |account_fields| = f.simple_fields_for :account do |account_fields|

View File

@ -9,7 +9,14 @@
.column-0 .column-0
.public-account-header.public-account-header--no-bar .public-account-header.public-account-header--no-bar
.public-account-header__image .public-account-header__image
= image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.jpg'), alt: @instance_presenter.site_title, class: 'parallax' - if @instance_presenter.hero.present? || @instance_presenter.thumbnail.present?
= image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url, alt: @instance_presenter.site_title, class: 'parallax'
- else
%div{:class => ("originalheader")}
= svg_logo
%h1
= link_to root_url, class: 'brand' do
= site_title
.column-1 .column-1
.landing-page__call-to-action{ dir: 'ltr' } .landing-page__call-to-action{ dir: 'ltr' }
@ -24,8 +31,13 @@
%strong= number_to_human @instance_presenter.status_count, strip_insignificant_zeros: true %strong= number_to_human @instance_presenter.status_count, strip_insignificant_zeros: true
%span= t 'about.status_count_after', count: @instance_presenter.status_count %span= t 'about.status_count_after', count: @instance_presenter.status_count
.row__mascot .row__mascot
.landing-page__mascot - if @instance_presenter.mascot&.file&.url
= image_tag @instance_presenter.mascot&.file&.url || asset_pack_path('media/images/elephant_ui_plane.svg'), alt: '' .landing-page__mascot
= image_tag @instance_presenter.mascot&.file&.url
- else
.landing-page__mascot{:class => ("originalmascot")}
%div{:class => ("originalmascotimg")}
= svg_logo
.column-2 .column-2
.contact-widget .contact-widget

View File

@ -7,9 +7,9 @@
.landing .landing
.landing__brand .landing__brand
= link_to root_url, class: 'brand' do %h1
= svg_logo_full = link_to root_url, class: 'brand' do
%span.brand__tagline=t 'about.tagline' = site_title
.landing__grid .landing__grid
.landing__grid__column.landing__grid__column-registration .landing__grid__column.landing__grid__column-registration
@ -35,22 +35,29 @@
%h4 %h4
= fa_icon 'globe fw' = fa_icon 'globe fw'
= t('about.see_whats_happening') = t('about.see_whats_happening')
%small= t('about.browse_public_posts') %small= t('about.browse_public_posts', title: site_title)
.directory__tag .directory__tag
= link_to 'https://joinmastodon.org/apps', target: '_blank', rel: 'noopener noreferrer' do = link_to 'https://joinmastodon.org/apps', target: '_blank', rel: 'noopener noreferrer' do
%h4 %h4
= fa_icon 'tablet fw' = fa_icon 'tablet fw'
= t('about.get_apps') = t('about.get_apps')
%small= t('about.apps_platforms') %small= t('about.apps_platforms', title: site_title)
.landing__grid__column.landing__grid__column-login .landing__grid__column.landing__grid__column-login
.box-widget .box-widget
= render 'login' = render 'login'
.hero-widget .hero-widget
.hero-widget__img - if @instance_presenter.hero.present? || @instance_presenter.thumbnail.present?
= image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.jpg'), alt: @instance_presenter.site_title .hero-widget__img
= image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url, alt: @instance_presenter.site_title
- else
%div{:class => ("originalhero")}
= svg_logo
%h1
= link_to root_url, class: 'brand' do
= site_title
.hero-widget__text .hero-widget__text
%p %p

View File

@ -77,7 +77,7 @@
%h4= t 'admin.dashboard.software' %h4= t 'admin.dashboard.software'
%ul %ul
%li %li
Mastodon Hometown
%span.pull-right= @version %span.pull-right= @version
%li %li
Ruby Ruby

View File

@ -1,6 +1,7 @@
.hero-widget .hero-widget
.hero-widget__img - if @instance_presenter.hero.present? || @instance_presenter.thumbnail.present?
= image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url || asset_pack_path('media/images/preview.jpg'), alt: @instance_presenter.site_title .hero-widget__img
= image_tag @instance_presenter.hero&.file&.url || @instance_presenter.thumbnail&.file&.url, alt: @instance_presenter.site_title
.hero-widget__text .hero-widget__text
%p= @instance_presenter.site_short_description.html_safe.presence || t('about.about_mastodon_html') %p= @instance_presenter.site_short_description.html_safe.presence || t('about.about_mastodon_html')

View File

@ -1,5 +1,5 @@
%h3= t 'sessions.title' %h3= t 'sessions.title'
%p.muted-hint= t 'sessions.explanation' %p.muted-hint= t('sessions.explanation', title: site_title)
%hr.spacer/ %hr.spacer/

View File

@ -10,7 +10,7 @@
.app-holder#mastodon{ data: { props: Oj.dump(default_props) } } .app-holder#mastodon{ data: { props: Oj.dump(default_props) } }
%noscript %noscript
= image_pack_tag 'logo.svg', alt: 'Mastodon' = image_pack_tag 'logo.svg', alt: site_title
%div %div
= t('errors.noscript_html', apps_path: 'https://joinmastodon.org/apps') = t('errors.noscript_html', apps_path: 'https://joinmastodon.org/apps', title: site_title)

Some files were not shown because too many files have changed in this diff Show More