Refactor sidebar

This commit is contained in:
Thomas Nordquist
2019-07-07 16:24:18 +02:00
parent 6bead5b5a6
commit b79725bdf0
16 changed files with 420 additions and 313 deletions

View File

@@ -0,0 +1,38 @@
import * as q from '../../../../../backend/src/Model'
import CustomIconButton from '../../helper/CustomIconButton'
import Delete from '@material-ui/icons/Delete'
import React, { useCallback } from 'react'
import { Badge } from '@material-ui/core'
export const RecursiveTopicDeleteButton = (props: {
node?: q.TreeNode<any>
deleteTopicAction: (node: q.TreeNode<any>, a: boolean, limit: number) => void
}) => {
const onClick = useCallback(() => {
if (props.node) {
props.deleteTopicAction(props.node, true, deleteLimit)
}
}, [props.node])
if (!props.node) {
return null
}
const deleteLimit = 50
const topicCount = props.node ? props.node.childTopicCount() : 0
if (topicCount === 0 || (props.node.message && topicCount === 1)) {
return null
}
return (
<Badge
style={{
top: '3px',
right: '3px',
}}
badgeContent={<span style={{ whiteSpace: 'nowrap' }}>{topicCount >= deleteLimit ? '50+' : topicCount}</span>}
color="secondary"
>
<CustomIconButton onClick={onClick} tooltip={`Deletes up to ${deleteLimit} sub-topics with a single click`}>
<Delete style={{ marginTop: '-3px' }} color="action" />
</CustomIconButton>
</Badge>
)
}

View File

@@ -0,0 +1,73 @@
import React from 'react'
import * as q from '../../../../../backend/src/Model'
import Button from '@material-ui/core/Button'
import { withStyles, Theme } from '@material-ui/core/styles'
import { treeActions } from '../../../actions'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { TopicViewModel } from '../../../model/TopicViewModel'
interface Props {
classes: any
theme: Theme
node?: q.TreeNode<TopicViewModel>
selected?: q.TreeNode<TopicViewModel>
actions: typeof treeActions
didSelectNode: (node: q.TreeNode<TopicViewModel>) => void
}
const styles = (theme: Theme) => ({
button: {
textTransform: 'none' as 'none',
padding: '3px 5px 3px 5px',
minWidth: '30px',
},
})
class Topic extends React.Component<Props, {}> {
public render() {
const { node, theme } = this.props
if (!node) {
return null
}
let key = 0
const breadCrumps = node
.branch()
.map(node => node.sourceEdge)
.filter(edge => Boolean(edge))
.map(edge => [
<Button
onClick={() => this.props.actions.selectTopic(edge!.target)}
size="small"
variant={theme.palette.type === 'light' ? 'contained' : undefined}
color={theme.palette.type === 'light' ? 'primary' : 'secondary'}
className={this.props.classes.button}
key={edge!.hash()}
>
{edge!.name || <span dangerouslySetInnerHTML={{ __html: '&nbsp;' }} />}
</Button>,
])
if (breadCrumps.length === 0) {
return null
}
const joinedBreadCrumps = breadCrumps.reduce((prev, current) =>
prev.concat([<span key={(key += 1)}> / </span>]).concat(current)
)
return <span style={{ lineHeight: '2.2em' }}>{joinedBreadCrumps}</span>
}
}
const mapDispatchToProps = (dispatch: any) => {
return {
actions: bindActionCreators(treeActions, dispatch),
}
}
export default connect(
null,
mapDispatchToProps
)(withStyles(styles, { withTheme: true })(Topic))

View File

@@ -0,0 +1,19 @@
import * as q from '../../../../../backend/src/Model'
import CustomIconButton from '../../helper/CustomIconButton'
import Delete from '@material-ui/icons/Delete'
import React from 'react'
export const TopicDeleteButton = (props: {
node?: q.TreeNode<any>
deleteTopicAction: (node: q.TreeNode<any>) => void
}) => {
const { node } = props
if (!node || !node.message || !node.message.value) {
return null
}
return (
<CustomIconButton onClick={() => props.deleteTopicAction(node)} tooltip="Clear this topic">
<Delete style={{ marginTop: '-3px' }} />
</CustomIconButton>
)
}

View File

@@ -0,0 +1,48 @@
import * as q from '../../../../../backend/src/Model'
import Copy from '../../helper/Copy'
import Panel from '../Panel'
import React, { useMemo } from 'react'
import Topic from './Topic'
import { bindActionCreators } from 'redux'
import { connect } from 'react-redux'
import { RecursiveTopicDeleteButton } from './RecursiveTopicDeleteButton'
import { sidebarActions } from '../../../actions'
import { TopicDeleteButton } from './TopicDeleteButton'
const TopicPanel = (props: { node?: q.TreeNode<any>; actions: typeof sidebarActions; updateNode: () => void }) => {
const { node, updateNode } = props
const copyTopic = node ? <Copy value={node.path()} /> : null
const deleteTopic = (topic?: q.TreeNode<any>, recursive: boolean = false, maxCount = 50) => {
if (!topic) {
return
}
props.actions.clearTopic(topic, recursive, maxCount)
}
return useMemo(
() => (
<Panel disabled={!Boolean(node)}>
<span>
Topic {copyTopic}
<TopicDeleteButton node={node} deleteTopicAction={deleteTopic} />
<RecursiveTopicDeleteButton node={node} deleteTopicAction={deleteTopic} />
</span>
<Topic node={node} didSelectNode={updateNode} />
</Panel>
),
[node, node && node.childTopicCount()]
)
}
const mapDispatchToProps = (dispatch: any) => {
return {
actions: bindActionCreators(sidebarActions, dispatch),
}
}
export default connect(
undefined,
mapDispatchToProps
)(TopicPanel)