diff --git a/app/javascript/flavours/glitch/components/autosuggest_input.js b/app/javascript/flavours/glitch/components/autosuggest_input.js
index 5fc952d8e..a6ae3bc75 100644
--- a/app/javascript/flavours/glitch/components/autosuggest_input.js
+++ b/app/javascript/flavours/glitch/components/autosuggest_input.js
@@ -49,7 +49,7 @@ export default class AutosuggestInput extends ImmutablePureComponent {
autoFocus: PropTypes.bool,
className: PropTypes.string,
id: PropTypes.string,
- searchTokens: PropTypes.arrayOf(PropTypes.string),
+ searchTokens: ImmutablePropTypes.list,
maxLength: PropTypes.number,
};
diff --git a/app/javascript/flavours/glitch/features/compose/index.js b/app/javascript/flavours/glitch/features/compose/index.js
index a7795a04d..d3070a199 100644
--- a/app/javascript/flavours/glitch/features/compose/index.js
+++ b/app/javascript/flavours/glitch/features/compose/index.js
@@ -61,12 +61,12 @@ class Compose extends React.PureComponent {
+
{view}
);
@@ -164,13 +164,17 @@ export default class ColumnsArea extends ImmutablePureComponent {
const floatingActionButton = shouldHideFAB(this.context.router.history.location.pathname) ? null :
;
return columnIndex !== -1 ? [
+
,
+
{links.map(this.renderView)}
,
floatingActionButton,
] : [
-
{children}
,
+
,
+
+
{children}
,
floatingActionButton,
];
diff --git a/app/javascript/flavours/glitch/features/ui/components/notifications_counter_icon.js b/app/javascript/flavours/glitch/features/ui/components/notifications_counter_icon.js
new file mode 100644
index 000000000..137658b94
--- /dev/null
+++ b/app/javascript/flavours/glitch/features/ui/components/notifications_counter_icon.js
@@ -0,0 +1,24 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+import { connect } from 'react-redux';
+import Icon from 'flavours/glitch/components/icon';
+
+const mapStateToProps = state => ({
+ count: state.getIn(['notifications', 'unread']),
+ showBadge: state.getIn(['local_settings', 'notifications', 'tab_badge']),
+});
+
+const formatNumber = num => num > 99 ? '99+' : num;
+
+const NotificationsCounterIcon = ({ count, showBadge }) => (
+
+
+ {showBadge && count > 0 && {formatNumber(count)}}
+
+);
+
+NotificationsCounterIcon.propTypes = {
+ count: PropTypes.number.isRequired,
+};
+
+export default connect(mapStateToProps)(NotificationsCounterIcon);
diff --git a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
index b44a21a42..8963b16b3 100644
--- a/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
+++ b/app/javascript/flavours/glitch/features/ui/components/tabs_bar.js
@@ -4,34 +4,11 @@ import { NavLink, withRouter } from 'react-router-dom';
import { FormattedMessage, injectIntl } from 'react-intl';
import { debounce } from 'lodash';
import { isUserTouching } from 'flavours/glitch/util/is_mobile';
-import { connect } from 'react-redux';
-
-const mapStateToProps = state => ({
- unreadNotifications: state.getIn(['notifications', 'unread']),
- showBadge: state.getIn(['local_settings', 'notifications', 'tab_badge']),
-});
-
-@connect(mapStateToProps)
-class NotificationsIcon extends React.PureComponent {
- static propTypes = {
- unreadNotifications: PropTypes.number,
- showBadge: PropTypes.bool,
- };
-
- render() {
- const { unreadNotifications, showBadge } = this.props;
- return (
-
-
- { showBadge && unreadNotifications > 0 && }
-
- );
- }
-}
+import NotificationsCounterIcon from './notifications_counter_icon';
export const links = [
,
-
,
+
,
,
,
diff --git a/app/javascript/flavours/glitch/features/ui/index.js b/app/javascript/flavours/glitch/features/ui/index.js
index f8fff934d..36156a5ef 100644
--- a/app/javascript/flavours/glitch/features/ui/index.js
+++ b/app/javascript/flavours/glitch/features/ui/index.js
@@ -2,7 +2,6 @@ import React from 'react';
import NotificationsContainer from './containers/notifications_container';
import PropTypes from 'prop-types';
import LoadingBarContainer from './containers/loading_bar_container';
-import TabsBar from './components/tabs_bar';
import ModalContainer from './containers/modal_container';
import { connect } from 'react-redux';
import { Redirect, withRouter } from 'react-router-dom';
@@ -69,6 +68,7 @@ const mapStateToProps = state => ({
unreadNotifications: state.getIn(['notifications', 'unread']),
showFaviconBadge: state.getIn(['local_settings', 'notifications', 'favicon_badge']),
hicolorPrivacyIcons: state.getIn(['local_settings', 'hicolor_privacy_icons']),
+ forceSingleColumn: state.getIn(['settings', 'forceSingleColumn'], false),
});
const keyMap = {
@@ -126,6 +126,7 @@ export default class UI extends React.Component {
dropdownMenuIsOpen: PropTypes.bool,
unreadNotifications: PropTypes.number,
showFaviconBadge: PropTypes.bool,
+ forceSingleColumn: PropTypes.bool,
};
state = {
@@ -431,7 +432,9 @@ export default class UI extends React.Component {
render () {
const { width, draggingOver } = this.state;
- const { children, layout, isWide, navbarUnder, dropdownMenuIsOpen } = this.props;
+ const { children, layout, isWide, navbarUnder, dropdownMenuIsOpen, forceSingleColumn } = this.props;
+ const singleColumn = forceSingleColumn || isMobile(width, layout);
+ const redirect = singleColumn ?
:
;
const columnsClass = layout => {
switch (layout) {
@@ -475,11 +478,9 @@ export default class UI extends React.Component {
return (
- {navbarUnder ? null : (
)}
-
-
+
-
+ {redirect}
@@ -518,7 +519,6 @@ export default class UI extends React.Component {
- {navbarUnder ? () : null}
diff --git a/app/javascript/flavours/glitch/reducers/settings.js b/app/javascript/flavours/glitch/reducers/settings.js
index a37863a69..a568183df 100644
--- a/app/javascript/flavours/glitch/reducers/settings.js
+++ b/app/javascript/flavours/glitch/reducers/settings.js
@@ -15,6 +15,8 @@ const initialState = ImmutableMap({
skinTone: 1,
+ forceSingleColumn: false,
+
home: ImmutableMap({
shows: ImmutableMap({
reblog: true,
diff --git a/app/javascript/flavours/glitch/styles/components/columns.scss b/app/javascript/flavours/glitch/styles/components/columns.scss
index 0bf01ed8d..50438393e 100644
--- a/app/javascript/flavours/glitch/styles/components/columns.scss
+++ b/app/javascript/flavours/glitch/styles/components/columns.scss
@@ -13,16 +13,6 @@
position: relative;
}
-@include limited-single-column('screen and (min-width: 360px)', $parent: null) {
- .columns-area {
- padding: 10px;
- }
-
- .react-swipeable-view-container .columns-area {
- height: calc(100% - 20px) !important;
- }
-}
-
.react-swipeable-view-container {
&,
.columns-area,
@@ -63,34 +53,6 @@
overflow: hidden;
}
-@include limited-single-column('screen and (min-width: 360px)', $parent: null) {
- .tabs-bar {
- margin: 10px;
- margin-bottom: 0;
- }
-}
-
-:root { // Overrides .wide stylings for mobile view
- @include single-column('screen and (max-width: 630px)', $parent: null) {
- .column {
- flex: auto;
- width: 100%;
- min-width: 0;
- max-width: none;
- padding: 0;
- }
-
- .columns-area {
- flex-direction: column;
- }
-
- .search__input,
- .autosuggest-textarea__textarea {
- font-size: 16px;
- }
- }
-}
-
@include multi-columns('screen and (min-width: 631px)', $parent: null) {
.columns-area {
padding: 0;
@@ -442,6 +404,10 @@
contain: strict;
}
+ & > span {
+ max-width: 400px;
+ }
+
a {
color: $highlight-text-color;
text-decoration: none;
diff --git a/app/javascript/flavours/glitch/styles/components/drawer.scss b/app/javascript/flavours/glitch/styles/components/drawer.scss
index 9f426448f..07558a8d0 100644
--- a/app/javascript/flavours/glitch/styles/components/drawer.scss
+++ b/app/javascript/flavours/glitch/styles/components/drawer.scss
@@ -276,6 +276,7 @@
background: lighten($ui-base-color, 13%) url('data:image/svg+xml;utf8,') no-repeat bottom / 100% auto;
flex: 1;
min-height: 47px;
+ display: none;
> img {
display: block;
@@ -295,6 +296,10 @@
border: none;
cursor: inherit;
}
+
+ @media screen and (min-height: 640px) {
+ display: block;
+ }
}
.pseudo-drawer {
diff --git a/app/javascript/flavours/glitch/styles/components/index.scss b/app/javascript/flavours/glitch/styles/components/index.scss
index 9db64bbcb..8f385e15a 100644
--- a/app/javascript/flavours/glitch/styles/components/index.scss
+++ b/app/javascript/flavours/glitch/styles/components/index.scss
@@ -553,6 +553,7 @@
}
.tabs-bar {
+ box-sizing: border-box;
display: flex;
background: lighten($ui-base-color, 8%);
flex: 0 0 auto;
@@ -590,15 +591,130 @@
}
}
- span:last-child {
+ span {
margin-left: 5px;
display: none;
}
}
-@include multi-columns('screen and (min-width: 631px)', $parent: null) {
+@media screen and (min-width: 600px) {
+ .tabs-bar__link {
+ span {
+ display: inline;
+ }
+ }
+}
+
+.columns-area--mobile {
+ flex-direction: column;
+ width: 100%;
+ max-width: 600px;
+ margin: 0 auto;
+
+ .column,
+ .drawer {
+ width: 100%;
+ height: 100%;
+ padding: 0;
+ }
+
+ .search__input,
+ .autosuggest-textarea__textarea {
+ font-size: 16px;
+ }
+
+ @media screen and (min-width: 360px) {
+ padding: 10px;
+ }
+
+ @media screen and (min-width: 630px) {
+ .detailed-status {
+ padding: 15px;
+
+ .media-gallery,
+ .video-player {
+ margin-top: 15px;
+ }
+ }
+
+ .account__header__bar {
+ padding: 5px 10px;
+ }
+
+ .navigation-bar,
+ .compose-form {
+ padding: 15px;
+ }
+
+ .compose-form .compose-form__publish .compose-form__publish-button-wrapper {
+ padding-top: 15px;
+ }
+
+ .status {
+ padding: 15px 15px 15px (48px + 15px * 2);
+ min-height: 48px + 2px;
+
+ &__avatar {
+ left: 15px;
+ top: 17px;
+ }
+
+ &__content {
+ padding-top: 5px;
+ }
+
+ &__prepend {
+ margin-left: 48px + 15px * 2;
+ padding-top: 15px;
+ }
+
+ &__prepend-icon-wrapper {
+ left: -32px;
+ }
+
+ .media-gallery,
+ &__action-bar,
+ .video-player {
+ margin-top: 10px;
+ }
+ }
+ }
+}
+
+@media screen and (min-width: 360px) {
.tabs-bar {
- display: none;
+ margin: 10px auto;
+ margin-bottom: 0;
+ width: calc(100% - 20px);
+ max-width: 600px;
+ }
+
+ .react-swipeable-view-container .columns-area--mobile {
+ height: calc(100% - 20px) !important;
+ }
+
+ .getting-started__wrapper,
+ .getting-started__trends,
+ .search {
+ margin-bottom: 10px;
+ }
+}
+
+.icon-with-badge {
+ position: relative;
+
+ &__badge {
+ position: absolute;
+ right: -13px;
+ top: -13px;
+ background: $ui-highlight-color;
+ border: 2px solid lighten($ui-base-color, 8%);
+ padding: 1px 6px;
+ border-radius: 6px;
+ font-size: 10px;
+ font-weight: 500;
+ line-height: 14px;
+ color: $primary-text-color;
}
}
@@ -1272,6 +1388,61 @@
height: 1em;
}
+.navigational-toggle {
+ padding: 10px;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ font-size: 14px;
+ color: $dark-text-color;
+}
+
+.layout-toggle {
+ display: flex;
+ padding: 5px;
+
+ button {
+ box-sizing: border-box;
+ flex: 0 0 50%;
+ background: transparent;
+ padding: 5px;
+ border: 0;
+ position: relative;
+
+ &:hover,
+ &:focus,
+ &:active {
+ svg path:first-child {
+ fill: lighten($ui-base-color, 16%);
+ }
+ }
+ }
+
+ svg {
+ width: 100%;
+ height: auto;
+
+ path:first-child {
+ fill: lighten($ui-base-color, 12%);
+ }
+
+ path:last-child {
+ fill: darken($ui-base-color, 14%);
+ }
+ }
+
+ &__active {
+ color: $ui-highlight-color;
+ position: absolute;
+ top: 50%;
+ left: 50%;
+ transform: translate(-50%, -50%);
+ background: lighten($ui-base-color, 12%);
+ border-radius: 50%;
+ padding: 0.35rem;
+ }
+}
+
::-webkit-scrollbar-thumb {
border-radius: 0;
}