From 3cb3108646f81ea838a03923d9d51895e61fdb74 Mon Sep 17 00:00:00 2001 From: Joris Date: Wed, 13 Sep 2023 09:28:23 +0200 Subject: Go to previous or next book with left and right --- src/view/books.ts | 62 +++++++++++++++++++++++++++++++++++++------- src/view/components/modal.ts | 12 ++++++--- 2 files changed, 60 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/view/books.ts b/src/view/books.ts index 7cb3cc1..5ec019a 100644 --- a/src/view/books.ts +++ b/src/view/books.ts @@ -6,18 +6,56 @@ export function view(books: Rx>): Html { return h('div', { className: 'g-Books' }, withVar(undefined, (focusBook, updateFocusBook) => [ - focusBook.map(book => book && bookDetailModal({ - book, - onClose: () => updateFocusBook(_ => undefined) - })), - books.map(bs => bs.map(book => viewBook({ - book, - onSelect: (book) => updateFocusBook(_ => book) - }))) + books.map(bs => [ + focusBook.map(book => { + if (book !== undefined) { + let onKeyup = keyupHandler({ + books: bs, + book, + onUpdate: (book: Book.Book) => updateFocusBook(_ => book) + }) + + return bookDetailModal({ + book, + onClose: () => updateFocusBook(_ => undefined), + onmount: () => addEventListener('keyup', onKeyup), + onunmount: () => removeEventListener('keyup', onKeyup) + }) + } + }), + bs.map(book => viewBook({ + book, + onSelect: (book) => updateFocusBook(_ => book) + })) + ]) ]) ) } +interface KeyupHandlerParams { + books: Array + book: Book.Book + onUpdate: (book: Book.Book) => void +} + +function keyupHandler({ books, book, onUpdate }: KeyupHandlerParams): ((e: KeyboardEvent) => void) { + return (e: KeyboardEvent) => { + if (e.key === 'ArrowLeft') { + const indexedBooks = books.map((b, i) => ({ b, i })) + const focus = indexedBooks.find(({ b }) => b == book) + if (focus !== undefined && focus.i > 0) { + onUpdate(books[focus.i - 1]) + } + } else if (e.key === 'ArrowRight') { + const indexedBooks = books.map((b, i) => ({ b, i })) + const focus = indexedBooks.find(({ b }) => b == book) + if (focus !== undefined && focus.i < books.length - 1) { + onUpdate(books[focus.i + 1]) + } + } + } +} + interface ViewBookParams { book: Book.Book onSelect: (book: Book.Book) => void @@ -38,9 +76,11 @@ function viewBook({ book, onSelect }: ViewBookParams): Html { interface BookDetailModalParams { book: Book.Book onClose: () => void + onmount: () => void + onunmount: () => void } -function bookDetailModal({ book, onClose }: BookDetailModalParams): Html { +function bookDetailModal({ book, onClose, onmount, onunmount }: BookDetailModalParams): Html { return Modal.view({ header: h('div', h('div', { className: 'g-BookDetail__Title' }, `${book.title}, ${book.date}`), @@ -61,7 +101,9 @@ function bookDetailModal({ book, onClose }: BookDetailModalParams): Html { .map(str => h('p', str)) ) ), - onClose + onClose, + onmount, + onunmount }) } diff --git a/src/view/components/modal.ts b/src/view/components/modal.ts index 95f907c..5e845e1 100644 --- a/src/view/components/modal.ts +++ b/src/view/components/modal.ts @@ -1,15 +1,19 @@ import { h, Html } from 'lib/rx' interface Params { - header: Html, - body: Html, + header: Html + body: Html onClose: () => void + onmount?: (element: Element) => void + onunmount?: (element: Element) => void } -export function view({ header, body, onClose }: Params): Html { +export function view({ header, body, onClose, onmount, onunmount }: Params): Html { return h('div', { className: 'g-Modal', - onclick: () => onClose() + onclick: () => onClose(), + onmount: (element: Element) => onmount && onmount(element), + onunmount: (element: Element) => onunmount && onunmount(element) }, h('div', { className: 'g-Modal__Content', -- cgit v1.2.3