fixed image grid

web/dev
Laine Hallot 3 years ago committed by Laine Hallot
parent f15f5b2946
commit 18bcb72f45

@ -3,6 +3,7 @@ module.exports = {
siteMetadata: { siteMetadata: {
title: ``, title: ``,
siteUrl: `https://www.yourdomain.tld`, siteUrl: `https://www.yourdomain.tld`,
pathPrefix: '/Anime-Girls-Holding-Programming-Books',
}, },
plugins: [ plugins: [
'gatsby-plugin-postcss', 'gatsby-plugin-postcss',

File diff suppressed because it is too large Load Diff

@ -12,7 +12,8 @@
"build": "gatsby build", "build": "gatsby build",
"serve": "gatsby serve", "serve": "gatsby serve",
"clean": "gatsby clean", "clean": "gatsby clean",
"typecheck": "tsc --noEmit" "typecheck": "tsc --noEmit",
"deploy": "gatsby build --prefix-paths && gh-pages -d public"
}, },
"dependencies": { "dependencies": {
"@mdx-js/mdx": "^1.6.22", "@mdx-js/mdx": "^1.6.22",
@ -28,7 +29,8 @@
"gatsby-transformer-sharp": "^4.9.0", "gatsby-transformer-sharp": "^4.9.0",
"react": "^17.0.1", "react": "^17.0.1",
"react-dom": "^17.0.1", "react-dom": "^17.0.1",
"react-helmet": "^6.1.0" "react-helmet": "^6.1.0",
"react-image-lightbox": "^5.1.4"
}, },
"devDependencies": { "devDependencies": {
"@types/node": "^17.0.14", "@types/node": "^17.0.14",

@ -1,29 +1,59 @@
import React, { useContext } from 'react'; import React, { useContext, useState } from 'react';
import { useStaticQuery, graphql } from 'gatsby'; import Lightbox from 'react-image-lightbox';
import AnimeImage from './AnimeImage'; import AnimeImage from './AnimeImage';
import { ImageFiles } from '../types';
import { ImagesContext } from './Layout'; import { ImagesContext } from './Layout';
const AnimeImageGrid: React.FC = () => { const AnimeImageGrid: React.FC = () => {
const images = useContext(ImagesContext); const images = useContext(ImagesContext);
console.log(images);
const data: ImageFiles = useStaticQuery(graphql` const [isOpen, setIsOpen] = useState(false);
query { const [photoIndex, setPhotoIndex] = useState(0);
allFile {
nodes {
relativeDirectory
name
}
}
}
`);
console.log(images);
return ( return (
<div className="grid grid-flow-row-dense auto-rows-min gap-y-4 grid-cols-1 lg:grid-cols-2 xl:grid-cols-3"> <>
{(images as any).allImages.edges.map((file: any) => ( <div className="cursor-pointer grid grid-flow-row-dense auto-rows-min gap-4 grid-cols-1 lg:grid-cols-2 xl:grid-cols-2">
<AnimeImage image={file.node} /> {images &&
images.edges.map(({ node }, index) => (
<AnimeImage
image={node}
key={node.name}
onClick={() => {
setPhotoIndex(index);
setIsOpen(true);
}}
/>
))} ))}
</div> </div>
{isOpen && images && (
<Lightbox
reactModalStyle={{ display: 'flex', backgroundColor: '' }}
enableZoom={true}
mainSrc={
images.edges[photoIndex].node.childImageSharp.original.src && ''
}
nextSrc={
images.edges[Math.min(photoIndex + 1, images.edges.length - 1)].node
.childImageSharp.original.src && ''
}
prevSrc={
images.edges[Math.max(photoIndex - 1, 0)].node.childImageSharp
.original.src && ''
}
onCloseRequest={() => setIsOpen(false)}
onMovePrevRequest={() => {
if (images) {
setPhotoIndex((photoIndex - 1) % images.edges.length);
}
}}
onMoveNextRequest={() => {
if (images) {
setPhotoIndex((photoIndex + 1) % images.edges.length);
}
}}
/>
)}
</>
); );
}; };

@ -5,15 +5,16 @@ import { ImageFile } from '../types';
interface AnimeImageProps { interface AnimeImageProps {
image: any; image: any;
onClick: () => void;
} }
const AnimeImage: React.FC<AnimeImageProps> = ({ image }) => { const AnimeImage: React.FC<AnimeImageProps> = ({ image, onClick }) => {
const pic = getImage(image); const pic = getImage(image);
return ( return (
<div <div
key={image.id} key={image.id}
className="relative group inline-block" className="relative group col-span-1 h-96"
style={{ height: pic?.height, width: pic?.width }} onClick={onClick}
> >
<div <div
className=" className="
@ -37,7 +38,14 @@ const AnimeImage: React.FC<AnimeImageProps> = ({ image }) => {
<span className="break-all">{image.name.replace(/_/g, ' ')}</span> <span className="break-all">{image.name.replace(/_/g, ' ')}</span>
</span> </span>
</div> </div>
<GatsbyImage image={pic} alt={image.name} title={image.name} /> <GatsbyImage
className="h-full"
image={pic}
alt={image.name}
title={image.name}
height={'100%'}
width={'100%'}
/>
</div> </div>
); );
}; };

@ -1,8 +1,7 @@
import React, { createContext, useMemo, useState } from 'react'; import React, { createContext, useCallback, useMemo, useState } from 'react';
import AnimeImageGrid from '../components/AimeImageGrid';
import { useAnimeImages } from '../hooks/useAnimeImages'; import { useAnimeImages } from '../hooks/useAnimeImages';
import { useDirectories } from '../hooks/useDirectories'; import { useDirectories } from '../hooks/useDirectories';
import { ImageFiles } from '../types'; import { AllImages } from '../types';
// styles // styles
const pageStyles = { const pageStyles = {
@ -10,29 +9,31 @@ const pageStyles = {
padding: 96, padding: 96,
fontFamily: '-apple-system, Roboto, sans-serif, serif', fontFamily: '-apple-system, Roboto, sans-serif, serif',
}; };
const headingStyles = {
marginTop: 0,
marginBottom: 64,
maxWidth: 320,
};
const headingAccentStyles = {
color: '#663399',
};
const linkStyle = {
color: '#8954A8',
fontWeight: 'bold',
fontSize: 16,
verticalAlign: '5%',
};
export const ImagesContext = createContext<ImageFiles | undefined>(undefined); export const ImagesContext = createContext<AllImages | undefined>(undefined);
// markup
const Layout: React.FC = ({ children }) => { const Layout: React.FC = ({ children }) => {
const directories = useDirectories(); const directories = useDirectories();
const allImages = useAnimeImages(); const allImages = useAnimeImages();
console.log(allImages); const [selectedDir, setSelectedDir] = useState('');
const images = useMemo(() => allImages, [allImages]);
const images = useMemo(() => {
const desu: typeof allImages = {
edges: [],
};
if (allImages && allImages.edges) {
if (selectedDir === '') {
return allImages;
}
desu.edges = allImages.edges.filter(({ node }) => {
return selectedDir === node.relativeDirectory;
});
}
return desu;
}, [allImages, selectedDir]);
const handleDirSelect = useCallback((relativePath: string) => {
setSelectedDir(relativePath);
}, []);
return ( return (
<ImagesContext.Provider value={images}> <ImagesContext.Provider value={images}>
@ -40,8 +41,23 @@ const Layout: React.FC = ({ children }) => {
<nav className="flex flex-col w-2/12 h-screen overflow-y-scroll space-y-2 px-6"> <nav className="flex flex-col w-2/12 h-screen overflow-y-scroll space-y-2 px-6">
{directories.allDirectory.edges.map(({ node }: any) => ( {directories.allDirectory.edges.map(({ node }: any) => (
<span <span
className="p-2 hover:bg-indigo-500 hover:text-white transition-colors duration-300 rounded-md cursor-pointer" className={`
onClick={() => {}} p-2
hover:bg-indigo-500
hover:text-white
transition-colors
duration-300
rounded-md
cursor-pointer
${
node.relativePath === selectedDir
? 'bg-indigo-500 text-white'
: ''
}
`}
onClick={_event => {
handleDirSelect(node.relativePath);
}}
> >
{node.name} {node.name}
</span> </span>

@ -1,28 +1,35 @@
import { useStaticQuery, graphql } from 'gatsby'; import { useStaticQuery, graphql } from 'gatsby';
import { Directories, ImageFiles } from '../types'; import { AllImages, ImageQueryResponse } from '../types';
const useAnimeImages = (): ImageFiles => { const useAnimeImages = (): AllImages => {
const data = useStaticQuery(graphql` const { allImages }: ImageQueryResponse = useStaticQuery(graphql`
query { query {
allImages: allFile(sort: { order: ASC, fields: relativeDirectory }) { allImages: allFile(
sort: { order: ASC, fields: relativeDirectory }
filter: { sourceInstanceName: { eq: "images" } }
) {
edges { edges {
node { node {
name name
base
id id
relativePath relativeDirectory
childImageSharp { childImageSharp {
gatsbyImageData( gatsbyImageData(
width: 400 width: 800
placeholder: TRACED_SVG placeholder: TRACED_SVG
formats: [AUTO, WEBP, AVIF] formats: [AUTO, JPG, PNG, AVIF]
) )
original {
src
}
} }
} }
} }
} }
} }
`); `);
return data; return allImages;
}; };
export { useAnimeImages }; export { useAnimeImages };

@ -1,3 +1,348 @@
@tailwind base; @tailwind base;
@tailwind components; @tailwind components;
@tailwind utilities; @tailwind utilities;
@keyframes closeWindow {
0% {
opacity: 1;
}
100% {
opacity: 0;
}
}
.ril__outer {
background-color: rgba(0, 0, 0, 0.85);
outline: none;
top: 0;
left: 0;
right: 0;
bottom: 0;
z-index: 1000;
width: 100%;
height: 100%;
-ms-content-zooming: none;
-ms-user-select: none;
-ms-touch-select: none;
touch-action: none;
}
.ril__outerClosing {
opacity: 0;
}
.ril__inner {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
}
.ril__image,
.ril__imagePrev,
.ril__imageNext {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
margin: auto;
max-width: none;
-ms-content-zooming: none;
-ms-user-select: none;
-ms-touch-select: none;
touch-action: none;
}
.ril__imageDiscourager {
background-repeat: no-repeat;
background-position: center;
background-size: contain;
}
.ril__navButtons {
border: none;
position: absolute;
top: 0;
bottom: 0;
width: 20px;
height: 34px;
padding: 40px 30px;
margin: auto;
cursor: pointer;
opacity: 0.7;
}
.ril__navButtons:hover {
opacity: 1;
}
.ril__navButtons:active {
opacity: 0.7;
}
.ril__navButtonPrev {
left: 0;
background: rgba(0, 0, 0, 0.2)
url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjM0Ij48cGF0aCBkPSJtIDE5LDMgLTIsLTIgLTE2LDE2IDE2LDE2IDEsLTEgLTE1LC0xNSAxNSwtMTUgeiIgZmlsbD0iI0ZGRiIvPjwvc3ZnPg==')
no-repeat center;
}
.ril__navButtonNext {
right: 0;
background: rgba(0, 0, 0, 0.2)
url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjM0Ij48cGF0aCBkPSJtIDEsMyAyLC0yIDE2LDE2IC0xNiwxNiAtMSwtMSAxNSwtMTUgLTE1LC0xNSB6IiBmaWxsPSIjRkZGIi8+PC9zdmc+')
no-repeat center;
}
.ril__downloadBlocker {
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-image: url('data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7');
background-size: cover;
}
.ril__caption,
.ril__toolbar {
background-color: rgba(0, 0, 0, 0.5);
position: absolute;
left: 0;
right: 0;
display: flex;
justify-content: space-between;
}
.ril__caption {
bottom: 0;
max-height: 150px;
overflow: auto;
}
.ril__captionContent {
padding: 10px 20px;
color: #fff;
}
.ril__toolbar {
top: 0;
height: 50px;
}
.ril__toolbarSide {
height: 50px;
margin: 0;
}
.ril__toolbarLeftSide {
padding-left: 20px;
padding-right: 0;
flex: 0 1 auto;
overflow: hidden;
text-overflow: ellipsis;
}
.ril__toolbarRightSide {
padding-left: 0;
padding-right: 20px;
flex: 0 0 auto;
}
.ril__toolbarItem {
display: inline-block;
line-height: 50px;
padding: 0;
color: #fff;
font-size: 120%;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
}
.ril__toolbarItemChild {
vertical-align: middle;
}
.ril__builtinButton {
width: 40px;
height: 35px;
cursor: pointer;
border: none;
opacity: 0.7;
}
.ril__builtinButton:hover {
opacity: 1;
}
.ril__builtinButton:active {
outline: none;
}
.ril__builtinButtonDisabled {
cursor: default;
opacity: 0.5;
}
.ril__builtinButtonDisabled:hover {
opacity: 0.5;
}
.ril__closeButton {
background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZlcnNpb249IjEuMSIgd2lkdGg9IjIwIiBoZWlnaHQ9IjIwIj48cGF0aCBkPSJtIDEsMyAxLjI1LC0xLjI1IDcuNSw3LjUgNy41LC03LjUgMS4yNSwxLjI1IC03LjUsNy41IDcuNSw3LjUgLTEuMjUsMS4yNSAtNy41LC03LjUgLTcuNSw3LjUgLTEuMjUsLTEuMjUgNy41LC03LjUgLTcuNSwtNy41IHoiIGZpbGw9IiNGRkYiLz48L3N2Zz4=')
no-repeat center;
}
.ril__zoomInButton {
background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCI+PGcgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PHBhdGggZD0iTTEgMTlsNi02Ii8+PHBhdGggZD0iTTkgOGg2Ii8+PHBhdGggZD0iTTEyIDV2NiIvPjwvZz48Y2lyY2xlIGN4PSIxMiIgY3k9IjgiIHI9IjciIGZpbGw9Im5vbmUiIHN0cm9rZT0iI2ZmZiIgc3Ryb2tlLXdpZHRoPSIyIi8+PC9zdmc+')
no-repeat center;
}
.ril__zoomOutButton {
background: url('data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyMCIgaGVpZ2h0PSIyMCI+PGcgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiIHN0cm9rZS1saW5lY2FwPSJyb3VuZCI+PHBhdGggZD0iTTEgMTlsNi02Ii8+PHBhdGggZD0iTTkgOGg2Ii8+PC9nPjxjaXJjbGUgY3g9IjEyIiBjeT0iOCIgcj0iNyIgZmlsbD0ibm9uZSIgc3Ryb2tlPSIjZmZmIiBzdHJva2Utd2lkdGg9IjIiLz48L3N2Zz4=')
no-repeat center;
}
.ril__outerAnimating {
animation-name: closeWindow;
}
@keyframes pointFade {
0%,
19.999%,
100% {
opacity: 0;
}
20% {
opacity: 1;
}
}
.ril__loadingCircle {
width: 60px;
height: 60px;
position: relative;
}
.ril__loadingCirclePoint {
width: 100%;
height: 100%;
position: absolute;
left: 0;
top: 0;
}
.ril__loadingCirclePoint::before {
content: '';
display: block;
margin: 0 auto;
width: 11%;
height: 30%;
background-color: #fff;
border-radius: 30%;
animation: pointFade 800ms infinite ease-in-out both;
}
.ril__loadingCirclePoint:nth-of-type(1) {
transform: rotate(0deg);
}
.ril__loadingCirclePoint:nth-of-type(7) {
transform: rotate(180deg);
}
.ril__loadingCirclePoint:nth-of-type(1)::before,
.ril__loadingCirclePoint:nth-of-type(7)::before {
animation-delay: -800ms;
}
.ril__loadingCirclePoint:nth-of-type(2) {
transform: rotate(30deg);
}
.ril__loadingCirclePoint:nth-of-type(8) {
transform: rotate(210deg);
}
.ril__loadingCirclePoint:nth-of-type(2)::before,
.ril__loadingCirclePoint:nth-of-type(8)::before {
animation-delay: -666ms;
}
.ril__loadingCirclePoint:nth-of-type(3) {
transform: rotate(60deg);
}
.ril__loadingCirclePoint:nth-of-type(9) {
transform: rotate(240deg);
}
.ril__loadingCirclePoint:nth-of-type(3)::before,
.ril__loadingCirclePoint:nth-of-type(9)::before {
animation-delay: -533ms;
}
.ril__loadingCirclePoint:nth-of-type(4) {
transform: rotate(90deg);
}
.ril__loadingCirclePoint:nth-of-type(10) {
transform: rotate(270deg);
}
.ril__loadingCirclePoint:nth-of-type(4)::before,
.ril__loadingCirclePoint:nth-of-type(10)::before {
animation-delay: -400ms;
}
.ril__loadingCirclePoint:nth-of-type(5) {
transform: rotate(120deg);
}
.ril__loadingCirclePoint:nth-of-type(11) {
transform: rotate(300deg);
}
.ril__loadingCirclePoint:nth-of-type(5)::before,
.ril__loadingCirclePoint:nth-of-type(11)::before {
animation-delay: -266ms;
}
.ril__loadingCirclePoint:nth-of-type(6) {
transform: rotate(150deg);
}
.ril__loadingCirclePoint:nth-of-type(12) {
transform: rotate(330deg);
}
.ril__loadingCirclePoint:nth-of-type(6)::before,
.ril__loadingCirclePoint:nth-of-type(12)::before {
animation-delay: -133ms;
}
.ril__loadingCirclePoint:nth-of-type(7) {
transform: rotate(180deg);
}
.ril__loadingCirclePoint:nth-of-type(13) {
transform: rotate(360deg);
}
.ril__loadingCirclePoint:nth-of-type(7)::before,
.ril__loadingCirclePoint:nth-of-type(13)::before {
animation-delay: 0ms;
}
.ril__loadingContainer {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.ril__imagePrev .ril__loadingContainer,
.ril__imageNext .ril__loadingContainer {
display: none;
}
.ril__errorContainer {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
display: flex;
align-items: center;
justify-content: center;
color: #fff;
}
.ril__imagePrev .ril__errorContainer,
.ril__imageNext .ril__errorContainer {
display: none;
}
.ril__loadingContainer__icon {
color: #fff;
position: absolute;
top: 50%;
left: 50%;
transform: translateX(-50%) translateY(-50%);
}

@ -1,3 +1,5 @@
import { IGatsbyImageData } from 'gatsby-plugin-image';
export interface Directory { export interface Directory {
name: string; name: string;
relativePath: string; relativePath: string;
@ -12,10 +14,19 @@ export interface Directories {
export interface ImageFile { export interface ImageFile {
name: string; name: string;
relativeDirectory: string; relativeDirectory: string;
base: string;
childImageSharp: {
gatsbyImageData: IGatsbyImageData;
original: {
src: string;
};
};
} }
export interface ImageFiles { export interface AllImages {
allFile: { edges: { node: ImageFile }[];
edges: ImageFile[]; }
};
export interface ImageQueryResponse {
allImages: AllImages;
} }

Loading…
Cancel
Save