Added language selector + better use of components

This commit is contained in:
DrMint 2022-02-19 02:14:16 +01:00
parent b634c92142
commit 57399a60dd
13 changed files with 279 additions and 162 deletions

View File

@ -3,6 +3,9 @@ import MainPanel from "./Panels/MainPanel";
import { useState } from "react";
import Head from "next/head";
import { useSwipeable } from "react-swipeable";
import { useRouter } from "next/router";
import Button from "components/Button";
import { prettyLanguage } from "queries/helpers";
type AppLayoutProps = {
subPanel?: React.ReactNode;
@ -14,9 +17,11 @@ type AppLayoutProps = {
export default function AppLayout(props: AppLayoutProps): JSX.Element {
const titlePrefix = "Accords Library";
const router = useRouter();
const [mainPanelOpen, setMainPanelOpen] = useState(false);
const [subPanelOpen, setsubPanelOpen] = useState(false);
const [subPanelOpen, setSubPanelOpen] = useState(false);
const [languagePanelOpen, setLanguagePanelOpen] = useState(false);
const sensibilitySwipe = 1.1;
const handlers = useSwipeable({
@ -25,13 +30,13 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
if (mainPanelOpen) {
setMainPanelOpen(false);
} else if (props.subPanel && props.contentPanel) {
setsubPanelOpen(true);
setSubPanelOpen(true);
}
},
onSwipedRight: (SwipeEventData) => {
if (SwipeEventData.velocity < sensibilitySwipe) return;
if (subPanelOpen) {
setsubPanelOpen(false);
setSubPanelOpen(false);
} else {
setMainPanelOpen(true);
}
@ -74,7 +79,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
<p className="text-2xl font-black font-headers">{props.title}</p>
<span
className="material-icons mt-[.1em] cursor-pointer"
onClick={() => setsubPanelOpen(true)}
onClick={() => setSubPanelOpen(true)}
>
{props.subPanel && !turnSubIntoContent
? props.subPanelIcon
@ -110,12 +115,12 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
${turnSubIntoContent ? "z-10" : ""}
${
mainPanelOpen || subPanelOpen
? " opacity-50"
: "opacity-0 translate-x-full"
? "opacity-50"
: "opacity-0 pointer-events-none touch-none"
}`}
onClick={() => {
setMainPanelOpen(false);
setsubPanelOpen(false);
setSubPanelOpen(false);
}}
></div>
@ -142,7 +147,48 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {
className={`${mainPanelClass} border-r-[1px] border-black border-dotted top-0 bottom-0 left-0 right-12 overflow-y-scroll webkit-scrollbar:w-0 [scrollbar-width:none] transition-transform duration-300 z-20 bg-light bg-paper bg-blend-multiply bg-local bg-[length:10cm]
${mainPanelOpen ? "" : "mobile:-translate-x-full"}`}
>
<MainPanel langui={props.langui} />
<MainPanel
langui={props.langui}
setLanguagePanelOpen={setLanguagePanelOpen}
/>
</div>
{/* Language selection background */}
<div
className={`fixed bg-dark inset-0 transition-all duration-500 z-20 grid place-content-center ${
languagePanelOpen
? "bg-opacity-50"
: "bg-opacity-0 pointer-events-none touch-none"
}`}
onClick={() => {
setLanguagePanelOpen(false);
}}
>
<div
className={`p-10 bg-light rounded-lg shadow-2xl shadow-dark grid gap-4 place-items-center transition-transform ${
languagePanelOpen ? "scale-100" : "scale-0"
}`}
>
<h2 className="text-2xl">Select a language</h2>
<div className="flex flex-wrap flex-row gap-2">
{router.locales?.sort().map((locale) => (
<>
{locale !== "xx" ? (
<Button
key={locale}
active={locale === router.locale}
href={router.asPath}
locale={locale}
>
{prettyLanguage(locale)}
</Button>
) : (
""
)}
</>
))}
</div>
</div>
</div>
</div>
);

View File

@ -4,19 +4,27 @@ type ButtonProps = {
className?: string;
href?: string;
children: React.ReactChild | React.ReactChild[];
active?: boolean;
locale?: string;
};
export default function Button(props: ButtonProps): JSX.Element {
const button = (
<div
className={`grid place-content-center place-items-center border-[1px] border-dark text-dark rounded-full cursor-pointer px-4 pt-[0.4rem] pb-[0.5rem] transition-all hover:text-light hover:bg-dark hover:drop-shadow-dark-lg active:bg-black active:drop-shadow-black-lg active:border-black ${props.className}`}
className={`grid place-content-center place-items-center border-[1px] border-dark text-dark rounded-full px-4 pt-[0.4rem] pb-[0.5rem] transition-all ${
props.className
} ${
props.active
? "text-light bg-black drop-shadow-black-lg !border-black cursor-not-allowed"
: "cursor-pointer hover:text-light hover:bg-dark hover:drop-shadow-dark-lg active:bg-black active:drop-shadow-black-lg active:border-black"
}`}
>
{props.children}
</div>
);
const result = props.href ? (
<Link href={props.href} passHref>
<Link href={props.href} locale={props.locale} passHref>
{button}
</Link>
) : (

View File

@ -6,11 +6,7 @@ type ChipProps = {
export default function Chip(props: ChipProps): JSX.Element {
return (
<div
className={
"grid place-content-center place-items-center text-xs pb-[0.14rem] px-1.5 border-[1px] rounded-full opacity-70" +
" " +
props.className
}
className={`grid place-content-center place-items-center text-xs pb-[0.14rem] px-1.5 border-[1px] rounded-full opacity-70 ${props.className}`}
>
{props.children}
</div>

View File

@ -0,0 +1,16 @@
type InsetBoxProps = {
className?: string;
children: React.ReactChild | React.ReactChild[];
id?: string;
};
export default function InsetBox(props: InsetBoxProps): JSX.Element {
return (
<div
id={props.id}
className={`w-full shadow-inner-sm shadow-dark bg-mid rounded-xl p-8 ${props.className}`}
>
{props.children}
</div>
);
}

View File

@ -15,7 +15,7 @@ export default function NavOption(props: NavOptionProps): JSX.Element {
const divActive = "bg-mid shadow-inner-sm shadow-dark";
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-dark active:shadow-inner active:shadow-dark transition-all ${
const divCommon = `gap-x-5 w-full rounded-2xl cursor-pointer p-4 hover:bg-mid hover:shadow-inner-sm hover:shadow-dark hover:active:shadow-inner hover:active:shadow-dark transition-all ${
props.border ? border : ""
} ${isActive ? divActive : ""}`;

View File

@ -9,6 +9,7 @@ import Markdown from "markdown-to-jsx";
type MainPanelProps = {
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"];
setLanguagePanelOpen: Function;
};
export default function MainPanel(props: MainPanelProps): JSX.Element {
@ -29,7 +30,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {
/>
</div>
</Link>
<div className="relative mt-5">
<div className="relative mt-5" onClick={() => props.setLanguagePanelOpen(true)}>
{router.locale ? (
<Button className="absolute right-0 top-[-1.3em] text-xs !py-0.5 !px-2.5">
{router.locale.toUpperCase()}

View File

@ -82,6 +82,7 @@ query getEras($language_code: String) {
ending_year
title(filters: { language: { code: { eq: $language_code } } }) {
title
description
}
}
}
@ -124,119 +125,118 @@ query getChronologyItems($language_code: String) {
}
query getLibraryItemsPreview($language_code: String) {
libraryItems(
filters: { root_item: { eq: true } }
pagination: { limit: -1 }
sort: ["title:asc", "subtitle:asc"]
) {
data {
id
attributes {
title
subtitle
slug
thumbnail {
data {
attributes {
name
alternativeText
caption
width
height
url
}
}
}
release_date {
year
month
day
}
price {
amount
currency {
data {
attributes {
symbol
code
}
}
}
}
metadata {
__typename
... on ComponentMetadataBooks {
subtype {
data {
attributes {
slug
titles(
filters: { language: { code: { eq: $language_code } } }
) {
title
}
}
}
}
}
... on ComponentMetadataGame {
platform {
data {
attributes {
short
}
}
}
}
... on ComponentMetadataVideo {
subtype {
data {
attributes {
slug
titles(
filters: { language: { code: { eq: $language_code } } }
) {
title
}
}
}
}
}
... on ComponentMetadataAudio {
subtype {
data {
attributes {
slug
titles(
filters: { language: { code: { eq: $language_code } } }
) {
title
}
}
}
}
}
... on ComponentMetadataOther {
subtype {
data {
attributes {
slug
titles(
filters: { language: { code: { eq: $language_code } } }
) {
title
}
}
}
}
}
}
}
}
}
libraryItems(
filters: { root_item: { eq: true } }
pagination: { limit: -1 }
sort: ["title:asc", "subtitle:asc"]
) {
data {
id
attributes {
title
subtitle
slug
thumbnail {
data {
attributes {
name
alternativeText
caption
width
height
url
}
}
}
release_date {
year
month
day
}
price {
amount
currency {
data {
attributes {
symbol
code
}
}
}
}
metadata {
__typename
... on ComponentMetadataBooks {
subtype {
data {
attributes {
slug
titles(
filters: { language: { code: { eq: $language_code } } }
) {
title
}
}
}
}
}
... on ComponentMetadataGame {
platform {
data {
attributes {
short
}
}
}
}
... on ComponentMetadataVideo {
subtype {
data {
attributes {
slug
titles(
filters: { language: { code: { eq: $language_code } } }
) {
title
}
}
}
}
}
... on ComponentMetadataAudio {
subtype {
data {
attributes {
slug
titles(
filters: { language: { code: { eq: $language_code } } }
) {
title
}
}
}
}
}
... on ComponentMetadataOther {
subtype {
data {
attributes {
slug
titles(
filters: { language: { code: { eq: $language_code } } }
) {
title
}
}
}
}
}
}
}
}
}
}
query getLibraryItemsSlugs {
libraryItems(pagination: { limit: -1 }) {
data {

View File

@ -165,6 +165,7 @@ export type GetErasQuery = {
title: Array<{
__typename: "ComponentTranslationsChronologyEra";
title: string;
description: string;
}>;
};
}>;

View File

@ -32,6 +32,7 @@ import Button from "components/Button";
import HorizontalLine from "components/HorizontalLine";
import AppLayout from "components/AppLayout";
import LibraryItemsPreview from "components/Library/LibraryItemsPreview";
import InsetBox from "components/InsetBox";
type LibrarySlugProps = {
libraryItem: GetLibraryItemQuery;
@ -124,10 +125,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
)}
</div>
<div
id="summary"
className="bg-mid w-full grid place-items-center p-8 rounded-2xl shadow-inner-sm shadow-dark"
>
<InsetBox id="summary" className="grid place-items-center">
<div className="w-[clamp(0px,100%,42rem)] grid place-items-center gap-8">
{item.subitem_of.data.length > 0 ? (
<div className="grid place-items-center">
@ -159,7 +157,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
""
)}
</div>
</div>
</InsetBox>
{item.gallery.data.length > 0 ? (
<div id="gallery" className="grid place-items-center gap-8 w-full">
@ -188,9 +186,9 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
""
)}
<div
<InsetBox
id="details"
className="bg-mid w-full grid place-items-center p-8 rounded-2xl text-left shadow-inner-sm shadow-dark"
className="grid place-items-center"
>
<div className="w-[clamp(0px,100%,42rem)] grid place-items gap-8">
<h2 className="text-2xl text-center">
@ -345,7 +343,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
""
)}
</div>
</div>
</InsetBox>
{item.subitems.data.length > 0 ? (
item.metadata.length > 0 &&

View File

@ -16,6 +16,8 @@ import NavOption from "components/PanelComponents/NavOption";
import ReturnButton from "components/PanelComponents/ReturnButton";
import HorizontalLine from "components/HorizontalLine";
import AppLayout from "components/AppLayout";
import { prettySlug } from "queries/helpers";
import InsetBox from "components/InsetBox";
interface DataChronologyProps {
chronologyItems: GetChronologyItemsQuery;
@ -27,20 +29,39 @@ export default function DataChronology(
props: DataChronologyProps
): JSX.Element {
const langui = props.langui.websiteInterfaces.data[0].attributes;
const chronologyItems = props.chronologyItems.chronologyItems;
const chronologyEras = props.chronologyEras.chronologyEras;
// Group by year the Chronology items
let chronologyItemYearGroups: GetChronologyItemsQuery["chronologyItems"]["data"][number][][] =
let chronologyItemYearGroups: GetChronologyItemsQuery["chronologyItems"]["data"][number][][][] =
[];
if (props.chronologyItems.chronologyItems) {
props.chronologyItems.chronologyItems.data.map((item) => {
if (!chronologyItemYearGroups.hasOwnProperty(item.attributes.year)) {
chronologyItemYearGroups[item.attributes.year] = [item];
} else {
chronologyItemYearGroups[item.attributes.year].push(item);
}
});
}
chronologyEras.data.map((era) => {
chronologyItemYearGroups.push([]);
});
let currentChronologyEraIndex = 0;
chronologyItems.data.map((item) => {
if (
item.attributes.year >
chronologyEras.data[currentChronologyEraIndex].attributes.ending_year
) {
currentChronologyEraIndex++;
}
if (
!chronologyItemYearGroups[currentChronologyEraIndex].hasOwnProperty(
item.attributes.year
)
) {
chronologyItemYearGroups[currentChronologyEraIndex][
item.attributes.year
] = [item];
} else {
chronologyItemYearGroups[currentChronologyEraIndex][
item.attributes.year
].push(item);
}
});
const subPanel = (
<SubPanel>
@ -51,7 +72,7 @@ export default function DataChronology(
<NavOption
key={era.id}
url={"#" + era.attributes.slug}
title={era.attributes.title[0] ? era.attributes.title[0].title : ""}
title={era.attributes.title.length > 0 ? era.attributes.title[0].title : prettySlug(era.attributes.slug)}
subtitle={
era.attributes.starting_year + " → " + era.attributes.ending_year
}
@ -63,17 +84,32 @@ export default function DataChronology(
const contentPanel = (
<ContentPanel>
{chronologyItemYearGroups.map((items, index: number) => {
if (items && items[0].attributes.year) {
return (
{chronologyItemYearGroups.map((era, eraIndex) => (
<>
<InsetBox
id={chronologyEras.data[eraIndex].attributes.slug}
className="grid text-center my-8 gap-4"
>
<h2 className="text-2xl">
{chronologyEras.data[eraIndex].attributes.title.length > 0
? chronologyEras.data[eraIndex].attributes.title[0].title
: prettySlug(chronologyEras.data[eraIndex].attributes.slug)}
</h2>
<p className="whitespace-pre-line ">
{chronologyEras.data[eraIndex].attributes.title.length > 0
? chronologyEras.data[eraIndex].attributes.title[0].description
: ""}
</p>
</InsetBox>
{era.map((items, index) => (
<ChronologyYearComponent
key={index}
key={`${eraIndex}-${index}`}
year={items[0].attributes.year}
items={items}
/>
);
}
})}
))}
</>
))}
</ContentPanel>
);

View File

@ -51,7 +51,7 @@ export function prettyinlineTitle(
export function prettyItemType(
metadata: {
__typename: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["metadata"][number]["__typename"]
__typename: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["metadata"][number]["__typename"];
},
langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"]
): string {
@ -73,7 +73,7 @@ export function prettyItemType(
}
export function prettyItemSubType(
metadata: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["metadata"][number],
metadata: GetLibraryItemsPreviewQuery["libraryItems"]["data"][number]["attributes"]["metadata"][number]
): string {
switch (metadata.__typename) {
case "ComponentMetadataAudio":
@ -92,6 +92,25 @@ export function prettyItemSubType(
}
}
export function prettyLanguage(code: string): string {
switch (code) {
case "en":
return "English";
case "es":
return "Español";
case "fr":
return "Français";
case "ja":
return "日本語";
case "en":
return "English";
case "xx":
return "██";
default:
return code;
}
}
export function capitalizeString(string: string): string {
function capitalizeWord(word: string): string {
return word.charAt(0).toUpperCase() + word.substring(1);

View File

@ -9,7 +9,7 @@
}
* {
@apply box-border font-body font-medium scroll-smooth;
@apply box-border font-body font-medium scroll-smooth scroll-m-8;
}
h1,
@ -25,10 +25,6 @@
@apply transition-colors underline-offset-2 decoration-dotted underline decoration-dark hover:text-dark;
}
*:target {
@apply scroll-mt-4;
}
*::selection {
@apply bg-dark text-light;
}

View File

@ -79,7 +79,7 @@ module.exports = {
".drop-shadow-dark-2xl": {
filter: "drop-shadow(0 25px 25px rgb(156 102 68 / 0.8))",
},
".drop-shadow-black-lg": {
filter:
"drop-shadow(0 10px 8px rgb(27 24 17 / 0.2)) drop-shadow(0 4px 3px rgb(27 24 17 / 0.4))",