diff options
-rw-r--r-- | public/gallery.js | 81 | ||||
-rw-r--r-- | public/style.css | 30 |
2 files changed, 79 insertions, 32 deletions
diff --git a/public/gallery.js b/public/gallery.js index 96f0216..dbcadf6 100644 --- a/public/gallery.js +++ b/public/gallery.js @@ -14,6 +14,56 @@ function call(method, params) { const loading = (window.location.hostname !== 'localhost') ? 'lazy' : undefined +let Header = { + global: [ + {name: "Browse", route: '/browse'}, + {name: "Tags", route: '/tags'}, + {name: "Duplicates", route: '/duplicates'}, + {name: "Orphans", route: '/orphans'}, + ], + + image: [ + { + route: '/view', + render: () => m(m.route.Link, { + href: `/view/:key`, + params: {key: m.route.param('key')}, + class: m.route.get().startsWith('/view') + ? 'active' : undefined, + }, "View"), + }, + { + route: '/similar', + render: () => m(m.route.Link, { + href: `/similar/:key`, + params: {key: m.route.param('key')}, + class: m.route.get().startsWith('/similar') + ? 'active' : undefined, + }, "Similar"), + }, + ], + + view(vnode) { + const route = m.route.get() + const main = this.global.map(x => + m(m.route.Link, { + href: x.route, + class: route.startsWith(x.route) ? 'active' : undefined, + }, x.name)) + + let context + if (this.image.some(x => route.startsWith(x.route))) + context = this.image.map(x => x.render()) + + return m('.header', {}, [ + m('nav', main), + m('nav', context), + // TODO: End it with an activity indicator. + m('.activity', '☺'), + ]) + }, +} + // - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - let BrowseModel = { @@ -113,7 +163,7 @@ let Browse = { view(vnode) { return m('.container', {}, [ - m('.header', {}, "Browser"), + m(Header), m('.body', {}, [ m('ul.sidebar', BrowseModel.getBrowseLinks().map(link => m(BrowseBarLink, {link}))), @@ -209,13 +259,7 @@ let View = { : "No image.", ]) return m('.container', {}, [ - m('.header', {}, [ - "View", - m(m.route.Link, { - href: `/similar/:key`, - params: {key: ViewModel.sha1}, - }, "Similar"), - ]), + m(Header), m('.body', {}, [view, m(ViewBar)]), ]) }, @@ -298,13 +342,7 @@ let Similar = { view(vnode) { return m('.container', {}, [ - m('.header', {}, [ - "Similarity search", - m(m.route.Link, { - href: `/view/:key`, - params: {key: SimilarModel.sha1}, - }, "View"), - ]), + m(Header), m('.body', {}, m(SimilarList)), ]) }, @@ -353,9 +391,7 @@ let Duplicates = { view(vnode) { return m('.container', {}, [ - m('.header', {}, [ - "Duplicates", - ]), + m(Header), m('.body', {}, m(DuplicatesList)), ]) }, @@ -421,9 +457,7 @@ let Orphans = { view(vnode) { return m('.container', {}, [ - m('.header', {}, [ - "Orphans", - ]), + m(Header), m('.body', {}, m(OrphansList)), ]) }, @@ -436,11 +470,12 @@ window.addEventListener('load', () => { // The path doesn't need to be escaped, perhaps change that (":key..."). "/browse/": Browse, "/browse/:key": Browse, - "/view/:key": View, - "/similar/:key": Similar, "/duplicates": Duplicates, "/orphans": Orphans, + "/view/:key": View, + "/similar/:key": Similar, + "/tags": undefined, "/tags/:space": undefined, "/tags/:space/:tag": undefined, diff --git a/public/style.css b/public/style.css index 0276e43..0df44d9 100644 --- a/public/style.css +++ b/public/style.css @@ -1,22 +1,33 @@ body { margin: 0; padding: 0; font-family: sans-serif; } - a { color: inherit; } .container { display: flex; flex-direction: column; height: 100vh; width: 100vw; overflow: hidden; } -.body { display: flex; flex-grow: 1; overflow: hidden; } -.header { padding: .25rem .5rem; background: #aaa; color: white; - border-bottom: 1px solid #444; - display: flex; justify-content: space-between; align-items: baseline; - column-gap: .5rem; } +.body { display: flex; flex-grow: 1; overflow: hidden; position: relative; } +.body::after { content: ''; position: absolute; pointer-events: none; + top: 0; left: 0; right: 0; height: .75rem; + background: linear-gradient(#fff, rgb(255 255 255 / 0%)); } + +.header { color: #000; background: #aaa linear-gradient(#888, #999); + display: flex; justify-content: space-between; column-gap: .5rem; } +.header nav { display: flex; margin: 0 .5rem; align-items: end; } +.header nav a { display: block; text-decoration: none; + background: #bbb linear-gradient(#bbb, #ccc); + margin: .25rem 0 0 -1px; padding: .25rem .75rem; + border: 1px solid #888; border-radius: .5rem .5rem 0 0; } +.header nav a.active { font-weight: bold; border-bottom: 1px solid #fff; + background: #fff linear-gradient(#ddd, #fff); } +.header nav a.active, .header nav a:hover { padding-bottom: .4rem; } +.header .activity { padding: .25rem .5rem; align-self: center; color: #fff; } + +ul.sidebar { margin: 0; padding: .5rem 0; background: #eee; + min-width: 10rem; overflow: auto; border-right: 1px solid #ccc; } -ul.sidebar { margin: 0; padding: 0; background: #eee; - border-right: 1px solid #ccc; min-width: 10rem; overflow: auto; } ul.sidebar li { margin: 0; padding: 0; } ul.sidebar li a { padding: .25rem .5rem; padding-left: 30px; display: block; text-decoration: none; white-space: nowrap; } -ul.sidebar li a:hover { background: #ddd; } +ul.sidebar li a:hover { background-color: rgb(0 0 0 / 10%); } ul.sidebar li.parent a { background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20'%3E%3Cpath d='M 4 14 10 8 16 14' stroke='%23888' stroke-width='4' fill='none' /%3E%3C/svg%3E%0A"); @@ -43,6 +54,7 @@ img.thumbnail { display: block; box-shadow: 0 0 3px rgba(0, 0, 0, 0.75); .view { display: flex; flex-grow: 1; overflow: hidden; justify-content: center; align-items: center; } .view img { max-width: 100%; max-height: 100%; object-fit: contain; } +.view img { z-index: 1; } .viewbar { padding: .25rem .5rem; background: #eee; border-left: 1px solid #ccc; min-width: 20rem; overflow: auto; } |