diff --git a/.github/dependabot.yml b/.github/dependabot.yml
deleted file mode 100644
index c4cd48878..000000000
--- a/.github/dependabot.yml
+++ /dev/null
@@ -1,22 +0,0 @@
-# To get started with Dependabot version updates, you'll need to specify which
-# package ecosystems to update and where the package manifests are located.
-# Please see the documentation for all configuration options:
-# https://help.github.com/github/administering-a-repository/configuration-options-for-dependency-updates
-
-version: 2
-updates:
- - package-ecosystem: npm
- directory: "/"
- schedule:
- interval: weekly
- open-pull-requests-limit: 99
- allow:
- - dependency-type: direct
-
- - package-ecosystem: bundler
- directory: "/"
- schedule:
- interval: weekly
- open-pull-requests-limit: 99
- allow:
- - dependency-type: direct
diff --git a/Gemfile b/Gemfile
index 3a4799347..2c8e7c6dc 100644
--- a/Gemfile
+++ b/Gemfile
@@ -99,6 +99,8 @@ gem 'json-ld'
gem 'json-ld-preloaded', '~> 3.1'
gem 'rdf-normalize', '~> 0.4'
+gem 'redcarpet', "~> 3.4.0"
+
group :development, :test do
gem 'fabrication', '~> 2.22'
gem 'fuubar', '~> 2.5'
diff --git a/Gemfile.lock b/Gemfile.lock
index 1696facde..8a63e1d65 100644
--- a/Gemfile.lock
+++ b/Gemfile.lock
@@ -486,6 +486,14 @@ GEM
rdf-normalize (0.4.0)
rdf (~> 3.1)
redis (4.2.5)
+ redcarpet (3.4.0)
+ redis-actionpack (5.2.0)
+ actionpack (>= 5, < 7)
+ redis-rack (>= 2.1.0, < 3)
+ redis-store (>= 1.1.0, < 2)
+ redis-activesupport (5.2.0)
+ activesupport (>= 3, < 7)
+ redis-store (>= 1.3, < 2)
redis-namespace (1.8.1)
redis (>= 3.0.4)
regexp_parser (2.1.1)
@@ -762,6 +770,7 @@ DEPENDENCIES
rails-i18n (~> 6.0)
rails-settings-cached (~> 0.6)
rdf-normalize (~> 0.4)
+ redcarpet (~> 3.4.0)
redis (~> 4.2)
redis-namespace (~> 1.8)
resolv (~> 0.1.0)
diff --git a/app/controllers/api/v2/media_controller.rb b/app/controllers/api/v2/media_controller.rb
index 0c1baf01d..de2c72313 100644
--- a/app/controllers/api/v2/media_controller.rb
+++ b/app/controllers/api/v2/media_controller.rb
@@ -1,5 +1,8 @@
# frozen_string_literal: true
+class Api::V2::MediaController < Api::V1::MediaController
+end
+__END__
class Api::V2::MediaController < Api::V1::MediaController
def create
@media_attachment = current_account.media_attachments.create!({ delay_processing: true }.merge(media_attachment_params))
diff --git a/app/controllers/settings/preferences_controller.rb b/app/controllers/settings/preferences_controller.rb
index 32b5d7948..6598e9ea1 100644
--- a/app/controllers/settings/preferences_controller.rb
+++ b/app/controllers/settings/preferences_controller.rb
@@ -55,6 +55,8 @@ class Settings::PreferencesController < Settings::BaseController
:setting_use_pending_items,
:setting_trends,
:setting_crop_images,
+ :setting_place_tab_bar_at_bottom,
+ :setting_show_tab_bar_label,
notification_emails: %i(follow follow_request reblog favourite mention digest report pending_account trending_tag),
interactions: %i(must_be_follower must_be_following must_be_following_dm)
)
diff --git a/app/javascript/fonts/MaterialIcons-Regular.ttf b/app/javascript/fonts/MaterialIcons-Regular.ttf
new file mode 100644
index 000000000..e50801b3b
Binary files /dev/null and b/app/javascript/fonts/MaterialIcons-Regular.ttf differ
diff --git a/app/javascript/images/logo.svg b/app/javascript/images/logo.svg
index 034a9c221..82a6025a7 100644
--- a/app/javascript/images/logo.svg
+++ b/app/javascript/images/logo.svg
@@ -1 +1,17 @@
-
+
+
+
diff --git a/app/javascript/images/logo_alt.svg b/app/javascript/images/logo_alt.svg
index 102d4c787..4c04c93b8 100644
--- a/app/javascript/images/logo_alt.svg
+++ b/app/javascript/images/logo_alt.svg
@@ -1 +1,16 @@
-
+
+
+
diff --git a/app/javascript/mastodon/actions/UtilBtns.js b/app/javascript/mastodon/actions/UtilBtns.js
new file mode 100644
index 000000000..52ccc6877
--- /dev/null
+++ b/app/javascript/mastodon/actions/UtilBtns.js
@@ -0,0 +1,71 @@
+import { changeCompose } from '../actions/compose';
+
+
+
+export const UTILBTNS_GOJI = 'UTILBTNS_GOJI';
+export const UTILBTNS_HARUKIN = 'UTILBTNS_HARUKIN';
+
+
+
+export function submitGoji (textarea) {
+ return function (dispatch, getState) {
+ if (!textarea.value) {
+ let text = [
+ "#ゴジモリィィィィイイ",
+ ":goji:"
+ ].join("\r\n");
+
+ dispatch(submitGojiRequest());
+ dispatch(changeCompose(text));
+
+ textarea.focus();
+ }
+ }
+}
+
+export function submitGojiRequest () {
+ return {
+ type: UTILBTNS_GOJI
+ }
+}
+
+export function submitHarukin (textarea) {
+ return function (dispatch, getState) {
+ const HARUKINS = [":harukin: ", ":harukin_old: ", ":harukin_ika: ", ":harukin_tako: "];
+ const MAX = 6;
+
+ if (!textarea.value) {
+ let text = "";
+
+ let quantity = Math.round(Math.random() * MAX + 1);
+ let type = Math.round(Math.random() * (HARUKINS.length - 1));
+
+ let harukin = HARUKINS[type];
+
+ switch (quantity) {
+ default:
+ text = [
+ harukin.repeat(quantity),
+ "🔥 ".repeat(quantity)
+ ].join("\r\n");
+
+ break;
+
+ case MAX + 1:
+ text = `${harukin}💕\r\n`.repeat(6);
+ break;
+ }
+
+ dispatch(submitHarukinRequest());
+ dispatch(changeCompose(text));
+
+ textarea.focus();
+ }
+ }
+}
+
+export function submitHarukinRequest () {
+ return {
+ type: UTILBTNS_HARUKIN
+ }
+}
diff --git a/app/javascript/mastodon/components/announcement_icon_button.js b/app/javascript/mastodon/components/announcement_icon_button.js
new file mode 100644
index 000000000..0de58c6f7
--- /dev/null
+++ b/app/javascript/mastodon/components/announcement_icon_button.js
@@ -0,0 +1,90 @@
+import React from 'react';
+import Motion from 'react-motion/lib/Motion';
+import spring from 'react-motion/lib/spring';
+import PropTypes from 'prop-types';
+
+class IconButton extends React.PureComponent {
+
+ static propTypes = {
+ className: PropTypes.string,
+ title: PropTypes.string.isRequired,
+ icon: PropTypes.string.isRequired,
+ onClick: PropTypes.func,
+ size: PropTypes.number,
+ active: PropTypes.bool,
+ style: PropTypes.object,
+ activeStyle: PropTypes.object,
+ disabled: PropTypes.bool,
+ inverted: PropTypes.bool,
+ animate: PropTypes.bool,
+ overlay: PropTypes.bool,
+ };
+
+ static defaultProps = {
+ size: 18,
+ active: false,
+ disabled: false,
+ animate: false,
+ overlay: false,
+ };
+
+ handleClick = (e) => {
+ e.preventDefault();
+
+ if (!this.props.disabled) {
+ this.props.onClick(e);
+ }
+ }
+
+ render () {
+ const style = {
+ fontSize: `${this.props.size}px`,
+ width: `${this.props.size * 1.28571429}px`,
+ height: `${this.props.size * 1.28571429}px`,
+ lineHeight: `${this.props.size}px`,
+ ...this.props.style,
+ ...(this.props.active ? this.props.activeStyle : {}),
+ };
+
+ const classes = ['icon-button'];
+
+ if (this.props.active) {
+ classes.push('active');
+ }
+
+ if (this.props.disabled) {
+ classes.push('disabled');
+ }
+
+ if (this.props.inverted) {
+ classes.push('inverted');
+ }
+
+ if (this.props.overlay) {
+ classes.push('overlayed');
+ }
+
+ if (this.props.className) {
+ classes.push(this.props.className);
+ }
+
+ return (
+
+ {({ rotate }) =>
+
+ }
+
+ );
+ }
+
+}
+
+export default IconButton;
diff --git a/app/javascript/mastodon/components/status_action_bar.js b/app/javascript/mastodon/components/status_action_bar.js
index a6447b8ab..68ea9d6a2 100644
--- a/app/javascript/mastodon/components/status_action_bar.js
+++ b/app/javascript/mastodon/components/status_action_bar.js
@@ -124,6 +124,14 @@ class StatusActionBar extends ImmutablePureComponent {
}
}
+ handleBookmarkClick = () => {
+ this.props.onBookmark(this.props.status);
+ }
+
+ handleReblogClick = (e) => {
+ this.props.onReblog(this.props.status, e);
+ }
+
_openInteractionDialog = type => {
window.open(`/interact/${this.props.status.get('id')}?type=${type}`, 'mastodon-intent', 'width=445,height=600,resizable=no,menubar=no,status=no,scrollbars=yes');
}
diff --git a/app/javascript/mastodon/features/compose/components/announcements.js b/app/javascript/mastodon/features/compose/components/announcements.js
new file mode 100644
index 000000000..ad7043e89
--- /dev/null
+++ b/app/javascript/mastodon/features/compose/components/announcements.js
@@ -0,0 +1,127 @@
+import React from 'react';
+import Immutable from 'immutable';
+import PropTypes from 'prop-types';
+import Link from 'react-router-dom/Link';
+import { defineMessages, injectIntl } from 'react-intl';
+import IconButton from '../../../components/announcement_icon_button';
+import Motion from 'react-motion/lib/Motion';
+import spring from 'react-motion/lib/spring';
+
+const Collapsable = ({ fullHeight, minHeight, isVisible, children }) => (
+
+ {({ height }) =>
+
+ {children}
+
+ }
+
+);
+
+Collapsable.propTypes = {
+ fullHeight: PropTypes.number.isRequired,
+ minHeight: PropTypes.number.isRequired,
+ isVisible: PropTypes.bool.isRequired,
+ children: PropTypes.node.isRequired,
+};
+
+const messages = defineMessages({
+ toggle_visible: { id: 'media_gallery.toggle_visible', defaultMessage: 'Toggle visibility' },
+ welcome: { id: 'welcome.message', defaultMessage: '{domain}へようこそ!' },
+ markdown: { id: 'markdown.list', defaultMessage: 'markdown一覧' },
+});
+
+const hashtags = Immutable.fromJS([
+ '神崎ドン自己紹介',
+]);
+
+class Announcements extends React.PureComponent {
+
+ static propTypes = {
+ intl: PropTypes.object.isRequired,
+ homeSize: PropTypes.number,
+ isLoading: PropTypes.bool,
+ };
+
+ state = {
+ showId: null,
+ isLoaded: false,
+ };
+
+ onClick = (announcementId, currentState) => {
+ this.setState({ showId: currentState.showId === announcementId ? null : announcementId });
+ }
+ nl2br (text) {
+ return text.split(/(\n)/g).map((line, i) => {
+ if (line.match(/(\n)/g)) {
+ return React.createElement('br', { key: i });
+ }
+ return line;
+ });
+ }
+
+ render () {
+ const { intl } = this.props;
+
+ return (
+
+ );
+ }
+
+ componentWillReceiveProps (nextProps) {
+ if (!this.state.isLoaded) {
+ if (!nextProps.isLoading && (nextProps.homeSize === 0 || this.props.homeSize !== nextProps.homeSize)) {
+ this.setState({ isLoaded: true });
+ }
+ }
+ }
+
+}
+
+export default injectIntl(Announcements);
diff --git a/app/javascript/mastodon/features/compose/components/compose_form.js b/app/javascript/mastodon/features/compose/components/compose_form.js
index 8f9a8a261..81eb74c32 100644
--- a/app/javascript/mastodon/features/compose/components/compose_form.js
+++ b/app/javascript/mastodon/features/compose/components/compose_form.js
@@ -21,6 +21,7 @@ import ImmutablePureComponent from 'react-immutable-pure-component';
import { length } from 'stringz';
import { countableText } from '../util/counter';
import Icon from 'mastodon/components/icon';
+import { UserCounter } from './user_counter';
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';
@@ -29,6 +30,10 @@ const messages = defineMessages({
spoiler_placeholder: { id: 'compose_form.spoiler_placeholder', defaultMessage: 'Write your warning here' },
publish: { id: 'compose_form.publish', defaultMessage: 'Toot' },
publishLoud: { id: 'compose_form.publish_loud', defaultMessage: '{publish}!' },
+
+
+ utilBtns_goji: { id: 'compose_form.utilBtns_goji', defaultMessage: 'Typo!!!' },
+ utilBtns_harukin: { id: 'compose_form.utilBtns_harukin', defaultMessage: 'Burn Harukin' }
});
export default @injectIntl
@@ -61,7 +66,9 @@ class ComposeForm extends ImmutablePureComponent {
onPickEmoji: PropTypes.func.isRequired,
showSearch: PropTypes.bool,
anyMedia: PropTypes.bool,
- singleColumn: PropTypes.bool,
+ singleColumn: PropTypes.bool,
+ onGojiSubmit: PropTypes.func.isRequired,
+ onHarukinSubmit: PropTypes.func.isRequired
};
static defaultProps = {
@@ -87,7 +94,7 @@ class ComposeForm extends ImmutablePureComponent {
const fulltext = this.getFulltextForCharacterCounting();
const isOnlyWhitespace = fulltext.length !== 0 && fulltext.trim().length === 0;
- return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 500 || (isOnlyWhitespace && !anyMedia));
+ return !(isSubmitting || isUploading || isChangingUpload || length(fulltext) > 2048 || (isOnlyWhitespace && !anyMedia));
}
handleSubmit = () => {
@@ -194,6 +201,10 @@ class ComposeForm extends ImmutablePureComponent {
this.props.onPickEmoji(position, data, needsSpace);
}
+
+ handleOnGojiSubmit = () => this.props.onGojiSubmit(this.autosuggestTextarea.textarea);
+ handleOnHarukinSubmit = () => this.props.onHarukinSubmit(this.autosuggestTextarea.textarea);
+
render () {
const { intl, onPaste, showSearch } = this.props;
const disabled = this.props.isSubmitting;
@@ -259,11 +270,22 @@ class ComposeForm extends ImmutablePureComponent {
-
+
-
+
+
+
+
+
+
+
+
+
+
);
diff --git a/app/javascript/mastodon/features/compose/components/user_counter.js b/app/javascript/mastodon/features/compose/components/user_counter.js
new file mode 100644
index 000000000..e49d2f1a8
--- /dev/null
+++ b/app/javascript/mastodon/features/compose/components/user_counter.js
@@ -0,0 +1,10 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+export default class UserCounter extends React.PureComponent {
+ render () {
+ return (
+ 10人
+ );
+ }
+}
diff --git a/app/javascript/mastodon/features/compose/containers/announcements_container.js b/app/javascript/mastodon/features/compose/containers/announcements_container.js
new file mode 100644
index 000000000..e1dbb29b9
--- /dev/null
+++ b/app/javascript/mastodon/features/compose/containers/announcements_container.js
@@ -0,0 +1,11 @@
+import { connect } from 'react-redux';
+import Announcements from '../components/announcements';
+
+const mapStateToProps = state => {
+ return {
+ homeSize: state.getIn(['timelines', 'home', 'items']).size,
+ isLoading: state.getIn(['timelines', 'home', 'isLoading']),
+ };
+};
+
+export default connect(mapStateToProps)(Announcements);
diff --git a/app/javascript/mastodon/features/compose/containers/compose_form_container.js b/app/javascript/mastodon/features/compose/containers/compose_form_container.js
index 37a0e8845..d78b20fc7 100644
--- a/app/javascript/mastodon/features/compose/containers/compose_form_container.js
+++ b/app/javascript/mastodon/features/compose/containers/compose_form_container.js
@@ -11,6 +11,11 @@ import {
uploadCompose,
} from '../../../actions/compose';
+import {
+ submitGoji,
+ submitHarukin
+} from '../../../actions/UtilBtns';
+
const mapStateToProps = state => ({
text: state.getIn(['compose', 'text']),
suggestions: state.getIn(['compose', 'suggestions']),
@@ -60,6 +65,14 @@ const mapDispatchToProps = (dispatch) => ({
onPickEmoji (position, data, needsSpace) {
dispatch(insertEmojiCompose(position, data, needsSpace));
},
+
+ onGojiSubmit (textarea) {
+ dispatch(submitGoji(textarea));
+ },
+
+ onHarukinSubmit (textarea) {
+ dispatch(submitHarukin(textarea));
+ },
});
diff --git a/app/javascript/mastodon/features/compose/index.js b/app/javascript/mastodon/features/compose/index.js
index e2de8b0e6..e7e0fb423 100644
--- a/app/javascript/mastodon/features/compose/index.js
+++ b/app/javascript/mastodon/features/compose/index.js
@@ -1,4 +1,4 @@
-import React from 'react';
+import React, { Fragment } from 'react';
import ComposeFormContainer from './containers/compose_form_container';
import NavigationContainer from './containers/navigation_container';
import PropTypes from 'prop-types';
@@ -14,16 +14,28 @@ import SearchResultsContainer from './containers/search_results_container';
import { changeComposing } from '../../actions/compose';
import { openModal } from 'mastodon/actions/modal';
import elephantUIPlane from '../../../images/elephant_ui_plane.svg';
-import { mascot } from '../../initial_state';
+import { mascot, show_tab_bar_label } from '../../initial_state';
import Icon from 'mastodon/components/icon';
import { logOut } from 'mastodon/utils/log_out';
+import AnnouncementsContainer from './containers/announcements_container';
+import NotificationsCounterIcon from '../ui/components/notifications_counter_icon';
+import classNames from 'classnames';
const messages = defineMessages({
+ short_start: { id: 'navigation_bar.short.getting_started', defaultMessage: 'Started' },
+ short_home_timeline: { id: 'navigation_bar.short.home', defaultMessage: 'Home' },
+ short_notifications: { id: 'navigation_bar.short.notifications', defaultMessage: 'Notif.' },
+ short_public: { id: 'navigation_bar.short.public_timeline', defaultMessage: 'FTL' },
+ short_community: { id: 'navigation_bar.short.community_timeline', defaultMessage: 'LTL' },
+ short_lists: { id: 'navigation_bar.short.lists', defaultMessage: 'Lists' },
+ short_preferences: { id: 'navigation_bar.short.preferences', defaultMessage: 'Pref.' },
+ short_logout: { id: 'navigation_bar.short.logout', defaultMessage: 'Logout' },
start: { id: 'getting_started.heading', defaultMessage: 'Getting started' },
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
public: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
community: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
+ lists: { id: 'navigation_bar.lists', defaultMessage: 'Lists' },
preferences: { id: 'navigation_bar.preferences', defaultMessage: 'Preferences' },
logout: { id: 'navigation_bar.logout', defaultMessage: 'Logout' },
compose: { id: 'navigation_bar.compose', defaultMessage: 'Compose new toot' },
@@ -88,30 +100,54 @@ class Compose extends React.PureComponent {
this.props.dispatch(changeComposing(false));
}
+ tab (id) {
+ const { columns, intl: { formatMessage } } = this.props;
+
+ if (!columns.some(column => column.get('id') === id)) {
+ const tabParams = {
+ 'START': { to: '/getting-started', title: formatMessage(messages.start), label: formatMessage(messages.short_start), icon_id: 'bars' },
+ 'HOME': { to: '/timelines/home', title: formatMessage(messages.home_timeline), label: formatMessage(messages.short_home_timeline), icon_id: 'home' },
+ 'NOTIFICATIONS': { to: '/notifications', title: formatMessage(messages.notifications), label: formatMessage(messages.short_notifications), icon_id: 'bell' },
+ 'COMMUNITY': { to: '/timelines/public/local', title: formatMessage(messages.community), label: formatMessage(messages.short_community), icon_id: 'users' },
+ 'PUBLIC': { to: '/timelines/public', title: formatMessage(messages.public), label: formatMessage(messages.short_public), icon_id: 'globe' },
+ 'LIST': { to: '/lists', title: formatMessage(messages.lists), label: formatMessage(messages.short_lists), icon_id: 'list-ul' },
+ 'PREFERENCES': { href: '/settings/preferences', title: formatMessage(messages.preferences), label: formatMessage(messages.short_preferences), icon_id: 'cog' },
+ 'SIGN_OUT': { href: '/auth/sign_out', title: formatMessage(messages.logout), label: formatMessage(messages.short_logout), icon_id: 'sign-out', method: 'delete' },
+ };
+
+ const { href, to, title, label, icon_id, method } = tabParams[id];
+
+ const icon = (id === 'NOTIFICATIONS') ? : ;
+
+ if (href) {
+ return (
+ {icon}{label}
+ );
+ } else {
+ return (
+ {icon}{label}
+ );
+ }
+ }
+ return null;
+ }
+
render () {
const { multiColumn, showSearch, isSearchPage, intl } = this.props;
let header = '';
if (multiColumn) {
- const { columns } = this.props;
+ const defaultTabIds = ['START', 'HOME', 'NOTIFICATIONS', 'COMMUNITY', 'PUBLIC', 'LIST', 'PREFERENCES', 'SIGN_OUT'];
+// const defaultTabIds = ['START', 'HOME', 'NOTIFICATIONS', 'PUBLIC', 'LIST', 'PREFERENCES', 'SIGN_OUT'];
+
+ let tabs = defaultTabIds;
+
header = (
);
}
@@ -127,6 +163,7 @@ class Compose extends React.PureComponent {
+

diff --git a/app/javascript/mastodon/features/getting_started/index.js b/app/javascript/mastodon/features/getting_started/index.js
index 1b9994612..67cb7db1a 100644
--- a/app/javascript/mastodon/features/getting_started/index.js
+++ b/app/javascript/mastodon/features/getting_started/index.js
@@ -18,6 +18,7 @@ import TrendsContainer from './containers/trends_container';
const messages = defineMessages({
home_timeline: { id: 'tabs_bar.home', defaultMessage: 'Home' },
notifications: { id: 'tabs_bar.notifications', defaultMessage: 'Notifications' },
+ admin_notifications: { id: 'tabs_bar.admin_notifications', defaultMessage: 'Admin Notifications' },
public_timeline: { id: 'navigation_bar.public_timeline', defaultMessage: 'Federated timeline' },
settings_subheading: { id: 'column_subheading.settings', defaultMessage: 'Settings' },
community_timeline: { id: 'navigation_bar.community_timeline', defaultMessage: 'Local timeline' },
@@ -107,9 +108,10 @@ class GettingStarted extends ImmutablePureComponent {
if (profile_directory) {
navItems.push(
,
+
,
);
- height += 48;
+ height += 48*2;
}
navItems.push(
@@ -120,9 +122,10 @@ class GettingStarted extends ImmutablePureComponent {
} else if (profile_directory) {
navItems.push(
,
+
,
);
- height += 48;
+ height += 48*2;
}
if (multiColumn && !columns.find(item => item.get('id') === 'HOME')) {
diff --git a/app/javascript/mastodon/features/ui/components/columns_area.js b/app/javascript/mastodon/features/ui/components/columns_area.js
index 039abe432..bfb9561da 100644
--- a/app/javascript/mastodon/features/ui/components/columns_area.js
+++ b/app/javascript/mastodon/features/ui/components/columns_area.js
@@ -8,7 +8,7 @@ import ReactSwipeableViews from 'react-swipeable-views';
import TabsBar, { links, getIndex, getLink } from './tabs_bar';
import { Link } from 'react-router-dom';
-import { disableSwiping } from 'mastodon/initial_state';
+import { disableSwiping, place_tab_bar_at_bottom } from 'mastodon/initial_state';
import BundleContainer from '../containers/bundle_container';
import ColumnLoading from './column_loading';
@@ -34,6 +34,8 @@ import NavigationPanel from './navigation_panel';
import { supportsPassiveEvents } from 'detect-passive-events';
import { scrollRight } from '../../../scroll';
+import classNames from 'classnames';
+
const componentMap = {
'COMPOSE': Compose,
'HOME': HomeTimeline,
@@ -216,14 +218,14 @@ class ColumnsArea extends ImmutablePureComponent {
const columnIndex = getIndex(this.context.router.history.location.pathname);
if (singleColumn) {
- const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null :
;
+ const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null :
;
const content = columnIndex !== -1 ? (
-
+
{links.map(this.renderView)}
) : (
- {children}
+ {children}
);
return (
diff --git a/app/javascript/mastodon/features/ui/components/link_footer.js b/app/javascript/mastodon/features/ui/components/link_footer.js
index 3c4cff9f9..432fd5f14 100644
--- a/app/javascript/mastodon/features/ui/components/link_footer.js
+++ b/app/javascript/mastodon/features/ui/components/link_footer.js
@@ -53,6 +53,7 @@ class LinkFooter extends React.PureComponent {
·
·
·
+ ·
·
·
diff --git a/app/javascript/mastodon/features/ui/components/tabs_bar.js b/app/javascript/mastodon/features/ui/components/tabs_bar.js
index 1911da8ba..4252339ea 100644
--- a/app/javascript/mastodon/features/ui/components/tabs_bar.js
+++ b/app/javascript/mastodon/features/ui/components/tabs_bar.js
@@ -6,14 +6,16 @@ import { debounce } from 'lodash';
import { isUserTouching } from '../../../is_mobile';
import Icon from 'mastodon/components/icon';
import NotificationsCounterIcon from './notifications_counter_icon';
+import { place_tab_bar_at_bottom, show_tab_bar_label } from 'mastodon/initial_state';
+import classNames from 'classnames';
export const links = [
- ,
- ,
- ,
- ,
- ,
- ,
+ ,
+ ,
+ ,
+ ,
+ ,
+ ,
];
export function getIndex (path) {
@@ -31,7 +33,7 @@ class TabsBar extends React.PureComponent {
static propTypes = {
intl: PropTypes.object.isRequired,
history: PropTypes.object.isRequired,
- }
+ };
setRef = ref => {
this.node = ref;
@@ -74,8 +76,8 @@ class TabsBar extends React.PureComponent {
return (
-