Skip to content

Commit

Permalink
gallery basic version #3
Browse files Browse the repository at this point in the history
  • Loading branch information
ukorvl committed Aug 2, 2023
1 parent 40a1adb commit bb11aa7
Show file tree
Hide file tree
Showing 13 changed files with 196 additions and 92 deletions.
46 changes: 0 additions & 46 deletions app/gallery/#components/Gallery/Gallery.tsx

This file was deleted.

28 changes: 0 additions & 28 deletions app/gallery/#constants/config.ts

This file was deleted.

9 changes: 2 additions & 7 deletions app/gallery/page.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import {Metadata} from 'next';
import Gallery from './#components/Gallery/Gallery';
import Gallery from '@/components/Gallery/Gallery';

export const metadata: Metadata = {
title: 'Gallery',
Expand All @@ -13,10 +13,5 @@ export const metadata: Metadata = {
* @returns React component.
*/
export default function GalleryPage() {
return (
<div>
Gallery
<Gallery />
</div>
);
return <Gallery />;
}
4 changes: 4 additions & 0 deletions app/globals.css
Original file line number Diff line number Diff line change
Expand Up @@ -31,4 +31,8 @@
.animated-link:focus:after {
width: 100%;
}

.focus-ring {
@apply focus:ring-2 focus:outline-none focus:ring-white;
}
}
1 change: 1 addition & 0 deletions app/layout.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const bodyCn = clsx(
'flex-col',
'min-h-screen',
'bg-[radial-gradient(ellipse_at_top_right,_var(--tw-gradient-stops))] from-black via-alternate to-black',
'bg-fixed',
);

const mainCn = clsx('flex', 'flex-col', 'items-center', 'justify-center', 'p-24');
Expand Down
4 changes: 1 addition & 3 deletions components/Button/Button.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,7 @@ const baseButtonCn = clsx(
'relative',
'overflow-hidden',
'select-none',
'focus:ring-4',
'focus:outline-none',
'focus:ring-white',
'focus-ring',
);

const buttonDefaultCn = clsx(
Expand Down
52 changes: 52 additions & 0 deletions components/Gallery/Gallery.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
'use client';

import {MutableRefObject} from 'react';
import clsx from 'clsx';
import {Gallery as PSGallery, Item, GalleryProps} from 'react-photoswipe-gallery';
import 'photoswipe/dist/photoswipe.css';
import useNetworkSpeed from '@/lib/shared/useNetworkSpeed';
import config from './config';
import GalleryItem from './GalleryItem';

const containerCn = clsx('flex', 'flex-wrap', 'gap-4', 'justify-center');

const photoSwipeOptions: GalleryProps['options'] = {
zoom: false,
bgOpacity: 0.9,
};

/**
* @returns React component.
*/
export default function Gallery() {
const [, isFast] = useNetworkSpeed();

return (
<div className={containerCn}>
<PSGallery options={photoSwipeOptions}>
{config.map(({src, lowQualitySrc, dimensions: {width, height}, blurDataURL}) => {
const computedSrc = isFast ? src : lowQualitySrc;
return (
<Item
original={computedSrc}
thumbnail={computedSrc}
alt=""
width={width}
height={height}
key={computedSrc}
>
{({open, ref}) => (
<GalleryItem
open={open}
ref={ref as MutableRefObject<HTMLImageElement>}
blurDataURL={blurDataURL}
src={computedSrc}
/>
)}
</Item>
);
})}
</PSGallery>
</div>
);
}
77 changes: 77 additions & 0 deletions components/Gallery/GalleryItem.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
import {MouseEvent} from 'react';
import clsx from 'clsx';
import Image from 'next/image';
import {forwardRef} from 'react';
import {useHotkeys} from 'react-hotkeys-hook';
import AppearInViewport from '../AppearInViewport/AppearInViewport';

/**
* Props.
*/
type GalleryItemProps = {
src: string;
blurDataURL: string;
open: (e: MouseEvent) => void;
};

const imgCn = clsx('rounded-md', 'overflow-hidden');
const overflowCn = clsx(
'cursor-pointer',
'relative',
'after:absolute',
'after:content-[""]',
'after:w-full',
'after:h-full',
'after:top-0',
'after:left-0',
'after:bg-[radial-gradient(circle,_var(--tw-gradient-stops))] from-white to-transparent',
'after:transition-opacity',
'after:duration-300',
'after:ease-out',
'after:opacity-0',
'hover:after:opacity-20',
'transition-transform',
'duration-500',
'ease-out',
'hover:translate-y-1',
'rounded-md',
'focus-ring',
);

/**
* @returns React component.
*/
const GalleryItem = forwardRef<HTMLImageElement, GalleryItemProps>(function GalleryItem(
{open, src, blurDataURL},
ref,
) {
const hotkeysRef = useHotkeys<HTMLDivElement>(['enter', 'space'], open as any, {
preventDefault: true,
});

return (
<AppearInViewport>
{/* eslint-disable-next-line jsx-a11y/click-events-have-key-events */}
<div
className={overflowCn}
style={{height: 300, width: 400}}
onClick={open}
tabIndex={0}
role="link"
ref={hotkeysRef}
>
<Image
className={imgCn}
ref={ref}
src={src}
placeholder="blur"
blurDataURL={blurDataURL}
alt=""
fill
/>
</div>
</AppearInViewport>
);
});

export default GalleryItem;
28 changes: 28 additions & 0 deletions components/Gallery/config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
/**
* Gallery images configuration.
*/
const config = [
{fileName: 'gallery.0.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.1.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.2.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.3.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.4.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.5.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.6.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.7.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.8.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.9.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.10.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.11.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.12.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.13.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.14.jpg', dimensions: {width: 920, height: 600}},
{fileName: 'gallery.15.jpg', dimensions: {width: 920, height: 600}},
] as const;

export default config.map(({fileName, dimensions}) => ({
dimensions,
src: `/images/${fileName}`,
blurDataURL: `/images/blured/${fileName}`,
lowQualitySrc: `/images/low-quality/${fileName}`,
}));
16 changes: 11 additions & 5 deletions components/ScrollToTop/ScrollToTop.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {m} from 'framer-motion';
import {FontAwesomeIcon} from '@fortawesome/react-fontawesome';
import {faCircleArrowUp} from '@fortawesome/free-solid-svg-icons';
import useScroll, {ScrollHandler} from '@/lib/shared/useScroll';
import isPrefersReducedMotion from '@/utils/isPrefersReducedMotion';

/**
* Props.
Expand All @@ -15,8 +16,8 @@ type ScrollToTopButtonProps = {
} & Pick<CSSProperties, 'top' | 'left' | 'bottom' | 'right'>;

const variants = {
visible: {opacity: 1, x: 0},
hidden: {opacity: 0, x: '-100%'},
visible: {opacity: 1, y: 0},
hidden: {opacity: 0, y: '2rem'},
};

/**
Expand All @@ -37,14 +38,19 @@ export default function ScrollToTopButton({offset = 1000, ...position}: ScrollTo

return (
<m.button
className="absolute"
className="fixed"
initial="hidden"
animate={visible ? 'visible' : 'hidden'}
variants={variants}
onClick={() => scrollToTop()}
transition={{duration: 0.5, ease: 'easeOut'}}
onClick={() => scrollToTop(!isPrefersReducedMotion())}
aria-hidden={true}
style={position}
>
<FontAwesomeIcon icon={faCircleArrowUp} />
<FontAwesomeIcon
icon={faCircleArrowUp}
size="2xl"
/>
</m.button>
);
}
Expand Down
2 changes: 2 additions & 0 deletions lib/shared/useNetworkSpeed.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
'use client';

import {useEffect, useState} from 'react';
import {isServer} from '@/utils/isServer';

Expand Down
6 changes: 3 additions & 3 deletions public/manifest.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,18 @@
"start_url": "/",
"icons": [
{
"src": "/logo/logo.png",
"src": "/icons/logo.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "/logo/logo_maskable.png",
"src": "/icons/logo_maskable.png",
"type": "image/png",
"sizes": "192x192",
"purpose": "maskable"
},
{
"src": "/logo/logo_512.png",
"src": "/icons/logo_512.png",
"type": "image/png",
"sizes": "512x512"
}
Expand Down
15 changes: 15 additions & 0 deletions utils/isPrefersReducedMotion.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import {isServer} from './isServer';

const query = '(prefers-reduced-motion: reduce)';

/**
* @returns True if the user has requested reduced motion.
*/
export default function isPrefersReducedMotion() {
if (isServer()) {
return false;
}

const mediaQueryList = window.matchMedia(query);
return mediaQueryList.matches;
}

0 comments on commit bb11aa7

Please sign in to comment.