[Glitch] Add responsive panels to the single-column layout
Port 1e5532e693 to glitch-soc
Signed-off-by: Thibaut Girka <thib@sitedethib.com>
			
			
This commit is contained in:
		| @@ -68,6 +68,14 @@ const messages = defineMessages({ | ||||
|   uploadErrorPoll:  { id: 'upload_error.poll', defaultMessage: 'File upload not allowed with polls.' }, | ||||
| }); | ||||
|  | ||||
| const COMPOSE_PANEL_BREAKPOINT = 600 + (285 * 1) + (10 * 3); | ||||
|  | ||||
| export const ensureComposeIsVisible = (getState, routerHistory) => { | ||||
|   if (!getState().getIn(['compose', 'mounted']) && window.innerWidth < COMPOSE_PANEL_BREAKPOINT) { | ||||
|     routerHistory.push('/statuses/new'); | ||||
|   } | ||||
| }; | ||||
|  | ||||
| export function changeCompose(text) { | ||||
|   return { | ||||
|     type: COMPOSE_CHANGE, | ||||
| @@ -81,16 +89,14 @@ export function cycleElefriendCompose() { | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function replyCompose(status, router) { | ||||
| export function replyCompose(status, routerHistory) { | ||||
|   return (dispatch, getState) => { | ||||
|     dispatch({ | ||||
|       type: COMPOSE_REPLY, | ||||
|       status: status, | ||||
|     }); | ||||
|  | ||||
|     if (router && !getState().getIn(['compose', 'mounted'])) { | ||||
|       router.push('/statuses/new'); | ||||
|     } | ||||
|     ensureComposeIsVisible(getState, routerHistory); | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| @@ -106,29 +112,25 @@ export function resetCompose() { | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function mentionCompose(account, router) { | ||||
| export function mentionCompose(account, routerHistory) { | ||||
|   return (dispatch, getState) => { | ||||
|     dispatch({ | ||||
|       type: COMPOSE_MENTION, | ||||
|       account: account, | ||||
|     }); | ||||
|  | ||||
|     if (!getState().getIn(['compose', 'mounted'])) { | ||||
|       router.push('/statuses/new'); | ||||
|     } | ||||
|     ensureComposeIsVisible(getState, routerHistory); | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function directCompose(account, router) { | ||||
| export function directCompose(account, routerHistory) { | ||||
|   return (dispatch, getState) => { | ||||
|     dispatch({ | ||||
|       type: COMPOSE_DIRECT, | ||||
|       account: account, | ||||
|     }); | ||||
|  | ||||
|     if (!getState().getIn(['compose', 'mounted'])) { | ||||
|       router.push('/statuses/new'); | ||||
|     } | ||||
|     ensureComposeIsVisible(getState, routerHistory); | ||||
|   }; | ||||
| }; | ||||
|  | ||||
|   | ||||
| @@ -2,6 +2,7 @@ import api from 'flavours/glitch/util/api'; | ||||
|  | ||||
| import { deleteFromTimelines } from './timelines'; | ||||
| import { importFetchedStatus, importFetchedStatuses } from './importer'; | ||||
| import { ensureComposeIsVisible } from './compose'; | ||||
|  | ||||
| export const STATUS_FETCH_REQUEST = 'STATUS_FETCH_REQUEST'; | ||||
| export const STATUS_FETCH_SUCCESS = 'STATUS_FETCH_SUCCESS'; | ||||
| @@ -80,7 +81,7 @@ export function redraft(status, raw_text, content_type) { | ||||
|   }; | ||||
| }; | ||||
|  | ||||
| export function deleteStatus(id, router, withRedraft = false) { | ||||
| export function deleteStatus(id, routerHistory, withRedraft = false) { | ||||
|   return (dispatch, getState) => { | ||||
|     let status = getState().getIn(['statuses', id]); | ||||
|  | ||||
| @@ -97,9 +98,7 @@ export function deleteStatus(id, router, withRedraft = false) { | ||||
|       if (withRedraft) { | ||||
|         dispatch(redraft(status, response.data.text, response.data.content_type)); | ||||
|  | ||||
|         if (!getState().getIn(['compose', 'mounted'])) { | ||||
|           router.push('/statuses/new'); | ||||
|         } | ||||
|         ensureComposeIsVisible(getState, routerHistory); | ||||
|       } | ||||
|     }).catch(error => { | ||||
|       dispatch(deleteStatusFail(id, error)); | ||||
|   | ||||
| @@ -49,7 +49,7 @@ export default class AutosuggestInput extends ImmutablePureComponent { | ||||
|     autoFocus: PropTypes.bool, | ||||
|     className: PropTypes.string, | ||||
|     id: PropTypes.string, | ||||
|     searchTokens: ImmutablePropTypes.list, | ||||
|     searchTokens: PropTypes.arrayOf(PropTypes.string), | ||||
|     maxLength: PropTypes.number, | ||||
|   }; | ||||
|  | ||||
|   | ||||
| @@ -17,7 +17,7 @@ export default class NavigationBar extends ImmutablePureComponent { | ||||
|       <div className='drawer--account'> | ||||
|         <Permalink className='avatar' href={this.props.account.get('url')} to={`/accounts/${this.props.account.get('id')}`}> | ||||
|           <span style={{ display: 'none' }}>{this.props.account.get('acct')}</span> | ||||
|           <Avatar account={this.props.account} size={40} /> | ||||
|           <Avatar account={this.props.account} size={48} /> | ||||
|         </Permalink> | ||||
|  | ||||
|         <Permalink className='acct' href={this.props.account.get('url')} to={`/accounts/${this.props.account.get('id')}`}> | ||||
|   | ||||
| @@ -60,6 +60,10 @@ class SearchPopout extends React.PureComponent { | ||||
| export default @injectIntl | ||||
| class Search extends React.PureComponent { | ||||
|  | ||||
|   static contextTypes = { | ||||
|     router: PropTypes.object.isRequired, | ||||
|   }; | ||||
|  | ||||
|   static propTypes = { | ||||
|     value: PropTypes.string.isRequired, | ||||
|     submitted: PropTypes.bool, | ||||
| @@ -67,6 +71,7 @@ class Search extends React.PureComponent { | ||||
|     onSubmit: PropTypes.func.isRequired, | ||||
|     onClear: PropTypes.func.isRequired, | ||||
|     onShow: PropTypes.func.isRequired, | ||||
|     openInRoute: PropTypes.bool, | ||||
|     intl: PropTypes.object.isRequired, | ||||
|   }; | ||||
|  | ||||
| @@ -109,8 +114,10 @@ class Search extends React.PureComponent { | ||||
|     const { onSubmit } = this.props; | ||||
|     switch (e.key) { | ||||
|     case 'Enter': | ||||
|       if (onSubmit) { | ||||
|         onSubmit(); | ||||
|       onSubmit(); | ||||
|  | ||||
|       if (this.props.openInRoute) { | ||||
|         this.context.router.history.push('/search'); | ||||
|       } | ||||
|       break; | ||||
|     case 'Escape': | ||||
|   | ||||
| @@ -10,12 +10,10 @@ import ImmutablePropTypes from 'react-immutable-proptypes'; | ||||
| import ImmutablePureComponent from 'react-immutable-pure-component'; | ||||
| import { me, invitesEnabled, version } from 'flavours/glitch/util/initial_state'; | ||||
| import { fetchFollowRequests } from 'flavours/glitch/actions/accounts'; | ||||
| import { changeSetting } from 'flavours/glitch/actions/settings'; | ||||
| import { List as ImmutableList } from 'immutable'; | ||||
| import { createSelector } from 'reselect'; | ||||
| import { fetchLists } from 'flavours/glitch/actions/lists'; | ||||
| import { preferencesLink, profileLink, signOutLink } from 'flavours/glitch/util/backend_links'; | ||||
| import Toggle from 'react-toggle'; | ||||
|  | ||||
| const messages = defineMessages({ | ||||
|   heading: { id: 'getting_started.heading', defaultMessage: 'Getting started' }, | ||||
| @@ -54,7 +52,6 @@ const makeMapStateToProps = () => { | ||||
|     columns: state.getIn(['settings', 'columns']), | ||||
|     unreadFollowRequests: state.getIn(['user_lists', 'follow_requests', 'items'], ImmutableList()).size, | ||||
|     unreadNotifications: state.getIn(['notifications', 'unread']), | ||||
|     forceSingleColumn: state.getIn(['settings', 'forceSingleColumn'], false), | ||||
|   }); | ||||
|  | ||||
|   return mapStateToProps; | ||||
| @@ -64,7 +61,6 @@ const mapDispatchToProps = dispatch => ({ | ||||
|   fetchFollowRequests: () => dispatch(fetchFollowRequests()), | ||||
|   fetchLists: () => dispatch(fetchLists()), | ||||
|   openSettings: () => dispatch(openModal('SETTINGS', {})), | ||||
|   changeForceSingleColumn: checked => dispatch(changeSetting(['forceSingleColumn'], checked)), | ||||
| }); | ||||
|  | ||||
| const badgeDisplay = (number, limit) => { | ||||
| @@ -92,8 +88,6 @@ export default class GettingStarted extends ImmutablePureComponent { | ||||
|     lists: ImmutablePropTypes.list, | ||||
|     fetchLists: PropTypes.func.isRequired, | ||||
|     openSettings: PropTypes.func.isRequired, | ||||
|     forceSingleColumn: PropTypes.bool, | ||||
|     changeForceSingleColumn: PropTypes.func.isRequired, | ||||
|   }; | ||||
|  | ||||
|   componentWillMount () { | ||||
| @@ -108,12 +102,8 @@ export default class GettingStarted extends ImmutablePureComponent { | ||||
|     } | ||||
|   } | ||||
|  | ||||
|   handleForceSingleColumnChange = ({ target }) => { | ||||
|     this.props.changeForceSingleColumn(target.checked); | ||||
|   } | ||||
|  | ||||
|   render () { | ||||
|     const { intl, myAccount, columns, multiColumn, unreadFollowRequests, unreadNotifications, lists, openSettings, forceSingleColumn } = this.props; | ||||
|     const { intl, myAccount, columns, multiColumn, unreadFollowRequests, unreadNotifications, lists, openSettings } = this.props; | ||||
|  | ||||
|     const navItems = []; | ||||
|     let listItems = []; | ||||
| @@ -193,11 +183,6 @@ export default class GettingStarted extends ImmutablePureComponent { | ||||
|             </p> | ||||
|           </div> | ||||
|         </div> | ||||
|  | ||||
|         <label className='navigational-toggle'> | ||||
|           <FormattedMessage id='getting_started.use_simple_layout' defaultMessage='Use simple layout' /> | ||||
|           <Toggle checked={forceSingleColumn} onChange={this.handleForceSingleColumnChange} /> | ||||
|         </label> | ||||
|       </Column> | ||||
|     ); | ||||
|   } | ||||
|   | ||||
							
								
								
									
										17
									
								
								app/javascript/flavours/glitch/features/search/index.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								app/javascript/flavours/glitch/features/search/index.js
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| import React from 'react'; | ||||
| import SearchContainer from 'flavours/glitch/features/compose/containers/search_container'; | ||||
| import SearchResultsContainer from 'flavours/glitch/features/compose/containers/search_results_container'; | ||||
|  | ||||
| const Search = () => ( | ||||
|   <div className='column search-page'> | ||||
|     <SearchContainer /> | ||||
|  | ||||
|     <div className='drawer__pager'> | ||||
|       <div className='drawer__inner darker'> | ||||
|         <SearchResultsContainer /> | ||||
|       </div> | ||||
|     </div> | ||||
|   </div> | ||||
| ); | ||||
|  | ||||
| export default Search; | ||||
| @@ -13,6 +13,8 @@ import ColumnLoading from './column_loading'; | ||||
| import DrawerLoading from './drawer_loading'; | ||||
| import BundleColumnError from './bundle_column_error'; | ||||
| import { Compose, Notifications, HomeTimeline, CommunityTimeline, PublicTimeline, HashtagTimeline, DirectTimeline, FavouritedStatuses, BookmarkedStatuses, ListTimeline } from 'flavours/glitch/util/async-components'; | ||||
| import ComposePanel from './compose_panel'; | ||||
| import NavigationPanel from './navigation_panel'; | ||||
|  | ||||
| import detectPassiveEvents from 'detect-passive-events'; | ||||
| import { scrollRight } from 'flavours/glitch/util/scroll'; | ||||
| @@ -173,14 +175,22 @@ export default class ColumnsArea extends ImmutablePureComponent { | ||||
|  | ||||
|       return ( | ||||
|         <div className='columns-area__panels'> | ||||
|           <div className='columns-area__panels__pane' /> | ||||
|           <div className='columns-area__panels__pane columns-area__panels__pane--compositional'> | ||||
|             <div className='columns-area__panels__pane__inner'> | ||||
|               <ComposePanel /> | ||||
|             </div> | ||||
|           </div> | ||||
|  | ||||
|           <div className='columns-area__panels__main'> | ||||
|             <TabsBar key='tabs' /> | ||||
|             {content} | ||||
|           </div> | ||||
|  | ||||
|           <div className='columns-area__panels__pane' /> | ||||
|           <div className='columns-area__panels__pane columns-area__panels__pane--start columns-area__panels__pane--navigational'> | ||||
|             <div className='columns-area__panels__pane__inner'> | ||||
|               <NavigationPanel /> | ||||
|             </div> | ||||
|           </div> | ||||
|  | ||||
|           {floatingActionButton} | ||||
|         </div> | ||||
|   | ||||
| @@ -0,0 +1,41 @@ | ||||
| import React from 'react'; | ||||
| import SearchContainer from 'flavours/glitch/features/compose/containers/search_container'; | ||||
| import ComposeFormContainer from 'flavours/glitch/features/compose/containers/compose_form_container'; | ||||
| import NavigationContainer from 'flavours/glitch/features/compose/containers/navigation_container'; | ||||
| import { invitesEnabled, version, repository, source_url } from 'mastodon/initial_state'; | ||||
| import { Link } from 'react-router-dom'; | ||||
| import { FormattedMessage } from 'react-intl'; | ||||
|  | ||||
| const ComposePanel = () => ( | ||||
|   <div className='compose-panel'> | ||||
|     <SearchContainer openInRoute /> | ||||
|     <NavigationContainer /> | ||||
|     <ComposeFormContainer /> | ||||
|  | ||||
|     <div className='flex-spacer' /> | ||||
|  | ||||
|     <div className='getting-started__footer'> | ||||
|       <ul> | ||||
|         {invitesEnabled && <li><a href='/invites' target='_blank'><FormattedMessage id='getting_started.invite' defaultMessage='Invite people' /></a> · </li>} | ||||
|         <li><Link to='/keyboard-shortcuts'><FormattedMessage id='navigation_bar.keyboard_shortcuts' defaultMessage='Hotkeys' /></Link> · </li> | ||||
|         <li><a href='/auth/edit'><FormattedMessage id='getting_started.security' defaultMessage='Security' /></a> · </li> | ||||
|         <li><a href='/about/more' target='_blank'><FormattedMessage id='navigation_bar.info' defaultMessage='About this server' /></a> · </li> | ||||
|         <li><a href='https://joinmastodon.org/apps' target='_blank'><FormattedMessage id='navigation_bar.apps' defaultMessage='Mobile apps' /></a> · </li> | ||||
|         <li><a href='/terms' target='_blank'><FormattedMessage id='getting_started.terms' defaultMessage='Terms of service' /></a> · </li> | ||||
|         <li><a href='/settings/applications' target='_blank'><FormattedMessage id='getting_started.developers' defaultMessage='Developers' /></a> · </li> | ||||
|         <li><a href='https://docs.joinmastodon.org' target='_blank'><FormattedMessage id='getting_started.documentation' defaultMessage='Documentation' /></a> · </li> | ||||
|         <li><a href='/auth/sign_out' data-method='delete'><FormattedMessage id='navigation_bar.logout' defaultMessage='Logout' /></a></li> | ||||
|       </ul> | ||||
|  | ||||
|       <p> | ||||
|         <FormattedMessage | ||||
|           id='getting_started.open_source_notice' | ||||
|           defaultMessage='Mastodon is open source software. You can contribute or report issues on GitHub at {github}.' | ||||
|           values={{ github: <span><a href={source_url} rel='noopener' target='_blank'>{repository}</a> (v{version})</span> }} | ||||
|         /> | ||||
|       </p> | ||||
|     </div> | ||||
|   </div> | ||||
| ); | ||||
|  | ||||
| export default ComposePanel; | ||||
| @@ -0,0 +1,55 @@ | ||||
| import React from 'react'; | ||||
| import PropTypes from 'prop-types'; | ||||
| import ImmutablePropTypes from 'react-immutable-proptypes'; | ||||
| import ImmutablePureComponent from 'react-immutable-pure-component'; | ||||
| import { fetchLists } from 'flavours/glitch/actions/lists'; | ||||
| import { connect } from 'react-redux'; | ||||
| import { createSelector } from 'reselect'; | ||||
| import { NavLink, withRouter } from 'react-router-dom'; | ||||
| import Icon from 'flavours/glitch/components/icon'; | ||||
|  | ||||
| const getOrderedLists = createSelector([state => state.get('lists')], lists => { | ||||
|   if (!lists) { | ||||
|     return lists; | ||||
|   } | ||||
|  | ||||
|   return lists.toList().filter(item => !!item).sort((a, b) => a.get('title').localeCompare(b.get('title'))); | ||||
| }); | ||||
|  | ||||
| const mapStateToProps = state => ({ | ||||
|   lists: getOrderedLists(state), | ||||
| }); | ||||
|  | ||||
| export default @withRouter | ||||
| @connect(mapStateToProps) | ||||
| class ListPanel extends ImmutablePureComponent { | ||||
|  | ||||
|   static propTypes = { | ||||
|     dispatch: PropTypes.func.isRequired, | ||||
|     lists: ImmutablePropTypes.list, | ||||
|   }; | ||||
|  | ||||
|   componentDidMount () { | ||||
|     const { dispatch } = this.props; | ||||
|     dispatch(fetchLists()); | ||||
|   } | ||||
|  | ||||
|   render () { | ||||
|     const { lists } = this.props; | ||||
|  | ||||
|     if (!lists) { | ||||
|       return null; | ||||
|     } | ||||
|  | ||||
|     return ( | ||||
|       <div> | ||||
|         <hr /> | ||||
|  | ||||
|         {lists.map(list => ( | ||||
|           <NavLink key={list.get('id')} className='column-link column-link--transparent' strict to={`/timelines/list/${list.get('id')}`}><Icon className='column-link__icon' icon='list-ul' fixedWidth />{list.get('title')}</NavLink> | ||||
|         ))} | ||||
|       </div> | ||||
|     ); | ||||
|   } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,27 @@ | ||||
| import React from 'react'; | ||||
| import { NavLink, withRouter } from 'react-router-dom'; | ||||
| import { FormattedMessage } from 'react-intl'; | ||||
| import Icon from 'flavours/glitch/components/icon'; | ||||
| import NotificationsCounterIcon from './notifications_counter_icon'; | ||||
| import ListPanel from './list_panel'; | ||||
|  | ||||
| const NavigationPanel = () => ( | ||||
|   <div className='navigation-panel'> | ||||
|     <NavLink className='column-link column-link--transparent' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><Icon className='column-link__icon' icon='home' fixedWidth /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink> | ||||
|     <NavLink className='column-link column-link--transparent' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon className='column-link__icon' /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink> | ||||
|     <NavLink className='column-link column-link--transparent' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><Icon className='column-link__icon' icon='users' fixedWidth /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink> | ||||
|     <NavLink className='column-link column-link--transparent' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><Icon className='column-link__icon' icon='globe' fixedWidth /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink> | ||||
|     <NavLink className='column-link column-link--transparent' to='/timelines/direct'><Icon className='column-link__icon' icon='envelope' fixedWidth /><FormattedMessage id='navigation_bar.direct' defaultMessage='Direct messages' /></NavLink> | ||||
|     <NavLink className='column-link column-link--transparent' to='/favourites'><Icon className='column-link__icon' icon='star' fixedWidth /><FormattedMessage id='navigation_bar.favourites' defaultMessage='Favourites' /></NavLink> | ||||
|     <NavLink className='column-link column-link--transparent' to='/lists'><Icon className='column-link__icon' icon='list-ul' fixedWidth /><FormattedMessage id='navigation_bar.lists' defaultMessage='Lists' /></NavLink> | ||||
|  | ||||
|     <ListPanel /> | ||||
|  | ||||
|     <hr /> | ||||
|  | ||||
|     <a className='column-link column-link--transparent' href='/settings/preferences' target='_blank'><Icon className='column-link__icon' icon='cog' fixedWidth /><FormattedMessage id='navigation_bar.preferences' defaultMessage='Preferences' /></a> | ||||
|     <a className='column-link column-link--transparent' href='/relationships' target='_blank'><Icon className='column-link__icon' icon='address-book-o' fixedWidth /><FormattedMessage id='navigation_bar.follows_and_followers' defaultMessage='Follows and followers' /></a> | ||||
|   </div> | ||||
| ); | ||||
|  | ||||
| export default withRouter(NavigationPanel); | ||||
| @@ -10,15 +10,17 @@ const mapStateToProps = state => ({ | ||||
|  | ||||
| const formatNumber = num => num > 99 ? '99+' : num; | ||||
|  | ||||
| const NotificationsCounterIcon = ({ count, showBadge }) => ( | ||||
| const NotificationsCounterIcon = ({ count, className, showBadge }) => ( | ||||
|   <i className='icon-with-badge'> | ||||
|     <Icon icon='bell' fixedWidth /> | ||||
|     <Icon icon='bell' fixedWidth className={className} /> | ||||
|     {showBadge && count > 0 && <i className='icon-with-badge__badge'>{formatNumber(count)}</i>} | ||||
|   </i> | ||||
| ); | ||||
|  | ||||
| NotificationsCounterIcon.propTypes = { | ||||
|   count: PropTypes.number.isRequired, | ||||
|   showBadge: PropTypes.bool, | ||||
|   className: PropTypes.string, | ||||
| }; | ||||
|  | ||||
| export default connect(mapStateToProps)(NotificationsCounterIcon); | ||||
|   | ||||
| @@ -7,14 +7,13 @@ import { isUserTouching } from 'flavours/glitch/util/is_mobile'; | ||||
| import NotificationsCounterIcon from './notifications_counter_icon'; | ||||
|  | ||||
| export const links = [ | ||||
|   <NavLink className='tabs-bar__link primary' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><i className='fa fa-fw fa-home' /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>, | ||||
|   <NavLink className='tabs-bar__link primary' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>, | ||||
|   <NavLink className='tabs-bar__link' to='/timelines/home' data-preview-title-id='column.home' data-preview-icon='home' ><i className='fa fa-fw fa-home' /><FormattedMessage id='tabs_bar.home' defaultMessage='Home' /></NavLink>, | ||||
|   <NavLink className='tabs-bar__link' to='/notifications' data-preview-title-id='column.notifications' data-preview-icon='bell' ><NotificationsCounterIcon /><FormattedMessage id='tabs_bar.notifications' defaultMessage='Notifications' /></NavLink>, | ||||
|  | ||||
|   <NavLink className='tabs-bar__link secondary' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><i className='fa fa-fw fa-users' /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>, | ||||
|   <NavLink className='tabs-bar__link secondary' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><i className='fa fa-fw fa-globe' /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>, | ||||
|   <NavLink className='tabs-bar__link primary' to='/search' data-preview-title-id='tabs_bar.search' data-preview-icon='bell' ><i className='fa fa-fw fa-search' /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>, | ||||
|  | ||||
|   <NavLink className='tabs-bar__link primary' style={{ flexGrow: '0', flexBasis: '30px' }} to='/getting-started' data-preview-title-id='getting_started.heading' data-preview-icon='bars' ><i className='fa fa-fw fa-bars' /></NavLink>, | ||||
|   <NavLink className='tabs-bar__link' to='/timelines/public/local' data-preview-title-id='column.community' data-preview-icon='users' ><i className='fa fa-fw fa-users' /><FormattedMessage id='tabs_bar.local_timeline' defaultMessage='Local' /></NavLink>, | ||||
|   <NavLink className='tabs-bar__link' exact to='/timelines/public' data-preview-title-id='column.public' data-preview-icon='globe' ><i className='fa fa-fw fa-globe' /><FormattedMessage id='tabs_bar.federated_timeline' defaultMessage='Federated' /></NavLink>, | ||||
|   <NavLink className='tabs-bar__link optional' to='/search' data-preview-title-id='tabs_bar.search' data-preview-icon='bell' ><i className='fa fa-fw fa-search' /><FormattedMessage id='tabs_bar.search' defaultMessage='Search' /></NavLink>, | ||||
|   <NavLink className='tabs-bar__link' style={{ flexGrow: '0', flexBasis: '30px' }} to='/getting-started' data-preview-title-id='getting_started.heading' data-preview-icon='bars' ><i className='fa fa-fw fa-bars' /></NavLink>, | ||||
| ]; | ||||
|  | ||||
| export function getIndex (path) { | ||||
|   | ||||
| @@ -44,10 +44,11 @@ import { | ||||
|   Mutes, | ||||
|   PinnedStatuses, | ||||
|   Lists, | ||||
|   Search, | ||||
|   GettingStartedMisc, | ||||
| } from 'flavours/glitch/util/async-components'; | ||||
| import { HotKeys } from 'react-hotkeys'; | ||||
| import { me } from 'flavours/glitch/util/initial_state'; | ||||
| import { me, forceSingleColumn } from 'flavours/glitch/util/initial_state'; | ||||
| import { defineMessages, injectIntl } from 'react-intl'; | ||||
|  | ||||
| // Dummy import, to make sure that <Status /> ends up in the application bundle. | ||||
| @@ -68,7 +69,6 @@ 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,7 +126,6 @@ export default class UI extends React.Component { | ||||
|     dropdownMenuIsOpen: PropTypes.bool, | ||||
|     unreadNotifications: PropTypes.number, | ||||
|     showFaviconBadge: PropTypes.bool, | ||||
|     forceSingleColumn: PropTypes.bool, | ||||
|   }; | ||||
|  | ||||
|   state = { | ||||
| @@ -432,7 +431,7 @@ export default class UI extends React.Component { | ||||
|  | ||||
|   render () { | ||||
|     const { width, draggingOver } = this.state; | ||||
|     const { children, layout, isWide, navbarUnder, dropdownMenuIsOpen, forceSingleColumn } = this.props; | ||||
|     const { children, layout, isWide, navbarUnder, dropdownMenuIsOpen } = this.props; | ||||
|     const singleColumn = forceSingleColumn || isMobile(width, layout); | ||||
|     const redirect = singleColumn ? <Redirect from='/' to='/timelines/home' exact /> : <Redirect from='/' to='/getting-started' exact />; | ||||
|  | ||||
| @@ -494,7 +493,7 @@ export default class UI extends React.Component { | ||||
|               <WrappedRoute path='/bookmarks' component={BookmarkedStatuses} content={children} /> | ||||
|               <WrappedRoute path='/pinned' component={PinnedStatuses} content={children} /> | ||||
|  | ||||
|               <WrappedRoute path='/search' component={Compose} content={children} componentParams={{ isSearchPage: true }} /> | ||||
|               <WrappedRoute path='/search' component={Search} content={children} /> | ||||
|  | ||||
|               <WrappedRoute path='/statuses/new' component={Compose} content={children} /> | ||||
|               <WrappedRoute path='/statuses/:statusId' exact component={Status} content={children} /> | ||||
|   | ||||
| @@ -15,8 +15,6 @@ const initialState = ImmutableMap({ | ||||
|  | ||||
|   skinTone: 1, | ||||
|  | ||||
|   forceSingleColumn: false, | ||||
|  | ||||
|   home: ImmutableMap({ | ||||
|     shows: ImmutableMap({ | ||||
|       reblog: true, | ||||
|   | ||||
| @@ -26,7 +26,12 @@ | ||||
|       display: flex; | ||||
|       justify-content: flex-end; | ||||
|  | ||||
|       &--start { | ||||
|         justify-content: flex-start; | ||||
|       } | ||||
|  | ||||
|       &__inner { | ||||
|         width: 285px; | ||||
|         pointer-events: auto; | ||||
|         height: 100%; | ||||
|       } | ||||
| @@ -178,9 +183,31 @@ | ||||
|   padding: 15px; | ||||
|   text-decoration: none; | ||||
|  | ||||
|   &:hover { | ||||
|   &:hover, | ||||
|   &:focus, | ||||
|   &:active { | ||||
|     background: lighten($ui-base-color, 11%); | ||||
|   } | ||||
|  | ||||
|   &:focus { | ||||
|     outline: 0; | ||||
|   } | ||||
|  | ||||
|   &--transparent { | ||||
|     background: transparent; | ||||
|     color: $ui-secondary-color; | ||||
|  | ||||
|     &:hover, | ||||
|     &:focus, | ||||
|     &:active { | ||||
|       background: transparent; | ||||
|       color: $primary-text-color; | ||||
|     } | ||||
|  | ||||
|     &.active { | ||||
|       color: $ui-highlight-color; | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| .column-link__icon { | ||||
| @@ -506,31 +533,3 @@ | ||||
|     margin: 0 5px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .floating-action-button { | ||||
|   position: fixed; | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|   width: 3.9375rem; | ||||
|   height: 3.9375rem; | ||||
|   bottom: 1.3125rem; | ||||
|   right: 1.3125rem; | ||||
|   background: darken($ui-highlight-color, 3%); | ||||
|   color: $white; | ||||
|   border-radius: 50%; | ||||
|   font-size: 21px; | ||||
|   line-height: 21px; | ||||
|   text-decoration: none; | ||||
|   box-shadow: 2px 3px 9px rgba($base-shadow-color, 0.4); | ||||
|  | ||||
|   &:hover, | ||||
|   &:focus, | ||||
|   &:active { | ||||
|     background: lighten($ui-highlight-color, 7%); | ||||
|   } | ||||
|  | ||||
|   @media screen and (min-width: 630px) { | ||||
|     display: none; | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -564,6 +564,7 @@ | ||||
|   display: block; | ||||
|   flex: 1 1 auto; | ||||
|   padding: 15px 10px; | ||||
|   padding-bottom: 13px; | ||||
|   color: $primary-text-color; | ||||
|   text-decoration: none; | ||||
|   text-align: center; | ||||
| @@ -588,6 +589,7 @@ | ||||
|   &:active { | ||||
|     @include multi-columns('screen and (min-width: 631px)') { | ||||
|       background: lighten($ui-base-color, 14%); | ||||
|       border-bottom-color: lighten($ui-base-color, 14%); | ||||
|     } | ||||
|   } | ||||
|  | ||||
| @@ -617,11 +619,21 @@ | ||||
|     padding: 0; | ||||
|   } | ||||
|  | ||||
|   .search__input, | ||||
|   .autosuggest-textarea__textarea { | ||||
|     font-size: 16px; | ||||
|   } | ||||
|  | ||||
|   .search__input { | ||||
|     line-height: 18px; | ||||
|     font-size: 16px; | ||||
|     padding: 15px; | ||||
|     padding-right: 30px; | ||||
|   } | ||||
|  | ||||
|   .search__icon .fa { | ||||
|     top: 15px; | ||||
|   } | ||||
|  | ||||
|   @media screen and (min-width: 360px) { | ||||
|     padding: 10px 0; | ||||
|   } | ||||
| @@ -677,6 +689,58 @@ | ||||
|         margin-top: 10px; | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     .account { | ||||
|       padding: 15px 10px; | ||||
|     } | ||||
|  | ||||
|     .notification { | ||||
|       &__message { | ||||
|         margin-left: 48px + 15px * 2; | ||||
|         padding-top: 15px; | ||||
|       } | ||||
|  | ||||
|       &__favourite-icon-wrapper { | ||||
|         left: -32px; | ||||
|       } | ||||
|  | ||||
|       .status { | ||||
|         padding-top: 8px; | ||||
|       } | ||||
|  | ||||
|       .account { | ||||
|         padding-top: 8px; | ||||
|       } | ||||
|  | ||||
|       .account__avatar-wrapper { | ||||
|         margin-left: 17px; | ||||
|         margin-right: 15px; | ||||
|       } | ||||
|     } | ||||
|   } | ||||
| } | ||||
|  | ||||
| .floating-action-button { | ||||
|   position: fixed; | ||||
|   display: flex; | ||||
|   justify-content: center; | ||||
|   align-items: center; | ||||
|   width: 3.9375rem; | ||||
|   height: 3.9375rem; | ||||
|   bottom: 1.3125rem; | ||||
|   right: 1.3125rem; | ||||
|   background: darken($ui-highlight-color, 3%); | ||||
|   color: $white; | ||||
|   border-radius: 50%; | ||||
|   font-size: 21px; | ||||
|   line-height: 21px; | ||||
|   text-decoration: none; | ||||
|   box-shadow: 2px 3px 9px rgba($base-shadow-color, 0.4); | ||||
|  | ||||
|   &:hover, | ||||
|   &:focus, | ||||
|   &:active { | ||||
|     background: lighten($ui-highlight-color, 7%); | ||||
|   } | ||||
| } | ||||
|  | ||||
| @@ -698,12 +762,41 @@ | ||||
|   } | ||||
| } | ||||
|  | ||||
| @media screen and (max-width: 600px + (285px * 1) + (10px * 1)) { | ||||
|   .columns-area__panels__pane--compositional { | ||||
|     display: none; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @media screen and (min-width: 600px + (285px * 1) + (10px * 1)) { | ||||
|   .floating-action-button, | ||||
|   .tabs-bar__link.optional { | ||||
|     display: none; | ||||
|   } | ||||
|  | ||||
|   .search-page .search { | ||||
|     display: none; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @media screen and (max-width: 600px + (285px * 2) + (10px * 2)) { | ||||
|   .columns-area__panels__pane--navigational { | ||||
|     display: none; | ||||
|   } | ||||
| } | ||||
|  | ||||
| @media screen and (min-width: 600px + (285px * 2) + (10px * 2)) { | ||||
|   .tabs-bar { | ||||
|     display: none; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .icon-with-badge { | ||||
|   position: relative; | ||||
|  | ||||
|   &__badge { | ||||
|     position: absolute; | ||||
|     right: -13px; | ||||
|     left: 9px; | ||||
|     top: -13px; | ||||
|     background: $ui-highlight-color; | ||||
|     border: 2px solid lighten($ui-base-color, 8%); | ||||
| @@ -716,6 +809,57 @@ | ||||
|   } | ||||
| } | ||||
|  | ||||
| .column-link--transparent .icon-with-badge__badge { | ||||
|   border-color: darken($ui-base-color, 8%); | ||||
| } | ||||
|  | ||||
| .compose-panel { | ||||
|   width: 285px; | ||||
|   margin-top: 10px; | ||||
|   display: flex; | ||||
|   flex-direction: column; | ||||
|   height: 100%; | ||||
|  | ||||
|   .search__input { | ||||
|     line-height: 18px; | ||||
|     font-size: 16px; | ||||
|     padding: 15px; | ||||
|     padding-right: 30px; | ||||
|   } | ||||
|  | ||||
|   .search__icon .fa { | ||||
|     top: 15px; | ||||
|   } | ||||
|  | ||||
|   .navigation-bar { | ||||
|     padding-top: 20px; | ||||
|     padding-bottom: 20px; | ||||
|   } | ||||
|  | ||||
|   .flex-spacer { | ||||
|     background: transparent; | ||||
|   } | ||||
|  | ||||
|   .autosuggest-textarea__textarea { | ||||
|     max-height: 200px; | ||||
|   } | ||||
|  | ||||
|   .compose-form__upload-thumbnail { | ||||
|     height: 80px; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .navigation-panel { | ||||
|   margin-top: 10px; | ||||
|  | ||||
|   hr { | ||||
|     border: 0; | ||||
|     background: transparent; | ||||
|     border-top: 1px solid lighten($ui-base-color, 4%); | ||||
|     margin: 10px 0; | ||||
|   } | ||||
| } | ||||
|  | ||||
| .scrollable { | ||||
|   overflow-y: scroll; | ||||
|   overflow-x: hidden; | ||||
| @@ -1386,15 +1530,6 @@ | ||||
|   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; | ||||
|   | ||||
| @@ -149,3 +149,7 @@ export function GettingStartedMisc () { | ||||
| export function ListAdder () { | ||||
|   return import(/* webpackChunkName: "features/glitch/async/list_adder" */'flavours/glitch/features/list_adder'); | ||||
| } | ||||
|  | ||||
| export function Search () { | ||||
|   return import(/*webpackChunkName: "features/glitch/async/search" */'flavours/glitch/features/search'); | ||||
| } | ||||
|   | ||||
| @@ -28,5 +28,6 @@ export const version = getMeta('version'); | ||||
| export const mascot = getMeta('mascot'); | ||||
| export const isStaff = getMeta('is_staff'); | ||||
| export const defaultContentType = getMeta('default_content_type'); | ||||
| export const forceSingleColumn = !getMeta('advanced_layout'); | ||||
|  | ||||
| export default initialState; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user