add navigation

This commit is contained in:
Kentai Radiquum 2025-02-01 01:00:12 +05:00
parent 889c8c0d37
commit 5e30c48bac
Signed by: Radiquum
GPG key ID: 858E8EE696525EED
8 changed files with 325 additions and 49 deletions

View file

@ -19,6 +19,7 @@ if (!fs.existsSync("out")) fs.mkdirSync("out");
import { S3Client, ListObjectsV2Command } from "@aws-sdk/client-s3";
import IndexPage from "./templates";
import type { ReactNode } from "react";
import ImagesPage from "./templates/images";
const S3 = new S3Client({
region: "auto",
@ -132,13 +133,13 @@ function generateHTMLFile(
url: process.env.WEB_URL as string,
preload: [
`${
environment == "prod" ? process.env.WEB_URL : "."
environment == "prod" ? process.env.WEB_URL : ""
}/data/config.json`,
`${
environment == "prod" ? process.env.WEB_URL : "."
environment == "prod" ? process.env.WEB_URL : ""
}/data/images.json`,
`${
environment == "prod" ? process.env.WEB_URL : "."
environment == "prod" ? process.env.WEB_URL : ""
}/data/videos.json`,
],
dns: [process.env.ENDPOINT as string, "https://wsrv.nl"],
@ -199,9 +200,7 @@ generateHTMLFile(
videos.length
} Videos | ${images.length + videos.length} Total`,
[
environment == "dev"
? "/static/renderImages.js"
: "/static/renderImages.min.js",
environment == "dev" ? "/static/utils.js" : "/static/utils.min.js",
environment == "dev"
? "/static/populateIndex.js"
: "/static/populateIndex.min.js",
@ -214,8 +213,12 @@ generateHTMLFile(
"Wah-Collection/Images",
"/images/",
`Image page of Wah-Collection | ${images.length} Images`,
[],
// <IndexPage />,
<p>There Should Be Red Pandas!</p>,
[
environment == "dev" ? "/static/utils.js" : "/static/utils.min.js",
environment == "dev"
? "/static/populateImages.js"
: "/static/populateImages.min.js",
],
<ImagesPage />,
"out/images/index.html"
);

View file

@ -8,4 +8,28 @@
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
.material-symbols--navigate-next {
display: inline-block;
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12.6 12L8 7.4L9.4 6l6 6l-6 6L8 16.6z'/%3E%3C/svg%3E");
background-color: currentColor;
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
.material-symbols--navigate-before {
display: inline-block;
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='m14 18l-6-6l6-6l1.4 1.4l-4.6 4.6l4.6 4.6z'/%3E%3C/svg%3E");
background-color: currentColor;
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}

View file

@ -0,0 +1,56 @@
function Placeholder() {
const placeholder = document.createElement("a");
placeholder.dataset.type = "placeholder__image";
placeholder.className =
"relative aspect-square min-w-48 sm:min-w-auto rounded-sm overflow-hidden";
const placeholder_loader = document.createElement("div");
placeholder_loader.dataset.type = "placeholder__image__loader";
placeholder_loader.className =
"w-full h-full absolute inset-0 bg-gray-400 opacity-30 animate-pulse z-[3]";
placeholder.appendChild(placeholder_loader);
return placeholder;
}
async function __tmp_loadImages() {
const container = document.getElementById("images_images");
let config = await get("/data/config.json");
let images = await get("/data/images.json");
const start = getOffset();
const end = getOffset() + getImagesPerPage();
const url = new URL(window.location.toString());
if (start < 0) {
url.searchParams.set("offset", 0);
window.location.href = url.href;
} else if (end > images.length) {
url.searchParams.set("offset", images.length - getImagesPerPage());
window.location.href = url.href;
}
images.slice(start, end).forEach((image, idx) => {
container.appendChild(Placeholder());
let Images = document.querySelectorAll('[data-type="placeholder__image"]');
const iid = Number(start) + Number(idx);
setTimeout(() => {
renderImage(
config.endpoint,
config.bucket,
config.prefix,
image,
iid,
Images[idx]
);
}, 250);
});
}
window.onload = () => {
enableNav();
__tmp_loadImages();
};

View file

@ -1,37 +0,0 @@
async function get(url) {
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to fetch ${url}`);
}
return await res.json();
}
function renderImage(endpoint, bucket, prefix, isrc, iid, placeholder) {
const src = `${endpoint}/${bucket}/${prefix}/${isrc}`;
const loader = placeholder.querySelector(
'[data-type="placeholder__image__loader"]'
);
const blurImg = document.createElement("img");
const Img = document.createElement("img");
blurImg.src = `https://wsrv.nl/?url=${encodeURI(src)}&w=16&h=16`;
blurImg.className = "object-cover w-full h-full absolute inset-0";
blurImg.loading = "lazy";
Img.src = `https://wsrv.nl/?url=${encodeURI(src)}&w=256&h=256`;
Img.srcset = `https://wsrv.nl/?url=${encodeURI(
src
)}&w=256&h=256 256w, https://wsrv.nl/?url=${encodeURI(src)}&w=512&h=512 512w`;
Img.sizes = `(max-width: 600px) 256px, 512px`;
Img.className = "invisible object-cover w-full h-full absolute inset-0";
Img.loading = "lazy";
placeholder.appendChild(blurImg);
placeholder.appendChild(Img);
Img.addEventListener("load", () => {
Img.classList.remove("invisible");
blurImg.remove();
loader.remove();
placeholder.href = `/image/?id=${iid}`;
Img.removeEventListener("load", this);
});
}

