Skip to content

Commit

Permalink
Merge pull request #137 from IgorKowalczyk/photohraphy
Browse files Browse the repository at this point in the history
Rebuild photography page
  • Loading branch information
IgorKowalczyk authored Sep 16, 2022
2 parents 60e2da4 + dc520e2 commit 5e57127
Show file tree
Hide file tree
Showing 11 changed files with 171 additions and 172 deletions.
17 changes: 9 additions & 8 deletions components/elements/BlurImage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@ import Image from "next/image";
import * as FutureImage from "next/future/image";
import { useState } from "react";
import { PlusIcon } from "@heroicons/react/24/outline";
// Todo: wait for layout="raw" to be supported by Next.js

export function BlurImage({ image }) {
export function BlurImage({ src, alt }) {
const [isLoading, setLoading] = useState(true);
return (
<div className="group">
<Image src={image.url} alt={image.name} className={`${isLoading ? "scale-110 blur-2xl grayscale" : "scale-100 blur-0 grayscale-0"} rounded-lg bg-zinc-200 duration-200 group-hover:opacity-75 dark:bg-zinc-200/[15%]`} onLoadingComplete={() => setLoading(false)} layout="fill" objectFit="cover" />
<div className="absolute inset-0 flex items-center justify-center opacity-0 duration-300 group-hover:opacity-100 motion-reduce:transition-none">
<PlusIcon className="h-9 w-9 text-white" />
<a href={src} target="_blank" rel="noreferrer" className="group">
<div className="group aspect-w-1 aspect-h-1 w-full overflow-hidden xl:aspect-w-5 xl:aspect-h-5">
<Image src={src} alt={alt} className={`${isLoading ? "scale-110 blur-2xl grayscale" : "scale-100 blur-0 grayscale-0"} rounded-lg bg-zinc-200 duration-200 group-hover:opacity-75 dark:bg-zinc-200/[15%]`} onLoadingComplete={() => setLoading(false)} layout="fill" objectFit="cover" />
<div className="absolute inset-0 flex items-center justify-center opacity-0 duration-300 group-hover:opacity-100 motion-reduce:transition-none">
<PlusIcon className="h-9 w-9 text-white" />
</div>
</div>
</div>
</a>
);
}

export function BlurPreview({ image }) {
const [isLoading, setLoading] = useState(true);
return <FutureImage src={image.src} alt={image.src} className={`${isLoading ? "scale-110 blur-2xl grayscale" : "scale-100 blur-0 grayscale-0"} z-[5] h-10 w-10 rounded-full border-2 border-[#e6e6e9] bg-zinc-200 duration-200 group-hover:border-[#f6f6f7] motion-reduce:transition-none dark:border-[#343c4d] dark:bg-zinc-200/[15%] dark:group-hover:border-[#474f63]`} onLoadingComplete={() => setLoading(false)} layout="raw" height="40" width="40" />;
return <FutureImage src={image} alt={image} className={`${isLoading ? "scale-110 blur-2xl grayscale" : "scale-100 blur-0 grayscale-0"} z-[5] h-10 w-10 rounded-full border-2 border-[#e6e6e9] bg-zinc-200 duration-200 group-hover:border-[#f6f6f7] motion-reduce:transition-none dark:border-[#343c4d] dark:bg-zinc-200/[15%] dark:group-hover:border-[#474f63]`} onLoadingComplete={() => setLoading(false)} layout="raw" height="40" width="40" />;
}
36 changes: 36 additions & 0 deletions components/photography/ImagesList.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import Link from "next/link";
import { CameraIcon } from "@heroicons/react/24/solid";
import { parseISO, format } from "date-fns";
import { BlurPreview } from "@components/elements/BlurImage";

export function ListElement({ title, description, slug, publishedAt, index, preview, count }) {
return (
<Link href={`/photography/${slug}`}>
<a className="w-full">
<li className="group mb-10 ml-6 -mt-3 rounded-2xl px-6 py-3 duration-200 hover:bg-zinc-200/50 motion-reduce:transition-none dark:hover:bg-white/10">
<span className="absolute -left-3 flex h-6 w-6 items-center justify-center rounded-full bg-blue-200 ring-8 ring-white dark:bg-blue-900 dark:ring-[#040d21]">
<CameraIcon className="h-3 w-3 text-blue-700 dark:text-blue-400" />
</span>
<header>
<h3 className="mb-1 flex items-center text-lg font-semibold text-slate-900 dark:text-white">
{title} {index === 0 && <span className="mr-2 ml-3 rounded bg-blue-200 px-2.5 py-0.5 text-sm font-medium dark:bg-white/10">🔥 Latest</span>}
</h3>
<time className="mb-2 block text-sm font-normal leading-none text-slate-500 dark:text-slate-500" dateTime={parseISO(publishedAt)}>
{format(parseISO(publishedAt), "MMMM dd, yyyy")}
</time>
</header>
<p className=" text-base font-normal text-slate-600 dark:text-slate-400">{description}</p>
{preview && preview.length > 0 && (
<div className="relative mb-2 flex -space-x-4 pt-2 group-hover:-space-x-3">
{preview.map((image, index) => (
<BlurPreview key={`${index}-image-prev`} image={image} />
))}
{count - preview.length > 0 && <p className="z-10 flex h-10 w-10 items-center justify-center rounded-full border-2 border-[#edeeef] bg-[#edeeef] font-poppins text-xs font-medium text-gray-600 duration-200 group-hover:border-[#f6f6f7] group-hover:bg-[#f0eff0] motion-reduce:transition-none dark:border-[#343c4d] dark:bg-[#2b3342] dark:text-gray-300 dark:group-hover:border-[#4a5367] dark:group-hover:bg-[#343c4d]">+{count - preview.length}</p>}
</div>
)}
<p className="inline-flex text-sm font-semibold text-[#1491ff]">Show more</p>
</li>
</a>
</Link>
);
}
17 changes: 16 additions & 1 deletion contentlayer.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -62,9 +62,24 @@ const OtherPage = defineDocumentType(() => ({
computedFields,
}));

const Photography = defineDocumentType(() => ({
name: "Photography",
filePathPattern: "photography/*.mdx",
contentType: "mdx",
fields: {
title: { type: "string", required: true },
description: { type: "string", required: true },
publishedAt: { type: "string", required: true },
author: { type: "string", required: true },
preview: { type: "string", required: true },
count: { type: "number", required: true },
},
computedFields,
}));

const contentLayerConfig = makeSource({
contentDirPath: "data",
documentTypes: [Blog, OtherPage],
documentTypes: [Blog, OtherPage, Photography],
mdx: {
remarkPlugins: [remarkGfm],
rehypePlugins: [
Expand Down
12 changes: 12 additions & 0 deletions data/photography/bologna.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
title: "Bologna, Italy"
publishedAt: "2022-07-20"
author: "Igor Kowalczyk"
description: "Photos taken during my month-long stay in Italy. I lived on the edge of the city, and I worked and visited various excellent places. "
preview: ["/photography/bologna/1.jpg", "/photography/bologna/2.jpg", "/photography/bologna/3.jpg"]
count: 10
---

<BlurImage src="/photography/bologna/1.jpg" alt="Bologna 01" />
<BlurImage src="/photography/bologna/2.jpg" alt="Bologna 02" />
<BlurImage src="/photography/bologna/3.jpg" alt="Bologna 03" />
31 changes: 0 additions & 31 deletions pages/api/photography/all.jsx

This file was deleted.

28 changes: 0 additions & 28 deletions pages/api/photography/bologna.jsx

This file was deleted.

52 changes: 0 additions & 52 deletions pages/photography/[image].jsx

This file was deleted.

54 changes: 54 additions & 0 deletions pages/photography/[slug].jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import MDXComponents from "@/components/MDX/Components";
import { Container } from "@components/elements/Container";
import { useMDXComponent } from "next-contentlayer/hooks";
import { allPhotographies } from "contentlayer/generated";
import { parseISO, format } from "date-fns";
import { meta } from "@/config";
import { BlurImage } from "@components/elements/BlurImage";
import Image from "next/image";

export default function Post({ post }) {
const Component = useMDXComponent(post.body.code);
return (
<Container title={`${meta.title} - ${post.title} `} description={post.summary} date={new Date(post.publishedAt).toISOString()} type="article">
<article className="mx-auto px-4 sm:px-6 lg:px-8">
<header className="mb-6 w-full">
<div className="mt-2 flex w-full flex-col items-center justify-center md:flex-row md:items-center">
<div>
<h1 className="mb-4 flex items-center justify-center box-decoration-clone bg-clip-text text-center font-poppins text-[2rem] font-semibold motion-reduce:transition-none">
{post.title}
<span className="bg-gradient-to-r from-[#6310ff] to-[#1491ff] box-decoration-clone bg-clip-text text-fill-transparent dark:from-[#a2facf] dark:to-[#64acff]">.</span>
</h1>
<div className="flex items-center">
<Image alt={meta.title} height={24} width={24} src="/assets/avatar.png" className="rounded-full" />
<time className="ml-2 text-sm text-gray-700 dark:text-gray-300" dateTime={parseISO(post.publishedAt)}>
{post.author} / {format(parseISO(post.publishedAt), "MMMM dd, yyyy")}
</time>
</div>
</div>
</div>
<p className="mt-4 pb-6 text-center font-poppins text-slate-600 dark:text-slate-400">{post.description}</p>
</header>

<div className="mx-auto max-w-2xl px-4 sm:px-6 lg:max-w-7xl lg:px-8">
<div className="grid grid-cols-1 gap-y-10 gap-x-6 sm:grid-cols-2 lg:grid-cols-3 xl:grid-cols-4 xl:gap-x-8">
<Component components={{ ...MDXComponents, BlurImage }} />
</div>
</div>
</article>
</Container>
);
}

export async function getStaticPaths() {
return {
paths: allPhotographies.map((p) => ({ params: { slug: p.slug } })),
fallback: false,
};
}

export async function getStaticProps({ params }) {
const post = allPhotographies.find((post) => post.slug === params.slug);

return { props: { post } };
}
89 changes: 39 additions & 50 deletions pages/photography/index.jsx
Original file line number Diff line number Diff line change
@@ -1,59 +1,48 @@
import NextLink from "next/link";
import { meta } from "@/config";
import { Container } from "@components/elements/Container";
import { ChevronRightIcon } from "@heroicons/react/24/outline";
import { BlurPreview } from "@components/elements/BlurImage";
import { SWR } from "@lib/swr";

export default function Photography({ props }) {
const { data: _categories } = SWR("/api/photography/all");
const categories = _categories ? _categories : null;
import { ListElement } from "@components/photography/ImagesList";
import { pick } from "contentlayer/client";
import { allPhotographies } from "contentlayer/generated";
import { meta } from "@/config";
import { useState } from "react";

export default function Photography({ photos }) {
const [searchValue, setSearchValue] = useState("");
const filteredPhotos = photos.filter((photo) => photo.title.toLowerCase().split(" ").join("").includes(searchValue.toLowerCase().split(" ").join("")) || photo.description.toLowerCase().split(" ").join("").includes(searchValue.toLowerCase().split(" ").join("")));
return (
<Container title={`${meta.title} - Photography`}>
<h1 className="my-6 flex flex-wrap items-center justify-center box-decoration-clone bg-clip-text text-center font-poppins text-[2rem] font-semibold motion-reduce:transition-none">
My photography<span className="bg-gradient-to-r from-[#6310ff] to-[#1491ff] box-decoration-clone bg-clip-text text-fill-transparent dark:from-[#a2facf] dark:to-[#64acff]">.</span>
</h1>
<section id={"photography"} className="mx-auto flex max-w-3xl scroll-mt-20 flex-col items-start justify-center px-6">
<div className="mx-auto mb-16 flex max-w-2xl flex-col items-start justify-center px-8">
<h1 className="mb-4 flex items-center justify-center box-decoration-clone bg-clip-text text-center font-poppins text-[2rem] font-semibold motion-reduce:transition-none">
My photography<span className="bg-gradient-to-r from-[#6310ff] to-[#1491ff] box-decoration-clone bg-clip-text text-fill-transparent dark:from-[#a2facf] dark:to-[#64acff]">.</span>
</h1>
<p className="pb-2 font-poppins text-slate-600 dark:text-slate-400">I call this page my second Instagram, here I upload photos taken by me in various places around the world. From Poland - my home country to Italy.</p>
<p className="pb-6 font-poppins text-slate-600 dark:text-slate-400">I love traveling, I love taking pictures, from every trip I bring back hundreds of different photos. Here you can browse through the best ones</p>
{_categories ? (
categories && (
<>
{categories?.map((category, index) => (
<NextLink href={category.slug} key={`${index}-image`}>
<a className="group mb-4 w-full cursor-pointer">
<article className="group flex flex-col justify-between rounded-md bg-zinc-200/[25%] px-6 py-4 duration-200 hover:bg-zinc-200/60 motion-reduce:transition-none dark:bg-white/[10%] dark:text-white dark:hover:bg-white/[15%]" key={category.id}>
<div className="flex flex-row justify-between">
<h4 className="relative flex w-full items-center text-lg font-medium text-gray-900 dark:text-gray-100 md:text-xl">
{category.name}
<ChevronRightIcon className="inline-block h-4 w-4 translate-x-[1px] opacity-0 duration-200 group-hover:translate-x-[5px] group-hover:opacity-100 motion-reduce:transition-none" />
</h4>
<p className="w-2/4 text-left text-gray-500 duration-200 motion-reduce:transition-none md:mb-0 md:text-right">{category.date}</p>
</div>
<p className="mt-2 text-slate-600 duration-200 motion-reduce:transition-none dark:text-slate-400">{category.description || "Nothing to say..."}</p>
{category.preview && category.preview.images.length > 0 && (
<div className="relative flex -space-x-4 pt-2 group-hover:-space-x-3">
{category.preview.images.map((image, index) => (
<BlurPreview key={`${index}-image-prev`} image={image} />
))}
{category.count - category.preview.images.length > 0 && <p className="z-10 flex h-10 w-10 items-center justify-center rounded-full border-2 border-[#edeeef] bg-[#edeeef] font-poppins text-xs font-medium text-gray-600 duration-200 group-hover:border-[#f6f6f7] group-hover:bg-[#f0eff0] motion-reduce:transition-none dark:border-[#343c4d] dark:bg-[#2b3342] dark:text-gray-300 dark:group-hover:border-[#4a5367] dark:group-hover:bg-[#343c4d]">+{category.count - category.preview.images.length}</p>}
</div>
)}
</article>
</a>
</NextLink>
))}
</>
)
) : (
<>
{Array.from({ length: 1 }).map((_, index) => (
<div key={index} className="mb-4 h-[140px] w-full animate-pulse rounded-md bg-zinc-200 dark:bg-zinc-200/[15%] dark:text-white" />
))}
</>
)}
</section>
<div className="relative mb-4 w-full">
<input aria-label="Search photos" type="text" onChange={(e) => setSearchValue(e.target.value)} placeholder="Search photos" className={`${!filteredPhotos.length ? "ring-rose-500 focus:text-rose-500 focus:dark:text-red-400" : ""} block w-full rounded-md bg-zinc-200/[25%] px-4 py-2 text-slate-900 outline-none duration-200 hover:bg-zinc-200/60 focus:bg-zinc-200/60 focus:shadow-md focus:ring dark:bg-slate-800 dark:text-slate-100`} />
<svg className="absolute right-3 top-[10px] h-5 w-5 text-slate-400 dark:text-slate-300" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z" />
</svg>
</div>
<h3 className="mt-8 mb-4 flex items-center justify-center box-decoration-clone bg-clip-text text-center font-poppins text-[1.7rem] font-semibold motion-reduce:transition-none">
All Photos<span className="bg-gradient-to-r from-[#6310ff] to-[#1491ff] box-decoration-clone bg-clip-text text-fill-transparent dark:from-[#a2facf] dark:to-[#64acff]">.</span>
</h3>
{!filteredPhotos.length && <p className="mb-4 text-rose-500">No images found!</p>}

<ol className="relative mt-8 border-l border-slate-200 dark:border-slate-700">
{filteredPhotos.map((post, index) => (
<ListElement {...post} index={index} key={index} />
))}
{filteredPhotos.length > 0 && (
<li className="mb-10 ml-4">
<div className="absolute -left-1.5 mt-1.5 h-3 w-3 rounded-full border border-white bg-slate-200 dark:border-slate-900 dark:bg-slate-700"></div>
</li>
)}
</ol>
</div>
</Container>
);
}

export function getStaticProps() {
const photos = allPhotographies.map((post) => pick(post, ["slug", "title", "description", "publishedAt", "preview", "count"])).sort((a, b) => Number(new Date(b.publishedAt)) - Number(new Date(a.publishedAt)));
return { props: { photos } };
}
4 changes: 2 additions & 2 deletions public/feed.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@
<description><![CDATA[Igor Kowalczyk]]></description>
<link>https://igorkowalczyk.dev</link>
<generator>RSS for Node</generator>
<lastBuildDate>Fri, 09 Sep 2022 19:24:56 GMT</lastBuildDate>
<lastBuildDate>Fri, 16 Sep 2022 19:10:04 GMT</lastBuildDate>
<atom:link href="https://igorkowalczyk.dev/feed.xml" rel="self" type="application/rss+xml"/>
<item>
<title><![CDATA[How i built my website]]></title>
<title><![CDATA[How I built my website]]></title>
<description><![CDATA[A bit about how I built this site along with the blog and some new things and technologies I learned while rebuilding my portfolio.]]></description>
<link>https://igorkowalczyk.dev/blog/how-i-built-my-website</link>
<guid isPermaLink="true">https://igorkowalczyk.dev/blog/how-i-built-my-website</guid>
Expand Down
Loading

0 comments on commit 5e57127

Please sign in to comment.