diff --git a/package.json b/package.json index c6d9612..4150c2d 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,8 @@ "webpack": "^3.3.0", "webpack-dev-middleware": "^1.6.1", "webpack-dev-server": "^2.5.1", - "webpack-hot-middleware": "^2.10.0" + "webpack-hot-middleware": "^2.10.0", + "font-awesome": "^4.7.0" }, "devDependencies": { "babel-eslint": "^7.2.3", @@ -42,6 +43,7 @@ "eslint-plugin-import": "^2.7.0", "eslint-plugin-jsx-a11y": "^6.0.2", "eslint-plugin-react": "^7.1.0", + "file-loader": "^0.11.2", "node-sass": "^4.5.3", "react-hot-loader": "^1.3.0", "react-render": "^1.1.0", diff --git a/src/app/app.jsx b/src/app/app.jsx index b1474ec..188676c 100644 --- a/src/app/app.jsx +++ b/src/app/app.jsx @@ -1,16 +1,33 @@ -import React from 'react'; - import './app.scss'; -import { Column, Row, Title, Button } from '../components'; -const onAddClick = (event) => { -}; +import React, { Component } from 'react'; + +import { setup } from '../client/setup.js'; +import { Main } from '../ui/Main.jsx'; + +var app = null; + +export const getApp = () => { + return app; +} -const App = () => ( - - Contact Book - -); - -Button.propTypes = { - children: PropTypes.string, - label: PropTypes.string, - onClick: PropTypes.func.isRequired -}; - -Button.defaultProps = { - label: null, - children: null -}; - -export default Button; diff --git a/src/components/controls/icon-button.jsx b/src/components/controls/icon-button.jsx deleted file mode 100644 index 72692e6..0000000 --- a/src/components/controls/icon-button.jsx +++ /dev/null @@ -1,17 +0,0 @@ -import React, { PropTypes } from 'react'; -import Icon from 'react-evil-icons'; - -const IconButton = ({ icon, onClick }) => ( - -); - -IconButton.propTypes = { - icon: PropTypes.oneOf([ - 'plus', - 'heart', - 'clock' - ]).isRequired, - onClick: PropTypes.func.isRequired -}; - -export default IconButton; diff --git a/src/components/controls/index.js b/src/components/controls/index.js deleted file mode 100644 index 36d4bc7..0000000 --- a/src/components/controls/index.js +++ /dev/null @@ -1,4 +0,0 @@ -import IconButton from './icon-button'; -import Button from './button'; - -export { IconButton, Button }; diff --git a/src/components/grid/box.jsx b/src/components/grid/box.jsx deleted file mode 100644 index 27a1fa7..0000000 --- a/src/components/grid/box.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import React, { PropTypes } from 'react'; - -const Box = ({ children, className }) => ( -
{children}
-); - -Box.propTypes = { - children: PropTypes.oneOfType([ - PropTypes.element, - PropTypes.arrayOf(PropTypes.element) - ]), - className: PropTypes.string -}; - -Box.defaultProps = { - className: '', - children: null -}; - -export default Box; diff --git a/src/components/grid/column.jsx b/src/components/grid/column.jsx deleted file mode 100644 index 294ec56..0000000 --- a/src/components/grid/column.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import React, { PropTypes } from 'react'; - -const Column = ({ children, className }) => ( -
{children}
-); - -Column.propTypes = { - children: PropTypes.oneOfType([ - PropTypes.element, - PropTypes.arrayOf(PropTypes.element) - ]), - className: PropTypes.string -}; - -Column.defaultProps = { - className: '', - children: null -}; - -export default Column; diff --git a/src/components/grid/grid.scss b/src/components/grid/grid.scss deleted file mode 100644 index 1c238ae..0000000 --- a/src/components/grid/grid.scss +++ /dev/null @@ -1,15 +0,0 @@ -.grid { - &.box { - display: flex; - } - - &.vbox { - display: flex; - flex-direction: column; - } - - &.hbox { - display: flex; - flex-direction: row; - } -} diff --git a/src/components/grid/index.js b/src/components/grid/index.js deleted file mode 100644 index 1036bca..0000000 --- a/src/components/grid/index.js +++ /dev/null @@ -1,7 +0,0 @@ -import './grid.scss'; - -import Box from './box'; -import Column from './column'; -import Row from './row'; - -export { Box, Column, Row }; diff --git a/src/components/grid/row.jsx b/src/components/grid/row.jsx deleted file mode 100644 index 36a4f2d..0000000 --- a/src/components/grid/row.jsx +++ /dev/null @@ -1,20 +0,0 @@ -import React, { PropTypes } from 'react'; - -const Row = ({ children, className }) => ( -
{children}
-); - -Row.propTypes = { - children: PropTypes.oneOfType([ - PropTypes.element, - PropTypes.arrayOf(PropTypes.element) - ]), - className: PropTypes.string -}; - -Row.defaultProps = { - className: '', - children: null -}; - -export default Row; diff --git a/src/components/index.js b/src/components/index.js deleted file mode 100644 index ddadfeb..0000000 --- a/src/components/index.js +++ /dev/null @@ -1,5 +0,0 @@ -import './resets.scss'; - -export { IconButton, Button } from './controls'; -export { Box, Column, Row } from './grid'; -export { Title, Subtitle, Label, Description } from './typography'; diff --git a/src/components/resets.scss b/src/components/resets.scss deleted file mode 100644 index a4a7089..0000000 --- a/src/components/resets.scss +++ /dev/null @@ -1,33 +0,0 @@ -html, -body { - font-family: "Aktiv Grotesk", "Arial", sans-serif; -} - -body, -html, -div, -article, -nav, -footer, -aside, -h1, -h2, -h3, -h4, -h5, -h6, -p, -span { - margin: 0; - border: 0; - padding: 0; - font-size: 100%; -} - -div, -article, -nav, -footer, -aside { - display: flex; -} diff --git a/src/components/typography/description.jsx b/src/components/typography/description.jsx deleted file mode 100644 index 1c1c394..0000000 --- a/src/components/typography/description.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import React, { PropTypes } from 'react'; - -const Description = ({ children, className }) => ( - {children} -); - -Description.propTypes = { - children: PropTypes.string.isRequired, - className: PropTypes.string -}; - -Description.defaultProps = { - className: '' -}; - -export default Description; diff --git a/src/components/typography/index.js b/src/components/typography/index.js deleted file mode 100644 index 52a45b4..0000000 --- a/src/components/typography/index.js +++ /dev/null @@ -1,8 +0,0 @@ -import './typography.scss'; - -import Title from './title'; -import Subtitle from './subtitle'; -import Label from './label'; -import Description from './description'; - -export { Title, Subtitle, Label, Description }; diff --git a/src/components/typography/label.jsx b/src/components/typography/label.jsx deleted file mode 100644 index c9b2a25..0000000 --- a/src/components/typography/label.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import React, { PropTypes } from 'react'; - -const Label = ({ children, className }) => ( - -); - -Label.propTypes = { - children: PropTypes.string.isRequired, - className: PropTypes.string -}; - -Label.defaultProps = { - className: '' -}; - -export default Label; diff --git a/src/components/typography/subtitle.jsx b/src/components/typography/subtitle.jsx deleted file mode 100644 index 0c95ec8..0000000 --- a/src/components/typography/subtitle.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import React, { PropTypes } from 'react'; - -const Subtitle = ({ children, className }) => ( -

{children}

-); - -Subtitle.propTypes = { - children: PropTypes.string.isRequired, - className: PropTypes.string -}; - -Subtitle.defaultProps = { - className: '' -}; - -export default Subtitle; diff --git a/src/components/typography/title.jsx b/src/components/typography/title.jsx deleted file mode 100644 index 2019925..0000000 --- a/src/components/typography/title.jsx +++ /dev/null @@ -1,16 +0,0 @@ -import React, { PropTypes } from 'react'; - -const Title = ({ children, className }) => ( -

{children}

-); - -Title.propTypes = { - children: PropTypes.string.isRequired, - className: PropTypes.string -}; - -Title.defaultProps = { - className: '' -}; - -export default Title; diff --git a/src/components/typography/typography.scss b/src/components/typography/typography.scss deleted file mode 100644 index f23fe48..0000000 --- a/src/components/typography/typography.scss +++ /dev/null @@ -1,17 +0,0 @@ -.typography { - &.title { - font-size: 16pt; - } - - &.subtitle { - font-size: 14pt; - } - - &.label { - font-size: 9pt; - } - - &.description { - font-size: 9pt; - } -} diff --git a/src/index.html b/src/index.html index 6de1522..1a542ff 100644 --- a/src/index.html +++ b/src/index.html @@ -3,9 +3,10 @@ Web App - + -
This must be World Wide Web!
+
+
diff --git a/src/index.jsx b/src/index.jsx index 3930082..6480884 100644 --- a/src/index.jsx +++ b/src/index.jsx @@ -1,9 +1,11 @@ import React from 'react'; import { render } from 'react-dom'; -import App from './app/app'; +import { App } from './app/app'; + +import 'font-awesome/scss/font-awesome.scss'; try { - const appContainer = document.getElementById('app'); + const appContainer = document.getElementById('render-target'); render(, appContainer); } catch (e) { /* eslint-disable no-console */ diff --git a/src/ui/Contact/ContactForm.jsx b/src/ui/Contact/ContactForm.jsx new file mode 100644 index 0000000..9b1a3d2 --- /dev/null +++ b/src/ui/Contact/ContactForm.jsx @@ -0,0 +1,42 @@ +import './ContactForm.scss'; +import React, { Component } from 'react'; + +export class ContactForm extends Component { + onSubmit(){ + var newContact = { + firstName: this.refs["firstName"].value, + lastName: this.refs["lastName"].value, + email: this.refs["email"].value, + phone: this.refs["phone"].value + }; + this.props.submitFunc(newContact); + } + + render() { + return ( +
+
+ + + + + + + + + + + + +
+ +
+ ); + } +} + + diff --git a/src/ui/Contact/ContactForm.scss b/src/ui/Contact/ContactForm.scss new file mode 100644 index 0000000..7c962b3 --- /dev/null +++ b/src/ui/Contact/ContactForm.scss @@ -0,0 +1,30 @@ +.contact-form { + + form { + input[type=text] { + width: 100%; + padding: 12px 20px; + margin: 8px 0; + display: block; + border: 1px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + } + label { + color: #106054; + font-weight: bold; + } + } + button.submit { + font-weight: bold; + width: 100%; + background-color: #18917E; + color: white; + padding: 14px 0; + margin-top: 30px; + border: none; + border-radius: 4px; + } + +} + diff --git a/src/ui/Content/ContactList/ContactList.jsx b/src/ui/Content/ContactList/ContactList.jsx new file mode 100644 index 0000000..41be34b --- /dev/null +++ b/src/ui/Content/ContactList/ContactList.jsx @@ -0,0 +1,42 @@ +import './ContactList.scss'; +import React, { Component } from 'react'; + +import { ContactListItem } from './ContactListItem/ContactListItem.jsx'; + +export class ContactList extends Component { + getListItems() { + return getState()['contactList']; + } + + render() { + return ( +
+

+ Contact List +

+
+ + + + + + + + + + + + { this.getListItems().map((contact, index) => ( + + )) } + + +
Full NameEmailPhone
+
+
+ ); + } +} + + diff --git a/src/ui/Content/ContactList/ContactList.scss b/src/ui/Content/ContactList/ContactList.scss new file mode 100644 index 0000000..92f2660 --- /dev/null +++ b/src/ui/Content/ContactList/ContactList.scss @@ -0,0 +1,22 @@ +.contact-list { + table { + border-collapse: collapse; + width: 100%; + th, td { + text-align: left; + padding: 8px; + } + + tr:nth-child(even){background-color: #f2f2f2} + tr:nth-child(odd){background-color: hsla(0,0%,80%,1)} + + + + th { + background-color: hsla(171,72%,22%,1); + color: white; + } + + } +} + diff --git a/src/ui/Content/ContactList/ContactListItem/ContactListItem.jsx b/src/ui/Content/ContactList/ContactListItem/ContactListItem.jsx new file mode 100644 index 0000000..87f7f99 --- /dev/null +++ b/src/ui/Content/ContactList/ContactListItem/ContactListItem.jsx @@ -0,0 +1,39 @@ +import './ContactListItem.scss'; +import React, { Component } from 'react'; + +import { removeContact, toggleContactFavorite } from '../../../../client/contacts/manage-contacts.js'; +import { goToEditContact } from '../../../../client/router/change-page.js'; + +export class ContactListItem extends Component { + removeItem() { + removeContact(this.props.index); + } + + render() { + return ( + + + { this.props.noFavoriteIcon == true ? + null + : + ( this.props.isFavorite ? + + : + + ) + } + { this.props.fullName } + + { this.props.email } + { this.props.phone } + { goToEditContact(this.props.index); console.log('Editing: ' + this.props.index); } }> + Edit + + { this.removeItem(); } }> + Remove + + + ); + } +} + diff --git a/src/ui/Content/ContactList/ContactListItem/ContactListItem.scss b/src/ui/Content/ContactList/ContactListItem/ContactListItem.scss new file mode 100644 index 0000000..2fec75a --- /dev/null +++ b/src/ui/Content/ContactList/ContactListItem/ContactListItem.scss @@ -0,0 +1,9 @@ +.contact-list-item { + .favorite-icon { + color: #106054; + font-size: 20px; + margin-right: 4px; + cursor: pointer; + } +} + diff --git a/src/ui/Content/Content.jsx b/src/ui/Content/Content.jsx new file mode 100644 index 0000000..5bdc345 --- /dev/null +++ b/src/ui/Content/Content.jsx @@ -0,0 +1,36 @@ +import './Content.scss'; +import React, { Component } from 'react'; + +import { ContactList } from './ContactList/ContactList.jsx'; +import { EditContact } from './EditContact/EditContact.jsx'; +import { NewContact } from './NewContact/NewContact.jsx'; +import { FavoriteList } from './FavoriteList/FavoriteList.jsx'; + +import { getContactFromIndex } from '../../client/contacts/manage-contacts.js'; + +export class Content extends Component { + + getMainContent(){ + switch (getCurrentPage()) { + case "home": + return ; + case "contact-list": + return ; + case "add-new-contact": + return ; + case "edit-contact": + return ; + case "favorite-list": + return ; + } + } + render() { + return ( +
+ + { this.getMainContent() } +
+ ); + } +} + diff --git a/src/ui/Content/Content.scss b/src/ui/Content/Content.scss new file mode 100644 index 0000000..6ffb937 --- /dev/null +++ b/src/ui/Content/Content.scss @@ -0,0 +1,12 @@ +.content { + background-color: hsla(0,0%,90%,1); + + .main-page { + h1 { + text-align: center; + } + .body { + margin: 0 calc(7% - 10px); + } + } +} diff --git a/src/ui/Content/EditContact/EditContact.jsx b/src/ui/Content/EditContact/EditContact.jsx new file mode 100644 index 0000000..4fe367b --- /dev/null +++ b/src/ui/Content/EditContact/EditContact.jsx @@ -0,0 +1,30 @@ +import './EditContact.scss'; +import React, { Component } from 'react'; + +import { removeContact, getContactFromIndex, editContact } from '../../../client/contacts/manage-contacts.js'; +import { ContactForm } from '../../Contact/ContactForm.jsx'; +import { goToContactList } from '../../../client/router/change-page.js'; + +export class EditContact extends Component { + submitFunc(savedContact) { + editContact(this.props.index, savedContact); + goToContactList(); + } + render() { + return ( +
+

+ { this.props.contact.firstName + ' ' + this.props.contact.lastName } +

+
+ + this.submitFunc(savedContact) } /> +
+
+ ); + } +} + + diff --git a/src/ui/Content/EditContact/EditContact.scss b/src/ui/Content/EditContact/EditContact.scss new file mode 100644 index 0000000..b35a48b --- /dev/null +++ b/src/ui/Content/EditContact/EditContact.scss @@ -0,0 +1,4 @@ +.edit-contact { + +} + diff --git a/src/ui/Content/FavoriteList/FavoriteList.jsx b/src/ui/Content/FavoriteList/FavoriteList.jsx new file mode 100644 index 0000000..09b8c24 --- /dev/null +++ b/src/ui/Content/FavoriteList/FavoriteList.jsx @@ -0,0 +1,44 @@ +import React, { Component } from 'react'; + +import { ContactListItem } from '../ContactList/ContactListItem/ContactListItem.jsx'; + +export class FavoriteList extends Component { + getListItems() { + return getState()['contactList'].map((contact, index) => { + contact.index = index; + return contact; + }).filter((contact) => contact.isFavorite == true); + } + + render() { + return ( +
+

+ My Favorites +

+
+ + + + + + + + + + + + { this.getListItems().map((contact) => ( + + )) } + + +
Full NameEmailPhone
+
+
+ ); + } +} + + diff --git a/src/ui/Content/NewContact/NewContact.jsx b/src/ui/Content/NewContact/NewContact.jsx new file mode 100644 index 0000000..4ac2598 --- /dev/null +++ b/src/ui/Content/NewContact/NewContact.jsx @@ -0,0 +1,32 @@ +import './NewContact.scss'; +import React, { Component } from 'react'; + +import { addNewContact } from '../../../client/contacts/manage-contacts.js'; +import { ContactForm } from '../../Contact/ContactForm.jsx'; +import { goToContactList } from '../../../client/router/change-page.js'; + +export class NewContact extends Component { + submitFunc(savedContact) { + addNewContact(savedContact) + goToContactList(); + console.log('toto'); + } + + render() { + return ( +
+

+ Add New Contact +

+
+ + this.submitFunc(savedContact) } /> + +
+
+ ); + } +} + + diff --git a/src/components/typography/paragraph.jsx b/src/ui/Content/NewContact/NewContact.scss similarity index 100% rename from src/components/typography/paragraph.jsx rename to src/ui/Content/NewContact/NewContact.scss diff --git a/src/ui/Header/Header.jsx b/src/ui/Header/Header.jsx new file mode 100644 index 0000000..05eb8e6 --- /dev/null +++ b/src/ui/Header/Header.jsx @@ -0,0 +1,13 @@ +import './Header.scss'; + +import React, { Component } from 'react'; + +export class Header extends Component { + render() { + return ( +
+
+ ); + } +} + diff --git a/src/ui/Header/Header.scss b/src/ui/Header/Header.scss new file mode 100644 index 0000000..5823c11 --- /dev/null +++ b/src/ui/Header/Header.scss @@ -0,0 +1,3 @@ +.header { + background-color: #18917E; +} diff --git a/src/ui/Main.jsx b/src/ui/Main.jsx new file mode 100644 index 0000000..674f910 --- /dev/null +++ b/src/ui/Main.jsx @@ -0,0 +1,29 @@ +import './Main.scss' + +import React, { Component } from 'react'; + +import { NavBar } from './NavBar/NavBar.jsx'; +import { Header } from './Header/Header.jsx'; +import { Content } from './Content/Content.jsx'; + + +export class Main extends Component { + render() { + return ( +
+
+
+ KKVESPER +
+ +
+ +
+
+ +
+
+ ); + } +} + diff --git a/src/ui/Main.scss b/src/ui/Main.scss new file mode 100644 index 0000000..9fe753a --- /dev/null +++ b/src/ui/Main.scss @@ -0,0 +1,40 @@ +.main { + display: flex; + flex-direction: row; + justify-content: space-between; + + .side-part { + display: flex; + flex-direction: column; + flex-basis: 250px; + + .logo { + flex-basis: 50px; + background-color: #18917E; + color: #FEFCFA; + display: flex; + justify-content: center; + align-items: center; + font-size: 26px; + font-weight: bold; + } + .nav-bar { + flex-grow: 1; + } + + } + + .central-part { + display: flex; + flex-direction: column; + flex-grow: 1; + + .header { + flex-basis: 50px; + } + .content { + flex-grow: 1; + } + } +} + diff --git a/src/ui/NavBar/NavBar.jsx b/src/ui/NavBar/NavBar.jsx new file mode 100644 index 0000000..016871d --- /dev/null +++ b/src/ui/NavBar/NavBar.jsx @@ -0,0 +1,51 @@ +import './NavBar.scss'; + +import React, { Component } from 'react'; + +import { goToContactList, goToAddNewContact, goToFavoriteList } from '../../client/router/change-page.js'; + +export class NavBar extends Component { + + render() { + return ( +
+
+ Navigation +
+
+ +
goToContactList() } > +
+ +
+
+ Contacts +
+
+ + +
goToAddNewContact() } > +
+ +
+
+ New Contact +
+
+ + +
goToFavoriteList() } > +
+ +
+
+ Favorites +
+
+ +
+
+ ); + } +} + diff --git a/src/ui/NavBar/NavBar.scss b/src/ui/NavBar/NavBar.scss new file mode 100644 index 0000000..52426b0 --- /dev/null +++ b/src/ui/NavBar/NavBar.scss @@ -0,0 +1,25 @@ +.nav-bar { + background-color: #1D1D1B; + color: #FEFCFA; + + .description { + color: hsla(171,72%,23%,1); + margin: 22px 22px; + font-size: 24px; + } + .nav-list { + .nav-item { + display: flex; + flex-direction: row; + padding: 12px 0; + + .icon-part { + flex-basis: 66px; + + i { + margin-left: 22px; + } + } + } + } +} diff --git a/tools/webpack/development.js b/tools/webpack/development.js index e08bbbb..e1dd815 100644 --- a/tools/webpack/development.js +++ b/tools/webpack/development.js @@ -31,8 +31,7 @@ const devConfig = { enforce: 'pre', test: /\.js(x|)$/, loaders: [ - 'babel-loader', - 'eslint-loader' + 'babel-loader' ], exclude: /node_modules/ }, @@ -40,6 +39,12 @@ const devConfig = { test: /\.scss$/, loader: 'style-loader!css-loader!sass-loader' }, + { + test: /\.css$/, + loaders: ['style-loader', 'css-loader'] + }, + { test: /\.(png|woff|woff2|eot|ttf|svg)$/, loader: 'file-loader' }, + { test: /\.js(x|)$/, loaders: [