-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
23 changed files
with
1,179 additions
and
59 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
webpack* |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
module.exports = { | ||
extends: "eslint:recommended", | ||
env: { | ||
browser: true, | ||
es6: true | ||
}, | ||
parserOptions: { | ||
ecmaVersion: 6, | ||
sourceType: "module" | ||
}, | ||
parser: "@typescript-eslint/parser", | ||
plugins: ["@typescript-eslint", "lit"], | ||
rules: { | ||
"no-cond-assign": "off", | ||
"no-console": "off", | ||
"no-unused-vars": "off", | ||
"no-debugger": "off", | ||
// todo - fix warn/off rules | ||
"lit/no-duplicate-template-bindings": "error", | ||
"lit/no-template-bind": "error", | ||
"lit/no-template-map": "warn", | ||
"lit/no-useless-template-literals": "error", | ||
"lit/attribute-value-entities": "error", | ||
"lit/no-invalid-html": "error" | ||
} | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,7 +1,17 @@ | ||
# Book Search | ||
# Books Search | ||
|
||
Playground with: | ||
- Custom Elements | ||
Under the hood: | ||
- TypeScript | ||
- Speech Recongition | ||
- [Open Library API](https://openlibrary.org/developers/api) | ||
- [lit-html](https://github.com/polymer/lit-html) | ||
- [lit-elements](https://github.com/polymer/lit-element) | ||
- [Speech Recongition API](https://developer.mozilla.org/en-US/docs/Web/API/SpeechRecognition) | ||
- [Open Library API](https://openlibrary.org/developers/api) | ||
|
||
|
||
Useful resources: | ||
- [Custom Elements v1: Reusable Web Components](https://developers.google.com/web/fundamentals/web-components/customelements) | ||
- [Using the Web Speech API | ||
](https://developer.mozilla.org/en-US/docs/Web/API/Web_Speech_API/Using_the_Web_Speech_API) | ||
- [A curated list of awesome lit-html resources](https://github.com/web-padawan/awesome-lit-html) | ||
- [How lit-html works?](https://github.com/Polymer/lit-html/wiki/How-it-Works) | ||
- [Open Web Component Recommendations (open-wc)](https://open-wc.org/developing/) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
declare global { | ||
var SpeechRecognitionDeclaration: { | ||
new (): SpeechRecognition; | ||
}; | ||
|
||
interface Window { | ||
webkitSpeechRecognition: typeof SpeechRecognitionDeclaration; | ||
} | ||
} | ||
export {}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,25 +1,36 @@ | ||
{ | ||
"name": "book-search", | ||
"name": "books-search", | ||
"version": "0.0.1", | ||
"main": "index.js", | ||
"scripts": { | ||
"start": "webpack-dev-server", | ||
"build": "webpack" | ||
"start": "webpack-dev-server --config webpack.dev.js", | ||
"lint": "eslint", | ||
"build": "webpack --config webpack.prod.js" | ||
}, | ||
"repository": { | ||
"type": "git", | ||
"url": "git+ssh://git@github.com/mrkosima/book-search.git" | ||
"url": "git+ssh://git@github.com/mrkosima/books-search.git" | ||
}, | ||
"author": "Kanstantsin Klimashevich <klimashevich.k@gmail.com>", | ||
"license": "UNLICENSED", | ||
"homepage": "https://github.com/mrkosima/book-search#readme", | ||
"homepage": "https://github.com/mrkosima/books-search#readme", | ||
"devDependencies": { | ||
"@typescript-eslint/eslint-plugin": "^1.8.0", | ||
"@typescript-eslint/parser": "^1.8.0", | ||
"clean-webpack-plugin": "^2.0.2", | ||
"eslint": "^5.16.0", | ||
"eslint-loader": "^2.1.2", | ||
"eslint-plugin-lit": "^1.0.0", | ||
"html-webpack-plugin": "^3.2.0", | ||
"ts-loader": "^6.0.0", | ||
"typescript": "^3.4.5", | ||
"webpack": "^4.31.0", | ||
"webpack-cli": "^3.3.2", | ||
"webpack-dev-server": "^3.3.1" | ||
"webpack-dev-server": "^3.3.1", | ||
"webpack-merge": "^4.2.1" | ||
}, | ||
"dependencies": { | ||
"lit-element": "^2.1.0", | ||
"timeago.js": "^4.0.0-beta.2" | ||
} | ||
} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
<!DOCTYPE html> | ||
<html> | ||
<head> | ||
<meta charset="utf-8" /> | ||
<title><%= htmlWebpackPlugin.options.title %></title> | ||
<meta name="viewport" content="width=device-width, initial-scale=1" /> | ||
</head> | ||
|
||
<body> | ||
<chrome-checker minVersion="73"> | ||
<books-search></books-search> | ||
</chrome-checker> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
interface BookApi { | ||
title: string; | ||
isbn: string[]; | ||
author_name: string[]; | ||
} | ||
|
||
interface BooksApi { | ||
docs: BookApi[]; | ||
numFound: number; | ||
start: number; | ||
} | ||
|
||
type CoverUrils = { [key in "small" | "medium" | "large"]: string }; | ||
|
||
export interface Book { | ||
id: string; | ||
authorName: string; | ||
coverUrls: CoverUrils; | ||
} | ||
|
||
export type Books = Book[]; | ||
|
||
const SEARCH_API = "http://openlibrary.org/search.json"; | ||
|
||
const prepareQueryString = (text: string) => | ||
text | ||
.replace(/[^\w\s]/g, "") | ||
.split(" ") | ||
.filter(word => !!word) | ||
.join("+"); | ||
|
||
const fetchApi = <T>(path: string): Promise<T> => | ||
fetch(path).then(res => res.json()); | ||
|
||
const getCoverUrl = ( | ||
key: "isbn" | "oclc" | "lccn" | "olid" | "id", | ||
value: string, | ||
size: "S" | "M" | "L" | ||
) => `http://covers.openlibrary.org/a/${key}/${value}-${size}.jpg`; | ||
|
||
const getCoverUrls = (isbn: string): CoverUrils => ({ | ||
small: getCoverUrl("isbn", isbn, "S"), | ||
medium: getCoverUrl("isbn", isbn, "M"), | ||
large: getCoverUrl("isbn", isbn, "L") | ||
}); | ||
|
||
const convertBooksApi = (booksApi: BooksApi): Books => { | ||
return booksApi.docs | ||
.filter(book => book.author_name && book.isbn && book.isbn.length > 0) | ||
.map(book => ({ | ||
id: book.isbn[0], | ||
authorName: book.author_name.join(", "), | ||
coverUrls: getCoverUrls(book.isbn[0]) | ||
})); | ||
}; | ||
|
||
export const searchBooks = (text: string): Promise<Books> => | ||
fetchApi<BooksApi>(`${SEARCH_API}?q=${prepareQueryString(text)}`).then( | ||
books => convertBooksApi(books).slice(0, 5) | ||
); | ||
|
||
// http://covers.openlibrary.org/a/$key/$value-$size.jpg | ||
// http://covers.openlibrary.org/a/isbn/$value-$size.jpg |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { LitElement, html, customElement, property, css } from "lit-element"; | ||
import { repeat } from "lit-html/directives/repeat"; | ||
import { Books } from "../api/booksService"; | ||
|
||
@customElement("books-gallery") | ||
export class BooksGallery extends LitElement { | ||
@property({ type: Array }) books: Books = []; | ||
|
||
protected active: boolean = false; | ||
|
||
static get styles() { | ||
return css` | ||
* { | ||
color: red; | ||
} | ||
`; | ||
} | ||
|
||
static get properties() { | ||
return { | ||
active: { attribute: false, type: Boolean } | ||
}; | ||
} | ||
|
||
public connectedCallback() { | ||
super.connectedCallback(); | ||
document.addEventListener("visibilitychange", this.checkActive); | ||
window.addEventListener("focus", this.checkActive); | ||
window.addEventListener("blur", this.checkActive); | ||
this.checkActive(); | ||
} | ||
public disconnectedCallback() { | ||
document.removeEventListener("visibilitychange", this.checkActive); | ||
window.removeEventListener("focus", this.checkActive); | ||
window.removeEventListener("blur", this.checkActive); | ||
super.disconnectedCallback(); | ||
} | ||
|
||
protected render() { | ||
const booksList = html` | ||
<ul> | ||
${repeat( | ||
this.books, | ||
book => book.id, | ||
(book, i) => html` | ||
<li>${book.authorName}</li> | ||
` | ||
)} | ||
<ul></ul> | ||
</ul> | ||
`; | ||
return html` | ||
<h3>Books Gallery</h3> | ||
${booksList} | ||
<h4>Active: ${this.active.toString()}</h4> | ||
`; | ||
} | ||
|
||
private checkActive = () => { | ||
this.active = !document.hidden; // Todo - uncomment && document.hasFocus() | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { customElement, LitElement, css, html } from "lit-element"; | ||
import { searchBooks, Books } from "../api/booksService"; | ||
|
||
import "./voice-input"; | ||
import "./books-gallery"; | ||
import "./custom-loader"; | ||
import "./time-ago"; | ||
|
||
@customElement("books-search") | ||
export class BooksSearch extends LitElement { | ||
private books: Books = []; | ||
|
||
private searchText: string = ""; | ||
private loading: boolean = false; | ||
private updateTime: number; | ||
|
||
static get styles() { | ||
return css` | ||
* { | ||
color: green; | ||
} | ||
`; | ||
} | ||
|
||
static get properties() { | ||
return { | ||
books: { attribute: false, type: Array }, | ||
searchText: { attribute: false, type: String }, | ||
loading: { attribute: false, type: Boolean, reflect: true }, | ||
updateTime: { attribute: false, type: Number } | ||
}; | ||
} | ||
|
||
protected render() { | ||
const content = this.loading | ||
? html` | ||
<custom-loader></custom-loader> | ||
` | ||
: html` | ||
<books-gallery .books=${this.books}></books-gallery> | ||
`; | ||
|
||
return html` | ||
<h1>Hello</h1> | ||
<voice-input | ||
placeholder="Search" | ||
language="en" | ||
@valueChanged=${this.onSearchChanged} | ||
></voice-input> | ||
<time-ago .time=${this.updateTime}></time-ago> | ||
${content} | ||
`; | ||
} | ||
|
||
private updateSearchText = (value: string) => { | ||
if (this.searchText !== value) { | ||
this.searchText = value; | ||
this.fetchData(this.searchText); | ||
} | ||
}; | ||
|
||
private onSearchChanged = (event: CustomEvent) => { | ||
this.updateSearchText(event.detail); | ||
}; | ||
|
||
private fetchData = (searchText: string) => { | ||
this.loading = true; | ||
searchBooks(searchText).then(this.handleBooksLoaded, this.handleError); | ||
}; | ||
|
||
private handleBooksLoaded = (books: Books) => { | ||
this.loading = false; | ||
this.books = books; | ||
this.updateTime = Date.now(); | ||
}; | ||
|
||
private handleError = (error: any) => { | ||
console.warn(error); | ||
this.loading = false; | ||
this.updateTime = null; | ||
}; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import { | ||
LitElement, | ||
html, | ||
customElement, | ||
property, | ||
TemplateResult | ||
} from "lit-element"; | ||
|
||
@customElement("chrome-checker") | ||
export class ChromeChecker extends LitElement { | ||
@property({ type: String }) minVersion: string; | ||
|
||
render() { | ||
if (!this.supported()) { | ||
let message: TemplateResult; | ||
if (this.isChrome() && this.minVersion) { | ||
message = html` | ||
<p> | ||
Please upgrade your Google Chrome browser to version | ||
${this.minVersion} or higher. | ||
</p> | ||
`; | ||
} else { | ||
message = html` | ||
<p> | ||
To enter the website please use | ||
<a href="https://www.google.com/chrome/">Google Chrome</a>. | ||
</p> | ||
`; | ||
} | ||
|
||
return html` | ||
<h2> | ||
Your browser is not supported | ||
</h2> | ||
${message} | ||
`; | ||
} | ||
return html` | ||
<slot></slot> | ||
`; | ||
} | ||
|
||
private isChrome = () => | ||
/Chrome/.test(navigator.userAgent) && /Google Inc/.test(navigator.vendor); | ||
|
||
private getChromeVersion = (): number => { | ||
const match = /Chrome\/(\d+)/g.exec(navigator.userAgent); | ||
if (match.length > 1) { | ||
return +match[1]; | ||
} | ||
return -1; | ||
}; | ||
|
||
private supported = () => { | ||
const chrome = this.isChrome(); | ||
if (chrome && !isNaN(+this.minVersion)) { | ||
return +this.minVersion <= this.getChromeVersion(); | ||
} | ||
return chrome; | ||
}; | ||
} |
Oops, something went wrong.