diff --git a/assets/search.js b/assets/search.js index 24f0c5d..caa8b72 100644 --- a/assets/search.js +++ b/assets/search.js @@ -68,25 +68,35 @@ function debouncer(interval, callback) { form.classList.remove("focus"); }); - function moveFocus(delta) { + function moveFocus(element, delta) { const focusIndexText = document.activeElement.getAttribute("data-focusindex"); - if (!focusIndexText) return; - const currentIndex = parseInt(focusIndexText, 10); - const nextIndex = currentIndex + delta; + const nextIndex = focusIndexText ? parseInt(focusIndexText, 10) + delta : 0; - const candidate = form.querySelector("[data-focusindex=\"" + nextIndex + "\"]"); + const candidate = element.querySelector("[data-focusindex=\"" + nextIndex + "\"]"); if (candidate) candidate.focus(); } - form.addEventListener('keydown', function (ev) { + function focusControl(element, ev) { if (ev.key === 'ArrowUp') { ev.preventDefault(); ev.stopPropagation(); - moveFocus(-1); + moveFocus(element, -1); } else if (ev.key === 'ArrowDown') { ev.preventDefault(); ev.stopPropagation(); - moveFocus(1); + moveFocus(element, 1); } - }); + } + + for (let element of document.querySelectorAll(".keyboard-focus-control")) { + const captureElement = element; + element.addEventListener('keydown', ev => focusControl(captureElement, ev)); + } + + const defaultKeyboardFocusControl = document.querySelector(".default-keyboard-focus-control"); + if (defaultKeyboardFocusControl) { + document.addEventListener('keydown', ev => { + focusControl(defaultKeyboardFocusControl, ev); + }); + } })(); diff --git a/assets/style.css b/assets/style.css index 68e4316..e16f4b5 100644 --- a/assets/style.css +++ b/assets/style.css @@ -6,6 +6,10 @@ url('amatic-sc-v9-latin-regular.woff') format('woff'); } +.prototype { + display: none; +} + html { font-family: "Apple Garamond", "Baskerville", "Times New Roman", "Droid Serif", "Times", @@ -292,13 +296,29 @@ article ul.search-results { } .search-result { border: 1px solid #ccc; - padding: 8px 16px; - margin-bottom: 16px; + padding: 0; + margin-bottom: 8px; +} +.search-result .title { + font-weight: bold; } .snippet { white-space: pre-line; } +.search-result p { + margin: 0; +} +.search-result a { + display: block; + color: inherit; + text-decoration: none; + padding: 8px; +} +.search-result a:hover, .search-result a:focus { + background: #0074D9; + color: white; +} .search { text-align: center; @@ -347,33 +367,10 @@ article ul.search-results { } .live-results .search-result { - padding: 0; border-top: none; margin: 0; } -.live-results .search-result li { - padding: 0; -} -.live-results .search-result a { - display: block; - color: inherit; - text-decoration: none; - padding: 8px; -} -.live-results .search-result a:hover, .live-results .search-result a:focus { - background: #0074D9; - color: white; -} - -.live-results .search-result .title { - font-weight: bold; -} - -.prototype { - display: none; -} - @media (min-width: 630px) { .search { text-align: right; diff --git a/src/resources/search_resource.rs b/src/resources/search_resource.rs index c5da67b..c8dc71b 100644 --- a/src/resources/search_resource.rs +++ b/src/resources/search_resource.rs @@ -128,29 +128,36 @@ impl Resource for SearchResource { } fn get(self: Box) -> ResponseFuture { - #[derive(BartDisplay)] - #[template="templates/search.html"] - struct Template<'a> { - query: &'a str, - hits: Vec, - } - #[derive(Serialize)] struct JsonResponse<'a> { query: &'a str, hits: &'a [models::SearchResult], } - impl models::SearchResult { - fn link(&self) -> String { + struct Hit<'a> { + index: usize, + slug: &'a str, + title: &'a str, + snippet: &'a str, + } + + impl<'a> Hit<'a> { + fn link(&self) -> &'a str { if self.slug == "" { - ".".to_owned() + "." } else { - self.slug.clone() + self.slug } } } + #[derive(BartDisplay)] + #[template="templates/search.html"] + struct Template<'a> { + query: &'a str, + hits: &'a [Hit<'a>], + } + // TODO: Show a search "front page" when no query is given: let query = self.query.as_ref().map(|x| x.clone()).unwrap_or("".to_owned()); @@ -172,7 +179,15 @@ impl Resource for SearchResource { title: "Search", body: &Template { query: self.query.as_ref().map(|x| &**x).unwrap_or(""), - hits: data, + hits: &data.iter() + .enumerate() + .map(|(i, result)| Hit { + index: i, + slug: &result.slug, + title: &result.title, + snippet: &result.snippet, + }) + .collect::>(), }, }.to_string())), } diff --git a/templates/layout.html b/templates/layout.html index 18c0287..d1b78f3 100644 --- a/templates/layout.html +++ b/templates/layout.html @@ -8,7 +8,7 @@ -