Added support for gestures to open close menus
This commit is contained in:
parent
76deea2aa7
commit
7dd2325e97
|
@ -12,7 +12,8 @@
|
||||||
"markdown-to-jsx": "^7.1.6",
|
"markdown-to-jsx": "^7.1.6",
|
||||||
"next": "^12.0.7",
|
"next": "^12.0.7",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-dom": "17.0.2"
|
"react-dom": "17.0.2",
|
||||||
|
"react-swipeable": "^6.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/typography": "^0.5.0",
|
"@tailwindcss/typography": "^0.5.0",
|
||||||
|
@ -3316,6 +3317,14 @@
|
||||||
"react": "17.0.2"
|
"react": "17.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/react-swipeable": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-swipeable/-/react-swipeable-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-nWQ8dEM8e/uswZLSIkXUsAnQmnX4MTcryOHBQIQYRMJFDpgDBSiVbKsz/BZVCIScF4NtJh16oyxwaNOepR6xSw==",
|
||||||
|
"peerDependencies": {
|
||||||
|
"react": "^16.8.3 || ^17"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/regenerator-runtime": {
|
"node_modules/regenerator-runtime": {
|
||||||
"version": "0.13.4",
|
"version": "0.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz",
|
||||||
|
@ -6464,6 +6473,12 @@
|
||||||
"scheduler": "^0.20.2"
|
"scheduler": "^0.20.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"react-swipeable": {
|
||||||
|
"version": "6.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/react-swipeable/-/react-swipeable-6.2.0.tgz",
|
||||||
|
"integrity": "sha512-nWQ8dEM8e/uswZLSIkXUsAnQmnX4MTcryOHBQIQYRMJFDpgDBSiVbKsz/BZVCIScF4NtJh16oyxwaNOepR6xSw==",
|
||||||
|
"requires": {}
|
||||||
|
},
|
||||||
"regenerator-runtime": {
|
"regenerator-runtime": {
|
||||||
"version": "0.13.4",
|
"version": "0.13.4",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.4.tgz",
|
||||||
|
|
|
@ -15,7 +15,8 @@
|
||||||
"markdown-to-jsx": "^7.1.6",
|
"markdown-to-jsx": "^7.1.6",
|
||||||
"next": "^12.0.7",
|
"next": "^12.0.7",
|
||||||
"react": "17.0.2",
|
"react": "17.0.2",
|
||||||
"react-dom": "17.0.2"
|
"react-dom": "17.0.2",
|
||||||
|
"react-swipeable": "^6.2.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/typography": "^0.5.0",
|
"@tailwindcss/typography": "^0.5.0",
|
||||||
|
|
|
@ -2,6 +2,7 @@ import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
|
||||||
import MainPanel from "./Panels/MainPanel";
|
import MainPanel from "./Panels/MainPanel";
|
||||||
import { useState } from "react";
|
import { useState } from "react";
|
||||||
import Head from "next/head";
|
import Head from "next/head";
|
||||||
|
import { useSwipeable } from "react-swipeable";
|
||||||
|
|
||||||
type AppLayoutProps = {
|
type AppLayoutProps = {
|
||||||
subPanel?: React.ReactNode;
|
subPanel?: React.ReactNode;
|
||||||
|
@ -17,6 +18,14 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
|
||||||
const [mainPanelOpen, setMainPanelOpen] = useState(false);
|
const [mainPanelOpen, setMainPanelOpen] = useState(false);
|
||||||
const [subPanelOpen, setsubPanelOpen] = useState(false);
|
const [subPanelOpen, setsubPanelOpen] = useState(false);
|
||||||
|
|
||||||
|
const handlers = useSwipeable({
|
||||||
|
onSwipedLeft: () =>
|
||||||
|
mainPanelOpen ? setMainPanelOpen(false) : props.subPanel && props.contentPanel ? setsubPanelOpen(true) : "",
|
||||||
|
onSwipedRight: () =>
|
||||||
|
subPanelOpen ? setsubPanelOpen(false) : setMainPanelOpen(true),
|
||||||
|
preventDefaultTouchmoveEvent: true,
|
||||||
|
});
|
||||||
|
|
||||||
const mainPanelClass =
|
const mainPanelClass =
|
||||||
"fixed desktop:left-0 desktop:top-0 desktop:bottom-0 desktop:w-[20rem]";
|
"fixed desktop:left-0 desktop:top-0 desktop:bottom-0 desktop:w-[20rem]";
|
||||||
const subPanelClass =
|
const subPanelClass =
|
||||||
|
@ -34,7 +43,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<div {...handlers}>
|
||||||
<Head>
|
<Head>
|
||||||
<title>
|
<title>
|
||||||
{props.title ? `${titlePrefix} - ${props.title}` : titlePrefix}
|
{props.title ? `${titlePrefix} - ${props.title}` : titlePrefix}
|
||||||
|
@ -75,7 +84,9 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
|
||||||
<div className="grid place-content-center h-full">
|
<div className="grid place-content-center h-full">
|
||||||
<div className="text-dark border-dark border-2 border-dotted rounded-2xl p-8 grid grid-flow-col place-items-center gap-9">
|
<div className="text-dark border-dark border-2 border-dotted rounded-2xl p-8 grid grid-flow-col place-items-center gap-9">
|
||||||
<p className="text-4xl">❮</p>
|
<p className="text-4xl">❮</p>
|
||||||
<p className="text-2xl w-64">Select one of the options in the sidebar</p>
|
<p className="text-2xl w-64">
|
||||||
|
Select one of the options in the sidebar
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
@ -99,7 +110,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
|
||||||
{/* Sub panel */}
|
{/* Sub panel */}
|
||||||
{props.subPanel ? (
|
{props.subPanel ? (
|
||||||
<div
|
<div
|
||||||
className={`${subPanelClass} border-r-[1px] mobile:border-r-0 mobile:border-l-[1px] border-black top-0 bottom-0 right-0 left-12 bg-light overflow-y-scroll webkit-scrollbar:w-0 [scrollbar-width:none] transition-transform duration-500
|
className={`${subPanelClass} border-r-[1px] mobile:border-r-0 mobile:border-l-[1px] border-black top-0 bottom-0 right-0 left-12 bg-light overflow-y-scroll webkit-scrollbar:w-0 [scrollbar-width:none] transition-transform duration-300
|
||||||
${
|
${
|
||||||
turnSubIntoContent
|
turnSubIntoContent
|
||||||
? "mobile:mobile:translate-x-0 mobile:bottom-20 mobile:left-0 mobile:border-l-0"
|
? "mobile:mobile:translate-x-0 mobile:bottom-20 mobile:left-0 mobile:border-l-0"
|
||||||
|
@ -115,11 +126,11 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
|
||||||
|
|
||||||
{/* Main panel */}
|
{/* Main panel */}
|
||||||
<div
|
<div
|
||||||
className={`${mainPanelClass} border-r-[1px] border-black top-0 bottom-0 left-0 right-12 bg-light overflow-y-scroll webkit-scrollbar:w-0 [scrollbar-width:none] transition-transform duration-500 z-20
|
className={`${mainPanelClass} border-r-[1px] border-black top-0 bottom-0 left-0 right-12 bg-light overflow-y-scroll webkit-scrollbar:w-0 [scrollbar-width:none] transition-transform duration-300 z-20
|
||||||
${mainPanelOpen ? "" : "mobile:-translate-x-full"}`}
|
${mainPanelOpen ? "" : "mobile:-translate-x-full"}`}
|
||||||
>
|
>
|
||||||
<MainPanel langui={props.langui} />
|
<MainPanel langui={props.langui} />
|
||||||
</div>
|
</div>
|
||||||
</>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,67 +0,0 @@
|
||||||
import Link from "next/link";
|
|
||||||
import { GetLibraryItemsPreviewQuery } from "graphql/operations-types";
|
|
||||||
import { getAssetURL, prettyDate, prettyPrice } from "queries/helpers";
|
|
||||||
import Image from "next/image";
|
|
||||||
|
|
||||||
export type LibraryContentPreviewProps = {
|
|
||||||
item: {
|
|
||||||
slug: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["slug"];
|
|
||||||
thumbnail: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["thumbnail"];
|
|
||||||
title: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["title"];
|
|
||||||
subtitle: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["subtitle"];
|
|
||||||
price?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["price"];
|
|
||||||
release_date?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["release_date"];
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
export default function LibraryContentPreview(
|
|
||||||
props: LibraryContentPreviewProps
|
|
||||||
): JSX.Element {
|
|
||||||
const item = props.item;
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Link href={"/library/media/" + item.slug} passHref>
|
|
||||||
<div className="drop-shadow-dark-xl cursor-pointer grid items-end hover:rounded-3xl [--cover-opacity:0] hover:[--cover-opacity:1] hover:scale-[1.02] transition-transform">
|
|
||||||
{item.thumbnail.data ? (
|
|
||||||
<Image
|
|
||||||
src={getAssetURL(item.thumbnail.data.attributes.url)}
|
|
||||||
alt={item.thumbnail.data.attributes.alternativeText}
|
|
||||||
height={item.thumbnail.data.attributes.height}
|
|
||||||
width={item.thumbnail.data.attributes.width}
|
|
||||||
/>
|
|
||||||
) : (
|
|
||||||
<div className="w-full aspect-[21/29.7] bg-light rounded-lg"></div>
|
|
||||||
)}
|
|
||||||
<div className="linearbg-1 drop-shadow-dark-lg absolute bottom-2 inset-x-[-0.15rem] opacity-[var(--cover-opacity)] transition-opacity z-20 grid p-4 gap-4 text-left">
|
|
||||||
<div>
|
|
||||||
<h2 className="text-lg leading-7">{item.title}</h2>
|
|
||||||
<h3 className="leading-3">{item.subtitle}</h3>
|
|
||||||
</div>
|
|
||||||
<div className="grid grid-flow-col">
|
|
||||||
{item.release_date ? (
|
|
||||||
<p className="text-sm">
|
|
||||||
<span className="material-icons !text-base translate-y-[.15em] mr-1">
|
|
||||||
event
|
|
||||||
</span>
|
|
||||||
{prettyDate(item.release_date)}
|
|
||||||
</p>
|
|
||||||
) : (
|
|
||||||
""
|
|
||||||
)}
|
|
||||||
{item.price ? (
|
|
||||||
<p className="text-sm justify-self-end">
|
|
||||||
<span className="material-icons !text-base translate-y-[.15em] mr-1">
|
|
||||||
shopping_cart
|
|
||||||
</span>
|
|
||||||
{prettyPrice(item.price)}
|
|
||||||
</p>
|
|
||||||
) : (
|
|
||||||
""
|
|
||||||
)}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</Link>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
@ -8,6 +8,7 @@ type PanelHeaderProps = {
|
||||||
|
|
||||||
export default function PanelHeader(props: PanelHeaderProps): JSX.Element {
|
export default function PanelHeader(props: PanelHeaderProps): JSX.Element {
|
||||||
return (
|
return (
|
||||||
|
<>
|
||||||
<div className="w-full grid place-items-center">
|
<div className="w-full grid place-items-center">
|
||||||
{props.icon ? (
|
{props.icon ? (
|
||||||
<span className="material-icons !text-4xl mb-3">{props.icon}</span>
|
<span className="material-icons !text-4xl mb-3">{props.icon}</span>
|
||||||
|
@ -16,7 +17,8 @@ export default function PanelHeader(props: PanelHeaderProps): JSX.Element {
|
||||||
)}
|
)}
|
||||||
<h2 className="text-2xl">{props.title}</h2>
|
<h2 className="text-2xl">{props.title}</h2>
|
||||||
{props.description ? <p>{props.description}</p> : ""}
|
{props.description ? <p>{props.description}</p> : ""}
|
||||||
<HorizontalLine />
|
|
||||||
</div>
|
</div>
|
||||||
|
<HorizontalLine />
|
||||||
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,7 @@ import Button from "components/Button";
|
||||||
import HorizontalLine from "components/HorizontalLine";
|
import HorizontalLine from "components/HorizontalLine";
|
||||||
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
|
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
|
||||||
import Markdown from "markdown-to-jsx";
|
import Markdown from "markdown-to-jsx";
|
||||||
|
import Script from "next/script";
|
||||||
|
|
||||||
type MainPanelProps = {
|
type MainPanelProps = {
|
||||||
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
|
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
|
||||||
|
@ -15,18 +16,21 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
|
||||||
const langui = props.langui;
|
const langui = props.langui;
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
return (
|
return (
|
||||||
<div className="grid justify-center content-start p-8 gap-y-2 justify-items-center text-center">
|
<div
|
||||||
|
id="mainPanel"
|
||||||
|
className="flex flex-col justify-center content-start p-8 gap-y-2 justify-items-center text-center"
|
||||||
|
>
|
||||||
<div className="">
|
<div className="">
|
||||||
<div className="grid place-items-center">
|
<div className="grid place-items-center mobile:grid-flow-col">
|
||||||
<Link href="/" passHref>
|
<Link href="/" passHref>
|
||||||
<div className="w-1/2 cursor-pointer transition-[filter] hover:colorize-dark">
|
<div className="mobile:w-10 mobile:self-end w-1/2 cursor-pointer transition-[filter] hover:colorize-dark">
|
||||||
<SVG
|
<SVG
|
||||||
src={"/icons/accords.svg"}
|
src={"/icons/accords.svg"}
|
||||||
alt={"Logo of Accord's Library"}
|
alt={"Logo of Accord's Library"}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
</Link>
|
</Link>
|
||||||
<div className="relative mt-5">
|
<div className="relative mt-5 mobile:self-start">
|
||||||
{router.locale ? (
|
{router.locale ? (
|
||||||
<Button className="absolute right-0 top-[-1.3em] text-xs !py-0.5 !px-2.5">
|
<Button className="absolute right-0 top-[-1.3em] text-xs !py-0.5 !px-2.5">
|
||||||
{router.locale.toUpperCase()}
|
{router.locale.toUpperCase()}
|
||||||
|
|
|
@ -4,7 +4,7 @@ type SubPanelProps = {
|
||||||
|
|
||||||
export default function SubPanel(props: SubPanelProps): JSX.Element {
|
export default function SubPanel(props: SubPanelProps): JSX.Element {
|
||||||
return (
|
return (
|
||||||
<div className="grid p-8 gap-y-2 justify-items-center text-center">
|
<div className="flex flex-col p-8 gap-y-2 justify-items-center text-center mobile:h-full">
|
||||||
{props.children}
|
{props.children}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|
|
@ -4,7 +4,6 @@ import SVG from "components/SVG";
|
||||||
import { getWebsiteInterface } from "graphql/operations";
|
import { getWebsiteInterface } from "graphql/operations";
|
||||||
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
|
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
|
||||||
import { GetStaticProps } from "next";
|
import { GetStaticProps } from "next";
|
||||||
import Script from "next/script";
|
|
||||||
type HomeProps = {
|
type HomeProps = {
|
||||||
langui: GetWebsiteInterfaceQuery;
|
langui: GetWebsiteInterfaceQuery;
|
||||||
};
|
};
|
||||||
|
@ -24,19 +23,6 @@ export default function Home(props: HomeProps): JSX.Element {
|
||||||
<h2 className="mt-0">Discover • Analyse • Translate • Archive</h2>
|
<h2 className="mt-0">Discover • Analyse • Translate • Archive</h2>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<button id="goFS">Go fullscreen</button>
|
|
||||||
<Script
|
|
||||||
id="myScript"
|
|
||||||
strategy="afterInteractive"
|
|
||||||
dangerouslySetInnerHTML={{
|
|
||||||
__html: `
|
|
||||||
var goFS = document.getElementById("goFS");
|
|
||||||
goFS.addEventListener("click", function() {
|
|
||||||
document.body.requestFullscreen();
|
|
||||||
}, false);`,
|
|
||||||
}}
|
|
||||||
></Script>
|
|
||||||
|
|
||||||
<h2>What is this?</h2>
|
<h2>What is this?</h2>
|
||||||
<p>
|
<p>
|
||||||
Accord’s Library aims at gathering and archiving all of Yoko
|
Accord’s Library aims at gathering and archiving all of Yoko
|
||||||
|
|
|
@ -50,6 +50,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
||||||
/>
|
/>
|
||||||
<HorizontalLine />
|
<HorizontalLine />
|
||||||
|
|
||||||
|
<div className="grid gap-4">
|
||||||
<NavOption
|
<NavOption
|
||||||
title={langui.library_item_summary}
|
title={langui.library_item_summary}
|
||||||
url="#summary"
|
url="#summary"
|
||||||
|
@ -101,6 +102,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
|
||||||
) : (
|
) : (
|
||||||
""
|
""
|
||||||
)}
|
)}
|
||||||
|
</div>
|
||||||
</SubPanel>
|
</SubPanel>
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue