mirror of
https://github.com/wah-su/wahs.wah.su.git
synced 2025-04-09 01:34:37 +00:00
add navigation
This commit is contained in:
parent
889c8c0d37
commit
5e30c48bac
8 changed files with 325 additions and 49 deletions
|
@ -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"
|
||||
);
|
||||
|
|
|
@ -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%;
|
||||
}
|
56
src/static/populateImages.js
Normal file
56
src/static/populateImages.js
Normal 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();
|
||||
};
|
|
@ -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);
|
||||
});
|
||||
}
|
|
@ -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
101
src/static/utils.js
Normal 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)
|
||||
})
|
||||
|
||||
}
|
12
src/templates/Components/PageNavigation.tsx
Normal file
12
src/templates/Components/PageNavigation.tsx
Normal 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
14
src/templates/images.tsx
Normal 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 />
|
||||
</>
|
||||
);
|
||||
}
|
Loading…
Add table
Reference in a new issue