From 11f637e43c120e528a94cb3073883187a8d696b2 Mon Sep 17 00:00:00 2001 From: Přemysl Eric Janouch Date: Fri, 15 Dec 2023 22:43:58 +0100 Subject: Improve web views --- main.go | 16 +++++++-------- public/gallery.js | 59 ++++++++++++++++++++++++++++++++++++++++++++----------- 2 files changed, 54 insertions(+), 21 deletions(-) diff --git a/main.go b/main.go index b01e687..8c154e8 100644 --- a/main.go +++ b/main.go @@ -183,7 +183,6 @@ func handleThumbs(w http.ResponseWriter, r *http.Request) { func getSubdirectories(tx *sql.Tx, parent int64) (names []string, err error) { // TODO: This is like dbCollectStrings(), just needs an argument. - // TODO: Should this return full paths, or not? Clean it up. rows, err := tx.Query( `SELECT name FROM directory WHERE IFNULL(parent, 0) = ?`, parent) if err != nil { @@ -282,7 +281,7 @@ func getImagePaths(sha1 string) (paths []string, err error) { UNION ALL SELECT d.parent, d.name || '/' || p.path FROM directory AS d JOIN paths AS p ON d.id = p.parent - ) SELECT '/' || path FROM paths WHERE parent IS NULL`, sha1) + ) SELECT path FROM paths WHERE parent IS NULL`, sha1) if err != nil { return nil, err } @@ -430,16 +429,15 @@ func idForPath(tx *sql.Tx, path []string, create bool) (int64, error) { } func decodeWebPath(path string) []string { - // Trailing slashes don't provide information. - path = strings.TrimSuffix(path, "/") - // Relative paths could be handled differently, // but right now, they're assumed to start at the root. - list := strings.Split(path, "/") - if len(list) > 0 && list[0] == "" { - list = list[1:] + result := []string{} + for _, crumb := range strings.Split(path, "/") { + if crumb != "" { + result = append(result, crumb) + } } - return list + return result } // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/public/gallery.js b/public/gallery.js index d25c544..940b0d2 100644 --- a/public/gallery.js +++ b/public/gallery.js @@ -14,35 +14,64 @@ let BrowseModel = { entries: [], async reload(path) { - this.path = path - this.subdirectories = [] - this.entries = [] + if (this.path !== path) { + this.path = path + this.subdirectories = [] + this.entries = [] + } let resp = await call('browse', {path: path}) this.subdirectories = resp.subdirectories this.entries = resp.entries }, + + joinPath(parent, child) { + if (!parent) + return child + if (!child) + return parent + return `${parent}/${child}` + }, + + getBrowseLinks() { + if (this.path === undefined) + return [] + + let links = [{name: "Root", path: "", level: -1}], path + for (const crumb of this.path.split('/').filter(s => !!s)) { + path = this.joinPath(path, crumb) + links.push({name: crumb, path: path, level: -1}) + } + + links[links.length - 1].level = 0 + + for (const sub of this.subdirectories) { + links.push( + {name: sub, path: this.joinPath(this.path, sub), level: +1}) + } + return links + }, } let Browse = { - // Reload the model immediately, to improve responsibility. + // Reload the model immediately, to improve responsivity. // But we don't need to: https://mithril.js.org/route.html#preloading-data // Also see: https://mithril.js.org/route.html#route-cancellation--blocking oninit(vnode) { - let path = vnode.attrs.key || "/" + let path = vnode.attrs.key || "" BrowseModel.reload(path) }, view(vnode) { return m('.container', {}, [ m('.header', {}, "Browse"), - m('h1', "Root"), - m('ul', BrowseModel.subdirectories.map(sd => { - const name = sd.split('/').pop() + m('ul', BrowseModel.getBrowseLinks().map(link => { + // TODO: Differentiate the level as CSS classes. + // - Last entry (current path) should look selected. return m('li', m(m.route.Link, { href: `/browse/:key`, - params: {key: `${BrowseModel.path}/${sd}`}, - }, name)) + params: {key: link.path}, + }, `${link.level} ${link.name}`)) })), m('.browser', {}, BrowseModel.entries.map(e => { return m(m.route.Link, {href: `/view/${e.sha1}`}, @@ -76,13 +105,19 @@ let View = { }, view(vnode) { - // TODO: Show more information. return m('.container', {}, [ m('.header', {}, "View"), - m('ul', ViewModel.paths.map(sd => m('li', sd))), ViewModel.sha1 !== undefined ? m('img', {src: `/image/${ViewModel.sha1}`}) : "No image.", + m('h2', "Locations"), + m('ul', ViewModel.paths.map(sd => m('li', sd))), + m('h2', "Tags"), + Object.entries(ViewModel.tags).map(([group, tags]) => [ + m("h3", group), + m("ul", Object.entries(tags).map( + ([tag, weight]) => m("li", `${tag}: ${weight}`))), + ]), ]) }, } -- cgit v1.2.3-70-g09d2