diff options
Diffstat (limited to 'app/javascript')
17 files changed, 396 insertions, 214 deletions
diff --git a/app/javascript/mastodon/actions/compose.js b/app/javascript/mastodon/actions/compose.js index 24e64e06c..3ee9e1e7b 100644 --- a/app/javascript/mastodon/actions/compose.js +++ b/app/javascript/mastodon/actions/compose.js @@ -8,6 +8,7 @@ import { refreshHomeTimeline, refreshCommunityTimeline, refreshPublicTimeline, + refreshDirectTimeline, } from './timelines'; export const COMPOSE_CHANGE = 'COMPOSE_CHANGE'; @@ -133,6 +134,8 @@ export function submitCompose() { if (response.data.in_reply_to_id === null && response.data.visibility === 'public') { insertOrRefresh('community', refreshCommunityTimeline); insertOrRefresh('public', refreshPublicTimeline); + } else if (response.data.visibility === 'direct') { + insertOrRefresh('direct', refreshDirectTimeline); } }).catch(function (error) { dispatch(submitComposeFail(error)); diff --git a/app/javascript/mastodon/actions/streaming.js b/app/javascript/mastodon/actions/streaming.js index 7802694a3..a2e25c930 100644 --- a/app/javascript/mastodon/actions/streaming.js +++ b/app/javascript/mastodon/actions/streaming.js @@ -92,3 +92,4 @@ export const connectCommunityStream = () => connectTimelineStream('community', ' export const connectMediaStream = () => connectTimelineStream('community', 'public:local'); export const connectPublicStream = () => connectTimelineStream('public', 'public'); export const connectHashtagStream = (tag) => connectTimelineStream(`hashtag:${tag}`, `hashtag&tag=${tag}`); +export const connectDirectStream = () => connectTimelineStream('direct', 'direct'); diff --git a/app/javascript/mastodon/actions/timelines.js b/app/javascript/mastodon/actions/timelines.js index 09abe2702..935bbb6f0 100644 --- a/app/javascript/mastodon/actions/timelines.js +++ b/app/javascript/mastodon/actions/timelines.js @@ -115,6 +115,7 @@ export function refreshTimeline(timelineId, path, params = {}) { export const refreshHomeTimeline = () => refreshTimeline('home', '/api/v1/timelines/home'); export const refreshPublicTimeline = () => refreshTimeline('public', '/api/v1/timelines/public'); export const refreshCommunityTimeline = () => refreshTimeline('community', '/api/v1/timelines/public', { local: true }); +export const refreshDirectTimeline = () => refreshTimeline('direct', '/api/v1/timelines/direct'); export const refreshAccountTimeline = accountId => refreshTimeline(`account:${accountId}`, `/api/v1/accounts/${accountId}/statuses`); export const refreshAccountMediaTimeline = accountId => refreshTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { only_media: true }); export const refreshHashtagTimeline = hashtag => refreshTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`); @@ -155,6 +156,7 @@ export function expandTimeline(timelineId, path, params = {}) { export const expandHomeTimeline = () => expandTimeline('home', '/api/v1/timelines/home'); export const expandPublicTimeline = () => expandTimeline('public', '/api/v1/timelines/public'); export const expandCommunityTimeline = () => expandTimeline('community', '/api/v1/timelines/public', { local: true }); +export const expandDirectTimeline = () => expandTimeline('direct', '/api/v1/timelines/direct'); export const expandAccountTimeline = accountId => expandTimeline(`account:${accountId}`, `/api/v1/accounts/${accountId}/statuses`); export const expandAccountMediaTimeline = accountId => expandTimeline(`account:${accountId}:media`, `/api/v1/accounts/${accountId}/statuses`, { only_media: true }); export const expandHashtagTimeline = hashtag => expandTimeline(`hashtag:${hashtag}`, `/api/v1/timelines/tag/${hashtag}`); diff --git a/app/javascript/mastodon/components/column_header.js b/app/javascript/mastodon/components/column_header.js index c47296a51..71530ffdd 100644 --- a/app/javascript/mastodon/components/column_header.js +++ b/app/javascript/mastodon/components/column_header.js @@ -175,7 +175,9 @@ export default class ColumnHeader extends React.PureComponent { <div className={wrapperClassName}> <h1 tabIndex={focusable ? 0 : null} role='button' className={buttonClassName} aria-label={title} onClick={this.handleTitleClick}> <i className={`fa fa-fw fa-${icon} column-header__icon`} /> - {title} + <span className='column-header__title'> + {title} + </span> <div className='column-header__buttons'> {backButton} { notifCleaning ? ( diff --git a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js index 71944128c..699687c69 100644 --- a/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js +++ b/app/javascript/mastodon/features/compose/containers/emoji_picker_dropdown_container.js @@ -46,7 +46,7 @@ const getFrequentlyUsedEmojis = createSelector([ const getCustomEmojis = createSelector([ state => state.get('custom_emojis'), -], emojis => emojis.sort((a, b) => { +], emojis => emojis.filter(e => e.get('visible_in_picker')).sort((a, b) => { const aShort = a.get('shortcode').toLowerCase(); const bShort = b.get('shortcode').toLowerCase(); diff --git a/app/javascript/mastodon/features/direct_timeline/containers/column_settings_container.js b/app/javascript/mastodon/features/direct_timeline/containers/column_settings_container.js new file mode 100644 index 000000000..1833f69e5 --- /dev/null +++ b/app/javascript/mastodon/features/direct_timeline/containers/column_settings_container.js @@ -0,0 +1,17 @@ +import { connect } from 'react-redux'; +import ColumnSettings from '../../community_timeline/components/column_settings'; +import { changeSetting } from '../../../actions/settings'; + +const mapStateToProps = state => ({ + settings: state.getIn(['settings', 'direct']), +}); + +const mapDispatchToProps = dispatch => ({ + + onChange (key, checked) { + dispatch(changeSetting(['direct', ...key], checked)); + }, + +}); + +export default connect(mapStateToProps, mapDispatchToProps)(ColumnSettings); diff --git a/app/javascript/mastodon/features/direct_timeline/index.js b/app/javascript/mastodon/features/direct_timeline/index.js new file mode 100644 index 000000000..05e092ee0 --- /dev/null +++ b/app/javascript/mastodon/features/direct_timeline/index.js @@ -0,0 +1,107 @@ +import React from 'react'; +import { connect } from 'react-redux'; +import PropTypes from 'prop-types'; +import StatusListContainer from '../ui/containers/status_list_container'; +import Column from '../../components/column'; +import ColumnHeader from '../../components/column_header'; +import { + refreshDirectTimeline, + expandDirectTimeline, +} from '../../actions/timelines'; +import { addColumn, removeColumn, moveColumn } from '../../actions/columns'; +import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; +import ColumnSettingsContainer from './containers/column_settings_container'; +import { connectDirectStream } from '../../actions/streaming'; + +const messages = defineMessages({ + title: { id: 'column.direct', defaultMessage: 'Direct messages' }, +}); + +const mapStateToProps = state => ({ + hasUnread: state.getIn(['timelines', 'direct', 'unread']) > 0, +}); + +@connect(mapStateToProps) +@injectIntl +export default class DirectTimeline extends React.PureComponent { + + static propTypes = { + dispatch: PropTypes.func.isRequired, + columnId: PropTypes.string, + intl: PropTypes.object.isRequired, + hasUnread: PropTypes.bool, + multiColumn: PropTypes.bool, + }; + + handlePin = () => { + const { columnId, dispatch } = this.props; + + if (columnId) { + dispatch(removeColumn(columnId)); + } else { + dispatch(addColumn('DIRECT', {})); + } + } + + handleMove = (dir) => { + const { columnId, dispatch } = this.props; + dispatch(moveColumn(columnId, dir)); + } + + handleHeaderClick = () => { + this.column.scrollTop(); + } + + componentDidMount () { + const { dispatch } = this.props; + + dispatch(refreshDirectTimeline()); + this.disconnect = dispatch(connectDirectStream()); + } + + componentWillUnmount () { + if (this.disconnect) { + this.disconnect(); + this.disconnect = null; + } + } + + setRef = c => { + this.column = c; + } + + handleLoadMore = () => { + this.props.dispatch(expandDirectTimeline()); + } + + render () { + const { intl, hasUnread, columnId, multiColumn } = this.props; + const pinned = !!columnId; + + return ( + <Column ref={this.setRef}> + <ColumnHeader + icon='envelope' + active={hasUnread} + title={intl.formatMessage(messages.title)} + onPin={this.handlePin} + onMove={this.handleMove} + onClick={this.handleHeaderClick} + pinned={pinned} + multiColumn={multiColumn} + > + <ColumnSettingsContainer /> + </ColumnHeader> + + <StatusListContainer + trackScroll={!pinned} + scrollKey={`direct_timeline-${columnId}`} + timelineId='direct' + loadMore={this.handleLoadMore} + emptyMessage={<FormattedMessage id='empty_column.direct' defaultMessage="You don't have any direct messages yet. When you send or receive one, it will show up here." />} + /> + </Column> + ); + } + +} diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js index 68267c54f..9b94b9830 100644 --- a/app/javascript/mastodon/features/getting_started/index.js +++ b/app/javascript/mastodon/features/getting_started/index.js @@ -17,6 +17,7 @@ const messages = defineMessages({ navigation_subheading: { id: 'column_subheading.navigation', defaultMessage: 'Navigation' }, settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' }, community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' }, + direct: { id: 'navigation_bar.direct', defaultMessage: 'Direct messages' }, preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' }, settings: { id: 'navigation_bar.app_settings', defaultMessage: 'App settings' }, follow_requests: { id: 'navigation_bar.follow_requests', defaultMessage: 'Follow requests' }, @@ -78,18 +79,22 @@ export default class GettingStarted extends ImmutablePureComponent { } } + if (!multiColumn || !columns.find(item => item.get('id') === 'DIRECT')) { + navItems.push(<ColumnLink key='4' icon='envelope' text={intl.formatMessage(messages.direct)} to='/timelines/direct' />); + } + navItems = navItems.concat([ - <ColumnLink key='4' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />, - <ColumnLink key='5' icon='thumb-tack' text={intl.formatMessage(messages.pins)} to='/pinned' />, + <ColumnLink key='5' icon='star' text={intl.formatMessage(messages.favourites)} to='/favourites' />, + <ColumnLink key='6' icon='thumb-tack' text={intl.formatMessage(messages.pins)} to='/pinned' />, ]); if (me.get('locked')) { - navItems.push(<ColumnLink key='6' icon='users' text={intl.formatMessage(messages.follow_requests)} to='/follow_requests' />); + navItems.push(<ColumnLink key='7' icon='users' text={intl.formatMessage(messages.follow_requests)} to='/follow_requests' />); } navItems = navItems.concat([ - <ColumnLink key='7' icon='volume-off' text={intl.formatMessage(messages.mutes)} to='/mutes' />, - <ColumnLink key='8' icon='ban' text={intl.formatMessage(messages.blocks)} to='/blocks' />, + <ColumnLink key='8' icon='volume-off' text={intl.formatMessage(messages.mutes)} to='/mutes' />, + <ColumnLink key='9' icon='ban' text={intl.formatMessage(messages.blocks)} to='/blocks' />, ]); return ( diff --git a/app/javascript/mastodon/features/ui/components/columns_area.js b/app/javascript/mastodon/features/ui/components/columns_area.js index 5610095b9..ee1064229 100644 --- a/app/javascript/mastodon/features/ui/components/columns_area.js +++ b/app/javascript/mastodon/features/ui/components/columns_area.js @@ -11,7 +11,7 @@ import BundleContainer from '../containers/bundle_container'; import ColumnLoading from './column_loading'; import DrawerLoading from './drawer_loading'; import BundleColumnError from './bundle_column_error'; -import { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, FavouritedStatuses } from '../../ui/util/async-components'; +import { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, DirectTimeline, FavouritedStatuses } from '../../ui/util/async-components'; import detectPassiveEvents from 'detect-passive-events'; import { scrollRight } from '../../../scroll'; @@ -23,6 +23,7 @@ const componentMap = { 'PUBLIC': PublicTimeline, 'COMMUNITY': CommunityTimeline, 'HASHTAG': HashtagTimeline, + 'DIRECT': DirectTimeline, 'FAVOURITES': FavouritedStatuses, }; diff --git a/app/javascript/mastodon/features/ui/index.js b/app/javascript/mastodon/features/ui/index.js index 883bfe055..9f77ab5aa 100644 --- a/app/javascript/mastodon/features/ui/index.js +++ b/app/javascript/mastodon/features/ui/index.js @@ -29,6 +29,7 @@ import { Following, Reblogs, Favourites, + DirectTimeline, HashtagTimeline, Notifications, FollowRequests, @@ -71,6 +72,7 @@ const keyMap = { goToNotifications: 'g n', goToLocal: 'g l', goToFederated: 'g t', + goToDirect: 'g d', goToStart: 'g s', goToFavourites: 'g f', goToPinned: 'g p', @@ -302,6 +304,10 @@ export default class UI extends React.Component { this.context.router.history.push('/timelines/public'); } + handleHotkeyGoToDirect = () => { + this.context.router.history.push('/timelines/direct'); + } + handleHotkeyGoToStart = () => { this.context.router.history.push('/getting-started'); } @@ -357,6 +363,7 @@ export default class UI extends React.Component { goToNotifications: this.handleHotkeyGoToNotifications, goToLocal: this.handleHotkeyGoToLocal, goToFederated: this.handleHotkeyGoToFederated, + goToDirect: this.handleHotkeyGoToDirect, goToStart: this.handleHotkeyGoToStart, goToFavourites: this.handleHotkeyGoToFavourites, goToPinned: this.handleHotkeyGoToPinned, @@ -377,6 +384,7 @@ export default class UI extends React.Component { <WrappedRoute path='/timelines/home' component={HomeTimeline} content={children} /> <WrappedRoute path='/timelines/public' exact component={PublicTimeline} content={children} /> <WrappedRoute path='/timelines/public/local' component={CommunityTimeline} content={children} /> + <WrappedRoute path='/timelines/direct' component={DirectTimeline} content={children} /> <WrappedRoute path='/timelines/tag/:id' component={HashtagTimeline} content={children} /> <WrappedRoute path='/notifications' component={Notifications} content={children} /> diff --git a/app/javascript/mastodon/features/ui/util/async-components.js b/app/javascript/mastodon/features/ui/util/async-components.js index 7f2b303a7..dc8e9dfb9 100644 --- a/app/javascript/mastodon/features/ui/util/async-components.js +++ b/app/javascript/mastodon/features/ui/util/async-components.js @@ -26,6 +26,10 @@ export function HashtagTimeline () { return import(/* webpackChunkName: "features/hashtag_timeline" */'../../hashtag_timeline'); } +export function DirectTimeline() { + return import(/* webpackChunkName: "features/direct_timeline" */'../../direct_timeline'); +} + export function Status () { return import(/* webpackChunkName: "features/status" */'../../status'); } diff --git a/app/javascript/mastodon/locales/defaultMessages.json b/app/javascript/mastodon/locales/defaultMessages.json index f400b283f..ebb514e69 100644 --- a/app/javascript/mastodon/locales/defaultMessages.json +++ b/app/javascript/mastodon/locales/defaultMessages.json @@ -758,6 +758,19 @@ { "descriptors": [ { + "defaultMessage": "Direct messages", + "id": "column.direct" + }, + { + "defaultMessage": "You don't have any direct messages yet. When you send or receive one, it will show up here.", + "id": "empty_column.direct" + } + ], + "path": "app/javascript/mastodon/features/direct_timeline/index.json" + }, + { + "descriptors": [ + { "defaultMessage": "Favourites", "id": "column.favourites" } @@ -817,6 +830,10 @@ "id": "navigation_bar.community_timeline" }, { + "defaultMessage": "Direct messages", + "id": "navigation_bar.direct" + }, + { "defaultMessage": "Preferences", "id": "navigation_bar.preferences" }, diff --git a/app/javascript/mastodon/locales/en.json b/app/javascript/mastodon/locales/en.json index 1d0bbcee5..efe0e1de9 100644 --- a/app/javascript/mastodon/locales/en.json +++ b/app/javascript/mastodon/locales/en.json @@ -28,6 +28,7 @@ "bundle_modal_error.retry": "Try again", "column.blocks": "Blocked users", "column.community": "Local timeline", + "column.direct": "Direct messages", "column.favourites": "Favourites", "column.follow_requests": "Follow requests", "column.home": "Home", @@ -80,6 +81,7 @@ "emoji_button.symbols": "Symbols", "emoji_button.travel": "Travel & Places", "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.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.public_timeline": "the public timeline", @@ -106,6 +108,7 @@ "missing_indicator.label": "Not found", "navigation_bar.blocks": "Blocked users", "navigation_bar.community_timeline": "Local timeline", + "navigation_bar.direct": "Direct messages", "navigation_bar.edit_profile": "Edit profile", "navigation_bar.favourites": "Favourites", "navigation_bar.follow_requests": "Follow requests", diff --git a/app/javascript/mastodon/locales/eo.json b/app/javascript/mastodon/locales/eo.json index 22639f6f9..3f67a8fff 100644 --- a/app/javascript/mastodon/locales/eo.json +++ b/app/javascript/mastodon/locales/eo.json @@ -1,221 +1,221 @@ { "account.block": "Bloki @{name}", - "account.block_domain": "Hide everything from {domain}", - "account.disclaimer_full": "Information below may reflect the user's profile incompletely.", + "account.block_domain": "Kaŝi ĉion el {domain}", + "account.disclaimer_full": "La ĉi-subaj informoj povas ne plene reflekti la profilon de la uzanto.", "account.edit_profile": "Redakti la profilon", "account.follow": "Sekvi", "account.followers": "Sekvantoj", "account.follows": "Sekvatoj", "account.follows_you": "Sekvas vin", - "account.media": "Media", + "account.media": "Sonbildaĵoj", "account.mention": "Mencii @{name}", - "account.mute": "Mute @{name}", + "account.mute": "Silentigi @{name}", "account.posts": "Mesaĝoj", - "account.report": "Report @{name}", + "account.report": "Signali @{name}", "account.requested": "Atendas aprobon", - "account.share": "Share @{name}'s profile", + "account.share": "Diskonigi la profilon de @{name}", "account.unblock": "Malbloki @{name}", - "account.unblock_domain": "Unhide {domain}", - "account.unfollow": "Malsekvi", - "account.unmute": "Unmute @{name}", - "account.view_full_profile": "View full profile", - "boost_modal.combo": "You can press {combo} to skip this next time", - "bundle_column_error.body": "Something went wrong while loading this component.", - "bundle_column_error.retry": "Try again", - "bundle_column_error.title": "Network error", - "bundle_modal_error.close": "Close", - "bundle_modal_error.message": "Something went wrong while loading this component.", - "bundle_modal_error.retry": "Try again", - "column.blocks": "Blocked users", + "account.unblock_domain": "Malkaŝi {domain}", + "account.unfollow": "Ne plus sekvi", + "account.unmute": "Malsilentigi @{name}", + "account.view_full_profile": "Vidi plenan profilon", + "boost_modal.combo": "La proksiman fojon, premu {combo} por pasigi", + "bundle_column_error.body": "Io malfunkciis ŝargante tiun ĉi komponanton.", + "bundle_column_error.retry": "Bonvolu reprovi", + "bundle_column_error.title": "Reta eraro", + "bundle_modal_error.close": "Fermi", + "bundle_modal_error.message": "Io malfunkciis ŝargante tiun ĉi komponanton.", + "bundle_modal_error.retry": "Bonvolu reprovi", + "column.blocks": "Blokitaj uzantoj", "column.community": "Loka tempolinio", - "column.favourites": "Favourites", - "column.follow_requests": "Follow requests", + "column.favourites": "Favoritoj", + "column.follow_requests": "Abonpetoj", "column.home": "Hejmo", - "column.mutes": "Muted users", + "column.mutes": "Silentigitaj uzantoj", "column.notifications": "Sciigoj", - "column.pins": "Pinned toot", + "column.pins": "Alpinglitaj pepoj", "column.public": "Fratara tempolinio", "column_back_button.label": "Reveni", - "column_header.hide_settings": "Hide settings", - "column_header.moveLeft_settings": "Move column to the left", - "column_header.moveRight_settings": "Move column to the right", - "column_header.pin": "Pin", - "column_header.show_settings": "Show settings", - "column_header.unpin": "Unpin", - "column_subheading.navigation": "Navigation", - "column_subheading.settings": "Settings", - "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", + "column_header.hide_settings": "Kaŝi agordojn", + "column_header.moveLeft_settings": "Movi kolumnon maldekstren", + "column_header.moveRight_settings": "Movi kolumnon dekstren", + "column_header.pin": "Alpingli", + "column_header.show_settings": "Malkaŝi agordojn", + "column_header.unpin": "Depingli", + "column_subheading.navigation": "Navigado", + "column_subheading.settings": "Agordoj", + "compose_form.lock_disclaimer": "Via konta ne estas ŝlosita. Iu ajn povas sekvi vin por vidi viajn privatajn pepojn.", + "compose_form.lock_disclaimer.lock": "ŝlosita", "compose_form.placeholder": "Pri kio vi pensas?", "compose_form.publish": "Hup", "compose_form.publish_loud": "{publish}!", "compose_form.sensitive": "Marki ke la enhavo estas tikla", "compose_form.spoiler": "Kaŝi la tekston malantaŭ averto", - "compose_form.spoiler_placeholder": "Content warning", - "confirmation_modal.cancel": "Cancel", - "confirmations.block.confirm": "Block", - "confirmations.block.message": "Are you sure you want to block {name}?", - "confirmations.delete.confirm": "Delete", - "confirmations.delete.message": "Are you sure you want to delete this status?", - "confirmations.domain_block.confirm": "Hide entire domain", - "confirmations.domain_block.message": "Are you really, really sure you want to block the entire {domain}? In most cases a few targeted blocks or mutes are sufficient and preferable.", - "confirmations.mute.confirm": "Mute", - "confirmations.mute.message": "Are you sure you want to mute {name}?", - "confirmations.unfollow.confirm": "Unfollow", - "confirmations.unfollow.message": "Are you sure you want to unfollow {name}?", - "embed.instructions": "Embed this status on your website by copying the code below.", - "embed.preview": "Here is what it will look like:", - "emoji_button.activity": "Activity", - "emoji_button.custom": "Custom", - "emoji_button.flags": "Flags", - "emoji_button.food": "Food & Drink", - "emoji_button.label": "Insert emoji", - "emoji_button.nature": "Nature", - "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", - "emoji_button.objects": "Objects", - "emoji_button.people": "People", - "emoji_button.recent": "Frequently used", - "emoji_button.search": "Search...", - "emoji_button.search_results": "Search results", - "emoji_button.symbols": "Symbols", - "emoji_button.travel": "Travel & Places", - "empty_column.community": "The local timeline is empty. Write something publicly to get the ball rolling!", - "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.public_timeline": "the public timeline", - "empty_column.notifications": "You don't have any notifications yet. Interact with others to start the conversation.", - "empty_column.public": "There is nothing here! Write something publicly, or manually follow users from other instances to fill it up", - "follow_request.authorize": "Authorize", - "follow_request.reject": "Reject", - "getting_started.appsshort": "Apps", - "getting_started.faq": "FAQ", + "compose_form.spoiler_placeholder": "Skribu tie vian averton", + "confirmation_modal.cancel": "Malfari", + "confirmations.block.confirm": "Bloki", + "confirmations.block.message": "Ĉu vi konfirmas la blokadon de {name}?", + "confirmations.delete.confirm": "Malaperigi", + "confirmations.delete.message": "Ĉu vi konfirmas la malaperigon de tiun pepon?", + "confirmations.domain_block.confirm": "Kaŝi la tutan reton", + "confirmations.domain_block.message": "Ĉu vi vere, vere certas, ke vi volas bloki {domain} tute? Plej ofte, kelkaj celitaj blokadoj aŭ silentigoj estas sufiĉaj kaj preferindaj.", + "confirmations.mute.confirm": "Silentigi", + "confirmations.mute.message": "Ĉu vi konfirmas la silentigon de {name}?", + "confirmations.unfollow.confirm": "Ne plu sekvi", + "confirmations.unfollow.message": "Ĉu vi volas ĉesi sekvi {name}?", + "embed.instructions": "Enmetu tiun statkonigon ĉe vian retejon kopiante la ĉi-suban kodon.", + "embed.preview": "Ĝi aperos tiel:", + "emoji_button.activity": "Aktivecoj", + "emoji_button.custom": "Personaj", + "emoji_button.flags": "Flagoj", + "emoji_button.food": "Manĝi kaj trinki", + "emoji_button.label": "Enmeti mieneton", + "emoji_button.nature": "Naturo", + "emoji_button.not_found": "Neniuj mienetoj!! (╯°□°)╯︵ ┻━┻", + "emoji_button.objects": "Objektoj", + "emoji_button.people": "Homoj", + "emoji_button.recent": "Ofte uzataj", + "emoji_button.search": "Serĉo…", + "emoji_button.search_results": "Rezultatoj de serĉo", + "emoji_button.symbols": "Simboloj", + "emoji_button.travel": "Vojaĝoj & lokoj", + "empty_column.community": "La loka tempolinio estas malplena. Skribu ion por plenigi ĝin!", + "empty_column.hashtag": "Ĝise, neniu enhavo estas asociita kun tiu kradvorto.", + "empty_column.home": "Via hejma tempolinio estas malplena! Vizitu {public} aŭ uzu la serĉilon por renkonti aliajn uzantojn.", + "empty_column.home.public_timeline": "la publika tempolinio", + "empty_column.notifications": "Vi dume ne havas sciigojn. Interagi kun aliajn uzantojn por komenci la konversacion.", + "empty_column.public": "Estas nenio ĉi tie! Publike skribu ion, aŭ mane sekvu uzantojn de aliaj instancoj por plenigi la publikan tempolinion.", + "follow_request.authorize": "Akcepti", + "follow_request.reject": "Rifuzi", + "getting_started.appsshort": "Aplikaĵoj", + "getting_started.faq": "Oftaj demandoj", "getting_started.heading": "Por komenci", - "getting_started.open_source_notice": "Mastodon estas malfermitkoda programo. Vi povas kontribui aŭ raporti problemojn en github je {github}.", - "getting_started.userguide": "User Guide", - "home.column_settings.advanced": "Advanced", - "home.column_settings.basic": "Basic", - "home.column_settings.filter_regex": "Filter out by regular expressions", - "home.column_settings.show_reblogs": "Show boosts", - "home.column_settings.show_replies": "Show replies", - "home.settings": "Column settings", + "getting_started.open_source_notice": "Mastodono estas malfermkoda programo. Vi povas kontribui aŭ raporti problemojn en GitHub je {github}.", + "getting_started.userguide": "Gvidilo de uzo", + "home.column_settings.advanced": "Precizaj agordoj", + "home.column_settings.basic": "Bazaj agordoj", + "home.column_settings.filter_regex": "Forfiltri per regulesprimo", + "home.column_settings.show_reblogs": "Montri diskonigojn", + "home.column_settings.show_replies": "Montri respondojn", + "home.settings": "Agordoj de la kolumno", "lightbox.close": "Fermi", - "lightbox.next": "Next", - "lightbox.previous": "Previous", - "loading_indicator.label": "Ŝarĝanta...", - "media_gallery.toggle_visible": "Toggle visibility", - "missing_indicator.label": "Not found", - "navigation_bar.blocks": "Blocked users", + "lightbox.next": "Malantaŭa", + "lightbox.previous": "Antaŭa", + "loading_indicator.label": "Ŝarganta…", + "media_gallery.toggle_visible": "Baskuli videblecon", + "missing_indicator.label": "Ne trovita", + "navigation_bar.blocks": "Blokitaj uzantoj", "navigation_bar.community_timeline": "Loka tempolinio", "navigation_bar.edit_profile": "Redakti la profilon", - "navigation_bar.favourites": "Favourites", - "navigation_bar.follow_requests": "Follow requests", - "navigation_bar.info": "Extended information", + "navigation_bar.favourites": "Favoritaj", + "navigation_bar.follow_requests": "Abonpetoj", + "navigation_bar.info": "Plia informo", "navigation_bar.logout": "Elsaluti", - "navigation_bar.mutes": "Muted users", - "navigation_bar.pins": "Pinned toots", + "navigation_bar.mutes": "Silentigitaj uzantoj", + "navigation_bar.pins": "Alpinglitaj pepoj", "navigation_bar.preferences": "Preferoj", "navigation_bar.public_timeline": "Fratara tempolinio", "notification.favourite": "{name} favoris vian mesaĝon", "notification.follow": "{name} sekvis vin", "notification.mention": "{name} menciis vin", "notification.reblog": "{name} diskonigis vian mesaĝon", - "notifications.clear": "Clear notifications", - "notifications.clear_confirmation": "Are you sure you want to permanently clear all your notifications?", + "notifications.clear": "Forviŝi la sciigojn", + "notifications.clear_confirmation": "Ĉu vi certe volas malaperigi ĉiujn viajn sciigojn?", "notifications.column_settings.alert": "Retumilaj atentigoj", - "notifications.column_settings.favourite": "Favoroj:", + "notifications.column_settings.favourite": "Favoritoj:", "notifications.column_settings.follow": "Novaj sekvantoj:", "notifications.column_settings.mention": "Mencioj:", - "notifications.column_settings.push": "Push notifications", - "notifications.column_settings.push_meta": "This device", + "notifications.column_settings.push": "Puŝsciigoj", + "notifications.column_settings.push_meta": "Tiu ĉi aparato", "notifications.column_settings.reblog": "Diskonigoj:", "notifications.column_settings.show": "Montri en kolono", - "notifications.column_settings.sound": "Play sound", - "onboarding.done": "Done", - "onboarding.next": "Next", - "onboarding.page_five.public_timelines": "The local timeline shows public posts from everyone on {domain}. The federated timeline shows public posts from everyone who people on {domain} follow. These are the Public Timelines, a great way to discover new people.", - "onboarding.page_four.home": "The home timeline shows posts from people you follow.", - "onboarding.page_four.notifications": "The notifications column shows when someone interacts with you.", - "onboarding.page_one.federation": "Mastodon is a network of independent servers joining up to make one larger social network. We call these servers instances.", - "onboarding.page_one.handle": "You are on {domain}, so your full handle is {handle}", - "onboarding.page_one.welcome": "Welcome to Mastodon!", - "onboarding.page_six.admin": "Your instance's admin is {admin}.", - "onboarding.page_six.almost_done": "Almost done...", - "onboarding.page_six.appetoot": "Bon Appetoot!", - "onboarding.page_six.apps_available": "There are {apps} available for iOS, Android and other platforms.", - "onboarding.page_six.github": "Mastodon is free open-source software. You can report bugs, request features, or contribute to the code on {github}.", - "onboarding.page_six.guidelines": "community guidelines", - "onboarding.page_six.read_guidelines": "Please read {domain}'s {guidelines}!", - "onboarding.page_six.various_app": "mobile apps", - "onboarding.page_three.profile": "Edit your profile to change your avatar, bio, and display name. There, you will also find other preferences.", - "onboarding.page_three.search": "Use the search bar to find people and look at hashtags, such as {illustration} and {introductions}. To look for a person who is not on this instance, use their full handle.", - "onboarding.page_two.compose": "Write posts from the compose column. You can upload images, change privacy settings, and add content warnings with the icons below.", - "onboarding.skip": "Skip", - "privacy.change": "Adjust status privacy", - "privacy.direct.long": "Post to mentioned users only", - "privacy.direct.short": "Direct", - "privacy.private.long": "Post to followers only", - "privacy.private.short": "Followers-only", - "privacy.public.long": "Post to public timelines", - "privacy.public.short": "Public", - "privacy.unlisted.long": "Do not show in public timelines", - "privacy.unlisted.short": "Unlisted", - "relative_time.days": "{number}d", + "notifications.column_settings.sound": "Eligi sonon", + "onboarding.done": "Farita", + "onboarding.next": "Malantaŭa", + "onboarding.page_five.public_timelines": "La loka tempolinio enhavas mesaĝojn de ĉiuj ĉe {domain}. La federacia tempolinio enhavas ĉiujn mesaĝojn de uzantoj, kiujn iu ĉe {domain} sekvas. Ambaŭ tre utilas por trovi novajn kunparolantojn.", + "onboarding.page_four.home": "La hejma tempolinio enhavas la mesaĝojn de ĉiuj uzantoj, kiuj vi sekvas.", + "onboarding.page_four.notifications": "La sciiga kolumno informas vin kiam iu interagas kun vi.", + "onboarding.page_one.federation": "Mastodono estas reto de nedependaj serviloj, unuiĝintaj por krei pligrandan socian retejon. Ni nomas tiujn servilojn instancoj.", + "onboarding.page_one.handle": "Vi estas ĉe {domain}, unu el la multaj instancoj de Mastodono. Via kompleta uznomo do estas {handle}", + "onboarding.page_one.welcome": "Bonvenon al Mastodono!", + "onboarding.page_six.admin": "Via instancestro estas {admin}.", + "onboarding.page_six.almost_done": "Estas preskaŭ finita…", + "onboarding.page_six.appetoot": "Bonan a‘pepi’ton!", + "onboarding.page_six.apps_available": "{apps} estas elŝuteblaj por iOS, Androido kaj alioj. Kaj nun… bonan a‘pepi’ton!", + "onboarding.page_six.github": "Mastodono estas libera, senpaga kaj malfermkoda programaro. Vi povas signali cimojn, proponi funkciojn aŭ kontribui al gîa kreskado ĉe {github}.", + "onboarding.page_six.guidelines": "komunreguloj", + "onboarding.page_six.read_guidelines": "Ni petas vin: ne forgesu legi la {guidelines}n de {domain}!", + "onboarding.page_six.various_app": "telefon-aplikaĵoj", + "onboarding.page_three.profile": "Redaktu vian profilon por ŝanĝi vian avataron, priskribon kaj vian nomon. Vi tie trovos ankoraŭ aliajn agordojn.", + "onboarding.page_three.search": "Uzu la serĉokampo por trovi uzantojn kaj esplori kradvortojn tiel ke {illustration} kaj {introductions}. Por trovi iun, kiu ne estas ĉe ĉi tiu instanco, uzu ĝian kompletan uznomon.", + "onboarding.page_two.compose": "Skribu pepojn en la verkkolumno. Vi povas aldoni bildojn, ŝanĝi la agordojn de privateco kaj aldoni tiklavertojn (« content warning ») dank' al la piktogramoj malsupre.", + "onboarding.skip": "Pasigi", + "privacy.change": "Alĝustigi la privateco de la mesaĝo", + "privacy.direct.long": "Vidigi nur al la menciitaj personoj", + "privacy.direct.short": "Rekta", + "privacy.private.long": "Vidigi nur al viaj sekvantoj", + "privacy.private.short": "Nursekvanta", + "privacy.public.long": "Vidigi en publikaj tempolinioj", + "privacy.public.short": "Publika", + "privacy.unlisted.long": "Ne vidigi en publikaj tempolinioj", + "privacy.unlisted.short": "Nelistigita", + "relative_time.days": "{number}t", "relative_time.hours": "{number}h", - "relative_time.just_now": "now", + "relative_time.just_now": "nun", "relative_time.minutes": "{number}m", "relative_time.seconds": "{number}s", - "reply_indicator.cancel": "Rezigni", - "report.placeholder": "Additional comments", - "report.submit": "Submit", - "report.target": "Reporting", + "reply_indicator.cancel": "Malfari", + "report.placeholder": "Pliaj komentoj", + "report.submit": "Sendi", + "report.target": "Signalaĵo", "search.placeholder": "Serĉi", - "search_popout.search_format": "Advanced search format", - "search_popout.tips.hashtag": "hashtag", - "search_popout.tips.status": "status", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", - "search_popout.tips.user": "user", - "search_results.total": "{count, number} {count, plural, one {result} other {results}}", - "standalone.public_title": "A look inside...", - "status.cannot_reblog": "This post cannot be boosted", + "search_popout.search_format": "Detala serĉo", + "search_popout.tips.hashtag": "kradvorto", + "search_popout.tips.status": "statkonigo", + "search_popout.tips.text": "Simpla teksto eligas la kongruajn afiŝnomojn, uznomojn kaj kradvortojn.", + "search_popout.tips.user": "uzanto", + "search_results.total": "{count, number} {count, plural, one {rezultato} other {rezultatoj}}", + "standalone.public_title": "Rigardeti…", + "status.cannot_reblog": "Tiun publikaĵon oni ne povas diskonigi", "status.delete": "Forigi", - "status.embed": "Embed", + "status.embed": "Enmeti", "status.favourite": "Favori", - "status.load_more": "Load more", - "status.media_hidden": "Media hidden", + "status.load_more": "Ŝargi plie", + "status.media_hidden": "Sonbildaĵo kaŝita", "status.mention": "Mencii @{name}", - "status.more": "More", - "status.mute_conversation": "Mute conversation", - "status.open": "Expand this status", - "status.pin": "Pin on profile", + "status.more": "Pli", + "status.mute_conversation": "Silentigi konversacion", + "status.open": "Disfaldi statkonigon", + "status.pin": "Pingli al la profilo", "status.reblog": "Diskonigi", - "status.reblogged_by": "{name} diskonigita", + "status.reblogged_by": "{name} diskonigis", "status.reply": "Respondi", - "status.replyAll": "Reply to thread", - "status.report": "Report @{name}", + "status.replyAll": "Respondi al la fadeno", + "status.report": "Signali @{name}", "status.sensitive_toggle": "Alklaki por vidi", "status.sensitive_warning": "Tikla enhavo", - "status.share": "Share", - "status.show_less": "Show less", - "status.show_more": "Show more", - "status.unmute_conversation": "Unmute conversation", - "status.unpin": "Unpin from profile", + "status.share": "Diskonigi", + "status.show_less": "Refaldi", + "status.show_more": "Disfaldi", + "status.unmute_conversation": "Malsilentigi konversacion", + "status.unpin": "Depingli de profilo", "tabs_bar.compose": "Ekskribi", - "tabs_bar.federated_timeline": "Federated", + "tabs_bar.federated_timeline": "Federacia tempolinio", "tabs_bar.home": "Hejmo", - "tabs_bar.local_timeline": "Local", + "tabs_bar.local_timeline": "Loka tempolinio", "tabs_bar.notifications": "Sciigoj", - "upload_area.title": "Drag & drop to upload", - "upload_button.label": "Aldoni enhavaĵon", - "upload_form.description": "Describe for the visually impaired", + "upload_area.title": "Algliti por alŝuti", + "upload_button.label": "Aldoni sonbildaĵon", + "upload_form.description": "Priskribi por la misvidantaj", "upload_form.undo": "Malfari", - "upload_progress.label": "Uploading...", - "video.close": "Close video", - "video.exit_fullscreen": "Exit full screen", - "video.expand": "Expand video", - "video.fullscreen": "Full screen", - "video.hide": "Hide video", - "video.mute": "Mute sound", - "video.pause": "Pause", - "video.play": "Play", - "video.unmute": "Unmute sound" + "upload_progress.label": "Alŝutanta…", + "video.close": "Fermi videon", + "video.exit_fullscreen": "Eliri el plenekrano", + "video.expand": "Vastigi videon", + "video.fullscreen": "Igi plenekrane", + "video.hide": "Kaŝi videon", + "video.mute": "Silentigi", + "video.pause": "Paŭzi", + "video.play": "Legi", + "video.unmute": "Malsilentigi" } diff --git a/app/javascript/mastodon/locales/ru.json b/app/javascript/mastodon/locales/ru.json index 104b063f5..65bc5b374 100644 --- a/app/javascript/mastodon/locales/ru.json +++ b/app/javascript/mastodon/locales/ru.json @@ -63,20 +63,20 @@ "confirmations.mute.message": "Вы уверены, что хотите заглушить {name}?", "confirmations.unfollow.confirm": "Отписаться", "confirmations.unfollow.message": "Вы уверены, что хотите отписаться от {name}?", - "embed.instructions": "Embed this status on your website by copying the code below.", - "embed.preview": "Here is what it will look like:", + "embed.instructions": "Встройте этот статус на Вашем сайте, скопировав код внизу.", + "embed.preview": "Так это будет выглядеть:", "emoji_button.activity": "Занятия", - "emoji_button.custom": "Custom", + "emoji_button.custom": "Собственные", "emoji_button.flags": "Флаги", "emoji_button.food": "Еда и напитки", "emoji_button.label": "Вставить эмодзи", "emoji_button.nature": "Природа", - "emoji_button.not_found": "No emojos!! (╯°□°)╯︵ ┻━┻", + "emoji_button.not_found": "Нет эмодзи!! (╯°□°)╯︵ ┻━┻", "emoji_button.objects": "Предметы", "emoji_button.people": "Люди", - "emoji_button.recent": "Frequently used", + "emoji_button.recent": "Последние", "emoji_button.search": "Найти...", - "emoji_button.search_results": "Search results", + "emoji_button.search_results": "Результаты поиска", "emoji_button.symbols": "Символы", "emoji_button.travel": "Путешествия", "empty_column.community": "Локальная лента пуста. Напишите что-нибудь, чтобы разогреть народ!", @@ -159,34 +159,34 @@ "privacy.public.short": "Публичный", "privacy.unlisted.long": "Не показывать в лентах", "privacy.unlisted.short": "Скрытый", - "relative_time.days": "{number}d", - "relative_time.hours": "{number}h", - "relative_time.just_now": "now", - "relative_time.minutes": "{number}m", - "relative_time.seconds": "{number}s", + "relative_time.days": "{number}д", + "relative_time.hours": "{number}ч", + "relative_time.just_now": "только что", + "relative_time.minutes": "{number}м", + "relative_time.seconds": "{number}с", "reply_indicator.cancel": "Отмена", "report.placeholder": "Комментарий", "report.submit": "Отправить", "report.target": "Жалуемся на", "search.placeholder": "Поиск", - "search_popout.search_format": "Advanced search format", - "search_popout.tips.hashtag": "hashtag", - "search_popout.tips.status": "status", - "search_popout.tips.text": "Simple text returns matching display names, usernames and hashtags", - "search_popout.tips.user": "user", + "search_popout.search_format": "Продвинутый формат поиска", + "search_popout.tips.hashtag": "хэштег", + "search_popout.tips.status": "статус", + "search_popout.tips.text": "Простой ввод текста покажет совпадающие имена пользователей, отображаемые имена и хэштеги", + "search_popout.tips.user": "пользователь", "search_results.total": "{count, number} {count, plural, one {результат} few {результата} many {результатов} other {результатов}}", - "standalone.public_title": "A look inside...", + "standalone.public_title": "Прямо сейчас", "status.cannot_reblog": "Этот статус не может быть продвинут", "status.delete": "Удалить", - "status.embed": "Embed", + "status.embed": "Встроить", "status.favourite": "Нравится", "status.load_more": "Показать еще", "status.media_hidden": "Медиаконтент скрыт", "status.mention": "Упомянуть @{name}", - "status.more": "More", + "status.more": "Больше", "status.mute_conversation": "Заглушить тред", "status.open": "Развернуть статус", - "status.pin": "Pin on profile", + "status.pin": "Закрепить в профиле", "status.reblog": "Продвинуть", "status.reblogged_by": "{name} продвинул(а)", "status.reply": "Ответить", @@ -194,11 +194,11 @@ "status.report": "Пожаловаться", "status.sensitive_toggle": "Нажмите для просмотра", "status.sensitive_warning": "Чувствительный контент", - "status.share": "Share", + "status.share": "Поделиться", "status.show_less": "Свернуть", "status.show_more": "Развернуть", "status.unmute_conversation": "Снять глушение с треда", - "status.unpin": "Unpin from profile", + "status.unpin": "Открепить от профиля", "tabs_bar.compose": "Написать", "tabs_bar.federated_timeline": "Глобальная", "tabs_bar.home": "Главная", @@ -206,16 +206,16 @@ "tabs_bar.notifications": "Уведомления", "upload_area.title": "Перетащите сюда, чтобы загрузить", "upload_button.label": "Добавить медиаконтент", - "upload_form.description": "Describe for the visually impaired", + "upload_form.description": "Описать для людей с нарушениями зрения", "upload_form.undo": "Отменить", "upload_progress.label": "Загрузка...", - "video.close": "Close video", - "video.exit_fullscreen": "Exit full screen", - "video.expand": "Expand video", - "video.fullscreen": "Full screen", - "video.hide": "Hide video", - "video.mute": "Mute sound", - "video.pause": "Pause", - "video.play": "Play", - "video.unmute": "Unmute sound" + "video.close": "Закрыть видео", + "video.exit_fullscreen": "Покинуть полноэкранный режим", + "video.expand": "Развернуть видео", + "video.fullscreen": "Полноэкранный режим", + "video.hide": "Скрыть видео", + "video.mute": "Заглушить звук", + "video.pause": "Пауза", + "video.play": "Пуск", + "video.unmute": "Включить звук" } diff --git a/app/javascript/mastodon/reducers/settings.js b/app/javascript/mastodon/reducers/settings.js index 0c0dae388..4b8a652d1 100644 --- a/app/javascript/mastodon/reducers/settings.js +++ b/app/javascript/mastodon/reducers/settings.js @@ -58,6 +58,12 @@ const initialState = ImmutableMap({ body: '', }), }), + + direct: ImmutableMap({ + regex: ImmutableMap({ + body: '', + }), + }), }); const defaultColumns = fromJS([ diff --git a/app/javascript/styles/mastodon/components.scss b/app/javascript/styles/mastodon/components.scss index 076aa9576..2506bbe62 100644 --- a/app/javascript/styles/mastodon/components.scss +++ b/app/javascript/styles/mastodon/components.scss @@ -2503,6 +2503,7 @@ button.icon-button.active i.fa-retweet { } .column-header { + display: flex; padding: 15px; font-size: 16px; background: lighten($ui-base-color, 4%); @@ -2528,12 +2529,10 @@ button.icon-button.active i.fa-retweet { } .column-header__buttons { - position: absolute; - right: 0; - top: 0; - height: 100%; - display: flex; height: 48px; + display: flex; + margin: -15px; + margin-left: 0; } .column-header__button { @@ -2692,6 +2691,14 @@ button.icon-button.active i.fa-retweet { } } +.column-header__title { + display: inline-block; + text-overflow: ellipsis; + overflow: hidden; + white-space: nowrap; + flex: 1; +} + .text-btn { display: inline-block; padding: 0; @@ -3465,7 +3472,6 @@ button.icon-button.active i.fa-retweet { right: 0; bottom: 0; background: rgba($base-overlay-background, 0.7); - transform: translateZ(0); } .modal-root__container { |