From a2cfae043e77d0e6d8782c60fe31e6da318c28cc Mon Sep 17 00:00:00 2001 From: Kentai Radiquum Date: Sat, 1 Feb 2025 17:39:37 +0500 Subject: [PATCH] add video page --- src/build.tsx | 15 +++ src/static/populateIndex.js | 19 ++- src/static/populateVideos.js | 56 ++++++++ src/static/tailwind.css | 24 ++++ src/static/utils.js | 139 ++++++++++++++++++-- src/templates/Components/PageNavigation.tsx | 59 ++++++--- src/templates/Components/PlaceHolderVid.tsx | 17 +++ src/templates/images.tsx | 4 +- src/templates/index.tsx | 25 +++- src/templates/videos.tsx | 14 ++ 10 files changed, 338 insertions(+), 34 deletions(-) create mode 100644 src/static/populateVideos.js create mode 100644 src/templates/Components/PlaceHolderVid.tsx create mode 100644 src/templates/videos.tsx diff --git a/src/build.tsx b/src/build.tsx index 46d818d..46768fa 100644 --- a/src/build.tsx +++ b/src/build.tsx @@ -20,6 +20,7 @@ import { S3Client, ListObjectsV2Command } from "@aws-sdk/client-s3"; import IndexPage from "./templates"; import type { ReactNode } from "react"; import ImagesPage from "./templates/images"; +import VideosPage from "./templates/videos"; const S3 = new S3Client({ region: "auto", @@ -222,3 +223,17 @@ generateHTMLFile( , "out/images/index.html" ); + +generateHTMLFile( + "Wah-Collection/Images", + "/videos/", + `Video page of Wah-Collection | ${videos.length} Videos`, + [ + environment == "dev" ? "/static/utils.js" : "/static/utils.min.js", + environment == "dev" + ? "/static/populateVideos.js" + : "/static/populateVideos.min.js", + ], + , + "out/videos/index.html" +); diff --git a/src/static/populateIndex.js b/src/static/populateIndex.js index e83fc9e..b21e33d 100644 --- a/src/static/populateIndex.js +++ b/src/static/populateIndex.js @@ -14,7 +14,7 @@ function randomElements(src, count) { async function populateIndex() { let config = await get("/data/config.json"); let images = await get("/data/images.json"); - // let videos = await get("/data/videos.json"); + let videos = await get("/data/videos.json"); const Images = document.querySelectorAll('[data-type="placeholder__image"]'); const VisibleImages = []; @@ -24,6 +24,14 @@ async function populateIndex() { } }); + const Videos = document.querySelectorAll('[data-type="placeholder__video"]'); + const VisibleVideos = []; + Videos.forEach((placeholder) => { + if (placeholder.checkVisibility()) { + VisibleVideos.push(placeholder); + } + }); + randomElements(images, VisibleImages.length).forEach((image, idx) => { renderImage( config.endpoint, @@ -34,6 +42,15 @@ async function populateIndex() { VisibleImages[idx] ); }); + + randomElements(videos, VisibleVideos.length).forEach((video, idx) => { + renderVideo( + config.endpoint, + config.bucket, + config.prefix, + video.src, + VisibleVideos[idx]) + }); } window.onload = () => { populateIndex(); diff --git a/src/static/populateVideos.js b/src/static/populateVideos.js new file mode 100644 index 0000000..36e7dd3 --- /dev/null +++ b/src/static/populateVideos.js @@ -0,0 +1,56 @@ +function PlaceholderVid() { + const placeholder = document.createElement("video"); + placeholder.dataset.type = "placeholder__video"; + placeholder.controls = true; + placeholder.className = + "relative aspect-square w-full h-full max-w-48 max-h-48 sm:max-w-none sm:max-h-none rounded-sm [&:not(:fullscreen)]:object-cover"; + + const placeholder_loader = document.createElement("div"); + placeholder_loader.dataset.type = "placeholder__video__loader"; + placeholder_loader.className = + "w-full h-full absolute inset-0 bg-gray-400 opacity-30 animate-pulse z-[3]"; + const placeholder_source = document.createElement("source"); + placeholder.appendChild(placeholder_loader); + placeholder.appendChild(placeholder_source); + + return placeholder; +} + +async function __tmp_loadVideos() { + const container = document.getElementById("videos_videos"); + + let config = await get("/data/config.json"); + let videos = await get("/data/videos.json"); + + const start = getOffset(); + const end = getOffset() + getVideosPerPage(); + + const url = new URL(window.location.toString()); + + if (start < 0) { + url.searchParams.set("offset", 0); + window.location.href = url.href; + } else if (end > videos.length) { + url.searchParams.set("offset", videos.length - getVideosPerPage()); + window.location.href = url.href; + } + + videos.slice(start, end).forEach((video, idx) => { + container.appendChild(PlaceholderVid()); + let videos = document.querySelectorAll('[data-type="placeholder__video"]'); + setTimeout(() => { + renderVideo( + config.endpoint, + config.bucket, + config.prefix, + video, + videos[idx] + ); + }, 250); + }); +} + +window.onload = () => { + enableNav(); + __tmp_loadVideos(); +}; diff --git a/src/static/tailwind.css b/src/static/tailwind.css index ce6c1d9..6131cca 100644 --- a/src/static/tailwind.css +++ b/src/static/tailwind.css @@ -587,6 +587,9 @@ .mt-2 { margin-top: calc(var(--spacing) * 2); } + .mb-4 { + margin-bottom: calc(var(--spacing) * 4); + } .contents { display: contents; } @@ -620,6 +623,9 @@ .h-full { height: 100%; } + .max-h-48 { + max-height: calc(var(--spacing) * 48); + } .min-h-16 { min-height: calc(var(--spacing) * 16); } @@ -635,6 +641,9 @@ .w-full { width: 100%; } + .max-w-48 { + max-width: calc(var(--spacing) * 48); + } .min-w-48 { min-width: calc(var(--spacing) * 48); } @@ -772,6 +781,16 @@ height: calc(var(--spacing) * 10); } } + .sm\:max-h-none { + @media (width >= 40rem) { + max-height: none; + } + } + .sm\:max-w-none { + @media (width >= 40rem) { + max-width: none; + } + } .sm\:min-w-auto { @media (width >= 40rem) { min-width: auto; @@ -854,6 +873,11 @@ color: #f9ebeb; } } + .\[\&\:not\(\:fullscreen\)\]\:object-cover { + &:not(:fullscreen) { + object-fit: cover; + } + } } .material-symbols--arrow-forward-rounded { display: inline-block; diff --git a/src/static/utils.js b/src/static/utils.js index efdb5fb..f42b121 100644 --- a/src/static/utils.js +++ b/src/static/utils.js @@ -9,6 +9,9 @@ async function get(url) { function getAspect(image) { return Number(image.naturalWidth / image.naturalHeight); } +function getAspectVid(video) { + return Number(video.videoWidth / video.videoHeight); +} function renderImage(endpoint, bucket, prefix, isrc, iid, placeholder) { const src = `${endpoint}/${bucket}/${prefix}/${isrc}`; @@ -34,7 +37,12 @@ function renderImage(endpoint, bucket, prefix, isrc, iid, placeholder) { placeholder.appendChild(blurImg); placeholder.appendChild(Img); - if (view == "masonry" && ["/images", "/images/", "/images/index.html"].includes(window.location.pathname)) { + if ( + view == "masonry" && + ["/images", "/images/", "/images/index.html"].includes( + window.location.pathname + ) + ) { container.classList.remove( "xl:grid-cols-[repeat(auto-fill,minmax(20%,1fr))]" ); @@ -75,6 +83,55 @@ function renderImage(endpoint, bucket, prefix, isrc, iid, placeholder) { }); } +function renderVideo(endpoint, bucket, prefix, vsrc, placeholder) { + const loader = placeholder.querySelector( + '[data-type="placeholder__video__loader"]' + ); + + const view = getView(); + const container = document.getElementById("videos_videos"); + + const source = placeholder.querySelector("source"); + const ext = vsrc.split(".")[vsrc.split(".").length - 1]; + placeholder.src = `${endpoint}/${bucket}/${prefix}/${vsrc}`; + placeholder.preload = "metadata"; + source.src = `${endpoint}/${bucket}/${prefix}/${vsrc}`; + source.type = `video/${ext}`; + + if ( + view == "masonry" && + ["/videos", "/videos/", "/videos/index.html"].includes( + window.location.pathname + ) + ) { + container.classList.remove( + "xl:grid-cols-[repeat(auto-fill,minmax(20%,1fr))]" + ); + container.classList.add("xl:grid-cols-[repeat(6,minmax(180px,1fr))]"); + container.classList.add("xl:[grid-auto-flow:_row_dense]"); + + placeholder.addEventListener("loadedmetadata", () => { + const aspect = getAspectVid(placeholder); + + if (aspect < 0.95) { + placeholder.classList.remove("aspect-square"); + placeholder.classList.add("aspect-[1/2]"); + placeholder.classList.add("w-full"); + placeholder.classList.add("h-full"); + placeholder.classList.add("[grid-row:span_2]"); + } else if (aspect > 1.05) { + placeholder.classList.remove("aspect-square"); + placeholder.classList.add("aspect-[2/1]"); + placeholder.classList.add("w-full"); + placeholder.classList.add("h-full"); + placeholder.classList.add("[grid-column:span_2]"); + } + + placeholder.removeEventListener("loadedmetadata", this); + }); + } +} + function setView(view) { localStorage.setItem("view", view); } @@ -130,6 +187,43 @@ function getImagesPerPage() { return count; } +function setVideosPerPage(count) { + localStorage.setItem("VideosPP", count); +} +function getVideosPerPage() { + let count = localStorage.getItem("VideosPP"); + const url = new URL(window.location.toString()); + const countParam = url.searchParams.get("VideosPP"); + + if (!count && !countParam) { + setVideosPerPage(24); + url.searchParams.set("VideosPP", 24); + count = Number(24); + } else if (countParam) { + count = Number(countParam); + } else if (count) { + url.searchParams.set("VideosPP", count); + window.history.pushState( + "", + `Wah-Collection/Videos`, + `?${url.searchParams.toString()}` + ); + count = Number(count); + } else { + count = 24; + } + + const active = document.querySelectorAll(`[data-ipp="${count}"]`); + if (active.length > 0) { + active.forEach((item) => { + item.classList.add("underline"); + item.classList.add("text-orange-500"); + item.classList.add("font-bold"); + }); + } + return count; +} + function setOffset(offset) { const url = new URL(window.location.toString()); url.searchParams.set("offset", offset); @@ -146,19 +240,40 @@ function getOffset() { } function enableNav() { - function handleClickPrev() { - setOffset(getOffset() - getImagesPerPage()); - } + if ( + ["/images", "/images/", "/images/index.html"].includes( + window.location.pathname + ) + ) { + function handleClickPrev() { + setOffset(getOffset() - getImagesPerPage()); + } - function handleClickNext() { - setOffset(getOffset() + getImagesPerPage()); - } + function handleClickNext() { + setOffset(getOffset() + getImagesPerPage()); + } - function handleClickIpp(ipp) { - setImagesPerPage(ipp); - const url = new URL(window.location.toString()); - url.searchParams.set("ImagesPP", ipp); - window.location.href = url.href; + function handleClickIpp(ipp) { + setImagesPerPage(ipp); + const url = new URL(window.location.toString()); + url.searchParams.set("ImagesPP", ipp); + window.location.href = url.href; + } + } else { + function handleClickPrev() { + setOffset(getOffset() - getVideosPerPage()); + } + + function handleClickNext() { + setOffset(getOffset() + getVideosPerPage()); + } + + function handleClickIpp(ipp) { + setVideosPerPage(ipp); + const url = new URL(window.location.toString()); + url.searchParams.set("VideosPP", ipp); + window.location.href = url.href; + } } function handleClickView(view) { diff --git a/src/templates/Components/PageNavigation.tsx b/src/templates/Components/PageNavigation.tsx index a7706d6..bd39877 100644 --- a/src/templates/Components/PageNavigation.tsx +++ b/src/templates/Components/PageNavigation.tsx @@ -1,32 +1,57 @@ -export default function PageNav() { - - const ipp = [12,24,32,48,72,100,250,500,1000] +export default function PageNav(props: { path: string }) { + let ipp; + if (props.path == "/images") { + ipp = [12, 24, 32, 48, 72, 100, 250, 500, 1000]; + } else { + ipp = [24, 48, 72, 100]; + } return (
-
{ipp.map((item, idx) => { - return + return ( + + ); })}
- - + +
-
diff --git a/src/templates/Components/PlaceHolderVid.tsx b/src/templates/Components/PlaceHolderVid.tsx new file mode 100644 index 0000000..1f27637 --- /dev/null +++ b/src/templates/Components/PlaceHolderVid.tsx @@ -0,0 +1,17 @@ +export default function PlaceholderVid(props: { isMobileHidden?: boolean }) { + return ( + + ); +} diff --git a/src/templates/images.tsx b/src/templates/images.tsx index 76d1f83..5437978 100644 --- a/src/templates/images.tsx +++ b/src/templates/images.tsx @@ -3,12 +3,12 @@ import PageNav from "./Components/PageNavigation"; export default function ImagesPage() { return ( <> - +
- + ); } diff --git a/src/templates/index.tsx b/src/templates/index.tsx index 9984b14..3118bb6 100644 --- a/src/templates/index.tsx +++ b/src/templates/index.tsx @@ -1,5 +1,6 @@ import AllLink from "./Components/AllLink"; import Placeholder from "./Components/PlaceHolder"; +import PlaceholderVid from "./Components/PlaceHolderVid"; export default function IndexPage() { return ( @@ -7,13 +8,33 @@ export default function IndexPage() {

Images

{[...Array(7).keys()].map((idx) => { - return 4} />; + return ( + 4} + /> + ); })}
+

Videos

+
+ {[...Array(3).keys()].map((idx) => { + return ( + 1} + /> + ); + })} + +
); } diff --git a/src/templates/videos.tsx b/src/templates/videos.tsx new file mode 100644 index 0000000..5e34664 --- /dev/null +++ b/src/templates/videos.tsx @@ -0,0 +1,14 @@ +import PageNav from "./Components/PageNavigation"; + +export default function VideosPage() { + return ( + <> + +
+ + + ); +}