Use of cJoin and cIf

This commit is contained in:
DrMint 2022-06-15 07:33:20 +02:00
parent 1510366bc8
commit c076ec06ad
44 changed files with 515 additions and 266 deletions

View File

@ -2,6 +2,7 @@ import { Button } from "components/Inputs/Button";
import { useAppLayout } from "contexts/AppLayoutContext"; import { useAppLayout } from "contexts/AppLayoutContext";
import { UploadImageFragment } from "graphql/generated"; import { UploadImageFragment } from "graphql/generated";
import { AppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps } from "graphql/getAppStaticProps";
import { cIf, cJoin } from "helpers/className";
import { prettyLanguage, prettySlug } from "helpers/formatters"; import { prettyLanguage, prettySlug } from "helpers/formatters";
import { getOgImage, ImageQuality, OgImage } from "helpers/img"; import { getOgImage, ImageQuality, OgImage } from "helpers/img";
// import { getClient, Indexes, search, SearchResult } from "helpers/search"; // import { getClient, Indexes, search, SearchResult } from "helpers/search";
@ -181,19 +182,23 @@ export function AppLayout(props: Immutable<Props>): JSX.Element {
return ( return (
<div <div
className={`${ className={cJoin(
appLayout.darkMode ? "set-theme-dark" : "set-theme-light" cIf(appLayout.darkMode, "set-theme-dark", "set-theme-light"),
} ${ cIf(
appLayout.dyslexic appLayout.dyslexic,
? "set-theme-font-dyslexic" "set-theme-font-dyslexic",
: "set-theme-font-standard" "set-theme-font-standard"
}`} )
)}
> >
<div <div
{...handlers} {...handlers}
className={`fixed inset-0 m-0 grid touch-pan-y bg-light p-0 text-black className={cJoin(
[grid-template-areas:'main_sub_content'] ${gridCol} mobile:grid-cols-[1fr] `fixed inset-0 m-0 grid touch-pan-y bg-light p-0 text-black
mobile:grid-rows-[1fr_5rem] mobile:[grid-template-areas:'content''navbar']`} [grid-template-areas:'main_sub_content'] mobile:grid-cols-[1fr]
mobile:grid-rows-[1fr_5rem] mobile:[grid-template-areas:'content''navbar']`,
gridCol
)}
> >
<Head> <Head>
<title>{metaTitle}</title> <title>{metaTitle}</title>
@ -222,21 +227,25 @@ export function AppLayout(props: Immutable<Props>): JSX.Element {
{/* Background when navbar is opened */} {/* Background when navbar is opened */}
<div <div
className={`absolute inset-0 transition-[backdrop-filter] className={cJoin(
duration-500 [grid-area:content] mobile:z-10 ${ `absolute inset-0 transition-[backdrop-filter] duration-500 [grid-area:content]
(appLayout.mainPanelOpen || appLayout.subPanelOpen) && isMobile mobile:z-10`,
? "[backdrop-filter:blur(2px)]" cIf(
: "pointer-events-none touch-none " (appLayout.mainPanelOpen || appLayout.subPanelOpen) && isMobile,
}`} "[backdrop-filter:blur(2px)]",
"pointer-events-none touch-none"
)
)}
> >
<div <div
className={`absolute inset-0 bg-shade transition-opacity duration-500 className={cJoin(
${turnSubIntoContent ? "" : ""} "absolute inset-0 bg-shade transition-opacity duration-500",
${ cIf(
(appLayout.mainPanelOpen || appLayout.subPanelOpen) && isMobile (appLayout.mainPanelOpen || appLayout.subPanelOpen) && isMobile,
? "opacity-60" "opacity-60",
: "opacity-0" "opacity-0"
}`} )
)}
onClick={() => { onClick={() => {
appLayout.setMainPanelOpen(false); appLayout.setMainPanelOpen(false);
appLayout.setSubPanelOpen(false); appLayout.setSubPanelOpen(false);
@ -255,7 +264,7 @@ export function AppLayout(props: Immutable<Props>): JSX.Element {
<div className="grid h-full place-content-center"> <div className="grid h-full place-content-center">
<div <div
className="grid grid-flow-col place-items-center gap-9 rounded-2xl className="grid grid-flow-col place-items-center gap-9 rounded-2xl
border-2 border-dotted border-dark p-8 text-dark opacity-40" border-2 border-dotted border-dark p-8 text-dark opacity-40"
> >
<p className="text-4xl"></p> <p className="text-4xl"></p>
<p className="w-64 text-2xl">{langui.select_option_sidebar}</p> <p className="w-64 text-2xl">{langui.select_option_sidebar}</p>
@ -267,16 +276,18 @@ export function AppLayout(props: Immutable<Props>): JSX.Element {
{/* Sub panel */} {/* Sub panel */}
{subPanel && ( {subPanel && (
<div <div
className={`texture-paper-dots overflow-y-scroll border-r-[1px] border-dotted className={cJoin(
border-black bg-light transition-transform duration-300 [grid-area:sub] `texture-paper-dots overflow-y-scroll border-r-[1px] border-dotted
[scrollbar-width:none] webkit-scrollbar:w-0 mobile:z-10 mobile:w-[90%] border-black bg-light transition-transform duration-300 [grid-area:sub]
mobile:justify-self-end mobile:border-r-0 mobile:border-l-[1px] [scrollbar-width:none] webkit-scrollbar:w-0 mobile:z-10 mobile:w-[90%]
mobile:[grid-area:content] mobile:justify-self-end mobile:border-r-0 mobile:border-l-[1px]
${ mobile:[grid-area:content]`,
turnSubIntoContent turnSubIntoContent
? "mobile:w-full mobile:border-l-0" ? "mobile:w-full mobile:border-l-0"
: !appLayout.subPanelOpen && "mobile:translate-x-[100vw]" : appLayout.subPanelOpen
}`} ? ""
: "mobile:translate-x-[100vw]"
)}
> >
{subPanel} {subPanel}
</div> </div>
@ -284,12 +295,13 @@ export function AppLayout(props: Immutable<Props>): JSX.Element {
{/* Main panel */} {/* Main panel */}
<div <div
className={`texture-paper-dots overflow-y-scroll border-r-[1px] border-dotted className={cJoin(
border-black bg-light transition-transform duration-300 [grid-area:main] `texture-paper-dots overflow-y-scroll border-r-[1px] border-dotted
[scrollbar-width:none] webkit-scrollbar:w-0 mobile:z-10 mobile:w-[90%] border-black bg-light transition-transform duration-300 [grid-area:main]
mobile:justify-self-start mobile:[grid-area:content] ${ [scrollbar-width:none] webkit-scrollbar:w-0 mobile:z-10 mobile:w-[90%]
appLayout.mainPanelOpen ? "" : "mobile:-translate-x-full" mobile:justify-self-start mobile:[grid-area:content]`,
}`} cIf(!appLayout.mainPanelOpen, "mobile:-translate-x-full")
)}
> >
<MainPanel langui={langui} /> <MainPanel langui={langui} />
</div> </div>
@ -301,25 +313,28 @@ export function AppLayout(props: Immutable<Props>): JSX.Element {
> >
<Ico <Ico
icon={appLayout.mainPanelOpen ? Icon.Close : Icon.Menu} icon={appLayout.mainPanelOpen ? Icon.Close : Icon.Menu}
className="mt-[.1em] cursor-pointer" className="mt-[.1em] cursor-pointer !text-2xl"
onClick={() => { onClick={() => {
appLayout.setMainPanelOpen(!appLayout.mainPanelOpen); appLayout.setMainPanelOpen(!appLayout.mainPanelOpen);
appLayout.setSubPanelOpen(false); appLayout.setSubPanelOpen(false);
}} }}
/> />
<p <p
className={`overflow-hidden text-center font-headers font-black ${ className={cJoin(
ogTitle && ogTitle.length > 30 "overflow-hidden text-center font-headers font-black",
? "max-h-14 text-xl" cIf(
: "max-h-16 text-2xl" ogTitle && ogTitle.length > 30,
}`} "max-h-14 text-xl",
"max-h-16 text-2xl"
)
)}
> >
{ogTitle} {ogTitle}
</p> </p>
{subPanel && !turnSubIntoContent && ( {subPanel && !turnSubIntoContent && (
<Ico <Ico
icon={appLayout.subPanelOpen ? Icon.Close : subPanelIcon} icon={appLayout.subPanelOpen ? Icon.Close : subPanelIcon}
className="mt-[.1em] cursor-pointer" className="mt-[.1em] cursor-pointer !text-2xl"
onClick={() => { onClick={() => {
appLayout.setSubPanelOpen(!appLayout.subPanelOpen); appLayout.setSubPanelOpen(!appLayout.subPanelOpen);
appLayout.setMainPanelOpen(false); appLayout.setMainPanelOpen(false);

View File

@ -1,3 +1,4 @@
import { cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
interface Props { interface Props {
@ -8,9 +9,12 @@ interface Props {
export function Chip(props: Immutable<Props>): JSX.Element { export function Chip(props: Immutable<Props>): JSX.Element {
return ( return (
<div <div
className={`grid place-content-center place-items-center whitespace-nowrap rounded-full className={cJoin(
border-[1px] px-1.5 pb-[0.14rem] text-xs opacity-70 `grid place-content-center place-items-center whitespace-nowrap rounded-full
transition-[color,_opacity,_border-color] hover:opacity-100 ${props.className}`} border-[1px] px-1.5 pb-[0.14rem] text-xs opacity-70
transition-[color,_opacity,_border-color] hover:opacity-100`,
props.className
)}
> >
{props.children} {props.children}
</div> </div>

View File

@ -1,3 +1,4 @@
import { cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
interface Props { interface Props {
@ -5,9 +6,13 @@ interface Props {
} }
export function HorizontalLine(props: Immutable<Props>): JSX.Element { export function HorizontalLine(props: Immutable<Props>): JSX.Element {
const { className } = props;
return ( return (
<div <div
className={`my-8 h-0 w-full border-t-[3px] border-dotted border-black ${props.className}`} className={cJoin(
"my-8 h-0 w-full border-t-[3px] border-dotted border-black",
className
)}
></div> ></div>
); );
} }

View File

@ -1,3 +1,4 @@
import { cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
import { MouseEventHandler } from "react"; import { MouseEventHandler } from "react";
@ -10,7 +11,13 @@ interface Props {
export function Ico(props: Immutable<Props>): JSX.Element { export function Ico(props: Immutable<Props>): JSX.Element {
const { onClick, icon, className } = props; const { onClick, icon, className } = props;
return ( return (
<span onClick={onClick} className={`material-icons ${className}`}> <span
onClick={onClick}
className={cJoin(
"material-icons [font-size:inherit] [line-height:inherit]",
className
)}
>
{icon} {icon}
</span> </span>
); );

View File

@ -1,4 +1,5 @@
import { Ico, Icon } from "components/Ico"; import { Ico, Icon } from "components/Ico";
import { cIf, cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { MouseEventHandler } from "react"; import { MouseEventHandler } from "react";
@ -38,14 +39,18 @@ export function Button(props: Immutable<Props>): JSX.Element {
draggable={draggable} draggable={draggable}
id={id} id={id}
onClick={onClick} onClick={onClick}
className={`component-button group grid select-none grid-flow-col place-content-center className={cJoin(
place-items-center gap-2 rounded-full border-[1px] border-dark px-4 pt-[0.4rem] pb-[0.5rem] `component-button group grid select-none grid-flow-col place-content-center
text-dark transition-all ${ place-items-center gap-2 rounded-full border-[1px] border-dark py-3 px-4 leading-none
active text-dark transition-all`,
? "!border-black bg-black text-light drop-shadow-black-lg" cIf(
: `cursor-pointer hover:bg-dark hover:text-light hover:drop-shadow-shade-lg active,
"!border-black bg-black text-light drop-shadow-black-lg",
`cursor-pointer hover:bg-dark hover:text-light hover:drop-shadow-shade-lg
active:border-black active:bg-black active:text-light active:drop-shadow-black-lg` active:border-black active:bg-black active:text-light active:drop-shadow-black-lg`
} ${className}`} ),
className
)}
> >
{badgeNumber && ( {badgeNumber && (
<div <div
@ -55,7 +60,9 @@ export function Button(props: Immutable<Props>): JSX.Element {
<p className="-translate-y-[0.05em]">{badgeNumber}</p> <p className="-translate-y-[0.05em]">{badgeNumber}</p>
</div> </div>
)} )}
{icon && <Ico className="translate-y-[0.04em] !text-base" icon={icon} />} {icon && (
<Ico className="[font-size:150%] [line-height:0.66]" icon={icon} />
)}
{text && <p className="-translate-y-[0.05em] text-center">{text}</p>} {text && <p className="-translate-y-[0.05em] text-center">{text}</p>}
</div> </div>
); );

View File

@ -1,3 +1,4 @@
import { cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
import { useEffect, useRef } from "react"; import { useEffect, useRef } from "react";
@ -31,7 +32,7 @@ export function ButtonGroup(props: Immutable<Props>): JSX.Element {
}, [children]); }, [children]);
return ( return (
<div ref={ref} className={`grid grid-flow-col ${className}`}> <div ref={ref} className={cJoin("grid grid-flow-col", className)}>
{children} {children}
</div> </div>
); );

View File

@ -1,5 +1,6 @@
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { AppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps } from "graphql/getAppStaticProps";
import { cJoin } from "helpers/className";
import { prettyLanguage } from "helpers/formatters"; import { prettyLanguage } from "helpers/formatters";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
import { Dispatch, Fragment, SetStateAction } from "react"; import { Dispatch, Fragment, SetStateAction } from "react";
@ -20,7 +21,7 @@ export function LanguageSwitcher(props: Immutable<Props>): JSX.Element {
return ( return (
<ToolTip <ToolTip
content={ content={
<div className={`flex flex-col gap-2 ${className}`}> <div className={cJoin("flex flex-col gap-2", className)}>
{[...locales].map(([locale, value], index) => ( {[...locales].map(([locale, value], index) => (
<Fragment key={index}> <Fragment key={index}>
{locale && ( {locale && (

View File

@ -1,4 +1,5 @@
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
import { Dispatch, SetStateAction } from "react"; import { Dispatch, SetStateAction } from "react";
import { Button } from "./Button"; import { Button } from "./Button";
@ -11,10 +12,10 @@ interface Props {
} }
export function PageSelector(props: Immutable<Props>): JSX.Element { export function PageSelector(props: Immutable<Props>): JSX.Element {
const { page, setPage, maxPage } = props; const { page, setPage, maxPage, className } = props;
return ( return (
<div className={`flex flex-row place-content-center ${props.className}`}> <div className={cJoin("flex flex-row place-content-center", className)}>
<Button <Button
onClick={() => { onClick={() => {
if (page > 0) setPage(page - 1); if (page > 0) setPage(page - 1);

View File

@ -1,4 +1,5 @@
import { Ico, Icon } from "components/Ico"; import { Ico, Icon } from "components/Ico";
import { cIf, cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
import { Dispatch, Fragment, SetStateAction, useState } from "react"; import { Dispatch, Fragment, SetStateAction, useState } from "react";
@ -17,16 +18,19 @@ export function Select(props: Immutable<Props>): JSX.Element {
return ( return (
<div <div
className={`relative text-center transition-[filter] ${ className={cJoin(
opened && "z-10 drop-shadow-shade-lg" "relative text-center transition-[filter]",
} ${className}`} cIf(opened, "z-10 drop-shadow-shade-lg"),
className
)}
> >
<div <div
className={`grid cursor-pointer grid-flow-col grid-cols-[1fr_auto_auto] place-items-center className={cJoin(
rounded-[1em] bg-light p-1 outline outline-2 outline-offset-[-2px] outline-mid `grid cursor-pointer grid-flow-col grid-cols-[1fr_auto_auto] place-items-center
transition-all hover:bg-mid hover:outline-[transparent] ${ rounded-[1em] bg-light p-1 outline outline-2 outline-offset-[-2px] outline-mid
opened && "rounded-b-none bg-highlight outline-[transparent]" transition-all hover:bg-mid hover:outline-[transparent]`,
}`} cIf(opened, "rounded-b-none bg-highlight outline-[transparent]")
)}
> >
<p onClick={() => setOpened(!opened)} className="w-full"> <p onClick={() => setOpened(!opened)} className="w-full">
{state === -1 ? "—" : options[state]} {state === -1 ? "—" : options[state]}
@ -44,18 +48,19 @@ export function Select(props: Immutable<Props>): JSX.Element {
/> />
</div> </div>
<div <div
className={`left-0 right-0 rounded-b-[1em] ${ className={cJoin(
opened ? "absolute" : "hidden" "left-0 right-0 rounded-b-[1em]",
}`} cIf(opened, "absolute", "hidden")
)}
> >
{options.map((option, index) => ( {options.map((option, index) => (
<Fragment key={index}> <Fragment key={index}>
{index !== state && ( {index !== state && (
<div <div
className={` ${ className={cJoin(
opened ? "bg-highlight" : "bg-light" "cursor-pointer p-1 transition-colors last-of-type:rounded-b-[1em] hover:bg-mid",
} cursor-pointer p-1 cIf(opened, "bg-highlight", "bg-light")
transition-colors last-of-type:rounded-b-[1em] hover:bg-mid`} )}
id={option} id={option}
onClick={() => { onClick={() => {
setOpened(false); setOpened(false);

View File

@ -1,3 +1,4 @@
import { cIf, cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
import { Dispatch, SetStateAction } from "react"; import { Dispatch, SetStateAction } from "react";
@ -12,23 +13,29 @@ export function Switch(props: Immutable<Props>): JSX.Element {
const { state, setState, className, disabled } = props; const { state, setState, className, disabled } = props;
return ( return (
<div <div
className={`relative grid h-6 w-12 rounded-full border-2 className={cJoin(
border-mid transition-colors ${ "relative grid h-6 w-12 rounded-full border-2 border-mid transition-colors",
disabled ? "cursor-not-allowed" : "cursor-pointer" cIf(disabled, "cursor-not-allowed", "cursor-pointer"),
} ${className} ${ cIf(
state ? "border-none bg-mid shadow-inner-sm shadow-shade" : "bg-light" state,
}`} "border-none bg-mid shadow-inner-sm shadow-shade",
"bg-light"
),
className
)}
onClick={() => { onClick={() => {
if (!disabled) setState(!state); if (!disabled) setState(!state);
}} }}
> >
<div <div
className={`absolute ${ className={cJoin(
state ? "top-[2px] bottom-[2px] left-[2px]" : "top-0 bottom-0 left-0" "absolute aspect-square rounded-full bg-dark transition-transform",
} cIf(
aspect-square rounded-full bg-dark transition-transform ${ state,
state && "translate-x-[120%]" "top-[2px] bottom-[2px] left-[2px] translate-x-[120%]",
}`} "top-0 bottom-0 left-0"
)
)}
></div> ></div>
</div> </div>
); );

View File

@ -1,4 +1,5 @@
import { Ico, Icon } from "components/Ico"; import { Ico, Icon } from "components/Ico";
import { cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
import { Dispatch, SetStateAction } from "react"; import { Dispatch, SetStateAction } from "react";
@ -16,7 +17,7 @@ export function TextInput(props: Immutable<Props>): JSX.Element {
const { state, setState, className, name, placeholder } = props; const { state, setState, className, name, placeholder } = props;
return ( return (
<div className={`relative ${className}`}> <div className={cJoin("relative", className)}>
<input <input
className="w-full" className="w-full"
type="text" type="text"

View File

@ -1,3 +1,4 @@
import { cIf, cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
interface Props { interface Props {
@ -10,12 +11,18 @@ export function WithLabel(props: Immutable<Props>): JSX.Element {
const { label, input, disabled } = props; const { label, input, disabled } = props;
return ( return (
<div <div
className={`flex flex-row place-content-between place-items-center gap-2 ${ className={cJoin(
disabled ? "text-dark brightness-150 contrast-75 grayscale" : "" "flex flex-row place-content-between place-items-center gap-2",
}`} cIf(disabled, "text-dark brightness-150 contrast-75 grayscale")
)}
> >
{label && ( {label && (
<p className={`text-left ${label.length < 10 ? "flex-shrink-0" : ""}`}> <p
className={cJoin(
"text-left",
cIf(label.length < 10, "flex-shrink-0")
)}
>
{label}: {label}:
</p> </p>
)} )}

View File

@ -1,3 +1,4 @@
import { cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
interface Props { interface Props {
@ -10,7 +11,10 @@ export function InsetBox(props: Immutable<Props>): JSX.Element {
return ( return (
<div <div
id={props.id} id={props.id}
className={`w-full rounded-xl bg-mid p-8 shadow-inner-sm shadow-shade ${props.className}`} className={cJoin(
"w-full rounded-xl bg-mid p-8 shadow-inner-sm shadow-shade",
props.className
)}
> >
{props.children} {props.children}
</div> </div>

View File

@ -4,6 +4,7 @@ import { Img } from "components/Img";
import { InsetBox } from "components/InsetBox"; import { InsetBox } from "components/InsetBox";
import { ToolTip } from "components/ToolTip"; import { ToolTip } from "components/ToolTip";
import { useAppLayout } from "contexts/AppLayoutContext"; import { useAppLayout } from "contexts/AppLayoutContext";
import { cJoin } from "helpers/className";
import { slugify } from "helpers/formatters"; import { slugify } from "helpers/formatters";
import { getAssetURL, ImageQuality } from "helpers/img"; import { getAssetURL, ImageQuality } from "helpers/img";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
@ -32,7 +33,7 @@ export function Markdawn(props: Immutable<Props>): JSX.Element {
<> <>
<LightBox /> <LightBox />
<Markdown <Markdown
className={`formatted ${props.className}`} className={cJoin("formatted", props.className)}
options={{ options={{
slugify: slugify, slugify: slugify,
overrides: { overrides: {

View File

@ -19,7 +19,7 @@ export function TOC(props: Immutable<Props>): JSX.Element {
<h3 className="text-xl">Table of content</h3> <h3 className="text-xl">Table of content</h3>
<div className="max-w-[14.5rem] text-left"> <div className="max-w-[14.5rem] text-left">
<p className="relative my-2 overflow-x-hidden text-ellipsis whitespace-nowrap text-left"> <p className="relative my-2 overflow-x-hidden text-ellipsis whitespace-nowrap text-left">
<a className="" onClick={async () => router.replace(`#${toc.slug}`)}> <a onClick={async () => router.replace(`#${toc.slug}`)}>
{<abbr title={toc.title}>{toc.title}</abbr>} {<abbr title={toc.title}>{toc.title}</abbr>}
</a> </a>
</p> </p>

View File

@ -1,5 +1,6 @@
import { Ico, Icon } from "components/Ico"; import { Ico, Icon } from "components/Ico";
import { ToolTip } from "components/ToolTip"; import { ToolTip } from "components/ToolTip";
import { cJoin, cIf } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
import { MouseEventHandler } from "react"; import { MouseEventHandler } from "react";
@ -17,16 +18,6 @@ interface Props {
export function NavOption(props: Immutable<Props>): JSX.Element { export function NavOption(props: Immutable<Props>): JSX.Element {
const router = useRouter(); const router = useRouter();
const isActive = router.asPath.startsWith(props.url); const isActive = router.asPath.startsWith(props.url);
const divActive = "bg-mid shadow-inner-sm shadow-shade";
const border =
"outline outline-mid outline-2 outline-offset-[-2px] hover:outline-[transparent]";
const divCommon = `gap-x-5 w-full rounded-2xl cursor-pointer p-4 hover:bg-mid
hover:shadow-inner-sm hover:shadow-shade hover:active:shadow-inner
hover:active:shadow-shade transition-all ${props.border ? border : ""} ${
isActive ? divActive : ""
}`;
return ( return (
<ToolTip <ToolTip
@ -51,11 +42,21 @@ export function NavOption(props: Immutable<Props>): JSX.Element {
} }
} }
}} }}
className={`relative grid auto-cols-fr grid-flow-col grid-cols-[auto] justify-center ${ className={cJoin(
props.icon ? "text-left" : "text-center" `relative grid w-full cursor-pointer auto-cols-fr grid-flow-col grid-cols-[auto]
} ${divCommon}`} justify-center gap-x-5 rounded-2xl p-4 transition-all hover:bg-mid hover:shadow-inner-sm
hover:shadow-shade hover:active:shadow-inner hover:active:shadow-shade`,
cIf(props.icon, "text-left", "text-center"),
cIf(
props.border,
"outline outline-2 outline-offset-[-2px] outline-mid hover:outline-[transparent]"
),
cIf(isActive, "bg-mid shadow-inner-sm shadow-shade")
)}
> >
{props.icon && <Ico icon={props.icon} className="mt-[.1em]" />} {props.icon && (
<Ico icon={props.icon} className="mt-[-.1em] !text-2xl" />
)}
{!props.reduced && ( {!props.reduced && (
<div> <div>

View File

@ -3,6 +3,7 @@ import { Icon } from "components/Ico";
import { Button } from "components/Inputs/Button"; import { Button } from "components/Inputs/Button";
import { useAppLayout } from "contexts/AppLayoutContext"; import { useAppLayout } from "contexts/AppLayoutContext";
import { AppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps } from "graphql/getAppStaticProps";
import { cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
interface Props { interface Props {
@ -25,13 +26,14 @@ export function ReturnButton(props: Immutable<Props>): JSX.Element {
return ( return (
<div <div
className={`${ className={cJoin(
props.displayOn === ReturnButtonType.Mobile props.displayOn === ReturnButtonType.Mobile
? "desktop:hidden" ? "desktop:hidden"
: props.displayOn === ReturnButtonType.Desktop : props.displayOn === ReturnButtonType.Desktop
? "mobile:hidden" ? "mobile:hidden"
: "" : "",
} ${props.className}`} props.className
)}
> >
<Button <Button
onClick={() => appLayout.setSubPanelOpen(false)} onClick={() => appLayout.setSubPanelOpen(false)}

View File

@ -1,29 +1,33 @@
import { cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
interface Props { interface Props {
children: React.ReactNode; children: React.ReactNode;
autoformat?: boolean;
width?: ContentPanelWidthSizes; width?: ContentPanelWidthSizes;
} }
export enum ContentPanelWidthSizes { export enum ContentPanelWidthSizes {
Default = "default", Default = "default",
Large = "large", Large = "large",
Full = "full",
} }
export function ContentPanel(props: Immutable<Props>): JSX.Element { export function ContentPanel(props: Immutable<Props>): JSX.Element {
const width = props.width ? props.width : ContentPanelWidthSizes.Default; const { width = ContentPanelWidthSizes.Default, children } = props;
const widthCSS =
width === ContentPanelWidthSizes.Default ? "max-w-2xl" : "w-full";
return ( return (
<div className={`grid px-4 pt-10 pb-20 desktop:py-20 desktop:px-10`}> <div className={`grid px-4 pt-10 pb-20 desktop:py-20 desktop:px-10`}>
<main <main
className={`${ className={cJoin(
props.autoformat && "formatted" "place-self-center",
} ${widthCSS} place-self-center`} width === ContentPanelWidthSizes.Default
? "max-w-2xl"
: width === ContentPanelWidthSizes.Large
? "max-w-4xl"
: "w-full"
)}
> >
{props.children} {children}
</main> </main>
</div> </div>
); );

View File

@ -9,6 +9,7 @@ import { useMediaDesktop } from "hooks/useMediaQuery";
import Markdown from "markdown-to-jsx"; import Markdown from "markdown-to-jsx";
import Link from "next/link"; import Link from "next/link";
import { Icon } from "components/Ico"; import { Icon } from "components/Ico";
import { cIf, cJoin } from "helpers/className";
interface Props { interface Props {
langui: AppStaticProps["langui"]; langui: AppStaticProps["langui"];
@ -21,15 +22,17 @@ export function MainPanel(props: Immutable<Props>): JSX.Element {
return ( return (
<div <div
className={`grid content-start justify-center gap-y-2 p-8 text-center ${ className={cJoin(
appLayout.mainPanelReduced && isDesktop && "px-4" "grid content-start justify-center gap-y-2 p-8 text-center",
}`} cIf(appLayout.mainPanelReduced && isDesktop, "px-4")
)}
> >
{/* Reduce/expand main menu */} {/* Reduce/expand main menu */}
<div <div
className={`fixed top-1/2 mobile:hidden ${ className={cJoin(
appLayout.mainPanelReduced ? "left-[4.65rem]" : "left-[18.65rem]" "fixed top-1/2 mobile:hidden",
}`} cIf(appLayout.mainPanelReduced, "left-[4.65rem]", "left-[18.65rem]")
)}
onClick={() => onClick={() =>
appLayout.setMainPanelReduced(!appLayout.mainPanelReduced) appLayout.setMainPanelReduced(!appLayout.mainPanelReduced)
} }
@ -46,26 +49,28 @@ export function MainPanel(props: Immutable<Props>): JSX.Element {
<div className="grid place-items-center"> <div className="grid place-items-center">
<Link href="/" passHref> <Link href="/" passHref>
<div <div
className={`${ className={cJoin(
appLayout.mainPanelReduced && isDesktop ? "w-12" : "w-1/2" `mb-4 aspect-square cursor-pointer bg-black transition-colors
} mb-4 aspect-square cursor-pointer bg-black [mask:url('/icons/accords.svg')] ![mask-size:contain] ![mask-repeat:no-repeat]
transition-colors [mask:url('/icons/accords.svg')] ![mask-position:center] hover:bg-dark`,
![mask-size:contain] ![mask-repeat:no-repeat] ![mask-position:center] hover:bg-dark`} cIf(appLayout.mainPanelReduced && isDesktop, "w-12", "w-1/2")
)}
></div> ></div>
</Link> </Link>
{appLayout.mainPanelReduced && isDesktop ? ( {(!appLayout.mainPanelReduced || !isDesktop) && (
""
) : (
<h2 className="text-3xl">Accord&rsquo;s Library</h2> <h2 className="text-3xl">Accord&rsquo;s Library</h2>
)} )}
<div <div
className={`flex ${ className={cJoin(
appLayout.mainPanelReduced && isDesktop "flex flex-wrap gap-2",
? "flex-col gap-3" cIf(
: "flex-row" appLayout.mainPanelReduced && isDesktop,
} flex-wrap gap-2`} "flex-col gap-3",
"flex-row"
)
)}
> >
<ToolTip <ToolTip
content={<h3 className="text-2xl">{langui.open_settings}</h3>} content={<h3 className="text-2xl">{langui.open_settings}</h3>}
@ -176,9 +181,10 @@ export function MainPanel(props: Immutable<Props>): JSX.Element {
{appLayout.mainPanelReduced && isDesktop ? "" : <HorizontalLine />} {appLayout.mainPanelReduced && isDesktop ? "" : <HorizontalLine />}
<div <div
className={`text-center ${ className={cJoin(
appLayout.mainPanelReduced && isDesktop ? "hidden" : "" "text-center",
}`} cIf(appLayout.mainPanelReduced && isDesktop, "hidden")
)}
> >
<p> <p>
{langui.licensing_notice && ( {langui.licensing_notice && (

View File

@ -1,4 +1,5 @@
import { useAppLayout } from "contexts/AppLayoutContext"; import { useAppLayout } from "contexts/AppLayoutContext";
import { cIf, cJoin } from "helpers/className";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
import { Dispatch, SetStateAction, useEffect } from "react"; import { Dispatch, SetStateAction, useEffect } from "react";
import Hotkeys from "react-hot-keys"; import Hotkeys from "react-hot-keys";
@ -40,32 +41,37 @@ export function Popup(props: Immutable<Props>): JSX.Element {
}} }}
> >
<div <div
className={`fixed inset-0 z-50 grid place-content-center className={cJoin(
transition-[backdrop-filter] duration-500 ${ "fixed inset-0 z-50 grid place-content-center transition-[backdrop-filter] duration-500",
state ? "[backdrop-filter:blur(2px)]" : "pointer-events-none touch-none" cIf(
}`} state,
"[backdrop-filter:blur(2px)]",
"pointer-events-none touch-none"
)
)}
> >
<div <div
className={`fixed inset-0 bg-shade transition-all duration-500 ${ className={cJoin(
state ? "bg-opacity-50" : "bg-opacity-0" "fixed inset-0 bg-shade transition-all duration-500",
}`} cIf(state, "bg-opacity-50", "bg-opacity-0")
)}
onClick={() => { onClick={() => {
setState(false); setState(false);
}} }}
/> />
<div <div
className={`${ className={cJoin(
padding && "p-10 mobile:p-6" "grid place-items-center gap-4 transition-transform",
} grid place-items-center gap-4 transition-transform ${ cIf(padding, "p-10 mobile:p-6"),
state ? "scale-100" : "scale-0" cIf(state, "scale-100", "scale-0"),
} ${ cIf(
fillViewport fillViewport,
? "absolute inset-10" "absolute inset-10",
: "relative max-h-[80vh] overflow-y-auto mobile:w-[85vw]" "relative max-h-[80vh] overflow-y-auto mobile:w-[85vw]"
} ${ ),
hideBackground ? "" : "rounded-lg bg-light shadow-2xl shadow-shade" cIf(!hideBackground, "rounded-lg bg-light shadow-2xl shadow-shade")
}`} )}
> >
{children} {children}
</div> </div>

View File

@ -5,6 +5,7 @@ import {
UploadImageFragment, UploadImageFragment,
} from "graphql/generated"; } from "graphql/generated";
import { AppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps } from "graphql/getAppStaticProps";
import { cIf, cJoin } from "helpers/className";
import { import {
prettyDate, prettyDate,
prettyDuration, prettyDuration,
@ -130,14 +131,15 @@ export function PreviewCard(props: Immutable<Props>): JSX.Element {
{stackNumber > 0 && ( {stackNumber > 0 && (
<> <>
<div <div
className={`absolute inset-0 scale-[.85] overflow-hidden bg-light brightness-[0.8] className={cJoin(
sepia-[0.5] transition-[top_transform] group-hover:-top-8 ${ `absolute inset-0 scale-[.85] overflow-hidden bg-light brightness-[0.8] sepia-[0.5]
thumbnailRounded && "rounded-md" transition-[top_transform] group-hover:-top-8`,
}`} cIf(thumbnailRounded, "rounded-md")
)}
> >
{thumbnail && ( {thumbnail && (
<Img <Img
className="opacity-30 " className="opacity-30"
image={thumbnail} image={thumbnail}
quality={ImageQuality.Medium} quality={ImageQuality.Medium}
/> />
@ -145,10 +147,11 @@ export function PreviewCard(props: Immutable<Props>): JSX.Element {
</div> </div>
<div <div
className={`absolute inset-0 overflow-hidden bg-light brightness-[0.9] sepia-[0.2] className={cJoin(
transition-[top_transform] group-hover:-top-4 group-hover:scale-[.94] ${ `absolute inset-0 overflow-hidden bg-light brightness-[0.9] sepia-[0.2]
thumbnailRounded && "rounded-md" transition-[top_transform] group-hover:-top-4 group-hover:scale-[.94]`,
}`} cIf(thumbnailRounded, "rounded-md")
)}
> >
{thumbnail && ( {thumbnail && (
<Img <Img
@ -171,19 +174,24 @@ export function PreviewCard(props: Immutable<Props>): JSX.Element {
}} }}
> >
<Img <Img
className={`${ className={cJoin(
thumbnailRounded && cIf(
(keepInfoVisible thumbnailRounded,
? "rounded-t-md" cIf(
: "rounded-md notHoverable:rounded-b-none") keepInfoVisible,
} ${thumbnailForceAspectRatio && "h-full w-full object-cover"}`} "rounded-t-md",
"rounded-md notHoverable:rounded-b-none"
)
),
cIf(thumbnailForceAspectRatio, "h-full w-full object-cover")
)}
image={thumbnail} image={thumbnail}
quality={ImageQuality.Medium} quality={ImageQuality.Medium}
/> />
{stackNumber > 0 && ( {stackNumber > 0 && (
<div <div
className="absolute right-2 top-2 rounded-full bg-black className="absolute right-2 top-2 rounded-full bg-black
bg-opacity-60 px-2 text-light" bg-opacity-60 px-2 text-light"
> >
{stackNumber} {stackNumber}
</div> </div>
@ -200,8 +208,8 @@ export function PreviewCard(props: Immutable<Props>): JSX.Element {
/> />
</div> </div>
<div <div
className="absolute right-2 bottom-2 rounded-full bg-black className="absolute right-2 bottom-2 rounded-full bg-black bg-opacity-60 px-2
bg-opacity-60 px-2 text-light" text-light"
> >
{prettyDuration(hoverlay.duration)} {prettyDuration(hoverlay.duration)}
</div> </div>
@ -211,11 +219,14 @@ export function PreviewCard(props: Immutable<Props>): JSX.Element {
) : ( ) : (
<div <div
style={{ aspectRatio: thumbnailAspectRatio }} style={{ aspectRatio: thumbnailAspectRatio }}
className={`relative w-full bg-light ${ className={cJoin(
keepInfoVisible "relative w-full bg-light",
? "rounded-t-md" cIf(
: "rounded-md notHoverable:rounded-b-none" keepInfoVisible,
}`} "rounded-t-md",
"rounded-md notHoverable:rounded-b-none"
)
)}
> >
{stackNumber > 0 && ( {stackNumber > 0 && (
<div <div
@ -228,11 +239,14 @@ export function PreviewCard(props: Immutable<Props>): JSX.Element {
</div> </div>
)} )}
<div <div
className={`z-20 grid gap-2 p-4 transition-opacity linearbg-obi ${ className={cJoin(
!keepInfoVisible && "z-20 grid gap-2 p-4 transition-opacity linearbg-obi",
`-inset-x-0.5 bottom-2 opacity-0 group-hover:opacity-100 hoverable:absolute cIf(
hoverable:drop-shadow-shade-lg notHoverable:rounded-b-md` !keepInfoVisible,
}`} `-inset-x-0.5 bottom-2 opacity-0 group-hover:opacity-100 hoverable:absolute
hoverable:drop-shadow-shade-lg notHoverable:rounded-b-md`
)
)}
> >
{metadata?.position === "Top" && metadataJSX} {metadata?.position === "Top" && metadataJSX}
{topChips && topChips.length > 0 && ( {topChips && topChips.length > 0 && (

View File

@ -34,9 +34,8 @@ export function PreviewLine(props: Immutable<Props>): JSX.Element {
return ( return (
<Link href={href} passHref> <Link href={href} passHref>
<div <div
className="flex h-36 w-full cursor-pointer className="flex h-36 w-full cursor-pointer flex-row place-items-center gap-4 overflow-hidden
flex-row place-items-center gap-4 overflow-hidden rounded-md rounded-md bg-light pr-4 transition-transform drop-shadow-shade-xl hover:scale-[1.02]"
bg-light pr-4 transition-transform drop-shadow-shade-xl hover:scale-[1.02]"
> >
{thumbnail ? ( {thumbnail ? (
<div className="aspect-[3/2] h-full"> <div className="aspect-[3/2] h-full">

View File

@ -1,22 +0,0 @@
import { Immutable } from "helpers/types";
import Image from "next/image";
interface Props {
src: string;
alt: string;
className?: string;
}
export function SVG(props: Immutable<Props>): JSX.Element {
return (
<div className={props.className}>
<Image
src={props.src}
alt={props.src}
height={1000}
width={1000}
unoptimized
/>
</div>
);
}

View File

@ -1,10 +1,12 @@
import Tippy, { TippyProps } from "@tippyjs/react"; import Tippy, { TippyProps } from "@tippyjs/react";
import { cJoin } from "helpers/className";
import "tippy.js/animations/scale-subtle.css"; import "tippy.js/animations/scale-subtle.css";
interface Props extends TippyProps {} interface Props extends TippyProps {}
export function ToolTip(props: Props): JSX.Element { export function ToolTip(props: Props): JSX.Element {
const newProps: Props = { const newProps: Props = {
className: cJoin("text-[80%]", props.className),
delay: [150, 0], delay: [150, 0],
interactive: true, interactive: true,
animation: "scale-subtle", animation: "scale-subtle",
@ -12,7 +14,7 @@ export function ToolTip(props: Props): JSX.Element {
}; };
return ( return (
<Tippy className={`text-[80%] ${newProps.className}`} {...newProps}> <Tippy {...newProps}>
<div>{props.children}</div> <div>{props.children}</div>
</Tippy> </Tippy>
); );

View File

@ -0,0 +1,50 @@
import { Chip } from "components/Chip";
import { ToolTip } from "components/ToolTip";
import { AppStaticProps } from "graphql/getAppStaticProps";
import { getStatusDescription } from "helpers/others";
import { useSmartLanguage } from "hooks/useSmartLanguage";
interface Props {
source?: string;
translations:
| {
language: string | undefined;
definition: string | null | undefined;
status: string | undefined;
}[]
| undefined;
languages: AppStaticProps["languages"];
langui: AppStaticProps["langui"];
index: number;
}
export default function DefinitionCard(props: Props): JSX.Element {
const { source, translations = [], languages, langui, index } = props;
const [selectedTranslation, LanguageSwitcher] = useSmartLanguage({
items: translations,
languages: languages,
languageExtractor: (item) => item.language,
});
return (
<>
<div className="flex place-items-center gap-2">
{/* TODO: Langui */}
<p className="font-headers text-lg">{`Definition ${index}`}</p>
{selectedTranslation?.status && (
<ToolTip
content={getStatusDescription(selectedTranslation.status, langui)}
maxWidth={"20rem"}
>
<Chip>{selectedTranslation.status}</Chip>
</ToolTip>
)}
{translations.length > 1 && <LanguageSwitcher />}
</div>
<p className="italic">{`${langui.source}: ${source}`}</p>
<p>{selectedTranslation?.definition}</p>
</>
);
}

11
src/helpers/className.ts Normal file
View File

@ -0,0 +1,11 @@
export function cIf(
condition: boolean | null | undefined | string,
ifTrueCss: string,
ifFalseCss?: string
) {
return condition ? ifTrueCss : ifFalseCss ?? "";
}
export function cJoin(...args: (string | undefined)[]): string {
return args.filter((elem) => elem).join(" ");
}

View File

@ -1,4 +1,8 @@
import { GetContentTextQuery, GetPostQuery } from "graphql/generated"; import {
GetContentTextQuery,
GetPostQuery,
GetWikiPageQuery,
} from "graphql/generated";
import React from "react"; import React from "react";
type Post = NonNullable< type Post = NonNullable<
@ -17,6 +21,15 @@ export interface ContentWithTranslations extends Omit<Content, "translations"> {
translations: NonNullable<Content["translations"]>; translations: NonNullable<Content["translations"]>;
} }
type WikiPage = NonNullable<
NonNullable<GetWikiPageQuery["wikiPages"]>["data"][number]["attributes"]
>;
export interface WikiPageWithTranslations
extends Omit<WikiPage, "translations"> {
translations: NonNullable<WikiPage["translations"]>;
}
type ImmutableBlackList<T> = JSX.Element | React.ReactNode | Function; type ImmutableBlackList<T> = JSX.Element | React.ReactNode | Function;
export type Immutable<T> = { export type Immutable<T> = {

View File

@ -4,6 +4,7 @@ import {
getPostStaticProps, getPostStaticProps,
PostStaticProps, PostStaticProps,
} from "graphql/getPostStaticProps"; } from "graphql/getPostStaticProps";
import { cIf, cJoin } from "helpers/className";
import { randomInt } from "helpers/numbers"; import { randomInt } from "helpers/numbers";
import { Immutable } from "helpers/types"; import { Immutable } from "helpers/types";
import { useRouter } from "next/router"; import { useRouter } from "next/router";
@ -27,10 +28,13 @@ export default function AboutUs(
const contactForm = ( const contactForm = (
<div className="flex flex-col gap-8 text-center"> <div className="flex flex-col gap-8 text-center">
<form <form
className={`grid gap-8 ${ className={cJoin(
formState !== "stale" && "grid gap-8",
"pointer-events-none cursor-not-allowed touch-none opacity-60" cIf(
}`} formState !== "stale",
"pointer-events-none cursor-not-allowed touch-none opacity-60"
)
)}
onSubmit={(event) => { onSubmit={(event) => {
event.preventDefault(); event.preventDefault();

View File

@ -64,7 +64,7 @@ export default function Channel(props: Props): JSX.Element {
); );
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<div className="mb-8"> <div className="mb-8">
<h1 className="text-3xl">{channel?.title}</h1> <h1 className="text-3xl">{channel?.title}</h1>
<p>{channel?.subscribers.toLocaleString()} subscribers</p> <p>{channel?.subscribers.toLocaleString()} subscribers</p>

View File

@ -82,7 +82,7 @@ export default function Videos(props: Props): JSX.Element {
); );
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<PageSelector <PageSelector
maxPage={Math.floor(videos.length / itemPerPage)} maxPage={Math.floor(videos.length / itemPerPage)}
page={page} page={page}

View File

@ -72,7 +72,7 @@ export default function Video(props: Props): JSX.Element {
); );
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<ReturnButton <ReturnButton
href="/library/" href="/library/"
title={langui.library} title={langui.library}

View File

@ -425,10 +425,7 @@ export async function getStaticProps(
language_code: context.locale ?? "en", language_code: context.locale ?? "en",
}); });
if ( if (!content.contents?.data[0]?.attributes?.translations) {
!content.contents ||
!content.contents.data[0]?.attributes?.translations
) {
return { notFound: true }; return { notFound: true };
} }
const props: Props = { const props: Props = {

View File

@ -143,16 +143,15 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
</SubPanel> </SubPanel>
); );
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
{[...groups].map(([name, items]) => ( {[...groups].map(
<Fragment key={name}> ([name, items], index) =>
{items.length > 0 && ( items.length > 0 && (
<Fragment> <Fragment key={index}>
{name && ( {name && (
<h2 <h2
key={`h2${name}`} className="flex flex-row place-items-center gap-2 pb-2 pt-10 text-2xl
className="flex flex-row place-items-center gap-2 first-of-type:pt-0"
pb-2 pt-10 text-2xl first-of-type:pt-0"
> >
{name} {name}
<Chip>{`${items.reduce((currentSum, item) => { <Chip>{`${items.reduce((currentSum, item) => {
@ -173,8 +172,8 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
}`}</Chip> }`}</Chip>
</h2> </h2>
)} )}
<div <div
key={`items${name}`}
className="grid grid-cols-2 items-end gap-8 className="grid grid-cols-2 items-end gap-8
desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] mobile:gap-4" desktop:grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] mobile:gap-4"
> >
@ -226,9 +225,8 @@ export default function Contents(props: Immutable<Props>): JSX.Element {
))} ))}
</div> </div>
</Fragment> </Fragment>
)} )
</Fragment> )}
))}
</ContentPanel> </ContentPanel>
); );
return ( return (

View File

@ -21,7 +21,7 @@ export default function CheckupContents(props: Immutable<Props>): JSX.Element {
const testReport = testingContent(contents); const testReport = testingContent(contents);
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
{<h2 className="text-2xl">{testReport.title}</h2>} {<h2 className="text-2xl">{testReport.title}</h2>}
<div className="my-4 grid grid-cols-[2em,3em,2fr,1fr,0.5fr,0.5fr,2fr] items-center gap-2"> <div className="my-4 grid grid-cols-[2em,3em,2fr,1fr,0.5fr,0.5fr,2fr] items-center gap-2">
@ -37,8 +37,8 @@ export default function CheckupContents(props: Immutable<Props>): JSX.Element {
{testReport.lines.map((line, index) => ( {testReport.lines.map((line, index) => (
<div <div
key={index} key={index}
className="mb-2 grid className="mb-2 grid grid-cols-[2em,3em,2fr,1fr,0.5fr,0.5fr,2fr] items-center
grid-cols-[2em,3em,2fr,1fr,0.5fr,0.5fr,2fr] items-center justify-items-start gap-2" justify-items-start gap-2"
> >
<Button <Button
href={line.frontendUrl} href={line.frontendUrl}

View File

@ -26,7 +26,7 @@ export default function CheckupLibraryItems(
const testReport = testingLibraryItem(libraryItems); const testReport = testingLibraryItem(libraryItems);
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
{<h2 className="text-2xl">{testReport.title}</h2>} {<h2 className="text-2xl">{testReport.title}</h2>}
<div className="my-4 grid grid-cols-[2em,3em,2fr,1fr,0.5fr,0.5fr,2fr] items-center gap-2"> <div className="my-4 grid grid-cols-[2em,3em,2fr,1fr,0.5fr,0.5fr,2fr] items-center gap-2">

View File

@ -146,7 +146,7 @@ export default function Editor(props: Immutable<Props>): JSX.Element {
} }
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<Popup setState={setConverterOpened} state={converterOpened}> <Popup setState={setConverterOpened} state={converterOpened}>
<div className="text-center"> <div className="text-center">
<h2 className="mt-4">Convert HTML to markdown</h2> <h2 className="mt-4">Convert HTML to markdown</h2>

View File

@ -16,9 +16,8 @@ export default function Home(props: Immutable<PostStaticProps>): JSX.Element {
prependBody={ prependBody={
<div className="grid w-full place-content-center place-items-center gap-5 text-center"> <div className="grid w-full place-content-center place-items-center gap-5 text-center">
<div <div
className="aspect-square w-32 className="aspect-square w-32 bg-black [mask:url('/icons/accords.svg')]
bg-black [mask:url('/icons/accords.svg')] [mask-size:contain] [mask-repeat:no-repeat] [mask-size:contain] [mask-repeat:no-repeat] [mask-position:center] mobile:w-[50vw]"
[mask-position:center] mobile:w-[50vw]"
/> />
<h1 className="mb-0 text-5xl">Accord&rsquo;s Library</h1> <h1 className="mb-0 text-5xl">Accord&rsquo;s Library</h1>
<h2 className="-mt-5 text-xl"> <h2 className="-mt-5 text-xl">

View File

@ -119,7 +119,7 @@ export default function LibrarySlug(props: Immutable<Props>): JSX.Element {
); );
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<LightBox /> <LightBox />
<ReturnButton <ReturnButton
@ -444,6 +444,7 @@ export default function LibrarySlug(props: Immutable<Props>): JSX.Element {
subtitle={subitem.attributes.subtitle} subtitle={subitem.attributes.subtitle}
thumbnail={subitem.attributes.thumbnail?.data?.attributes} thumbnail={subitem.attributes.thumbnail?.data?.attributes}
thumbnailAspectRatio="21/29.7" thumbnailAspectRatio="21/29.7"
thumbnailRounded={false}
keepInfoVisible={keepInfoVisible} keepInfoVisible={keepInfoVisible}
topChips={ topChips={
subitem.attributes.metadata && subitem.attributes.metadata &&

View File

@ -69,7 +69,7 @@ export default function LibrarySlug(props: Immutable<Props>): JSX.Element {
); );
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<LightBox /> <LightBox />
<ReturnButton <ReturnButton

View File

@ -250,7 +250,7 @@ export default function Library(props: Immutable<Props>): JSX.Element {
</SubPanel> </SubPanel>
); );
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
{[...groups].map(([name, items]) => ( {[...groups].map(([name, items]) => (
<Fragment key={name}> <Fragment key={name}>
{items.length > 0 && ( {items.length > 0 && (

View File

@ -85,7 +85,7 @@ export default function News(props: Immutable<Props>): JSX.Element {
); );
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<div <div
className="grid grid-cols-1 items-end gap-8 className="grid grid-cols-1 items-end gap-8
desktop:grid-cols-[repeat(auto-fill,_minmax(20rem,1fr))]" desktop:grid-cols-[repeat(auto-fill,_minmax(20rem,1fr))]"

View File

@ -1,10 +1,21 @@
import { AppLayout } from "components/AppLayout"; import { AppLayout } from "components/AppLayout";
import { ContentPanel } from "components/Panels/ContentPanel"; import { Chip } from "components/Chip";
import { HorizontalLine } from "components/HorizontalLine";
import { Img } from "components/Img";
import {
ReturnButton,
ReturnButtonType,
} from "components/PanelComponents/ReturnButton";
import {
ContentPanel,
ContentPanelWidthSizes,
} from "components/Panels/ContentPanel";
import { SubPanel } from "components/Panels/SubPanel"; import { SubPanel } from "components/Panels/SubPanel";
import { GetWikiPageQuery } from "graphql/generated"; import DefinitionCard from "components/Wiki/DefinitionCard";
import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps"; import { AppStaticProps, getAppStaticProps } from "graphql/getAppStaticProps";
import { getReadySdk } from "graphql/sdk"; import { getReadySdk } from "graphql/sdk";
import { Immutable } from "helpers/types"; import { Immutable, WikiPageWithTranslations } from "helpers/types";
import { useSmartLanguage } from "hooks/useSmartLanguage";
import { import {
GetStaticPathsContext, GetStaticPathsContext,
GetStaticPathsResult, GetStaticPathsResult,
@ -12,16 +23,89 @@ import {
} from "next"; } from "next";
interface Props extends AppStaticProps { interface Props extends AppStaticProps {
page: NonNullable< page: WikiPageWithTranslations;
NonNullable<GetWikiPageQuery["wikiPages"]>["data"][number]["attributes"]
>;
} }
export default function WikiPage(props: Immutable<Props>): JSX.Element { export default function WikiPage(props: Immutable<Props>): JSX.Element {
const { page, langui } = props; const { page, langui, languages } = props;
const subPanel = <SubPanel>Hello</SubPanel>; const [selectedTranslation, LanguageSwitcher] = useSmartLanguage({
const contentPanel = <ContentPanel>{page.slug}</ContentPanel>; items: page.translations,
languages: languages,
languageExtractor: (item) => item.language?.data?.attributes?.code,
});
const subPanel = (
<SubPanel>
<ReturnButton
href={`/wiki`}
title={langui.wiki}
langui={langui}
displayOn={ReturnButtonType.Desktop}
horizontalLine
/>
</SubPanel>
);
const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}>
<ReturnButton
href={`/wiki`}
title={langui.wiki}
langui={langui}
displayOn={ReturnButtonType.Mobile}
className="mb-10"
/>
<div className="flex place-content-center gap-4">
<h1 className="text-center text-3xl">{selectedTranslation?.title}</h1>
<LanguageSwitcher />
</div>
<HorizontalLine />
{selectedTranslation && (
<div className="text-justify">
<div
className="float-right ml-8 mb-8 w-[25rem] overflow-hidden rounded-lg bg-mid
text-center"
>
{page.thumbnail?.data?.attributes && (
<Img image={page.thumbnail.data.attributes} />
)}
<div className="my-4 grid gap-4 p-4">
<p className="font-headers text-xl">{langui.categories}</p>
<div className="flex flex-row flex-wrap place-content-center gap-2">
{page.categories?.data.map((category) => (
<Chip key={category.id}>{category.attributes?.name}</Chip>
))}
</div>
</div>
</div>
{selectedTranslation.summary && (
<div className="mb-6">
<p className="font-headers text-lg">{langui.summary}</p>
<p>{selectedTranslation.summary}</p>
</div>
)}
{page.definitions?.map((definition, index) => (
<DefinitionCard
key={index}
source={definition?.source?.data?.attributes?.name}
translations={definition?.translations?.map((translation) => ({
language: translation?.language?.data?.attributes?.code,
definition: translation?.definition,
status: translation?.status,
}))}
index={index + 1}
languages={languages}
langui={langui}
/>
))}
</div>
)}
</ContentPanel>
);
return ( return (
<AppLayout <AppLayout
@ -42,10 +126,11 @@ export async function getStaticProps(
language_code: context.locale ?? "en", language_code: context.locale ?? "en",
slug: slug, slug: slug,
}); });
if (!page.wikiPages?.data[0].attributes) return { notFound: true }; if (!page.wikiPages?.data[0].attributes?.translations)
return { notFound: true };
const props: Props = { const props: Props = {
...(await getAppStaticProps(context)), ...(await getAppStaticProps(context)),
page: page.wikiPages.data[0].attributes, page: page.wikiPages.data[0].attributes as WikiPageWithTranslations,
}; };
return { return {
props: props, props: props,

View File

@ -92,7 +92,7 @@ export default function Wiki(props: Immutable<Props>): JSX.Element {
); );
const contentPanel = ( const contentPanel = (
<ContentPanel width={ContentPanelWidthSizes.Large}> <ContentPanel width={ContentPanelWidthSizes.Full}>
<div <div
className="grid grid-cols-2 items-end gap-8 className="grid grid-cols-2 items-end gap-8
desktop:grid-cols-[repeat(auto-fill,_minmax(20rem,1fr))] mobile:gap-4" desktop:grid-cols-[repeat(auto-fill,_minmax(20rem,1fr))] mobile:gap-4"

View File

@ -172,6 +172,19 @@ input[type="submit"] {
[background-blend-mode:var(--theme-texture-dots-blend)]; [background-blend-mode:var(--theme-texture-dots-blend)];
} }
/* DEBUGGING */
.false {
@apply border-2 border-[red] text-[red] outline-dotted outline-2 outline-[red];
}
.undefined {
@apply border-2 border-[green] text-[green] outline-dotted outline-2 outline-[green];
}
.null {
@apply border-2 border-[blue] text-[blue] outline-dotted outline-2 outline-[blue];
}
/* TIPPY */ /* TIPPY */
.tippy-box[data-animation="fade"][data-state="hidden"] { .tippy-box[data-animation="fade"][data-state="hidden"] {