navbar skeleton

This commit is contained in:
Ruidy Nemausat 2020-02-04 15:10:44 +01:00
parent 99e61fdd74
commit 0c1e426669
10 changed files with 263 additions and 181 deletions

View file

@ -97,7 +97,8 @@ Free meal planner for cooks short on ideas! (like me …)
1. add sidenav on mobile
1. send message after contact form validation (confirm to sender and msg+info to admin)
1. Breadcrumb
1. Design & Breadcrumb
1. Cookie bar
1. code cleanup (props and refactoring)
1. Back to top button
1. Take a look at some components [here](http://react-materialize.github.io/react-materialize/?path=/story/css-grid--default)

View file

@ -5,7 +5,7 @@
<link rel="icon" href="%PUBLIC_URL%/favicon.ico" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#ee6e73" />
<meta name="description" content="Chef's | Meal Planner" />
<meta name="description" content="Online Meal Planner | Chef's" />
<link rel="apple-touch-icon" href="%PUBLIC_URL%/logo192.png" />
<link rel="manifest" href="%PUBLIC_URL%/manifest.json" />
@ -28,15 +28,9 @@
href="https://fonts.googleapis.com/css?family=Marck+Script&display=swap"
rel="stylesheet"
/>
<title>Chef's | Meal Planner</title>
<title>Online Meal Planner | Chef's</title>
</head>
<body>
<!-- <script>
document.addEventListener("DOMContentLoaded", function() {
var elems = document.querySelectorAll(".sidenav");
var instances = M.Sidenav.init(elems, options);
});
</script> -->
<noscript>You need to enable JavaScript to run this app.</noscript>
<div id="root"></div>
</body>

View file

@ -1,39 +1,43 @@
import React from "react";
import { useInput } from "../utils/inputHook";
export const ContactForm = ({ handleSubmit }) => {
export const ContactForm = ({ onSubmit }) => {
// const fields = ["firstname", "lastname", "email", "phone", "message"];
// const [firstName, setFirstName] = useState("");
// const [firstName, setFirstName] = useState("");
const onSubmit = ev => {
const handleSubmit = ev => {
ev.preventDefault();
handleSubmit(true);
onSubmit(true);
};
// const handleChange = ev => {
// const { value } = ev.target;
// setFirstName(value);
// };
// const handleChange = ev => {
// const { value } = ev.target;
// setFirstName(value);
// };
// const { value, bind } = useInput("");
const { bind } = useInput("");
return (
<form onSubmit={onSubmit}>
<form onSubmit={handleSubmit}>
<div className="row">
<div className="col s12">
<div className="col s12 m6">
<ContactFormInput id="First Name" />
</div>
<div className="col s12 m6">
<ContactFormInput id="Last Name" />
</div>
<div className="col s12 m6">
<ContactFormInput
id="Email"
type="email"
placeholder="jd@mail.com"
id="First Name"
// value={firstName}
// onChange={handleChange}
{...bind}
/>
</div>
<div className="col s12 m6">
<ContactFormInput id="Phone" placeholder="0123456789" />
<ContactFormInput id="Last Name" {...bind} />
</div>
<div className="col s12 m6">
<ContactFormInput id="Email" type="email" />
</div>
<div className="col s12 m6">
<ContactFormInput id="Phone" />
</div>
<div className="col s12">
<ContactFormTextArea id="Message" />
@ -45,18 +49,18 @@ export const ContactForm = ({ handleSubmit }) => {
);
};
const ContactFormInput = ({ id, type = "text" }) => {
const ContactFormInput = ({ id, type = "text", value, onChange }) => {
return (
<div className="input-field">
{/* <i class="material-icons prefix">account_circle</i> */}
<label for={id}>{id}</label>
<label htmlFor={id}>{id}</label>
<input
className="validate"
type={type}
id={id}
name={id}
// value={value}
// onChange={onChange}
name={value}
value={value}
onChange={onChange}
/>
</div>
);
@ -65,7 +69,7 @@ const ContactFormInput = ({ id, type = "text" }) => {
const ContactFormTextArea = ({ id }) => {
return (
<div className="input-field">
<label for={id}>{id}</label>
<label htmlFor={id}>{id}</label>
<textarea
className="materialize-textarea validate"
rows="12"
@ -85,7 +89,7 @@ const ContactFormSubmit = ({ text }) => {
type="submit"
name="submit"
>
<i class="material-icons right">send</i> {text}
<i className="material-icons right">send</i> {text}
</button>
);
};

View file

@ -9,8 +9,9 @@ import { LogOutButton } from "./LogOutButton";
export const Navbar = props => {
const { isAuthenticated } = useAuth0();
const links = ["categories", "contact"];
const { openNavClick } = props;
return (
<div className="row">
<div className="navbar-fixed">
<nav>
<div className="nav-wrapper">
<div className="container ">
@ -29,50 +30,17 @@ export const Navbar = props => {
</li>
<li>{!isAuthenticated ? <LogInButton /> : <LogOutButton />}</li>
</ul>
<a
href="#"
data-target="slide-out"
class="sidenav-trigger "
onClick={openNavClick}
>
<i class="material-icons">menu</i>
</a>
</div>
</div>
</nav>
{/* <ul id="slide-out" class="sidenav show-on-small">
<li>
<div class="user-view">
<div class="background">
<img src="images/office.jpg" />
</div>
<a href="#user">
<img class="circle" src="images/yuna.jpg" />
</a>
<a href="#name">
<span class="white-text name">John Doe</span>
</a>
<a href="#email">
<span class="white-text email">jdandturk@gmail.com</span>
</a>
</div>
</li>
<li>
<a href="#!">
<i class="material-icons">cloud</i>First Link With Icon
</a>
</li>
<li>
<a href="#!">Second Link</a>
</li>
<li>
<div class="divider"></div>
</li>
<li>
<a class="subheader">Subheader</a>
</li>
<li>
<a class="waves-effect" href="#!">
Third Link With Waves
</a>
</li>
</ul>
<a href="#" data-target="slide-out" class="sidenav-trigger">
<i class="material-icons">menu</i>
</a> */}
</div>
);
};

View file

@ -4,28 +4,38 @@ import { Link } from "react-router-dom";
export const SearchBar = props => {
return (
<div className="container">
<div className="row center-align">
<form>
<input
className="input-field col s10"
type="text"
name="search"
value={props.searchString}
placeholder="Search a recipe"
onChange={props.handleChange}
/>
<Link to="/search">
<button
className="btn-floating waves-effect waves-light"
type="submit"
name="searchButton"
value="Search"
onClick={props.onSubmit}
>
<i className="material-icons right">send</i>
</button>
</Link>
</form>
<div className=" nav-wrapper">
<div className="row center-align">
<form>
<div className="input-field col s10">
<input
className=""
id="search"
type="search"
required
name="search"
value={props.searchString}
placeholder="Search for a recipe"
onChange={props.handleChange}
/>
<label className="label-icon" htmlFor="search">
<i className="material-icons">search</i>
</label>
<i className="material-icons">close</i>
</div>
<Link to="/search">
<button
className="btn-floating waves-effect waves-light"
type="submit"
name="searchButton"
value="Search"
onClick={props.onSubmit}
>
<i className="material-icons right">send</i>
</button>
</Link>
</form>
</div>
</div>
</div>
);

View file

@ -0,0 +1,59 @@
import React, { useState } from "react";
import { Link } from "react-router-dom";
// import { useAuth0 } from "../utils/auth0-spa";
// import { Logo } from "./Logo";
// import { RandomButton } from "./RandomButton";
// import { FooterLink } from "./FooterLink";
// import { LogInButton } from "./LogInButton";
// import { LogOutButton } from "./LogOutButton";
export const SideNav = props => {
const { showNav } = props;
let transformStyle = {
transform: showNav ? "translateX(0%)" : "translateX(-105%)"
};
// let sideNavStyle = { width: showNav ? "250px" : "0" };
return (
<>
<ul id="slide-out" class="sidenav" style={transformStyle}>
<li>
<div class="user-view">
<div class="background">
<img src={require("../images/chef.svg")} />
</div>
<a href="#user">
<img class="circle" src={require("../images/chef.svg")} />
</a>
<a href="#name">
<span class="white-text name">John Doe</span>
</a>
<a href="#email">
<span class="white-text email">jdandturk@gmail.com</span>
</a>
</div>
</li>
<li>
<a href="#!">
<i class="material-icons">cloud</i>First Link With Icon
</a>
</li>
<li>
<a href="#!">Second Link</a>
</li>
<li>
<div class="divider"></div>
</li>
<li>
<a class="subheader">Subheader</a>
</li>
<li>
<a class="waves-effect" href="#!">
Third Link With Waves
</a>
</li>
</ul>
</>
);
};

View file

@ -1,7 +1,7 @@
import React from "react";
import ReactDOM from "react-dom";
import "./index.css";
import { App } from "./App";
import { App } from "./pages/App.jsx";
import * as serviceWorker from "./serviceWorker";
import { Auth0Provider } from "./utils/auth0-spa";
import history from "./utils/history";

View file

@ -1,23 +1,24 @@
import React, { useState } from "react";
import { Router } from "./utils/router";
import { Router } from "../utils/router";
import { Switch, Route, Redirect } from "react-router-dom";
import { useAuth0 } from "./utils/auth0-spa";
import { Home } from "./pages/Home";
import { Meal } from "./pages/Meal";
import { SearchPage } from "./pages/Search";
import { CategoryListPage } from "./pages/CategoryList";
import { CategoryPage } from "./pages/Category";
import { ContactPage } from "./pages/Contact";
import { NotFoundPage } from "./pages/NotFound";
import { Navbar } from "./components/Navbar";
import { SearchBar } from "./components/SearchBar";
import { Footer } from "./components/Footer";
import "./index.css";
import { getData } from "./utils/methods";
import history from "./utils/history";
import { Profile } from "./pages/Profile";
import { PrivateRoute } from "./components/PrivateRoute";
import { PreLoader } from "./components/PreLoader";
import { useAuth0 } from "../utils/auth0-spa";
import { Home } from "./Home";
import { Meal } from "./Meal";
import { SearchPage } from "./Search";
import { CategoryListPage } from "./CategoryList";
import { CategoryPage } from "./Category";
import { ContactPage } from "./Contact";
import { NotFoundPage } from "./NotFound";
import { Navbar } from "../components/Navbar";
import { SearchBar } from "../components/SearchBar";
import { Footer } from "../components/Footer";
import { getData } from "../utils/methods";
import history from "../utils/history";
import { Profile } from "./Profile";
import { PrivateRoute } from "../components/PrivateRoute";
import { PreLoader } from "../components/PreLoader";
import { SideNav } from "../components/SideNav";
import "../index.css";
export const App = () => {
const { loading } = useAuth0();
@ -35,7 +36,7 @@ export const App = () => {
strArea: "Mine",
strInstructions:
"Cook the pasta following pack instructions.\r\n\r\nHeat the oil in a non-stick frying pan and cook the onion, garlic and chilli for 3-4 mins to soften. Stir in the tomato pur\u00e9e and cook for 1 min, then add the pilchards with their sauce. Cook, breaking up the fish with a wooden spoon, then add the olives and continue to cook for a few more mins.\r\n\r\nDrain the pasta and add to the pan with 2-3 tbsp of the cooking water. Toss everything together well, then divide between plates and serve, scattered with Parmesan.",
strMealThumb: require("./images/breakfast.svg"),
strMealThumb: require("../images/breakfast.svg"),
// "https://www.themealdb.com/images/media/meals/vvtvtr1511180578.jpg",
strTags: null,
strYoutube: "#",
@ -109,80 +110,108 @@ export const App = () => {
const buttonUrl = "/random";
const [showNav, setShowNav] = useState(false);
const openNavClick = ev => {
ev.preventDefault();
setShowNav(true);
document.addEventListener("keydown", handleEscKey);
};
const closeNavClick = ev => {
ev.preventDefault();
setShowNav(false);
document.removeEventListener("keydown", handleEscKey);
};
const handleEscKey = ev => {
if (ev.key === "Escape") {
setShowNav(false);
}
};
return loading ? (
<div className="container center-align valign-wrapper">
<PreLoader />
</div>
) : (
<Router history={history}>
<header>
<Navbar handleClick={getRandomMeal} buttonUrl={buttonUrl} />
</header>
<SearchBar
searchString={searchString}
handleChange={handleChange}
onSubmit={getSearchResults}
/>
<Switch>
<Route exact path="/">
<Home buttonUrl={buttonUrl} />
</Route>
<PrivateRoute exact path="/profile">
<Profile />
</PrivateRoute>
<Route exact path={buttonUrl}>
{meal !== undefined && meal.meals !== null ? (
<Meal meal={meal} getMeal={getRandomMeal} />
) : (
<NotFoundPage handleClick={getRandomMeal} />
)}
</Route>
<Route exact path="/categories">
<CategoryListPage items={categories} getCategories={getCategories} />
</Route>
<Route path="/categories/:strCategory/">
<CategoryPage
getData={getData}
getMeal={getMeal}
setMeal={setMeal}
meal={meal}
<>
<Router history={history}>
<header>
<Navbar
handleClick={getRandomMeal}
buttonUrl={buttonUrl}
openNavClick={openNavClick}
/>
</Route>
<Route exact path="/search">
<SearchPage
<SearchBar
searchString={searchString}
searchResults={searchResults}
handleChange={handleChange}
onSubmit={getSearchResults}
/>
</Route>
<SideNav showNav={showNav} />
</header>
<Route path="/contact">
<ContactPage />
</Route>
<Switch>
<Route exact path="/">
<Home buttonUrl={buttonUrl} />
</Route>
<Route path="/404">
<NotFoundPage handleClick={getRandomMeal} />
</Route>
<PrivateRoute exact path="/profile">
<Profile />
</PrivateRoute>
<Route path="/:idMeal">
{meal !== undefined && meal.meals !== null ? (
<Meal meal={meal} getMeal={getMeal} />
) : (
<Route exact path={buttonUrl}>
{meal !== undefined && meal.meals !== null ? (
<Meal meal={meal} getMeal={getRandomMeal} />
) : (
<NotFoundPage handleClick={getRandomMeal} />
)}
</Route>
<Route exact path="/categories">
<CategoryListPage
items={categories}
getCategories={getCategories}
/>
</Route>
<Route path="/categories/:strCategory/">
<CategoryPage
getData={getData}
getMeal={getMeal}
setMeal={setMeal}
meal={meal}
/>
</Route>
<Route exact path="/search">
<SearchPage
searchString={searchString}
searchResults={searchResults}
/>
</Route>
<Route path="/contact">
<ContactPage />
</Route>
<Route path="/404">
<NotFoundPage handleClick={getRandomMeal} />
)}
</Route>
</Route>
<Route path="*">
<Redirect to="/404" />
</Route>
</Switch>
<Route path="/:idMeal">
{meal !== undefined && meal.meals !== null ? (
<Meal meal={meal} getMeal={getMeal} />
) : (
<NotFoundPage handleClick={getRandomMeal} />
)}
</Route>
<Footer />
</Router>
<Route path="*">
<Redirect to="/404" />
</Route>
</Switch>
<Footer />
</Router>
</>
);
};

View file

@ -16,8 +16,8 @@ export const ContactPage = props => {
</div>
) : (
<div className="container">
<h1 className="logo">Contact Us</h1>
<ContactForm handleSubmit={setIsSubmitted} />
<h2 className="logo">Contact Us</h2>
<ContactForm onSubmit={setIsSubmitted} />
</div>
);
};

17
src/utils/inputHook.js Normal file
View file

@ -0,0 +1,17 @@
import { useState } from "react";
export const useInput = initialValue => {
const [value, setValue] = useState(initialValue);
return {
value,
setValue,
reset: () => setValue(""),
bind: {
value,
onChange: ev => {
setValue(ev.target.value);
}
}
};
};