[WebUI] Masonry Layout for Gallery

This commit is contained in:
blessedcoolant
2022-10-09 14:08:46 +13:00
committed by Lincoln Stein
parent 3046dabde2
commit 3170c83d8d
13 changed files with 553 additions and 513 deletions

View File

@@ -17,6 +17,8 @@
.hoverable-image-image {
width: 100%;
height: 100%;
object-fit: cover;
max-width: 100%;
max-height: 100%;
}

View File

@@ -55,12 +55,31 @@
@include HideScrollbar;
}
.image-gallery {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(80px, auto));
gap: 0.5rem;
justify-items: center;
.masonry-grid {
display: -webkit-box; /* Not needed if autoprefixing */
display: -ms-flexbox; /* Not needed if autoprefixing */
display: flex;
margin-left: 0.5rem; /* gutter size offset */
width: auto;
}
.masonry-grid_column {
padding-left: 0.5rem; /* gutter size */
background-clip: padding-box;
}
/* Style your items */
.masonry-grid_column > .hoverable-image {
/* change div to reference your elements you put in <Masonry> */
background: var(--tab-color);
margin-bottom: 0.5rem;
}
// .image-gallery {
// display: grid;
// grid-template-columns: repeat(auto-fill, minmax(80px, auto));
// gap: 0.5rem;
// justify-items: center;
// }
.image-gallery-load-more-btn {
background-color: var(--btn-load-more) !important;

View File

@@ -1,25 +1,25 @@
import { Button, IconButton } from '@chakra-ui/button';
import { Resizable } from 're-resizable';
import React from 'react';
import React, { useState } from 'react';
import { useHotkeys } from 'react-hotkeys-hook';
import { MdClear, MdPhotoLibrary } from 'react-icons/md';
import Masonry from 'react-masonry-css';
import { requestImages } from '../../app/socketio/actions';
import { RootState, useAppDispatch, useAppSelector } from '../../app/store';
import IAIIconButton from '../../common/components/IAIIconButton';
import {
selectNextImage,
selectPrevImage,
setShouldShowGallery,
} from './gallerySlice';
import { selectNextImage, selectPrevImage } from './gallerySlice';
import HoverableImage from './HoverableImage';
import { setShouldShowGallery } from '../options/optionsSlice';
export default function ImageGallery() {
const {
images,
currentImageUuid,
areMoreImagesAvailable,
shouldShowGallery,
} = useAppSelector((state: RootState) => state.gallery);
const { images, currentImageUuid, areMoreImagesAvailable } = useAppSelector(
(state: RootState) => state.gallery
);
const shouldShowGallery = useAppSelector(
(state: RootState) => state.options.shouldShowGallery
);
const activeTab = useAppSelector(
(state: RootState) => state.options.activeTab
@@ -27,6 +27,12 @@ export default function ImageGallery() {
const dispatch = useAppDispatch();
const [column, setColumn] = useState<number | undefined>();
const handleResize = (event: MouseEvent | TouchEvent | any) => {
setColumn(Math.floor((window.innerWidth - event.x) / 120));
};
const handleShowGalleryToggle = () => {
dispatch(setShouldShowGallery(!shouldShowGallery));
};
@@ -83,6 +89,7 @@ export default function ImageGallery() {
minWidth={'300'}
maxWidth={activeTab == 1 ? '300' : '600'}
className="image-gallery-popup"
onResize={handleResize}
>
{/* <div className="image-gallery-popup"></div> */}
<div className="image-gallery-header">
@@ -97,7 +104,12 @@ export default function ImageGallery() {
</div>
<div className="image-gallery-container">
{images.length ? (
<div className="image-gallery">
<Masonry
className="masonry-grid"
columnClassName="masonry-grid_column"
breakpointCols={column}
>
{/* <div className="image-gallery"> */}
{images.map((image) => {
const { uuid } = image;
const isSelected = currentImageUuid === uuid;
@@ -109,7 +121,8 @@ export default function ImageGallery() {
/>
);
})}
</div>
{/* </div> */}
</Masonry>
) : (
<div className="image-gallery-container-placeholder">
<MdPhotoLibrary />

View File

@@ -11,14 +11,12 @@ export interface GalleryState {
areMoreImagesAvailable: boolean;
latest_mtime?: number;
earliest_mtime?: number;
shouldShowGallery: boolean;
}
const initialState: GalleryState = {
currentImageUuid: '',
images: [],
areMoreImagesAvailable: true,
shouldShowGallery: false,
};
export const gallerySlice = createSlice({
@@ -140,9 +138,6 @@ export const gallerySlice = createSlice({
state.areMoreImagesAvailable = areMoreImagesAvailable;
}
},
setShouldShowGallery: (state, action: PayloadAction<boolean>) => {
state.shouldShowGallery = action.payload;
},
},
});
@@ -155,7 +150,6 @@ export const {
setIntermediateImage,
selectNextImage,
selectPrevImage,
setShouldShowGallery,
} = gallerySlice.actions;
export default gallerySlice.reducer;

View File

@@ -35,6 +35,7 @@ export interface OptionsState {
showAdvancedOptions: boolean;
activeTab: number;
shouldShowImageDetails: boolean;
shouldShowGallery: boolean;
}
const initialOptionsState: OptionsState = {
@@ -66,6 +67,7 @@ const initialOptionsState: OptionsState = {
showAdvancedOptions: true,
activeTab: 0,
shouldShowImageDetails: false,
shouldShowGallery: false,
};
const initialState: OptionsState = initialOptionsState;
@@ -279,6 +281,9 @@ export const optionsSlice = createSlice({
setShouldShowImageDetails: (state, action: PayloadAction<boolean>) => {
state.shouldShowImageDetails = action.payload;
},
setShouldShowGallery: (state, action: PayloadAction<boolean>) => {
state.shouldShowGallery = action.payload;
},
},
});
@@ -315,6 +320,7 @@ export const {
setShowAdvancedOptions,
setActiveTab,
setShouldShowImageDetails,
setShouldShowGallery,
} = optionsSlice.actions;
export default optionsSlice.reducer;

View File

@@ -6,7 +6,7 @@ import { RootState, useAppSelector } from '../../../app/store';
export default function ImageToImage() {
const shouldShowGallery = useAppSelector(
(state: RootState) => state.gallery.shouldShowGallery
(state: RootState) => state.options.shouldShowGallery
);
return (

View File

@@ -6,7 +6,7 @@ import { RootState, useAppSelector } from '../../../app/store';
export default function TextToImage() {
const shouldShowGallery = useAppSelector(
(state: RootState) => state.gallery.shouldShowGallery
(state: RootState) => state.options.shouldShowGallery
);
return (