Add a bunch of modal dialogs
This commit is contained in:
parent
68d3136f39
commit
99ec936fd1
10 changed files with 281 additions and 0 deletions
22
src/components/LoginModal/LoginModal.tsx
Normal file
22
src/components/LoginModal/LoginModal.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react'
|
||||
import Portal from '../../Portal'
|
||||
|
||||
import Modal from '../Modal/Modal'
|
||||
import Overlay from '../Overlay/Overlay'
|
||||
|
||||
const LoginModal = ({ close }) => {
|
||||
return (
|
||||
<Portal>
|
||||
<div>
|
||||
<Modal>
|
||||
<input className="Input" name="email" type="text" placeholder="Email address" />
|
||||
<input className="Input" name="password" type="password" placeholder="Password" />
|
||||
<button className="Button">Log in</button>
|
||||
</Modal>
|
||||
<Overlay onClick={close} />
|
||||
</div>
|
||||
</Portal>
|
||||
)
|
||||
}
|
||||
|
||||
export default LoginModal
|
||||
57
src/components/Modal/Modal.css
Normal file
57
src/components/Modal/Modal.css
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
.ModalContainer {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.Modal {
|
||||
background: #f5f5f5;
|
||||
border-radius: 8px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
max-height: 600px;
|
||||
min-width: 360px;
|
||||
max-width: 480px;
|
||||
padding: 24px;
|
||||
position: relative;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.Modal > .Input {
|
||||
-webkit-font-smoothing: antialiased;
|
||||
border: none;
|
||||
|
||||
background-color: white;
|
||||
border-radius: 6px;
|
||||
color: #555;
|
||||
display: block;
|
||||
font-size: 18px;
|
||||
margin-bottom: 8px;
|
||||
padding: 12px 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.Modal > .Button {
|
||||
background: #61B3FF;
|
||||
color: #315E87;
|
||||
display: block;
|
||||
min-height: 45px;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.Modal > .Button:hover {
|
||||
background: #4B9BE5;
|
||||
color: #233E56;
|
||||
}
|
||||
|
||||
::placeholder { /* Chrome, Firefox, Opera, Safari 10.1+ */
|
||||
color: #a9a9a9 !important;
|
||||
opacity: 1; /* Firefox */
|
||||
}
|
||||
22
src/components/Modal/Modal.tsx
Normal file
22
src/components/Modal/Modal.tsx
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
import React from 'react'
|
||||
import classnames from 'classnames'
|
||||
|
||||
import './Modal.css'
|
||||
|
||||
interface Props {
|
||||
styleName?: string
|
||||
}
|
||||
|
||||
class Modal extends React.Component<Props> {
|
||||
render() {
|
||||
return (
|
||||
<div className="ModalContainer">
|
||||
<div className={classnames("Modal", this.props.styleName)}>
|
||||
{this.props.children}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default Modal
|
||||
12
src/components/Overlay/Overlay.css
Normal file
12
src/components/Overlay/Overlay.css
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
.Overlay {
|
||||
background: black;
|
||||
position: absolute;
|
||||
opacity: 0.28;
|
||||
|
||||
height: 100%;
|
||||
width: 100%;
|
||||
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 2;
|
||||
}
|
||||
8
src/components/Overlay/Overlay.tsx
Normal file
8
src/components/Overlay/Overlay.tsx
Normal file
|
|
@ -0,0 +1,8 @@
|
|||
import React from 'react'
|
||||
import './Overlay.css'
|
||||
|
||||
const Overlay = ({ onClick }) => (
|
||||
<div className="Overlay" onClick={onClick} />
|
||||
)
|
||||
|
||||
export default Overlay
|
||||
9
src/components/SearchModal/SearchModal.css
Normal file
9
src/components/SearchModal/SearchModal.css
Normal file
|
|
@ -0,0 +1,9 @@
|
|||
.SearchModal {
|
||||
min-height: 320px;
|
||||
min-width: 600px;
|
||||
}
|
||||
|
||||
.SearchModal > .Input {
|
||||
padding: 12px 8px;
|
||||
text-align: left;
|
||||
}
|
||||
94
src/components/SearchModal/SearchModal.tsx
Normal file
94
src/components/SearchModal/SearchModal.tsx
Normal file
|
|
@ -0,0 +1,94 @@
|
|||
import React from 'react'
|
||||
import { v1 as uuidv1 } from 'uuid'
|
||||
|
||||
import Portal from '../../Portal'
|
||||
|
||||
import Modal from '../Modal/Modal'
|
||||
import Overlay from '../Overlay/Overlay'
|
||||
|
||||
import './SearchModal.css'
|
||||
|
||||
interface Props {
|
||||
close: () => void
|
||||
placeholderText: string
|
||||
}
|
||||
|
||||
interface State {
|
||||
query: string,
|
||||
results: { [key: string]: any }
|
||||
isLoaded: boolean
|
||||
message: string
|
||||
}
|
||||
|
||||
class SearchModal extends React.Component<Props, State> {
|
||||
searchQuery
|
||||
|
||||
constructor(props) {
|
||||
super(props)
|
||||
this.state = {
|
||||
query: '',
|
||||
results: {},
|
||||
isLoaded: false,
|
||||
message: ''
|
||||
}
|
||||
}
|
||||
|
||||
fetchResults = (query) => {
|
||||
fetch(`http://127.0.0.1:3000/api/v1/search?query=${query}`)
|
||||
.then(res => res.json())
|
||||
.then((result) => {
|
||||
// console.log("hello world!")
|
||||
console.log(result)
|
||||
// this.setState({
|
||||
// isLoaded: true,
|
||||
// results: result
|
||||
// })
|
||||
}, (error) => {
|
||||
// this.setState({
|
||||
// isLoaded: true,
|
||||
// message: error
|
||||
// })
|
||||
})
|
||||
}
|
||||
|
||||
inputChanged = (event) => {
|
||||
const query = this.searchQuery.value
|
||||
if (query.length > 2) {
|
||||
console.log(query)
|
||||
this.fetchResults(query)
|
||||
}
|
||||
|
||||
// if (query) {
|
||||
// this.setState({ query, isLoaded: true, message: '' }, () => {
|
||||
// // this.fetchResults(query)
|
||||
// })
|
||||
// } else {
|
||||
// this.setState({ query, results: {}, message: '' })
|
||||
// }
|
||||
}
|
||||
|
||||
render() {
|
||||
const { query, isLoaded, message } = this.state
|
||||
|
||||
return (
|
||||
<Portal key="search_portal">
|
||||
<Modal styleName="SearchModal" key="search_modal">
|
||||
<input
|
||||
className="Input"
|
||||
defaultValue={query}
|
||||
id="SearchInput"
|
||||
name="query"
|
||||
key="search_input_key"
|
||||
type="text"
|
||||
ref={el => this.searchQuery = el}
|
||||
onChange={this.inputChanged}
|
||||
placeholder={this.props.placeholderText}
|
||||
/>
|
||||
</Modal>
|
||||
<Overlay onClick={this.props.close} />
|
||||
</Portal>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default SearchModal
|
||||
24
src/components/SignupModal/SignupModal.tsx
Normal file
24
src/components/SignupModal/SignupModal.tsx
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
import React from 'react'
|
||||
import Portal from '../../Portal'
|
||||
|
||||
import Modal from '../Modal/Modal'
|
||||
import Overlay from '../Overlay/Overlay'
|
||||
|
||||
const SignupModal = ({ close }) => {
|
||||
return (
|
||||
<Portal>
|
||||
<div>
|
||||
<Modal>
|
||||
<input className="Input" name="username" type="text" placeholder="Username" />
|
||||
<input className="Input" name="email" type="text" placeholder="Email address" />
|
||||
<input className="Input" name="password" type="password" placeholder="Password" />
|
||||
<input className="Input" name="confirm_password" type="password" placeholder="Password (again)" />
|
||||
<button className="Button">Sign up</button>
|
||||
</Modal>
|
||||
<Overlay onClick={close} />
|
||||
</div>
|
||||
</Portal>
|
||||
)
|
||||
}
|
||||
|
||||
export default SignupModal
|
||||
|
|
@ -1,8 +1,15 @@
|
|||
import React from 'react'
|
||||
import './UnauthMenu.css'
|
||||
|
||||
import LoginModal from '../LoginModal/LoginModal'
|
||||
import SignupModal from '../SignupModal/SignupModal'
|
||||
|
||||
import { useModal as useSignupModal } from '../../useModal'
|
||||
import { useModal as useLoginModal } from '../../useModal'
|
||||
|
||||
function UnauthMenu() {
|
||||
const { open: signupOpen, openModal: openSignupModal, closeModal: closeSignupModal } = useSignupModal()
|
||||
const { open: loginOpen, openModal: openLoginModal, closeModal: closeLoginModal } = useLoginModal()
|
||||
|
||||
return (
|
||||
<ul className="Menu">
|
||||
|
|
@ -12,7 +19,16 @@ function UnauthMenu() {
|
|||
</div>
|
||||
<div className="MenuGroup">
|
||||
<li className="MenuItem" onClick={openLoginModal}>Log in</li>
|
||||
{loginOpen ? (
|
||||
<LoginModal
|
||||
close={closeLoginModal}
|
||||
/>
|
||||
) : null}
|
||||
<li className="MenuItem" onClick={openSignupModal}>Sign up</li>
|
||||
{signupOpen ? (
|
||||
<SignupModal
|
||||
close={closeSignupModal}
|
||||
/>
|
||||
) : null}
|
||||
</div>
|
||||
</ul>
|
||||
|
|
|
|||
17
src/useModal.ts
Normal file
17
src/useModal.ts
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
import { useState } from 'react'
|
||||
|
||||
export const useModal = () => {
|
||||
const [open, onOpenModal] = useState(false)
|
||||
const [close, onCloseModal] = useState(false)
|
||||
|
||||
const openModal = () => {
|
||||
onOpenModal(true)
|
||||
}
|
||||
|
||||
const closeModal = () => {
|
||||
onCloseModal(true)
|
||||
onOpenModal(false)
|
||||
}
|
||||
|
||||
return { open, close, openModal, closeModal }
|
||||
}
|
||||
Loading…
Reference in a new issue