ShareBoard modal. WIP
This commit is contained in:
parent
b8bfc7fce3
commit
55620f45df
6 changed files with 183 additions and 17 deletions
33
webapp/src/components/modal.scss
Normal file
33
webapp/src/components/modal.scss
Normal file
|
@ -0,0 +1,33 @@
|
|||
.Modal {
|
||||
position: absolute;
|
||||
top: 25px;
|
||||
left: -200px;
|
||||
z-index: 10;
|
||||
|
||||
min-width: 430px;
|
||||
box-shadow: rgba(var(--main-fg), 0.1) 0px 0px 0px 1px, rgba(var(--main-fg), 0.1) 0px 2px 4px;
|
||||
background-color: rgb(var(--main-bg));
|
||||
padding: 10px;
|
||||
|
||||
@media screen and (max-width: 430px) {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
min-width: 0;
|
||||
}
|
||||
|
||||
.hideOnWidescreen {
|
||||
/* Hide controls (e.g. close button) on larger screens */
|
||||
@media not screen and (max-width: 430px) {
|
||||
display: none !important;
|
||||
}
|
||||
}
|
||||
> .toolbar {
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
height: 30px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
}
|
62
webapp/src/components/modal.tsx
Normal file
62
webapp/src/components/modal.tsx
Normal file
|
@ -0,0 +1,62 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React from 'react'
|
||||
import {injectIntl, IntlShape} from 'react-intl'
|
||||
|
||||
import IconButton from '../widgets/buttons/iconButton'
|
||||
import CloseIcon from '../widgets/icons/close'
|
||||
import './modal.scss'
|
||||
|
||||
type Props = {
|
||||
onClose: () => void
|
||||
intl: IntlShape
|
||||
}
|
||||
|
||||
class Modal extends React.PureComponent<Props> {
|
||||
private node: React.RefObject<HTMLDivElement>
|
||||
|
||||
public constructor(props: Props) {
|
||||
super(props)
|
||||
this.node = React.createRef()
|
||||
}
|
||||
|
||||
public componentDidMount(): void {
|
||||
document.addEventListener('click', this.closeOnBlur, true)
|
||||
}
|
||||
|
||||
public componentWillUnmount(): void {
|
||||
document.removeEventListener('click', this.closeOnBlur, true)
|
||||
}
|
||||
|
||||
private closeOnBlur = (e: Event) => {
|
||||
if (this.node && this.node.current && e.target && this.node.current.contains(e.target as Node)) {
|
||||
return
|
||||
}
|
||||
|
||||
this.props.onClose()
|
||||
}
|
||||
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<div
|
||||
className='Modal'
|
||||
ref={this.node}
|
||||
>
|
||||
<div className='toolbar hideOnWidescreen'>
|
||||
<IconButton
|
||||
onClick={this.closeClicked}
|
||||
icon={<CloseIcon/>}
|
||||
title={'Close'}
|
||||
/>
|
||||
</div>
|
||||
{this.props.children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
private closeClicked = () => {
|
||||
this.props.onClose()
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(Modal)
|
4
webapp/src/components/modalWrapper.scss
Normal file
4
webapp/src/components/modalWrapper.scss
Normal file
|
@ -0,0 +1,4 @@
|
|||
.ModalWrapper {
|
||||
position: relative;
|
||||
overflow: unset;
|
||||
}
|
19
webapp/src/components/modalWrapper.tsx
Normal file
19
webapp/src/components/modalWrapper.tsx
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React from 'react'
|
||||
import './modalWrapper.scss'
|
||||
|
||||
type Props = {
|
||||
}
|
||||
|
||||
class ModalWrapper extends React.PureComponent<Props> {
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<div className='ModalWrapper'>
|
||||
{this.props.children}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default ModalWrapper
|
25
webapp/src/components/shareBoardComponent.tsx
Normal file
25
webapp/src/components/shareBoardComponent.tsx
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Copyright (c) 2015-present Mattermost, Inc. All Rights Reserved.
|
||||
// See LICENSE.txt for license information.
|
||||
import React from 'react'
|
||||
import {injectIntl, IntlShape} from 'react-intl'
|
||||
|
||||
import Modal from './modal'
|
||||
|
||||
type Props = {
|
||||
onClose: () => void
|
||||
intl: IntlShape
|
||||
}
|
||||
|
||||
class ShareBoardComponent extends React.PureComponent<Props> {
|
||||
render(): JSX.Element {
|
||||
return (
|
||||
<Modal
|
||||
onClose={this.props.onClose}
|
||||
>
|
||||
{'TODO'}
|
||||
</Modal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default injectIntl(ShareBoardComponent)
|
|
@ -26,7 +26,9 @@ import MenuWrapper from '../widgets/menuWrapper'
|
|||
|
||||
import {Editable} from './editable'
|
||||
import FilterComponent from './filterComponent'
|
||||
import ModalWrapper from './modalWrapper'
|
||||
import NewCardButton from './newCardButton'
|
||||
import ShareBoardComponent from './shareBoardComponent'
|
||||
import './viewHeader.scss'
|
||||
|
||||
type Props = {
|
||||
|
@ -45,6 +47,7 @@ type Props = {
|
|||
type State = {
|
||||
isSearching: boolean
|
||||
showFilter: boolean
|
||||
showShareDialog: boolean
|
||||
}
|
||||
|
||||
class ViewHeader extends React.Component<Props, State> {
|
||||
|
@ -56,7 +59,7 @@ class ViewHeader extends React.Component<Props, State> {
|
|||
|
||||
constructor(props: Props) {
|
||||
super(props)
|
||||
this.state = {isSearching: Boolean(this.props.boardTree.getSearchText()), showFilter: false}
|
||||
this.state = {isSearching: Boolean(this.props.boardTree.getSearchText()), showFilter: false, showShareDialog: false}
|
||||
}
|
||||
|
||||
componentDidUpdate(prevPros: Props, prevState: State): void {
|
||||
|
@ -287,21 +290,27 @@ class ViewHeader extends React.Component<Props, State> {
|
|||
|
||||
{!this.props.readonly &&
|
||||
<>
|
||||
<MenuWrapper>
|
||||
<IconButton icon={<OptionsIcon/>}/>
|
||||
<Menu>
|
||||
<Menu.Text
|
||||
id='exportCsv'
|
||||
name={intl.formatMessage({id: 'ViewHeader.export-csv', defaultMessage: 'Export to CSV'})}
|
||||
onClick={() => CsvExporter.exportTableCsv(boardTree)}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='exportBoardArchive'
|
||||
name={intl.formatMessage({id: 'ViewHeader.export-board-archive', defaultMessage: 'Export board archive'})}
|
||||
onClick={() => Archiver.exportBoardTree(boardTree)}
|
||||
/>
|
||||
<ModalWrapper>
|
||||
<MenuWrapper>
|
||||
<IconButton icon={<OptionsIcon/>}/>
|
||||
<Menu>
|
||||
<Menu.Text
|
||||
id='exportCsv'
|
||||
name={intl.formatMessage({id: 'ViewHeader.export-csv', defaultMessage: 'Export to CSV'})}
|
||||
onClick={() => CsvExporter.exportTableCsv(boardTree)}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='exportBoardArchive'
|
||||
name={intl.formatMessage({id: 'ViewHeader.export-board-archive', defaultMessage: 'Export board archive'})}
|
||||
onClick={() => Archiver.exportBoardTree(boardTree)}
|
||||
/>
|
||||
<Menu.Text
|
||||
id='shareBoard'
|
||||
name={intl.formatMessage({id: 'ViewHeader.share-board', defaultMessage: 'Share board'})}
|
||||
onClick={this.showShareDialog}
|
||||
/>
|
||||
|
||||
{/*
|
||||
{/*
|
||||
|
||||
<Menu.Separator/>
|
||||
|
||||
|
@ -327,8 +336,14 @@ class ViewHeader extends React.Component<Props, State> {
|
|||
/>
|
||||
|
||||
*/}
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
</Menu>
|
||||
</MenuWrapper>
|
||||
{this.state.showShareDialog &&
|
||||
<ShareBoardComponent
|
||||
onClose={this.hideShareDialog}
|
||||
/>
|
||||
}
|
||||
</ModalWrapper>
|
||||
|
||||
{/* New card button */}
|
||||
|
||||
|
@ -353,6 +368,14 @@ class ViewHeader extends React.Component<Props, State> {
|
|||
this.setState({showFilter: false})
|
||||
}
|
||||
|
||||
private showShareDialog = () => {
|
||||
this.setState({showShareDialog: true})
|
||||
}
|
||||
|
||||
private hideShareDialog = () => {
|
||||
this.setState({showShareDialog: false})
|
||||
}
|
||||
|
||||
private onSearchKeyDown = (e: React.KeyboardEvent) => {
|
||||
if (e.keyCode === 27) { // ESC: Clear search
|
||||
if (this.searchFieldRef.current) {
|
||||
|
|
Loading…
Reference in a new issue