From 376880c0c1592a37e6a7810cb9d80c32fba5116f Mon Sep 17 00:00:00 2001 From: "Claudio Maggioni (maggicl)" Date: Fri, 20 Nov 2020 21:58:45 +0100 Subject: [PATCH] 'State of the art' responsive design --- ui/index.html | 102 ++----------------------------------------- ui/search.js | 71 ++++++++++++++++++++++++++++++ ui/style.css | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 194 insertions(+), 98 deletions(-) create mode 100644 ui/search.js create mode 100644 ui/style.css diff --git a/ui/index.html b/ui/index.html index 099896f..3b76618 100644 --- a/ui/index.html +++ b/ui/index.html @@ -7,58 +7,7 @@ - + @@ -83,7 +32,8 @@ main { flex: 1; display: flex; flex-grow: 1; min-height: 0 } - + ` diff --git a/ui/search.js b/ui/search.js new file mode 100644 index 0000000..fabbdca --- /dev/null +++ b/ui/search.js @@ -0,0 +1,71 @@ +// vim: set ts=2 sw=2 et tw=80: + +const urlParams = new URLSearchParams(window.location.search); +const query = urlParams.get('q'); +const solr = "http://localhost:8983/solr/photo"; +const q = document.querySelector("#q"); +const templateHTML = document.querySelector("#document").innerHTML; +const docs = document.querySelector("#docs"); +let foamtree = null; +let queryResult = null; + +function buildCard(docData) { + const emptyOr = s => s ? s : ""; + return templateHTML + .replaceAll("{{ id }}", emptyOr(docData.id)) + .replaceAll("{{ title }}", emptyOr(docData.t_title)) + .replaceAll("{{ author }}", emptyOr(docData.t_author)) + .replaceAll("{{ description }}", emptyOr(docData.t_description)) + .replaceAll("{{ url }}", emptyOr(docData.img_url)) + .replaceAll("{{ site_url }}", "#"); +} + +function updateResults() { + docs.innerHTML = queryResult.response.docs.map(d => { + return buildCard(d); + }).reduce((a, b) => a + b, ""); +} + +async function buildQuery(e) { + if (e) e.preventDefault(); + let docMap = {} + + let list = await fetch(solr + "/clustering?q=" + q.value); + queryResult = await list.json(); + console.log(queryResult); + + updateResults(); + for (const e of queryResult.response.docs) { + docMap[e.id] = e; + } + + let clusters = queryResult.clusters.map(e => { + return { + label: e.labels[0], + weight: e.score, + groups: e.docs.map(id => { + return { id, label: docMap[id].t_title }; + }) + }; + }); + + if (foamtree === null) { + foamtree = new CarrotSearchFoamTree({ + id: "visualization", + layout: "squarified", + groupLabelFontFamily: "Fira Sans", + dataObject: { + groups: clusters + } + }); + } else { + foamtree.set({ dataObject: { groups: clusters }}); + } +}; + +if (query) { + q.value = query; + buildQuery().catch(console.error); +} + +document.querySelector("#form").addEventListener("submit", buildQuery); diff --git a/ui/style.css b/ui/style.css new file mode 100644 index 0000000..756fd70 --- /dev/null +++ b/ui/style.css @@ -0,0 +1,119 @@ +/* vim: set ts=2 sw=2 et tw=80: */ + +:root { --columns: 14; } +@media screen and (max-width: 3000px) { :root { --columns: 13; } } +@media screen and (max-width: 2800px) { :root { --columns: 12; } } +@media screen and (max-width: 2600px) { :root { --columns: 11; } } +@media screen and (max-width: 2400px) { :root { --columns: 10; } } +@media screen and (max-width: 2200px) { :root { --columns: 9; } } +@media screen and (max-width: 2000px) { :root { --columns: 8; } } +@media screen and (max-width: 1800px) { :root { --columns: 7; } } +@media screen and (max-width: 1600px) { :root { --columns: 6; } } +@media screen and (max-width: 1400px) { :root { --columns: 5; } } +@media screen and (max-width: 1200px) { :root { --columns: 4; } } +@media screen and (max-width: 1000px) { :root { --columns: 3; } } +@media screen and (max-width: 800px) { :root { --columns: 2; } } +@media screen and (max-width: 600px) { :root { --columns: 1; } } + +* { + font-size: 14px; +} + +body { + font-family: 'Fira Sans', sans-serif; + margin: 0; + display: flex; + height: 100vh; + max-height: 100vh; + flex-direction: column; +} + +nav { + flex: 0 0; +} + +main { + flex: 1; + display: flex; + flex-grow: 1; + min-height: 0; +} + +#visualization { + width: 15rem; + padding: .25rem; + border-radius: .125rem; + margin-right: .5rem; + background: #AAA; +} + +#docs { + flex-grow: 1; + flex: 2; + display: grid; + grid-template-columns: repeat(var(--columns),1fr); + overflow-y: scroll; +} + +.title { + background: #333; + color: white; + text-align: center; + padding: 1rem; +} + +.title h1 { + margin: 0; + font-size: 1.4rem; +} + +.searchbox { + padding: 1em; + background: #666; +} + +.searchbox input { + width: calc(100% - 2em); +} + +.document { + float: left; + margin: .25rem; + background: #CCC; + border-radius: .125rem; + text-align: center; + max-width: calc((100vw - 16rem - 20px) / var(--columns) + 1rem); + max-width: calc((100vw - 16rem - 20px) / var(--columns) + 1rem); +} + +.document .img_box { + background: #222; + padding: .5rem; + padding-bottom: 0; + display: inline-block; + width: calc((100vw - 16rem - 20px) / var(--columns) - 3rem); + height: calc((100vw - 16rem - 20px) / var(--columns) - 3rem); + background-repeat: no-repeat; + background-position: center center; + background-size: cover; +} + +.document p { + word-wrap: break-word; +} + +.document h2 { + font-size: 1.2rem; +} + +.document h3 { + font-size: 1.1rem; +} + +.document img { + margin: .5rem .5rem 0 .5rem; +} + +.document h2, .document h3, .document p { + margin: .25rem; +};