diff --git a/.github/workflows/node.js.yml b/.github/workflows/node.js.yml
deleted file mode 100644
index a5242e0..0000000
--- a/.github/workflows/node.js.yml
+++ /dev/null
@@ -1,37 +0,0 @@
-# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node
-# For more information see: https://help.github.com/actions/language-and-framework-guides/using-nodejs-with-github-actions
-
-name: Node.js CI
-
-on:
-# push:
-# branches: [ main ]
- pull_request:
- branches: [ main ]
-
-jobs:
- build:
-
- runs-on: ubuntu-latest
-
- strategy:
- matrix:
- node-version: [16.x]
- # See supported Node.js release schedule at https://nodejs.org/en/about/releases/
-
- steps:
- - uses: actions/checkout@v2
- - name: Use Node.js ${{ matrix.node-version }}
- uses: actions/setup-node@v2
- with:
- node-version: ${{ matrix.node-version }}
- cache: 'npm'
- - run: npm ci
- - run: npm run lint
- - run: npm run build --if-present
- env:
- ACCESS_TOKEN: ${{ secrets.ACCESS_TOKEN }}
- NEXT_PUBLIC_URL_CMS: ${{ secrets.NEXT_PUBLIC_URL_CMS }}
- NEXT_PUBLIC_URL_IMG: ${{ secrets.NEXT_PUBLIC_URL_IMG }}
- NEXT_PUBLIC_URL_SELF: ${{ secrets.NEXT_PUBLIC_URL_SELF }}
- URL_GRAPHQL: ${{ secrets.URL_GRAPHQL }}
diff --git a/README.md b/README.md
index 0f72637..7912e64 100644
--- a/README.md
+++ b/README.md
@@ -1,9 +1,5 @@
# Accords-library.com
-[![Node.js CI](https://github.com/Accords-Library/accords-library.com/actions/workflows/node.js.yml/badge.svg?branch=main)](https://github.com/Accords-Library/accords-library.com/actions/workflows/node.js.yml)
-[![GitHub](https://img.shields.io/github/license/Accords-Library/accords-library.com?style=flat-square)](https://github.com/Accords-Library/accords-library.com/blob/main/LICENSE)
-![Libraries.io dependency status for GitHub repo](https://img.shields.io/librariesio/github/Accords-Library/accords-library.com?style=flat-square)
-
## Technologies
#### [Back](https://github.com/Accords-Library/strapi.accords-library.com)
diff --git a/package-lock.json b/package-lock.json
index e9fc868..a6f4ebf 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -16,6 +16,7 @@
"next": "^12.1.0",
"react": "17.0.2",
"react-dom": "17.0.2",
+ "react-image-lightbox": "^5.1.4",
"react-swipeable": "^6.2.0",
"turndown": "^7.1.1"
},
@@ -1707,6 +1708,11 @@
"node": ">=0.10.0"
}
},
+ "node_modules/exenv": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
+ "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50="
+ },
"node_modules/fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -2982,7 +2988,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -3055,11 +3060,46 @@
"react": "17.0.2"
}
},
+ "node_modules/react-image-lightbox": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/react-image-lightbox/-/react-image-lightbox-5.1.4.tgz",
+ "integrity": "sha512-kTiAODz091bgT7SlWNHab0LSMZAPJtlNWDGKv7pLlLY1krmf7FuG1zxE0wyPpeA8gPdwfr3cu6sPwZRqWsc3Eg==",
+ "dependencies": {
+ "prop-types": "^15.7.2",
+ "react-modal": "^3.11.1"
+ },
+ "peerDependencies": {
+ "react": "16.x || 17.x",
+ "react-dom": "16.x || 17.x"
+ }
+ },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ },
+ "node_modules/react-lifecycles-compat": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+ },
+ "node_modules/react-modal": {
+ "version": "3.14.4",
+ "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.14.4.tgz",
+ "integrity": "sha512-8surmulejafYCH9wfUmFyj4UfbSJwjcgbS9gf3oOItu4Hwd6ivJyVBETI0yHRhpJKCLZMUtnhzk76wXTsNL6Qg==",
+ "dependencies": {
+ "exenv": "^1.2.0",
+ "prop-types": "^15.7.2",
+ "react-lifecycles-compat": "^3.0.0",
+ "warning": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "peerDependencies": {
+ "react": "^0.14.0 || ^15.0.0 || ^16 || ^17",
+ "react-dom": "^0.14.0 || ^15.0.0 || ^16 || ^17"
+ }
},
"node_modules/react-swipeable": {
"version": "6.2.0",
@@ -3577,6 +3617,14 @@
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
"dev": true
},
+ "node_modules/warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "dependencies": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"node_modules/which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
@@ -4858,6 +4906,11 @@
"integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==",
"dev": true
},
+ "exenv": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/exenv/-/exenv-1.2.2.tgz",
+ "integrity": "sha1-KueOhdmJQVhnCwPUe+wfA72Ru50="
+ },
"fast-deep-equal": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz",
@@ -5761,7 +5814,6 @@
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
- "dev": true,
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
@@ -5805,11 +5857,35 @@
"scheduler": "^0.20.2"
}
},
+ "react-image-lightbox": {
+ "version": "5.1.4",
+ "resolved": "https://registry.npmjs.org/react-image-lightbox/-/react-image-lightbox-5.1.4.tgz",
+ "integrity": "sha512-kTiAODz091bgT7SlWNHab0LSMZAPJtlNWDGKv7pLlLY1krmf7FuG1zxE0wyPpeA8gPdwfr3cu6sPwZRqWsc3Eg==",
+ "requires": {
+ "prop-types": "^15.7.2",
+ "react-modal": "^3.11.1"
+ }
+ },
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
- "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==",
- "dev": true
+ "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
+ },
+ "react-lifecycles-compat": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz",
+ "integrity": "sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA=="
+ },
+ "react-modal": {
+ "version": "3.14.4",
+ "resolved": "https://registry.npmjs.org/react-modal/-/react-modal-3.14.4.tgz",
+ "integrity": "sha512-8surmulejafYCH9wfUmFyj4UfbSJwjcgbS9gf3oOItu4Hwd6ivJyVBETI0yHRhpJKCLZMUtnhzk76wXTsNL6Qg==",
+ "requires": {
+ "exenv": "^1.2.0",
+ "prop-types": "^15.7.2",
+ "react-lifecycles-compat": "^3.0.0",
+ "warning": "^4.0.3"
+ }
},
"react-swipeable": {
"version": "6.2.0",
@@ -6171,6 +6247,14 @@
"integrity": "sha512-l8lCEmLcLYZh4nbunNZvQCJc5pv7+RCwa8q/LdUx8u7lsWvPDKmpodJAJNwkAhJC//dFY48KuIEmjtd4RViDrA==",
"dev": true
},
+ "warning": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/warning/-/warning-4.0.3.tgz",
+ "integrity": "sha512-rpJyN222KWIvHJ/F53XSZv0Zl/accqHR8et1kpaMTD/fLCRxtV8iX8czMzY7sVZupTI3zcUTg8eycS2kNF9l6w==",
+ "requires": {
+ "loose-envify": "^1.0.0"
+ }
+ },
"which": {
"version": "2.0.2",
"resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz",
diff --git a/package.json b/package.json
index 07b9196..69a7da8 100644
--- a/package.json
+++ b/package.json
@@ -18,6 +18,7 @@
"next": "^12.1.0",
"react": "17.0.2",
"react-dom": "17.0.2",
+ "react-image-lightbox": "^5.1.4",
"react-swipeable": "^6.2.0",
"turndown": "^7.1.1"
},
diff --git a/src/components/AppLayout.tsx b/src/components/AppLayout.tsx
index 4d43c9d..97fc640 100644
--- a/src/components/AppLayout.tsx
+++ b/src/components/AppLayout.tsx
@@ -111,6 +111,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
return (
{props.children}
diff --git a/src/components/Content/ThumbnailHeader.tsx b/src/components/Content/ThumbnailHeader.tsx
index b9bfd44..89607d0 100644
--- a/src/components/Content/ThumbnailHeader.tsx
+++ b/src/components/Content/ThumbnailHeader.tsx
@@ -3,95 +3,88 @@ import {
GetWebsiteInterfaceQuery,
} from "graphql/operations-types";
import { prettyinlineTitle, prettySlug, slugify } from "queries/helpers";
-import Button from "components/Button";
import Img, { ImageQuality } from "components/Img";
import InsetBox from "components/InsetBox";
import Chip from "components/Chip";
export type ThumbnailHeaderProps = {
- content: {
- slug: GetContentQuery["contents"]["data"][number]["attributes"]["slug"];
- thumbnail: GetContentQuery["contents"]["data"][number]["attributes"]["thumbnail"];
- titles: GetContentQuery["contents"]["data"][number]["attributes"]["titles"];
- type: GetContentQuery["contents"]["data"][number]["attributes"]["type"];
- categories: GetContentQuery["contents"]["data"][number]["attributes"]["categories"];
- };
+ pre_title?: string;
+ title: string;
+ subtitle?: string;
+ description?: string;
+ type?: GetContentQuery["contents"]["data"][number]["attributes"]["type"];
+ categories?: GetContentQuery["contents"]["data"][number]["attributes"]["categories"];
+ thumbnail?: GetContentQuery["contents"]["data"][number]["attributes"]["thumbnail"];
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
};
export default function ThumbnailHeader(
props: ThumbnailHeaderProps
): JSX.Element {
- const content = props.content;
- const langui = props.langui;
+ const {
+ langui,
+ pre_title,
+ title,
+ subtitle,
+ thumbnail,
+ type,
+ categories,
+ description,
+ } = props;
return (
<>
- {content.thumbnail.data ? (
+ {thumbnail && thumbnail.data ? (
) : (
-
+
)}
0
- ? prettyinlineTitle(
- content.titles[0].pre_title,
- content.titles[0].title,
- content.titles[0].subtitle
- )
- : prettySlug(content.slug)
+ prettyinlineTitle(pre_title || "", title, subtitle || "")
)}
className="grid place-items-center text-center"
>
- {content.titles.length > 0 ? (
- <>
-
{content.titles[0].pre_title}
-
{content.titles[0].title}
-
{content.titles[0].subtitle}
- >
- ) : (
-
{prettySlug(content.slug)}
- )}
+
{pre_title}
+
{title}
+
{subtitle}
- {content.type && (
+ {type && type.data && (
{langui.type}
- {content.type.data.attributes.titles.length > 0
- ? content.type.data.attributes.titles[0].title
- : prettySlug(content.type.data.attributes.slug)}
+ {type.data.attributes.titles.length > 0
+ ? type.data.attributes.titles[0].title
+ : prettySlug(type.data.attributes.slug)}
)}
- {content.categories.data.length > 0 && (
+ {categories && categories.data.length > 0 && (
{langui.categories}
- {content.categories.data.map((category) => (
+ {categories.data.map((category) => (
{category.attributes.name}
))}
)}
- {content.titles.length > 0 && content.titles[0].description && (
- {content.titles[0].description}
- )}
+ {description && {description}}
>
);
}
diff --git a/src/components/Img.tsx b/src/components/Img.tsx
index 8723bbb..24861e5 100644
--- a/src/components/Img.tsx
+++ b/src/components/Img.tsx
@@ -50,7 +50,7 @@ export function getImgSizesByQuality(
type ImgProps = {
className?: string;
- image: StrapiImage;
+ image?: StrapiImage;
quality?: ImageQuality;
alt?: ImageProps["alt"];
layout?: ImageProps["layout"];
@@ -60,42 +60,46 @@ type ImgProps = {
};
export default function Img(props: ImgProps): JSX.Element {
- const imgSize = getImgSizesByQuality(
- props.image.width,
- props.image.height,
- props.quality ? props.quality : ImageQuality.Small
- );
+ if (props.image) {
+ const imgSize = getImgSizesByQuality(
+ props.image.width,
+ props.image.height,
+ props.quality ? props.quality : ImageQuality.Small
+ );
- if (props.rawImg) {
- return (
- // eslint-disable-next-line @next/next/no-img-element
-
- );
+ if (props.rawImg) {
+ return (
+ // eslint-disable-next-line @next/next/no-img-element
+
+ );
+ } else {
+ return (
+
+ );
+ }
} else {
- return (
-
- );
+ return <>>;
}
}
diff --git a/src/components/LightBox.tsx b/src/components/LightBox.tsx
new file mode 100644
index 0000000..5def290
--- /dev/null
+++ b/src/components/LightBox.tsx
@@ -0,0 +1,39 @@
+import { useMediaMobile } from "hooks/useMediaQuery";
+import { Dispatch, SetStateAction } from "react";
+import Lightbox from "react-image-lightbox";
+
+export type LightBoxProps = {
+ setState:
+ | Dispatch>
+ | Dispatch>;
+ state: boolean;
+ images: string[];
+ index: number;
+ setIndex: Dispatch>;
+};
+
+export default function LightBox(props: LightBoxProps): JSX.Element {
+ const { state, setState, images, index, setIndex } = props;
+ const mobile = useMediaMobile();
+
+ return (
+ <>
+ {state && (
+ document.getElementById("MyAppLayout"),
+ }}
+ mainSrc={images[index]}
+ prevSrc={index > 0 ? images[index - 1] : undefined}
+ nextSrc={index < images.length ? images[index + 1] : undefined}
+ onMovePrevRequest={() => setIndex(index - 1)}
+ onMoveNextRequest={() => setIndex(index + 1)}
+ imageCaption=""
+ imageTitle=""
+ onCloseRequest={() => setState(false)}
+ imagePadding={mobile ? 0 : 70}
+ />
+ )}
+ >
+ );
+}
diff --git a/src/components/Markdown/Markdawn.tsx b/src/components/Markdown/Markdawn.tsx
index 51c71ba..4cb08c1 100644
--- a/src/components/Markdown/Markdawn.tsx
+++ b/src/components/Markdown/Markdawn.tsx
@@ -1,10 +1,12 @@
import HorizontalLine from "components/HorizontalLine";
+import Img, { getAssetURL, ImageQuality } from "components/Img";
import InsetBox from "components/InsetBox";
+import LightBox from "components/LightBox";
import ToolTip from "components/ToolTip";
import { useAppLayout } from "contexts/AppLayoutContext";
import Markdown from "markdown-to-jsx";
import { slugify } from "queries/helpers";
-import React from "react";
+import React, { useState } from "react";
type ScenBreakProps = {
className?: string;
@@ -15,177 +17,353 @@ export default function Markdawn(props: ScenBreakProps): JSX.Element {
const appLayout = useAppLayout();
const text = preprocessMarkDawn(props.text);
+ const [lightboxOpen, setLightboxOpen] = useState(false);
+ const [lightboxImages, setLightboxImages] = useState([""]);
+ const [lightboxIndex, setLightboxIndex] = useState(0);
+
if (text) {
return (
- {
- return (
-
-
+ <>
+
+ {
+ return (
+
+
+ {props.children}
+
+
+
+ );
+ },
+ },
+ h2: {
+ component: (props: {
+ id: string;
+ style: React.CSSProperties;
+ children: React.ReactNode;
+ }) => {
+ return (
+
+
+ {props.children}
+
+
+
+ );
+ },
+ },
+ h3: {
+ component: (props: {
+ id: string;
+ style: React.CSSProperties;
+ children: React.ReactNode;
+ }) => {
+ return (
+
+
+ {props.children}
+
+
+
+ );
+ },
+ },
+ h4: {
+ component: (props: {
+ id: string;
+ style: React.CSSProperties;
+ children: React.ReactNode;
+ }) => {
+ return (
+
+
+ {props.children}
+
+
+
+ );
+ },
+ },
+ h5: {
+ component: (props: {
+ id: string;
+ style: React.CSSProperties;
+ children: React.ReactNode;
+ }) => {
+ return (
+
+
+ {props.children}
+
+
+
+ );
+ },
+ },
+ h6: {
+ component: (props: {
+ id: string;
+ style: React.CSSProperties;
+ children: React.ReactNode;
+ }) => {
+ return (
+
+
+ {props.children}
+
+
+
+ );
+ },
+ },
+ Sep: {
+ component: () => {
+ return ;
+ },
+ },
+ SceneBreak: {
+ component: (props: { id: string }) => {
+ return (
+
+ * * *
+
+ );
+ },
+ },
+ player: {
+ component: () => {
+ return (
+
+ {appLayout.playerName ? appLayout.playerName : ""}
+
+ );
+ },
+ },
+ Transcript: {
+ component: (props) => {
+ return (
+
{props.children}
-
-
-
- {
- navigator.clipboard.writeText(
- process.env.NEXT_PUBLIC_URL_SELF +
- window.location.pathname +
- "#" +
- props.id
- );
- }}
- >
- link
-
-
-
-
- );
+
+ );
+ },
},
- },
- h3: {
- component: (props: {
- id: string;
- style: React.CSSProperties;
- children: React.ReactNode;
- }) => {
- return (
-
-
+ Line: {
+ component: (props) => {
+ return (
+ <>
+
+ {props.name}
+
+
{props.children}
+ >
+ );
+ },
+ },
+ InsetBox: {
+ component: (props) => {
+ return (
+
{props.children}
+ );
+ },
+ },
+ li: {
+ component: (props: { children: React.ReactNode }) => {
+ return (
+
100
+ ? "my-4"
+ : ""
+ }
+ >
{props.children}
-
-
-
- {
- navigator.clipboard.writeText(
- process.env.NEXT_PUBLIC_URL_SELF +
- window.location.pathname +
- "#" +
- props.id
- );
- }}
- >
- link
-
-
-
-
- );
+
+ );
+ },
+ },
+ Highlight: {
+ component: (props: { children: React.ReactNode }) => {
+ return {props.children};
+ },
+ },
+ footer: {
+ component: (props: { children: React.ReactNode }) => {
+ return (
+ <>
+
+ {props.children}
+ >
+ );
+ },
+ },
+ img: {
+ component: (props: {
+ alt: string;
+ src: string;
+ width?: number;
+ height?: number;
+ caption?: string;
+ name?: string;
+ }) => {
+ return (
+ {
+ setLightboxOpen(true);
+ setLightboxImages([
+ props.src.startsWith("/uploads/")
+ ? getAssetURL(props.src, ImageQuality.Large)
+ : props.src,
+ ]);
+ setLightboxIndex(0);
+ }}
+ >
+ {props.src.startsWith("/uploads/") ? (
+
+
+
+ ) : (
+
+
+
+ )}
+
+ );
+ },
},
},
- Sep: {
- component: () => {
- return ;
- },
- },
- SceneBreak: {
- component: (props: { id: string }) => {
- return (
-
- * * *
-
- );
- },
- },
- player: {
- component: () => {
- return (
-
- {appLayout.playerName ? appLayout.playerName : ""}
-
- );
- },
- },
- Transcript: {
- component: (props) => {
- return (
-
- {props.children}
-
- );
- },
- },
- Line: {
- component: (props) => {
- return (
- <>
-
- {props.name}
-
- {props.children}
- >
- );
- },
- },
- InsetBox: {
- component: (props) => {
- return {props.children};
- },
- },
- li: {
- component: (props: { children: React.ReactNode }) => {
- return (
- 100
- ? "my-4"
- : ""
- }
- >
- {props.children}
-
- );
- },
- },
- Highlight: {
- component: (props: { children: React.ReactNode }) => {
- return {props.children};
- },
- },
- footer: {
- component: (props: { children: React.ReactNode }) => {
- return (
- <>
-
- {props.children}
- >
- );
- },
- },
- },
- }}
- >
- {text}
-
+ }}
+ >
+ {text}
+
+ >
);
}
return <>>;
}
+function HeaderToolTip(props: { id: string }) {
+ return (
+
+
+ {
+ navigator.clipboard.writeText(
+ process.env.NEXT_PUBLIC_URL_SELF +
+ window.location.pathname +
+ "#" +
+ props.id
+ );
+ }}
+ >
+ link
+
+
+
+ );
+}
+
export function preprocessMarkDawn(text: string): string {
let scenebreakIndex = 0;
+ const visitedSlugs: string[] = [];
+
const result = text.split("\n").map((line) => {
if (line === "* * *" || line === "---") {
scenebreakIndex++;
return ``;
}
+
+ if (line.startsWith("# ")) {
+ return markdawnHeadersParser(headerLevels.h1, line, visitedSlugs);
+ }
+
+ if (line.startsWith("## ")) {
+ return markdawnHeadersParser(headerLevels.h2, line, visitedSlugs);
+ }
+
+ if (line.startsWith("### ")) {
+ return markdawnHeadersParser(headerLevels.h3, line, visitedSlugs);
+ }
+
+ if (line.startsWith("#### ")) {
+ return markdawnHeadersParser(headerLevels.h4, line, visitedSlugs);
+ }
+
+ if (line.startsWith("##### ")) {
+ return markdawnHeadersParser(headerLevels.h5, line, visitedSlugs);
+ }
+
+ if (line.startsWith("###### ")) {
+ return markdawnHeadersParser(headerLevels.h6, line, visitedSlugs);
+ }
+
return line;
});
return result.join("\n");
}
+
+enum headerLevels {
+ h1 = 1,
+ h2 = 2,
+ h3 = 3,
+ h4 = 4,
+ h5 = 5,
+ h6 = 6,
+}
+
+function markdawnHeadersParser(
+ headerLevel: headerLevels,
+ line: string,
+ visitedSlugs: string[]
+): string {
+ const lineText = line.slice(headerLevel + 1);
+ let slug = slugify(lineText);
+ let newSlug = slug;
+ let index = 2;
+ while (visitedSlugs.includes(newSlug)) {
+ newSlug = `${slug}-${index}`;
+ index++;
+ }
+ visitedSlugs.push(newSlug);
+ return `<${headerLevels[headerLevel]} id="${newSlug}">${lineText}${headerLevels[headerLevel]}>`;
+}
+function getAssetUrl(): React.SetStateAction {
+ throw new Error("Function not implemented.");
+}
diff --git a/src/components/Markdown/TOC.tsx b/src/components/Markdown/TOC.tsx
index ed2ce6b..8e50a0e 100644
--- a/src/components/Markdown/TOC.tsx
+++ b/src/components/Markdown/TOC.tsx
@@ -13,44 +13,55 @@ export default function TOC(props: TOCProps): JSX.Element {
const toc = getTocFromMarkdawn(preprocessMarkDawn(text), title);
return (
-
+ <>
Table of content
-
- -
+
+
+
+
+ >
+ );
+}
+
+type TOCLevelProps = {
+ tocchildren: TOC[];
+ parentNumbering: string;
+ router: NextRouter;
+};
+
+function TOCLevel(props: TOCLevelProps): JSX.Element {
+ const { tocchildren, parentNumbering, router } = props;
+ return (
+
+ {tocchildren.map((child, childIndex) => (
+ <>
+ -
+ {`${parentNumbering}${
+ childIndex + 1
+ }.`}
+ router.replace(`#${child.slug}`)}>
+ {{child.title}}
+
+
+
+ >
+ ))}
+
);
}
@@ -69,13 +80,23 @@ export function getTocFromMarkdawn(text: string, title?: string): TOC {
let h5 = -1;
let scenebreak = 0;
let scenebreakIndex = 0;
+
+ function getTitle(line: string): string {
+ return line.slice(line.indexOf(`">`) + 2, line.indexOf(""));
+ }
+
+ function getSlug(line: string): string {
+ return line.slice(line.indexOf(`id="`) + 4, line.indexOf(`">`));
+ }
+
text.split("\n").map((line) => {
- if (line.startsWith("# ")) {
- toc.slug = slugify(line);
- } else if (line.startsWith("## ")) {
+ if (line.startsWith("= 0) {
- toc.children[h2].children[h3].children[h4].children[h5].children.push({
- title: `Scene break ${scenebreak}`,
- slug: slugify(`scene-break-${scenebreakIndex}`),
- children: [],
- });
+ toc.children[h2].children[h3].children[h4].children[h5].children.push(
+ child
+ );
} else if (h4 >= 0) {
- toc.children[h2].children[h3].children[h4].children.push({
- title: `Scene break ${scenebreak}`,
- slug: slugify(`scene-break-${scenebreakIndex}`),
- children: [],
- });
+ toc.children[h2].children[h3].children[h4].children.push(child);
} else if (h3 >= 0) {
- toc.children[h2].children[h3].children.push({
- title: `Scene break ${scenebreak}`,
- slug: slugify(`scene-break-${scenebreakIndex}`),
- children: [],
- });
+ toc.children[h2].children[h3].children.push(child);
} else if (h2 >= 0) {
- toc.children[h2].children.push({
- title: `Scene break ${scenebreak}`,
- slug: slugify(`scene-break-${scenebreakIndex}`),
- children: [],
- });
+ toc.children[h2].children.push(child);
} else {
- toc.children.push({
- title: `Scene break ${scenebreak}`,
- slug: slugify(`scene-break-${scenebreakIndex}`),
- children: [],
- });
+ toc.children.push(child);
}
}
});
+
return toc;
}
diff --git a/src/components/News/PostsPreview.tsx b/src/components/News/PostsPreview.tsx
new file mode 100644
index 0000000..ee0fdc9
--- /dev/null
+++ b/src/components/News/PostsPreview.tsx
@@ -0,0 +1,64 @@
+import Link from "next/link";
+import { prettyDate, prettySlug } from "queries/helpers";
+import Chip from "components/Chip";
+import Img, { ImageQuality } from "components/Img";
+import { GetPostsPreviewQuery } from "graphql/operations-types";
+
+export type PostPreviewProps = {
+ post: {
+ slug: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["slug"];
+ thumbnail: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["thumbnail"];
+ translations: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["translations"];
+ categories: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["categories"];
+ date: GetPostsPreviewQuery["posts"]["data"][number]["attributes"]["date"];
+ };
+};
+
+export default function PostPreview(props: PostPreviewProps): JSX.Element {
+ const post = props.post;
+
+ return (
+
+
+ {post.thumbnail.data ? (
+
+ ) : (
+
+ )}
+
+
+ {post.date && (
+
+
+ event
+
+ {prettyDate(post.date)}
+
+ )}
+
+
+ {post.translations.length > 0 ? (
+ <>
+
{post.translations[0].title}
+
{post.translations[0].excerpt}
+ >
+ ) : (
+
{prettySlug(post.slug)}
+ )}
+
+
+ {post.categories.data.map((category) => (
+
+ {category.attributes.short}
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/src/components/Popup.tsx b/src/components/Popup.tsx
index c9a30e1..7cd91b5 100644
--- a/src/components/Popup.tsx
+++ b/src/components/Popup.tsx
@@ -2,12 +2,17 @@ import { Dispatch, SetStateAction } from "react";
import Button from "./Button";
export type PopupProps = {
- setState: Dispatch>;
+ setState:
+ | Dispatch>
+ | Dispatch>;
state?: boolean;
children: React.ReactNode;
+ fillViewport?: boolean;
+ hideBackground?: boolean;
};
export default function Popup(props: PopupProps): JSX.Element {
+
return (
{
+ if (e.key.match("Escape")) props.setState(false);
+ }}
+ tabIndex={0}
>