Bläddra i källkod

Added Material Design components. Revamp drawer and extract logic to its own component

Tati 7 år sedan
förälder
incheckning
f62df7066f

+ 6 - 0
package.json

@@ -9,10 +9,16 @@
   "author": "",
   "license": "ISC",
   "dependencies": {
+    "@material/react-card": "^0.11.0",
+    "@material/react-drawer": "^0.11.0",
+    "@types/classnames": "^2.2.7",
     "@types/dotenv": "^6.1.0",
+    "@types/material-components-web": "^0.43.1",
+    "@types/node": "^11.13.2",
     "@types/sqlite3": "^3.1.3",
     "dotenv": "^6.2.0",
     "express": "^4.16.4",
+    "material-components-web": "^1.1.1",
     "nano": "^8.0.0",
     "ramda": "^0.26.1",
     "sqlite3": "^4.0.6"

+ 1 - 0
recipes/.env

@@ -0,0 +1 @@
+SASS_PATH=node_modules:src

+ 2 - 2
recipes/package.json

@@ -3,8 +3,9 @@
   "version": "0.1.0",
   "private": true,
   "dependencies": {
+    "@material/react-drawer": "^0.11.0",
+    "@material/react-list": "^0.11.0",
     "@types/jest": "^24.0.11",
-    "@types/muicss": "^0.9.1",
     "@types/node": "^11.13.0",
     "@types/react": "^16.8.12",
     "@types/react-dom": "^16.8.3",
@@ -13,7 +14,6 @@
     "@types/storybook__addon-links": "^3.3.4",
     "@types/storybook__react": "^4.0.1",
     "axios": "^0.18.0",
-    "muicss": "^0.9.41",
     "node-sass": "^4.11.0",
     "react": "^16.8.4",
     "react-dom": "^16.8.4",

+ 0 - 3
recipes/public/index.html

@@ -25,9 +25,6 @@
     <title>Recipes</title>
     <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Roboto:300,400,500">
     <link rel="stylesheet" href="https://fonts.googleapis.com/css?family=Lekton">
-    <link href="//cdn.muicss.com/mui-0.9.41/css/mui.min.css" rel="stylesheet" type="text/css" />
-    <script src="//cdn.muicss.com/mui-0.9.41/js/mui.min.js"></script>
-
   </head>
   <body>
     <noscript>You need to enable JavaScript to run this app.</noscript>

+ 20 - 48
recipes/src/App.tsx

@@ -1,7 +1,9 @@
-import { BrowserRouter as Router, Route, Link } from "react-router-dom";
+import { BrowserRouter as Router, Route, Link, NavLink } from "react-router-dom";
 import React, { Component, Props } from 'react';
-import axios from 'axios';
-import Navbar from './components/Navbar';
+import CBKDrawer from './components/Drawer';
+import List, {ListItem, ListItemText} from '@material/react-list';
+
+import './styles/app.scss';
 
 function Index() {
   return <h2>Home</h2>;
@@ -11,62 +13,32 @@ function Users() {
   return <h2>Users</h2>;
 }
 
-class Recipes extends Component {
-  constructor(props: any) {
-    super(props);
-    this.state = {
-      error: null,
-      isLoaded: false,
-      recipes: [],
-    }
-  }
-
-  componentDidMount(){
-    axios.get('https://recipes.davidventura.com.ar/recipes/ingredients/?ingredients=beef,bacon').then(response => {
-      console.log('response', response.data);
-      this.setState({
-        isLoaded: true,
-        recipes: response.data,
-      })
-    }).catch(error => {
-      this.setState({
-        isLoaded: true,
-        error: error,
-        recipes: [],
-      })
-    })
-  }
-
-  render() {
-    return (
-      <h2>Recipes yayyy!!</h2>
-    )
-  }
-}
-
-class App extends Component {
+class App extends Component<{}, {}> {
   navbarItems: { title: string, path: string, active: boolean }[]
 
   constructor(props: any) {
     super(props);
     this.navbarItems = [
-      { title: 'home', path: '/', active: false },
-      { title: 'recipes', path: '/recipes', active: false },
-      { title: 'planner', path: '/planner', active: false },
-      { title: 'shoplist', path: '/shoplist', active: false },
+      { title: 'Recipes', path: '/recipes', active: false },
+      { title: 'Planner', path: '/planner', active: false },
+      { title: 'Shoplist', path: '/shoplist', active: false },
     ];
   }
 
   render() {
     return (
       <Router>
-        <div>
-          <Navbar items={this.navbarItems}></Navbar>
-
-          <Route path="/" exact component={Index} />
-          <Route path="/recipes/" component={Recipes} />
-          <Route path="/users/" component={Users} />
-        </div>
+        <CBKDrawer>
+          {
+            this.navbarItems.map((item, i) => (
+              <NavLink
+                to={item.path}
+                activeClassName='active'
+                key={i}
+              >{item.title}</NavLink>
+            ))
+          }
+        </CBKDrawer>
       </Router>
     )
   }

+ 0 - 0
recipes/src/components/Card/.stories.js


+ 27 - 0
recipes/src/components/Card/index.tsx

@@ -0,0 +1,27 @@
+import React from 'react';
+import Card, {
+  CardActions,
+  CardActionButtons,
+  CardActionIcons
+} from "@material/react-card";
+
+import '@material/react-card/dist/card.min.css';
+
+function RCard(){
+  return(
+    <Card>
+      <h1>Title</h1>
+      <CardActions>
+        <CardActionButtons>
+          <button>Click Me</button>
+        </CardActionButtons>
+
+        <CardActionIcons>
+          <i>Click Me Too!</i>
+        </CardActionIcons>
+      </CardActions>
+    </Card>
+  )
+}
+
+export default RCard;

+ 0 - 0
recipes/src/components/Card/styles.scss


+ 44 - 0
recipes/src/components/Drawer/index.tsx

@@ -0,0 +1,44 @@
+import React, { ReactNode, ReactChildren } from 'react';
+import Drawer, {
+  DrawerHeader,
+  DrawerSubtitle,
+  DrawerTitle,
+  DrawerContent,
+} from '@material/react-drawer';
+import List, {ListItem, ListItemText} from '@material/react-list';
+
+import '@material/react-drawer/dist/drawer.min.css';
+import '@material/react-list/dist/list.min.css';
+
+import './styles.scss';
+import { ReactNodeArray } from 'prop-types';
+
+type CBKDrawerProps = {
+  children: ReactNodeArray,
+}
+
+function CBKDrawer(props: CBKDrawerProps) {
+  return (
+    <Drawer className='cbk-drawer'>
+      <DrawerHeader>
+        <DrawerTitle tag='h1'>
+          cookbook
+        </DrawerTitle>
+      </DrawerHeader>
+
+      <DrawerContent tag='main'>
+        <List>
+          {
+            props.children.map((child: any, i) => (
+              <ListItem key={i}>
+                { child }
+              </ListItem>
+            ))
+          }
+        </List>
+      </DrawerContent>
+    </Drawer>
+  );
+}
+
+export default CBKDrawer;

+ 42 - 0
recipes/src/components/Drawer/styles.scss

@@ -0,0 +1,42 @@
+@import '../../styles/variables';
+
+.cbk-drawer {
+  background-color: #BDBDBD;
+  padding-top: $spacing-xx-large;
+  text-align: center;
+  font-family: $font-family-display;
+  color: $white;
+  
+  .mdc-drawer__title {
+    text-transform: uppercase;
+    color: $white;
+    font-family: $font-family-display;
+    font-weight: $font-weight-bold;
+    letter-spacing: 0.075em;
+    font-size: $font-size-xx-large
+  }
+
+  .mdc-list-item {
+    justify-content: center;
+
+    a {
+      color: white;
+      text-decoration: none;
+      font-family: $font-family-display;
+      font-size: $font-size-x-large;
+      letter-spacing: 0.075em;
+      font-weight: $font-weight-bold;
+    }
+
+    a:hover::after {
+      content: "";
+      display: block;
+      margin: 0 auto;
+      width: 56px;
+      opacity: 50%;
+      margin-top: -10px;
+      border-bottom: 10px solid;
+      border-bottom-color: $grey-500;
+    }
+  }
+}

+ 0 - 49
recipes/src/components/Navbar/index.tsx

@@ -1,49 +0,0 @@
-import React from 'react';
-import { BrowserRouter as Router, Route, Link } from "react-router-dom";
-
-import './styles.scss';
-
-type LinkItem = {
-  title: string,
-  path: string,
-  active: boolean,
-}
-
-
-type NavbarProps = { 
-  items: LinkItem[]
-};
-
-function NavbarLink(props: {link: LinkItem}) {
-  return (
-    <li
-      key={props.link.title}
-      className={`Navbar__items__links ${props.link.active ? 'Navbar__items__links--active' : ''}`}
-    >
-      <Link to={props.link.path}>{props.link.title}</Link>
-    </li>
-  )
-}
-
-function Navbar(props: NavbarProps) {
-  return (
-    <nav
-      className='Navbar'
-    >
-      <ul className='Navbar__items'>
-        <li
-          key='brand'
-          className='Navbar__brand'
-        >
-          <h1>Cookbook</h1>
-        </li>
-        {
-          props.items.map((item: any) => <NavbarLink link={item}/>)
-        }
-          
-      </ul>
-    </nav>
-  );
-}
-
-export default Navbar;

+ 0 - 19
recipes/src/components/Navbar/navbar.stories.js

@@ -1,19 +0,0 @@
-import React from 'react';
-import { BrowserRouter as Router } from 'react-router-dom';
-import { storiesOf } from '@storybook/react';
-
-import Navbar from './index';
-
-const navbarItems = [
-  { title: 'home', path: '/' },
-  { title: 'recipes', path: '/recipes' },
-  { title: 'planner', path: '/planner' },
-  { title: 'shoplist', path: '/shoplist' },
-];
-
-storiesOf('Navbar', module)
-  .add('default', () => (
-    <Router>
-      <Navbar items={navbarItems}></Navbar>
-    </Router>
-  ))

+ 0 - 47
recipes/src/components/Navbar/styles.scss

@@ -1,47 +0,0 @@
-@import './../../styles/_index.scss';
-
-.Navbar {
-  width: 264px;
-  background-color: #BDBDBD;
-  position: fixed;
-  top: 0;
-  bottom: 0;
-  height: 100%;
-  padding-top: $spacing-xx-large;
-  text-align: center;
-  box-shadow: $box-shadow;
-  &__brand {
-    color: white;
-    padding-bottom: $spacing-large;
-  }
-}
-
-.Navbar__items__links {
-  text-transform: uppercase;
-  padding: $spacing-small 0;
-  font-family: $font-family-display;
-  font-weight: $font-weight-bold;
-  font-size: $font-size-x-large;
-  line-height: 40px;
-  height: 30px;
-
-  a {
-    color: $white;
-  }
-
-  a:hover {
-    text-decoration: none;
-  
-  }
-
-  a:hover::after {
-    content: "";
-    display: block;
-    margin: 0 auto;
-    width: 56px;
-    opacity: 50%;
-    margin-top: -20px;
-    border-bottom: 10px solid;
-    border-bottom-color: $grey-500;
-  }
-}

+ 45 - 0
recipes/src/components/RecipeCard/index.tsx

@@ -0,0 +1,45 @@
+import React, { Component } from 'react';
+
+import './styles.scss';
+
+type Ingredient = {
+  name: string,
+  ingredients: {
+    name: string,
+    quantity: number,
+    unit: string,
+    _original: string,
+  }[],
+}
+
+export type Recipe = {
+  _id: string,
+  name: string,
+  author: {
+    name: string,
+  },
+  details: {
+    preparationTime: string,
+    cookingTime: string,
+    servings: number,
+  },
+  ingredients: Ingredient[],
+  instructions: string[],
+  summary: string,
+  tags: string[],
+}
+
+type RecipeCardProps = {
+  recipe: Recipe,
+  actions?: boolean,
+}
+
+export class RecipeCard extends Component<RecipeCardProps, {}> {
+  render() {
+    return (
+      <h2>recipeCard</h2>
+    );
+  }
+}
+
+export default RecipeCard;

+ 7 - 0
recipes/src/components/RecipeCard/styles.scss

@@ -0,0 +1,7 @@
+@import './../../styles/index.scss';
+
+.RecipeCard {
+  background-color: white;
+  height: 144px;
+  padding: $spacing-small;
+}

+ 0 - 19
recipes/src/components/button.stories.js

@@ -1,19 +0,0 @@
-import React from 'react';
-
-import { storiesOf } from '@storybook/react';
-import { action } from '@storybook/addon-actions';
-import { linkTo } from '@storybook/addon-links';
-
-import { Button, Welcome } from '@storybook/react/demo';
-
-storiesOf('Welcome', module).add('to Storybook', () => <Welcome showApp={linkTo('Button')} />);
-
-storiesOf('Button', module)
-  .add('with text', () => <Button onClick={action('clicked')}>Hello Button</Button>)
-  .add('with some emoji', () => (
-    <Button onClick={action('clicked')}>
-      <span role="img" aria-label="so cool">
-        😀 😎 👍 💯
-      </span>
-    </Button>
-  ));

+ 0 - 1
recipes/src/index.js

@@ -1,6 +1,5 @@
 import React from 'react';
 import ReactDOM from 'react-dom';
-import './styles/app.scss';
 import App from './App';
 import * as serviceWorker from './serviceWorker';
 

+ 52 - 0
recipes/src/routes/Recipes.tsx

@@ -0,0 +1,52 @@
+import React, { Component } from 'react';
+import { RecipeCard, Recipe } from '../components/RecipeCard';
+import Card from '../components/Card';
+import axios from 'axios';
+
+type RecipeState = {
+  error: null | Error,
+  isLoaded: boolean,
+  recipes: Recipe[],
+}
+
+class Recipes extends Component<{}, RecipeState> {
+  constructor(props: any) {
+    super(props);
+    this.state = {
+      error: null,
+      isLoaded: false,
+      recipes: [],
+    }
+  }
+
+  componentDidMount(){
+    axios.get('https://recipes.davidventura.com.ar/recipes/ingredients/?ingredients=beef,bacon').then(response => {
+      console.log('response', response.data);
+      this.setState({
+        isLoaded: true,
+        recipes: response.data,
+      })
+    }).catch(error => {
+      this.setState({
+        isLoaded: true,
+        error: error,
+        recipes: [],
+      })
+    })
+  }
+
+  render() {
+    return (
+      <div>
+        <Card></Card>
+        {/* {
+          this.state.recipes.map((_recipe) => (
+            <RecipeCard recipe={_recipe} key={_recipe._id}/>
+          ))
+        } */}
+      </div>
+    )
+  }
+}
+
+export default Recipes;

recipes/src/styles/_index.scss → recipes/src/styles/_variables.scss


+ 8 - 1
recipes/src/styles/app.scss

@@ -1,4 +1,5 @@
-@import './_index.scss';
+@import './_variables.scss';
+
 
 body {
   margin: 0;
@@ -8,6 +9,7 @@ body {
   color: $grey-900;
   -webkit-font-smoothing: antialiased;
   -moz-osx-font-smoothing: grayscale;
+  background-color: $grey-100;
 }
 
 ul {
@@ -27,4 +29,9 @@ h1 {
 code {
   font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
     monospace;
+}
+
+#root {
+  display: flex;
+  height: 100vh;
 }

+ 2 - 1
recipes/tsconfig.json

@@ -21,6 +21,7 @@
   },
   "include": [
     "src",
-    ".storybook/button.stories.js"
+    ".storybook/button.stories.js",
+    "src/components/Card/.stories.js"
   ]
 }

+ 2 - 0
recipes/types/@material/react-drawer.d.ts

@@ -0,0 +1,2 @@
+export = index;
+declare const index: any;