Use of cJoin and cIf
This commit is contained in:
parent
1510366bc8
commit
c076ec06ad
|
@ -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);
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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 && (
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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>
|
||||||
)}
|
)}
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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: {
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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)}
|
||||||
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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’s Library</h2>
|
<h2 className="text-3xl">Accord’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 && (
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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 && (
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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>
|
|
||||||
);
|
|
||||||
}
|
|
|
@ -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>
|
||||||
);
|
);
|
||||||
|
|
|
@ -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>
|
||||||
|
</>
|
||||||
|
);
|
||||||
|
}
|
|
@ -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(" ");
|
||||||
|
}
|
|
@ -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> = {
|
||||||
|
|
|
@ -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();
|
||||||
|
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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 = {
|
||||||
|
|
|
@ -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 (
|
||||||
|
|
|
@ -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}
|
||||||
|
|
|
@ -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">
|
||||||
|
|
|
@ -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>
|
||||||
|
|
|
@ -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’s Library</h1>
|
<h1 className="mb-0 text-5xl">Accord’s Library</h1>
|
||||||
<h2 className="-mt-5 text-xl">
|
<h2 className="-mt-5 text-xl">
|
||||||
|
|
|
@ -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 &&
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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 && (
|
||||||
|
|
|
@ -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))]"
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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"] {
|
||||||
|
|
Loading…
Reference in New Issue