ShareBoard modal. WIP

This commit is contained in:
Chen-I Lim 2021-01-13 10:12:22 -08:00
parent b8bfc7fce3
commit 55620f45df
6 changed files with 183 additions and 17 deletions

View 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;
}
}

View 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)

View file

@ -0,0 +1,4 @@
.ModalWrapper {
position: relative;
overflow: unset;
}

View 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

View 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)

View file

@ -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) {