View file

@ -578,6 +578,9 @@
.mx-auto {
margin-inline: auto;
}
.my-4 {
margin-block: calc(var(--spacing) * 4);
}
.mt-4 {
margin-top: calc(var(--spacing) * 4);
}
@ -641,9 +644,45 @@
.animate-pulse {
animation: var(--animate-pulse);
}
.cursor-pointer {
cursor: pointer;
}
.resize {
resize: both;
}
.grid-cols-\[repeat\(auto-fill\,1fr\)\] {
grid-template-columns: repeat(auto-fill,1fr);
}
.grid-cols-\[repeat\(auto-fill\,minmax\(1fr\,1fr\)\)\] {
grid-template-columns: repeat(auto-fill,minmax(1fr,1fr));
}
.grid-cols-\[repeat\(auto-fill\,minmax\(5\%\,1fr\)\)\] {
grid-template-columns: repeat(auto-fill,minmax(5%,1fr));
}
.grid-cols-\[repeat\(auto-fill\,minmax\(25\%\,1fr\)\)\] {
grid-template-columns: repeat(auto-fill,minmax(25%,1fr));
}
.grid-cols-\[repeat\(auto-fill\,minmax\(250px\,1fr\)\)\] {
grid-template-columns: repeat(auto-fill,minmax(250px,1fr));
}
.grid-cols-\[repeat\(auto-fill\,minmax\(25vw\,1fr\)\)\] {
grid-template-columns: repeat(auto-fill,minmax(25vw,1fr));
}
.grid-cols-\[repeat\(auto-fill\,minmax\(40\%\,1fr\)\)\] {
grid-template-columns: repeat(auto-fill,minmax(40%,1fr));
}
.grid-cols-\[repeat\(auto-fill\,minmax\(40vw\,1fr\)\)\] {
grid-template-columns: repeat(auto-fill,minmax(40vw,1fr));
}
.grid-cols-\[repeat\(auto-fill\,minmax\(45vw\,1fr\)\)\] {
grid-template-columns: repeat(auto-fill,minmax(45vw,1fr));
}
.grid-cols-\[repeat\(auto-fill\,minmax\(50\%\,1fr\)\)\] {
grid-template-columns: repeat(auto-fill,minmax(50%,1fr));
}
.grid-cols-\[repeat\(auto-fill\,minmax\(50vw\,1fr\)\)\] {
grid-template-columns: repeat(auto-fill,minmax(50vw,1fr));
}
.flex-col {
flex-direction: column;
}
@ -682,9 +721,6 @@
.bg-gray-400 {
background-color: var(--color-gray-400);
}
.bg-orange-600 {
background-color: var(--color-orange-600);
}
.bg-orange-800 {
background-color: var(--color-orange-800);
}
@ -706,6 +742,9 @@
.px-4 {
padding-inline: calc(var(--spacing) * 4);
}
.py-2 {
padding-block: calc(var(--spacing) * 2);
}
.py-4 {
padding-block: calc(var(--spacing) * 4);
}
@ -723,6 +762,9 @@
.text-\[\#f9ebeb\] {
color: #f9ebeb;
}
.text-white {
color: var(--color-white);
}
.underline {
text-decoration-line: underline;
}
@ -733,6 +775,9 @@
outline-style: var(--tw-outline-style);
outline-width: 1px;
}
.filter {
filter: var(--tw-blur,) var(--tw-brightness,) var(--tw-contrast,) var(--tw-grayscale,) var(--tw-hue-rotate,) var(--tw-invert,) var(--tw-saturate,) var(--tw-sepia,) var(--tw-drop-shadow,);
}
.transition-colors {
transition-property: color, background-color, border-color, outline-color, text-decoration-color, fill, stroke, --tw-gradient-from, --tw-gradient-via, --tw-gradient-to;
transition-timing-function: var(--tw-ease, var(--default-transition-timing-function));
@ -823,6 +868,28 @@
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
.material-symbols--navigate-next {
display: inline-block;
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='M12.6 12L8 7.4L9.4 6l6 6l-6 6L8 16.6z'/%3E%3C/svg%3E");
background-color: currentColor;
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
.material-symbols--navigate-before {
display: inline-block;
--svg: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24'%3E%3Cpath fill='%23000' d='m14 18l-6-6l6-6l1.4 1.4l-4.6 4.6l4.6 4.6z'/%3E%3C/svg%3E");
background-color: currentColor;
-webkit-mask-image: var(--svg);
mask-image: var(--svg);
-webkit-mask-repeat: no-repeat;
mask-repeat: no-repeat;
-webkit-mask-size: 100% 100%;
mask-size: 100% 100%;
}
@keyframes spin {
to {
transform: rotate(360deg);
@ -884,3 +951,39 @@
inherits: false;
initial-value: solid;
}
@property --tw-blur {
syntax: "*";
inherits: false;
}
@property --tw-brightness {
syntax: "*";
inherits: false;
}
@property --tw-contrast {
syntax: "*";
inherits: false;
}
@property --tw-grayscale {
syntax: "*";
inherits: false;
}
@property --tw-hue-rotate {
syntax: "*";
inherits: false;
}
@property --tw-invert {
syntax: "*";
inherits: false;
}
@property --tw-opacity {
syntax: "*";
inherits: false;
}
@property --tw-saturate {
syntax: "*";
inherits: false;
}
@property --tw-sepia {
syntax: "*";
inherits: false;
}

101
src/static/utils.js Normal file
View file

@ -0,0 +1,101 @@
async function get(url) {
const res = await fetch(url);
if (!res.ok) {
throw new Error(`Failed to fetch ${url}`);
}
return await res.json();
}
function renderImage(endpoint, bucket, prefix, isrc, iid, placeholder) {
const src = `${endpoint}/${bucket}/${prefix}/${isrc}`;
const loader = placeholder.querySelector(
'[data-type="placeholder__image__loader"]'
);
const blurImg = document.createElement("img");
const Img = document.createElement("img");
blurImg.src = `https://wsrv.nl/?url=${encodeURI(src)}&w=16&h=16`;
blurImg.className = "object-cover w-full h-full absolute inset-0";
blurImg.loading = "lazy";
Img.src = `https://wsrv.nl/?url=${encodeURI(src)}&w=256&h=256`;
Img.srcset = `https://wsrv.nl/?url=${encodeURI(
src
)}&w=256&h=256 256w, https://wsrv.nl/?url=${encodeURI(src)}&w=512&h=512 512w`;
Img.sizes = `(max-width: 600px) 256px, 512px`;
Img.className = "invisible object-cover w-full h-full absolute inset-0";
Img.loading = "lazy";
placeholder.appendChild(blurImg);
placeholder.appendChild(Img);
Img.addEventListener("load", () => {
Img.classList.remove("invisible");
blurImg.remove();
loader.remove();
placeholder.href = `/image/?id=${iid}`;
Img.removeEventListener("load", this);
});
}
function setImagesPerPage(count) {
localStorage.setItem("ImagesPP", count);
}
function getImagesPerPage() {
const count = localStorage.getItem("ImagesPP");
const url = new URL(window.location.toString());
const countParam = url.searchParams.get("ImagesPP");
if (!count && !countParam) {
setImagesPerPage(24);
url.searchParams.set("ImagesPP", 24);
return Number(24);
} else if (countParam) {
return Number(countParam);
} else if (count) {
url.searchParams.set("ImagesPP", count);
window.history.pushState(
{ offset: getOffset(), ImagesPP: count },
`Wah-Collection/Images`,
`?${url.searchParams.toString()}`
);
return Number(count);
} else {
return 24;
}
}
function setOffset(offset) {
const url = new URL(window.location.toString());
url.searchParams.set("offset", offset);
window.location.href = url.href;
}
function getOffset() {
const url = new URL(window.location.toString());
const offset = url.searchParams.get("offset");
if (!offset) {
return 0;
}
return Number(offset);
}
function enableNav() {
function handleClickPrev() {
setOffset(getOffset() - getImagesPerPage())
}
function handleClickNext() {
setOffset(getOffset() + getImagesPerPage())
}
const nav_prev = document.querySelectorAll("#nav_prev")
const nav_next = document.querySelectorAll("#nav_next")
nav_prev.forEach((item) => {
item.addEventListener('click', handleClickPrev)
})
nav_next.forEach((item) => {
item.addEventListener('click', handleClickNext)
})
}

View file

@ -0,0 +1,12 @@
export default function PageNav() {
return (
<div className="bg-orange-800/50 rounded-sm py-2 text-white flex justify-between gap-4 items-center">
<button className="flex justify-center gap-4 items-center cursor-pointer" id="nav_prev">
<div className="material-symbols--navigate-before w-16 h-16"></div>
</button>
<button className="flex justify-center gap-4 items-center cursor-pointer" id="nav_next">
<div className="material-symbols--navigate-next w-16 h-16"></div>
</button>
</div>
);
}

14
src/templates/images.tsx Normal file
View file

@ -0,0 +1,14 @@
import PageNav from "./Components/PageNavigation";
export default function ImagesPage() {
return (
<>
<PageNav />
<div
id="images_images"
className="my-4 overflow-hidden grid grid-cols-[repeat(auto-fill,minmax(250px,1fr))] xl:grid-cols-[repeat(auto-fill,minmax(20%,1fr))] sm:items-center sm:justify-center gap-4"
></div>
<PageNav />
</>
);
}