Skip to content

Commit

Permalink
Add image gallery with slides
Browse files Browse the repository at this point in the history
  • Loading branch information
Nio-o committed Sep 12, 2019
1 parent 26b1f14 commit bb317e2
Show file tree
Hide file tree
Showing 7 changed files with 236 additions and 97 deletions.
2 changes: 2 additions & 0 deletions src/assets/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,3 +25,5 @@ export {default as VkIcon} from './vk.svg';
export {default as MapMarker} from './marker.svg';
// @ts-ignore
export {default as MediumIcon} from './medium.svg';
// @ts-ignore
export {default as TriangleIcon} from './triangle.svg';
7 changes: 7 additions & 0 deletions src/assets/triangle.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
13 changes: 3 additions & 10 deletions src/ui/about/about.component.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {EventTO} from '../../view-models/data.view-model';
import {Paragraph} from '../ui-kit/paragraph/paragraph.component';
import {mediaLg, mediaMd, mediaMdX} from '../../utils/css.utils';
import {clamp} from '../../utils/number.utils';
import {ModalImage} from '../modalImage/modalImage.component';
import {ImageGallery} from '../image-gallery/image-gallery/image-gallery.component';

//#region styled
const AboutStyled = styled.section`
Expand All @@ -31,7 +31,7 @@ const ParagraphStyled = styled(Paragraph)`
margin-bottom: 20px;
line-height: 1.5;
`;
const PhotosStyled = styled.div<{count: number}>`
const ImageGalleryStyled = styled(ImageGallery)<{count: number}>`
display: none;
grid-gap: 10px;
margin-bottom: 35px;
Expand All @@ -49,9 +49,6 @@ const PhotosStyled = styled.div<{count: number}>`
grid-template-columns: repeat(${({count}) => clamp(count, 1, 5)}, 1fr);
}
`;
const PhotoStyled = styled(ModalImage)`
width: 100%;
`;
//#endregion

interface AboutProps {
Expand Down Expand Up @@ -86,11 +83,7 @@ export const About: FC<AboutProps> = memo(({className}) => {
<ParagraphStyled key={i}>{about}</ParagraphStyled>
))}
</TextStyled>
<PhotosStyled count={data.event.photos.length}>
{event.photos.map((photo, i) => (
<PhotoStyled {...photo} key={i} />
))}
</PhotosStyled>
<ImageGalleryStyled count={data.event.photos.length} images={event.photos}/>
</Container>
</AboutStyled>
);
Expand Down
41 changes: 41 additions & 0 deletions src/ui/image-gallery/image-gallery-item/image-gallery-item.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import * as React from 'react';
import styled from '@emotion/styled';

const ImageStyled = styled.img`
width: 100%;
cursor: zoom-in;
`;

export interface ModalProps {
isOpened: boolean;
srcSmall: string;
srcLarge: string;
alt: string;
className?: string;
}

interface ModalImageProps {
src: string;
alt: string;
id: number;
className?: string;
srcLarge?: string;
onClick?: (key: number) => any;
}

export class ImageGalleryItem extends React.Component<ModalImageProps> {
constructor(props: ModalImageProps) {
super(props);
}

handleClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => {
if (!this.props.onClick) {
return;
}
this.props.onClick(this.props.id);
};

render(): React.ReactNode {
return <ImageStyled onClick={this.handleClick} className={this.props.className} src={this.props.src} alt={this.props.alt} />;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
import * as React from 'react';
import styled from '@emotion/styled';
import {FC, memo} from 'react';
import {TriangleIcon} from '../../../assets/index';
import {Icon} from '../../ui-kit/icon/icon.component';

//#region styled
const OverlayStyled = styled.div`
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
background: rgba(0, 0, 0, 0.7);
z-index: 999;
display: flex;
justify-content: center;
align-items: center;
flex-wrap: nowrap;
user-select: none;
`;
const NextStyled = styled.div`
right: 20px;
color: rgba(255, 255, 255, 0.7);
position: absolute;
width: 40px;
height: 100%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: flex-end;
&:hover {
color: var(--yellow);
}
`;
const PrevStyled = styled.div`
left: 20px;
transform: rotate(180deg);
color: rgba(255, 255, 255, 0.7);
position: absolute;
width: 40px;
height: 100%;
cursor: pointer;
display: flex;
align-items: center;
justify-content: flex-end;
&:hover {
color: var(--yellow);
}
`;
const ImageStyled = styled.img`
width: auto;
max-width: 50%;
max-height: 60%;
height: auto;
display: block;
cursor: pointer;
user-select: none;
&:hover + ${NextStyled} {
color: var(--yellow);
}
`;
//#endregion

interface ImageGalleryOverlayProps {
isLast: boolean;
isFirst: boolean;
src: string;
onNextClick: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => any;
onPrevClick: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => any;
onOverlayClick: (event: React.MouseEvent<HTMLDivElement, MouseEvent>) => any;
className?: string;
}

export const ImageGalleryOverlay: FC<ImageGalleryOverlayProps> = memo(
({src, isLast, isFirst, onNextClick, onPrevClick, onOverlayClick, className}) => {
return (
<OverlayStyled className={className} onClick={onOverlayClick}>
{!isFirst && (
<PrevStyled onClick={onPrevClick}>
<Icon svg={TriangleIcon} />
</PrevStyled>
)}
<ImageStyled onClick={onNextClick} src={src}></ImageStyled>
{!isLast && (
<NextStyled onClick={onNextClick}>
<Icon svg={TriangleIcon} />
</NextStyled>
)}
</OverlayStyled>
);
},
);
87 changes: 87 additions & 0 deletions src/ui/image-gallery/image-gallery/image-gallery.component.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
import * as React from 'react';
import {ImageGalleryItem} from '../image-gallery-item/image-gallery-item';
import {ImageGalleryOverlay} from '../image-gallery-overlay/image-gallery-overlay.component';

interface ImageGalleryProps {
images: Image[];
className?: string;
}

interface ImageGalleryState {
isOpened: boolean;
activeIndex: number;
}

interface Image {
alt: string;
src: string;
srcLarge?: string;
}

export class ImageGallery extends React.Component<ImageGalleryProps> {
state: ImageGalleryState;

constructor(props: ImageGalleryProps) {
super(props);

this.state = {
isOpened: false,
activeIndex: 0,
};
}

onImageClick = (id: number): void => {
this.setState({
isOpened: true,
activeIndex: id,
});
};

onOverlayClick = (): void => {
this.setState({
isOpened: false,
});
};

onNextClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>): void => {
event.stopPropagation();

const nextIndex = Math.min(this.state.activeIndex + 1, this.props.images.length - 1);
this.setState({activeIndex: nextIndex});
};

onPrevClick = (event: React.MouseEvent<HTMLDivElement, MouseEvent>): void => {
event.stopPropagation();

const prevIndex = Math.max(this.state.activeIndex - 1, 0);
this.setState({activeIndex: prevIndex});
};

render(): React.ReactNode {
// Create Overlay
let overlay: JSX.Element | null = null;
if (this.state.isOpened) {
const img = this.props.images[this.state.activeIndex];
overlay = (
<ImageGalleryOverlay
src={img.srcLarge || img.src}
onNextClick={this.onNextClick}
onPrevClick={this.onPrevClick}
onOverlayClick={this.onOverlayClick}
isFirst={this.state.activeIndex === 0}
isLast={this.state.activeIndex + 1 === this.props.images.length}
/>
);
}

// Images list
const images = this.props.images.map((img, i) => <ImageGalleryItem onClick={this.onImageClick} {...img} key={i} id={i} />);

return (
<div className={this.props.className}>
{images}
{overlay}
</div>
);
}
}
87 changes: 0 additions & 87 deletions src/ui/modalImage/modalImage.component.tsx

This file was deleted.

0 comments on commit bb317e2

Please sign in to comment.