first commit
This commit is contained in:
174
src/App.css
Executable file
174
src/App.css
Executable file
@@ -0,0 +1,174 @@
|
||||
html, body, .root {
|
||||
height: 100%;
|
||||
}
|
||||
body {
|
||||
line-height: 1.5;
|
||||
}
|
||||
body, .app {
|
||||
background: white;
|
||||
}
|
||||
|
||||
/* main page */
|
||||
|
||||
.list-books-title {
|
||||
padding: 10px 0;
|
||||
background: #2e7c31;
|
||||
text-align: center;
|
||||
}
|
||||
.list-books-title h1 {
|
||||
font-weight: 400;
|
||||
margin: 0;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.list-books-content {
|
||||
padding: 0 0 80px;
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.bookshelf {
|
||||
padding: 0 10px 20px;
|
||||
}
|
||||
|
||||
@media (min-width: 600px) {
|
||||
.bookshelf {
|
||||
padding: 0 20px 40px;
|
||||
}
|
||||
}
|
||||
|
||||
.bookshelf-title {
|
||||
border-bottom: 1px solid #dedede;
|
||||
}
|
||||
.bookshelf-books {
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.open-search {
|
||||
position: fixed;
|
||||
right: 25px;
|
||||
bottom: 25px;
|
||||
}
|
||||
.open-search a {
|
||||
display: block;
|
||||
width: 50px;
|
||||
height: 50px;
|
||||
border-radius: 50%;
|
||||
background: #2e7d32;
|
||||
background-image: url('./icons/add.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 28px;
|
||||
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
/* search page */
|
||||
|
||||
.search-books-bar {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
z-index: 5;
|
||||
display: flex;
|
||||
box-shadow: 0 10px 20px rgba(0,0,0,0.19), 0 0 6px rgba(0,0,0,0.23);
|
||||
}
|
||||
.search-books-input-wrapper {
|
||||
flex: 1;
|
||||
background: #e9e;
|
||||
}
|
||||
.search-books-bar input {
|
||||
width: 100%;
|
||||
padding: 15px 10px;
|
||||
font-size: 1.25em;
|
||||
border: none;
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.close-search {
|
||||
display: block;
|
||||
top: 20px;
|
||||
left: 15px;
|
||||
width: 50px;
|
||||
height: 53px;
|
||||
background: white;
|
||||
background-image: url('./icons/arrow-back.svg');
|
||||
background-position: center;
|
||||
background-repeat: no-repeat;
|
||||
background-size: 28px;
|
||||
font-size: 0;
|
||||
}
|
||||
|
||||
.search-books-results {
|
||||
padding: 80px 10px 20px;
|
||||
}
|
||||
|
||||
/* books grid */
|
||||
|
||||
.books-grid {
|
||||
list-style-type: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
.books-grid li {
|
||||
padding: 10px 15px;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.book {
|
||||
width: 140px;
|
||||
}
|
||||
.book-title,
|
||||
.book-authors {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
.book-title {
|
||||
margin-top: 10px;
|
||||
}
|
||||
.book-authors {
|
||||
color: #999;
|
||||
}
|
||||
|
||||
.book-top {
|
||||
position: relative;
|
||||
height: 200px;
|
||||
display: flex;
|
||||
align-items: flex-end;
|
||||
}
|
||||
|
||||
.book-shelf-changer {
|
||||
position: absolute;
|
||||
right: 0;
|
||||
bottom: -10px;
|
||||
width: 40px;
|
||||
height: 40px;
|
||||
border-radius: 50%;
|
||||
background: #60ac5d;
|
||||
background-image: url('./icons/arrow-drop-down.svg');
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-size: 20px;
|
||||
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
|
||||
}
|
||||
.book-shelf-changer select {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
opacity: 0;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
/* book cover */
|
||||
|
||||
.book-cover {
|
||||
box-shadow: 0 3px 6px rgba(0,0,0,0.16), 0 3px 6px rgba(0,0,0,0.23);
|
||||
background: #eee;
|
||||
}
|
||||
.book-cover-title {
|
||||
padding: 20px 10px 0;
|
||||
text-align: center;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
206
src/App.js
Executable file
206
src/App.js
Executable file
@@ -0,0 +1,206 @@
|
||||
import React from 'react'
|
||||
// import * as BooksAPI from './BooksAPI'
|
||||
import './App.css'
|
||||
|
||||
class BooksApp extends React.Component {
|
||||
state = {
|
||||
/**
|
||||
* TODO: Instead of using this state variable to keep track of which page
|
||||
* we're on, use the URL in the browser's address bar. This will ensure that
|
||||
* users can use the browser's back and forward buttons to navigate between
|
||||
* pages, as well as provide a good URL they can bookmark and share.
|
||||
*/
|
||||
showSearchPage: false
|
||||
}
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div className="app">
|
||||
{this.state.showSearchPage ? (
|
||||
<div className="search-books">
|
||||
<div className="search-books-bar">
|
||||
<a className="close-search" onClick={() => this.setState({ showSearchPage: false })}>Close</a>
|
||||
<div className="search-books-input-wrapper">
|
||||
{/*
|
||||
NOTES: The search from BooksAPI is limited to a particular set of search terms.
|
||||
You can find these search terms here:
|
||||
https://github.com/udacity/reactnd-project-myreads-starter/blob/master/SEARCH_TERMS.md
|
||||
|
||||
However, remember that the BooksAPI.search method DOES search by title or author. So, don't worry if
|
||||
you don't find a specific author or title. Every search is limited by search terms.
|
||||
*/}
|
||||
<input type="text" placeholder="Search by title or author"/>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div className="search-books-results">
|
||||
<ol className="books-grid"></ol>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="list-books">
|
||||
<div className="list-books-title">
|
||||
<h1>MyReads</h1>
|
||||
</div>
|
||||
<div className="list-books-content">
|
||||
<div>
|
||||
<div className="bookshelf">
|
||||
<h2 className="bookshelf-title">Currently Reading</h2>
|
||||
<div className="bookshelf-books">
|
||||
<ol className="books-grid">
|
||||
<li>
|
||||
<div className="book">
|
||||
<div className="book-top">
|
||||
<div className="book-cover" style={{ width: 128, height: 193, backgroundImage: 'url("http://books.google.com/books/content?id=PGR2AwAAQBAJ&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE73-GnPVEyb7MOCxDzOYF1PTQRuf6nCss9LMNOSWBpxBrz8Pm2_mFtWMMg_Y1dx92HT7cUoQBeSWjs3oEztBVhUeDFQX6-tWlWz1-feexS0mlJPjotcwFqAg6hBYDXuK_bkyHD-y&source=gbs_api")' }}></div>
|
||||
<div className="book-shelf-changer">
|
||||
<select>
|
||||
<option value="none" disabled>Move to...</option>
|
||||
<option value="currentlyReading">Currently Reading</option>
|
||||
<option value="wantToRead">Want to Read</option>
|
||||
<option value="read">Read</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="book-title">To Kill a Mockingbird</div>
|
||||
<div className="book-authors">Harper Lee</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div className="book">
|
||||
<div className="book-top">
|
||||
<div className="book-cover" style={{ width: 128, height: 188, backgroundImage: 'url("http://books.google.com/books/content?id=yDtCuFHXbAYC&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE72RRiTR6U5OUg3IY_LpHTL2NztVWAuZYNFE8dUuC0VlYabeyegLzpAnDPeWxE6RHi0C2ehrR9Gv20LH2dtjpbcUcs8YnH5VCCAH0Y2ICaKOTvrZTCObQbsfp4UbDqQyGISCZfGN&source=gbs_api")' }}></div>
|
||||
<div className="book-shelf-changer">
|
||||
<select>
|
||||
<option value="none" disabled>Move to...</option>
|
||||
<option value="currentlyReading">Currently Reading</option>
|
||||
<option value="wantToRead">Want to Read</option>
|
||||
<option value="read">Read</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="book-title">Enders Game</div>
|
||||
<div className="book-authors">Orson Scott Card</div>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bookshelf">
|
||||
<h2 className="bookshelf-title">Want to Read</h2>
|
||||
<div className="bookshelf-books">
|
||||
<ol className="books-grid">
|
||||
<li>
|
||||
<div className="book">
|
||||
<div className="book-top">
|
||||
<div className="book-cover" style={{ width: 128, height: 193, backgroundImage: 'url("http://books.google.com/books/content?id=uu1mC6zWNTwC&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE73pGHfBNSsJG9Y8kRBpmLUft9O4BfItHioHolWNKOdLavw-SLcXADy3CPAfJ0_qMb18RmCa7Ds1cTdpM3dxAGJs8zfCfm8c6ggBIjzKT7XR5FIB53HHOhnsT7a0Cc-PpneWq9zX&source=gbs_api")' }}></div>
|
||||
<div className="book-shelf-changer">
|
||||
<select>
|
||||
<option value="none" disabled>Move to...</option>
|
||||
<option value="currentlyReading">Currently Reading</option>
|
||||
<option value="wantToRead">Want to Read</option>
|
||||
<option value="read">Read</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="book-title">1776</div>
|
||||
<div className="book-authors">David McCullough</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div className="book">
|
||||
<div className="book-top">
|
||||
<div className="book-cover" style={{ width: 128, height: 192, backgroundImage: 'url("http://books.google.com/books/content?id=wrOQLV6xB-wC&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE72G3gA5A-Ka8XjOZGDFLAoUeMQBqZ9y-LCspZ2dzJTugcOcJ4C7FP0tDA8s1h9f480ISXuvYhA_ZpdvRArUL-mZyD4WW7CHyEqHYq9D3kGnrZCNiqxSRhry8TiFDCMWP61ujflB&source=gbs_api")' }}></div>
|
||||
<div className="book-shelf-changer">
|
||||
<select>
|
||||
<option value="none" disabled>Move to...</option>
|
||||
<option value="currentlyReading">Currently Reading</option>
|
||||
<option value="wantToRead">Want to Read</option>
|
||||
<option value="read">Read</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="book-title">Harry Potter and the Sorcerers Stone</div>
|
||||
<div className="book-authors">J.K. Rowling</div>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
<div className="bookshelf">
|
||||
<h2 className="bookshelf-title">Read</h2>
|
||||
<div className="bookshelf-books">
|
||||
<ol className="books-grid">
|
||||
<li>
|
||||
<div className="book">
|
||||
<div className="book-top">
|
||||
<div className="book-cover" style={{ width: 128, height: 192, backgroundImage: 'url("http://books.google.com/books/content?id=pD6arNyKyi8C&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE70Rw0CCwNZh0SsYpQTkMbvz23npqWeUoJvVbi_gXla2m2ie_ReMWPl0xoU8Quy9fk0Zhb3szmwe8cTe4k7DAbfQ45FEzr9T7Lk0XhVpEPBvwUAztOBJ6Y0QPZylo4VbB7K5iRSk&source=gbs_api")' }}></div>
|
||||
<div className="book-shelf-changer">
|
||||
<select>
|
||||
<option value="none" disabled>Move to...</option>
|
||||
<option value="currentlyReading">Currently Reading</option>
|
||||
<option value="wantToRead">Want to Read</option>
|
||||
<option value="read">Read</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="book-title">The Hobbit</div>
|
||||
<div className="book-authors">J.R.R. Tolkien</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div className="book">
|
||||
<div className="book-top">
|
||||
<div className="book-cover" style={{ width: 128, height: 174, backgroundImage: 'url("http://books.google.com/books/content?id=1q_xAwAAQBAJ&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE712CA0cBYP8VKbEcIVEuFJRdX1k30rjLM29Y-dw_qU1urEZ2cQ42La3Jkw6KmzMmXIoLTr50SWTpw6VOGq1leINsnTdLc_S5a5sn9Hao2t5YT7Ax1RqtQDiPNHIyXP46Rrw3aL8&source=gbs_api")' }}></div>
|
||||
<div className="book-shelf-changer">
|
||||
<select>
|
||||
<option value="none" disabled>Move to...</option>
|
||||
<option value="currentlyReading">Currently Reading</option>
|
||||
<option value="wantToRead">Want to Read</option>
|
||||
<option value="read">Read</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="book-title">Oh, the Places Youll Go!</div>
|
||||
<div className="book-authors">Seuss</div>
|
||||
</div>
|
||||
</li>
|
||||
<li>
|
||||
<div className="book">
|
||||
<div className="book-top">
|
||||
<div className="book-cover" style={{ width: 128, height: 192, backgroundImage: 'url("http://books.google.com/books/content?id=32haAAAAMAAJ&printsec=frontcover&img=1&zoom=1&imgtk=AFLRE72yckZ5f5bDFVIf7BGPbjA0KYYtlQ__nWB-hI_YZmZ-fScYwFy4O_fWOcPwf-pgv3pPQNJP_sT5J_xOUciD8WaKmevh1rUR-1jk7g1aCD_KeJaOpjVu0cm_11BBIUXdxbFkVMdi&source=gbs_api")' }}></div>
|
||||
<div className="book-shelf-changer">
|
||||
<select>
|
||||
<option value="none" disabled>Move to...</option>
|
||||
<option value="currentlyReading">Currently Reading</option>
|
||||
<option value="wantToRead">Want to Read</option>
|
||||
<option value="read">Read</option>
|
||||
<option value="none">None</option>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
<div className="book-title">The Adventures of Tom Sawyer</div>
|
||||
<div className="book-authors">Mark Twain</div>
|
||||
</div>
|
||||
</li>
|
||||
</ol>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="open-search">
|
||||
<a onClick={() => this.setState({ showSearchPage: true })}>Add a book</a>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
export default BooksApp
|
||||
16
src/App.test.js
Executable file
16
src/App.test.js
Executable file
@@ -0,0 +1,16 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import App from './App'
|
||||
|
||||
/**
|
||||
This course is not designed to teach Test Driven Development.
|
||||
Feel free to use this file to test your application, but it
|
||||
is not required.
|
||||
**/
|
||||
|
||||
it('renders without crashing', () => {
|
||||
const div = document.createElement('div')
|
||||
ReactDOM.render(<App />, div)
|
||||
})
|
||||
|
||||
|
||||
44
src/BooksAPI.js
Executable file
44
src/BooksAPI.js
Executable file
@@ -0,0 +1,44 @@
|
||||
|
||||
const api = "https://reactnd-books-api.udacity.com"
|
||||
|
||||
|
||||
// Generate a unique token for storing your bookshelf data on the backend server.
|
||||
let token = localStorage.token
|
||||
if (!token)
|
||||
token = localStorage.token = Math.random().toString(36).substr(-8)
|
||||
|
||||
const headers = {
|
||||
'Accept': 'application/json',
|
||||
'Authorization': token
|
||||
}
|
||||
|
||||
export const get = (bookId) =>
|
||||
fetch(`${api}/books/${bookId}`, { headers })
|
||||
.then(res => res.json())
|
||||
.then(data => data.book)
|
||||
|
||||
export const getAll = () =>
|
||||
fetch(`${api}/books`, { headers })
|
||||
.then(res => res.json())
|
||||
.then(data => data.books)
|
||||
|
||||
export const update = (book, shelf) =>
|
||||
fetch(`${api}/books/${book.id}`, {
|
||||
method: 'PUT',
|
||||
headers: {
|
||||
...headers,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ shelf })
|
||||
}).then(res => res.json())
|
||||
|
||||
export const search = (query) =>
|
||||
fetch(`${api}/search`, {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
...headers,
|
||||
'Content-Type': 'application/json'
|
||||
},
|
||||
body: JSON.stringify({ query })
|
||||
}).then(res => res.json())
|
||||
.then(data => data.books)
|
||||
3
src/icons/add.svg
Executable file
3
src/icons/add.svg
Executable file
@@ -0,0 +1,3 @@
|
||||
<svg fill="#ffffff" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 133 B |
3
src/icons/arrow-back.svg
Executable file
3
src/icons/arrow-back.svg
Executable file
@@ -0,0 +1,3 @@
|
||||
<svg fill="#888888" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M20 11H7.83l5.59-5.59L12 4l-8 8 8 8 1.41-1.41L7.83 13H20v-2z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 158 B |
3
src/icons/arrow-drop-down.svg
Executable file
3
src/icons/arrow-drop-down.svg
Executable file
@@ -0,0 +1,3 @@
|
||||
<svg fill="#FFFFFF" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M7 10l5 5 5-5z"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 112 B |
11
src/index.css
Executable file
11
src/index.css
Executable file
@@ -0,0 +1,11 @@
|
||||
html {
|
||||
box-sizing: border-box;
|
||||
}
|
||||
*, *:before, *:after {
|
||||
box-sizing: inherit;
|
||||
}
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
font-family: 'Roboto', sans-serif;
|
||||
}
|
||||
6
src/index.js
Executable file
6
src/index.js
Executable file
@@ -0,0 +1,6 @@
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import App from './App'
|
||||
import './index.css'
|
||||
|
||||
ReactDOM.render(<App />, document.getElementById('root'))
|
||||
Reference in New Issue
Block a user