-
{langui.global_type}
-
- {content.type.data.attributes.titles.length > 0
- ? content.type.data.attributes.titles[0].title
- : prettySlug(content.type.data.attributes.slug)}
-
+ {type?.data && (
+
+
{langui.type}
+
+
+ {type.data.attributes.titles.length > 0
+ ? type.data.attributes.titles[0].title
+ : prettySlug(type.data.attributes.slug)}
+
+
- ) : (
- ""
)}
- {content.categories.data.length > 0 ? (
-
-
{langui.global_categories}
- {content.categories.data.map((category) => (
-
{category.attributes.name}
- ))}
+ {categories && categories.data.length > 0 && (
+
+
{langui.categories}
+
+ {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..c3bec91 100644
--- a/src/components/Img.tsx
+++ b/src/components/Img.tsx
@@ -1,6 +1,5 @@
import { StrapiImage } from "graphql/operations-types";
-import { ImageProps } from "next/image";
-import Image from "next/image";
+import Image, { ImageProps } from "next/image";
export enum ImageQuality {
Small = "small",
@@ -10,11 +9,12 @@ export enum ImageQuality {
}
export function getAssetURL(url: string, quality: ImageQuality): string {
- url = url.replace(/^\/uploads/, "/" + quality);
- url = url.replace(/.jpg$/, ".webp");
- url = url.replace(/.png$/, ".webp");
- if (quality === ImageQuality.Og) url = url.replace(/.webp$/, ".jpg");
- return process.env.NEXT_PUBLIC_URL_IMG + url;
+ let newUrl = url;
+ newUrl = newUrl.replace(/^\/uploads/u, `/${quality}`);
+ newUrl = newUrl.replace(/.jpg$/u, ".webp");
+ newUrl = newUrl.replace(/.png$/u, ".webp");
+ if (quality === ImageQuality.Og) newUrl = newUrl.replace(/.webp$/u, ".jpg");
+ return process.env.NEXT_PUBLIC_URL_IMG + newUrl;
}
export function getImgSizesByMaxSize(
@@ -25,10 +25,9 @@ export function getImgSizesByMaxSize(
if (width > height) {
if (width < maxSize) return { width: width, height: height };
return { width: maxSize, height: (height / width) * maxSize };
- } else {
- if (height < maxSize) return { width: width, height: height };
- return { width: (width / height) * maxSize, height: maxSize };
}
+ if (height < maxSize) return { width: width, height: height };
+ return { width: (width / height) * maxSize, height: maxSize };
}
export function getImgSizesByQuality(
@@ -45,12 +44,14 @@ export function getImgSizesByQuality(
return getImgSizesByMaxSize(width, height, 1024);
case ImageQuality.Large:
return getImgSizesByMaxSize(width, height, 2048);
+ default:
+ return { width: 0, height: 0 };
}
}
type ImgProps = {
className?: string;
- image: StrapiImage;
+ image?: StrapiImage;
quality?: ImageQuality;
alt?: ImageProps["alt"];
layout?: ImageProps["layout"];
@@ -60,27 +61,28 @@ 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.rawImg) {
- return (
- // eslint-disable-next-line @next/next/no-img-element
-
+ if (props.image) {
+ const imgSize = getImgSizesByQuality(
+ props.image.width,
+ props.image.height,
+ props.quality ? props.quality : ImageQuality.Small
);
- } else {
+
+ if (props.rawImg) {
+ return (
+ // eslint-disable-next-line @next/next/no-img-element
+
+ );
+ }
return (
);
}
+ return <>>;
}
diff --git a/src/components/InsetBox.tsx b/src/components/InsetBox.tsx
index 83de892..c9f45ea 100644
--- a/src/components/InsetBox.tsx
+++ b/src/components/InsetBox.tsx
@@ -1,6 +1,6 @@
type InsetBoxProps = {
className?: string;
- children: React.ReactChild | React.ReactChild[];
+ children: React.ReactNode;
id?: string;
};
diff --git a/src/components/LanguageSwitcher.tsx b/src/components/LanguageSwitcher.tsx
new file mode 100644
index 0000000..af45511
--- /dev/null
+++ b/src/components/LanguageSwitcher.tsx
@@ -0,0 +1,42 @@
+import {
+ GetLanguagesQuery,
+ GetWebsiteInterfaceQuery,
+} from "graphql/operations-types";
+import { useRouter } from "next/router";
+import { prettyLanguage } from "queries/helpers";
+import Button from "./Button";
+
+type HorizontalLineProps = {
+ className?: string;
+ locales: string[];
+ languages: GetLanguagesQuery["languages"]["data"];
+ langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
+ href?: string;
+};
+
+export default function HorizontalLine(
+ props: HorizontalLineProps
+): JSX.Element {
+ const { locales, langui, href } = props;
+ const router = useRouter();
+
+ return (
+
+
+
{langui.language_switch_message}
+
+ {locales.map((locale, index) => (
+
+ {prettyLanguage(locale, props.languages)}
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/Library/ContentTOCLine.tsx b/src/components/Library/ContentTOCLine.tsx
new file mode 100644
index 0000000..06de4d4
--- /dev/null
+++ b/src/components/Library/ContentTOCLine.tsx
@@ -0,0 +1,101 @@
+import Button from "components/Button";
+import Chip from "components/Chip";
+import {
+ GetLibraryItemQuery,
+ GetWebsiteInterfaceQuery,
+} from "graphql/operations-types";
+import { prettyinlineTitle, prettySlug } from "queries/helpers";
+import { useState } from "react";
+
+type ContentTOCLineProps = {
+ content: GetLibraryItemQuery["libraryItems"]["data"][number]["attributes"]["contents"]["data"][number];
+ parentSlug: string;
+ langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
+};
+
+export default function ContentTOCLine(
+ props: ContentTOCLineProps
+): JSX.Element {
+ const { content, langui, parentSlug } = props;
+
+ const [opened, setOpened] = useState(false);
+
+ return (
+
+
+
+
+ subdirectory_arrow_right
+
+
+ {content.attributes.scan_set.length > 0 && (
+
+ {langui.view_scans}
+
+ )}
+
+ {content.attributes.content.data && (
+
+ {langui.open_content}
+
+ )}
+
+ {content.attributes.scan_set.length === 0 &&
+ !content.attributes.content.data
+ ? "The content is not available"
+ : ""}
+
+
+ );
+}
diff --git a/src/components/Library/LibraryContentPreview.tsx b/src/components/Library/LibraryContentPreview.tsx
index bcebbce..89c0c82 100644
--- a/src/components/Library/LibraryContentPreview.tsx
+++ b/src/components/Library/LibraryContentPreview.tsx
@@ -1,8 +1,8 @@
-import Link from "next/link";
-import { GetContentsQuery } from "graphql/operations-types";
-import { prettySlug } from "queries/helpers";
import Chip from "components/Chip";
import Img, { ImageQuality } from "components/Img";
+import { GetContentsQuery } from "graphql/operations-types";
+import Link from "next/link";
+import { prettySlug } from "queries/helpers";
export type LibraryContentPreviewProps = {
item: {
@@ -17,10 +17,10 @@ export type LibraryContentPreviewProps = {
export default function LibraryContentPreview(
props: LibraryContentPreviewProps
): JSX.Element {
- const item = props.item;
+ const { item } = props;
return (
-
+
{item.thumbnail.data ? (
- {item.type.data ? (
+ {item.type.data && (
{item.type.data.attributes.titles.length > 0
? item.type.data.attributes.titles[0].title
: prettySlug(item.type.data.attributes.slug)}
- ) : (
- ""
)}
diff --git a/src/components/Library/LibraryItemsPreview.tsx b/src/components/Library/LibraryItemsPreview.tsx
index d4f97ef..f667268 100644
--- a/src/components/Library/LibraryItemsPreview.tsx
+++ b/src/components/Library/LibraryItemsPreview.tsx
@@ -1,8 +1,12 @@
-import Link from "next/link";
-import { GetLibraryItemsPreviewQuery } from "graphql/operations-types";
-import { prettyDate, prettyPrice, prettyItemSubType } from "queries/helpers";
import Chip from "components/Chip";
import Img, { ImageQuality } from "components/Img";
+import { useAppLayout } from "contexts/AppLayoutContext";
+import {
+ GetCurrenciesQuery,
+ GetLibraryItemsPreviewQuery,
+} from "graphql/operations-types";
+import Link from "next/link";
+import { prettyDate, prettyItemSubType, prettyPrice } from "queries/helpers";
export type LibraryItemsPreviewProps = {
className?: string;
@@ -12,68 +16,76 @@ export type LibraryItemsPreviewProps = {
title: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["title"];
subtitle: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["subtitle"];
price?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["price"];
+ categories: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["categories"];
release_date?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["release_date"];
metadata?: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["metadata"];
};
+ currencies?: GetCurrenciesQuery["currencies"]["data"];
};
export default function LibraryItemsPreview(
props: LibraryItemsPreviewProps
): JSX.Element {
- const item = props.item;
+ const { item } = props;
+ const appLayout = useAppLayout();
return (
-
+
{item.thumbnail.data ? (
) : (
)}
- {item.metadata && item.metadata.length > 0 ? (
+ {item.metadata && item.metadata.length > 0 && (
{prettyItemSubType(item.metadata[0])}
- ) : (
- ""
)}
{item.title}
{item.subtitle}
- {item.release_date || item.price ? (
+
+
+ {item.categories.data.map((category) => (
+
+ {category.attributes.short}
+
+ ))}
+
+
+ {(item.release_date || item.price) && (
- {item.release_date ? (
+ {item.release_date && (
event
{prettyDate(item.release_date)}
- ) : (
- ""
)}
- {item.price ? (
+ {item.price && props.currencies && (
shopping_cart
- {prettyPrice(item.price)}
+ {prettyPrice(
+ item.price,
+ props.currencies,
+ appLayout.currency
+ )}
- ) : (
- ""
)}
- ) : (
- ""
)}
diff --git a/src/components/LightBox.tsx b/src/components/LightBox.tsx
new file mode 100644
index 0000000..41754bc
--- /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 8212ad4..3e7d108 100644
--- a/src/components/Markdown/Markdawn.tsx
+++ b/src/components/Markdown/Markdawn.tsx
@@ -1,30 +1,388 @@
+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 SceneBreak from "./SceneBreak";
+import { useRouter } from "next/router";
+import { slugify } from "queries/helpers";
+import React, { useState } from "react";
+import ReactDOMServer from "react-dom/server";
-type ScenBreakProps = {
+type MarkdawnProps = {
className?: string;
text: string;
};
-export default function Markdawn(props: ScenBreakProps): JSX.Element {
- if (props.text) {
+export default function Markdawn(props: MarkdawnProps): JSX.Element {
+ const appLayout = useAppLayout();
+ const text = preprocessMarkDawn(props.text);
+
+ const router = useRouter();
+
+ const [lightboxOpen, setLightboxOpen] = useState(false);
+ const [lightboxImages, setLightboxImages] = useState([""]);
+ const [lightboxIndex, setLightboxIndex] = useState(0);
+
+ if (text) {
return (
-
+
+ {
+ if (compProps.href.startsWith("/")) {
+ return (
+ router.push(compProps.href)}>
+ {compProps.children}
+
+ );
+ }
+ return {compProps.children} ;
+ },
+ },
+ h1: {
+ component: (compProps: {
+ id: string;
+ style: React.CSSProperties;
+ children: React.ReactNode;
+ }) => (
+
+ {compProps.children}
+
+
+ ),
+ },
+ h2: {
+ component: (compProps: {
+ id: string;
+ style: React.CSSProperties;
+ children: React.ReactNode;
+ }) => (
+
+ {compProps.children}
+
+
+ ),
+ },
+ h3: {
+ component: (compProps: {
+ id: string;
+ style: React.CSSProperties;
+ children: React.ReactNode;
+ }) => (
+
+ {compProps.children}
+
+
+ ),
+ },
+ h4: {
+ component: (compProps: {
+ id: string;
+ style: React.CSSProperties;
+ children: React.ReactNode;
+ }) => (
+
+ {compProps.children}
+
+
+ ),
+ },
+ h5: {
+ component: (compProps: {
+ id: string;
+ style: React.CSSProperties;
+ children: React.ReactNode;
+ }) => (
+
+ {compProps.children}
+
+
+ ),
+ },
+ h6: {
+ component: (compProps: {
+ id: string;
+ style: React.CSSProperties;
+ children: React.ReactNode;
+ }) => (
+
+ {compProps.children}
+
+
+ ),
+ },
+ Sep: {
+ component: () =>
,
+ },
+ SceneBreak: {
+ component: (compProps: { id: string }) => (
+
+ * * *
+
+ ),
+ },
+ IntraLink: {
+ component: (compProps: {
+ children: React.ReactNode;
+ target?: string;
+ page?: string;
+ }) => {
+ const slug = compProps.target
+ ? slugify(compProps.target)
+ : slugify(compProps.children?.toString());
+ return (
+
+ router.replace(
+ `${compProps.page ? compProps.page : ""}#${slug}`
+ )
+ }
+ >
+ {compProps.children}
+
+ );
+ },
+ },
+ player: {
+ component: () => (
+
+ {appLayout.playerName ? appLayout.playerName : ""}
+
+ ),
+ },
+ Transcript: {
+ component: (compProps) => (
+
+ {compProps.children}
+
+ ),
+ },
+ Line: {
+ component: (compProps) => (
+ <>
+
+ {compProps.name}
+
+ {compProps.children}
+ >
+ ),
+ },
+ InsetBox: {
+ component: (compProps) => (
+ {compProps.children}
+ ),
+ },
+ li: {
+ component: (compProps: { children: React.ReactNode }) => (
+ {compProps.children}>
+ ).length > 100
+ ? "my-4"
+ : ""
+ }
+ >
+ {compProps.children}
+
+ ),
+ },
+ Highlight: {
+ component: (compProps: { children: React.ReactNode }) => (
+ {compProps.children}
+ ),
+ },
+ footer: {
+ component: (compProps: { children: React.ReactNode }) => (
+ <>
+
+ {compProps.children}
+ >
+ ),
+ },
+ blockquote: {
+ component: (compProps: {
+ children: React.ReactNode;
+ cite?: string;
+ }) => (
+
+ {compProps.cite ? (
+ <>
+ “{compProps.children}”
+ — {compProps.cite}
+ >
+ ) : (
+ compProps.children
+ )}
+
+ ),
+ },
+ img: {
+ component: (compProps: {
+ alt: string;
+ src: string;
+ width?: number;
+ height?: number;
+ caption?: string;
+ name?: string;
+ }) => (
+ {
+ setLightboxOpen(true);
+ setLightboxImages([
+ compProps.src.startsWith("/uploads/")
+ ? getAssetURL(compProps.src, ImageQuality.Large)
+ : compProps.src,
+ ]);
+ setLightboxIndex(0);
+ }}
+ >
+ {compProps.src.startsWith("/uploads/") ? (
+
+
+
+ ) : (
+
+ {/* eslint-disable-next-line jsx-a11y/alt-text */}
+
+
+ )}
+
+ ),
+ },
},
- player: {
- component: () => {return {""} }
- },
- },
- }}
- >
- {props.text}
-
+ }}
+ >
+ {text}
+
+ >
);
}
return <>>;
-}
\ No newline at end of file
+}
+
+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 {
+ if (!text) return "";
+
+ let scenebreakIndex = 0;
+ const visitedSlugs: string[] = [];
+
+ const result = text.split("\n").map((line) => {
+ if (line === "* * *" || line === "---") {
+ scenebreakIndex += 1;
+ 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);
+ const slug = slugify(lineText);
+ let newSlug = slug;
+ let index = 2;
+ while (visitedSlugs.includes(newSlug)) {
+ newSlug = `${slug}-${index}`;
+ index += 1;
+ }
+ visitedSlugs.push(newSlug);
+ return `<${headerLevels[headerLevel]} id="${newSlug}">${lineText}${headerLevels[headerLevel]}>`;
+}
diff --git a/src/components/Markdown/SceneBreak.tsx b/src/components/Markdown/SceneBreak.tsx
deleted file mode 100644
index a636120..0000000
--- a/src/components/Markdown/SceneBreak.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-type ScenBreakProps = {
- className?: string;
-};
-
-export default function SceneBreak(props: ScenBreakProps): JSX.Element {
- return (
-
- * * *
-
- );
-}
diff --git a/src/components/Markdown/TOC.tsx b/src/components/Markdown/TOC.tsx
new file mode 100644
index 0000000..430c358
--- /dev/null
+++ b/src/components/Markdown/TOC.tsx
@@ -0,0 +1,165 @@
+import { useRouter } from "next/router";
+import { slugify } from "queries/helpers";
+import { preprocessMarkDawn } from "./Markdawn";
+
+type TOCProps = {
+ text: string;
+ title?: string;
+};
+
+export default function TOCComponent(props: TOCProps): JSX.Element {
+ const { text, title } = props;
+ const toc = getTocFromMarkdawn(preprocessMarkDawn(text), title);
+ const router = useRouter();
+
+ return (
+ <>
+ Table of content
+
+ >
+ );
+}
+
+type TOCLevelProps = {
+ tocchildren: TOC[];
+ parentNumbering: string;
+};
+
+function TOCLevel(props: TOCLevelProps): JSX.Element {
+ const router = useRouter();
+ const { tocchildren, parentNumbering } = props;
+ return (
+
+ {tocchildren.map((child, childIndex) => (
+ <>
+
+ {`${parentNumbering}${
+ childIndex + 1
+ }.`} {" "}
+ router.replace(`#${child.slug}`)}>
+ {{child.title} }
+
+
+
+ >
+ ))}
+
+ );
+}
+
+export type TOC = {
+ title: string;
+ slug: string;
+ children: TOC[];
+};
+
+export function getTocFromMarkdawn(text: string, title?: string): TOC {
+ const toc: TOC = {
+ title: title ?? "Return to top",
+ slug: slugify(title) ?? "",
+ children: [],
+ };
+ let h2 = -1;
+ let h3 = -1;
+ let h4 = -1;
+ 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("
+
+ {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/PanelComponents/NavOption.tsx b/src/components/PanelComponents/NavOption.tsx
index be793d4..c640aa9 100644
--- a/src/components/PanelComponents/NavOption.tsx
+++ b/src/components/PanelComponents/NavOption.tsx
@@ -1,14 +1,12 @@
+import ToolTip from "components/ToolTip";
import { useRouter } from "next/router";
-import Link from "next/link";
import { MouseEventHandler } from "react";
-import ReactDOMServer from "react-dom/server";
type NavOptionProps = {
url: string;
icon?: string;
title: string;
subtitle?: string;
- tooltipId?: string;
border?: boolean;
reduced?: boolean;
onClick?: MouseEventHandler;
@@ -25,21 +23,29 @@ export default function NavOption(props: NavOptionProps): JSX.Element {
} ${isActive ? divActive : ""}`;
return (
-
+
+ {props.title}
+ {props.subtitle && {props.subtitle}
}
+
+ }
+ placement="right"
+ className="text-left"
+ disabled={!props.reduced}
+ >
-
{props.title}
- {props.subtitle && (
-
{props.subtitle}
- )}
-
- )}
- data-for={props.tooltipId}
- className={`grid grid-flow-col grid-cols-[auto] auto-cols-fr justify-center ${
+ onClick={(event) => {
+ if (props.onClick) props.onClick(event);
+ if (props.url) {
+ if (props.url.startsWith("#")) {
+ router.replace(props.url);
+ } else {
+ router.push(props.url);
+ }
+ }
+ }}
+ className={`relative grid grid-flow-col grid-cols-[auto] auto-cols-fr justify-center ${
props.icon ? "text-left" : "text-center"
} ${divCommon}`}
>
@@ -54,6 +60,6 @@ export default function NavOption(props: NavOptionProps): JSX.Element {
)}
-
+
);
}
diff --git a/src/components/PanelComponents/PanelHeader.tsx b/src/components/PanelComponents/PanelHeader.tsx
index 94e32b3..925d46d 100644
--- a/src/components/PanelComponents/PanelHeader.tsx
+++ b/src/components/PanelComponents/PanelHeader.tsx
@@ -10,10 +10,8 @@ export default function PanelHeader(props: PanelHeaderProps): JSX.Element {
return (
<>
- {props.icon ? (
+ {props.icon && (
{props.icon}
- ) : (
- ""
)}
{props.title}
{props.description ?
{props.description}
: ""}
diff --git a/src/components/PanelComponents/ReturnButton.tsx b/src/components/PanelComponents/ReturnButton.tsx
index 6f2517c..e930e71 100644
--- a/src/components/PanelComponents/ReturnButton.tsx
+++ b/src/components/PanelComponents/ReturnButton.tsx
@@ -1,4 +1,5 @@
import Button from "components/Button";
+import HorizontalLine from "components/HorizontalLine";
import { useAppLayout } from "contexts/AppLayoutContext";
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
@@ -6,14 +7,39 @@ type ReturnButtonProps = {
href: string;
title: string;
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
+ displayOn: ReturnButtonType;
+ horizontalLine?: boolean;
+ className?: string;
};
+export enum ReturnButtonType {
+ mobile = "mobile",
+ desktop = "desktop",
+ both = "both",
+}
+
export default function ReturnButton(props: ReturnButtonProps): JSX.Element {
const appLayout = useAppLayout();
return (
-
appLayout.setSubPanelOpen(false)} href={props.href}>
- ❮ {props.langui.global_return_label} {props.title}
-
+
+ appLayout.setSubPanelOpen(false)}
+ href={props.href}
+ className="grid grid-flow-col gap-2"
+ >
+ navigate_before
+ {props.langui.return_to} {props.title}
+
+ {props.horizontalLine && }
+
);
}
diff --git a/src/components/Panels/ContentPanel.tsx b/src/components/Panels/ContentPanel.tsx
index 5b0dfa5..ad86d8a 100644
--- a/src/components/Panels/ContentPanel.tsx
+++ b/src/components/Panels/ContentPanel.tsx
@@ -5,19 +5,22 @@ type ContentPanelProps = {
};
export enum ContentPanelWidthSizes {
- default,
- large,
+ default = "default",
+ large = "large",
}
export default function ContentPanel(props: ContentPanelProps): JSX.Element {
const width = props.width ? props.width : ContentPanelWidthSizes.default;
const widthCSS =
- width === ContentPanelWidthSizes.default ? "max-w-[45rem]" : "w-full";
- const prose = props.autoformat ? "prose text-justify" : "";
+ width === ContentPanelWidthSizes.default ? "max-w-2xl" : "w-full";
return (
-
+
{props.children}
diff --git a/src/components/Panels/MainPanel.tsx b/src/components/Panels/MainPanel.tsx
index 1ac3b2f..f95ee31 100644
--- a/src/components/Panels/MainPanel.tsx
+++ b/src/components/Panels/MainPanel.tsx
@@ -1,20 +1,20 @@
-import Link from "next/link";
-import NavOption from "components/PanelComponents/NavOption";
-import SVG from "components/SVG";
-import { useRouter } from "next/router";
import Button from "components/Button";
import HorizontalLine from "components/HorizontalLine";
-import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
-import Markdown from "markdown-to-jsx";
-import { useMediaDesktop } from "hooks/useMediaQuery";
+import NavOption from "components/PanelComponents/NavOption";
+import ToolTip from "components/ToolTip";
import { useAppLayout } from "contexts/AppLayoutContext";
+import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
+import { useMediaDesktop } from "hooks/useMediaQuery";
+import Markdown from "markdown-to-jsx";
+import Link from "next/link";
+import { useRouter } from "next/router";
type MainPanelProps = {
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
};
export default function MainPanel(props: MainPanelProps): JSX.Element {
- const langui = props.langui;
+ const { langui } = props;
const router = useRouter();
const isDesktop = useMediaDesktop();
const appLayout = useAppLayout();
@@ -25,6 +25,20 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
appLayout.mainPanelReduced && isDesktop && "px-4"
}`}
>
+ {/* Reduce/expand main menu */}
+
+ appLayout.setMainPanelReduced(!appLayout.mainPanelReduced)
+ }
+ >
+
+ {appLayout.mainPanelReduced ? "chevron_right" : "chevron_left"}
+
+
+
@@ -49,32 +63,74 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
: "flex-row"
} flex-wrap gap-2`}
>
- {
- appLayout.setDarkMode(!appLayout.darkMode);
- appLayout.setSelectedThemeMode(true);
- }}
- className={
- appLayout.mainPanelReduced && isDesktop ? "" : "!py-0.5 !px-2.5"
- }
+ {langui.open_settings}}
+ placement="right"
+ className="text-left"
+ disabled={!appLayout.mainPanelReduced}
>
-
- {appLayout.darkMode ? "dark_mode" : "light_mode"}
-
-
-
- {router.locale && (
appLayout.setLanguagePanelOpen(true)}
className={
appLayout.mainPanelReduced && isDesktop
? ""
- : "!py-0.5 !px-2.5 !text-sm"
+ : "!py-0.5 !px-2.5"
+ }
+ onClick={() => {
+ appLayout.setConfigPanelOpen(true);
+ }}
+ >
+
+ settings
+
+
+
+
+ {router.locale && (
+ {langui.change_language}}
+ placement="right"
+ className="text-left"
+ disabled={!appLayout.mainPanelReduced}
+ >
+ appLayout.setLanguagePanelOpen(true)}
+ className={
+ appLayout.mainPanelReduced && isDesktop
+ ? ""
+ : "!py-0.5 !px-2.5 !text-sm"
+ }
+ >
+ {router.locale.toUpperCase()}
+
+
+ )}
+
+ {/* {langui.open_search}}
+ placement="right"
+ className="text-left"
+ disabled={!appLayout.mainPanelReduced}
+ >
+
- {router.locale.toUpperCase()}
+
+ search
+
- )}
+ */}
@@ -84,9 +140,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {