Created styles for login and register pages. Started styling home page
This commit is contained in:
parent
6c60520aae
commit
3f580213fa
@ -9,6 +9,7 @@
|
||||
"@types/react-dom": "^16.9.0",
|
||||
"@types/react-router-dom": "^5.1.6",
|
||||
"@types/validator": "^13.1.0",
|
||||
"generate-avatar": "^1.4.6",
|
||||
"graphql": "^15.3.0",
|
||||
"react": "^16.13.1",
|
||||
"react-dom": "^16.13.1",
|
||||
@ -38,6 +39,7 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@graphql-codegen/cli": "^1.17.10",
|
||||
"@graphql-codegen/typescript": "^1.17.10"
|
||||
"@graphql-codegen/typescript": "^1.17.10",
|
||||
"typescript-plugin-css-modules": "^2.7.0"
|
||||
}
|
||||
}
|
||||
|
28
public/index.css
Normal file
28
public/index.css
Normal file
@ -0,0 +1,28 @@
|
||||
:root {
|
||||
--backgroundColor: rgba(54, 54, 69, 0.05);
|
||||
--containerColor: rgb(54, 54, 69);
|
||||
--accentColor: rgb(109, 245, 119);
|
||||
--accentShadowColor: rgba(109, 245, 119, 0.16);
|
||||
|
||||
--onAccentFontColor: #ffffff;
|
||||
}
|
||||
|
||||
* {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
body {
|
||||
background-color: var(--backgroundColor);
|
||||
min-height: 100vh;
|
||||
color: var(--containerColor);
|
||||
}
|
||||
|
||||
input {
|
||||
color: var(--containerColor);
|
||||
}
|
||||
|
||||
#root {
|
||||
height: 100vh;
|
||||
}
|
@ -23,6 +23,8 @@
|
||||
work correctly both with client-side routing and a non-root public URL.
|
||||
Learn how to configure a non-root public URL by running `npm run build`.
|
||||
-->
|
||||
|
||||
<link rel="stylesheet" href="index.css" />
|
||||
<title>QuestionForm</title>
|
||||
</head>
|
||||
<body>
|
||||
|
@ -8,7 +8,9 @@ import { useUser } from '../hooks'
|
||||
import Authorize from './Authorize'
|
||||
import CreateForm from './CreateForm'
|
||||
import DoForm from './DoForm'
|
||||
import Home from './Home'
|
||||
import Login from './Login'
|
||||
import Navbar from './Navbar'
|
||||
import Register from './Register'
|
||||
import UserPage from './UserPage'
|
||||
|
||||
@ -20,6 +22,7 @@ const App: React.FC = () => {
|
||||
<ApolloProvider client={client}>
|
||||
<Context.Provider value={userContext}>
|
||||
<Router>
|
||||
<Navbar />
|
||||
<Switch>
|
||||
<Route path="/login" component={Login} />
|
||||
<Route path="/authorize" component={Authorize} />
|
||||
@ -27,6 +30,7 @@ const App: React.FC = () => {
|
||||
<Route path="/form/:id" component={DoForm} />
|
||||
<Route path="/create" component={CreateForm} />
|
||||
<Route path="/register" component={Register} />
|
||||
<Route exact path="/" component={Home} />
|
||||
</Switch>
|
||||
</Router>
|
||||
</Context.Provider>
|
||||
|
23
src/components/Card/index.tsx
Normal file
23
src/components/Card/index.tsx
Normal file
@ -0,0 +1,23 @@
|
||||
import React from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
|
||||
import styles from './main.module.css'
|
||||
|
||||
interface props {
|
||||
title: string
|
||||
subtitle?: string
|
||||
icon?: React.Component
|
||||
iconCounter?: number
|
||||
id: number
|
||||
}
|
||||
|
||||
const Card: React.FC<props> = ({ title, subtitle, id }) => {
|
||||
return (
|
||||
<Link to={`/form/${id}`} className={styles.card}>
|
||||
<h4>{title}</h4>
|
||||
{subtitle ?? <h5>{subtitle}</h5>}
|
||||
</Link>
|
||||
)
|
||||
}
|
||||
|
||||
export default Card
|
11
src/components/Card/main.module.css
Normal file
11
src/components/Card/main.module.css
Normal file
@ -0,0 +1,11 @@
|
||||
.card {
|
||||
display: block;
|
||||
background-color: var(--accentColor);
|
||||
width: 35vw;
|
||||
padding: 1.5vh;
|
||||
white-space: nowrap;
|
||||
border-radius: 0.75vh;
|
||||
box-shadow: 0 1px 6px 0 var(--accentShadowColor);
|
||||
text-decoration: none;
|
||||
color: var(--onAccentFontColor);
|
||||
}
|
40
src/components/Home/index.tsx
Normal file
40
src/components/Home/index.tsx
Normal file
@ -0,0 +1,40 @@
|
||||
import React from 'react'
|
||||
import { useQuery } from '@apollo/client'
|
||||
|
||||
import Card from '../Card'
|
||||
import { USER } from '../../apollo'
|
||||
import { QueryUserArgs, User } from '../../apollo/typeDefs.gen'
|
||||
import styles from './main.module.css'
|
||||
import { Redirect } from 'react-router-dom'
|
||||
|
||||
interface IUserQuery {
|
||||
user: User
|
||||
}
|
||||
|
||||
const Home: React.FC = () => {
|
||||
const { data, error, loading } = useQuery<IUserQuery, QueryUserArgs>(USER)
|
||||
if (loading) return <p>Loading...</p>
|
||||
|
||||
if (error?.message === 'Authorization required')
|
||||
return <Redirect to="/login" />
|
||||
|
||||
if (error) return <p>{error.message}</p>
|
||||
|
||||
const { user } = data!
|
||||
|
||||
const { forms } = user
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<ul className={styles.leftPad}>
|
||||
{forms!.map((form, formIndex) => (
|
||||
<li key={formIndex}>
|
||||
<Card title={form.title} id={form.id} />
|
||||
</li>
|
||||
))}
|
||||
</ul>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
export default Home
|
12
src/components/Home/main.module.css
Normal file
12
src/components/Home/main.module.css
Normal file
@ -0,0 +1,12 @@
|
||||
.container {
|
||||
display: grid;
|
||||
height: calc(100vh - 4rem);
|
||||
grid-template-columns: 4fr 3fr;
|
||||
}
|
||||
|
||||
.leftPad {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
align-items: center;
|
||||
list-style: none;
|
||||
}
|
@ -1,9 +1,10 @@
|
||||
import { useMutation } from '@apollo/client'
|
||||
import React, { ChangeEvent, FormEvent, useState } from 'react'
|
||||
import { Redirect } from 'react-router-dom'
|
||||
|
||||
import { LOGIN } from '../../apollo'
|
||||
import { MutationLoginArgs, ServerAnswer } from '../../apollo/typeDefs.gen'
|
||||
import styles from './main.module.css'
|
||||
import meme from './meme.png'
|
||||
|
||||
interface ILoginMutation {
|
||||
login: ServerAnswer
|
||||
@ -12,7 +13,7 @@ interface ILoginMutation {
|
||||
const Login: React.FC = () => {
|
||||
const [email, setEmail] = useState<string>('')
|
||||
|
||||
const [doLogin, { error, data }] = useMutation<
|
||||
const [doLogin, { error, data, loading }] = useMutation<
|
||||
ILoginMutation,
|
||||
MutationLoginArgs
|
||||
>(LOGIN)
|
||||
@ -29,13 +30,42 @@ const Login: React.FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<div className={styles.formCard}>
|
||||
<img
|
||||
className={styles.img}
|
||||
src={meme}
|
||||
alt="You can't forget password if you don't have it"
|
||||
/>
|
||||
<form className={styles.form} onSubmit={handleFormSubmit}>
|
||||
{data?.login.success ? (
|
||||
<div>
|
||||
<form onSubmit={handleFormSubmit}>
|
||||
<input type="text" onChange={handleInputChange} />
|
||||
<input type="submit" value="Login" />
|
||||
<h1>
|
||||
You will get <span className={styles.focus}>login link</span>{' '}
|
||||
<br /> in your <span className={styles.focus}>mailbox</span>
|
||||
</h1>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<h1 className={styles.header}>Login</h1>
|
||||
<input
|
||||
className={styles.input}
|
||||
name="email"
|
||||
id="email"
|
||||
type="email"
|
||||
placeholder="email"
|
||||
onChange={handleInputChange}
|
||||
/>
|
||||
{loading ? (
|
||||
'Loading...'
|
||||
) : (
|
||||
<input type="submit" value="Login" className={styles.button} />
|
||||
)}
|
||||
{error && <p className={styles.errorMsg}>{error.message}</p>}
|
||||
</>
|
||||
)}
|
||||
</form>
|
||||
{error && error.message}
|
||||
{data && data.login && data.login.success && <Redirect to="/" />}
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
81
src/components/Login/main.module.css
Normal file
81
src/components/Login/main.module.css
Normal file
@ -0,0 +1,81 @@
|
||||
.container {
|
||||
display: flex;
|
||||
min-height: calc(100% - 4rem);
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 2.3rem;
|
||||
}
|
||||
|
||||
.formCard {
|
||||
min-width: 50vw;
|
||||
background-color: #ffffff;
|
||||
border-radius: 20px;
|
||||
display: grid;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
max-width: 90vw;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.img {
|
||||
height: 70vh;
|
||||
object-fit: contain;
|
||||
}
|
||||
|
||||
.form {
|
||||
padding: 20px;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
gap: 5px;
|
||||
}
|
||||
|
||||
.form input {
|
||||
height: 2.3rem;
|
||||
border-radius: 100vh;
|
||||
border: none;
|
||||
outline: none;
|
||||
font-size: 1.2rem;
|
||||
padding: 0 0.7rem;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.form label {
|
||||
padding: 0 0.7rem;
|
||||
}
|
||||
|
||||
.header {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.input {
|
||||
border-bottom: 0.15rem var(--containerColor) solid !important;
|
||||
transition: border-bottom 0.1s;
|
||||
}
|
||||
.input:focus {
|
||||
border-bottom-width: 0rem !important;
|
||||
}
|
||||
|
||||
.button {
|
||||
background-color: var(--accentColor);
|
||||
}
|
||||
|
||||
.errorMsg {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.focus {
|
||||
color: var(--accentColor);
|
||||
}
|
||||
|
||||
@media (orientation: portrait) {
|
||||
.formCard {
|
||||
grid-template-columns: 1fr;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
min-height: calc(100% - 4rem);
|
||||
}
|
||||
|
||||
.img {
|
||||
height: initial;
|
||||
width: 100%;
|
||||
}
|
||||
}
|
BIN
src/components/Login/meme.png
Normal file
BIN
src/components/Login/meme.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 87 KiB |
14
src/components/Navbar/index.tsx
Normal file
14
src/components/Navbar/index.tsx
Normal file
@ -0,0 +1,14 @@
|
||||
import React from 'react'
|
||||
import { Link } from 'react-router-dom'
|
||||
import styles from './main.module.css'
|
||||
import logo from './logo.svg'
|
||||
|
||||
const Navbar: React.FC = () => (
|
||||
<nav className={styles.nav}>
|
||||
<Link to="/" className={styles.logo}>
|
||||
<img src={logo} alt="" className={styles.logo} />
|
||||
</Link>
|
||||
</nav>
|
||||
)
|
||||
|
||||
export default Navbar
|
26
src/components/Navbar/logo.svg
Normal file
26
src/components/Navbar/logo.svg
Normal file
@ -0,0 +1,26 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 20010904//EN" "http://www.w3.org/TR/2001/REC-SVG-20010904/DTD/svg10.dtd">
|
||||
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="1.70667in" height="1.70667in" viewBox="0 0 512 512">
|
||||
<path id="Selection" fill="#6df577" d="M 240.00,0.21
|
||||
C 240.00,0.21 264.00,0.21 264.00,0.21
|
||||
264.00,0.21 276.00,0.91 276.00,0.91
|
||||
300.87,2.65 324.65,8.22 348.00,16.95
|
||||
373.01,26.30 398.45,41.27 419.00,58.25
|
||||
439.59,75.27 457.63,95.40 471.95,118.00
|
||||
534.76,217.17 522.88,344.95 443.09,431.00
|
||||
423.70,451.91 400.58,469.96 375.00,482.75
|
||||
330.78,504.88 295.27,512.57 246.00,512.00
|
||||
246.00,512.00 236.00,511.09 236.00,511.09
|
||||
215.63,509.66 195.41,505.80 176.00,499.33
|
||||
139.83,487.29 108.97,469.02 81.00,443.09
|
||||
81.00,443.09 74.17,436.91 74.17,436.91
|
||||
31.81,393.29 5.16,336.79 0.91,276.00
|
||||
0.91,276.00 0.00,264.00 0.00,264.00
|
||||
0.00,264.00 0.00,248.00 0.00,248.00
|
||||
0.00,248.00 0.91,236.00 0.91,236.00
|
||||
2.95,206.83 10.08,177.63 22.31,151.00
|
||||
51.84,86.67 103.14,38.48 170.00,14.69
|
||||
186.39,8.86 203.75,4.61 221.00,2.28
|
||||
221.00,2.28 240.00,0.21 240.00,0.21 Z" />
|
||||
</svg>
|
After Width: | Height: | Size: 1.3 KiB |
16
src/components/Navbar/main.module.css
Normal file
16
src/components/Navbar/main.module.css
Normal file
@ -0,0 +1,16 @@
|
||||
.nav {
|
||||
display: flex;
|
||||
width: 100vw;
|
||||
height: 4rem;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
background-color: var(--containerColor);
|
||||
border-bottom-left-radius: 20px;
|
||||
border-bottom-right-radius: 20px;
|
||||
}
|
||||
|
||||
.logo {
|
||||
display: block;
|
||||
height: 2.7rem;
|
||||
width: 2.7rem;
|
||||
}
|
@ -1,8 +1,11 @@
|
||||
import { useMutation } from '@apollo/client'
|
||||
import React, { FormEvent } from 'react'
|
||||
import { Redirect } from 'react-router-dom'
|
||||
|
||||
import { REGISTER } from '../../apollo'
|
||||
import { MutationRegisterArgs, ServerAnswer } from '../../apollo/typeDefs.gen'
|
||||
import styles from '../Login/main.module.css'
|
||||
import meme from './meme.jpg'
|
||||
|
||||
interface IRegisterMutation {
|
||||
register: ServerAnswer
|
||||
@ -29,16 +32,37 @@ const Register: React.FC = () => {
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
Register
|
||||
<form onSubmit={handleSubmit}>
|
||||
<input type="email" name="email" placeholder="email" />
|
||||
<input type="text" name="name" placeholder="username" />
|
||||
{loading ? 'Loading...' : <input type="submit" value="Submit" />}
|
||||
{error && error.message}
|
||||
{data && data.register && data.register.success && <Redirect to="/" />}
|
||||
<div className={styles.container}>
|
||||
<div className={styles.formCard}>
|
||||
<img
|
||||
className={styles.img}
|
||||
src={meme}
|
||||
alt='Questionform says: "Is mailbox a password?"'
|
||||
/>
|
||||
<form className={styles.form} onSubmit={handleSubmit}>
|
||||
<h1 className={styles.header}>Register</h1>
|
||||
<input
|
||||
className={styles.input}
|
||||
type="email"
|
||||
name="email"
|
||||
placeholder="email"
|
||||
/>
|
||||
<input
|
||||
className={styles.input}
|
||||
type="text"
|
||||
name="name"
|
||||
placeholder="username"
|
||||
/>
|
||||
{loading ? (
|
||||
'Loading...'
|
||||
) : (
|
||||
<input className={styles.button} type="submit" value="Submit" />
|
||||
)}
|
||||
{error && <p className={styles.errorMsg}>{error.message}</p>}
|
||||
{data?.register.success && <Redirect to="/" />}
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
|
BIN
src/components/Register/meme.jpg
Normal file
BIN
src/components/Register/meme.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 61 KiB |
@ -11,3 +11,7 @@ code {
|
||||
font-family: source-code-pro, Menlo, Monaco, Consolas, 'Courier New',
|
||||
monospace;
|
||||
}
|
||||
|
||||
.App {
|
||||
height: 100vh;
|
||||
}
|
||||
|
@ -13,7 +13,8 @@
|
||||
"resolveJsonModule": true,
|
||||
"isolatedModules": true,
|
||||
"noEmit": true,
|
||||
"jsx": "react"
|
||||
"jsx": "react",
|
||||
"plugins": [{ "name": "typescript-plugin-css-modules" }]
|
||||
},
|
||||
"include": ["src"]
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user