mirror of
https://github.com/glitch-soc/mastodon.git
synced 2025-12-16 09:18:46 +00:00
Compare commits
21 Commits
theme-intl
...
flavour-ur
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f32ef29808 | ||
|
|
a634d3876f | ||
|
|
08b0861b96 | ||
|
|
01a3461bef | ||
|
|
d420e2f047 | ||
|
|
279231c5dd | ||
|
|
a98b0a47ef | ||
|
|
0466aa8d08 | ||
|
|
072ab191cc | ||
|
|
eec5d350fd | ||
|
|
26c9b9fa27 | ||
|
|
066458a659 | ||
|
|
7a8711ccac | ||
|
|
0e56797792 | ||
|
|
8606e53384 | ||
|
|
fbd2a0127c | ||
|
|
c5a688d70e | ||
|
|
7284e36fbd | ||
|
|
22cdbca82c | ||
|
|
a489e5d5cd | ||
|
|
abe95b614b |
@@ -81,6 +81,7 @@ class ApplicationController < ActionController::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def pack?(data, pack_name)
|
def pack?(data, pack_name)
|
||||||
|
return false unless data
|
||||||
if data['pack'].is_a?(Hash) && data['pack'].key?(pack_name)
|
if data['pack'].is_a?(Hash) && data['pack'].key?(pack_name)
|
||||||
return true if data['pack'][pack_name].is_a?(String) || data['pack'][pack_name].is_a?(Hash)
|
return true if data['pack'][pack_name].is_a?(String) || data['pack'][pack_name].is_a?(Hash)
|
||||||
end
|
end
|
||||||
@@ -89,16 +90,17 @@ class ApplicationController < ActionController::Base
|
|||||||
|
|
||||||
def nil_pack(data, pack_name, skin = 'default')
|
def nil_pack(data, pack_name, skin = 'default')
|
||||||
{
|
{
|
||||||
common: pack_name == 'common' ? nil : resolve_pack(data['name'] ? Themes.instance.flavour(current_flavour) : Themes.instance.core, 'common', skin),
|
common: pack_name == 'common' ? nil : resolve_pack(!data || data['name'] ? Themes.instance.flavour(current_flavour) : Themes.instance.core, 'common', skin),
|
||||||
flavour: data['name'],
|
flavour: data ? data['name'] : nil,
|
||||||
pack: nil,
|
pack: nil,
|
||||||
preload: nil,
|
preload: nil,
|
||||||
skin: nil,
|
skin: nil,
|
||||||
supported_locales: data['locales'],
|
supported_locales: data ? data['locales'] : nil,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
def resolve_pack(data, pack_name, skin = 'default')
|
def resolve_pack(data, pack_name, skin = 'default')
|
||||||
|
return nil_pack(data, pack_name, skin) unless data
|
||||||
result = pack(data, pack_name, skin)
|
result = pack(data, pack_name, skin)
|
||||||
unless result
|
unless result
|
||||||
if data['name'] && data.key?('fallback')
|
if data['name'] && data.key?('fallback')
|
||||||
@@ -154,13 +156,14 @@ class ApplicationController < ActionController::Base
|
|||||||
end
|
end
|
||||||
|
|
||||||
def current_flavour
|
def current_flavour
|
||||||
return Setting.default_settings['flavour'] unless Themes.instance.flavours.include? current_user&.setting_flavour
|
return params[:use_flavour].to_s if Themes.instance.flavours.include? params[:use_flavour].to_s
|
||||||
current_user.setting_flavour
|
return current_user.setting_flavour if Themes.instance.flavours.include? current_user&.setting_flavour
|
||||||
|
Setting.default_settings['flavour']
|
||||||
end
|
end
|
||||||
|
|
||||||
def current_skin
|
def current_skin
|
||||||
return 'default' unless Themes.instance.skins_for(current_flavour).include? current_user&.setting_skin
|
return current_user.setting_skin if Themes.instance.skins_for(current_flavour).include? current_user&.setting_skin
|
||||||
current_user.setting_skin
|
'default'
|
||||||
end
|
end
|
||||||
|
|
||||||
def cache_collection(raw, klass)
|
def cache_collection(raw, klass)
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ class HomeController < ApplicationController
|
|||||||
|
|
||||||
def index
|
def index
|
||||||
@body_classes = 'app-body'
|
@body_classes = 'app-body'
|
||||||
|
redirect_to "/$#{current_flavour}/#{params[:glob] || ''}" unless Themes.instance.flavours.include?(params[:use_flavour].to_s) or request.path.start_with?("/$#{current_flavour}")
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
@@ -58,7 +59,7 @@ class HomeController < ApplicationController
|
|||||||
end
|
end
|
||||||
|
|
||||||
def default_redirect_path
|
def default_redirect_path
|
||||||
if request.path.start_with?('/web')
|
if request.path.start_with?('/web') || request.path.match?(/\A\$[\w-]+/)
|
||||||
new_user_session_path
|
new_user_session_path
|
||||||
elsif single_user_mode?
|
elsif single_user_mode?
|
||||||
short_account_path(Account.first)
|
short_account_path(Account.first)
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ class Settings::PreferencesController < Settings::BaseController
|
|||||||
:setting_default_sensitive,
|
:setting_default_sensitive,
|
||||||
:setting_unfollow_modal,
|
:setting_unfollow_modal,
|
||||||
:setting_boost_modal,
|
:setting_boost_modal,
|
||||||
|
:setting_favourite_modal,
|
||||||
:setting_delete_modal,
|
:setting_delete_modal,
|
||||||
:setting_auto_play_gif,
|
:setting_auto_play_gif,
|
||||||
:setting_reduce_motion,
|
:setting_reduce_motion,
|
||||||
|
|||||||
@@ -58,6 +58,7 @@ export default class Status extends ImmutablePureComponent {
|
|||||||
'settings',
|
'settings',
|
||||||
'prepend',
|
'prepend',
|
||||||
'boostModal',
|
'boostModal',
|
||||||
|
'favouriteModal',
|
||||||
'muted',
|
'muted',
|
||||||
'collapse',
|
'collapse',
|
||||||
'notification',
|
'notification',
|
||||||
@@ -204,8 +205,8 @@ export default class Status extends ImmutablePureComponent {
|
|||||||
this.props.onReply(this.props.status, this.context.router.history);
|
this.props.onReply(this.props.status, this.context.router.history);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleHotkeyFavourite = () => {
|
handleHotkeyFavourite = (e) => {
|
||||||
this.props.onFavourite(this.props.status);
|
this.props.onFavourite(this.props.status, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleHotkeyBoost = e => {
|
handleHotkeyBoost = e => {
|
||||||
|
|||||||
@@ -71,8 +71,8 @@ export default class StatusActionBar extends ImmutablePureComponent {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFavouriteClick = () => {
|
handleFavouriteClick = (e) => {
|
||||||
this.props.onFavourite(this.props.status);
|
this.props.onFavourite(this.props.status, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleReblogClick = (e) => {
|
handleReblogClick = (e) => {
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export default class Mastodon extends React.PureComponent {
|
|||||||
return (
|
return (
|
||||||
<IntlProvider locale={locale} messages={messages}>
|
<IntlProvider locale={locale} messages={messages}>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<BrowserRouter basename='/web'>
|
<BrowserRouter basename='/$glitch'>
|
||||||
<ScrollContext>
|
<ScrollContext>
|
||||||
<Route path='/' component={UI} />
|
<Route path='/' component={UI} />
|
||||||
</ScrollContext>
|
</ScrollContext>
|
||||||
|
|||||||
@@ -20,7 +20,7 @@ import { initMuteModal } from 'flavours/glitch/actions/mutes';
|
|||||||
import { initReport } from 'flavours/glitch/actions/reports';
|
import { initReport } from 'flavours/glitch/actions/reports';
|
||||||
import { openModal } from 'flavours/glitch/actions/modal';
|
import { openModal } from 'flavours/glitch/actions/modal';
|
||||||
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
import { boostModal, deleteModal } from 'flavours/glitch/util/initial_state';
|
import { boostModal, favouriteModal, deleteModal } from 'flavours/glitch/util/initial_state';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
|
deleteConfirm: { id: 'confirmations.delete.confirm', defaultMessage: 'Delete' },
|
||||||
@@ -78,11 +78,19 @@ const mapDispatchToProps = (dispatch, { intl }) => ({
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
onFavourite (status) {
|
onModalFavourite (status) {
|
||||||
|
dispatch(favourite(status));
|
||||||
|
},
|
||||||
|
|
||||||
|
onFavourite (status, e) {
|
||||||
if (status.get('favourited')) {
|
if (status.get('favourited')) {
|
||||||
dispatch(unfavourite(status));
|
dispatch(unfavourite(status));
|
||||||
} else {
|
} else {
|
||||||
dispatch(favourite(status));
|
if (e.shiftKey || !favouriteModal) {
|
||||||
|
this.onModalFavourite(status);
|
||||||
|
} else {
|
||||||
|
dispatch(openModal('FAVOURITE', { status, onFavourite: this.onModalFavourite }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|||||||
@@ -48,8 +48,8 @@ export default class ActionBar extends React.PureComponent {
|
|||||||
this.props.onReblog(this.props.status, e);
|
this.props.onReblog(this.props.status, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleFavouriteClick = () => {
|
handleFavouriteClick = (e) => {
|
||||||
this.props.onFavourite(this.props.status);
|
this.props.onFavourite(this.props.status, e);
|
||||||
}
|
}
|
||||||
|
|
||||||
handleDeleteClick = () => {
|
handleDeleteClick = () => {
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import { openModal } from 'flavours/glitch/actions/modal';
|
|||||||
import { defineMessages, injectIntl } from 'react-intl';
|
import { defineMessages, injectIntl } from 'react-intl';
|
||||||
import ImmutablePureComponent from 'react-immutable-pure-component';
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
import { HotKeys } from 'react-hotkeys';
|
import { HotKeys } from 'react-hotkeys';
|
||||||
import { boostModal, deleteModal } from 'flavours/glitch/util/initial_state';
|
import { boostModal, favouriteModal, deleteModal } from 'flavours/glitch/util/initial_state';
|
||||||
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'flavours/glitch/util/fullscreen';
|
import { attachFullscreenListener, detachFullscreenListener, isFullscreen } from 'flavours/glitch/util/fullscreen';
|
||||||
|
|
||||||
const messages = defineMessages({
|
const messages = defineMessages({
|
||||||
@@ -95,11 +95,19 @@ export default class Status extends ImmutablePureComponent {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
handleFavouriteClick = (status) => {
|
handleModalFavourite = (status) => {
|
||||||
|
this.props.dispatch(favourite(status));
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFavouriteClick = (status, e) => {
|
||||||
if (status.get('favourited')) {
|
if (status.get('favourited')) {
|
||||||
this.props.dispatch(unfavourite(status));
|
this.props.dispatch(unfavourite(status));
|
||||||
} else {
|
} else {
|
||||||
this.props.dispatch(favourite(status));
|
if (e.shiftKey || !favouriteModal) {
|
||||||
|
this.handleModalFavourite(status);
|
||||||
|
} else {
|
||||||
|
this.props.dispatch(openModal('FAVOURITE', { status, onFavourite: this.handleModalFavourite }));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import React from 'react';
|
||||||
|
import ImmutablePropTypes from 'react-immutable-proptypes';
|
||||||
|
import PropTypes from 'prop-types';
|
||||||
|
import { defineMessages, injectIntl, FormattedMessage } from 'react-intl';
|
||||||
|
import Button from 'flavours/glitch/components/button';
|
||||||
|
import StatusContent from 'flavours/glitch/components/status_content';
|
||||||
|
import Avatar from 'flavours/glitch/components/avatar';
|
||||||
|
import RelativeTimestamp from 'flavours/glitch/components/relative_timestamp';
|
||||||
|
import DisplayName from 'flavours/glitch/components/display_name';
|
||||||
|
import ImmutablePureComponent from 'react-immutable-pure-component';
|
||||||
|
|
||||||
|
const messages = defineMessages({
|
||||||
|
favourite: { id: 'status.favourite', defaultMessage: 'Favourite' },
|
||||||
|
});
|
||||||
|
|
||||||
|
@injectIntl
|
||||||
|
export default class FavouriteModal extends ImmutablePureComponent {
|
||||||
|
|
||||||
|
static contextTypes = {
|
||||||
|
router: PropTypes.object,
|
||||||
|
};
|
||||||
|
|
||||||
|
static propTypes = {
|
||||||
|
status: ImmutablePropTypes.map.isRequired,
|
||||||
|
onFavourite: PropTypes.func.isRequired,
|
||||||
|
onClose: PropTypes.func.isRequired,
|
||||||
|
intl: PropTypes.object.isRequired,
|
||||||
|
};
|
||||||
|
|
||||||
|
componentDidMount() {
|
||||||
|
this.button.focus();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleFavourite = () => {
|
||||||
|
this.props.onFavourite(this.props.status);
|
||||||
|
this.props.onClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
handleAccountClick = (e) => {
|
||||||
|
if (e.button === 0) {
|
||||||
|
e.preventDefault();
|
||||||
|
this.props.onClose();
|
||||||
|
this.context.router.history.push(`/accounts/${this.props.status.getIn(['account', 'id'])}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
setRef = (c) => {
|
||||||
|
this.button = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
render () {
|
||||||
|
const { status, intl } = this.props;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div className='modal-root__modal favourite-modal'>
|
||||||
|
<div className='favourite-modal__container'>
|
||||||
|
<div className='status light'>
|
||||||
|
<div className='favourite-modal__status-header'>
|
||||||
|
<div className='favourite-modal__status-time'>
|
||||||
|
<a href={status.get('url')} className='status__relative-time' target='_blank' rel='noopener'><RelativeTimestamp timestamp={status.get('created_at')} /></a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<a onClick={this.handleAccountClick} href={status.getIn(['account', 'url'])} className='status__display-name'>
|
||||||
|
<div className='status__avatar'>
|
||||||
|
<Avatar account={status.get('account')} size={48} />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<DisplayName account={status.get('account')} />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<StatusContent status={status} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className='favourite-modal__action-bar'>
|
||||||
|
<div><FormattedMessage id='favourite_modal.combo' defaultMessage='You can press {combo} to skip this next time' values={{ combo: <span>Shift + <i className='fa fa-star' /></span> }} /></div>
|
||||||
|
<Button text={intl.formatMessage(messages.favourite)} onClick={this.handleFavourite} ref={this.setRef} />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@ import ActionsModal from './actions_modal';
|
|||||||
import MediaModal from './media_modal';
|
import MediaModal from './media_modal';
|
||||||
import VideoModal from './video_modal';
|
import VideoModal from './video_modal';
|
||||||
import BoostModal from './boost_modal';
|
import BoostModal from './boost_modal';
|
||||||
|
import FavouriteModal from './favourite_modal';
|
||||||
import DoodleModal from './doodle_modal';
|
import DoodleModal from './doodle_modal';
|
||||||
import ConfirmationModal from './confirmation_modal';
|
import ConfirmationModal from './confirmation_modal';
|
||||||
import {
|
import {
|
||||||
@@ -23,6 +24,7 @@ const MODAL_COMPONENTS = {
|
|||||||
'ONBOARDING': OnboardingModal,
|
'ONBOARDING': OnboardingModal,
|
||||||
'VIDEO': () => Promise.resolve({ default: VideoModal }),
|
'VIDEO': () => Promise.resolve({ default: VideoModal }),
|
||||||
'BOOST': () => Promise.resolve({ default: BoostModal }),
|
'BOOST': () => Promise.resolve({ default: BoostModal }),
|
||||||
|
'FAVOURITE': () => Promise.resolve({ default: FavouriteModal }),
|
||||||
'DOODLE': () => Promise.resolve({ default: DoodleModal }),
|
'DOODLE': () => Promise.resolve({ default: DoodleModal }),
|
||||||
'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
|
'CONFIRM': () => Promise.resolve({ default: ConfirmationModal }),
|
||||||
'MUTE': MuteModal,
|
'MUTE': MuteModal,
|
||||||
@@ -92,7 +94,7 @@ export default class ModalRoot extends React.PureComponent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
renderLoading = modalId => () => {
|
renderLoading = modalId => () => {
|
||||||
return ['MEDIA', 'VIDEO', 'BOOST', 'DOODLE', 'CONFIRM', 'ACTIONS'].indexOf(modalId) === -1 ? <ModalLoading /> : null;
|
return ['MEDIA', 'VIDEO', 'BOOST', 'FAVOURITE', 'DOODLE', 'CONFIRM', 'ACTIONS'].indexOf(modalId) === -1 ? <ModalLoading /> : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
renderError = (props) => {
|
renderError = (props) => {
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ const messages = {
|
|||||||
'status.collapse': 'Collapse',
|
'status.collapse': 'Collapse',
|
||||||
'status.uncollapse': 'Uncollapse',
|
'status.uncollapse': 'Uncollapse',
|
||||||
|
|
||||||
|
'favourite_modal.combo': 'You can press {combo} to skip this next time',
|
||||||
|
|
||||||
'home.column_settings.show_direct': 'Show DMs',
|
'home.column_settings.show_direct': 'Show DMs',
|
||||||
|
|
||||||
'notification.markForDeletion': 'Mark for deletion',
|
'notification.markForDeletion': 'Mark for deletion',
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ import inherited from 'mastodon/locales/ja.json';
|
|||||||
const messages = {
|
const messages = {
|
||||||
'getting_started.open_source_notice': 'Glitchsocは{Mastodon}によるフリーなオープンソースソフトウェアです。誰でもGitHub({github})から開発に參加したり、問題を報告したりできます。',
|
'getting_started.open_source_notice': 'Glitchsocは{Mastodon}によるフリーなオープンソースソフトウェアです。誰でもGitHub({github})から開発に參加したり、問題を報告したりできます。',
|
||||||
'layout.auto': '自動',
|
'layout.auto': '自動',
|
||||||
'layout.current_is': 'あなたの現在のレイアウト:',
|
'layout.current_is': 'あなたの現在のレイアウト:',
|
||||||
'layout.desktop': 'デスクトップ',
|
'layout.desktop': 'Desktop',
|
||||||
'layout.mobile': 'モバイル',
|
'layout.mobile': 'Mobile',
|
||||||
'navigation_bar.app_settings': 'アプリ設定',
|
'navigation_bar.app_settings': 'アプリ設定',
|
||||||
'getting_started.onboarding': '解説',
|
'getting_started.onboarding': '解説を表示',
|
||||||
'onboarding.page_one.federation': '{domain}はMastodonのインスタンスです。Mastodonとは、独立したサーバが連携して作るソーシャルネットワークです。これらのサーバーをインスタンスと呼びます。',
|
'onboarding.page_one.federation': '{domain}はMastodonのインスタンスです。Mastodonとは、独立したサーバが連携して作るソーシャルネットワークです。これらのサーバーをインスタンスと呼びます。',
|
||||||
'onboarding.page_one.welcome': '{domain}へようこそ!',
|
'onboarding.page_one.welcome': '{domain}へようこそ!',
|
||||||
'onboarding.page_six.github': '{domain}はGlitchsocを使用しています。Glitchsocは{Mastodon}のフレンドリーな{fork}で、どんなMastodonアプリやインスタンスとも互換性があります。Glitchsocは完全に無料で、オープンソースです。{github}でバグ報告や機能要望あるいは貢獻をすることが可能です。',
|
'onboarding.page_six.github': '{domain}はGlitchsocを使用しています。Glitchsocは{Mastodon}のフレンドリーな{fork}で、どんなMastodonアプリやインスタンスとも互換性があります。Glitchsocは完全に無料で、オープンソースです。{github}でバグ報告や機能要望あるいは貢獻をすることが可能です。',
|
||||||
@@ -29,8 +29,11 @@ const messages = {
|
|||||||
'settings.media_letterbox': 'メディアをレターボックス式で表示',
|
'settings.media_letterbox': 'メディアをレターボックス式で表示',
|
||||||
'settings.media_fullwidth': '全幅メディアプリビュー',
|
'settings.media_fullwidth': '全幅メディアプリビュー',
|
||||||
'settings.preferences': 'ユーザー設定',
|
'settings.preferences': 'ユーザー設定',
|
||||||
'settings.wide_view': 'ワイドビュー(デスクトップレイアウトのみ)',
|
'settings.wide_view': 'ワイドビュー(Desktopレイアウトのみ)',
|
||||||
'settings.navbar_under': 'ナビを画面下部に移動させる(モバイルレイアウトのみ)',
|
'settings.navbar_under': 'ナビを画面下部に移動させる(Mobileレイアウトのみ)',
|
||||||
|
'settings.compose_box_opts': 'コンポーズボックス設定',
|
||||||
|
'settings.side_arm': 'セカンダリートゥートボタン',
|
||||||
|
'settings.layout': 'レイアウト',
|
||||||
'status.collapse': '折りたたむ',
|
'status.collapse': '折りたたむ',
|
||||||
'status.uncollapse': '折りたたみを解除',
|
'status.uncollapse': '折りたたみを解除',
|
||||||
|
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ const notify = options =>
|
|||||||
icon: '/android-chrome-192x192.png',
|
icon: '/android-chrome-192x192.png',
|
||||||
tag: GROUP_TAG,
|
tag: GROUP_TAG,
|
||||||
data: {
|
data: {
|
||||||
url: (new URL('/web/notifications', self.location)).href,
|
url: (new URL('/$glitch/notifications', self.location)).href,
|
||||||
count: notifications.length + 1,
|
count: notifications.length + 1,
|
||||||
message: options.data.message,
|
message: options.data.message,
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -3913,6 +3913,7 @@ button.icon-button.active i.fa-retweet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.boost-modal,
|
.boost-modal,
|
||||||
|
.favourite-modal,
|
||||||
.confirmation-modal,
|
.confirmation-modal,
|
||||||
.report-modal,
|
.report-modal,
|
||||||
.actions-modal,
|
.actions-modal,
|
||||||
@@ -3944,7 +3945,8 @@ button.icon-button.active i.fa-retweet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.boost-modal__container {
|
.boost-modal__container,
|
||||||
|
.favourite-modal__container{
|
||||||
overflow-x: scroll;
|
overflow-x: scroll;
|
||||||
padding: 10px;
|
padding: 10px;
|
||||||
|
|
||||||
@@ -3955,6 +3957,7 @@ button.icon-button.active i.fa-retweet {
|
|||||||
}
|
}
|
||||||
|
|
||||||
.boost-modal__action-bar,
|
.boost-modal__action-bar,
|
||||||
|
.favourite-modal__action-bar,
|
||||||
.confirmation-modal__action-bar,
|
.confirmation-modal__action-bar,
|
||||||
.mute-modal__action-bar,
|
.mute-modal__action-bar,
|
||||||
.report-modal__action-bar {
|
.report-modal__action-bar {
|
||||||
@@ -3976,11 +3979,13 @@ button.icon-button.active i.fa-retweet {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.boost-modal__status-header {
|
.boost-modal__status-header,
|
||||||
|
.favourite-modal__status-header {
|
||||||
font-size: 15px;
|
font-size: 15px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.boost-modal__status-time {
|
.boost-modal__status-time,
|
||||||
|
.favourite-modal__status-time {
|
||||||
float: right;
|
float: right;
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,7 @@ export const reduceMotion = getMeta('reduce_motion');
|
|||||||
export const autoPlayGif = getMeta('auto_play_gif');
|
export const autoPlayGif = getMeta('auto_play_gif');
|
||||||
export const unfollowModal = getMeta('unfollow_modal');
|
export const unfollowModal = getMeta('unfollow_modal');
|
||||||
export const boostModal = getMeta('boost_modal');
|
export const boostModal = getMeta('boost_modal');
|
||||||
|
export const favouriteModal = getMeta('favourite_modal');
|
||||||
export const deleteModal = getMeta('delete_modal');
|
export const deleteModal = getMeta('delete_modal');
|
||||||
export const me = getMeta('me');
|
export const me = getMeta('me');
|
||||||
|
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ function main() {
|
|||||||
if (window.history && history.replaceState) {
|
if (window.history && history.replaceState) {
|
||||||
const { pathname, search, hash } = window.location;
|
const { pathname, search, hash } = window.location;
|
||||||
const path = pathname + search + hash;
|
const path = pathname + search + hash;
|
||||||
if (!(/^\/web[$/]/).test(path)) {
|
if (!(/^\/\$glitch[$/]/).test(path)) {
|
||||||
history.replaceState(null, document.title, `/web${path}`);
|
history.replaceState(null, document.title, `/$glitch${path}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ export default class Mastodon extends React.PureComponent {
|
|||||||
return (
|
return (
|
||||||
<IntlProvider locale={locale} messages={messages}>
|
<IntlProvider locale={locale} messages={messages}>
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
<BrowserRouter basename='/web'>
|
<BrowserRouter basename='/$vanilla'>
|
||||||
<ScrollContext>
|
<ScrollContext>
|
||||||
<Route path='/' component={UI} />
|
<Route path='/' component={UI} />
|
||||||
</ScrollContext>
|
</ScrollContext>
|
||||||
|
|||||||
@@ -1293,6 +1293,19 @@
|
|||||||
],
|
],
|
||||||
"path": "app/javascript/mastodon/features/ui/components/boost_modal.json"
|
"path": "app/javascript/mastodon/features/ui/components/boost_modal.json"
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
"descriptors": [
|
||||||
|
{
|
||||||
|
"defaultMessage": "Favourite",
|
||||||
|
"id": "status.favourite"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"defaultMessage": "You can press {combo} to skip this next time",
|
||||||
|
"id": "favourite_modal.combo"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"path": "app/javascript/mastodon/features/ui/components/favourite_modal.json"
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"descriptors": [
|
"descriptors": [
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
"bundle_modal_error.retry": "Try again",
|
"bundle_modal_error.retry": "Try again",
|
||||||
"column.blocks": "Blocked users",
|
"column.blocks": "Blocked users",
|
||||||
"column.community": "Local timeline",
|
"column.community": "Local timeline",
|
||||||
|
"column.direct": "Direct messages",
|
||||||
"column.favourites": "Favourites",
|
"column.favourites": "Favourites",
|
||||||
"column.follow_requests": "Follow requests",
|
"column.follow_requests": "Follow requests",
|
||||||
"column.home": "Home",
|
"column.home": "Home",
|
||||||
@@ -88,6 +89,7 @@
|
|||||||
"emoji_button.symbols": "Symbols",
|
"emoji_button.symbols": "Symbols",
|
||||||
"emoji_button.travel": "Travel & Places",
|
"emoji_button.travel": "Travel & Places",
|
||||||
"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.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",
|
||||||
@@ -141,6 +143,7 @@
|
|||||||
"mute_modal.hide_notifications": "Hide notifications from this user?",
|
"mute_modal.hide_notifications": "Hide notifications from this user?",
|
||||||
"navigation_bar.blocks": "Blocked users",
|
"navigation_bar.blocks": "Blocked users",
|
||||||
"navigation_bar.community_timeline": "Local timeline",
|
"navigation_bar.community_timeline": "Local timeline",
|
||||||
|
"navigation_bar.direct": "Direct messages",
|
||||||
"navigation_bar.edit_profile": "Edit profile",
|
"navigation_bar.edit_profile": "Edit profile",
|
||||||
"navigation_bar.favourites": "Favourites",
|
"navigation_bar.favourites": "Favourites",
|
||||||
"navigation_bar.follow_requests": "Follow requests",
|
"navigation_bar.follow_requests": "Follow requests",
|
||||||
|
|||||||
@@ -33,6 +33,7 @@
|
|||||||
"bundle_modal_error.retry": "再試行",
|
"bundle_modal_error.retry": "再試行",
|
||||||
"column.blocks": "ブロックしたユーザー",
|
"column.blocks": "ブロックしたユーザー",
|
||||||
"column.community": "ローカルタイムライン",
|
"column.community": "ローカルタイムライン",
|
||||||
|
"column.direct": "ダイレクトメッセージ",
|
||||||
"column.favourites": "お気に入り",
|
"column.favourites": "お気に入り",
|
||||||
"column.follow_requests": "フォローリクエスト",
|
"column.follow_requests": "フォローリクエスト",
|
||||||
"column.home": "ホーム",
|
"column.home": "ホーム",
|
||||||
@@ -88,6 +89,7 @@
|
|||||||
"emoji_button.symbols": "記号",
|
"emoji_button.symbols": "記号",
|
||||||
"emoji_button.travel": "旅行と場所",
|
"emoji_button.travel": "旅行と場所",
|
||||||
"empty_column.community": "ローカルタイムラインはまだ使われていません。何か書いてみましょう!",
|
"empty_column.community": "ローカルタイムラインはまだ使われていません。何か書いてみましょう!",
|
||||||
|
"empty_column.direct": "あなたはまだダイレクトメッセージを受け取っていません。あなたが送ったり受け取ったりすると、ここに表示されます。",
|
||||||
"empty_column.hashtag": "このハッシュタグはまだ使われていません。",
|
"empty_column.hashtag": "このハッシュタグはまだ使われていません。",
|
||||||
"empty_column.home": "まだ誰もフォローしていません。{public}を見に行くか、検索を使って他のユーザーを見つけましょう。",
|
"empty_column.home": "まだ誰もフォローしていません。{public}を見に行くか、検索を使って他のユーザーを見つけましょう。",
|
||||||
"empty_column.home.public_timeline": "連合タイムライン",
|
"empty_column.home.public_timeline": "連合タイムライン",
|
||||||
@@ -141,6 +143,7 @@
|
|||||||
"mute_modal.hide_notifications": "このユーザーからの通知を隠しますか?",
|
"mute_modal.hide_notifications": "このユーザーからの通知を隠しますか?",
|
||||||
"navigation_bar.blocks": "ブロックしたユーザー",
|
"navigation_bar.blocks": "ブロックしたユーザー",
|
||||||
"navigation_bar.community_timeline": "ローカルタイムライン",
|
"navigation_bar.community_timeline": "ローカルタイムライン",
|
||||||
|
"navigation_bar.direct": "ダイレクトメッセージ",
|
||||||
"navigation_bar.edit_profile": "プロフィールを編集",
|
"navigation_bar.edit_profile": "プロフィールを編集",
|
||||||
"navigation_bar.favourites": "お気に入り",
|
"navigation_bar.favourites": "お気に入り",
|
||||||
"navigation_bar.follow_requests": "フォローリクエスト",
|
"navigation_bar.follow_requests": "フォローリクエスト",
|
||||||
|
|||||||
@@ -12,8 +12,8 @@ function main() {
|
|||||||
if (window.history && history.replaceState) {
|
if (window.history && history.replaceState) {
|
||||||
const { pathname, search, hash } = window.location;
|
const { pathname, search, hash } = window.location;
|
||||||
const path = pathname + search + hash;
|
const path = pathname + search + hash;
|
||||||
if (!(/^\/web[$/]/).test(path)) {
|
if (!(/^\/\$vanilla[$/]/).test(path)) {
|
||||||
history.replaceState(null, document.title, `/web${path}`);
|
history.replaceState(null, document.title, `/$vanilla${path}`);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -102,16 +102,16 @@ const findBestClient = clients => {
|
|||||||
const openUrl = url =>
|
const openUrl = url =>
|
||||||
self.clients.matchAll({ type: 'window' }).then(clientList => {
|
self.clients.matchAll({ type: 'window' }).then(clientList => {
|
||||||
if (clientList.length !== 0) {
|
if (clientList.length !== 0) {
|
||||||
const webClients = clientList.filter(client => /\/web\//.test(client.url));
|
const webClients = clientList.filter(client => /\/\$vanilla\//.test(client.url));
|
||||||
|
|
||||||
if (webClients.length !== 0) {
|
if (webClients.length !== 0) {
|
||||||
const client = findBestClient(webClients);
|
const client = findBestClient(webClients);
|
||||||
const { pathname } = new URL(url);
|
const { pathname } = new URL(url);
|
||||||
|
|
||||||
if (pathname.startsWith('/web/')) {
|
if (pathname.startsWith('/$vanilla/')) {
|
||||||
return client.focus().then(client => client.postMessage({
|
return client.focus().then(client => client.postMessage({
|
||||||
type: 'navigate',
|
type: 'navigate',
|
||||||
path: pathname.slice('/web/'.length - 1),
|
path: pathname.slice('/$vanilla/'.length - 1),
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
} else if ('navigate' in clientList[0]) { // Chrome 42-48 does not support navigate
|
} else if ('navigate' in clientList[0]) { // Chrome 42-48 does not support navigate
|
||||||
|
|||||||
@@ -1054,23 +1054,23 @@ body.admin {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
.column-link[href="/web/timelines/public"] {
|
.column-link[href="/$vanilla/timelines/public"] {
|
||||||
background-image: url("~images/icon_public.png");
|
background-image: url("~images/icon_public.png");
|
||||||
&:hover { background-image: url("~images/icon_public.png"); }
|
&:hover { background-image: url("~images/icon_public.png"); }
|
||||||
}
|
}
|
||||||
.column-link[href="/web/timelines/public/local"] {
|
.column-link[href="/$vanilla/timelines/public/local"] {
|
||||||
background-image: url("~images/icon_local.png");
|
background-image: url("~images/icon_local.png");
|
||||||
&:hover { background-image: url("~images/icon_local.png"); }
|
&:hover { background-image: url("~images/icon_local.png"); }
|
||||||
}
|
}
|
||||||
.column-link[href="/web/pinned"] {
|
.column-link[href="/$vanilla/pinned"] {
|
||||||
background-image: url("~images/icon_pin.png");
|
background-image: url("~images/icon_pin.png");
|
||||||
&:hover { background-image: url("~images/icon_pin.png"); }
|
&:hover { background-image: url("~images/icon_pin.png"); }
|
||||||
}
|
}
|
||||||
.column-link[href="/web/favourites"] {
|
.column-link[href="/$vanilla/favourites"] {
|
||||||
background-image: url("~images/icon_likes.png");
|
background-image: url("~images/icon_likes.png");
|
||||||
&:hover { background-image: url("~images/icon_likes.png"); }
|
&:hover { background-image: url("~images/icon_likes.png"); }
|
||||||
}
|
}
|
||||||
.column-link[href="/web/blocks"] {
|
.column-link[href="/$vanilla/blocks"] {
|
||||||
background-image: url("~images/icon_blocks.png");
|
background-image: url("~images/icon_blocks.png");
|
||||||
&:hover { background-image: url("~images/icon_blocks.png"); }
|
&:hover { background-image: url("~images/icon_blocks.png"); }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ class UserSettingsDecorator
|
|||||||
user.settings['default_sensitive'] = default_sensitive_preference if change?('setting_default_sensitive')
|
user.settings['default_sensitive'] = default_sensitive_preference if change?('setting_default_sensitive')
|
||||||
user.settings['unfollow_modal'] = unfollow_modal_preference if change?('setting_unfollow_modal')
|
user.settings['unfollow_modal'] = unfollow_modal_preference if change?('setting_unfollow_modal')
|
||||||
user.settings['boost_modal'] = boost_modal_preference if change?('setting_boost_modal')
|
user.settings['boost_modal'] = boost_modal_preference if change?('setting_boost_modal')
|
||||||
|
user.settings['favourite_modal'] = favourite_modal_preference if change?('setting_favourite_modal')
|
||||||
user.settings['delete_modal'] = delete_modal_preference if change?('setting_delete_modal')
|
user.settings['delete_modal'] = delete_modal_preference if change?('setting_delete_modal')
|
||||||
user.settings['auto_play_gif'] = auto_play_gif_preference if change?('setting_auto_play_gif')
|
user.settings['auto_play_gif'] = auto_play_gif_preference if change?('setting_auto_play_gif')
|
||||||
user.settings['reduce_motion'] = reduce_motion_preference if change?('setting_reduce_motion')
|
user.settings['reduce_motion'] = reduce_motion_preference if change?('setting_reduce_motion')
|
||||||
@@ -54,6 +55,10 @@ class UserSettingsDecorator
|
|||||||
boolean_cast_setting 'setting_boost_modal'
|
boolean_cast_setting 'setting_boost_modal'
|
||||||
end
|
end
|
||||||
|
|
||||||
|
def favourite_modal_preference
|
||||||
|
boolean_cast_setting 'setting_favourite_modal'
|
||||||
|
end
|
||||||
|
|
||||||
def delete_modal_preference
|
def delete_modal_preference
|
||||||
boolean_cast_setting 'setting_delete_modal'
|
boolean_cast_setting 'setting_delete_modal'
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -75,7 +75,7 @@ class User < ApplicationRecord
|
|||||||
|
|
||||||
has_many :session_activations, dependent: :destroy
|
has_many :session_activations, dependent: :destroy
|
||||||
|
|
||||||
delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :delete_modal,
|
delegate :auto_play_gif, :default_sensitive, :unfollow_modal, :boost_modal, :favourite_modal, :delete_modal,
|
||||||
:reduce_motion, :system_font_ui, :noindex, :flavour, :skin,
|
:reduce_motion, :system_font_ui, :noindex, :flavour, :skin,
|
||||||
to: :settings, prefix: :setting, allow_nil: false
|
to: :settings, prefix: :setting, allow_nil: false
|
||||||
|
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ class InitialStateSerializer < ActiveModel::Serializer
|
|||||||
store[:me] = object.current_account.id.to_s
|
store[:me] = object.current_account.id.to_s
|
||||||
store[:unfollow_modal] = object.current_account.user.setting_unfollow_modal
|
store[:unfollow_modal] = object.current_account.user.setting_unfollow_modal
|
||||||
store[:boost_modal] = object.current_account.user.setting_boost_modal
|
store[:boost_modal] = object.current_account.user.setting_boost_modal
|
||||||
|
store[:favourite_modal] = object.current_account.user.setting_favourite_modal
|
||||||
store[:delete_modal] = object.current_account.user.setting_delete_modal
|
store[:delete_modal] = object.current_account.user.setting_delete_modal
|
||||||
store[:auto_play_gif] = object.current_account.user.setting_auto_play_gif
|
store[:auto_play_gif] = object.current_account.user.setting_auto_play_gif
|
||||||
store[:reduce_motion] = object.current_account.user.setting_reduce_motion
|
store[:reduce_motion] = object.current_account.user.setting_reduce_motion
|
||||||
|
|||||||
@@ -32,6 +32,7 @@
|
|||||||
|
|
||||||
= f.input :setting_unfollow_modal, as: :boolean, wrapper: :with_label
|
= f.input :setting_unfollow_modal, as: :boolean, wrapper: :with_label
|
||||||
= f.input :setting_boost_modal, as: :boolean, wrapper: :with_label
|
= f.input :setting_boost_modal, as: :boolean, wrapper: :with_label
|
||||||
|
= f.input :setting_favourite_modal, as: :boolean, wrapper: :with_label
|
||||||
= f.input :setting_delete_modal, as: :boolean, wrapper: :with_label
|
= f.input :setting_delete_modal, as: :boolean, wrapper: :with_label
|
||||||
|
|
||||||
.fields-group
|
.fields-group
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ en:
|
|||||||
setting_default_privacy: Post privacy
|
setting_default_privacy: Post privacy
|
||||||
setting_default_sensitive: Always mark media as sensitive
|
setting_default_sensitive: Always mark media as sensitive
|
||||||
setting_delete_modal: Show confirmation dialog before deleting a toot
|
setting_delete_modal: Show confirmation dialog before deleting a toot
|
||||||
|
setting_favourite_modal: Show confirmation dialog before favouriting
|
||||||
setting_flavour: Flavour
|
setting_flavour: Flavour
|
||||||
setting_noindex: Opt-out of search engine indexing
|
setting_noindex: Opt-out of search engine indexing
|
||||||
setting_reduce_motion: Reduce motion in animations
|
setting_reduce_motion: Reduce motion in animations
|
||||||
|
|||||||
@@ -309,7 +309,8 @@ Rails.application.routes.draw do
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
get '/web/(*any)', to: 'home#index', as: :web
|
get '/web/(*glob)', to: 'home#index', as: :web
|
||||||
|
get "/$:use_flavour/(*glob)", to: 'home#index'
|
||||||
|
|
||||||
get '/about', to: 'about#show'
|
get '/about', to: 'about#show'
|
||||||
get '/about/more', to: 'about#more'
|
get '/about/more', to: 'about#more'
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ defaults: &defaults
|
|||||||
default_sensitive: false
|
default_sensitive: false
|
||||||
unfollow_modal: false
|
unfollow_modal: false
|
||||||
boost_modal: false
|
boost_modal: false
|
||||||
|
favourite_modal: false
|
||||||
delete_modal: true
|
delete_modal: true
|
||||||
auto_play_gif: false
|
auto_play_gif: false
|
||||||
reduce_motion: false
|
reduce_motion: false
|
||||||
|
|||||||
Reference in New Issue
Block a user