diff --git a/next.config.js b/next.config.js index f6c43d3..f8dd901 100644 --- a/next.config.js +++ b/next.config.js @@ -3,7 +3,7 @@ module.exports = { swcMinify: true, reactStrictMode: true, i18n: { - locales: ["en", "fr", "ja", "es", "xx"], + locales: ["en", "fr", "ja", "es"], defaultLocale: "en", }, images: { diff --git a/run_accords_dev.sh b/run_accords_dev.sh index 67f17cb..e7c9e0a 100755 --- a/run_accords_dev.sh +++ b/run_accords_dev.sh @@ -1 +1 @@ -npx next dev -p 12500 +npx next dev -p 12499 diff --git a/src/components/AppLayout.tsx b/src/components/AppLayout.tsx index 40f5890..bf6c1ed 100644 --- a/src/components/AppLayout.tsx +++ b/src/components/AppLayout.tsx @@ -88,7 +88,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { const metaDescription = props.description ? props.description - : "Accord's Library aims at gathering and archiving all of Yoko Taro’s work. Yoko Taro is a Japanese video game director and scenario writer."; + : props.langui.default_description; return (
@@ -104,12 +104,8 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { content={`${titlePrefix} - ${ogTitle}`} > - {props.description && ( - <> - - - - )} + + @@ -160,7 +156,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element {

- Select one of the options in the sidebar + {props.langui.select_option_sidebar}

@@ -238,7 +234,7 @@ export default function AppLayout(props: AppLayoutProps): JSX.Element { appLayout.languagePanelOpen ? "scale-100" : "scale-0" }`} > -

Select a language

+

{props.langui.select_language}

{router.locales?.sort().map((locale) => ( ))} diff --git a/src/components/InsetBox.tsx b/src/components/InsetBox.tsx index 83de892..c9f45ea 100644 --- a/src/components/InsetBox.tsx +++ b/src/components/InsetBox.tsx @@ -1,6 +1,6 @@ type InsetBoxProps = { className?: string; - children: React.ReactChild | React.ReactChild[]; + children: React.ReactNode; id?: string; }; diff --git a/src/components/Library/LibraryItemsPreview.tsx b/src/components/Library/LibraryItemsPreview.tsx index d4f97ef..3db4afd 100644 --- a/src/components/Library/LibraryItemsPreview.tsx +++ b/src/components/Library/LibraryItemsPreview.tsx @@ -30,7 +30,7 @@ export default function LibraryItemsPreview( {item.thumbnail.data ? ( ) : (
diff --git a/src/components/PanelComponents/ReturnButton.tsx b/src/components/PanelComponents/ReturnButton.tsx index 6f2517c..c208c2b 100644 --- a/src/components/PanelComponents/ReturnButton.tsx +++ b/src/components/PanelComponents/ReturnButton.tsx @@ -13,7 +13,7 @@ export default function ReturnButton(props: ReturnButtonProps): JSX.Element { return ( ); } diff --git a/src/components/Panels/MainPanel.tsx b/src/components/Panels/MainPanel.tsx index 1ac3b2f..cc819aa 100644 --- a/src/components/Panels/MainPanel.tsx +++ b/src/components/Panels/MainPanel.tsx @@ -1,6 +1,5 @@ import Link from "next/link"; import NavOption from "components/PanelComponents/NavOption"; -import SVG from "components/SVG"; import { useRouter } from "next/router"; import Button from "components/Button"; import HorizontalLine from "components/HorizontalLine"; @@ -84,8 +83,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { appLayout.setMainPanelOpen(false)} @@ -94,8 +93,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { appLayout.setMainPanelOpen(false)} @@ -104,8 +103,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { appLayout.setMainPanelOpen(false)} @@ -114,8 +113,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { appLayout.setMainPanelOpen(false)} @@ -126,7 +125,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { appLayout.setMainPanelOpen(false)} @@ -135,7 +134,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { appLayout.setMainPanelOpen(false)} @@ -144,7 +143,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { appLayout.setMainPanelOpen(false)} @@ -153,7 +152,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { appLayout.setMainPanelOpen(false)} @@ -162,7 +161,7 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { appLayout.setMainPanelOpen(false)} @@ -176,8 +175,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element { }`} >

- {langui.main_licensing ? ( - {langui.main_licensing} + {langui.licensing_notice ? ( + {langui.licensing_notice} ) : ( "" )} @@ -194,8 +193,8 @@ export default function MainPanel(props: MainPanelProps): JSX.Element {

- {langui.main_copyright ? ( - {langui.main_copyright} + {langui.copyright_notice ? ( + {langui.copyright_notice} ) : ( "" )} diff --git a/src/components/Select.tsx b/src/components/Select.tsx new file mode 100644 index 0000000..06c6e2a --- /dev/null +++ b/src/components/Select.tsx @@ -0,0 +1,67 @@ +import { Dispatch, SetStateAction, useState } from "react"; + +export type SelectProps = { + setState: Dispatch>; + state: number; + options: string[]; + selected?: number; + allowEmpty?: boolean; + className?: string; + onChange?: Function; +}; + +export default function Select(props: SelectProps): JSX.Element { + const [opened, setOpened] = useState(false); + + return ( +

+
+

setOpened(!opened)} className="w-full"> + {props.state === -1 ? "—" : props.options[props.state]} +

+ {props.state >= 0 && props.allowEmpty && ( + props.setState(-1)} + className="material-icons !text-xs" + > + close + + )} + setOpened(!opened)} className="material-icons"> + {opened ? "arrow_drop_up" : "arrow_drop_down"} + +
+
+ {props.options.map((option, index) => ( + <> + {index !== props.state && ( +
{ + setOpened(false); + props.setState(index); + }} + > + {option} +
+ )} + + ))} +
+
+ ); +} diff --git a/src/components/Switch.tsx b/src/components/Switch.tsx new file mode 100644 index 0000000..6f33b96 --- /dev/null +++ b/src/components/Switch.tsx @@ -0,0 +1,26 @@ +import { Dispatch, SetStateAction } from "react"; + +export type SwitchProps = { + setState: Dispatch>; + state: boolean; + className?: string; +}; + +export default function Select(props: SwitchProps): JSX.Element { + return ( +
{ + props.setState(!props.state); + }} + > +
+
+ ); +} diff --git a/src/graphql/operation.graphql b/src/graphql/operation.graphql index 63d9963..99d0f31 100644 --- a/src/graphql/operation.graphql +++ b/src/graphql/operation.graphql @@ -1,72 +1,87 @@ query getWebsiteInterface($language_code: String) { - websiteInterfaces(filters: { language: { code: { eq: $language_code } } }) { + websiteInterfaces( + filters: { ui_language: { code: { eq: $language_code } } } + ) { data { attributes { - main_library - main_library_description - main_news - main_merch - main_gallery - main_archives - main_about_us - main_licensing - main_copyright + library + contents + wiki + chronicles + library_short_description + contents_short_description + wiki_short_description + chronicles_short_description + news + merch + gallery + archives + about_us + licensing_notice + copyright_notice + contents_description + type + category + categories + size + release_date + release_year + details + price + width + height + thickness + subitem + subitems + subitem_of + variant + variants + variant_of + summary + audio + video + textual + game + other + return_to + left_to_right + right_to_left + page + pages + page_order + binding + type_information + front_matter + back_matter + open_content + read_content + watch_content + listen_content + view_scans + paperback + hardcover + languages + select_language + language library_description - library_item_summary - library_item_gallery - library_item_details - library_item_subitems - library_item_variants - library_item_content - global_return_label - global_subitem_of - global_type - global_width - global_height - global_thickness - global_binding - global_language - global_languages - global_page - global_pages - global_page_order - global_release_date - global_price - library_item_physical_size - library_item_type_information - library_item_front_matter - library_item_back_matter - library_item_type_textual - library_item_type_audio - library_item_type_game - library_item_type_video - library_item_type_other - library_item_open_content - library_item_view_scans - content_read_content - content_watch_content - content_listen_content - global_category - global_categories - global_paperback - global_hardcover - global_left_to_right - global_right_to_left - main_wiki - main_wiki_description - main_chronicles - main_chronicles_description - library_items - library_items_description - library_content - library_content_description wiki_description - news_description chronicles_description + news_description + merch_description gallery_description archives_description about_us_description - merch_description + page_not_found + default_description + name + show_subitems + show_primary_items + show_secondary_items + no_type + no_year + order_by + group_by + select_option_sidebar } } } @@ -125,17 +140,14 @@ query getChronologyItems($language_code: String) { } query getLibraryItemsPreview($language_code: String) { - libraryItems( - filters: { root_item: { eq: true } } - pagination: { limit: -1 } - sort: ["title:asc", "subtitle:asc"] - ) { + libraryItems(pagination: { limit: -1 }) { data { id attributes { title subtitle slug + root_item thumbnail { data { attributes { diff --git a/src/graphql/operations-types.ts b/src/graphql/operations-types.ts index 57b4615..1789afd 100644 --- a/src/graphql/operations-types.ts +++ b/src/graphql/operations-types.ts @@ -86,71 +86,84 @@ export type GetWebsiteInterfaceQuery = { __typename: "WebsiteInterfaceEntity"; attributes: { __typename: "WebsiteInterface"; - main_library: string; - main_library_description: string; - main_news: string; - main_merch: string; - main_gallery: string; - main_archives: string; - main_about_us: string; - main_licensing: string; - main_copyright: string; + library: string; + contents: string; + wiki: string; + chronicles: string; + library_short_description: string; + contents_short_description: string; + wiki_short_description: string; + chronicles_short_description: string; + news: string; + merch: string; + gallery: string; + archives: string; + about_us: string; + licensing_notice: string; + copyright_notice: string; + contents_description: string; + type: string; + category: string; + categories: string; + size: string; + release_date: string; + release_year: string; + details: string; + price: string; + width: string; + height: string; + thickness: string; + subitem: string; + subitems: string; + subitem_of: string; + variant: string; + variants: string; + variant_of: string; + summary: string; + audio: string; + video: string; + textual: string; + game: string; + other: string; + return_to: string; + left_to_right: string; + right_to_left: string; + page: string; + pages: string; + page_order: string; + binding: string; + type_information: string; + front_matter: string; + back_matter: string; + open_content: string; + read_content: string; + watch_content: string; + listen_content: string; + view_scans: string; + paperback: string; + hardcover: string; + languages: string; + select_language: string; + language: string; library_description: string; - library_item_summary: string; - library_item_gallery: string; - library_item_details: string; - library_item_subitems: string; - library_item_variants: string; - library_item_content: string; - global_return_label: string; - global_subitem_of: string; - global_type: string; - global_width: string; - global_height: string; - global_thickness: string; - global_binding: string; - global_language: string; - global_languages: string; - global_page: string; - global_pages: string; - global_page_order: string; - global_release_date: string; - global_price: string; - library_item_physical_size: string; - library_item_type_information: string; - library_item_front_matter: string; - library_item_back_matter: string; - library_item_type_textual: string; - library_item_type_audio: string; - library_item_type_game: string; - library_item_type_video: string; - library_item_type_other: string; - library_item_open_content: string; - library_item_view_scans: string; - content_read_content: string; - content_watch_content: string; - content_listen_content: string; - global_category: string; - global_categories: string; - global_paperback: string; - global_hardcover: string; - global_left_to_right: string; - global_right_to_left: string; - main_wiki: string; - main_wiki_description: string; - main_chronicles: string; - main_chronicles_description: string; - library_items: string; - library_items_description: string; - library_content: string; - library_content_description: string; wiki_description: string; - news_description: string; chronicles_description: string; + news_description: string; + merch_description: string; gallery_description: string; archives_description: string; about_us_description: string; - merch_description: string; + page_not_found: string; + default_description: string; + name: string; + show_subitems: string; + show_primary_items: string; + show_secondary_items: string; + no_type: string; + no_year: string; + order_by: string; + group_by: string; + select_option_sidebar: string; }; }>; }; @@ -238,6 +251,7 @@ export type GetLibraryItemsPreviewQuery = { title: string; subtitle: string; slug: string; + root_item: boolean; thumbnail: { __typename: "UploadFileEntityResponse"; data: { diff --git a/src/pages/404.tsx b/src/pages/404.tsx index fd9217f..c54d2b5 100644 --- a/src/pages/404.tsx +++ b/src/pages/404.tsx @@ -4,6 +4,7 @@ import { getWebsiteInterface } from "graphql/operations"; import { GetStaticProps } from "next"; import { GetWebsiteInterfaceQuery } from "graphql/operations-types"; import AppLayout from "components/AppLayout"; +import ReturnButton from "components/PanelComponents/ReturnButton"; type FourOhFourProps = { langui: GetWebsiteInterfaceQuery; @@ -13,13 +14,13 @@ export default function FourOhFour(props: FourOhFourProps): JSX.Element { const langui = props.langui.websiteInterfaces.data[0].attributes; const contentPanel = ( -

404 - Page Not Found

- - Go back home - +

404 - {langui.page_not_found}

+
); - return ; + return ( + + ); } export const getStaticProps: GetStaticProps = async (context) => { diff --git a/src/pages/about-us/index.tsx b/src/pages/about-us/index.tsx index 2e4b3ff..8e69680 100644 --- a/src/pages/about-us/index.tsx +++ b/src/pages/about-us/index.tsx @@ -15,14 +15,14 @@ export default function AboutUs(props: AboutUsProps): JSX.Element { ); return ( diff --git a/src/pages/archives/index.tsx b/src/pages/archives/index.tsx index eb258b9..88fc0a2 100644 --- a/src/pages/archives/index.tsx +++ b/src/pages/archives/index.tsx @@ -15,14 +15,14 @@ export default function Archives(props: ArchivesProps): JSX.Element { ); return ( diff --git a/src/pages/chronicles/index.tsx b/src/pages/chronicles/index.tsx index 8f9db43..2ef7522 100644 --- a/src/pages/chronicles/index.tsx +++ b/src/pages/chronicles/index.tsx @@ -15,14 +15,14 @@ export default function Chronicles(props: ChroniclesProps): JSX.Element { ); return ( diff --git a/src/pages/contents/[slug]/index.tsx b/src/pages/contents/[slug]/index.tsx index 0abd7e0..144ecda 100644 --- a/src/pages/contents/[slug]/index.tsx +++ b/src/pages/contents/[slug]/index.tsx @@ -40,7 +40,7 @@ export default function ContentIndex(props: ContentIndexProps): JSX.Element { {content.text_set.length > 0 ? ( ) : ( "" @@ -48,7 +48,7 @@ export default function ContentIndex(props: ContentIndexProps): JSX.Element { {content.audio_set.length > 0 ? ( ) : ( "" @@ -56,7 +56,7 @@ export default function ContentIndex(props: ContentIndexProps): JSX.Element { {content.video_set.length > 0 ? ( ) : ( "" diff --git a/src/pages/gallery/index.tsx b/src/pages/gallery/index.tsx index 865078b..f9608f9 100644 --- a/src/pages/gallery/index.tsx +++ b/src/pages/gallery/index.tsx @@ -18,7 +18,7 @@ export default function Gallery(props: GalleryProps): JSX.Element { return ( diff --git a/src/pages/index.tsx b/src/pages/index.tsx index 538a2c0..73d909b 100644 --- a/src/pages/index.tsx +++ b/src/pages/index.tsx @@ -141,13 +141,11 @@ export default function Home(props: HomeProps): JSX.Element { ); return ( - <> - - + ); } diff --git a/src/pages/library/[slug].tsx b/src/pages/library/[slug].tsx index cd44876..235eb31 100644 --- a/src/pages/library/[slug].tsx +++ b/src/pages/library/[slug].tsx @@ -58,16 +58,12 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { const subPanel = ( - +
appLayout.setSubPanelOpen(false)} @@ -75,7 +71,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { {item.gallery.data.length > 0 ? ( appLayout.setSubPanelOpen(false)} @@ -85,7 +81,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { )} appLayout.setSubPanelOpen(false)} @@ -93,11 +89,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { {item.subitems.data.length > 0 ? ( appLayout.setSubPanelOpen(false)} @@ -107,11 +99,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { )} {item.contents.data.length > 0 ? ( - + ) : ( "" )} @@ -140,7 +128,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element {
{item.subitem_of.data.length > 0 ? (
-

{langui.global_subitem_of}

+

{langui.subitem_of}

) : ( "" @@ -450,7 +438,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { ) : ( "" @@ -474,7 +462,7 @@ export default function LibrarySlug(props: LibrarySlugProps): JSX.Element { return ( ; + export default function Library(props: LibraryProps): JSX.Element { const langui = props.langui.websiteInterfaces.data[0].attributes; + + const [showSubitems, setShowSubitems] = useState(false); + const [sortingMethod, setSortingMethod] = useState(0); + const [groupingMethod, setGroupingMethod] = useState(-1); + + const [filteredItems, setFilteredItems] = useState< + LibraryProps["libraryItems"]["libraryItems"]["data"] + >(filterItems(showSubitems, props.libraryItems.libraryItems.data)); + + const [sortedItems, setSortedItem] = useState< + LibraryProps["libraryItems"]["libraryItems"]["data"] + >(sortBy(groupingMethod, filteredItems)); + + const [groups, setGroups] = useState( + getGroups(langui, groupingMethod, sortedItems) + ); + + useEffect(() => { + setFilteredItems( + filterItems(showSubitems, props.libraryItems.libraryItems.data) + ); + }, [showSubitems, props.libraryItems.libraryItems.data]); + + useEffect(() => { + setSortedItem(sortBy(sortingMethod, filteredItems)); + }, [filteredItems, sortingMethod]); + + useEffect(() => { + setGroups(getGroups(langui, groupingMethod, sortedItems)); + }, [langui, groupingMethod, sortedItems]); + const subPanel = ( + +
+

{langui.group_by}:

+ +
+ +
+

{langui.show_subitems}:

+ +
); const contentPanel = ( -
- {props.libraryItems.libraryItems.data.map((item) => ( - - ))} -
+ {[...groups].map(([name, items]) => ( + <> + {items.length > 0 && ( + <> +

{name}

+
+ {items.map((item) => ( + + ))} +
+ + )} + + ))}
); return ( { return { props: {} }; } }; + +function getGroups( + langui: GetWebsiteInterfaceQuery["websiteInterfaces"]["data"][number]["attributes"], + groupByType: number, + items: LibraryProps["libraryItems"]["libraryItems"]["data"] +): GroupLibraryItems { + switch (groupByType) { + case 0: + return new Map(); + + case 1: + const groupType: GroupLibraryItems = new Map(); + groupType.set(langui.audio, []); + groupType.set(langui.game, []); + groupType.set(langui.textual, []); + groupType.set(langui.video, []); + groupType.set(langui.other, []); + groupType.set(langui.no_type, []); + items.map((item) => { + if (item.attributes.metadata.length > 0) { + switch (item.attributes.metadata[0].__typename) { + case "ComponentMetadataAudio": + groupType.get(langui.audio)?.push(item); + break; + case "ComponentMetadataGame": + groupType.get(langui.game)?.push(item); + break; + case "ComponentMetadataBooks": + groupType.get(langui.textual)?.push(item); + break; + case "ComponentMetadataVideo": + groupType.get(langui.video)?.push(item); + break; + case "ComponentMetadataOther": + switch ( + item.attributes.metadata[0].subtype.data.attributes.slug + ) { + case "audio-case": + groupType.get(langui.audio)?.push(item); + break; + + case "video-case": + groupType.get(langui.video)?.push(item); + break; + + case "game-case": + groupType.get(langui.game)?.push(item); + break; + + default: + groupType.get(langui.other)?.push(item); + break; + } + + break; + } + } else { + groupType.get(langui.no_type)?.push(item); + } + }); + return groupType; + + case 2: + const years: number[] = []; + items.map((item) => { + if (item.attributes.release_date) { + if (!years.includes(item.attributes.release_date.year)) + years.push(item.attributes.release_date.year); + } + }); + const groupYear: GroupLibraryItems = new Map(); + years.sort(); + years.map((year) => { + groupYear.set(year.toString(), []); + }); + groupYear.set(langui.no_year, []); + items.map((item) => { + if (item.attributes.release_date) { + groupYear + .get(item.attributes.release_date.year.toString()) + ?.push(item); + } else { + groupYear.get(langui.no_year)?.push(item); + } + }); + + return groupYear; + + default: + const groupDefault: GroupLibraryItems = new Map(); + groupDefault.set("", items); + return groupDefault; + } +} + +function filterItems( + showSubitems: boolean, + items: LibraryProps["libraryItems"]["libraryItems"]["data"] +): LibraryProps["libraryItems"]["libraryItems"]["data"] { + return [...items].filter((item) => { + let result = true; + if (!showSubitems && !item.attributes.root_item) result = false; + if ( + item.attributes.metadata.length > 0 && + item.attributes.metadata[0].__typename === "ComponentMetadataOther" && + (item.attributes.metadata[0].subtype.data.attributes.slug === + "variant-set" || + item.attributes.metadata[0].subtype.data.attributes.slug === + "relation-set") + ) + result = false; + return result; + }); +} + +function sortBy( + orderByType: number, + items: LibraryProps["libraryItems"]["libraryItems"]["data"] +): LibraryProps["libraryItems"]["libraryItems"]["data"] { + switch (orderByType) { + case 0: + return [...items].sort((a, b) => { + const titleA = prettyinlineTitle( + "", + a.attributes.title, + a.attributes.subtitle + ); + const titleB = prettyinlineTitle( + "", + b.attributes.title, + b.attributes.subtitle + ); + return titleA.localeCompare(titleB); + }); + case 1: + return [...items].sort((a, b) => { + const priceA = a.attributes.price ? a.attributes.price.amount : 99999; + const priceB = b.attributes.price ? b.attributes.price.amount : 99999; + return priceA - priceB; + }); + case 2: + return [...items].sort((a, b) => { + const dateA = + a.attributes.release_date !== null + ? prettyDate(a.attributes.release_date) + : "9999"; + const dateB = + b.attributes.release_date !== null + ? prettyDate(b.attributes.release_date) + : "9999"; + return dateA.localeCompare(dateB); + }); + default: + return items; + } +} diff --git a/src/pages/merch/index.tsx b/src/pages/merch/index.tsx index eaf0f80..393688a 100644 --- a/src/pages/merch/index.tsx +++ b/src/pages/merch/index.tsx @@ -15,7 +15,7 @@ export default function Merch(props: MerchProps): JSX.Element { @@ -23,7 +23,7 @@ export default function Merch(props: MerchProps): JSX.Element { return ( diff --git a/src/pages/news/index.tsx b/src/pages/news/index.tsx index 3521fba..4777519 100644 --- a/src/pages/news/index.tsx +++ b/src/pages/news/index.tsx @@ -15,7 +15,7 @@ export default function News(props: NewsProps): JSX.Element { @@ -23,7 +23,7 @@ export default function News(props: NewsProps): JSX.Element { return ( diff --git a/src/pages/wiki/index.tsx b/src/pages/wiki/index.tsx index 3ad13df..102448a 100644 --- a/src/pages/wiki/index.tsx +++ b/src/pages/wiki/index.tsx @@ -16,7 +16,7 @@ export default function Hubs(props: WikiProps): JSX.Element { @@ -25,7 +25,7 @@ export default function Hubs(props: WikiProps): JSX.Element { return (