Lightbox gestures and keyboard navigation
This commit is contained in:
parent
d648509311
commit
6d2240fb55
|
@ -14,12 +14,13 @@
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
"autoprefixer": "^10.4.7",
|
"autoprefixer": "^10.4.7",
|
||||||
"graphql-request": "^4.2.0",
|
"graphql-request": "^4.2.0",
|
||||||
|
"lightgallery": "^2.4.0",
|
||||||
"markdown-to-jsx": "^7.1.7",
|
"markdown-to-jsx": "^7.1.7",
|
||||||
"next": "^12.1.6",
|
"next": "^12.1.6",
|
||||||
"nodemailer": "^6.7.5",
|
"nodemailer": "^6.7.5",
|
||||||
"react": "18.1.0",
|
"react": "18.1.0",
|
||||||
"react-dom": "18.1.0",
|
"react-dom": "18.1.0",
|
||||||
"react-hotkeys-hook": "^3.4.4",
|
"react-hot-keys": "^2.7.2",
|
||||||
"react-swipeable": "^7.0.0",
|
"react-swipeable": "^7.0.0",
|
||||||
"turndown": "^7.1.1"
|
"turndown": "^7.1.1"
|
||||||
},
|
},
|
||||||
|
@ -907,7 +908,6 @@
|
||||||
"version": "7.17.2",
|
"version": "7.17.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
|
||||||
"integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
|
"integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.13.4"
|
||||||
},
|
},
|
||||||
|
@ -6275,6 +6275,14 @@
|
||||||
"node": ">= 0.8.0"
|
"node": ">= 0.8.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/lightgallery": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightgallery/-/lightgallery-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-9i/E/w3yaqs56y3k6SWIUS3JTLpeDCZIVnIuNppzAmj5KjLGy5wrFisoDUD0HdxVUdX0wHG5mjvB4h0TXtyf/w==",
|
||||||
|
"engines": {
|
||||||
|
"node": ">=6.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/lilconfig": {
|
"node_modules/lilconfig": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
|
||||||
|
@ -6965,7 +6973,6 @@
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
||||||
"dev": true,
|
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=0.10.0"
|
"node": ">=0.10.0"
|
||||||
}
|
}
|
||||||
|
@ -7574,7 +7581,6 @@
|
||||||
"version": "15.8.1",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
"dev": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
|
@ -7679,23 +7685,24 @@
|
||||||
"react": "^18.1.0"
|
"react": "^18.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-hotkeys-hook": {
|
"node_modules/react-hot-keys": {
|
||||||
"version": "3.4.4",
|
"version": "2.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-hot-keys/-/react-hot-keys-2.7.2.tgz",
|
||||||
"integrity": "sha512-vaORq07rWgmuF3owWRhgFV/3VL8/l2q9lz0WyVEddJnWTtKW+AOgU5YgYKuwN6h6h7bCcLG3MFsJIjCrM/5DvQ==",
|
"integrity": "sha512-Z7eSh7SU6s52+zP+vkfFoNk0x4kgEmnwqDiyACKv53crK2AZ7FUaBLnf+vxLor3dvtId9murLmKOsrJeYgeHWw==",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"hotkeys-js": "3.8.7"
|
"hotkeys-js": "^3.8.1",
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"react": ">=16.8.1",
|
"@babel/runtime": ">=7.10.0",
|
||||||
"react-dom": ">=16.8.1"
|
"react": ">=16.9.0",
|
||||||
|
"react-dom": ">=16.9.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/react-swipeable": {
|
"node_modules/react-swipeable": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
|
@ -7734,8 +7741,7 @@
|
||||||
"node_modules/regenerator-runtime": {
|
"node_modules/regenerator-runtime": {
|
||||||
"version": "0.13.9",
|
"version": "0.13.9",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
|
||||||
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
|
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/regexp.prototype.flags": {
|
"node_modules/regexp.prototype.flags": {
|
||||||
"version": "1.4.3",
|
"version": "1.4.3",
|
||||||
|
@ -9605,7 +9611,6 @@
|
||||||
"version": "7.17.2",
|
"version": "7.17.2",
|
||||||
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
|
"resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.17.2.tgz",
|
||||||
"integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
|
"integrity": "sha512-hzeyJyMA1YGdJTuWU0e/j4wKXrU4OMFvY2MSlaI9B7VQb0r5cxTE3EAIS2Q7Tn2RIcDkRvTA/v2JsAEhxe99uw==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"regenerator-runtime": "^0.13.4"
|
"regenerator-runtime": "^0.13.4"
|
||||||
}
|
}
|
||||||
|
@ -13768,6 +13773,11 @@
|
||||||
"type-check": "~0.4.0"
|
"type-check": "~0.4.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"lightgallery": {
|
||||||
|
"version": "2.4.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/lightgallery/-/lightgallery-2.4.0.tgz",
|
||||||
|
"integrity": "sha512-9i/E/w3yaqs56y3k6SWIUS3JTLpeDCZIVnIuNppzAmj5KjLGy5wrFisoDUD0HdxVUdX0wHG5mjvB4h0TXtyf/w=="
|
||||||
|
},
|
||||||
"lilconfig": {
|
"lilconfig": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-2.0.5.tgz",
|
||||||
|
@ -14265,8 +14275,7 @@
|
||||||
"object-assign": {
|
"object-assign": {
|
||||||
"version": "4.1.1",
|
"version": "4.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=",
|
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"object-hash": {
|
"object-hash": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
|
@ -14677,7 +14686,6 @@
|
||||||
"version": "15.8.1",
|
"version": "15.8.1",
|
||||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||||
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"loose-envify": "^1.4.0",
|
"loose-envify": "^1.4.0",
|
||||||
"object-assign": "^4.1.1",
|
"object-assign": "^4.1.1",
|
||||||
|
@ -14749,19 +14757,19 @@
|
||||||
"scheduler": "^0.22.0"
|
"scheduler": "^0.22.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-hotkeys-hook": {
|
"react-hot-keys": {
|
||||||
"version": "3.4.4",
|
"version": "2.7.2",
|
||||||
"resolved": "https://registry.npmjs.org/react-hotkeys-hook/-/react-hotkeys-hook-3.4.4.tgz",
|
"resolved": "https://registry.npmjs.org/react-hot-keys/-/react-hot-keys-2.7.2.tgz",
|
||||||
"integrity": "sha512-vaORq07rWgmuF3owWRhgFV/3VL8/l2q9lz0WyVEddJnWTtKW+AOgU5YgYKuwN6h6h7bCcLG3MFsJIjCrM/5DvQ==",
|
"integrity": "sha512-Z7eSh7SU6s52+zP+vkfFoNk0x4kgEmnwqDiyACKv53crK2AZ7FUaBLnf+vxLor3dvtId9murLmKOsrJeYgeHWw==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"hotkeys-js": "3.8.7"
|
"hotkeys-js": "^3.8.1",
|
||||||
|
"prop-types": "^15.7.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"react-is": {
|
"react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
|
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"react-swipeable": {
|
"react-swipeable": {
|
||||||
"version": "7.0.0",
|
"version": "7.0.0",
|
||||||
|
@ -14792,8 +14800,7 @@
|
||||||
"regenerator-runtime": {
|
"regenerator-runtime": {
|
||||||
"version": "0.13.9",
|
"version": "0.13.9",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.9.tgz",
|
||||||
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA==",
|
"integrity": "sha512-p3VT+cOEgxFsRRA9X4lkI1E+k2/CtnKtU4gcxyaCUreilL/vqI6CdZ3wxVUx3UOUg+gnUOQQcRI7BmSI656MYA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"regexp.prototype.flags": {
|
"regexp.prototype.flags": {
|
||||||
"version": "1.4.3",
|
"version": "1.4.3",
|
||||||
|
|
|
@ -21,12 +21,13 @@
|
||||||
"@tippyjs/react": "^4.2.6",
|
"@tippyjs/react": "^4.2.6",
|
||||||
"autoprefixer": "^10.4.7",
|
"autoprefixer": "^10.4.7",
|
||||||
"graphql-request": "^4.2.0",
|
"graphql-request": "^4.2.0",
|
||||||
|
"lightgallery": "^2.4.0",
|
||||||
"markdown-to-jsx": "^7.1.7",
|
"markdown-to-jsx": "^7.1.7",
|
||||||
"next": "^12.1.6",
|
"next": "^12.1.6",
|
||||||
"nodemailer": "^6.7.5",
|
"nodemailer": "^6.7.5",
|
||||||
"react": "18.1.0",
|
"react": "18.1.0",
|
||||||
"react-dom": "18.1.0",
|
"react-dom": "18.1.0",
|
||||||
"react-hotkeys-hook": "^3.4.4",
|
"react-hot-keys": "^2.7.2",
|
||||||
"react-swipeable": "^7.0.0",
|
"react-swipeable": "^7.0.0",
|
||||||
"turndown": "^7.1.1"
|
"turndown": "^7.1.1"
|
||||||
},
|
},
|
||||||
|
|
|
@ -39,19 +39,23 @@ export default function AppLayout(props: Props): JSX.Element {
|
||||||
|
|
||||||
const handlers = useSwipeable({
|
const handlers = useSwipeable({
|
||||||
onSwipedLeft: (SwipeEventData) => {
|
onSwipedLeft: (SwipeEventData) => {
|
||||||
if (SwipeEventData.velocity < sensibilitySwipe) return;
|
if (appLayout.menuGestures) {
|
||||||
if (appLayout.mainPanelOpen) {
|
if (SwipeEventData.velocity < sensibilitySwipe) return;
|
||||||
appLayout.setMainPanelOpen(false);
|
if (appLayout.mainPanelOpen) {
|
||||||
} else if (subPanel && contentPanel) {
|
appLayout.setMainPanelOpen(false);
|
||||||
appLayout.setSubPanelOpen(true);
|
} else if (subPanel && contentPanel) {
|
||||||
|
appLayout.setSubPanelOpen(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
onSwipedRight: (SwipeEventData) => {
|
onSwipedRight: (SwipeEventData) => {
|
||||||
if (SwipeEventData.velocity < sensibilitySwipe) return;
|
if (appLayout.menuGestures) {
|
||||||
if (appLayout.subPanelOpen) {
|
if (SwipeEventData.velocity < sensibilitySwipe) return;
|
||||||
appLayout.setSubPanelOpen(false);
|
if (appLayout.subPanelOpen) {
|
||||||
} else {
|
appLayout.setSubPanelOpen(false);
|
||||||
appLayout.setMainPanelOpen(true);
|
} else {
|
||||||
|
appLayout.setMainPanelOpen(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import { Dispatch, SetStateAction, useCallback } from "react";
|
import { Dispatch, SetStateAction } from "react";
|
||||||
import { useHotkeys } from "react-hotkeys-hook";
|
import Hotkeys from "react-hot-keys";
|
||||||
|
import { useSwipeable } from "react-swipeable";
|
||||||
import Img from "./Img";
|
import Img from "./Img";
|
||||||
import Button from "./Inputs/Button";
|
import Button from "./Inputs/Button";
|
||||||
import Popup from "./Popup";
|
import Popup from "./Popup";
|
||||||
|
@ -16,46 +17,73 @@ interface Props {
|
||||||
|
|
||||||
export default function LightBox(props: Props): JSX.Element {
|
export default function LightBox(props: Props): JSX.Element {
|
||||||
const { state, setState, images, index, setIndex } = props;
|
const { state, setState, images, index, setIndex } = props;
|
||||||
const handlePrevious = useCallback(() => {
|
|
||||||
setIndex((previousIndex) => (previousIndex > 0 ? previousIndex - 1 : 0));
|
|
||||||
}, [setIndex]);
|
|
||||||
|
|
||||||
const handleNext = useCallback(() => {
|
function handlePrevious() {
|
||||||
setIndex((previousIndex) =>
|
if (index > 0) setIndex(index - 1);
|
||||||
previousIndex < images.length - 1 ? previousIndex + 1 : images.length - 1
|
}
|
||||||
);
|
|
||||||
}, [images.length, setIndex]);
|
|
||||||
|
|
||||||
useHotkeys("left", handlePrevious);
|
function handleNext() {
|
||||||
useHotkeys("right", handleNext);
|
if (index < images.length - 1) setIndex(index + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
const sensibilitySwipe = 0.5;
|
||||||
|
|
||||||
|
const handlers = useSwipeable({
|
||||||
|
onSwipedLeft: (SwipeEventData) => {
|
||||||
|
if (SwipeEventData.velocity < sensibilitySwipe) return;
|
||||||
|
handleNext();
|
||||||
|
},
|
||||||
|
onSwipedRight: (SwipeEventData) => {
|
||||||
|
if (SwipeEventData.velocity < sensibilitySwipe) return;
|
||||||
|
handlePrevious();
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
{state && (
|
{state && (
|
||||||
<Popup setState={setState} state={state} fillViewport>
|
<Hotkeys
|
||||||
<div
|
keyName="left,right"
|
||||||
className="grid grid-cols-[4em,1fr,4em] place-items-center
|
allowRepeat
|
||||||
gap-4 w-full h-full overflow-hidden"
|
onKeyDown={(keyName) => {
|
||||||
>
|
if (keyName === "left") {
|
||||||
<div>
|
handlePrevious();
|
||||||
{index > 0 && (
|
} else {
|
||||||
<Button onClick={handlePrevious}>
|
handleNext();
|
||||||
<span className="material-icons">chevron_left</span>
|
}
|
||||||
</Button>
|
}}
|
||||||
)}
|
>
|
||||||
</div>
|
<Popup setState={setState} state={state} padding={false} fillViewport>
|
||||||
|
<div
|
||||||
|
{...handlers}
|
||||||
|
className={`grid grid-cols-[4em,1fr,4em] mobile:grid-cols-2
|
||||||
|
[grid-template-areas:"left_image_right"]
|
||||||
|
mobile:[grid-template-areas:"image_image""left_right"]
|
||||||
|
place-items-center first-letter:gap-4 w-full h-full overflow-hidden`}
|
||||||
|
>
|
||||||
|
<div className="[grid-area:left]">
|
||||||
|
{index > 0 && (
|
||||||
|
<Button onClick={handlePrevious}>
|
||||||
|
<span className="material-icons">chevron_left</span>
|
||||||
|
</Button>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
|
|
||||||
<Img className="max-h-full" image={images[index]} />
|
<Img
|
||||||
|
className="max-h-full [grid-area:image]"
|
||||||
|
image={images[index]}
|
||||||
|
/>
|
||||||
|
|
||||||
<div>
|
<div className="[grid-area:right]">
|
||||||
{index < images.length - 1 && (
|
{index < images.length - 1 && (
|
||||||
<Button onClick={handleNext}>
|
<Button onClick={handleNext}>
|
||||||
<span className="material-icons">chevron_right</span>
|
<span className="material-icons">chevron_right</span>
|
||||||
</Button>
|
</Button>
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Popup>
|
||||||
</Popup>
|
</Hotkeys>
|
||||||
)}
|
)}
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
|
|
|
@ -1,4 +1,6 @@
|
||||||
import { Dispatch, SetStateAction } from "react";
|
import { useAppLayout } from "contexts/AppLayoutContext";
|
||||||
|
import { Dispatch, SetStateAction, useEffect } from "react";
|
||||||
|
import Hotkeys from "react-hot-keys";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
setState:
|
setState:
|
||||||
|
@ -8,42 +10,65 @@ interface Props {
|
||||||
children: React.ReactNode;
|
children: React.ReactNode;
|
||||||
fillViewport?: boolean;
|
fillViewport?: boolean;
|
||||||
hideBackground?: boolean;
|
hideBackground?: boolean;
|
||||||
|
padding?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export default function Popup(props: Props): JSX.Element {
|
export default function Popup(props: Props): JSX.Element {
|
||||||
|
const {
|
||||||
|
setState,
|
||||||
|
state,
|
||||||
|
children,
|
||||||
|
fillViewport,
|
||||||
|
hideBackground,
|
||||||
|
padding = true,
|
||||||
|
} = props;
|
||||||
|
|
||||||
|
const appLayout = useAppLayout();
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
appLayout.setMenuGestures(!state);
|
||||||
|
// eslint-disable-next-line react-hooks/exhaustive-deps
|
||||||
|
}, [state]);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div
|
<Hotkeys
|
||||||
className={`fixed inset-0 z-50 grid place-content-center
|
keyName="escape"
|
||||||
transition-[backdrop-filter] duration-500 ${
|
allowRepeat
|
||||||
props.state
|
onKeyDown={() => {
|
||||||
? "[backdrop-filter:blur(2px)]"
|
setState(false);
|
||||||
: "pointer-events-none touch-none"
|
}}
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
<div
|
<div
|
||||||
className={`fixed bg-shade inset-0 transition-all duration-500 ${
|
className={`fixed inset-0 z-50 grid place-content-center
|
||||||
props.state ? "bg-opacity-50" : "bg-opacity-0"
|
transition-[backdrop-filter] duration-500 ${
|
||||||
}`}
|
state ? "[backdrop-filter:blur(2px)]" : "pointer-events-none touch-none"
|
||||||
onClick={() => {
|
}`}
|
||||||
props.setState(false);
|
|
||||||
}}
|
|
||||||
/>
|
|
||||||
|
|
||||||
<div
|
|
||||||
className={`p-10 grid gap-4 place-items-center transition-transform ${
|
|
||||||
props.state ? "scale-100" : "scale-0"
|
|
||||||
} ${
|
|
||||||
props.fillViewport
|
|
||||||
? "absolute inset-10"
|
|
||||||
: "relative max-h-[80vh] overflow-y-auto mobile:w-[85vw]"
|
|
||||||
} ${
|
|
||||||
props.hideBackground
|
|
||||||
? ""
|
|
||||||
: "bg-light rounded-lg shadow-2xl shadow-shade"
|
|
||||||
}`}
|
|
||||||
>
|
>
|
||||||
{props.children}
|
<div
|
||||||
|
className={`fixed bg-shade inset-0 transition-all duration-500 ${
|
||||||
|
state ? "bg-opacity-50" : "bg-opacity-0"
|
||||||
|
}`}
|
||||||
|
onClick={() => {
|
||||||
|
setState(false);
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
|
||||||
|
<div
|
||||||
|
className={`${
|
||||||
|
padding && "p-10 mobile:p-6"
|
||||||
|
} grid gap-4 place-items-center transition-transform ${
|
||||||
|
state ? "scale-100" : "scale-0"
|
||||||
|
} ${
|
||||||
|
fillViewport
|
||||||
|
? "absolute inset-10"
|
||||||
|
: "relative max-h-[80vh] overflow-y-auto mobile:w-[85vw]"
|
||||||
|
} ${
|
||||||
|
hideBackground ? "" : "bg-light rounded-lg shadow-2xl shadow-shade"
|
||||||
|
}`}
|
||||||
|
>
|
||||||
|
{children}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</Hotkeys>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
import useDarkMode from "hooks/useDarkMode";
|
import useDarkMode from "hooks/useDarkMode";
|
||||||
import useStateWithLocalStorage from "hooks/useStateWithLocalStorage";
|
import useStateWithLocalStorage from "hooks/useStateWithLocalStorage";
|
||||||
import React, { ReactNode, useContext } from "react";
|
import React, { ReactNode, useContext, useState } from "react";
|
||||||
|
|
||||||
interface AppLayoutState {
|
interface AppLayoutState {
|
||||||
subPanelOpen: boolean | undefined;
|
subPanelOpen: boolean | undefined;
|
||||||
|
@ -14,6 +14,7 @@ interface AppLayoutState {
|
||||||
currency: string | undefined;
|
currency: string | undefined;
|
||||||
playerName: string | undefined;
|
playerName: string | undefined;
|
||||||
preferredLanguages: string[] | undefined;
|
preferredLanguages: string[] | undefined;
|
||||||
|
menuGestures: boolean;
|
||||||
setSubPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>;
|
setSubPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>;
|
||||||
setConfigPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>;
|
setConfigPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>;
|
||||||
setMainPanelReduced: React.Dispatch<
|
setMainPanelReduced: React.Dispatch<
|
||||||
|
@ -31,6 +32,7 @@ interface AppLayoutState {
|
||||||
setPreferredLanguages: React.Dispatch<
|
setPreferredLanguages: React.Dispatch<
|
||||||
React.SetStateAction<string[] | undefined>
|
React.SetStateAction<string[] | undefined>
|
||||||
>;
|
>;
|
||||||
|
setMenuGestures: React.Dispatch<React.SetStateAction<boolean>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* eslint-disable @typescript-eslint/no-empty-function */
|
/* eslint-disable @typescript-eslint/no-empty-function */
|
||||||
|
@ -46,6 +48,7 @@ const initialState: AppLayoutState = {
|
||||||
currency: "USD",
|
currency: "USD",
|
||||||
playerName: "",
|
playerName: "",
|
||||||
preferredLanguages: [],
|
preferredLanguages: [],
|
||||||
|
menuGestures: true,
|
||||||
setSubPanelOpen: () => {},
|
setSubPanelOpen: () => {},
|
||||||
setMainPanelReduced: () => {},
|
setMainPanelReduced: () => {},
|
||||||
setMainPanelOpen: () => {},
|
setMainPanelOpen: () => {},
|
||||||
|
@ -57,6 +60,7 @@ const initialState: AppLayoutState = {
|
||||||
setCurrency: () => {},
|
setCurrency: () => {},
|
||||||
setPlayerName: () => {},
|
setPlayerName: () => {},
|
||||||
setPreferredLanguages: () => {},
|
setPreferredLanguages: () => {},
|
||||||
|
setMenuGestures: () => {},
|
||||||
};
|
};
|
||||||
/* eslint-enable @typescript-eslint/no-empty-function */
|
/* eslint-enable @typescript-eslint/no-empty-function */
|
||||||
|
|
||||||
|
@ -115,6 +119,8 @@ export function AppContextProvider(props: Props): JSX.Element {
|
||||||
string[] | undefined
|
string[] | undefined
|
||||||
>("preferredLanguages", initialState.preferredLanguages);
|
>("preferredLanguages", initialState.preferredLanguages);
|
||||||
|
|
||||||
|
const [menuGestures, setMenuGestures] = useState(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<AppContext.Provider
|
<AppContext.Provider
|
||||||
value={{
|
value={{
|
||||||
|
@ -129,6 +135,7 @@ export function AppContextProvider(props: Props): JSX.Element {
|
||||||
currency,
|
currency,
|
||||||
playerName,
|
playerName,
|
||||||
preferredLanguages,
|
preferredLanguages,
|
||||||
|
menuGestures,
|
||||||
setSubPanelOpen,
|
setSubPanelOpen,
|
||||||
setConfigPanelOpen,
|
setConfigPanelOpen,
|
||||||
setMainPanelReduced,
|
setMainPanelReduced,
|
||||||
|
@ -140,6 +147,7 @@ export function AppContextProvider(props: Props): JSX.Element {
|
||||||
setCurrency,
|
setCurrency,
|
||||||
setPlayerName,
|
setPlayerName,
|
||||||
setPreferredLanguages,
|
setPreferredLanguages,
|
||||||
|
setMenuGestures,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{props.children}
|
{props.children}
|
||||||
|
|
Loading…
Reference in New Issue