init
This commit is contained in:
commit
38a5c47dab
11 changed files with 550 additions and 0 deletions
79
templates/gallery.html
Normal file
79
templates/gallery.html
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>{{.Title}}</title>
|
||||
<script src="/assets/alpine.min.js" defer></script>
|
||||
<style>
|
||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||
body { background: black; height: 100vh; overflow: hidden; }
|
||||
.page {
|
||||
width: 100vw;
|
||||
height: 100vh;
|
||||
background-size: contain;
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
.page.landscape {
|
||||
width: 100vh;
|
||||
height: 100vw;
|
||||
transform: rotate(270deg) translateY(-50%);
|
||||
transform-origin: top right;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div
|
||||
x-data="{
|
||||
current: 0,
|
||||
landscape: false,
|
||||
width: 1080,
|
||||
height: 1920,
|
||||
imaginary: '{{.ImaginaryURL}}',
|
||||
pages: [{{range $i, $p := .Pages}}{{if $i}},{{end}}{path: '{{$p.Path}}', prefix: '{{$p.Prefix}}'}{{end}}],
|
||||
urls: [],
|
||||
prefetched: new Set(),
|
||||
buildUrls() {
|
||||
this.urls = this.pages.map(p => {
|
||||
if (p.prefix === 'imaginary') {
|
||||
return this.imaginary + '/fit?width=' + this.width + '&height=' + this.height + '&file=' + encodeURIComponent(p.path);
|
||||
}
|
||||
return '/static/' + p.path;
|
||||
});
|
||||
this.prefetched.clear();
|
||||
},
|
||||
prefetch() {
|
||||
const img = new Image();
|
||||
img.onload = () => {
|
||||
for (let i = 1; i <= 10 && this.current + i < this.urls.length; i++) {
|
||||
const url = this.urls[this.current + i];
|
||||
if (!this.prefetched.has(url)) {
|
||||
this.prefetched.add(url);
|
||||
new Image().src = url;
|
||||
}
|
||||
}
|
||||
};
|
||||
img.src = this.urls[this.current];
|
||||
},
|
||||
swap() {
|
||||
this.landscape = !this.landscape;
|
||||
[this.width, this.height] = [this.height, this.width];
|
||||
this.buildUrls();
|
||||
},
|
||||
init() {
|
||||
this.buildUrls();
|
||||
this.prefetch();
|
||||
this.$watch('current', () => this.prefetch());
|
||||
}
|
||||
}"
|
||||
@keydown.window.left.prevent="current = Math.max(0, current - 1)"
|
||||
@keydown.window.right.prevent="current = Math.min(urls.length - 1, current + 1)"
|
||||
@keydown.window.k.prevent="swap()"
|
||||
@keydown.window.backspace.prevent="history.back()"
|
||||
autofocus
|
||||
>
|
||||
<div class="page" :class="landscape ? 'landscape' : ''" :style="'background-image: url(\'' + urls[current] + '\');'"></div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
41
templates/index.html
Normal file
41
templates/index.html
Normal file
|
|
@ -0,0 +1,41 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Henna</title>
|
||||
<script src="/assets/htmx.min.js" defer></script>
|
||||
<script src="/assets/alpine.min.js" defer></script>
|
||||
</head>
|
||||
<body style="margin: 0; background-color: black; overflow: hidden;">
|
||||
<div id="app"
|
||||
x-data="{active: 0, total: {{len .Covers}}, row: 6, chapter: {{.Chapter}}, prefix: '{{.Prefix}}', comics: [{{range $i, $c := .Covers}}{{if $i}},{{end}}{{$c.Comic}}{{end}}]}"
|
||||
@keydown.window.left.prevent="active = Math.max(0, active - 1)"
|
||||
@keydown.window.right.prevent="active = Math.min(total - 1, active + 1)"
|
||||
@keydown.window.up.prevent="active = Math.max(0, active - row)"
|
||||
@keydown.window.down.prevent="active = Math.min(total - 1, active + row)"
|
||||
@keydown.window.i.prevent="htmx.ajax('GET', prefix + '/' + chapter, {target: '#app', swap: 'outerHTML'})"
|
||||
@keydown.window.n.prevent="htmx.ajax('GET', prefix + '/' + Math.max(0, chapter - 2), {target: '#app', swap: 'outerHTML'})"
|
||||
@keydown.window.enter.prevent="window.location.href = '/gallery/' + comics[active]"
|
||||
@wheel.window.prevent="$event.deltaY > 0 ? htmx.ajax('GET', prefix + '/' + chapter, {target: '#app', swap: 'outerHTML'}) : htmx.ajax('GET', prefix + '/' + Math.max(0, chapter - 2), {target: '#app', swap: 'outerHTML'})"
|
||||
autofocus
|
||||
>
|
||||
<div>
|
||||
{{range $i, $c := .Covers}}
|
||||
<div class="cover" :class="{'active': active === {{$i}}}">
|
||||
<img src="{{$c.Url}}" width="300" height="370">
|
||||
</div>
|
||||
{{end}}
|
||||
</div>
|
||||
<style>
|
||||
.cover { display: inline-block; margin: 2px; outline: 2px solid transparent; }
|
||||
.cover.active { outline: 2px solid #0af; }
|
||||
</style>
|
||||
<script>
|
||||
setTimeout(() => {
|
||||
[{{range $i, $c := .Preload}}{{if $i}},{{end}}'{{$c.Url}}'{{end}}].forEach(url => new Image().src = url);
|
||||
}, 200);
|
||||
</script>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
Loading…
Add table
Add a link
Reference in a new issue