forked from mastodon/mastodon
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Allow mounting arbitrary columns (mastodon#3207)
* Allow mounting arbitrary columns * Refactor column headers, allow pinning/unpinning and moving columns around * Collapse animation * Re-introduce scroll to top * Save column settings properly, do not display pin options in single-column view, do not display collapse icon if there is nothing to collapse * Fix one instance of public timeline being closed closing the stream Fix back buttons inconsistently sending you back to / even if history exists * Getting started displays links to columns that are not mounted
- Loading branch information
Showing
21 changed files
with
754 additions
and
153 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
import { saveSettings } from './settings'; | ||
|
||
export const COLUMN_ADD = 'COLUMN_ADD'; | ||
export const COLUMN_REMOVE = 'COLUMN_REMOVE'; | ||
export const COLUMN_MOVE = 'COLUMN_MOVE'; | ||
|
||
export function addColumn(id, params) { | ||
return dispatch => { | ||
dispatch({ | ||
type: COLUMN_ADD, | ||
id, | ||
params, | ||
}); | ||
|
||
dispatch(saveSettings()); | ||
}; | ||
}; | ||
|
||
export function removeColumn(uuid) { | ||
return dispatch => { | ||
dispatch({ | ||
type: COLUMN_REMOVE, | ||
uuid, | ||
}); | ||
|
||
dispatch(saveSettings()); | ||
}; | ||
}; | ||
|
||
export function moveColumn(uuid, direction) { | ||
return dispatch => { | ||
dispatch({ | ||
type: COLUMN_MOVE, | ||
uuid, | ||
direction, | ||
}); | ||
|
||
dispatch(saveSettings()); | ||
}; | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import scrollTop from '../scroll'; | ||
|
||
class Column extends React.PureComponent { | ||
|
||
static propTypes = { | ||
children: PropTypes.node, | ||
}; | ||
|
||
scrollTop () { | ||
const scrollable = this.node.querySelector('.scrollable'); | ||
|
||
if (!scrollable) { | ||
return; | ||
} | ||
|
||
this._interruptScrollAnimation = scrollTop(scrollable); | ||
} | ||
|
||
handleWheel = () => { | ||
if (typeof this._interruptScrollAnimation !== 'function') { | ||
return; | ||
} | ||
|
||
this._interruptScrollAnimation(); | ||
} | ||
|
||
setRef = c => { | ||
this.node = c; | ||
} | ||
|
||
render () { | ||
const { children } = this.props; | ||
|
||
return ( | ||
<div role='region' className='column' ref={this.setRef} onWheel={this.handleWheel}> | ||
{children} | ||
</div> | ||
); | ||
} | ||
|
||
} | ||
|
||
export default Column; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,138 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
import classNames from 'classnames'; | ||
import { FormattedMessage } from 'react-intl'; | ||
|
||
class ColumnHeader extends React.PureComponent { | ||
|
||
static contextTypes = { | ||
router: PropTypes.object, | ||
}; | ||
|
||
static propTypes = { | ||
title: PropTypes.string.isRequired, | ||
icon: PropTypes.string.isRequired, | ||
active: PropTypes.bool, | ||
multiColumn: PropTypes.bool, | ||
children: PropTypes.node, | ||
pinned: PropTypes.bool, | ||
onPin: PropTypes.func, | ||
onMove: PropTypes.func, | ||
onClick: PropTypes.func, | ||
}; | ||
|
||
state = { | ||
collapsed: true, | ||
animating: false, | ||
}; | ||
|
||
handleToggleClick = (e) => { | ||
e.stopPropagation(); | ||
this.setState({ collapsed: !this.state.collapsed, animating: true }); | ||
} | ||
|
||
handleTitleClick = () => { | ||
this.props.onClick(); | ||
} | ||
|
||
handleMoveLeft = () => { | ||
this.props.onMove(-1); | ||
} | ||
|
||
handleMoveRight = () => { | ||
this.props.onMove(1); | ||
} | ||
|
||
handleBackClick = () => { | ||
if (window.history && window.history.length === 1) this.context.router.push('/'); | ||
else this.context.router.goBack(); | ||
} | ||
|
||
handleTransitionEnd = () => { | ||
this.setState({ animating: false }); | ||
} | ||
|
||
render () { | ||
const { title, icon, active, children, pinned, onPin, multiColumn } = this.props; | ||
const { collapsed, animating } = this.state; | ||
|
||
const buttonClassName = classNames('column-header', { | ||
'active': active, | ||
}); | ||
|
||
const collapsibleClassName = classNames('column-header__collapsible', { | ||
'collapsed': collapsed, | ||
'animating': animating, | ||
}); | ||
|
||
const collapsibleButtonClassName = classNames('column-header__button', { | ||
'active': !collapsed, | ||
}); | ||
|
||
let extraContent, pinButton, moveButtons, backButton, collapseButton; | ||
|
||
if (children) { | ||
extraContent = ( | ||
<div key='extra-content' className='column-header__collapsible__extra'> | ||
{children} | ||
</div> | ||
); | ||
} | ||
|
||
if (multiColumn && pinned) { | ||
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={onPin}><i className='fa fa fa-times' /> <FormattedMessage id='column_header.unpin' defaultMessage='Unpin' /></button>; | ||
|
||
moveButtons = ( | ||
<div key='move-buttons' className='column-header__setting-arrows'> | ||
<button className='text-btn column-header__setting-btn' onClick={this.handleMoveLeft}><i className='fa fa-chevron-left' /></button> | ||
<button className='text-btn column-header__setting-btn' onClick={this.handleMoveRight}><i className='fa fa-chevron-right' /></button> | ||
</div> | ||
); | ||
} else if (multiColumn) { | ||
pinButton = <button key='pin-button' className='text-btn column-header__setting-btn' onClick={onPin}><i className='fa fa fa-plus' /> <FormattedMessage id='column_header.pin' defaultMessage='Pin' /></button>; | ||
|
||
backButton = ( | ||
<button onClick={this.handleBackClick} className='column-header__back-button'> | ||
<i className='fa fa-fw fa-chevron-left column-back-button__icon' /> | ||
<FormattedMessage id='column_back_button.label' defaultMessage='Back' /> | ||
</button> | ||
); | ||
} | ||
|
||
const collapsedContent = [ | ||
extraContent, | ||
]; | ||
|
||
if (multiColumn) { | ||
collapsedContent.push(moveButtons); | ||
collapsedContent.push(pinButton); | ||
} | ||
|
||
if (children || multiColumn) { | ||
collapseButton = <button className={collapsibleButtonClassName} onClick={this.handleToggleClick}><i className='fa fa-sliders' /></button>; | ||
} | ||
|
||
return ( | ||
<div> | ||
<div role='button heading' tabIndex='0' className={buttonClassName} onClick={this.handleTitleClick}> | ||
<i className={`fa fa-fw fa-${icon} column-header__icon`} /> | ||
{title} | ||
|
||
<div className='column-header__buttons'> | ||
{backButton} | ||
{collapseButton} | ||
</div> | ||
</div> | ||
|
||
<div className={collapsibleClassName} onTransitionEnd={this.handleTransitionEnd}> | ||
<div> | ||
{(!collapsed || animating) && collapsedContent} | ||
</div> | ||
</div> | ||
</div> | ||
); | ||
} | ||
|
||
} | ||
|
||
export default ColumnHeader; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.