Skip to content

Commit

Permalink
Merge pull request #6 from nemanjam/feature/add-gallery-page
Browse files Browse the repository at this point in the history
Add gallery page
  • Loading branch information
nemanjam authored Aug 17, 2024
2 parents 1c88769 + 3e42b15 commit bb8b233
Show file tree
Hide file tree
Showing 17 changed files with 363 additions and 11 deletions.
98 changes: 98 additions & 0 deletions docs/working-notes/my-old-code/Gallery.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
---
import { Image } from 'astro:assets';
import ReactGallery from '@/components/react/Gallery';
import { IMAGE_SIZES } from '@/constants/image';
import { cn } from '@/utils/styles';
import type { AstroImageProps, ImageProps } from '@/types/common';
import type { ImageMetadata } from 'astro';
export interface Props extends astroHTML.JSX.HTMLAttributes {}
// filenames
const EXCLUDE_IMAGES = ['avatar1.jpg'];
const getAllImagesMetadata = (): ImageMetadata[] => {
const imageModules = import.meta.glob<{ default: ImageMetadata }>(
// cant be even variable
'/src/assets/images/all-images/*.jpg',
{ eager: true }
);
// convert map to array
const imagesMetadata = Object.keys(imageModules)
// filter excluded filenames
.filter((path) => !EXCLUDE_IMAGES.some((excludedFileName) => path.endsWith(excludedFileName)))
// return metadata array
.map((path) => imageModules[path].default);
return imagesMetadata;
};
const imagesMetadata = getAllImagesMetadata();
const imageMetadataToAstroImageProps = (imagesMetadata: ImageMetadata): AstroImageProps => ({
src: imagesMetadata,
...IMAGE_SIZES.FIXED.MDX_XXS_16_9,
alt: 'Gallery image',
});
const astroImagePropsToReactImageProps = (astroImageProps: AstroImageProps): ImageProps => {
// console.log('astroImageProps', JSON.stringify(astroImageProps, null, 2));
const astroImageSrc = astroImageProps.src as ImageMetadata;
return {
src: astroImageSrc.src,
originalSrc: astroImageSrc.src,
width: parseInt(String(astroImageProps.width)),
height: parseInt(String(astroImageProps.height)),
};
};
const astroImages = imagesMetadata.map((metadata) => imageMetadataToAstroImageProps(metadata));
const reactImages = astroImages.map((astroProps) => astroImagePropsToReactImageProps(astroProps));
console.log('images', JSON.stringify(reactImages, null, 2));
const { class: className } = Astro.props;
---

<div class={cn('', className)}>
<ReactGallery
client:only="react"
images={reactImages}
thumbnailImageComponent={(<Image {...IMAGE_SIZES.FIXED.MDX_XXS_16_9} src="" alt="default" />)}
/>
</div>
{
/*
/@fs/home/username/Desktop/nemanjam.github.io/src/assets/images/all-images/cyco5.jpg?origWidth=4608&origHeight=2592&origFormat=jpg
<ul class={cn('grid gap-4 grid-cols-1 sm:grid-cols-2 md:grid-cols-3', className)}>
{
imagesMetadata.map((image) => (
<li>
<Image {...IMAGE_SIZES.FIXED.MDX_XXS_16_9} src={image} alt="my image" />
</li>
))
}
</ul>
interface Image {
key?: Key;
src: string;
width: number;
height: number;
nano?: string;
alt?: string;
tags?: ImageTag[];
isSelected?: boolean;
caption?: ReactNode;
customOverlay?: ReactNode;
thumbnailCaption?: ReactNode;
orientation?: number;
}
*/
}
3 changes: 3 additions & 0 deletions docs/working-notes/todo2.md
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ https://lea.verou.me/blog/2023/going-lean/#public-or-private-repo%3F
analytics, internationalisation, github issue template, small project
https://github.com/wanoo21/tailwind-astro-starting-blog

// good blog design
https://www.builder.io/blog/react-intersection-observer

-----------
za local state mora react ili solid
for state between pages nanostore with localStorage
Expand Down
22 changes: 22 additions & 0 deletions docs/working-notes/todo3.md
Original file line number Diff line number Diff line change
Expand Up @@ -472,4 +472,26 @@ astro env vars sa schema
astro component container, render component to string for rss
css directive transitions
remote collection 2.0, custom folder

-------------
// gallery


