diff --git a/client/package-lock.json b/client/package-lock.json index 5f4553e1..d8a8390f 100644 --- a/client/package-lock.json +++ b/client/package-lock.json @@ -17,6 +17,7 @@ "js-cookie": "^3.0.1", "lodash": "^4.17.20", "node-sass": "^7.0.1", + "photoswipe": "^5.2.7", "prop-types": "^15.8.1", "react": "^17.0.2", "react-beautiful-dnd": "^13.0.0", @@ -26,6 +27,7 @@ "react-i18next": "^11.16.6", "react-input-mask": "^2.0.4", "react-markdown": "^8.0.2", + "react-photoswipe-gallery": "^2.2.1", "react-redux": "^7.2.8", "react-router-dom": "^5.3.1", "react-scripts": "5.0.1", @@ -16224,6 +16226,14 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "node_modules/photoswipe": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.2.7.tgz", + "integrity": "sha512-AogMba7W/O5gOtDIZ8cQuou1ltwxlaLNoZY1qi1s+kbYXpZk9D6rXxnNGAfDppl+bfe+sKLW2w2sx+3uQ8oPzg==", + "engines": { + "node": ">= 0.12.0" + } + }, "node_modules/picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -18230,6 +18240,16 @@ "react-dom": "^15.5.x || ^16.x || ^17.x" } }, + "node_modules/react-photoswipe-gallery": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-photoswipe-gallery/-/react-photoswipe-gallery-2.2.1.tgz", + "integrity": "sha512-xaUKKmwRLCpEzB8+bU7yxjXvRBHaInpBcI6YQY0UOeFctHAL3jGRDk9j2YbwmlgN7kRStHTcyrSNxr+zSaOnKg==", + "peerDependencies": { + "photoswipe": ">= 5.2.2", + "prop-types": ">= 15.7.0", + "react": ">= 16.8.0" + } + }, "node_modules/react-popper": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.5.tgz", @@ -35010,6 +35030,11 @@ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=" }, + "photoswipe": { + "version": "5.2.7", + "resolved": "https://registry.npmjs.org/photoswipe/-/photoswipe-5.2.7.tgz", + "integrity": "sha512-AogMba7W/O5gOtDIZ8cQuou1ltwxlaLNoZY1qi1s+kbYXpZk9D6rXxnNGAfDppl+bfe+sKLW2w2sx+3uQ8oPzg==" + }, "picocolors": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", @@ -36319,6 +36344,12 @@ "integrity": "sha512-a5Q7CkWznBRUWPmocCvE8b6lEYw1s6+opp/60dCunhO+G6E4tDTO2Sd2jKE+leEnnrLAE2Wj5DlDHNqj5wPv1Q==", "requires": {} }, + "react-photoswipe-gallery": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/react-photoswipe-gallery/-/react-photoswipe-gallery-2.2.1.tgz", + "integrity": "sha512-xaUKKmwRLCpEzB8+bU7yxjXvRBHaInpBcI6YQY0UOeFctHAL3jGRDk9j2YbwmlgN7kRStHTcyrSNxr+zSaOnKg==", + "requires": {} + }, "react-popper": { "version": "2.2.5", "resolved": "https://registry.npmjs.org/react-popper/-/react-popper-2.2.5.tgz", diff --git a/client/package.json b/client/package.json index 26692c1b..a096c457 100755 --- a/client/package.json +++ b/client/package.json @@ -74,6 +74,7 @@ "js-cookie": "^3.0.1", "lodash": "^4.17.20", "node-sass": "^7.0.1", + "photoswipe": "^5.2.7", "prop-types": "^15.8.1", "react": "^17.0.2", "react-beautiful-dnd": "^13.0.0", @@ -83,6 +84,7 @@ "react-i18next": "^11.16.6", "react-input-mask": "^2.0.4", "react-markdown": "^8.0.2", + "react-photoswipe-gallery": "^2.2.1", "react-redux": "^7.2.8", "react-router-dom": "^5.3.1", "react-scripts": "5.0.1", diff --git a/client/src/components/CardModal/Attachments/Attachments.jsx b/client/src/components/CardModal/Attachments/Attachments.jsx index bf2c69a8..4ca211b0 100644 --- a/client/src/components/CardModal/Attachments/Attachments.jsx +++ b/client/src/components/CardModal/Attachments/Attachments.jsx @@ -1,88 +1,153 @@ import React, { useCallback } from 'react'; import PropTypes from 'prop-types'; import { useTranslation } from 'react-i18next'; -import { Button } from 'semantic-ui-react'; +import { Gallery, Item as GalleryItem } from 'react-photoswipe-gallery'; +import { Button, Grid } from 'semantic-ui-react'; import { useToggle } from '../../../lib/hooks'; import Item from './Item'; import styles from './Attachments.module.scss'; -const Attachments = React.memo(({ items, onUpdate, onDelete, onCoverUpdate }) => { - const [t] = useTranslation(); - const [isOpened, toggleOpened] = useToggle(); +const INITIALLY_VISIBLE = 4; - const handleToggleClick = useCallback(() => { - toggleOpened(); - }, [toggleOpened]); +const Attachments = React.memo( + ({ items, onUpdate, onDelete, onCoverUpdate, onGalleryOpen, onGalleryClose }) => { + const [t] = useTranslation(); + const [isAllVisible, toggleAllVisible] = useToggle(); - const handleCoverSelect = useCallback( - (id) => { - onCoverUpdate(id); - }, - [onCoverUpdate], - ); + const handleCoverSelect = useCallback( + (id) => { + onCoverUpdate(id); + }, + [onCoverUpdate], + ); - const handleCoverDeselect = useCallback(() => { - onCoverUpdate(null); - }, [onCoverUpdate]); + const handleCoverDeselect = useCallback(() => { + onCoverUpdate(null); + }, [onCoverUpdate]); - const handleUpdate = useCallback( - (id, data) => { - onUpdate(id, data); - }, - [onUpdate], - ); + const handleUpdate = useCallback( + (id, data) => { + onUpdate(id, data); + }, + [onUpdate], + ); - const handleDelete = useCallback( - (id) => { - onDelete(id); - }, - [onDelete], - ); + const handleDelete = useCallback( + (id) => { + onDelete(id); + }, + [onDelete], + ); - const visibleItems = isOpened ? items : items.slice(0, 4); + const handleBeforeGalleryOpen = useCallback( + (gallery) => { + onGalleryOpen(); - return ( - <> - {visibleItems.map((item) => ( - handleCoverSelect(item.id)} - onCoverDeselect={handleCoverDeselect} - onUpdate={(data) => handleUpdate(item.id, data)} - onDelete={() => handleDelete(item.id)} - /> - ))} - {items.length > 4 && ( -