Some checks failed
Test examples / Test Examples (20) (push) Has been cancelled
Test examples / Test Examples (22) (push) Has been cancelled
Lock Threads / action (push) Has been cancelled
Trigger Release / start (push) Has been cancelled
Stale issue handler / stale (push) Has been cancelled
Update Font Data / create-pull-request (push) Has been cancelled
build-and-deploy / deploy-target (push) Has been cancelled
build-and-deploy / build (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-musl - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-unknown-linux-gnu - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-pc-windows-msvc - node@16 (push) Has been cancelled
build-and-deploy / stable - aarch64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / stable - x86_64-apple-darwin - node@16 (push) Has been cancelled
build-and-deploy / build-wasm (nodejs) (push) Has been cancelled
build-and-deploy / build-wasm (web) (push) Has been cancelled
build-and-deploy / Deploy preview tarball (push) Has been cancelled
build-and-deploy / Potentially publish release (push) Has been cancelled
build-and-deploy / publish-turbopack-npm-packages (push) Has been cancelled
build-and-deploy / Deploy examples (push) Has been cancelled
build-and-deploy / thank you, build (push) Has been cancelled
build-and-deploy / Upload Turbopack Bytesize metrics to Datadog (push) Has been cancelled
Rspack Next.js development integration tests / Rspack integration tests (push) Has been cancelled
Rspack Next.js production integration tests / Rspack integration tests (push) Has been cancelled
Turbopack Next.js development integration tests / Next.js integration tests (push) Has been cancelled
Turbopack Next.js production integration tests / Next.js integration tests (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack development test manifest (push) Has been cancelled
Update Rspack test manifest / Update and upload Rspack production test manifest (push) Has been cancelled
Upload bundler test manifests to areweturboyet.com / Upload test results (push) Has been cancelled
Update React / create-pull-request (push) Has been cancelled
test-e2e-project-reset-cron / reset-test-project (push) Has been cancelled
Notify about the top 15 issues/PRs/feature requests (most reacted) in the last 90 days / run (push) Has been cancelled
175 lines
6.4 KiB
TypeScript
175 lines
6.4 KiB
TypeScript
import type { NextPage } from "next";
|
|
import Head from "next/head";
|
|
import Image from "next/image";
|
|
import Link from "next/link";
|
|
import { useRouter } from "next/router";
|
|
import { useEffect, useRef } from "react";
|
|
import Bridge from "../components/Icons/Bridge";
|
|
import Logo from "../components/Icons/Logo";
|
|
import Modal from "../components/Modal";
|
|
import cloudinary from "../utils/cloudinary";
|
|
import getBase64ImageUrl from "../utils/generateBlurPlaceholder";
|
|
import type { ImageProps } from "../utils/types";
|
|
import { useLastViewedPhoto } from "../utils/useLastViewedPhoto";
|
|
|
|
const Home: NextPage = ({ images }: { images: ImageProps[] }) => {
|
|
const router = useRouter();
|
|
const { photoId } = router.query;
|
|
const [lastViewedPhoto, setLastViewedPhoto] = useLastViewedPhoto();
|
|
|
|
const lastViewedPhotoRef = useRef<HTMLAnchorElement>(null);
|
|
|
|
useEffect(() => {
|
|
// This effect keeps track of the last viewed photo in the modal to keep the index page in sync when the user navigates back
|
|
if (lastViewedPhoto && !photoId) {
|
|
lastViewedPhotoRef.current.scrollIntoView({ block: "center" });
|
|
setLastViewedPhoto(null);
|
|
}
|
|
}, [photoId, lastViewedPhoto, setLastViewedPhoto]);
|
|
|
|
return (
|
|
<>
|
|
<Head>
|
|
<title>Next.js Conf 2022 Photos</title>
|
|
<meta
|
|
property="og:image"
|
|
content="https://nextjsconf-pics.vercel.app/og-image.png"
|
|
/>
|
|
<meta
|
|
name="twitter:image"
|
|
content="https://nextjsconf-pics.vercel.app/og-image.png"
|
|
/>
|
|
</Head>
|
|
<main className="mx-auto max-w-[1960px] p-4">
|
|
{photoId && (
|
|
<Modal
|
|
images={images}
|
|
onClose={() => {
|
|
setLastViewedPhoto(photoId);
|
|
}}
|
|
/>
|
|
)}
|
|
<div className="columns-1 gap-4 sm:columns-2 xl:columns-3 2xl:columns-4">
|
|
<div className="after:content relative mb-5 flex h-[629px] flex-col items-center justify-end gap-4 overflow-hidden rounded-lg bg-white/10 px-6 pb-16 pt-64 text-center text-white shadow-highlight after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:shadow-highlight lg:pt-0">
|
|
<div className="absolute inset-0 flex items-center justify-center opacity-20">
|
|
<span className="flex max-h-full max-w-full items-center justify-center">
|
|
<Bridge />
|
|
</span>
|
|
<span className="absolute left-0 right-0 bottom-0 h-[400px] bg-gradient-to-b from-black/0 via-black to-black"></span>
|
|
</div>
|
|
<Logo />
|
|
<h1 className="mt-8 mb-4 text-base font-bold uppercase tracking-widest">
|
|
2022 Event Photos
|
|
</h1>
|
|
<p className="max-w-[40ch] text-white/75 sm:max-w-[32ch]">
|
|
Our incredible Next.js community got together in San Francisco for
|
|
our first ever in-person conference!
|
|
</p>
|
|
<a
|
|
className="pointer z-10 mt-6 rounded-lg border border-white bg-white px-3 py-2 text-sm font-semibold text-black transition hover:bg-white/10 hover:text-white md:mt-4"
|
|
href="https://vercel.com/new/clone?repository-url=https://github.com/vercel/next.js/tree/canary/examples/with-cloudinary&project-name=nextjs-image-gallery&repository-name=with-cloudinary&env=NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME,CLOUDINARY_API_KEY,CLOUDINARY_API_SECRET,CLOUDINARY_FOLDER&envDescription=API%20Keys%20from%20Cloudinary%20needed%20to%20run%20this%20application"
|
|
target="_blank"
|
|
rel="noreferrer"
|
|
>
|
|
Clone and Deploy
|
|
</a>
|
|
</div>
|
|
{images.map(({ id, public_id, format, blurDataUrl }) => (
|
|
<Link
|
|
key={id}
|
|
href={`/?photoId=${id}`}
|
|
as={`/p/${id}`}
|
|
ref={id === Number(lastViewedPhoto) ? lastViewedPhotoRef : null}
|
|
shallow
|
|
className="after:content group relative mb-5 block w-full cursor-zoom-in after:pointer-events-none after:absolute after:inset-0 after:rounded-lg after:shadow-highlight"
|
|
>
|
|
<Image
|
|
alt="Next.js Conf photo"
|
|
className="transform rounded-lg brightness-90 transition will-change-auto group-hover:brightness-110"
|
|
style={{ transform: "translate3d(0, 0, 0)" }}
|
|
placeholder="blur"
|
|
blurDataURL={blurDataUrl}
|
|
src={`https://res.cloudinary.com/${process.env.NEXT_PUBLIC_CLOUDINARY_CLOUD_NAME}/image/upload/c_scale,w_720/${public_id}.${format}`}
|
|
width={720}
|
|
height={480}
|
|
sizes="(max-width: 640px) 100vw,
|
|
(max-width: 1280px) 50vw,
|
|
(max-width: 1536px) 33vw,
|
|
25vw"
|
|
/>
|
|
</Link>
|
|
))}
|
|
</div>
|
|
</main>
|
|
<footer className="p-6 text-center text-white/80 sm:p-12">
|
|
Thank you to{" "}
|
|
<a
|
|
href="https://edelsonphotography.com/"
|
|
target="_blank"
|
|
className="font-semibold hover:text-white"
|
|
rel="noreferrer"
|
|
>
|
|
Josh Edelson
|
|
</a>
|
|
,{" "}
|
|
<a
|
|
href="https://www.newrevmedia.com/"
|
|
target="_blank"
|
|
className="font-semibold hover:text-white"
|
|
rel="noreferrer"
|
|
>
|
|
Jenny Morgan
|
|
</a>
|
|
, and{" "}
|
|
<a
|
|
href="https://www.garysextonphotography.com/"
|
|
target="_blank"
|
|
className="font-semibold hover:text-white"
|
|
rel="noreferrer"
|
|
>
|
|
Gary Sexton
|
|
</a>{" "}
|
|
for the pictures.
|
|
</footer>
|
|
</>
|
|
);
|
|
};
|
|
|
|
export default Home;
|
|
|
|
export async function getStaticProps() {
|
|
const results = await cloudinary.v2.search
|
|
.expression(`folder:${process.env.CLOUDINARY_FOLDER}/*`)
|
|
.sort_by("public_id", "desc")
|
|
.max_results(400)
|
|
.execute();
|
|
let reducedResults: ImageProps[] = [];
|
|
|
|
let i = 0;
|
|
for (let result of results.resources) {
|
|
reducedResults.push({
|
|
id: i,
|
|
height: result.height,
|
|
width: result.width,
|
|
public_id: result.public_id,
|
|
format: result.format,
|
|
});
|
|
i++;
|
|
}
|
|
|
|
const blurImagePromises = results.resources.map((image: ImageProps) => {
|
|
return getBase64ImageUrl(image);
|
|
});
|
|
const imagesWithBlurDataUrls = await Promise.all(blurImagePromises);
|
|
|
|
for (let i = 0; i < reducedResults.length; i++) {
|
|
reducedResults[i].blurDataUrl = imagesWithBlurDataUrls[i];
|
|
}
|
|
|
|
return {
|
|
props: {
|
|
images: reducedResults,
|
|
},
|
|
};
|
|
}
|