Added a config menu with multiple options for the visitors + globally loaded props #7

Merged
DrMint merged 7 commits from develop into main 2022-03-07 15:06:54 +00:00
37 changed files with 1005 additions and 682 deletions

11
package-lock.json generated
View File

@ -8,6 +8,7 @@
"dependencies": {
"@fontsource/material-icons": "^4.5.2",
"@fontsource/material-icons-rounded": "^4.5.2",
"@fontsource/opendyslexic": "^4.5.2",
"@fontsource/vollkorn": "^4.5.4",
"@fontsource/zen-maru-gothic": "^4.5.5",
"markdown-to-jsx": "^7.1.6",
@ -199,6 +200,11 @@
"resolved": "https://registry.npmjs.org/@fontsource/material-icons-rounded/-/material-icons-rounded-4.5.2.tgz",
"integrity": "sha512-wk/vqodMF+4IBbxhI0cjaPBcouvRrnJdeQCslY0Zae8ojyZCUksJn4JTiQk89fbY9kvT3oG7AZIZ+poKdpS02w=="
},
"node_modules/@fontsource/opendyslexic": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/@fontsource/opendyslexic/-/opendyslexic-4.5.2.tgz",
"integrity": "sha512-vW+A3Bd1ZEG6nAZuix0OhbS0ygMlhvtc3RvLlDXrTAinrAZHQ0bOGUJRN2iaGbQ1kWNP8/7A+AKMFH5FM/pjKA=="
},
"node_modules/@fontsource/vollkorn": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/@fontsource/vollkorn/-/vollkorn-4.5.4.tgz",
@ -3800,6 +3806,11 @@
"resolved": "https://registry.npmjs.org/@fontsource/material-icons-rounded/-/material-icons-rounded-4.5.2.tgz",
"integrity": "sha512-wk/vqodMF+4IBbxhI0cjaPBcouvRrnJdeQCslY0Zae8ojyZCUksJn4JTiQk89fbY9kvT3oG7AZIZ+poKdpS02w=="
},
"@fontsource/opendyslexic": {
"version": "4.5.2",
"resolved": "https://registry.npmjs.org/@fontsource/opendyslexic/-/opendyslexic-4.5.2.tgz",
"integrity": "sha512-vW+A3Bd1ZEG6nAZuix0OhbS0ygMlhvtc3RvLlDXrTAinrAZHQ0bOGUJRN2iaGbQ1kWNP8/7A+AKMFH5FM/pjKA=="
},
"@fontsource/vollkorn": {
"version": "4.5.4",
"resolved": "https://registry.npmjs.org/@fontsource/vollkorn/-/vollkorn-4.5.4.tgz",

View File

@ -10,6 +10,7 @@
"dependencies": {
"@fontsource/material-icons": "^4.5.2",
"@fontsource/material-icons-rounded": "^4.5.2",
"@fontsource/opendyslexic": "^4.5.2",
"@fontsource/vollkorn": "^4.5.4",
"@fontsource/zen-maru-gothic": "^4.5.5",
"markdown-to-jsx": "^7.1.6",

View File

@ -13,20 +13,23 @@ import ReactTooltip from "react-tooltip";
import { useAppLayout } from "contexts/AppLayoutContext";
import { ImageQuality } from "./Img";
import Popup from "./Popup";
import { useEffect, useState } from "react";
import Select from "./Select";
import { AppStaticProps } from "queries/getAppStaticProps";
type AppLayoutProps = {
interface AppLayoutProps extends AppStaticProps {
subPanel?: React.ReactNode;
subPanelIcon?: string;
contentPanel?: React.ReactNode;
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
title?: string;
navTitle: string;
thumbnail?: StrapiImage;
description?: string;
extra?: React.ReactNode;
};
}
export default function AppLayout(props: AppLayoutProps): JSX.Element {
const { langui, currencies, languages, subPanel, contentPanel } = props;
const router = useRouter();
const isMobile = useMediaMobile();
const isCoarse = useMediaCoarse();
@ -39,7 +42,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
if (SwipeEventData.velocity < sensibilitySwipe) return;
if (appLayout.mainPanelOpen) {
appLayout.setMainPanelOpen(false);
} else if (props.subPanel && props.contentPanel) {
} else if (subPanel && contentPanel) {
appLayout.setSubPanelOpen(true);
}
},
@ -60,13 +63,13 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
appLayout.mainPanelReduced ? " desktop:left-[6rem]" : "desktop:left-[20rem]"
}`;
let contentPanelClass = "";
if (props.subPanel) {
if (subPanel) {
contentPanelClass = `fixed desktop:top-0 desktop:bottom-0 desktop:right-0 ${
appLayout.mainPanelReduced
? "desktop:left-[26rem]"
: "desktop:left-[40rem]"
}`;
} else if (props.contentPanel) {
} else if (contentPanel) {
contentPanelClass = `fixed desktop:top-0 desktop:bottom-0 desktop:right-0 ${
appLayout.mainPanelReduced
? "desktop:left-[6rem]"
@ -74,7 +77,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
}`;
}
const turnSubIntoContent = props.subPanel && !props.contentPanel;
const turnSubIntoContent = subPanel && !contentPanel;
const titlePrefix = "Accords Library";
const metaImage: OgImage = props.thumbnail
@ -89,10 +92,41 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
const metaDescription = props.description
? props.description
: props.langui.default_description;
: langui.default_description;
useEffect(() => {
document.getElementsByTagName("html")[0].style.fontSize = `${
(appLayout.fontSize || 1) * 100
}%`;
}, [appLayout.fontSize]);
const currencyOptions = currencies.map((currency) => {
return currency.attributes.code;
});
const [currencySelect, setCurrencySelect] = useState<number>(-1);
useEffect(() => {
appLayout.currency &&
setCurrencySelect(currencyOptions.indexOf(appLayout.currency));
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [appLayout.currency]);
useEffect(() => {
currencySelect >= 0 &&
appLayout.setCurrency(currencyOptions[currencySelect]);
// eslint-disable-next-line react-hooks/exhaustive-deps
}, [currencySelect]);
return (
<div className={appLayout.darkMode ? "set-theme-dark" : "set-theme-light"}>
<div
className={`${
appLayout.darkMode ? "set-theme-dark" : "set-theme-light"
} ${
appLayout.dyslexic
? "set-theme-font-dyslexic"
: "set-theme-font-standard"
}`}
>
<div
{...handlers}
className="fixed inset-0 touch-pan-y p-0 m-0 bg-light text-black"
@ -129,15 +163,13 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
<div
className={`top-0 left-0 right-0 bottom-20 overflow-y-scroll bg-light texture-paper-dots ${contentPanelClass}`}
>
{props.contentPanel ? (
props.contentPanel
{contentPanel ? (
contentPanel
) : (
<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 opacity-40">
<p className="text-4xl"></p>
<p className="text-2xl w-64">
{props.langui.select_option_sidebar}
</p>
<p className="text-2xl w-64">{langui.select_option_sidebar}</p>
</div>
</div>
)}
@ -145,21 +177,29 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
{/* Background when navbar is opened */}
<div
className={`fixed bg-shade inset-0 transition-opacity duration-500
className={`fixed inset-0 transition-[backdrop-filter] duration-500 ${
(appLayout.mainPanelOpen || appLayout.subPanelOpen) && isMobile
? "[backdrop-filter:blur(2px)]"
: "pointer-events-none touch-none "
}`}
>
<div
className={`fixed bg-shade inset-0 transition-opacity duration-500
${turnSubIntoContent ? "z-10" : ""}
${
(appLayout.mainPanelOpen || appLayout.subPanelOpen) && isMobile
? "opacity-60"
: "opacity-0 pointer-events-none touch-none"
: "opacity-0"
}`}
onClick={() => {
appLayout.setMainPanelOpen(false);
appLayout.setSubPanelOpen(false);
}}
></div>
onClick={() => {
appLayout.setMainPanelOpen(false);
appLayout.setSubPanelOpen(false);
}}
></div>
</div>
{/* Sub panel */}
{props.subPanel ? (
{subPanel ? (
<div
className={`${subPanelClass} border-r-[1px] mobile:bottom-20 mobile:border-r-0 mobile:border-l-[1px] border-black border-dotted top-0 bottom-0 right-0 left-12 overflow-y-scroll webkit-scrollbar:w-0 [scrollbar-width:none] transition-transform duration-300 bg-light texture-paper-dots
${
@ -170,7 +210,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
: ""
}`}
>
{props.subPanel}
{subPanel}
</div>
) : (
""
@ -181,7 +221,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
className={`${mainPanelClass} border-r-[1px] mobile:bottom-20 border-black border-dotted top-0 bottom-0 left-0 right-12 overflow-y-scroll webkit-scrollbar:w-0 [scrollbar-width:none] transition-transform duration-300 z-20 bg-light texture-paper-dots
${appLayout.mainPanelOpen ? "" : "mobile:-translate-x-full"}`}
>
<MainPanel langui={props.langui} />
<MainPanel langui={langui} />
</div>
{/* Main panel minimize button*/}
@ -217,7 +257,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
appLayout.setMainPanelOpen(false);
}}
>
{props.subPanel && !turnSubIntoContent
{subPanel && !turnSubIntoContent
? appLayout.subPanelOpen
? "close"
: props.subPanelIcon
@ -231,22 +271,151 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
state={appLayout.languagePanelOpen}
setState={appLayout.setLanguagePanelOpen}
>
<h2 className="text-2xl">{props.langui.select_language}</h2>
<div className="flex flex-wrap flex-row gap-2">
{router.locales?.sort().map((locale) => (
<h2 className="text-2xl">{langui.select_language}</h2>
<div className="flex flex-wrap flex-row gap-2 mobile:flex-col">
{languages.map((language) => (
<Button
key={locale}
active={locale === router.locale}
key={language.id}
active={language.attributes.code === router.locale}
href={router.asPath}
locale={locale}
locale={language.attributes.code}
onClick={() => appLayout.setLanguagePanelOpen(false)}
>
{prettyLanguage(locale)}
{language.attributes.localized_name}
</Button>
))}
</div>
</Popup>
<Popup
state={appLayout.configPanelOpen}
setState={appLayout.setConfigPanelOpen}
>
<h2 className="text-2xl">{langui.settings}</h2>
<div className="mt-4 grid gap-8 place-items-center text-center desktop:grid-cols-2">
<div>
<h3 className="text-xl">{langui.theme}</h3>
<div className="flex flex-row">
<Button
onClick={() => {
appLayout.setDarkMode(false);
appLayout.setSelectedThemeMode(true);
}}
active={
appLayout.selectedThemeMode === true &&
appLayout.darkMode === false
}
className="rounded-r-none"
>
{langui.light}
</Button>
<Button
onClick={() => {
appLayout.setSelectedThemeMode(false);
}}
active={appLayout.selectedThemeMode === false}
className="rounded-l-none rounded-r-none border-x-0"
>
{langui.auto}
</Button>
<Button
onClick={() => {
appLayout.setDarkMode(true);
appLayout.setSelectedThemeMode(true);
}}
active={
appLayout.selectedThemeMode === true &&
appLayout.darkMode === true
}
className="rounded-l-none"
>
{langui.dark}
</Button>
</div>
</div>
<div>
<h3 className="text-xl">{langui.currency}</h3>
<div>
<Select
options={currencyOptions}
state={currencySelect}
setState={setCurrencySelect}
className="w-28"
/>
</div>
</div>
<div>
<h3 className="text-xl">{langui.font_size}</h3>
<div className="flex flex-row">
<Button
className="rounded-r-none"
onClick={() =>
appLayout.setFontSize(
appLayout.fontSize ? appLayout.fontSize / 1.05 : 1 / 1.05
)
}
>
<span className="material-icons">text_decrease</span>
</Button>
<Button
className="rounded-l-none rounded-r-none border-x-0"
onClick={() => appLayout.setFontSize(1)}
>
{((appLayout.fontSize || 1) * 100).toLocaleString(undefined, {
maximumFractionDigits: 0,
})}
%
</Button>
<Button
className="rounded-l-none"
onClick={() =>
appLayout.setFontSize(
appLayout.fontSize ? appLayout.fontSize * 1.05 : 1 * 1.05
)
}
>
<span className="material-icons">text_increase</span>
</Button>
</div>
</div>
<div>
<h3 className="text-xl">{langui.font}</h3>
<div className="grid gap-2">
<Button
active={appLayout.dyslexic === false}
onClick={() => appLayout.setDyslexic(false)}
className="font-zenMaruGothic"
>
Zen Maru Gothic
</Button>
<Button
active={appLayout.dyslexic === true}
onClick={() => appLayout.setDyslexic(true)}
className="font-openDyslexic"
>
OpenDyslexic
</Button>
</div>
</div>
<div>
<h3 className="text-xl">{langui.player_name}</h3>
<input
type="text"
placeholder="<player>"
className="w-48"
onInput={(e) =>
appLayout.setPlayerName((e.target as HTMLInputElement).value)
}
/>
</div>
</div>
</Popup>
<ReactTooltip
id="MainPanelTooltip"
place="right"

View File

@ -1,8 +1,12 @@
import Link from "next/link";
import { GetLibraryItemsPreviewQuery } from "graphql/operations-types";
import {
GetCurrenciesQuery,
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";
export type LibraryItemsPreviewProps = {
className?: string;
@ -15,12 +19,14 @@ export type LibraryItemsPreviewProps = {
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 appLayout = useAppLayout();
return (
<Link href={"/library/" + item.slug} passHref>
@ -61,12 +67,16 @@ export default function LibraryItemsPreview(
) : (
""
)}
{item.price ? (
{item.price && props.currencies ? (
<p className="mobile:text-xs text-sm justify-self-end">
<span className="material-icons !text-base translate-y-[.15em] mr-1">
shopping_cart
</span>
{prettyPrice(item.price)}
{prettyPrice(
item.price,
props.currencies,
appLayout.currency
)}
</p>
) : (
""

View File

@ -1,3 +1,4 @@
import { useAppLayout } from "contexts/AppLayoutContext";
import Markdown from "markdown-to-jsx";
import SceneBreak from "./SceneBreak";
@ -7,6 +8,8 @@ type ScenBreakProps = {
};
export default function Markdawn(props: ScenBreakProps): JSX.Element {
const appLayout = useAppLayout();
if (props.text) {
return (
<Markdown
@ -17,7 +20,13 @@ export default function Markdawn(props: ScenBreakProps): JSX.Element {
component: SceneBreak,
},
player: {
component: () => {return <span className="text-dark opacity-70">{"<player>"}</span>}
component: () => {
return (
<span className="text-dark opacity-70">
{appLayout.playerName ? appLayout.playerName : "<player>"}
</span>
);
},
},
},
}}
@ -27,4 +36,4 @@ export default function Markdawn(props: ScenBreakProps): JSX.Element {
);
}
return <></>;
}
}

View File

@ -49,16 +49,19 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
} flex-wrap gap-2`}
>
<Button
onClick={() => {
appLayout.setDarkMode(!appLayout.darkMode);
appLayout.setSelectedThemeMode(true);
}}
className={
appLayout.mainPanelReduced && isDesktop ? "" : "!py-0.5 !px-2.5"
}
onClick={() => {
appLayout.setConfigPanelOpen(true);
}}
>
<span className="material-icons !text-sm">
{appLayout.darkMode ? "dark_mode" : "light_mode"}
<span
className={`material-icons ${
!(appLayout.mainPanelReduced && isDesktop) && "!text-sm"
} `}
>
settings
</span>
</Button>
@ -74,6 +77,20 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
{router.locale.toUpperCase()}
</Button>
)}
<Button
className={
appLayout.mainPanelReduced && isDesktop ? "" : "!py-0.5 !px-2.5"
}
>
<span
className={`material-icons ${
!(appLayout.mainPanelReduced && isDesktop) && "!text-sm"
} `}
>
search
</span>
</Button>
</div>
</div>
</div>

View File

@ -1,4 +1,5 @@
import { Dispatch, SetStateAction } from "react";
import Button from "./Button";
export type PopupProps = {
setState: Dispatch<SetStateAction<boolean | undefined>>;
@ -9,23 +10,29 @@ export type PopupProps = {
export default function Popup(props: PopupProps): JSX.Element {
return (
<div
className={`fixed inset-0 z-20 grid place-content-center ${
props.state ? "" : "pointer-events-none touch-none"
className={`fixed inset-0 z-50 grid place-content-center transition-[backdrop-filter] duration-500 ${
props.state ? "[backdrop-filter:blur(2px)]" : "pointer-events-none touch-none"
}`}
>
<div
className={`fixed bg-shade inset-0 transition-all duration-500 ${
props.state ? "bg-opacity-60" : "bg-opacity-0"
props.state ? "bg-opacity-50" : "bg-opacity-0"
}`}
onClick={() => {
props.setState(false);
}}
/>
<div
className={`p-10 bg-light rounded-lg shadow-2xl shadow-shade grid gap-4 place-items-center transition-transform ${
className={`relative p-10 bg-light rounded-lg shadow-2xl shadow-shade grid gap-4 place-items-center transition-transform ${
props.state ? "scale-100" : "scale-0"
}`}
>
<Button
className="!p-1 absolute -top-16 bg-light border-light border-4"
onClick={() => props.setState(false)}
>
<span className="material-icons p-1">close</span>
</Button>
{props.children}
</div>
</div>

View File

@ -1,15 +1,20 @@
import Chip from "components/Chip";
import { GetContentTextQuery } from "graphql/operations-types";
import {
GetContentTextQuery,
GetWebsiteInterfaceQuery,
} from "graphql/operations-types";
import Img, { ImageQuality } from "./Img";
import ReactDOMServer from "react-dom/server";
type RecorderChipProps = {
className?: string;
recorder: GetContentTextQuery["contents"]["data"][number]["attributes"]["text_set"][number]["transcribers"]["data"][number];
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
};
export default function RecorderChip(props: RecorderChipProps): JSX.Element {
const recorder = props.recorder;
const langui = props.langui;
return (
<Chip
key={recorder.id}
@ -28,7 +33,7 @@ export default function RecorderChip(props: RecorderChipProps): JSX.Element {
</div>
{recorder.attributes.languages.data.length > 0 && (
<div className="flex flex-row flex-wrap gap-1">
<p>Languages:</p>
<p>{langui.languages}:</p>
{recorder.attributes.languages.data.map((language) => (
<Chip key={language.attributes.code}>
{language.attributes.code.toUpperCase()}
@ -38,7 +43,7 @@ export default function RecorderChip(props: RecorderChipProps): JSX.Element {
)}
{recorder.attributes.pronouns && (
<div className="flex flex-row flex-wrap gap-1">
<p>Pronouns:</p>
<p>{langui.pronouns}:</p>
<Chip>{recorder.attributes.pronouns}</Chip>
</div>
)}

View File

@ -15,7 +15,7 @@ export default function Select(props: SelectProps): JSX.Element {
return (
<div
className={`relative transition-[filter] ${
className={`relative text-center transition-[filter] ${
opened && "drop-shadow-shade-lg z-10"
} ${props.className}`}
>
@ -49,7 +49,7 @@ export default function Select(props: SelectProps): JSX.Element {
{index !== props.state && (
<div
className="bg-light hover:bg-mid transition-colors cursor-pointer p-1 last-of-type:rounded-b-[1em]"
key={option}
key={index}
id={option}
onClick={() => {
setOpened(false);

View File

@ -5,13 +5,20 @@ import React, { ReactNode, useContext } from "react";
export interface AppLayoutState {
subPanelOpen: boolean | undefined;
languagePanelOpen: boolean | undefined;
configPanelOpen: boolean | undefined;
mainPanelReduced: boolean | undefined;
mainPanelOpen: boolean | undefined;
darkMode: boolean | undefined;
selectedThemeMode: boolean | undefined;
fontSize: number | undefined;
dyslexic: boolean | undefined;
currency: string | undefined;
playerName: string | undefined;
setSubPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>;
setLanguagePanelOpen: React.Dispatch<
React.SetStateAction<boolean | undefined>
>;
setConfigPanelOpen: React.Dispatch<React.SetStateAction<boolean | undefined>>;
setMainPanelReduced: React.Dispatch<
React.SetStateAction<boolean | undefined>
>;
@ -20,20 +27,35 @@ export interface AppLayoutState {
setSelectedThemeMode: React.Dispatch<
React.SetStateAction<boolean | undefined>
>;
setFontSize: React.Dispatch<React.SetStateAction<number | undefined>>;
setDyslexic: React.Dispatch<React.SetStateAction<boolean | undefined>>;
setCurrency: React.Dispatch<React.SetStateAction<string | undefined>>;
setPlayerName: React.Dispatch<React.SetStateAction<string | undefined>>;
}
const initialState: AppLayoutState = {
subPanelOpen: false,
languagePanelOpen: false,
configPanelOpen: false,
mainPanelReduced: false,
mainPanelOpen: false,
darkMode: false,
selectedThemeMode: false,
fontSize: 1,
dyslexic: false,
currency: "USD",
playerName: "",
setSubPanelOpen: () => {},
setLanguagePanelOpen: () => {},
setMainPanelReduced: () => {},
setMainPanelOpen: () => {},
setDarkMode: () => {},
setSelectedThemeMode: () => {},
setConfigPanelOpen: () => {},
setFontSize: () => {},
setDyslexic: () => {},
setCurrency: () => {},
setPlayerName: () => {},
};
const AppContext = React.createContext<AppLayoutState>(initialState);
@ -57,6 +79,10 @@ export const AppContextProvider = (props: Props) => {
boolean | undefined
>("languagePanelOpen", initialState.languagePanelOpen);
const [configPanelOpen, setConfigPanelOpen] = useStateWithLocalStorage<
boolean | undefined
>("configPanelOpen", initialState.configPanelOpen);
const [mainPanelReduced, setMainPanelReduced] = useStateWithLocalStorage<
boolean | undefined
>("mainPanelReduced", initialState.mainPanelReduced);
@ -65,25 +91,53 @@ export const AppContextProvider = (props: Props) => {
boolean | undefined
>("mainPanelOpen", initialState.mainPanelOpen);
const [darkMode, setDarkMode, setSelectedThemeMode] = useDarkMode(
"darkMode",
initialState.darkMode
const [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode] =
useDarkMode("darkMode", initialState.darkMode);
const [fontSize, setFontSize] = useStateWithLocalStorage<number | undefined>(
"fontSize",
initialState.fontSize
);
const [dyslexic, setDyslexic] = useStateWithLocalStorage<boolean | undefined>(
"dyslexic",
initialState.dyslexic
);
const [currency, setCurrency] = useStateWithLocalStorage<string | undefined>(
"currency",
initialState.currency
);
const [playerName, setPlayerName] = useStateWithLocalStorage<
string | undefined
>("playerName", initialState.playerName);
return (
<AppContext.Provider
value={{
subPanelOpen,
languagePanelOpen,
configPanelOpen,
mainPanelReduced,
mainPanelOpen,
darkMode,
selectedThemeMode,
fontSize,
dyslexic,
currency,
playerName,
setSubPanelOpen,
setLanguagePanelOpen,
setConfigPanelOpen,
setMainPanelReduced,
setMainPanelOpen,
setDarkMode,
setSelectedThemeMode,
setFontSize,
setDyslexic,
setCurrency,
setPlayerName,
}}
>
{props.children}

View File

@ -83,6 +83,32 @@ query getWebsiteInterface($language_code: String) {
group_by
select_option_sidebar
group
settings
theme
light
auto
dark
font_size
player_name
currency
font
calculated
status_incomplete
status_draft
status_review
status_done
incomplete
draft
review
done
status
transcribers
translators
proofreaders
transcript_notice
translation_notice
source_language
pronouns
}
}
}
@ -174,6 +200,7 @@ query getLibraryItemsPreview($language_code: String) {
attributes {
symbol
code
rate_to_usd
}
}
}
@ -322,6 +349,7 @@ query getLibraryItem($slug: String, $language_code: String) {
attributes {
symbol
code
rate_to_usd
}
}
}
@ -490,6 +518,7 @@ query getLibraryItem($slug: String, $language_code: String) {
attributes {
symbol
code
rate_to_usd
}
}
}
@ -1057,3 +1086,30 @@ query getContentText($slug: String, $language_code: String) {
}
}
}
query getCurrencies {
currencies {
data {
id
attributes {
code
symbol
rate_to_usd
display_decimals
}
}
}
}
query getLanguages {
languages {
data {
id
attributes {
name
code
localized_name
}
}
}
}

View File

@ -165,6 +165,32 @@ export type GetWebsiteInterfaceQuery = {
group_by: string;
select_option_sidebar: string;
group: string;
settings: string;
theme: string;
light: string;
auto: string;
dark: string;
font_size: string;
player_name: string;
currency: string;
font: string;
calculated: string;
status_incomplete: string;
status_draft: string;
status_review: string;
status_done: string;
incomplete: string;
draft: string;
review: string;
done: string;
status: string;
transcribers: string;
translators: string;
proofreaders: string;
transcript_notice: string;
translation_notice: string;
source_language: string;
pronouns: string;
};
}>;
};
@ -286,6 +312,7 @@ export type GetLibraryItemsPreviewQuery = {
__typename: "Currency";
symbol: string;
code: string;
rate_to_usd: number;
};
};
};
@ -478,6 +505,7 @@ export type GetLibraryItemQuery = {
__typename: "Currency";
symbol: string;
code: string;
rate_to_usd: number;
};
};
};
@ -693,6 +721,7 @@ export type GetLibraryItemQuery = {
__typename: "Currency";
symbol: string;
code: string;
rate_to_usd: number;
};
};
};
@ -1416,3 +1445,42 @@ export type GetContentTextQuery = {
}>;
};
};
export type GetCurrenciesQueryVariables = Exact<{ [key: string]: never }>;
export type GetCurrenciesQuery = {
__typename: "Query";
currencies: {
__typename: "CurrencyEntityResponseCollection";
data: Array<{
__typename: "CurrencyEntity";
id: string;
attributes: {
__typename: "Currency";
code: string;
symbol: string;
rate_to_usd: number;
display_decimals: boolean;
};
}>;
};
};
export type GetLanguagesQueryVariables = Exact<{ [key: string]: never }>;
export type GetLanguagesQuery = {
__typename: "Query";
languages: {
__typename: "LanguageEntityResponseCollection";
data: Array<{
__typename: "LanguageEntity";
id: string;
attributes: {
__typename: "Language";
name: string;
code: string;
localized_name: string;
};
}>;
};
};

View File

@ -11,8 +11,12 @@ import {
GetContentsSlugsQueryVariables,
GetContentTextQuery,
GetContentTextQueryVariables,
GetCurrenciesQuery,
GetCurrenciesQueryVariables,
GetErasQuery,
GetErasQueryVariables,
GetLanguagesQuery,
GetLanguagesQueryVariables,
GetLibraryItemQuery,
GetLibraryItemQueryVariables,
GetLibraryItemsPreviewQuery,
@ -123,3 +127,17 @@ export async function getContentText(
const query = getQueryFromOperations("getContentText");
return await graphQL(query, JSON.stringify(variables));
}
export async function getCurrencies(
variables: GetCurrenciesQueryVariables
): Promise<GetCurrenciesQuery> {
const query = getQueryFromOperations("getCurrencies");
return await graphQL(query, JSON.stringify(variables));
}
export async function getLanguages(
variables: GetLanguagesQueryVariables
): Promise<GetLanguagesQuery> {
const query = getQueryFromOperations("getLanguages");
return await graphQL(query, JSON.stringify(variables));
}

View File

@ -1647,6 +1647,7 @@ input CurrencyFiltersInput {
id: IDFilterInput
symbol: StringFilterInput
code: StringFilterInput
rate_to_usd: FloatFilterInput
createdAt: DateTimeFilterInput
updatedAt: DateTimeFilterInput
and: [CurrencyFiltersInput]
@ -1657,11 +1658,13 @@ input CurrencyFiltersInput {
input CurrencyInput {
symbol: String
code: String
rate_to_usd: Float
}
type Currency {
symbol: String!
code: String!
rate_to_usd: Float
createdAt: DateTime
updatedAt: DateTime
}
@ -2099,46 +2102,6 @@ type MetadataTypeEntityResponseCollection {
meta: ResponseCollectionMeta!
}
input OtherSubtypeFiltersInput {
id: IDFilterInput
slug: StringFilterInput
createdAt: DateTimeFilterInput
updatedAt: DateTimeFilterInput
and: [OtherSubtypeFiltersInput]
or: [OtherSubtypeFiltersInput]
not: OtherSubtypeFiltersInput
}
input OtherSubtypeInput {
slug: String
titles: [ComponentTranslationsSimpleTitleInput]
}
type OtherSubtype {
slug: String!
titles(
filters: ComponentTranslationsSimpleTitleFiltersInput
pagination: PaginationArg = {}
sort: [String] = []
): [ComponentTranslationsSimpleTitle]
createdAt: DateTime
updatedAt: DateTime
}
type OtherSubtypeEntity {
id: ID
attributes: OtherSubtype
}
type OtherSubtypeEntityResponse {
data: OtherSubtypeEntity
}
type OtherSubtypeEntityResponseCollection {
data: [OtherSubtypeEntity!]!
meta: ResponseCollectionMeta!
}
input PostFiltersInput {
id: IDFilterInput
authors: RecorderFiltersInput
@ -2655,6 +2618,7 @@ input WebsiteInterfaceFiltersInput {
order_by: StringFilterInput
group_by: StringFilterInput
select_option_sidebar: StringFilterInput
group: StringFilterInput
createdAt: DateTimeFilterInput
updatedAt: DateTimeFilterInput
and: [WebsiteInterfaceFiltersInput]
@ -2742,6 +2706,7 @@ input WebsiteInterfaceInput {
order_by: String
group_by: String
select_option_sidebar: String
group: String
}
type WebsiteInterface {
@ -2824,6 +2789,7 @@ type WebsiteInterface {
order_by: String
group_by: String
select_option_sidebar: String
group: String
createdAt: DateTime
updatedAt: DateTime
}
@ -2997,7 +2963,6 @@ union GenericMorph =
| LibraryItem
| MerchItem
| MetadataType
| OtherSubtype
| Post
| RangedContent
| Recorder
@ -3121,12 +3086,6 @@ type Query {
pagination: PaginationArg = {}
sort: [String] = []
): MetadataTypeEntityResponseCollection
otherSubtype(id: ID): OtherSubtypeEntityResponse
otherSubtypes(
filters: OtherSubtypeFiltersInput
pagination: PaginationArg = {}
sort: [String] = []
): OtherSubtypeEntityResponseCollection
post(id: ID): PostEntityResponse
posts(
filters: PostFiltersInput
@ -3277,12 +3236,6 @@ type Mutation {
data: MetadataTypeInput!
): MetadataTypeEntityResponse
deleteMetadataType(id: ID!): MetadataTypeEntityResponse
createOtherSubtype(data: OtherSubtypeInput!): OtherSubtypeEntityResponse
updateOtherSubtype(
id: ID!
data: OtherSubtypeInput!
): OtherSubtypeEntityResponse
deleteOtherSubtype(id: ID!): OtherSubtypeEntityResponse
createPost(data: PostInput!): PostEntityResponse
updatePost(id: ID!, data: PostInput!): PostEntityResponse
deletePost(id: ID!): PostEntityResponse

View File

@ -6,6 +6,7 @@ export default function useDarkMode(
key: string,
initialValue: boolean | undefined
): [
boolean | undefined,
boolean | undefined,
React.Dispatch<React.SetStateAction<boolean | undefined>>,
React.Dispatch<React.SetStateAction<boolean | undefined>>
@ -23,5 +24,5 @@ export default function useDarkMode(
if (selectedThemeMode === false) setDarkMode(prefersDarkMode);
}, [selectedThemeMode, prefersDarkMode, setDarkMode]);
return [darkMode, setDarkMode, setSelectedThemeMode];
return [darkMode, selectedThemeMode, setDarkMode, setSelectedThemeMode];
}

View File

@ -1,19 +1,15 @@
import Link from "next/link";
import ContentPanel from "components/Panels/ContentPanel";
import { getWebsiteInterface } from "graphql/operations";
import { GetStaticProps } from "next";
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
import AppLayout from "components/AppLayout";
import ReturnButton, {
ReturnButtonType,
} from "components/PanelComponents/ReturnButton";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type FourOhFourProps = {
langui: GetWebsiteInterfaceQuery;
};
interface FourOhFourProps extends AppStaticProps {}
export default function FourOhFour(props: FourOhFourProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui } = props;
const contentPanel = (
<ContentPanel>
<h1>404 - {langui.page_not_found}</h1>
@ -25,21 +21,14 @@ export default function FourOhFour(props: FourOhFourProps): JSX.Element {
/>
</ContentPanel>
);
return (
<AppLayout navTitle="404" langui={langui} contentPanel={contentPanel} />
);
return <AppLayout navTitle="404" contentPanel={contentPanel} {...props} />;
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: FourOhFourProps = {
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
return { props: {} };
const props: FourOhFourProps = {
...(await getAppStaticProps(context)),
};
return {
props: props,
};
};

View File

@ -2,14 +2,15 @@ import type { AppProps } from "next/app";
import "tailwind.css";
import "@fontsource/zen-maru-gothic/500.css";
import "@fontsource/vollkorn/700.css";
import "@fontsource/opendyslexic/400.css"
import "@fontsource/material-icons";
import { AppContextProvider } from "contexts/AppLayoutContext";
export default function AccordsLibraryApp(appProps: AppProps) {
export default function AccordsLibraryApp(props: AppProps) {
return (
<AppContextProvider>
<appProps.Component {...appProps.pageProps} />
<props.Component {...props.pageProps} />
</AppContextProvider>
);
}

View File

@ -16,6 +16,7 @@ class MyDocument extends Document {
return (
<Html>
<Head>
<link
rel="apple-touch-icon"
sizes="180x180"

View File

@ -1,16 +1,13 @@
import SubPanel from "components/Panels/SubPanel";
import PanelHeader from "components/PanelComponents/PanelHeader";
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
import { GetStaticProps } from "next";
import { getWebsiteInterface } from "graphql/operations";
import AppLayout from "components/AppLayout";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type AboutUsProps = {
langui: GetWebsiteInterfaceQuery;
};
interface AboutUsProps extends AppStaticProps {}
export default function AboutUs(props: AboutUsProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui } = props;
const subPanel = (
<SubPanel>
<PanelHeader
@ -21,24 +18,15 @@ export default function AboutUs(props: AboutUsProps): JSX.Element {
</SubPanel>
);
return (
<AppLayout
navTitle={langui.about_us}
langui={langui}
subPanel={subPanel}
/>
<AppLayout navTitle={langui.about_us} subPanel={subPanel} {...props} />
);
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: AboutUsProps = {
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
return { props: {} };
const props: AboutUsProps = {
...(await getAppStaticProps(context)),
};
return {
props: props,
};
};

View File

@ -1,16 +1,13 @@
import SubPanel from "components/Panels/SubPanel";
import PanelHeader from "components/PanelComponents/PanelHeader";
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
import { GetStaticProps } from "next";
import { getWebsiteInterface } from "graphql/operations";
import AppLayout from "components/AppLayout";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type ArchivesProps = {
langui: GetWebsiteInterfaceQuery;
};
interface ArchivesProps extends AppStaticProps {}
export default function Archives(props: ArchivesProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui } = props;
const subPanel = (
<SubPanel>
<PanelHeader
@ -21,24 +18,15 @@ export default function Archives(props: ArchivesProps): JSX.Element {
</SubPanel>
);
return (
<AppLayout
navTitle={langui.archives}
langui={langui}
subPanel={subPanel}
/>
<AppLayout navTitle={langui.archives} subPanel={subPanel} {...props} />
);
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: ArchivesProps = {
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
return { props: {} };
const props: ArchivesProps = {
...(await getAppStaticProps(context)),
};
return {
props: props,
};
};

View File

@ -1,16 +1,13 @@
import SubPanel from "components/Panels/SubPanel";
import PanelHeader from "components/PanelComponents/PanelHeader";
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
import { GetStaticProps } from "next";
import { getWebsiteInterface } from "graphql/operations";
import AppLayout from "components/AppLayout";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type ChroniclesProps = {
langui: GetWebsiteInterfaceQuery;
};
interface ChroniclesProps extends AppStaticProps {}
export default function Chronicles(props: ChroniclesProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui } = props;
const subPanel = (
<SubPanel>
<PanelHeader
@ -21,24 +18,15 @@ export default function Chronicles(props: ChroniclesProps): JSX.Element {
</SubPanel>
);
return (
<AppLayout
navTitle={langui.chronicles}
langui={langui}
subPanel={subPanel}
/>
<AppLayout navTitle={langui.chronicles} subPanel={subPanel} {...props} />
);
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: ChroniclesProps = {
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
return { props: {} };
const props: ChroniclesProps = {
...(await getAppStaticProps(context)),
};
return {
props: props,
};
};

View File

@ -1,13 +1,6 @@
import { GetStaticPaths, GetStaticProps } from "next";
import {
getContent,
getContentsSlugs,
getWebsiteInterface,
} from "graphql/operations";
import {
GetContentQuery,
GetWebsiteInterfaceQuery,
} from "graphql/operations-types";
import { getContent, getContentsSlugs } from "graphql/operations";
import { GetContentQuery } from "graphql/operations-types";
import ContentPanel from "components/Panels/ContentPanel";
import Button from "components/Button";
import HorizontalLine from "components/HorizontalLine";
@ -18,15 +11,14 @@ import ReturnButton, {
ReturnButtonType,
} from "components/PanelComponents/ReturnButton";
import { prettyinlineTitle, prettySlug } from "queries/helpers";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type ContentIndexProps = {
content: GetContentQuery;
langui: GetWebsiteInterfaceQuery;
};
interface ContentIndexProps extends AppStaticProps {
content: GetContentQuery["contents"]["data"][number]["attributes"];
}
export default function ContentIndex(props: ContentIndexProps): JSX.Element {
const content = props.content.contents.data[0].attributes;
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { content, langui } = props;
const subPanel = (
<SubPanel>
<ReturnButton
@ -36,7 +28,6 @@ export default function ContentIndex(props: ContentIndexProps): JSX.Element {
displayOn={ReturnButtonType.Desktop}
horizontalLine
/>
</SubPanel>
);
const contentPanel = (
@ -93,46 +84,46 @@ export default function ContentIndex(props: ContentIndexProps): JSX.Element {
: prettySlug(content.slug)
}
thumbnail={content.thumbnail.data?.attributes}
langui={langui}
contentPanel={contentPanel}
subPanel={subPanel}
description={
content.titles.length > 0 ? content.titles[0].description : undefined
description={`${langui.type}: ${
content.type.data.attributes.titles.length > 0
? content.type.data.attributes.titles[0].title
: prettySlug(content.type.data.attributes.slug)
}
${langui.categories}: ${
content.categories.data.length > 0 &&
content.categories.data
.map((category) => {
return category.attributes.short;
})
.join(" | ")
}
${content.titles.length > 0 ? content.titles[0].description : undefined}
`}
{...props}
/>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.params) {
if (context.params.slug && context.locale) {
if (context.params.slug instanceof Array)
context.params.slug = context.params.slug.join("");
const props: ContentIndexProps = {
content: await getContent({
slug: context.params.slug,
language_code: context.locale,
}),
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
}
return { props: {} };
const props: ContentIndexProps = {
...(await getAppStaticProps(context)),
content: (
await getContent({
slug: context.params?.slug?.toString() || "",
language_code: context.locale || "en",
})
).contents.data[0].attributes,
};
return {
props: props,
};
};
export const getStaticPaths: GetStaticPaths = async (context) => {
type Path = {
params: {
slug: string;
};
locale: string;
};
type Path = { params: { slug: string }; locale: string };
const data = await getContentsSlugs({});
const paths: Path[] = [];

View File

@ -1,13 +1,8 @@
import { GetStaticPaths, GetStaticProps } from "next";
import {
getContentsSlugs,
getContentText,
getWebsiteInterface,
} from "graphql/operations";
import { getContentsSlugs, getContentText } from "graphql/operations";
import {
Enum_Componentsetstextset_Status,
GetContentTextQuery,
GetWebsiteInterfaceQuery,
} from "graphql/operations-types";
import ContentPanel from "components/Panels/ContentPanel";
import HorizontalLine from "components/HorizontalLine";
@ -30,16 +25,16 @@ import { useRouter } from "next/router";
import Chip from "components/Chip";
import ReactTooltip from "react-tooltip";
import RecorderChip from "components/RecorderChip";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
interface ContentReadProps {
content: GetContentTextQuery;
langui: GetWebsiteInterfaceQuery;
interface ContentReadProps extends AppStaticProps {
content: GetContentTextQuery["contents"]["data"][number]["attributes"];
contentId: GetContentTextQuery["contents"]["data"][number]["id"];
}
export default function ContentRead(props: ContentReadProps): JSX.Element {
useTesting(props);
const content = props.content.contents.data[0].attributes;
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui, content } = props;
const router = useRouter();
const subPanel = (
@ -57,14 +52,14 @@ export default function ContentRead(props: ContentReadProps): JSX.Element {
<h2 className="text-xl">
{content.text_set[0].source_language.data.attributes.code ===
router.locale
? "This content is a transcript"
: "This content is a fan-translation"}
? langui.transcript_notice
: langui.translation_notice}
</h2>
{content.text_set[0].source_language.data.attributes.code !==
router.locale && (
<div className="grid place-items-center gap-2">
<p className="font-headers">Source language:</p>
<p className="font-headers">{langui.source_language}:</p>
<Button
href={router.asPath}
locale={
@ -79,20 +74,20 @@ export default function ContentRead(props: ContentReadProps): JSX.Element {
)}
<div className="grid grid-flow-col place-items-center place-content-center gap-2">
<p className="font-headers">Status:</p>
<p className="font-headers">{langui.status}:</p>
<Chip
data-tip={
content.text_set[0].status ===
Enum_Componentsetstextset_Status.Incomplete
? "This entry is only partially translated/transcribed."
? langui.status_incomplete
: content.text_set[0].status ===
Enum_Componentsetstextset_Status.Draft
? "This entry is just a draft. It usually means that this is a work-in-progress. Translation/transcription might be poor and/or computer-generated."
? langui.status_draft
: content.text_set[0].status ===
Enum_Componentsetstextset_Status.Review
? "This entry has not yet being proofread. The content should still be accurate."
: "This entry has been checked and proofread. If you notice any translation errors or typos, please contact us so we can fix it!"
? langui.status_review
: langui.status_done
}
data-for={"StatusTooltip"}
>
@ -102,10 +97,14 @@ export default function ContentRead(props: ContentReadProps): JSX.Element {
{content.text_set[0].transcribers.data.length > 0 && (
<div>
<p className="font-headers">Transcribers:</p>
<p className="font-headers">{langui.transcribers}:</p>
<div className="grid place-items-center place-content-center gap-2">
{content.text_set[0].transcribers.data.map((recorder) => (
<RecorderChip key={recorder.id} recorder={recorder} />
<RecorderChip
key={recorder.id}
langui={langui}
recorder={recorder}
/>
))}
</div>
</div>
@ -113,10 +112,14 @@ export default function ContentRead(props: ContentReadProps): JSX.Element {
{content.text_set[0].translators.data.length > 0 && (
<div>
<p className="font-headers">Translators:</p>
<p className="font-headers">{langui.translators}:</p>
<div className="grid place-items-center place-content-center gap-2">
{content.text_set[0].translators.data.map((recorder) => (
<RecorderChip key={recorder.id} recorder={recorder} />
<RecorderChip
key={recorder.id}
langui={langui}
recorder={recorder}
/>
))}
</div>
</div>
@ -124,10 +127,14 @@ export default function ContentRead(props: ContentReadProps): JSX.Element {
{content.text_set[0].proofreaders.data.length > 0 && (
<div>
<p className="font-headers">Proofreaders:</p>
<p className="font-headers">{langui.proofreaders}:</p>
<div className="grid place-items-center place-content-center gap-2">
{content.text_set[0].proofreaders.data.map((recorder) => (
<RecorderChip key={recorder.id} recorder={recorder} />
<RecorderChip
key={recorder.id}
langui={langui}
recorder={recorder}
/>
))}
</div>
</div>
@ -200,35 +207,45 @@ export default function ContentRead(props: ContentReadProps): JSX.Element {
: prettySlug(content.slug)
}
thumbnail={content.thumbnail.data?.attributes}
langui={langui}
contentPanel={contentPanel}
subPanel={subPanel}
extra={extra}
description={`${langui.type}: ${
content.type.data.attributes.titles.length > 0
? content.type.data.attributes.titles[0].title
: prettySlug(content.type.data.attributes.slug)
}
${langui.categories}: ${
content.categories.data.length > 0 &&
content.categories.data
.map((category) => {
return category.attributes.short;
})
.join(" | ")
}
${content.titles.length > 0 ? content.titles[0].description : undefined}
`}
{...props}
/>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.params) {
if (context.params.slug && context.locale) {
if (context.params.slug instanceof Array)
context.params.slug = context.params.slug.join("");
const props: ContentReadProps = {
content: await getContentText({
slug: context.params.slug,
language_code: context.locale,
}),
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
}
return { props: {} };
const content = (
await getContentText({
slug: context.params?.slug?.toString() || "",
language_code: context.locale || "en",
})
).contents.data[0];
const props: ContentReadProps = {
...(await getAppStaticProps(context)),
content: content.attributes,
contentId: content.id,
};
return {
props: props,
};
};
export const getStaticPaths: GetStaticPaths = async (context) => {
@ -254,11 +271,10 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
export function useTesting(props: ContentReadProps) {
const router = useRouter();
const content = props.content.contents.data[0].attributes;
const { content, contentId } = props;
const contentURL =
"/admin/content-manager/collectionType/api::content.content/" +
props.content.contents.data[0].id;
"/admin/content-manager/collectionType/api::content.content/" + contentId;
if (router.locale === "en") {
if (content.categories.data.length === 0) {

View File

@ -3,25 +3,56 @@ import SubPanel from "components/Panels/SubPanel";
import ContentPanel, {
ContentPanelWidthSizes,
} from "components/Panels/ContentPanel";
import {
GetContentsQuery,
GetWebsiteInterfaceQuery,
} from "graphql/operations-types";
import { getContents, getWebsiteInterface } from "graphql/operations";
import { GetContentsQuery } from "graphql/operations-types";
import { getContents } from "graphql/operations";
import PanelHeader from "components/PanelComponents/PanelHeader";
import AppLayout from "components/AppLayout";
import LibraryContentPreview from "components/Library/LibraryContentPreview";
import { prettyinlineTitle } from "queries/helpers";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type LibraryProps = {
contents: GetContentsQuery;
langui: GetWebsiteInterfaceQuery;
};
interface LibraryProps extends AppStaticProps {
contents: GetContentsQuery["contents"]["data"];
}
export default function Library(props: LibraryProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui } = props;
const subPanel = (
<SubPanel>
<PanelHeader
icon="workspaces"
title={langui.contents}
description={langui.contents_description}
/>
</SubPanel>
);
const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.large}>
<div className="grid gap-8 items-end grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))]">
{props.contents.map((item) => (
<LibraryContentPreview key={item.id} item={item.attributes} />
))}
</div>
</ContentPanel>
);
return (
<AppLayout
navTitle={langui.contents}
subPanel={subPanel}
contentPanel={contentPanel}
{...props}
/>
);
}
props.contents.contents.data.sort((a, b) => {
export const getStaticProps: GetStaticProps = async (context) => {
const contents = (
await getContents({
language_code: context.locale || "en",
})
).contents.data;
contents.sort((a, b) => {
const titleA =
a.attributes.titles.length > 0
? prettyinlineTitle(
@ -41,48 +72,11 @@ export default function Library(props: LibraryProps): JSX.Element {
return titleA.localeCompare(titleB);
});
const subPanel = (
<SubPanel>
<PanelHeader
icon="workspaces"
title="Contents"
description="Laboriosam vitae velit quis. Non et dolor reiciendis officia earum et molestias excepturi. Cupiditate officiis quis qui reprehenderit. Ut neque eos ipsa corrupti autem mollitia inventore. Exercitationem iste magni vel harum."
/>
</SubPanel>
);
const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.large}>
<div className="grid gap-8 items-end grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))]">
{props.contents.contents.data.map((item) => (
<LibraryContentPreview key={item.id} item={item.attributes} />
))}
</div>
</ContentPanel>
);
return (
<AppLayout
navTitle="Contents"
langui={langui}
subPanel={subPanel}
contentPanel={contentPanel}
/>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: LibraryProps = {
contents: await getContents({
language_code: context.locale,
}),
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
} else {
return { props: {} };
}
const props: LibraryProps = {
...(await getAppStaticProps(context)),
contents: contents,
};
return {
props: props,
};
};

View File

@ -1,20 +1,17 @@
import ContentPanel, {
ContentPanelWidthSizes,
} from "components/Panels/ContentPanel";
import { getWebsiteInterface } from "graphql/operations";
import { GetStaticProps } from "next";
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
import AppLayout from "components/AppLayout";
import { useCallback, useState } from "react";
import Markdawn from "components/Markdown/Markdawn";
import Script from "next/script";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type EditorProps = {
langui: GetWebsiteInterfaceQuery;
};
interface EditorProps extends AppStaticProps {}
export default function Editor(props: EditorProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui } = props;
const handleInput = useCallback((e) => {
setMarkdown(e.target.value);
@ -45,12 +42,14 @@ export default function Editor(props: EditorProps): JSX.Element {
onInput={handleInput}
className="bg-mid rounded-xl p-8 w-full font-monospace"
value={markdown}
title="Input textarea"
/>
<h2 className="mt-4">Convert text to markdown</h2>
<textarea
readOnly
id="htmlMdTextArea"
title="Ouput textarea"
onPaste={(event) => {
const TurndownService = require("turndown").default;
const turndownService = new TurndownService({
@ -86,22 +85,17 @@ export default function Editor(props: EditorProps): JSX.Element {
return (
<AppLayout
navTitle="Markdawn Editor"
langui={langui}
contentPanel={contentPanel}
{...props}
/>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: EditorProps = {
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
return { props: {} };
const props: EditorProps = {
...(await getAppStaticProps(context)),
};
return {
props: props,
};
};

View File

@ -1,14 +1,11 @@
import AppLayout from "components/AppLayout";
import { getWebsiteInterface } from "graphql/operations";
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
import { GetStaticProps } from "next";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type GalleryProps = {
langui: GetWebsiteInterfaceQuery;
};
interface GalleryProps extends AppStaticProps {}
export default function Gallery(props: GalleryProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui } = props;
const contentPanel = (
<iframe
className="w-full h-screen"
@ -19,22 +16,17 @@ export default function Gallery(props: GalleryProps): JSX.Element {
return (
<AppLayout
navTitle={langui.gallery}
langui={langui}
contentPanel={contentPanel}
{...props}
/>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: GalleryProps = {
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
return { props: {} };
const props: GalleryProps = {
...(await getAppStaticProps(context)),
};
return {
props: props,
};
};

View File

@ -1,16 +1,11 @@
import AppLayout from "components/AppLayout";
import ContentPanel from "components/Panels/ContentPanel";
import SVG from "components/SVG";
import { getWebsiteInterface } from "graphql/operations";
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
import { GetStaticProps } from "next";
type HomeProps = {
langui: GetWebsiteInterfaceQuery;
};
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
interface HomeProps extends AppStaticProps {}
export default function Home(props: HomeProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const contentPanel = (
<ContentPanel autoformat>
<div className="grid place-items-center place-content-center w-full gap-5 text-center">
@ -140,26 +135,14 @@ export default function Home(props: HomeProps): JSX.Element {
</ContentPanel>
);
return (
<AppLayout
navTitle={"Home"}
langui={langui}
contentPanel={contentPanel}
/>
);
return <AppLayout navTitle={"Home"} contentPanel={contentPanel} {...props} />;
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: HomeProps = {
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
} else {
return { props: {} };
}
const props: HomeProps = {
...(await getAppStaticProps(context)),
};
return {
props: props,
};
};

View File

@ -2,16 +2,11 @@ import ContentPanel, {
ContentPanelWidthSizes,
} from "components/Panels/ContentPanel";
import { GetStaticPaths, GetStaticProps } from "next";
import {
getLibraryItem,
getLibraryItemsSlugs,
getWebsiteInterface,
} from "graphql/operations";
import { getLibraryItem, getLibraryItemsSlugs } from "graphql/operations";
import {
Enum_Componentmetadatabooks_Binding_Type,
Enum_Componentmetadatabooks_Page_Order,
GetLibraryItemQuery,
GetWebsiteInterfaceQuery,
} from "graphql/operations-types";
import {
convertMmToInch,
@ -20,7 +15,6 @@ import {
prettyItemType,
prettyItemSubType,
prettyPrice,
prettySlug,
prettyTestError,
prettyTestWarning,
sortContent,
@ -32,7 +26,6 @@ import ReturnButton, {
import NavOption from "components/PanelComponents/NavOption";
import Chip from "components/Chip";
import Button from "components/Button";
import HorizontalLine from "components/HorizontalLine";
import AppLayout from "components/AppLayout";
import LibraryItemsPreview from "components/Library/LibraryItemsPreview";
import InsetBox from "components/InsetBox";
@ -40,16 +33,16 @@ import Img, { ImageQuality } from "components/Img";
import { useAppLayout } from "contexts/AppLayoutContext";
import { useRouter } from "next/router";
import ContentTOCLine from "components/Library/ContentTOCLine";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
interface LibrarySlugProps {
libraryItem: GetLibraryItemQuery;
langui: GetWebsiteInterfaceQuery;
interface LibrarySlugProps extends AppStaticProps {
item: GetLibraryItemQuery["libraryItems"]["data"][number]["attributes"];
itemId: GetLibraryItemQuery["libraryItems"]["data"][number]["id"];
}
export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
useTesting(props);
const item = props.libraryItem.libraryItems.data[0].attributes;
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { item, langui, currencies } = props;
const appLayout = useAppLayout();
const isVariantSet =
@ -202,7 +195,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
<h2 className="text-2xl text-center">{langui.details}</h2>
<div className="grid grid-flow-col w-full place-content-between">
{item.metadata.length > 0 ? (
<div className="grid place-items-center">
<div className="grid place-items-center place-content-start">
<h3 className="text-xl">{langui.type}</h3>
<div className="grid grid-flow-col gap-1">
<Chip>{prettyItemType(item.metadata[0], langui)}</Chip>
@ -215,7 +208,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
)}
{item.release_date ? (
<div className="grid place-items-center">
<div className="grid place-items-center place-content-start">
<h3 className="text-xl">{langui.release_date}</h3>
<p>{prettyDate(item.release_date)}</p>
</div>
@ -224,9 +217,22 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
)}
{item.price ? (
<div className="grid place-items-center">
<div className="grid place-items-center text-center place-content-start">
<h3 className="text-xl">{langui.price}</h3>
<p>{prettyPrice(item.price)}</p>
<p>
{prettyPrice(
item.price,
currencies,
item.price.currency.data.attributes.code
)}
</p>
{item.price.currency.data.attributes.code !==
appLayout.currency && (
<p>
{prettyPrice(item.price, currencies, appLayout.currency)}{" "}
<br />({langui.calculated?.toLowerCase()})
</p>
)}
</div>
) : (
""
@ -267,7 +273,9 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
""
)}
{item.metadata.length > 0 ? (
{item.metadata.length > 0 &&
item.metadata[0].__typename !== "ComponentMetadataGroup" &&
item.metadata[0].__typename !== "ComponentMetadataOther" ? (
<>
<h3 className="text-xl">{langui.type_information}</h3>
<div className="grid grid-cols-2 w-full place-content-between">
@ -322,9 +330,6 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
) : item.metadata[0].__typename ===
"ComponentMetadataGame" ? (
<></>
) : item.metadata[0].__typename ===
"ComponentMetadataGroup" ? (
<></>
) : (
""
)}
@ -382,7 +387,6 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
<AppLayout
navTitle={langui.library}
title={prettyinlineTitle("", item.title, item.subtitle)}
langui={langui}
contentPanel={contentPanel}
subPanel={subPanel}
thumbnail={item.thumbnail.data?.attributes}
@ -391,31 +395,26 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
? item.descriptions[0].description
: undefined
}
{...props}
/>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.params) {
if (context.params.slug && context.locale) {
if (context.params.slug instanceof Array)
context.params.slug = context.params.slug.join("");
const props: LibrarySlugProps = {
libraryItem: await getLibraryItem({
slug: context.params.slug,
language_code: context.locale,
}),
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
}
return { props: {} };
const item = (
await getLibraryItem({
slug: context.params?.slug?.toString() || "",
language_code: context.locale || "en",
})
).libraryItems.data[0];
const props: LibrarySlugProps = {
...(await getAppStaticProps(context)),
item: item.attributes,
itemId: item.id,
};
return {
props: props,
};
};
export const getStaticPaths: GetStaticPaths = async (context) => {
@ -440,17 +439,17 @@ export const getStaticPaths: GetStaticPaths = async (context) => {
};
function useTesting(props: LibrarySlugProps) {
const libraryItem = props.libraryItem.libraryItems.data[0].attributes;
const { item, itemId } = props;
const router = useRouter();
const libraryItemURL =
"/admin/content-manager/collectionType/api::library-item.library-item/" +
props.libraryItem.libraryItems.data[0].id;
itemId;
sortContent(libraryItem.contents);
sortContent(item.contents);
if (router.locale === "en") {
if (!libraryItem.thumbnail.data) {
if (!item.thumbnail.data) {
prettyTestError(
router,
"Missing thumbnail",
@ -458,7 +457,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
}
if (libraryItem.metadata.length === 0) {
if (item.metadata.length === 0) {
prettyTestError(
router,
"Missing metadata",
@ -467,14 +466,12 @@ function useTesting(props: LibrarySlugProps) {
);
} else {
if (
libraryItem.metadata[0].__typename === "ComponentMetadataGroup" &&
(libraryItem.metadata[0].subtype.data.attributes.slug ===
"relation-set" ||
libraryItem.metadata[0].subtype.data.attributes.slug ===
"variant-set")
item.metadata[0].__typename === "ComponentMetadataGroup" &&
(item.metadata[0].subtype.data.attributes.slug === "relation-set" ||
item.metadata[0].subtype.data.attributes.slug === "variant-set")
) {
// This is a group type item
if (libraryItem.price) {
if (item.price) {
prettyTestError(
router,
"Group-type items shouldn't have price",
@ -482,7 +479,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
}
if (libraryItem.size) {
if (item.size) {
prettyTestError(
router,
"Group-type items shouldn't have size",
@ -490,7 +487,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
}
if (libraryItem.release_date) {
if (item.release_date) {
prettyTestError(
router,
"Group-type items shouldn't have release_date",
@ -498,7 +495,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
}
if (libraryItem.contents.data.length > 0) {
if (item.contents.data.length > 0) {
prettyTestError(
router,
"Group-type items shouldn't have contents",
@ -506,7 +503,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
}
if (libraryItem.subitems.data.length === 0) {
if (item.subitems.data.length === 0) {
prettyTestError(
router,
"Group-type items should have subitems",
@ -517,8 +514,8 @@ function useTesting(props: LibrarySlugProps) {
} else {
// This is a normal item
if (libraryItem.metadata[0].__typename === "ComponentMetadataGroup") {
if (libraryItem.subitems.data.length === 0) {
if (item.metadata[0].__typename === "ComponentMetadataGroup") {
if (item.subitems.data.length === 0) {
prettyTestError(
router,
"Group-type item should have subitems",
@ -528,7 +525,7 @@ function useTesting(props: LibrarySlugProps) {
}
}
if (!libraryItem.price) {
if (!item.price) {
prettyTestWarning(
router,
"Missing price",
@ -536,7 +533,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
} else {
if (!libraryItem.price.amount) {
if (!item.price.amount) {
prettyTestError(
router,
"Missing amount",
@ -544,7 +541,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
}
if (!libraryItem.price.currency) {
if (!item.price.currency) {
prettyTestError(
router,
"Missing currency",
@ -554,8 +551,8 @@ function useTesting(props: LibrarySlugProps) {
}
}
if (!libraryItem.digital) {
if (!libraryItem.size) {
if (!item.digital) {
if (!item.size) {
prettyTestWarning(
router,
"Missing size",
@ -563,7 +560,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
} else {
if (!libraryItem.size.width) {
if (!item.size.width) {
prettyTestWarning(
router,
"Missing width",
@ -571,7 +568,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
}
if (!libraryItem.size.height) {
if (!item.size.height) {
prettyTestWarning(
router,
"Missing height",
@ -579,7 +576,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
}
if (!libraryItem.size.thickness) {
if (!item.size.thickness) {
prettyTestWarning(
router,
"Missing thickness",
@ -590,7 +587,7 @@ function useTesting(props: LibrarySlugProps) {
}
}
if (!libraryItem.release_date) {
if (!item.release_date) {
prettyTestWarning(
router,
"Missing release_date",
@ -598,7 +595,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
} else {
if (!libraryItem.release_date.year) {
if (!item.release_date.year) {
prettyTestError(
router,
"Missing year",
@ -606,7 +603,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
}
if (!libraryItem.release_date.month) {
if (!item.release_date.month) {
prettyTestError(
router,
"Missing month",
@ -614,7 +611,7 @@ function useTesting(props: LibrarySlugProps) {
libraryItemURL
);
}
if (!libraryItem.release_date.day) {
if (!item.release_date.day) {
prettyTestError(
router,
"Missing day",
@ -624,7 +621,7 @@ function useTesting(props: LibrarySlugProps) {
}
}
if (libraryItem.contents.data.length === 0) {
if (item.contents.data.length === 0) {
prettyTestWarning(
router,
"Missing contents",
@ -633,7 +630,7 @@ function useTesting(props: LibrarySlugProps) {
);
} else {
let currentRangePage = 0;
libraryItem.contents.data.map((content) => {
item.contents.data.map((content) => {
const contentURL =
"/admin/content-manager/collectionType/api::content.content/" +
content.id;
@ -694,26 +691,26 @@ function useTesting(props: LibrarySlugProps) {
}
});
if (libraryItem.metadata[0].__typename === "ComponentMetadataBooks") {
if (currentRangePage < libraryItem.metadata[0].page_count) {
if (item.metadata[0].__typename === "ComponentMetadataBooks") {
if (currentRangePage < item.metadata[0].page_count) {
prettyTestError(
router,
`Missing pages ${currentRangePage + 1} to ${
libraryItem.metadata[0].page_count
item.metadata[0].page_count
}`,
["libraryItem", "content"],
libraryItemURL
);
} else if (currentRangePage > libraryItem.metadata[0].page_count) {
} else if (currentRangePage > item.metadata[0].page_count) {
prettyTestError(
router,
`Page overflow, content references pages up to ${currentRangePage} when the highest expected was ${libraryItem.metadata[0].page_count}`,
`Page overflow, content references pages up to ${currentRangePage} when the highest expected was ${item.metadata[0].page_count}`,
["libraryItem", "content"],
libraryItemURL
);
}
if (libraryItem.metadata[0].languages.data.length === 0) {
if (item.metadata[0].languages.data.length === 0) {
prettyTestWarning(
router,
"Missing language",
@ -722,7 +719,7 @@ function useTesting(props: LibrarySlugProps) {
);
}
if (!libraryItem.metadata[0].page_count) {
if (!item.metadata[0].page_count) {
prettyTestWarning(
router,
"Missing page_count",
@ -735,7 +732,7 @@ function useTesting(props: LibrarySlugProps) {
}
}
if (!libraryItem.root_item && libraryItem.subitem_of.data.length === 0) {
if (!item.root_item && item.subitem_of.data.length === 0) {
prettyTestError(
router,
"This item is inaccessible (not root item and not subitem of another item)",
@ -744,7 +741,7 @@ function useTesting(props: LibrarySlugProps) {
);
}
if (libraryItem.gallery.data.length === 0) {
if (item.gallery.data.length === 0) {
prettyTestWarning(
router,
"Missing gallery",
@ -754,7 +751,7 @@ function useTesting(props: LibrarySlugProps) {
}
}
if (libraryItem.descriptions.length === 0) {
if (item.descriptions.length === 0) {
prettyTestWarning(
router,
"Missing description",

View File

@ -7,10 +7,7 @@ import {
GetLibraryItemsPreviewQuery,
GetWebsiteInterfaceQuery,
} from "graphql/operations-types";
import {
getLibraryItemsPreview,
getWebsiteInterface,
} from "graphql/operations";
import { getLibraryItemsPreview } from "graphql/operations";
import PanelHeader from "components/PanelComponents/PanelHeader";
import AppLayout from "components/AppLayout";
import LibraryItemsPreview from "components/Library/LibraryItemsPreview";
@ -18,11 +15,11 @@ import Select from "components/Select";
import { useEffect, useState } from "react";
import { prettyDate, prettyinlineTitle } from "queries/helpers";
import Switch from "components/Switch";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type LibraryProps = {
libraryItems: GetLibraryItemsPreviewQuery;
langui: GetWebsiteInterfaceQuery;
};
interface LibraryProps extends AppStaticProps {
items: GetLibraryItemsPreviewQuery["libraryItems"]["data"];
}
type GroupLibraryItems = Map<
string,
@ -30,7 +27,7 @@ type GroupLibraryItems = Map<
>;
export default function Library(props: LibraryProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui, items } = props;
const [showSubitems, setShowSubitems] = useState<boolean>(false);
const [showPrimaryItems, setShowPrimaryItems] = useState<boolean>(true);
@ -38,20 +35,13 @@ export default function Library(props: LibraryProps): JSX.Element {
const [sortingMethod, setSortingMethod] = useState<number>(0);
const [groupingMethod, setGroupingMethod] = useState<number>(-1);
const [filteredItems, setFilteredItems] = useState<
LibraryProps["libraryItems"]["libraryItems"]["data"]
>(
filterItems(
showSubitems,
showPrimaryItems,
showSecondaryItems,
props.libraryItems.libraryItems.data
)
const [filteredItems, setFilteredItems] = useState<LibraryProps["items"]>(
filterItems(showSubitems, showPrimaryItems, showSecondaryItems, items)
);
const [sortedItems, setSortedItem] = useState<
LibraryProps["libraryItems"]["libraryItems"]["data"]
>(sortBy(groupingMethod, filteredItems));
const [sortedItems, setSortedItem] = useState<LibraryProps["items"]>(
sortBy(groupingMethod, filteredItems)
);
const [groups, setGroups] = useState<GroupLibraryItems>(
getGroups(langui, groupingMethod, sortedItems)
@ -59,19 +49,9 @@ export default function Library(props: LibraryProps): JSX.Element {
useEffect(() => {
setFilteredItems(
filterItems(
showSubitems,
showPrimaryItems,
showSecondaryItems,
props.libraryItems.libraryItems.data
)
filterItems(showSubitems, showPrimaryItems, showSecondaryItems, items)
);
}, [
showSubitems,
props.libraryItems.libraryItems.data,
showPrimaryItems,
showSecondaryItems,
]);
}, [showSubitems, items, showPrimaryItems, showSecondaryItems]);
useEffect(() => {
setSortedItem(sortBy(sortingMethod, filteredItems));
@ -138,7 +118,11 @@ export default function Library(props: LibraryProps): JSX.Element {
className="grid gap-8 items-end mobile:grid-cols-2 desktop:grid-cols-[repeat(auto-fill,_minmax(13rem,1fr))] pb-12 border-b-[3px] border-dotted last-of-type:border-0"
>
{items.map((item) => (
<LibraryItemsPreview key={item.id} item={item.attributes} />
<LibraryItemsPreview
key={item.id}
item={item.attributes}
currencies={props.currencies}
/>
))}
</div>
</>
@ -150,35 +134,31 @@ export default function Library(props: LibraryProps): JSX.Element {
return (
<AppLayout
navTitle={langui.library}
langui={langui}
subPanel={subPanel}
contentPanel={contentPanel}
{...props}
/>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: LibraryProps = {
libraryItems: await getLibraryItemsPreview({
language_code: context.locale,
}),
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
} else {
return { props: {} };
}
const props: LibraryProps = {
...(await getAppStaticProps(context)),
items: (
await getLibraryItemsPreview({
language_code: context.locale || "en",
})
).libraryItems.data,
};
return {
props: props,
};
};
function getGroups(
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"],
groupByType: number,
items: LibraryProps["libraryItems"]["libraryItems"]["data"]
items: LibraryProps["items"]
): GroupLibraryItems {
switch (groupByType) {
case 0:
@ -276,8 +256,8 @@ function filterItems(
showSubitems: boolean,
showPrimaryItems: boolean,
showSecondaryItems: boolean,
items: LibraryProps["libraryItems"]["libraryItems"]["data"]
): LibraryProps["libraryItems"]["libraryItems"]["data"] {
items: LibraryProps["items"]
): LibraryProps["items"] {
return [...items].filter((item) => {
if (!showSubitems && !item.attributes.root_item) return false;
if (
@ -298,8 +278,8 @@ function filterItems(
function sortBy(
orderByType: number,
items: LibraryProps["libraryItems"]["libraryItems"]["data"]
): LibraryProps["libraryItems"]["libraryItems"]["data"] {
items: LibraryProps["items"]
): LibraryProps["items"] {
switch (orderByType) {
case 0:
return [...items].sort((a, b) => {

View File

@ -1,16 +1,12 @@
import SubPanel from "components/Panels/SubPanel";
import PanelHeader from "components/PanelComponents/PanelHeader";
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
import { GetStaticProps } from "next";
import { getWebsiteInterface } from "graphql/operations";
import AppLayout from "components/AppLayout";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type MerchProps = {
langui: GetWebsiteInterfaceQuery;
};
interface MerchProps extends AppStaticProps {}
export default function Merch(props: MerchProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui } = props;
const subPanel = (
<SubPanel>
<PanelHeader
@ -21,25 +17,14 @@ export default function Merch(props: MerchProps): JSX.Element {
</SubPanel>
);
return (
<AppLayout
navTitle={langui.merch}
langui={langui}
subPanel={subPanel}
/>
);
return <AppLayout navTitle={langui.merch} subPanel={subPanel} {...props} />;
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: MerchProps = {
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
return { props: {} };
const props: MerchProps = {
...(await getAppStaticProps(context)),
};
return {
props: props,
};
};

View File

@ -1,16 +1,13 @@
import SubPanel from "components/Panels/SubPanel";
import PanelHeader from "components/PanelComponents/PanelHeader";
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
import { GetStaticProps } from "next";
import { getWebsiteInterface } from "graphql/operations";
import AppLayout from "components/AppLayout";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type NewsProps = {
langui: GetWebsiteInterfaceQuery;
};
interface NewsProps extends AppStaticProps {}
export default function News(props: NewsProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui } = props;
const subPanel = (
<SubPanel>
<PanelHeader
@ -21,25 +18,14 @@ export default function News(props: NewsProps): JSX.Element {
</SubPanel>
);
return (
<AppLayout
navTitle={langui.news}
langui={langui}
subPanel={subPanel}
/>
);
return <AppLayout navTitle={langui.news} subPanel={subPanel} {...props} />;
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: NewsProps = {
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
return { props: {} };
const props: NewsProps = {
...(await getAppStaticProps(context)),
};
return {
props: props,
};
};

View File

@ -5,18 +5,9 @@ import ChronologyYearComponent from "components/Chronology/ChronologyYearCompone
import {
GetChronologyItemsQuery,
GetErasQuery,
GetWebsiteInterfaceQuery,
} from "graphql/operations-types";
import {
getEras,
getChronologyItems,
getWebsiteInterface,
} from "graphql/operations";
import { getEras, getChronologyItems } from "graphql/operations";
import NavOption from "components/PanelComponents/NavOption";
import ReturnButton, {
ReturnButtonType,
} from "components/PanelComponents/ReturnButton";
import HorizontalLine from "components/HorizontalLine";
import AppLayout from "components/AppLayout";
import {
prettySlug,
@ -26,34 +17,32 @@ import {
import InsetBox from "components/InsetBox";
import { useRouter } from "next/router";
import ReactTooltip from "react-tooltip";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
interface DataChronologyProps {
chronologyItems: GetChronologyItemsQuery;
chronologyEras: GetErasQuery;
langui: GetWebsiteInterfaceQuery;
interface DataChronologyProps extends AppStaticProps {
chronologyItems: GetChronologyItemsQuery["chronologyItems"]["data"];
chronologyEras: GetErasQuery["chronologyEras"]["data"];
}
export default function DataChronology(
props: DataChronologyProps
): JSX.Element {
useTesting(props);
const langui = props.langui.websiteInterfaces.data[0].attributes;
const chronologyItems = props.chronologyItems.chronologyItems;
const chronologyEras = props.chronologyEras.chronologyEras;
const { chronologyItems, chronologyEras } = props;
// Group by year the Chronology items
let chronologyItemYearGroups: GetChronologyItemsQuery["chronologyItems"]["data"][number][][][] =
[];
chronologyEras.data.map(() => {
chronologyEras.map(() => {
chronologyItemYearGroups.push([]);
});
let currentChronologyEraIndex = 0;
chronologyItems.data.map((item) => {
chronologyItems.map((item) => {
if (
item.attributes.year >
chronologyEras.data[currentChronologyEraIndex].attributes.ending_year
chronologyEras[currentChronologyEraIndex].attributes.ending_year
) {
currentChronologyEraIndex++;
}
@ -74,7 +63,7 @@ export default function DataChronology(
const subPanel = (
<SubPanel>
{props.chronologyEras.chronologyEras.data.map((era) => (
{chronologyEras.map((era) => (
<NavOption
key={era.id}
url={"#" + era.attributes.slug}
@ -97,17 +86,17 @@ export default function DataChronology(
{chronologyItemYearGroups.map((era, eraIndex) => (
<>
<InsetBox
id={chronologyEras.data[eraIndex].attributes.slug}
id={chronologyEras[eraIndex].attributes.slug}
className="grid text-center my-8 gap-4"
>
<h2 className="text-2xl">
{chronologyEras.data[eraIndex].attributes.title.length > 0
? chronologyEras.data[eraIndex].attributes.title[0].title
: prettySlug(chronologyEras.data[eraIndex].attributes.slug)}
{chronologyEras[eraIndex].attributes.title.length > 0
? chronologyEras[eraIndex].attributes.title[0].title
: prettySlug(chronologyEras[eraIndex].attributes.slug)}
</h2>
<p className="whitespace-pre-line ">
{chronologyEras.data[eraIndex].attributes.title.length > 0
? chronologyEras.data[eraIndex].attributes.title[0].description
{chronologyEras[eraIndex].attributes.title.length > 0
? chronologyEras[eraIndex].attributes.title[0].description
: ""}
</p>
</InsetBox>
@ -136,37 +125,36 @@ export default function DataChronology(
return (
<AppLayout
navTitle="Chronology"
langui={langui}
contentPanel={contentPanel}
subPanel={subPanel}
{...props}
/>
);
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: DataChronologyProps = {
chronologyItems: await getChronologyItems({
language_code: context.locale,
}),
chronologyEras: await getEras({ language_code: context.locale }),
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
return { props: {} };
const props: DataChronologyProps = {
...(await getAppStaticProps(context)),
chronologyItems: (
await getChronologyItems({
language_code: context.locale || "en",
})
).chronologyItems.data,
chronologyEras: (await getEras({ language_code: context.locale || "en" }))
.chronologyEras.data,
};
return {
props: props,
};
};
function useTesting({ chronologyItems, chronologyEras }: DataChronologyProps) {
function useTesting(props: DataChronologyProps) {
const router = useRouter();
chronologyEras.chronologyEras.data.map((era) => {
const { chronologyItems, chronologyEras } = props;
chronologyEras.map((era) => {
const chronologyErasURL =
"/admin/content-manager/collectionType/api::chronology-era.chronology-era/" +
chronologyItems.chronologyItems.data[0].id;
chronologyItems[0].id;
if (era.attributes.title.length === 0) {
prettyTestError(
@ -200,10 +188,10 @@ function useTesting({ chronologyItems, chronologyEras }: DataChronologyProps) {
}
});
chronologyItems.chronologyItems.data.map((item) => {
chronologyItems.map((item) => {
const chronologyItemsURL =
"/admin/content-manager/collectionType/api::chronology-item.chronology-item/" +
chronologyItems.chronologyItems.data[0].id;
chronologyItems[0].id;
const date = `${item.attributes.year}/${item.attributes.month}/${item.attributes.day}`;

View File

@ -1,17 +1,13 @@
import SubPanel from "components/Panels/SubPanel";
import PanelHeader from "components/PanelComponents/PanelHeader";
import { GetWebsiteInterfaceQuery } from "graphql/operations-types";
import { GetStaticProps } from "next";
import { getWebsiteInterface } from "graphql/operations";
import ContentPanel from "components/Panels/ContentPanel";
import AppLayout from "components/AppLayout";
import { AppStaticProps, getAppStaticProps } from "queries/getAppStaticProps";
type WikiProps = {
langui: GetWebsiteInterfaceQuery;
};
interface WikiProps extends AppStaticProps {}
export default function Hubs(props: WikiProps): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const { langui } = props;
const subPanel = (
<SubPanel>
<PanelHeader
@ -21,28 +17,15 @@ export default function Hubs(props: WikiProps): JSX.Element {
/>
</SubPanel>
);
const contentPanel = <ContentPanel>Hello</ContentPanel>;
return (
<AppLayout
navTitle={langui.wiki}
langui={langui}
contentPanel={contentPanel}
subPanel={subPanel}
/>
);
return <AppLayout navTitle={langui.wiki} subPanel={subPanel} {...props} />;
}
export const getStaticProps: GetStaticProps = async (context) => {
if (context.locale) {
const props: WikiProps = {
langui: await getWebsiteInterface({
language_code: context.locale,
}),
};
return {
props: props,
};
}
return { props: {} };
const props: WikiProps = {
...(await getAppStaticProps(context)),
};
return {
props: props,
};
};

View File

@ -0,0 +1,44 @@
import {
getCurrencies,
getLanguages,
getWebsiteInterface,
} from "graphql/operations";
import {
GetCurrenciesQuery,
GetLanguagesQuery,
GetWebsiteInterfaceQuery,
} from "graphql/operations-types";
import { GetStaticPropsContext, PreviewData } from "next";
import { ParsedUrlQuery } from "querystring";
export interface AppStaticProps {
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
currencies: GetCurrenciesQuery["currencies"]["data"];
languages: GetLanguagesQuery["languages"]["data"];
}
export async function getAppStaticProps(
context: GetStaticPropsContext<ParsedUrlQuery, PreviewData>
): Promise<AppStaticProps> {
const languages = (await getLanguages({})).languages.data;
languages.sort((a, b) => {
return a.attributes.localized_name.localeCompare(
b.attributes.localized_name
);
});
const currencies = (await getCurrencies({})).currencies.data;
currencies.sort((a, b) => {
return a.attributes.code.localeCompare(b.attributes.code);
});
return {
langui: (
await getWebsiteInterface({
language_code: context.locale || "en",
})
).websiteInterfaces.data[0].attributes,
currencies: currencies,
languages: languages,
};
}

View File

@ -4,6 +4,7 @@ import {
ImageQuality,
} from "components/Img";
import {
GetCurrenciesQuery,
GetLibraryItemQuery,
GetLibraryItemsPreviewQuery,
GetWebsiteInterfaceQuery,
@ -24,12 +25,27 @@ export function prettyDate(
}
export function prettyPrice(
pricePicker: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["price"]
pricePicker: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["price"],
currencies: GetCurrenciesQuery["currencies"]["data"],
targetCurrencyCode?: string
): string {
return (
pricePicker.currency.data.attributes.symbol +
pricePicker.amount.toLocaleString()
);
if (!targetCurrencyCode) return "";
let result = "";
currencies.map((currency) => {
if (currency.attributes.code === targetCurrencyCode) {
let amountInUSD =
pricePicker.amount * pricePicker.currency.data.attributes.rate_to_usd;
let amountInTargetCurrency =
amountInUSD / currency.attributes.rate_to_usd;
result =
currency.attributes.symbol +
amountInTargetCurrency.toLocaleString(undefined, {
minimumFractionDigits: currency.attributes.display_decimals ? 2 : 0,
maximumFractionDigits: currency.attributes.display_decimals ? 2 : 0,
});
}
});
return result;
}
export function prettySlug(slug?: string, parentSlug?: string): string {

View File

@ -78,9 +78,22 @@
}
.prose blockquote {
@apply border-l-dark
@apply border-l-dark;
}
/* INPUT */
input {
@apply rounded-full p-2 text-center bg-light outline outline-mid outline-2 outline-offset-[-2px] hover:outline-[transparent] text-dark hover:bg-mid transition-all;
}
input::placeholder {
@apply text-dark opacity-60;
}
input:focus-visible {
@apply outline-none bg-mid shadow-inner-sm;
}
}
@layer components {

View File

@ -18,6 +18,17 @@ const breakDektop = { min: "60rem" };
const breakMobile = { max: "60rem" };
const breakThin = { max: "25rem" };
const fontStandard = {
body: "Zen Maru Gothic",
headers: "Vollkorn",
monospace: "monospace",
};
const fontDyslexic = {
body: "OpenDyslexic",
headers: "OpenDyslexic",
monospace: "monospace",
};
/* END CONFIG */
function withOpacity(variableName) {
@ -41,9 +52,11 @@ module.exports = {
black: withOpacity("--theme-color-black"),
},
fontFamily: {
body: ["Zen Maru Gothic"],
headers: ["Vollkorn"],
monospace: ["monospace"],
body: ["var(--theme-font-body)"],
headers: ["var(--theme-font-headers)"],
monospace: ["var(--theme-font-monospace)"],
openDyslexic: ["OpenDyslexic"],
zenMaruGothic: ["Zen Maru Gothic"],
},
screens: {
desktop: breakDektop,
@ -61,7 +74,6 @@ module.exports = {
plugins: [
require("@tailwindcss/typography"),
// Colored Dropshadow
plugin(function ({ addUtilities }) {
addUtilities({
".set-theme-light": {
@ -85,6 +97,21 @@ module.exports = {
});
}),
plugin(function ({ addUtilities }) {
addUtilities({
".set-theme-font-standard": {
"--theme-font-body": fontStandard.body,
"--theme-font-headers": fontStandard.headers,
"--theme-font-monospace": fontStandard.monospace,
},
".set-theme-font-dyslexic": {
"--theme-font-body": fontDyslexic.body,
"--theme-font-headers": fontDyslexic.headers,
"--theme-font-monospace": fontStandard.monospace,
},
});
}),
plugin(function ({ addVariant, e }) {
addVariant("webkit-scrollbar", ({ modifySelectors, separator }) => {
modifySelectors(({ className }) => {