diff --git a/components/ParshaPicker.js b/components/ParshaPicker.js
index f61e899c..49516b18 100644
--- a/components/ParshaPicker.js
+++ b/components/ParshaPicker.js
@@ -1,4 +1,5 @@
import parshiyot from '../build/parshiyot.json'
+import fuzzy from '../src/fuzzy'
const Parsha = ({ ref, he }) => `
`
`
+/*
+
+ שלח
+ Shelach
+
+
+ בשלח
+ Beshalach
+
+
+ וישלח
+ Vayishlach
+
+*/
+
+/*
+
+ No results
+
+*/
+const Search = () => `
+
+`
+
+const decorateString = ({ string, atIndexes, withDecoration }) => {
+ let indexesIndex = 0
+ return string
+ .split('')
+ .map((char, i) => {
+ if (atIndexes[indexesIndex] !== i) return char
+
+ ++indexesIndex
+ return withDecoration(char)
+ }, '')
+ .join('')
+}
+
+const SearchResult = ({ string, indexes }) => `
+
+ ${decorateString({
+ string,
+ atIndexes: indexes,
+ withDecoration: (c) => (`${c}`)
+ })}
+
+
+`
+
const ParshaPicker = () => `
-
-
- ⚲
-
+ ${Search()}
${parshiyot
.reduce((books, parsha) => {
@@ -40,4 +93,39 @@ const ParshaPicker = () => `
`
+const searchResults = (query) => fuzzy(parshiyot.map(parsha => parsha.en), query)
+
+const htmlToElement = (html) => {
+ const template = document.createElement('template')
+ html = html.trim() // Never return a text node of whitespace as the result
+ template.innerHTML = html
+ return template.content.firstChild
+}
+
+const top = (n) => (_, i) => i < n
+
+const search = ({ jumper, query }) => {
+ const searchResultsElement = jumper.querySelector('.search-results')
+
+ if (query) {
+ searchResultsElement.classList.remove('u-hidden')
+ jumper.querySelector('.parsha-books').classList.add('u-hidden')
+
+ searchResultsElement.innerHTML = ''
+
+ searchResults(query)
+ .filter(top(5))
+ .map(SearchResult)
+ .map(htmlToElement)
+ .forEach(result => {
+ searchResultsElement.appendChild(result)
+ })
+ } else {
+ searchResultsElement.classList.add('u-hidden')
+ jumper.querySelector('.parsha-books').classList.remove('u-hidden')
+ }
+}
+
+export { search }
+
export default ParshaPicker
diff --git a/css/master.css b/css/master.css
index 46a544db..8d29c137 100644
--- a/css/master.css
+++ b/css/master.css
@@ -15,10 +15,13 @@
* {
box-sizing: border-box;
+ margin: 0;
+ padding: 0;
}
body {
height: 100vh;
+ font-family: sans-serif;
}
ol {
diff --git a/css/parsha-picker.css b/css/parsha-picker.css
index bc02bebe..af33e42d 100644
--- a/css/parsha-picker.css
+++ b/css/parsha-picker.css
@@ -26,31 +26,65 @@
padding: 2em 1em;
}
-.parsha-search {
- position: relative;
- font-family: sans-serif;
- border-bottom: 2px solid hsla(0, 0%, 0%, 0.25);
+.search {
+ direction: ltr;
}
-.parsha-search-input {
- border: none;
- direction: ltr;
- padding: 0.1em 2em 0.1em 0.5em;
- width: 30ch;
+.search {
+ background-color: hsla(0, 0%, 0%, 0.05);
+ display: inline-block;
+ border-radius: 4px;
color: hsla(0, 0%, 0%, 0.7);
+ border: 1px solid hsla(0, 0%, 0%, 0);
+ width: 30ch;
}
-.parsha-search-input:focus {
- outline: none;
- border-color: hsla(0, 0%, 0%, 0.5);
+.search:focus-within {
+ border: 1px solid hsla(0, 0%, 0%, 0.1);
}
-.parsha-search-icon {
- position: absolute;
- right: 10px;
+.search-bar {
+ display: flex;
+ padding: 0.5em 1em;
+}
+
+.search-bar > *:not(:first-child) {
+ margin-left: 1em;
+}
+
+.search-icon {
transform: rotate(-45deg);
- font-size: 1.25em;
- color: hsla(0, 0%, 0%, 0.7);
+ display: block;
+ font-size: 1.5em;
+}
+
+.search-input {
+ border: none;
+ background-color: transparent;
+ outline: none;
+ color: inherit;
+}
+
+.search-results {
+ border-top: 1px solid hsla(0, 0%, 0%, 0.2);
+}
+
+.search-result {
+ list-style: none;
+ padding: 1em 1em;
+ cursor: pointer;
+}
+
+.search-result:hover {
+ background-color: hsla(0, 0%, 0%, 0.05);
+}
+
+.search-result:not(:last-child) {
+ border-bottom: 1px solid hsla(0, 0%, 0%, 0.1);
+}
+
+.search-result-tag:not(:last-child) {
+ margin-bottom: 1em;
}
.parsha-books {
diff --git a/cypress/integration/jumper.cypress.test.js b/cypress/integration/jumper.cypress.test.js
index 979fe24d..eb4af772 100644
--- a/cypress/integration/jumper.cypress.test.js
+++ b/cypress/integration/jumper.cypress.test.js
@@ -76,13 +76,19 @@ describe('app', () => {
cy.contains('וירא')
})
- it.only('filters parshiyot', () => {
+ it('filters parshiyot', () => {
cy.get('body').type('/')
- cy
- .get('[placeholder*="search" i]')
+ cy.contains(/vayishlach/i).should('not.be.visible') // shouldn't start by showing search results
+
+ cy.focused()
+ .should('match', '[placeholder*="search" i]')
.type('shlch') // vayishlach, b'shalach, sh'lach
- cy.contains('נח').should('not.exist')
+ cy.contains('נח').should('not.be.visible') // hides parsha list
+
+ cy.contains('Vayishlach')
+ cy.contains(`Beshalach`)
+ cy.contains(`Sh'lach`)
})
})
diff --git a/dist/bundle.js b/dist/bundle.js
index 51e6ce39..69177661 100644
--- a/dist/bundle.js
+++ b/dist/bundle.js
@@ -104,7 +104,7 @@ eval("module.exports = [[\"בראשית\"],[\"בראשית\"],[\"בראשית\"]
/*! exports provided: 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 52, 53, default */
/***/ (function(module) {
-eval("module.exports = [{\"he\":\"בראשית\",\"ref\":{\"b\":1,\"c\":1,\"v\":1,\"a\":[1]}},{\"he\":\"נח\",\"ref\":{\"b\":1,\"c\":6,\"v\":9,\"a\":[1]}},{\"he\":\"לך לך\",\"ref\":{\"b\":1,\"c\":12,\"v\":1,\"a\":[1]}},{\"he\":\"וירא\",\"ref\":{\"b\":1,\"c\":18,\"v\":1,\"a\":[1]}},{\"he\":\"חיי שרה\",\"ref\":{\"b\":1,\"c\":23,\"v\":1,\"a\":[1]}},{\"he\":\"תולדות\",\"ref\":{\"b\":1,\"c\":25,\"v\":19,\"a\":[1]}},{\"he\":\"ויצא\",\"ref\":{\"b\":1,\"c\":28,\"v\":10,\"a\":[1]}},{\"he\":\"וישלח\",\"ref\":{\"b\":1,\"c\":32,\"v\":4,\"a\":[1]}},{\"he\":\"וישב\",\"ref\":{\"b\":1,\"c\":37,\"v\":1,\"a\":[1]}},{\"he\":\"מקץ\",\"ref\":{\"b\":1,\"c\":41,\"v\":1,\"a\":[1]}},{\"he\":\"ויגש\",\"ref\":{\"b\":1,\"c\":44,\"v\":18,\"a\":[1]}},{\"he\":\"ויחי\",\"ref\":{\"b\":1,\"c\":47,\"v\":28,\"a\":[1]}},{\"he\":\"שמות\",\"ref\":{\"b\":2,\"c\":1,\"v\":1,\"a\":[1]}},{\"he\":\"וארא\",\"ref\":{\"b\":2,\"c\":6,\"v\":2,\"a\":[1]}},{\"he\":\"בא\",\"ref\":{\"b\":2,\"c\":10,\"v\":1,\"a\":[1]}},{\"he\":\"בשלח\",\"ref\":{\"b\":2,\"c\":13,\"v\":17,\"a\":[1]}},{\"he\":\"יתרו\",\"ref\":{\"b\":2,\"c\":18,\"v\":1,\"a\":[1]}},{\"he\":\"משפטים\",\"ref\":{\"b\":2,\"c\":21,\"v\":1,\"a\":[1]}},{\"he\":\"תרומה\",\"ref\":{\"b\":2,\"c\":25,\"v\":1,\"a\":[1]}},{\"he\":\"תצוה\",\"ref\":{\"b\":2,\"c\":27,\"v\":20,\"a\":[1]}},{\"he\":\"כי תשא\",\"ref\":{\"b\":2,\"c\":30,\"v\":11,\"a\":[1]}},{\"he\":\"ויקהל\",\"ref\":{\"b\":2,\"c\":35,\"v\":1,\"a\":[1]}},{\"he\":\"פקודי\",\"ref\":{\"b\":2,\"c\":38,\"v\":21,\"a\":[1]}},{\"he\":\"ויקרא\",\"ref\":{\"b\":3,\"c\":1,\"v\":1,\"a\":[1]}},{\"he\":\"צו\",\"ref\":{\"b\":3,\"c\":6,\"v\":1,\"a\":[1]}},{\"he\":\"שמיני\",\"ref\":{\"b\":3,\"c\":9,\"v\":1,\"a\":[1]}},{\"he\":\"תזריע\",\"ref\":{\"b\":3,\"c\":12,\"v\":1,\"a\":[1]}},{\"he\":\"מצורע\",\"ref\":{\"b\":3,\"c\":14,\"v\":1,\"a\":[1]}},{\"he\":\"אחרי מות\",\"ref\":{\"b\":3,\"c\":16,\"v\":1,\"a\":[1]}},{\"he\":\"קדושים\",\"ref\":{\"b\":3,\"c\":19,\"v\":1,\"a\":[1]}},{\"he\":\"אמור\",\"ref\":{\"b\":3,\"c\":21,\"v\":1,\"a\":[1]}},{\"he\":\"בהר\",\"ref\":{\"b\":3,\"c\":25,\"v\":1,\"a\":[1]}},{\"he\":\"בחקתי\",\"ref\":{\"b\":3,\"c\":26,\"v\":3,\"a\":[1]}},{\"he\":\"במדבר\",\"ref\":{\"b\":4,\"c\":1,\"v\":1,\"a\":[1]}},{\"he\":\"נשא\",\"ref\":{\"b\":4,\"c\":4,\"v\":21,\"a\":[1]}},{\"he\":\"בהעלותך\",\"ref\":{\"b\":4,\"c\":8,\"v\":1,\"a\":[1]}},{\"he\":\"שלח\",\"ref\":{\"b\":4,\"c\":13,\"v\":1,\"a\":[1]}},{\"he\":\"קרח\",\"ref\":{\"b\":4,\"c\":16,\"v\":1,\"a\":[1]}},{\"he\":\"חקת\",\"ref\":{\"b\":4,\"c\":19,\"v\":1,\"a\":[1]}},{\"he\":\"בלק\",\"ref\":{\"b\":4,\"c\":22,\"v\":2,\"a\":[1]}},{\"he\":\"פנחס\",\"ref\":{\"b\":4,\"c\":25,\"v\":10,\"a\":[1]}},{\"he\":\"מטות\",\"ref\":{\"b\":4,\"c\":30,\"v\":2,\"a\":[1]}},{\"he\":\"מסעי\",\"ref\":{\"b\":4,\"c\":33,\"v\":1,\"a\":[1]}},{\"he\":\"דברים\",\"ref\":{\"b\":5,\"c\":1,\"v\":1,\"a\":[1]}},{\"he\":\"ואתחנן\",\"ref\":{\"b\":5,\"c\":3,\"v\":23,\"a\":[1]}},{\"he\":\"עקב\",\"ref\":{\"b\":5,\"c\":7,\"v\":12,\"a\":[1]}},{\"he\":\"ראה\",\"ref\":{\"b\":5,\"c\":11,\"v\":26,\"a\":[1]}},{\"he\":\"שופטים\",\"ref\":{\"b\":5,\"c\":16,\"v\":18,\"a\":[1]}},{\"he\":\"כי תצא\",\"ref\":{\"b\":5,\"c\":21,\"v\":10,\"a\":[1]}},{\"he\":\"כי תבוא\",\"ref\":{\"b\":5,\"c\":26,\"v\":1,\"a\":[1]}},{\"he\":\"נצבים\",\"ref\":{\"b\":5,\"c\":29,\"v\":9,\"a\":[1]}},{\"he\":\"וילך\",\"ref\":{\"b\":5,\"c\":31,\"v\":1,\"a\":[1]}},{\"he\":\"האזינו\",\"ref\":{\"b\":5,\"c\":32,\"v\":1,\"a\":[1]}},{\"he\":\"וזאת הברכה\",\"ref\":{\"b\":5,\"c\":33,\"v\":1,\"a\":[1]}}];\n\n//# sourceURL=webpack:///./build/parshiyot.json?");
+eval("module.exports = [{\"he\":\"בראשית\",\"en\":\"Bereshit\",\"ref\":{\"b\":1,\"c\":1,\"v\":1,\"a\":[1]}},{\"he\":\"נח\",\"en\":\"Noach\",\"ref\":{\"b\":1,\"c\":6,\"v\":9,\"a\":[1]}},{\"he\":\"לך לך\",\"en\":\"Lech Lecha\",\"ref\":{\"b\":1,\"c\":12,\"v\":1,\"a\":[1]}},{\"he\":\"וירא\",\"en\":\"Vayera\",\"ref\":{\"b\":1,\"c\":18,\"v\":1,\"a\":[1]}},{\"he\":\"חיי שרה\",\"en\":\"Chayei Sara\",\"ref\":{\"b\":1,\"c\":23,\"v\":1,\"a\":[1]}},{\"he\":\"תולדות\",\"en\":\"Toldot\",\"ref\":{\"b\":1,\"c\":25,\"v\":19,\"a\":[1]}},{\"he\":\"ויצא\",\"en\":\"Vayetzei\",\"ref\":{\"b\":1,\"c\":28,\"v\":10,\"a\":[1]}},{\"he\":\"וישלח\",\"en\":\"Vayishlach\",\"ref\":{\"b\":1,\"c\":32,\"v\":4,\"a\":[1]}},{\"he\":\"וישב\",\"en\":\"Vayeshev\",\"ref\":{\"b\":1,\"c\":37,\"v\":1,\"a\":[1]}},{\"he\":\"מקץ\",\"en\":\"Miketz\",\"ref\":{\"b\":1,\"c\":41,\"v\":1,\"a\":[1]}},{\"he\":\"ויגש\",\"en\":\"Vayigash\",\"ref\":{\"b\":1,\"c\":44,\"v\":18,\"a\":[1]}},{\"he\":\"ויחי\",\"en\":\"Vayechi\",\"ref\":{\"b\":1,\"c\":47,\"v\":28,\"a\":[1]}},{\"he\":\"שמות\",\"en\":\"Shemot\",\"ref\":{\"b\":2,\"c\":1,\"v\":1,\"a\":[1]}},{\"he\":\"וארא\",\"en\":\"Vaera\",\"ref\":{\"b\":2,\"c\":6,\"v\":2,\"a\":[1]}},{\"he\":\"בא\",\"en\":\"Bo\",\"ref\":{\"b\":2,\"c\":10,\"v\":1,\"a\":[1]}},{\"he\":\"בשלח\",\"en\":\"Beshalach\",\"ref\":{\"b\":2,\"c\":13,\"v\":17,\"a\":[1]}},{\"he\":\"יתרו\",\"en\":\"Yitro\",\"ref\":{\"b\":2,\"c\":18,\"v\":1,\"a\":[1]}},{\"he\":\"משפטים\",\"en\":\"Mishpatim\",\"ref\":{\"b\":2,\"c\":21,\"v\":1,\"a\":[1]}},{\"he\":\"תרומה\",\"en\":\"Terumah\",\"ref\":{\"b\":2,\"c\":25,\"v\":1,\"a\":[1]}},{\"he\":\"תצוה\",\"en\":\"Tetzaveh\",\"ref\":{\"b\":2,\"c\":27,\"v\":20,\"a\":[1]}},{\"he\":\"כי תשא\",\"en\":\"Ki Tisa\",\"ref\":{\"b\":2,\"c\":30,\"v\":11,\"a\":[1]}},{\"he\":\"ויקהל\",\"en\":\"Vayakhel\",\"ref\":{\"b\":2,\"c\":35,\"v\":1,\"a\":[1]}},{\"he\":\"פקודי\",\"en\":\"Pekudei\",\"ref\":{\"b\":2,\"c\":38,\"v\":21,\"a\":[1]}},{\"he\":\"ויקרא\",\"en\":\"Vayikra\",\"ref\":{\"b\":3,\"c\":1,\"v\":1,\"a\":[1]}},{\"he\":\"צו\",\"en\":\"Tzav\",\"ref\":{\"b\":3,\"c\":6,\"v\":1,\"a\":[1]}},{\"he\":\"שמיני\",\"en\":\"Shmini\",\"ref\":{\"b\":3,\"c\":9,\"v\":1,\"a\":[1]}},{\"he\":\"תזריע\",\"en\":\"Tazria\",\"ref\":{\"b\":3,\"c\":12,\"v\":1,\"a\":[1]}},{\"he\":\"מצורע\",\"en\":\"Metzora\",\"ref\":{\"b\":3,\"c\":14,\"v\":1,\"a\":[1]}},{\"he\":\"אחרי מות\",\"en\":\"Achrei Mot\",\"ref\":{\"b\":3,\"c\":16,\"v\":1,\"a\":[1]}},{\"he\":\"קדושים\",\"en\":\"Kedoshim\",\"ref\":{\"b\":3,\"c\":19,\"v\":1,\"a\":[1]}},{\"he\":\"אמור\",\"en\":\"Emor\",\"ref\":{\"b\":3,\"c\":21,\"v\":1,\"a\":[1]}},{\"he\":\"בהר\",\"en\":\"Behar\",\"ref\":{\"b\":3,\"c\":25,\"v\":1,\"a\":[1]}},{\"he\":\"בחקתי\",\"en\":\"Bechukotai\",\"ref\":{\"b\":3,\"c\":26,\"v\":3,\"a\":[1]}},{\"he\":\"במדבר\",\"en\":\"Bamidbar\",\"ref\":{\"b\":4,\"c\":1,\"v\":1,\"a\":[1]}},{\"he\":\"נשא\",\"en\":\"Nasso\",\"ref\":{\"b\":4,\"c\":4,\"v\":21,\"a\":[1]}},{\"he\":\"בהעלותך\",\"en\":\"Beha'alotcha\",\"ref\":{\"b\":4,\"c\":8,\"v\":1,\"a\":[1]}},{\"he\":\"שלח\",\"en\":\"Sh'lach\",\"ref\":{\"b\":4,\"c\":13,\"v\":1,\"a\":[1]}},{\"he\":\"קרח\",\"en\":\"Korach\",\"ref\":{\"b\":4,\"c\":16,\"v\":1,\"a\":[1]}},{\"he\":\"חקת\",\"en\":\"Chukat\",\"ref\":{\"b\":4,\"c\":19,\"v\":1,\"a\":[1]}},{\"he\":\"בלק\",\"en\":\"Balak\",\"ref\":{\"b\":4,\"c\":22,\"v\":2,\"a\":[1]}},{\"he\":\"פנחס\",\"en\":\"Pinchas\",\"ref\":{\"b\":4,\"c\":25,\"v\":10,\"a\":[1]}},{\"he\":\"מטות\",\"en\":\"Matot\",\"ref\":{\"b\":4,\"c\":30,\"v\":2,\"a\":[1]}},{\"he\":\"מסעי\",\"en\":\"Masei\",\"ref\":{\"b\":4,\"c\":33,\"v\":1,\"a\":[1]}},{\"he\":\"דברים\",\"en\":\"Devarim\",\"ref\":{\"b\":5,\"c\":1,\"v\":1,\"a\":[1]}},{\"he\":\"ואתחנן\",\"en\":\"Vaetchanan\",\"ref\":{\"b\":5,\"c\":3,\"v\":23,\"a\":[1]}},{\"he\":\"עקב\",\"en\":\"Eikev\",\"ref\":{\"b\":5,\"c\":7,\"v\":12,\"a\":[1]}},{\"he\":\"ראה\",\"en\":\"Re'eh\",\"ref\":{\"b\":5,\"c\":11,\"v\":26,\"a\":[1]}},{\"he\":\"שופטים\",\"en\":\"Shoftim\",\"ref\":{\"b\":5,\"c\":16,\"v\":18,\"a\":[1]}},{\"he\":\"כי תצא\",\"en\":\"Ki Teitzei\",\"ref\":{\"b\":5,\"c\":21,\"v\":10,\"a\":[1]}},{\"he\":\"כי תבוא\",\"en\":\"Ki Tavo\",\"ref\":{\"b\":5,\"c\":26,\"v\":1,\"a\":[1]}},{\"he\":\"נצבים\",\"en\":\"Nitzavim\",\"ref\":{\"b\":5,\"c\":29,\"v\":9,\"a\":[1]}},{\"he\":\"וילך\",\"en\":\"Vayeilech\",\"ref\":{\"b\":5,\"c\":31,\"v\":1,\"a\":[1]}},{\"he\":\"האזינו\",\"en\":\"Ha'Azinu\",\"ref\":{\"b\":5,\"c\":32,\"v\":1,\"a\":[1]}},{\"he\":\"וזאת הברכה\",\"en\":\"Vezot Haberakhah\",\"ref\":{\"b\":5,\"c\":33,\"v\":1,\"a\":[1]}}];\n\n//# sourceURL=webpack:///./build/parshiyot.json?");
/***/ }),
@@ -147,11 +147,11 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _Lin
/*!************************************!*\
!*** ./components/ParshaPicker.js ***!
\************************************/
-/*! exports provided: default */
+/*! exports provided: search, default */
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _build_parshiyot_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../build/parshiyot.json */ \"./build/parshiyot.json\");\nvar _build_parshiyot_json__WEBPACK_IMPORTED_MODULE_0___namespace = /*#__PURE__*/__webpack_require__.t(/*! ../build/parshiyot.json */ \"./build/parshiyot.json\", 1);\n\n\nconst Parsha = ({ ref, he }) => `\n ${he}\n\n`\n\nconst Book = (book) => `\n \n \n ${book.map(Parsha).join('')}\n
\n \n`\n\nconst ParshaPicker = () => `\n \n
\n \n ⚲\n
\n
\n ${_build_parshiyot_json__WEBPACK_IMPORTED_MODULE_0__\n .reduce((books, parsha) => {\n const book = parsha.ref.b\n books[book] = books[book] || []\n books[book].push(parsha)\n return books\n }, [])\n .map(Book)\n .join('')\n }\n
\n
\n`\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (ParshaPicker);\n\n\n//# sourceURL=webpack:///./components/ParshaPicker.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, \"search\", function() { return search; });\n/* harmony import */ var _build_parshiyot_json__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ../build/parshiyot.json */ \"./build/parshiyot.json\");\nvar _build_parshiyot_json__WEBPACK_IMPORTED_MODULE_0___namespace = /*#__PURE__*/__webpack_require__.t(/*! ../build/parshiyot.json */ \"./build/parshiyot.json\", 1);\n/* harmony import */ var _src_fuzzy__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ../src/fuzzy */ \"./src/fuzzy.js\");\n/* harmony import */ var _src_fuzzy__WEBPACK_IMPORTED_MODULE_1___default = /*#__PURE__*/__webpack_require__.n(_src_fuzzy__WEBPACK_IMPORTED_MODULE_1__);\n\n\n\nconst Parsha = ({ ref, he }) => `\n ${he}\n\n`\n\nconst Book = (book) => `\n \n \n ${book.map(Parsha).join('')}\n
\n \n`\n\n/*\n\n שלח
\n Shelach
\n\n\n בשלח
\n Beshalach
\n\n\n וישלח
\n Vayishlach
\n\n*/\n\n/*\n\n No results
\n\n*/\nconst Search = () => `\n \n`\n\nconst decorateString = ({ string, atIndexes, withDecoration }) => {\n let indexesIndex = 0\n return string\n .split('')\n .map((char, i) => {\n if (atIndexes[indexesIndex] !== i) return char\n\n ++indexesIndex\n return withDecoration(char)\n }, '')\n .join('')\n}\n\nconst SearchResult = ({ string, indexes }) => `\n \n ${decorateString({\n string,\n atIndexes: indexes,\n withDecoration: (c) => (`${c}`)\n })}\n
\n \n`\n\nconst ParshaPicker = () => `\n \n ${Search()}\n
\n ${_build_parshiyot_json__WEBPACK_IMPORTED_MODULE_0__\n .reduce((books, parsha) => {\n const book = parsha.ref.b\n books[book] = books[book] || []\n books[book].push(parsha)\n return books\n }, [])\n .map(Book)\n .join('')\n }\n
\n
\n`\n\nconst searchResults = (query) => _src_fuzzy__WEBPACK_IMPORTED_MODULE_1___default()(_build_parshiyot_json__WEBPACK_IMPORTED_MODULE_0__.map(parsha => parsha.en), query)\n\nconst htmlToElement = (html) => {\n const template = document.createElement('template')\n html = html.trim() // Never return a text node of whitespace as the result\n template.innerHTML = html\n return template.content.firstChild\n}\n\nconst top = (n) => (_, i) => i < n\n\nconst search = ({ jumper, query }) => {\n const searchResultsElement = jumper.querySelector('.search-results')\n\n if (query) {\n searchResultsElement.classList.remove('u-hidden')\n jumper.querySelector('.parsha-books').classList.add('u-hidden')\n\n searchResultsElement.innerHTML = ''\n\n searchResults(query)\n .filter(top(5))\n .map(SearchResult)\n .map(htmlToElement)\n .forEach(result => {\n searchResultsElement.appendChild(result)\n })\n } else {\n searchResultsElement.classList.add('u-hidden')\n jumper.querySelector('.parsha-books').classList.remove('u-hidden')\n }\n}\n\n\n\n/* harmony default export */ __webpack_exports__[\"default\"] = (ParshaPicker);\n\n\n//# sourceURL=webpack:///./components/ParshaPicker.js?");
/***/ }),
@@ -163,7 +163,7 @@ eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _bui
/***/ (function(module, __webpack_exports__, __webpack_require__) {
"use strict";
-eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _src__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./src */ \"./src/index.js\");\n/* harmony import */ var _components_Page__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./components/Page */ \"./components/Page.js\");\n/* harmony import */ var _components_ParshaPicker__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./components/ParshaPicker */ \"./components/ParshaPicker.js\");\n/* harmony import */ var _build_page_titles_json__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./build/page-titles.json */ \"./build/page-titles.json\");\nvar _build_page_titles_json__WEBPACK_IMPORTED_MODULE_3___namespace = /*#__PURE__*/__webpack_require__.t(/*! ./build/page-titles.json */ \"./build/page-titles.json\", 1);\n\n\n\n\n\nconst insertBefore = (parent, child) => {\n parent.insertAdjacentElement('afterbegin', child)\n}\n\nconst insertAfter = (parent, child) => {\n parent.insertAdjacentElement('beforeend', child)\n}\n\nconst fetchPage = (n) => {\n if (n <= 0) return Promise.resolve({})\n\n return window.fetch(`/build/pages/${n}.json`)\n .then((res) => res.json())\n .then((page) => ({ key: n, content: page }))\n .catch((err) => {\n console.error(err)\n return {}\n })\n}\n\nconst iterator = _src__WEBPACK_IMPORTED_MODULE_0__[\"IntegerIterator\"].new({ startingAt: 1 })\n\nconst cache = {}\n\nconst unpackCache = (cache) => Object.keys(cache).map(key => cache[key])\n\nlet isShowingParshaPicker = false\n\nconst htmlToElement = (html) => {\n const template = document.createElement('template')\n html = html.trim() // Never return a text node of whitespace as the result\n template.innerHTML = html\n return template.content.firstChild\n}\n\nconst state = {\n iterator\n}\n\nconst render = ({ cache, showAnnotations, title }) => {\n unpackCache(cache)\n .forEach(({ node, content }) => {\n const el = htmlToElement(Object(_components_Page__WEBPACK_IMPORTED_MODULE_1__[\"default\"])(content, showAnnotations))\n\n const firstChild = node.firstChild\n if (firstChild) {\n node.replaceChild(el, firstChild)\n } else {\n node.appendChild(el)\n }\n })\n\n document.querySelector('[data-target-id=\"parsha-title\"]').innerHTML = title\n}\n\nconst setState = (updates) => {\n const newState = Object.assign(state, updates)\n\n render(newState)\n}\n\nconst purgeObject = (obj) => {\n for (const key in obj) {\n delete obj[key]\n }\n}\n\nconst purgeNode = (node) => {\n while (node.firstChild) node.removeChild(node.firstChild)\n}\n\nconst makePageNode = (n) => {\n const node = document.createElement('div')\n node.classList.add('tikkun-page')\n node.setAttribute('data-page-number', n)\n\n return node\n}\n\nconst scrollToLine = ({ node, lineIndex }) => {\n const lines = [...node.querySelectorAll('.line')]\n\n const line = lines[lineIndex]\n\n const book = document.querySelector('.tikkun-book')\n\n book.scrollTop = line.offsetTop + (line.offsetHeight / 2) - (book.offsetHeight / 2)\n}\n\nconst app = {\n jumpTo: ({ ref }) => {\n purgeObject(cache)\n\n const { pageNumber, lineNumber } = Object(_src__WEBPACK_IMPORTED_MODULE_0__[\"physicalLocationFromRef\"])(ref)\n\n state.iterator = _src__WEBPACK_IMPORTED_MODULE_0__[\"IntegerIterator\"].new({ startingAt: pageNumber })\n\n purgeNode(document.querySelector('[data-target-id=\"tikkun-book\"]'))\n\n fetchPage(state.iterator.next())\n .then(renderNext)\n .then((pageNode) => {\n scrollToLine({ node: pageNode, lineIndex: lineNumber - 1 })\n })\n }\n}\n\nconst showParshaPicker = () => {\n document.querySelector('#js-app').appendChild(htmlToElement(Object(_components_ParshaPicker__WEBPACK_IMPORTED_MODULE_2__[\"default\"])()))\n\n document.querySelector('.parsha-search-input').addEventListener('input', (e) => {\n console.log(e.target.value)\n })\n\n ;[...document.querySelectorAll('[data-target-id=\"parsha\"]')]\n .forEach((parsha) => {\n parsha.addEventListener('click', (e) => {\n const refPart = (part) => Number(e.target.getAttribute(`data-jump-to-${part}`))\n app.jumpTo({ ref: { b: refPart('book'), c: refPart('chapter'), v: refPart('verse') } })\n\n toggleParshaPicker()\n })\n })\n}\n\nconst toggleParshaPicker = () => {\n isShowingParshaPicker = !isShowingParshaPicker\n\n ;[\n '[data-test-id=\"annotations-toggle\"]',\n '[data-target-id=\"repo-link\"]',\n '[data-target-id=\"tikkun-book\"]'\n ]\n .map(selector => document.querySelector(selector))\n .map(el => el.classList)\n .forEach(classList => {\n classList.toggle('u-hidden')\n classList.toggle('mod-animated')\n })\n\n if (isShowingParshaPicker) {\n showParshaPicker()\n } else {\n document.querySelector('#js-app').removeChild(document.querySelector('.parsha-picker'))\n }\n}\n\nconst toggleAnnotations = () => {\n const toggle = document.querySelector('[data-target-id=\"annotations-toggle\"]')\n\n toggle.checked = !toggle.checked\n\n setState({ showAnnotations: toggle.checked })\n}\n\nconst isInView = (view, scrollView) => {\n return (\n view.offsetTop < scrollView.scrollTop + scrollView.clientHeight\n ) && (\n view.offsetTop + view.clientHeight > scrollView.scrollTop\n )\n}\n\nconst updatePageTitle = (scrollView) => {\n const pages = [...document.querySelectorAll('.tikkun-page')]\n\n const inViewPages = pages.filter((page) => isInView(page, scrollView))\n\n const firstPageInView = inViewPages[0]\n\n const n = Number(firstPageInView.getAttribute('data-page-number'))\n setState({ title: Object(_src__WEBPACK_IMPORTED_MODULE_0__[\"title\"])(_build_page_titles_json__WEBPACK_IMPORTED_MODULE_3__[n - 1]) })\n}\n\nlet timeout\nconst debounce = (f) => {\n clearTimeout(timeout)\n timeout = setTimeout(f, 100)\n}\n\nconst renderPage = ({ insertStrategy: insert }) => ({ key, content }) => {\n const node = makePageNode(key)\n\n cache[key] = { node, content }\n insert(document.querySelector('[data-target-id=\"tikkun-book\"]'), node)\n\n setState({\n cache,\n showAnnotations: document.querySelector('[data-target-id=\"annotations-toggle\"]').checked,\n title: Object(_src__WEBPACK_IMPORTED_MODULE_0__[\"title\"])(_build_page_titles_json__WEBPACK_IMPORTED_MODULE_3__[key - 1])\n })\n\n return node\n}\n\nconst renderPrevious = renderPage({ insertStrategy: insertBefore })\nconst renderNext = renderPage({ insertStrategy: insertAfter })\n\nconst whenKey = (key, callback) => e => {\n if (e.key === key) callback()\n}\n\ndocument.addEventListener('DOMContentLoaded', () => {\n _src__WEBPACK_IMPORTED_MODULE_0__[\"InfiniteScroller\"]\n .new({\n container: document.querySelector('[data-target-id=\"tikkun-book\"]'),\n fetchPreviousContent: {\n fetch: () => fetchPage(state.iterator.previous()),\n render: (container, { key, content }) => renderPrevious({ key, content })\n },\n fetchNextContent: {\n fetch: () => fetchPage(state.iterator.next()),\n render: (container, { key, content }) => renderNext({ key, content })\n }\n })\n .attach()\n\n document.querySelector('[data-target-id=\"tikkun-book\"]').addEventListener('scroll', (e) => {\n debounce(() => updatePageTitle(e.target))\n })\n\n document.querySelector('[data-target-id=\"annotations-toggle\"]').addEventListener('change', (e) => {\n const showAnnotations = e.target.checked\n\n setState({ showAnnotations })\n })\n\n document.addEventListener('keydown', whenKey('Shift', toggleAnnotations))\n document.addEventListener('keyup', whenKey('Shift', toggleAnnotations))\n\n document.querySelector('[data-target-id=\"parsha-title\"]').addEventListener('click', toggleParshaPicker)\n document.addEventListener('keydown', whenKey('/', toggleParshaPicker))\n\n fetchPage(state.iterator.next())\n .then(renderNext)\n})\n\n\n//# sourceURL=webpack:///./index.js?");
+eval("__webpack_require__.r(__webpack_exports__);\n/* harmony import */ var _src__WEBPACK_IMPORTED_MODULE_0__ = __webpack_require__(/*! ./src */ \"./src/index.js\");\n/* harmony import */ var _components_Page__WEBPACK_IMPORTED_MODULE_1__ = __webpack_require__(/*! ./components/Page */ \"./components/Page.js\");\n/* harmony import */ var _components_ParshaPicker__WEBPACK_IMPORTED_MODULE_2__ = __webpack_require__(/*! ./components/ParshaPicker */ \"./components/ParshaPicker.js\");\n/* harmony import */ var _build_page_titles_json__WEBPACK_IMPORTED_MODULE_3__ = __webpack_require__(/*! ./build/page-titles.json */ \"./build/page-titles.json\");\nvar _build_page_titles_json__WEBPACK_IMPORTED_MODULE_3___namespace = /*#__PURE__*/__webpack_require__.t(/*! ./build/page-titles.json */ \"./build/page-titles.json\", 1);\n\n\n\n\n\nconst insertBefore = (parent, child) => {\n parent.insertAdjacentElement('afterbegin', child)\n}\n\nconst insertAfter = (parent, child) => {\n parent.insertAdjacentElement('beforeend', child)\n}\n\nconst fetchPage = (n) => {\n if (n <= 0) return Promise.resolve({})\n\n return window.fetch(`/build/pages/${n}.json`)\n .then((res) => res.json())\n .then((page) => ({ key: n, content: page }))\n .catch((err) => {\n console.error(err)\n return {}\n })\n}\n\nconst iterator = _src__WEBPACK_IMPORTED_MODULE_0__[\"IntegerIterator\"].new({ startingAt: 1 })\n\nconst cache = {}\n\nconst unpackCache = (cache) => Object.keys(cache).map(key => cache[key])\n\nlet isShowingParshaPicker = false\n\nconst htmlToElement = (html) => {\n const template = document.createElement('template')\n html = html.trim() // Never return a text node of whitespace as the result\n template.innerHTML = html\n return template.content.firstChild\n}\n\nconst state = {\n iterator\n}\n\nconst render = ({ cache, showAnnotations, title }) => {\n unpackCache(cache)\n .forEach(({ node, content }) => {\n const el = htmlToElement(Object(_components_Page__WEBPACK_IMPORTED_MODULE_1__[\"default\"])(content, showAnnotations))\n\n const firstChild = node.firstChild\n if (firstChild) {\n node.replaceChild(el, firstChild)\n } else {\n node.appendChild(el)\n }\n })\n\n document.querySelector('[data-target-id=\"parsha-title\"]').innerHTML = title\n}\n\nconst setState = (updates) => {\n const newState = Object.assign(state, updates)\n\n render(newState)\n}\n\nconst purgeObject = (obj) => {\n for (const key in obj) {\n delete obj[key]\n }\n}\n\nconst purgeNode = (node) => {\n while (node.firstChild) node.removeChild(node.firstChild)\n}\n\nconst makePageNode = (n) => {\n const node = document.createElement('div')\n node.classList.add('tikkun-page')\n node.setAttribute('data-page-number', n)\n\n return node\n}\n\nconst scrollToLine = ({ node, lineIndex }) => {\n const lines = [...node.querySelectorAll('.line')]\n\n const line = lines[lineIndex]\n\n const book = document.querySelector('.tikkun-book')\n\n book.scrollTop = line.offsetTop + (line.offsetHeight / 2) - (book.offsetHeight / 2)\n}\n\nconst app = {\n jumpTo: ({ ref }) => {\n purgeObject(cache)\n\n const { pageNumber, lineNumber } = Object(_src__WEBPACK_IMPORTED_MODULE_0__[\"physicalLocationFromRef\"])(ref)\n\n state.iterator = _src__WEBPACK_IMPORTED_MODULE_0__[\"IntegerIterator\"].new({ startingAt: pageNumber })\n\n purgeNode(document.querySelector('[data-target-id=\"tikkun-book\"]'))\n\n fetchPage(state.iterator.next())\n .then(renderNext)\n .then((pageNode) => {\n scrollToLine({ node: pageNode, lineIndex: lineNumber - 1 })\n })\n }\n}\n\nconst showParshaPicker = () => {\n const jumper = htmlToElement(Object(_components_ParshaPicker__WEBPACK_IMPORTED_MODULE_2__[\"default\"])())\n document.querySelector('#js-app').appendChild(jumper)\n\n jumper.querySelector('.search-input').addEventListener('input', (e) => {\n Object(_components_ParshaPicker__WEBPACK_IMPORTED_MODULE_2__[\"search\"])({ jumper, query: e.target.value })\n })\n\n ;[...document.querySelectorAll('[data-target-id=\"parsha\"]')]\n .forEach((parsha) => {\n parsha.addEventListener('click', (e) => {\n const refPart = (part) => Number(e.target.getAttribute(`data-jump-to-${part}`))\n app.jumpTo({ ref: { b: refPart('book'), c: refPart('chapter'), v: refPart('verse') } })\n\n toggleParshaPicker()\n })\n })\n}\n\nconst toggleParshaPicker = () => {\n isShowingParshaPicker = !isShowingParshaPicker\n\n ;[\n '[data-test-id=\"annotations-toggle\"]',\n '[data-target-id=\"repo-link\"]',\n '[data-target-id=\"tikkun-book\"]'\n ]\n .map(selector => document.querySelector(selector))\n .map(el => el.classList)\n .forEach(classList => {\n classList.toggle('u-hidden')\n classList.toggle('mod-animated')\n })\n\n if (isShowingParshaPicker) {\n showParshaPicker()\n } else {\n document.querySelector('#js-app').removeChild(document.querySelector('.parsha-picker'))\n }\n}\n\nconst toggleAnnotations = () => {\n const toggle = document.querySelector('[data-target-id=\"annotations-toggle\"]')\n\n toggle.checked = !toggle.checked\n\n setState({ showAnnotations: toggle.checked })\n}\n\nconst isInView = (view, scrollView) => {\n return (\n view.offsetTop < scrollView.scrollTop + scrollView.clientHeight\n ) && (\n view.offsetTop + view.clientHeight > scrollView.scrollTop\n )\n}\n\nconst updatePageTitle = (scrollView) => {\n const pages = [...document.querySelectorAll('.tikkun-page')]\n\n const inViewPages = pages.filter((page) => isInView(page, scrollView))\n\n const firstPageInView = inViewPages[0]\n\n const n = Number(firstPageInView.getAttribute('data-page-number'))\n setState({ title: Object(_src__WEBPACK_IMPORTED_MODULE_0__[\"title\"])(_build_page_titles_json__WEBPACK_IMPORTED_MODULE_3__[n - 1]) })\n}\n\nlet timeout\nconst debounce = (f) => {\n clearTimeout(timeout)\n timeout = setTimeout(f, 100)\n}\n\nconst renderPage = ({ insertStrategy: insert }) => ({ key, content }) => {\n const node = makePageNode(key)\n\n cache[key] = { node, content }\n insert(document.querySelector('[data-target-id=\"tikkun-book\"]'), node)\n\n setState({\n cache,\n showAnnotations: document.querySelector('[data-target-id=\"annotations-toggle\"]').checked,\n title: Object(_src__WEBPACK_IMPORTED_MODULE_0__[\"title\"])(_build_page_titles_json__WEBPACK_IMPORTED_MODULE_3__[key - 1])\n })\n\n return node\n}\n\nconst renderPrevious = renderPage({ insertStrategy: insertBefore })\nconst renderNext = renderPage({ insertStrategy: insertAfter })\n\nconst whenKey = (key, callback) => e => {\n if (e.key === key) callback()\n}\n\ndocument.addEventListener('DOMContentLoaded', () => {\n _src__WEBPACK_IMPORTED_MODULE_0__[\"InfiniteScroller\"]\n .new({\n container: document.querySelector('[data-target-id=\"tikkun-book\"]'),\n fetchPreviousContent: {\n fetch: () => fetchPage(state.iterator.previous()),\n render: (container, { key, content }) => renderPrevious({ key, content })\n },\n fetchNextContent: {\n fetch: () => fetchPage(state.iterator.next()),\n render: (container, { key, content }) => renderNext({ key, content })\n }\n })\n .attach()\n\n document.querySelector('[data-target-id=\"tikkun-book\"]').addEventListener('scroll', (e) => {\n debounce(() => updatePageTitle(e.target))\n })\n\n document.querySelector('[data-target-id=\"annotations-toggle\"]').addEventListener('change', (e) => {\n const showAnnotations = e.target.checked\n\n setState({ showAnnotations })\n })\n\n document.addEventListener('keydown', whenKey('Shift', toggleAnnotations))\n document.addEventListener('keyup', whenKey('Shift', toggleAnnotations))\n\n document.querySelector('[data-target-id=\"parsha-title\"]').addEventListener('click', toggleParshaPicker)\n document.addEventListener('keydown', whenKey('/', toggleParshaPicker))\n\n fetchPage(state.iterator.next())\n .then(renderNext)\n // .then(toggleParshaPicker)\n})\n\n\n//# sourceURL=webpack:///./index.js?");
/***/ }),
@@ -178,6 +178,17 @@ eval("const hebrewNumeralFromInteger = __webpack_require__(/*! ./hebrew-numeral
/***/ }),
+/***/ "./src/fuzzy.js":
+/*!**********************!*\
+ !*** ./src/fuzzy.js ***!
+ \**********************/
+/*! no static exports found */
+/***/ (function(module, exports) {
+
+eval("const hasEveryCharacterInOrder = needle => item => (new RegExp(needle\n .split('')\n .join('.*')\n, 'i')).test(item)\n\nconst matchIndexes = (needle, match) => {\n const needleChars = needle.split('')\n const matchChars = match.split('')\n\n const indexes = []\n let needleIndex = 0\n\n for (let i = 0; i < matchChars.length; i++) {\n if (needleChars[needleIndex].toLowerCase() === matchChars[i].toLowerCase()) {\n indexes.push(i)\n ++needleIndex\n\n if (needleIndex >= needleChars.length) break\n }\n }\n\n return indexes\n}\n\nconst indexScore = (needle, match) => {\n const indexes = matchIndexes(needle, match)\n\n return indexes\n .map(index => index - indexes[0])\n .reduce((a, b) => a + b)\n}\n\nmodule.exports = (haystack, needle) => haystack\n .filter(hasEveryCharacterInOrder(needle))\n .map(match => ({ indexes: matchIndexes(needle, match), string: match }))\n .sort((match, other) => {\n const matchScore = indexScore(needle, match.string)\n const otherScore = indexScore(needle, other.string)\n\n const score = matchScore - otherScore\n\n if (score === 0) {\n return match.indexes[0] - other.indexes[0]\n }\n\n return score\n })\n\n\n//# sourceURL=webpack:///./src/fuzzy.js?");
+
+/***/ }),
+
/***/ "./src/hebrew-numeral.js":
/*!*******************************!*\
!*** ./src/hebrew-numeral.js ***!
diff --git a/index.js b/index.js
index 15fbc393..cdea0567 100644
--- a/index.js
+++ b/index.js
@@ -1,6 +1,6 @@
import { InfiniteScroller, IntegerIterator, title as getTitle, physicalLocationFromRef } from './src'
import Page from './components/Page'
-import ParshaPicker from './components/ParshaPicker'
+import ParshaPicker, { search } from './components/ParshaPicker'
import pageTitles from './build/page-titles.json'
const insertBefore = (parent, child) => {
@@ -111,10 +111,11 @@ const app = {
}
const showParshaPicker = () => {
- document.querySelector('#js-app').appendChild(htmlToElement(ParshaPicker()))
+ const jumper = htmlToElement(ParshaPicker())
+ document.querySelector('#js-app').appendChild(jumper)
- document.querySelector('.parsha-search-input').addEventListener('input', (e) => {
- console.log(e.target.value)
+ jumper.querySelector('.search-input').addEventListener('input', (e) => {
+ search({ jumper, query: e.target.value })
})
;[...document.querySelectorAll('[data-target-id="parsha"]')]
@@ -238,4 +239,5 @@ document.addEventListener('DOMContentLoaded', () => {
fetchPage(state.iterator.next())
.then(renderNext)
+ // .then(toggleParshaPicker)
})