For lazy loading checkout unpic - https://unpic.pics/lib/

For image resizing I would use a CDN - depending on usage you might be able to use a free tier or pay very little.

For Gallery - https://benhowell.github.io/react-grid-gallery - which is client side React. For onscroll I used react-intersection-observer - https://www.builder.io/blog/react-intersection-observer

I hope this helps, sorry I can't share my code.
----
glob za slike
poenta, ne sme da ima {} za jednu opciju
ovo puca
'/src/assets/images/all-images/*.{jpg}',
ovo radi
'/src/assets/images/all-images/*.jpg',


------------
```
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,8 @@
"object-treeify": "^4.0.1",
"react": "^18.3.1",
"react-dom": "^18.3.1",
"react-grid-gallery": "^1.0.1",
"react-image-lightbox": "^5.1.4",
"reading-time": "^1.5.0",
"sharp": "0.32.6",
"tailwind-clip-path": "^1.0.0",
Expand Down
82 changes: 82 additions & 0 deletions src/components/Gallery.astro
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
---
import { getImage } from 'astro:assets';
import ReactGallery from '@/components/react/Gallery';
import { IMAGE_SIZES } from '@/constants/image';
import { cn } from '@/utils/styles';
import type { ImageProps } from '@/types/common';
import type { ImageMetadata } from 'astro';
export interface Props extends astroHTML.JSX.HTMLAttributes {}
// filenames
const EXCLUDE_IMAGES = ['avatar1.jpg'];
const getAllImagesMetadata = (): ImageMetadata[] => {
const imageModules = import.meta.glob<{ default: ImageMetadata }>(
// cant be even variable
'/src/assets/images/all-images/*.jpg',
{ eager: true }
);
// convert map to array
const imagesMetadata = Object.keys(imageModules)
// filter excluded filenames
.filter((path) => !EXCLUDE_IMAGES.some((excludedFileName) => path.endsWith(excludedFileName)))
// return metadata array
.map((path) => imageModules[path].default);
return imagesMetadata;
};
const imagesMetadata = getAllImagesMetadata();
const imageMetadataToReactImageProps = async (
imagesMetadata: ImageMetadata
): Promise<ImageProps> => {
const astroImageProps = {
src: imagesMetadata,
format: 'webp',
};
const thumbnailAstroImageProps = {
...astroImageProps,
...IMAGE_SIZES.FIXED.MDX_XXS_16_9,
alt: 'Thumbnail image',
};
const lightboxAstroImageProps = {
...astroImageProps,
...IMAGE_SIZES.FIXED.MDX_XL_16_9,
alt: 'Lightbox image',
};
const optimizedThumbnailAstroImageProps = await getImage(thumbnailAstroImageProps);
const { src, attributes } = optimizedThumbnailAstroImageProps;
const optimizedLightboxAstroImageProps = await getImage(lightboxAstroImageProps);
const { src: originalSrc } = optimizedLightboxAstroImageProps;
const reactImageProps = {
src,
originalSrc,
// width and height only for thumbnails
width: parseInt(String(attributes.width)),
height: parseInt(String(attributes.height)),
};
return reactImageProps;
};
const reactImages = await Promise.all(
imagesMetadata.map((metadata) => imageMetadataToReactImageProps(metadata))
);
// console.log('reactImages', reactImages);
const { class: className } = Astro.props;
---

<div class={cn('', className)}>
<ReactGallery client:only="react" images={reactImages} />
</div>
52 changes: 52 additions & 0 deletions src/components/react/Gallery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { useState } from 'react';

import { Gallery as ReactGridGallery } from 'react-grid-gallery';
import Lightbox from 'react-image-lightbox';

import type { ImageProps } from '@/types/common';

import 'react-image-lightbox/style.css';

interface Props {
images: ImageProps[];
}

// global polyfill for react-image-lightbox
window.global = window.global || window;

const Gallery: React.FC<Props> = ({ images }) => {
const [index, setIndex] = useState(-1);

const currentImage = images[index];
const nextIndex = (index + 1) % images.length;
const nextImage = images[nextIndex] || currentImage;
const prevIndex = (index + images.length - 1) % images.length;
const prevImage = images[prevIndex] || currentImage;

const handleClick = (index: number, _item: ImageProps) => setIndex(index);
const handleClose = () => setIndex(-1);
const handleMovePrev = () => setIndex(prevIndex);
const handleMoveNext = () => setIndex(nextIndex);

return (
<div>
<ReactGridGallery images={images} onClick={handleClick} enableImageSelection={false} />
{!!currentImage && (
<Lightbox
imageTitle={currentImage.caption}
mainSrc={currentImage.originalSrc}
mainSrcThumbnail={currentImage.src}
nextSrc={nextImage.originalSrc}
nextSrcThumbnail={nextImage.src}
prevSrc={prevImage.originalSrc}
prevSrcThumbnail={prevImage.src}
onCloseRequest={handleClose}
onMovePrevRequest={handleMovePrev}
onMoveNextRequest={handleMoveNext}
/>
)}
</div>
);
};

export default Gallery;
1 change: 1 addition & 0 deletions src/components/react/ScrollToTop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,7 @@ const ScrollToTop: React.FC<Props> = ({ children }) => {
};

// bellow 100 or it will break again on fast scroll
// todo: set threshold and remove debounce
const debouncedCallback = debounce(callback, 20);
const intersect = new IntersectionObserver(debouncedCallback);

Expand Down
4 changes: 4 additions & 0 deletions src/constants/navigation.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export const NAVIGATION_ITEMS = [
title: 'About',
path: ROUTES.ABOUT,
},
{
title: 'Gallery',
path: ROUTES.GALLERY,
},
// {
// title: 'Resume',
// path: ROUTES.RESUME,
Expand Down
1 change: 1 addition & 0 deletions src/constants/routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export const ROUTES = {
EXPLORE_TAGS: '/blog/explore/tags/',
EXPLORE_CATEGORIES: '/blog/explore/categories/',
DESIGN: '/design/',
GALLERY: '/gallery/',
/** maybe in future */
DRAFTS: '/drafts/',
_404: '/404/',
Expand Down
11 changes: 9 additions & 2 deletions src/layouts/Centered.astro
Original file line number Diff line number Diff line change
@@ -1,18 +1,25 @@
---
import Base from '@/layouts/Base.astro';
import { cn } from '@/utils/styles';
import type { BaseProps } from '@/layouts/Base.astro';
export interface Props extends BaseProps {}
export interface Props extends BaseProps, astroHTML.JSX.HTMLAttributes {}
const props = Astro.props;
// targets <main /> tag
const { class: className } = Astro.props;
---

{/* flex here to take full height for pagination, flex-row align-stretch */}
{/* h-full dosent work without all parents h-full */}

<Base {...props}>
<main id="main" class="flex-grow flex flex-col centered-px max-w-4xl py-4 lg:py-8">
<main
id="main"
class={cn('flex-grow flex flex-col centered-px max-w-4xl py-4 lg:py-8', className)}
>
<slot />
</main>
</Base>
7 changes: 5 additions & 2 deletions src/layouts/Page.astro
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
---
import Centered from '@/layouts/Centered.astro';
import { getOpenGraphImagePath } from '@/libs/api/open-graph/image-path';
import { cn } from '@/utils/styles';
export interface Content {
title: string;
description: string;
readingTime: number;
file: string;
url: string;
/** set max-w-xxx */
class: string;
}
export interface Props {
Expand All @@ -16,7 +19,7 @@ export interface Props {
// metadata from frontmatter
const { content } = Astro.props;
const { title, description } = content;
const { title, description, class: className } = content;
// available in Layouts
const { pathname } = Astro.url;
Expand All @@ -28,7 +31,7 @@ const image = getOpenGraphImagePath(path);
const metadata = { title, description, image };
---

<Centered {metadata}>
<Centered {metadata} class={cn(className)}>
<article class="my-prose">
<slot />
</article>
Expand Down
4 changes: 2 additions & 2 deletions src/pages/about.mdx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
---
layout: '../layouts/Page.astro'
title: 'About Me'
description: 'Lorem ipsum dolor sit amet'
title: 'About'
description: 'About me page'
---

import { Image } from 'astro:assets';
Expand Down
12 changes: 12 additions & 0 deletions src/pages/gallery.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
---
layout: '../layouts/Page.astro'
title: 'Gallery'
description: 'Image gallery'
class: 'max-w-5xl'
---

import Gallery from '../components/Gallery.astro';

# Gallery

<Gallery class="not-prose" />
Loading

0 comments on commit bb8b233

Please sign in to comment.