-
-
-
currentZoom <= 1 && handlePageNavigation("left")}
- />
-
currentZoom <= 1 && handlePageNavigation("right")}
- />
-
- ) : (
- <>
-
currentZoom <= 1 && handlePageNavigation("left")}
- style={{
- clipPath: leftSideClipPath,
- }}>
- {isSidePagesEnabled && (
-
- )}
-
-
-
-
-
currentZoom <= 1 && handlePageNavigation("right")}
- style={{
- clipPath: rightSideClipPath,
- }}>
-
- {isSidePagesEnabled && (
-
- )}
-
-
-
- >
- )}
-
-
-
-
-
-
- {currentPageIndex - 1} / {pages.length - 2}
-
-
{
- let value = 0;
- if (Array.isArray(event)) {
- value = event[0];
- } else {
- value = event;
- }
- changeCurrentPageIndex(() => value);
- }}
- />
-
- setIsGalleryMode((current) => !current)}
- size="small"
- />
-
-
-
-
- {item.contents?.data.map((content) => (
-
- {content.attributes?.scan_set?.[0] && (
- {
- const range = content.attributes?.range[0];
- let newPageIndex = index + 1;
- if (range?.__typename === "ComponentRangePageRange") {
- newPageIndex += range.starting_page;
- }
- changeCurrentPageIndex(() => newPageIndex);
- setIsGalleryMode(false);
- }}
- id={content.attributes.slug}
- translations={filterHasAttributes(
- content.attributes.content?.data?.attributes?.translations,
- ["language.data.attributes"] as const
- ).map((translation) => ({
- language: translation.language.data.attributes.code,
- title: prettyInlineTitle(
- translation.pre_title,
- translation.title,
- translation.subtitle
- ),
- }))}
- fallback={{
- title: prettySlug(content.attributes.slug, item.slug),
- }}
- content={content.attributes.content}
- />
- )}
-
- ))}
-
-
-
- ),
- [
- is1ColumnLayout,
- currentZoom,
- filterSettings,
- isDarkMode,
- pageHeight,
- effectiveDisplayMode,
- firstPage,
- pageQuality,
- bookType,
- leftSideClipPath,
- isSidePagesEnabled,
- leftSidePagesWidth,
- leftSidePagesCount,
- pageOrder,
- secondPage,
- rightSideClipPath,
- rightSidePagesWidth,
- rightSidePagesCount,
- isGalleryMode,
- currentPageIndex,
- pages.length,
- isFullscreen,
- toggleFullscreen,
- item.contents?.data,
- item.slug,
- handlePageNavigation,
- changeCurrentPageIndex,
- ]
- );
-
- return (
-
- );
-};
-export default LibrarySlug;
-
-/*
- * ╭──────────────────────╮
- * ───────────────────────────────────╯ NEXT DATA FETCHING ╰──────────────────────────────────────
- */
-
-export const getStaticProps: GetStaticProps = async (context) => {
- const sdk = getReadySdk();
- const langui = getLangui(context.locale);
- const item = await sdk.getLibraryItemScans({
- slug: context.params && isDefined(context.params.slug) ? context.params.slug.toString() : "",
- language_code: context.locale ?? "en",
- });
- if (!item.libraryItems?.data[0]?.attributes || !item.libraryItems.data[0]?.id)
- return { notFound: true };
- sortRangedContent(item.libraryItems.data[0].attributes.contents);
-
- const pages: UploadImageFragment[] = [];
-
- const cover = item.libraryItems.data[0].attributes.images?.[0]?.cover;
- if (cover) {
- if (cover.front?.data?.attributes) pages.push(cover.front.data.attributes);
- if (cover.inside_front?.data?.attributes) pages.push(cover.inside_front.data.attributes);
- }
-
- filterHasAttributes(item.libraryItems.data[0].attributes.contents?.data, [
- "attributes.scan_set",
- ] as const).forEach((content) =>
- filterHasAttributes(content.attributes.scan_set, ["pages.data"] as const).forEach((scanSet) =>
- filterHasAttributes(scanSet.pages.data, ["attributes"] as const)
- .sort((a, b) => {
- if (isDefinedAndNotEmpty(a.attributes.url) && isDefinedAndNotEmpty(b.attributes.url)) {
- let aName = getAssetFilename(a.attributes.url);
- let bName = getAssetFilename(b.attributes.url);
-
- /*
- * If the number is a succession of 0s, make the number
- * incrementally smaller than 0 (i.e: 00 becomes -1)
- */
- if (aName.replaceAll("0", "").length === 0) {
- aName = (1 - aName.length).toString(10);
- }
- if (bName.replaceAll("0", "").length === 0) {
- bName = (1 - bName.length).toString(10);
- }
-
- if (isInteger(aName) && isInteger(bName)) {
- return parseInt(aName, 10) - parseInt(bName, 10);
- }
- return a.attributes.url.localeCompare(b.attributes.url);
- }
- return 0;
- })
- .forEach((page) => pages.push(page.attributes))
- )
- );
-
- if (cover) {
- if (cover.inside_back?.data?.attributes) pages.push(cover.inside_back.data.attributes);
- if (cover.back?.data?.attributes) pages.push(cover.back.data.attributes);
- }
-
- const pageOrder: Props["pageOrder"] = (() => {
- const { metadata } = item.libraryItems.data[0].attributes;
- if (metadata?.[0]?.__typename === "ComponentMetadataBooks") {
- return metadata[0].page_order;
- }
- return PageOrder.LeftToRight;
- })();
-
- const bookType =
- item.libraryItems.data[0].attributes.metadata?.[0]?.__typename === "ComponentMetadataBooks" &&
- item.libraryItems.data[0].attributes.metadata[0].subtype?.data?.attributes?.slug === "manga"
- ? "manga"
- : "book";
-
- const pageWidth = item.libraryItems.data[0].attributes.size?.width ?? 120;
-
- if (pages.length === 0) return { notFound: true };
-
- const props: Props = {
- item: item.libraryItems.data[0].attributes,
- pages,
- pageOrder,
- bookType,
- pageWidth,
- itemSlug: item.libraryItems.data[0].attributes.slug,
- pageRatio: `${pages[0].width ?? 21} / ${pages[0].height ?? 29.7}`,
- openGraph: getOpenGraph(
- langui,
- item.libraryItems.data[0].attributes.title,
- undefined,
- item.libraryItems.data[0].attributes.thumbnail?.data?.attributes
- ),
- };
- return {
- props: props,
- };
-};
-
-// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
-
-export const getStaticPaths: GetStaticPaths = async (context) => {
- const sdk = getReadySdk();
- const libraryItems = await sdk.getLibraryItemsSlugs({});
- const paths: GetStaticPathsResult["paths"] = [];
- filterHasAttributes(libraryItems.libraryItems?.data, ["attributes"] as const).map((item) => {
- context.locales?.map((local) =>
- paths.push({ params: { slug: item.attributes.slug }, locale: local })
- );
- });
-
- return {
- paths,
- fallback: "blocking",
- };
-};
-
-/*
- * ╭──────────────────────╮
- * ───────────────────────────────────╯ PRIVATE COMPONENTS ╰──────────────────────────────────────
- */
-
-interface PageFiltersProps {
- page: "left" | "right" | "single";
- bookType: BookType;
- options: FilterSettings;
-}
-
-const PageFilters = ({ page, bookType, options }: PageFiltersProps) => {
- const isDarkMode = useAtomGetter(atoms.settings.darkMode);
- const commonCss = useMemo(
- () => cJoin("absolute inset-0", cIf(page === "right", "[background-position-x:-100%]")),
- [page]
- );
-
- return (
- <>
- {options.paperTexture && (
-
- )}
-
- {options.bookFold && (
-
- )}
-
- {options.lighting && (
- <>
-
-
- >
- )}
-
-
- >
- );
-};
-
-interface ScanSetProps {
- onClickOnImage: (index: number) => void;
- scanSet: NonNullable<
- NonNullable<
- NonNullable<
- NonNullable<
- NonNullable
["data"][number]["attributes"]
- >["contents"]
- >["data"][number]["attributes"]
- >["scan_set"]
- >;
- id: string;
- title: string;
-
- content: NonNullable<
- NonNullable<
- NonNullable<
- NonNullable["data"][number]["attributes"]
- >["contents"]
- >["data"][number]["attributes"]
- >["content"];
-}
-
-const ScanSet = ({ onClickOnImage, scanSet, id, title, content }: ScanSetProps): JSX.Element => {
- const is1ColumnLayout = useAtomGetter(atoms.containerQueries.is1ColumnLayout);
- const langui = useAtomGetter(atoms.localData.langui);
- const [selectedScan, LanguageSwitcher, languageSwitcherProps] = useSmartLanguage({
- items: scanSet,
- languageExtractor: useCallback(
- (item: NonNullable) => item.language?.data?.attributes?.code,
- []
- ),
- transform: useCallback((item: NonNullable) => {
- item.pages?.data.sort((a, b) => {
- if (
- a.attributes &&
- b.attributes &&
- isDefinedAndNotEmpty(a.attributes.url) &&
- isDefinedAndNotEmpty(b.attributes.url)
- ) {
- let aName = getAssetFilename(a.attributes.url);
- let bName = getAssetFilename(b.attributes.url);
-
- /*
- * If the number is a succession of 0s, make the number
- * incrementally smaller than 0 (i.e: 00 becomes -1)
- */
- if (aName.replaceAll("0", "").length === 0) {
- aName = (1 - aName.length).toString(10);
- }
- if (bName.replaceAll("0", "").length === 0) {
- bName = (1 - bName.length).toString(10);
- }
-
- if (isInteger(aName) && isInteger(bName)) {
- return parseInt(aName, 10) - parseInt(bName, 10);
- }
- return a.attributes.url.localeCompare(b.attributes.url);
- }
- return 0;
- });
- return item;
- }, []),
- });
-
- const pages = useMemo(
- () => filterHasAttributes(selectedScan?.pages?.data, ["attributes"]),
- [selectedScan]
- );
-
- return (
- <>
- {selectedScan && isDefined(pages) && (
-
-
-
- {title}
-
-
-
-
-
-
- {content?.data?.attributes && isDefinedAndNotEmpty(content.data.attributes.slug) && (
-
- )}
-
- {languageSwitcherProps.locales.size > 1 && (
-
- )}
-
-
-
{langui.status}:
-
-
-
-
-
- {selectedScan.scanners && selectedScan.scanners.data.length > 0 && (
-
-
{langui.scanners}:
-
- {filterHasAttributes(selectedScan.scanners.data, [
- "id",
- "attributes",
- ] as const).map((scanner) => (
-
-
-
- ))}
-
-
- )}
-
- {selectedScan.cleaners && selectedScan.cleaners.data.length > 0 && (
-
-
{langui.cleaners}:
-
- {filterHasAttributes(selectedScan.cleaners.data, [
- "id",
- "attributes",
- ] as const).map((cleaner) => (
-
-
-
- ))}
-
-
- )}
-
- {selectedScan.typesetters && selectedScan.typesetters.data.length > 0 && (
-
-
{langui.typesetters}:
-
- {filterHasAttributes(selectedScan.typesetters.data, [
- "id",
- "attributes",
- ] as const).map((typesetter) => (
-
-
-
- ))}
-
-
- )}
-
- {isDefinedAndNotEmpty(selectedScan.notes) && (
-
-
-
- )}
-
-
-
- {pages.map((page, index) => (
-
{
- onClickOnImage(index);
- }}>
-
-
- ))}
-
-
- )}
- >
- );
-};
-
-// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
-
-export const TranslatedScanSet = ({
- translations,
- fallback,
- ...otherProps
-}: TranslatedProps): JSX.Element => {
- const [selectedTranslation] = useSmartLanguage({
- items: translations,
- languageExtractor: useCallback((item: { language: string }): string => item.language, []),
- });
-
- return ;
-};
diff --git a/src/pages/library/index.tsx b/src/pages/library/index.tsx
deleted file mode 100644
index 6476846..0000000
--- a/src/pages/library/index.tsx
+++ /dev/null
@@ -1,507 +0,0 @@
-import { GetStaticProps } from "next";
-import { useState, useMemo, useCallback } from "react";
-import { useBoolean } from "usehooks-ts";
-import naturalCompare from "string-natural-compare";
-import { AppLayout, AppLayoutRequired } from "components/AppLayout";
-import { Select } from "components/Inputs/Select";
-import { Switch } from "components/Inputs/Switch";
-import { PanelHeader } from "components/PanelComponents/PanelHeader";
-import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
-import { SubPanel } from "components/Containers/SubPanel";
-import { GetLibraryItemsPreviewQuery } from "graphql/generated";
-import { getReadySdk } from "graphql/sdk";
-import { prettyInlineTitle, prettyItemSubType } from "helpers/formatters";
-import { LibraryItemUserStatus } from "types/types";
-import { Icon } from "components/Ico";
-import { WithLabel } from "components/Inputs/WithLabel";
-import { TextInput } from "components/Inputs/TextInput";
-import { Button } from "components/Inputs/Button";
-import { PreviewCardCTAs } from "components/Library/PreviewCardCTAs";
-import { isUntangibleGroupItem } from "helpers/libraryItem";
-import { PreviewCard } from "components/PreviewCard";
-import { useDeviceSupportsHover } from "hooks/useMediaQuery";
-import { ButtonGroup } from "components/Inputs/ButtonGroup";
-import { filterHasAttributes, isDefined, isDefinedAndNotEmpty, isUndefined } from "helpers/others";
-import { convertPrice } from "helpers/numbers";
-import { SmartList } from "components/SmartList";
-import { SelectiveNonNullable } from "types/SelectiveNonNullable";
-import { getOpenGraph } from "helpers/openGraph";
-import { compareDate } from "helpers/date";
-import { HorizontalLine } from "components/HorizontalLine";
-import { cIf, cJoin } from "helpers/className";
-import { getLangui } from "graphql/fetchLocalData";
-import { sendAnalytics } from "helpers/analytics";
-import { atoms } from "contexts/atoms";
-import { useAtomGetter } from "helpers/atoms";
-import { useLibraryItemUserStatus } from "hooks/useLibraryItemUserStatus";
-
-/*
- * ╭─────────────╮
- * ────────────────────────────────────────╯ CONSTANTS ╰──────────────────────────────────────────
- */
-
-const DEFAULT_FILTERS_STATE = {
- searchName: "",
- showSubitems: false,
- showPrimaryItems: true,
- showSecondaryItems: false,
- sortingMethod: 0,
- groupingMethod: -1,
- keepInfoVisible: false,
- filterUserStatus: undefined,
-};
-
-/*
- * ╭────────╮
- * ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
- */
-
-interface Props extends AppLayoutRequired {
- items: NonNullable["data"];
-}
-
-const Library = ({ items, ...otherProps }: Props): JSX.Element => {
- const hoverable = useDeviceSupportsHover();
- const langui = useAtomGetter(atoms.localData.langui);
- const currencies = useAtomGetter(atoms.localData.currencies);
-
- const { libraryItemUserStatus } = useLibraryItemUserStatus();
- const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl);
-
- const [searchName, setSearchName] = useState(DEFAULT_FILTERS_STATE.searchName);
-
- const {
- value: showSubitems,
- toggle: toggleShowSubitems,
- setValue: setShowSubitems,
- } = useBoolean(DEFAULT_FILTERS_STATE.showSubitems);
-
- const {
- value: showPrimaryItems,
- toggle: toggleShowPrimaryItems,
- setValue: setShowPrimaryItems,
- } = useBoolean(DEFAULT_FILTERS_STATE.showPrimaryItems);
-
- const {
- value: showSecondaryItems,
- toggle: toggleShowSecondaryItems,
- setValue: setShowSecondaryItems,
- } = useBoolean(DEFAULT_FILTERS_STATE.showSecondaryItems);
-
- const {
- value: keepInfoVisible,
- toggle: toggleKeepInfoVisible,
- setValue: setKeepInfoVisible,
- } = useBoolean(DEFAULT_FILTERS_STATE.keepInfoVisible);
-
- const [sortingMethod, setSortingMethod] = useState(DEFAULT_FILTERS_STATE.sortingMethod);
-
- const [groupingMethod, setGroupingMethod] = useState(
- DEFAULT_FILTERS_STATE.groupingMethod
- );
-
- const [filterUserStatus, setFilterUserStatus] = useState(
- DEFAULT_FILTERS_STATE.filterUserStatus
- );
-
- const filteringFunction = useCallback(
- (item: SelectiveNonNullable) => {
- if (!showSubitems && !item.attributes.root_item) return false;
- if (showSubitems && isUntangibleGroupItem(item.attributes.metadata?.[0])) {
- return false;
- }
- if (item.attributes.primary && !showPrimaryItems) return false;
- if (!item.attributes.primary && !showSecondaryItems) return false;
-
- if (isDefined(filterUserStatus) && item.id) {
- if (isUntangibleGroupItem(item.attributes.metadata?.[0])) {
- return false;
- }
- if (filterUserStatus === LibraryItemUserStatus.None) {
- if (libraryItemUserStatus[item.id]) {
- return false;
- }
- } else if (filterUserStatus !== libraryItemUserStatus[item.id]) {
- return false;
- }
- }
- return true;
- },
- [libraryItemUserStatus, filterUserStatus, showPrimaryItems, showSecondaryItems, showSubitems]
- );
-
- const sortingFunction = useCallback(
- (
- a: SelectiveNonNullable,
- b: SelectiveNonNullable
- ) => {
- switch (sortingMethod) {
- case 0: {
- const titleA = prettyInlineTitle("", a.attributes.title, a.attributes.subtitle);
- const titleB = prettyInlineTitle("", b.attributes.title, b.attributes.subtitle);
- return naturalCompare(titleA, titleB);
- }
- case 1: {
- const priceA = a.attributes.price
- ? convertPrice(a.attributes.price, currencies[0])
- : Infinity;
- const priceB = b.attributes.price
- ? convertPrice(b.attributes.price, currencies[0])
- : Infinity;
- return priceA - priceB;
- }
- case 2: {
- return compareDate(a.attributes.release_date, b.attributes.release_date);
- }
- default:
- return 0;
- }
- },
- [currencies, sortingMethod]
- );
-
- const groupingFunction = useCallback(
- (item: SelectiveNonNullable): string[] => {
- switch (groupingMethod) {
- case 0: {
- const categories = filterHasAttributes(item.attributes.categories?.data, [
- "attributes",
- ] as const);
- if (categories.length > 0) {
- return categories.map((category) => category.attributes.name);
- }
- return [langui.no_category ?? "No category"];
- }
- case 1: {
- if (item.attributes.metadata && item.attributes.metadata.length > 0) {
- switch (item.attributes.metadata[0]?.__typename) {
- case "ComponentMetadataAudio":
- return [langui.audio ?? "Audio"];
- case "ComponentMetadataGame":
- return [langui.game ?? "Game"];
- case "ComponentMetadataBooks":
- return [langui.textual ?? "Textual"];
- case "ComponentMetadataVideo":
- return [langui.video ?? "Video"];
- case "ComponentMetadataOther":
- return [langui.other ?? "Other"];
- case "ComponentMetadataGroup": {
- switch (item.attributes.metadata[0]?.subitems_type?.data?.attributes?.slug) {
- case "audio":
- return [langui.audio ?? "Audio"];
- case "video":
- return [langui.video ?? "Video"];
- case "game":
- return [langui.game ?? "Game"];
- case "textual":
- return [langui.textual ?? "Textual"];
- case "mixed":
- return [langui.group ?? "Group"];
- default: {
- return [langui.no_type ?? "No type"];
- }
- }
- }
- default:
- return [langui.no_type ?? "No type"];
- }
- } else {
- return [langui.no_type ?? "No type"];
- }
- }
- case 2: {
- if (item.attributes.release_date?.year) {
- return [item.attributes.release_date.year.toString()];
- }
- return [langui.no_year ?? "No year"];
- }
- default:
- return [""];
- }
- },
- [groupingMethod, langui]
- );
-
- const subPanel = useMemo(
- () => (
-
-
-
-
-
- {
- setSearchName(name);
- if (isDefinedAndNotEmpty(name)) {
- sendAnalytics("Library", "Change search term");
- } else {
- sendAnalytics("Library", "Clear search term");
- }
- }}
- />
-
-
- {
- setGroupingMethod(value);
- sendAnalytics(
- "Library",
- `Change grouping method (${["none", "category", "type", "year"][value + 1]})`
- );
- }}
- allowEmpty
- />
-
-
-
- {
- setSortingMethod(value);
- sendAnalytics(
- "Library",
- `Change sorting method (${["name", "price", "release date"][value]})`
- );
- }}
- />
-
-
-
- {
- toggleShowSubitems();
- sendAnalytics("Library", `${showSubitems ? "Hide" : "Show"} subitems`);
- }}
- />
-
-
-
- {
- toggleShowPrimaryItems();
- sendAnalytics("Library", `${showPrimaryItems ? "Hide" : "Show"} primary items`);
- }}
- />
-
-
-
- {
- toggleShowSecondaryItems();
- sendAnalytics("Library", `${showSecondaryItems ? "Hide" : "Show"} secondary items`);
- }}
- />
-
-
- {hoverable && (
-
- {
- toggleKeepInfoVisible();
- sendAnalytics("Library", `Always ${keepInfoVisible ? "hide" : "show"} info`);
- }}
- />
-
- )}
-
- {
- setFilterUserStatus(LibraryItemUserStatus.Want);
- sendAnalytics("Library", "Set filter status (I want)");
- },
- active: filterUserStatus === LibraryItemUserStatus.Want,
- },
- {
- tooltip: langui.only_display_items_i_have,
- icon: Icon.BackHand,
- onClick: () => {
- setFilterUserStatus(LibraryItemUserStatus.Have);
- sendAnalytics("Library", "Set filter status (I have)");
- },
- active: filterUserStatus === LibraryItemUserStatus.Have,
- },
- {
- tooltip: langui.only_display_unmarked_items,
- icon: Icon.RadioButtonUnchecked,
- onClick: () => {
- setFilterUserStatus(LibraryItemUserStatus.None);
- sendAnalytics("Library", "Set filter status (unmarked)");
- },
- active: filterUserStatus === LibraryItemUserStatus.None,
- },
- {
- tooltip: langui.only_display_unmarked_items,
- text: langui.all,
- onClick: () => {
- setFilterUserStatus(undefined);
- sendAnalytics("Library", "Set filter status (all)");
- },
- active: isUndefined(filterUserStatus),
- },
- ]}
- />
-
- {
- setSearchName(DEFAULT_FILTERS_STATE.searchName);
- setShowSubitems(DEFAULT_FILTERS_STATE.showSubitems);
- setShowPrimaryItems(DEFAULT_FILTERS_STATE.showPrimaryItems);
- setShowSecondaryItems(DEFAULT_FILTERS_STATE.showSecondaryItems);
- setSortingMethod(DEFAULT_FILTERS_STATE.sortingMethod);
- setGroupingMethod(DEFAULT_FILTERS_STATE.groupingMethod);
- setKeepInfoVisible(DEFAULT_FILTERS_STATE.keepInfoVisible);
- setFilterUserStatus(DEFAULT_FILTERS_STATE.filterUserStatus);
- sendAnalytics("Library", "Reset all filters");
- }}
- />
-
- ),
- [
- filterUserStatus,
- groupingMethod,
- hoverable,
- keepInfoVisible,
- langui,
- searchName,
- setKeepInfoVisible,
- setShowPrimaryItems,
- setShowSecondaryItems,
- setShowSubitems,
- showPrimaryItems,
- showSecondaryItems,
- showSubitems,
- sortingMethod,
- toggleKeepInfoVisible,
- toggleShowPrimaryItems,
- toggleShowSecondaryItems,
- toggleShowSubitems,
- ]
- );
-
- const contentPanel = useMemo(
- () => (
-
- item.id}
- renderItem={({ item }) => (
- 0 &&
- item.attributes.metadata[0]
- ? [prettyItemSubType(item.attributes.metadata[0])]
- : []
- }
- bottomChips={item.attributes.categories?.data.map(
- (category) => category.attributes?.short ?? ""
- )}
- metadata={{
- releaseDate: item.attributes.release_date,
- price: item.attributes.price,
- position: "Bottom",
- }}
- infoAppend={
- !isUntangibleGroupItem(item.attributes.metadata?.[0]) && (
-
- )
- }
- />
- )}
- className={cJoin(
- "grid-cols-2 items-end",
- cIf(isContentPanelAtLeast4xl, "grid-cols-[repeat(auto-fill,_minmax(13rem,1fr))]")
- )}
- searchingTerm={searchName}
- sortingFunction={sortingFunction}
- groupingFunction={groupingFunction}
- searchingBy={(item) =>
- prettyInlineTitle("", item.attributes.title, item.attributes.subtitle)
- }
- filteringFunction={filteringFunction}
- paginationItemPerPage={25}
- />
-
- ),
- [
- filteringFunction,
- groupingFunction,
- isContentPanelAtLeast4xl,
- items,
- keepInfoVisible,
- searchName,
- sortingFunction,
- ]
- );
-
- return (
-
- );
-};
-export default Library;
-
-/*
- * ╭──────────────────────╮
- * ───────────────────────────────────╯ NEXT DATA FETCHING ╰──────────────────────────────────────
- */
-
-export const getStaticProps: GetStaticProps = async (context) => {
- const sdk = getReadySdk();
- const langui = getLangui(context.locale);
- const items = await sdk.getLibraryItemsPreview({
- language_code: context.locale ?? "en",
- });
- if (!items.libraryItems?.data) return { notFound: true };
-
- const props: Props = {
- items: items.libraryItems.data,
- openGraph: getOpenGraph(langui, langui.library ?? "Library"),
- };
- return {
- props: props,
- };
-};
diff --git a/src/pages/merch/index.tsx b/src/pages/merch/index.tsx
deleted file mode 100644
index 389efc7..0000000
--- a/src/pages/merch/index.tsx
+++ /dev/null
@@ -1,49 +0,0 @@
-import { GetStaticProps } from "next";
-import { AppLayout, AppLayoutRequired } from "components/AppLayout";
-import { PanelHeader } from "components/PanelComponents/PanelHeader";
-import { SubPanel } from "components/Containers/SubPanel";
-import { Icon } from "components/Ico";
-import { getOpenGraph } from "helpers/openGraph";
-import { getLangui } from "graphql/fetchLocalData";
-import { atoms } from "contexts/atoms";
-import { useAtomGetter } from "helpers/atoms";
-
-/*
- * ╭────────╮
- * ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
- */
-
-interface Props extends AppLayoutRequired {}
-const Merch = (props: Props): JSX.Element => {
- const langui = useAtomGetter(atoms.localData.langui);
- return (
-
-
-
- }
- {...props}
- />
- );
-};
-export default Merch;
-
-/*
- * ╭──────────────────────╮
- * ───────────────────────────────────╯ NEXT DATA FETCHING ╰──────────────────────────────────────
- */
-
-export const getStaticProps: GetStaticProps = (context) => {
- const langui = getLangui(context.locale);
- const props: Props = {
- openGraph: getOpenGraph(langui, langui.merch ?? "Merch"),
- };
- return {
- props: props,
- };
-};
diff --git a/src/pages/news/[slug].tsx b/src/pages/news/[slug].tsx
deleted file mode 100644
index 67bd2fa..0000000
--- a/src/pages/news/[slug].tsx
+++ /dev/null
@@ -1,103 +0,0 @@
-import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
-import { NextRouter, useRouter } from "next/router";
-import { PostPage } from "components/PostPage";
-import { getPostStaticProps, PostStaticProps } from "graphql/getPostStaticProps";
-import { getReadySdk } from "graphql/sdk";
-import { filterHasAttributes, isDefined, isDefinedAndNotEmpty } from "helpers/others";
-import { Terminal } from "components/Cli/Terminal";
-import { PostWithTranslations } from "types/types";
-import { getDefaultPreferredLanguages, staticSmartLanguage } from "helpers/locales";
-import { prettyTerminalBoxedTitle } from "helpers/terminal";
-import { prettyMarkdown } from "helpers/description";
-import { atoms } from "contexts/atoms";
-import { useAtomGetter } from "helpers/atoms";
-/*
- * ╭────────╮
- * ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
- */
-
-interface Props extends PostStaticProps {}
-
-const LibrarySlug = (props: Props): JSX.Element => {
- const langui = useAtomGetter(atoms.localData.langui);
- const isTerminalMode = useAtomGetter(atoms.layout.terminalMode);
- const router = useRouter();
-
- if (isTerminalMode) {
- return (
-
- );
- }
-
- return (
-
- );
-};
-export default LibrarySlug;
-
-/*
- * ╭──────────────────────╮
- * ───────────────────────────────────╯ NEXT DATA FETCHING ╰──────────────────────────────────────
- */
-
-export const getStaticProps: GetStaticProps = async (context) => {
- const slug =
- context.params && isDefined(context.params.slug) ? context.params.slug.toString() : "";
- return await getPostStaticProps(slug)(context);
-};
-
-// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
-
-export const getStaticPaths: GetStaticPaths = async (context) => {
- const sdk = getReadySdk();
- const posts = await sdk.getPostsSlugs();
- const paths: GetStaticPathsResult["paths"] = [];
-
- filterHasAttributes(posts.posts?.data, ["attributes"] as const).map((item) => {
- context.locales?.map((local) =>
- paths.push({ params: { slug: item.attributes.slug }, locale: local })
- );
- });
- return {
- paths,
- fallback: "blocking",
- };
-};
-
-const terminalPostPage = (post: PostWithTranslations, router: NextRouter): string => {
- let result = "";
- if (router.locales && router.locale) {
- const selectedTranslation = staticSmartLanguage({
- items: filterHasAttributes(post.translations, ["language.data.attributes.code"] as const),
- languageExtractor: (item) => item.language.data.attributes.code,
- preferredLanguages: getDefaultPreferredLanguages(router.locale, router.locales),
- });
-
- if (selectedTranslation) {
- result += prettyTerminalBoxedTitle(selectedTranslation.title);
- if (isDefinedAndNotEmpty(selectedTranslation.excerpt)) {
- result += "\n\n";
- result += prettyMarkdown(selectedTranslation.excerpt);
- }
- if (isDefinedAndNotEmpty(selectedTranslation.body)) {
- result += "\n\n";
- result += prettyMarkdown(selectedTranslation.body);
- }
- }
- }
-
- result += "\n\n";
-
- return result;
-};
diff --git a/src/pages/news/index.tsx b/src/pages/news/index.tsx
deleted file mode 100644
index 9eb8523..0000000
--- a/src/pages/news/index.tsx
+++ /dev/null
@@ -1,206 +0,0 @@
-import { GetStaticProps } from "next";
-import { useMemo, useState } from "react";
-import { useBoolean } from "usehooks-ts";
-import { AppLayout, AppLayoutRequired } from "components/AppLayout";
-import { Switch } from "components/Inputs/Switch";
-import { PanelHeader } from "components/PanelComponents/PanelHeader";
-import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
-import { SubPanel } from "components/Containers/SubPanel";
-import { GetPostsPreviewQuery } from "graphql/generated";
-import { getReadySdk } from "graphql/sdk";
-import { prettySlug } from "helpers/formatters";
-import { Icon } from "components/Ico";
-import { WithLabel } from "components/Inputs/WithLabel";
-import { TextInput } from "components/Inputs/TextInput";
-import { Button } from "components/Inputs/Button";
-import { useDeviceSupportsHover } from "hooks/useMediaQuery";
-import { filterHasAttributes, isDefinedAndNotEmpty } from "helpers/others";
-import { SmartList } from "components/SmartList";
-import { getOpenGraph } from "helpers/openGraph";
-import { compareDate } from "helpers/date";
-import { TranslatedPreviewCard } from "components/PreviewCard";
-import { HorizontalLine } from "components/HorizontalLine";
-import { cIf } from "helpers/className";
-import { getLangui } from "graphql/fetchLocalData";
-import { sendAnalytics } from "helpers/analytics";
-import { Terminal } from "components/Cli/Terminal";
-import { atoms } from "contexts/atoms";
-import { useAtomGetter } from "helpers/atoms";
-
-/*
- * ╭─────────────╮
- * ────────────────────────────────────────╯ CONSTANTS ╰──────────────────────────────────────────
- */
-
-const DEFAULT_FILTERS_STATE = {
- searchName: "",
- keepInfoVisible: true,
-};
-
-/*
- * ╭────────╮
- * ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
- */
-
-interface Props extends AppLayoutRequired {
- posts: NonNullable["data"];
-}
-
-const News = ({ posts, ...otherProps }: Props): JSX.Element => {
- const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl);
- const langui = useAtomGetter(atoms.localData.langui);
- const hoverable = useDeviceSupportsHover();
- const [searchName, setSearchName] = useState(DEFAULT_FILTERS_STATE.searchName);
- const {
- value: keepInfoVisible,
- toggle: toggleKeepInfoVisible,
- setValue: setKeepInfoVisible,
- } = useBoolean(DEFAULT_FILTERS_STATE.keepInfoVisible);
- const isTerminalMode = useAtomGetter(atoms.layout.terminalMode);
-
- const subPanel = useMemo(
- () => (
-
-
-
-
-
- {
- setSearchName(name);
- if (isDefinedAndNotEmpty(name)) {
- sendAnalytics("News", "Change search term");
- } else {
- sendAnalytics("News", "Clear search term");
- }
- }}
- />
-
- {hoverable && (
-
- {
- toggleKeepInfoVisible();
- sendAnalytics("News", `Always ${keepInfoVisible ? "hide" : "show"} info`);
- }}
- />
-
- )}
-
- {
- setSearchName(DEFAULT_FILTERS_STATE.searchName);
- setKeepInfoVisible(DEFAULT_FILTERS_STATE.keepInfoVisible);
- sendAnalytics("News", "Reset all filters");
- }}
- />
-
- ),
- [hoverable, keepInfoVisible, langui, searchName, setKeepInfoVisible, toggleKeepInfoVisible]
- );
-
- const contentPanel = useMemo(
- () => (
-
- post.id}
- renderItem={({ item: post }) => (
- ({
- language: translation.language.data.attributes.code,
- title: translation.title,
- description: translation.excerpt,
- }))}
- fallback={{ title: prettySlug(post.attributes.slug) }}
- thumbnail={post.attributes.thumbnail?.data?.attributes}
- thumbnailAspectRatio="3/2"
- thumbnailForceAspectRatio
- bottomChips={post.attributes.categories?.data.map(
- (category) => category.attributes?.short ?? ""
- )}
- keepInfoVisible={keepInfoVisible}
- metadata={{
- releaseDate: post.attributes.date,
- releaseDateFormat: "long",
- position: "Top",
- }}
- />
- )}
- className={cIf(
- isContentPanelAtLeast4xl,
- "grid-cols-[repeat(auto-fill,_minmax(15rem,1fr))] gap-x-6 gap-y-8",
- "grid-cols-2 gap-x-4 gap-y-6"
- )}
- searchingTerm={searchName}
- searchingBy={(post) =>
- `${prettySlug(post.attributes.slug)} ${post.attributes.translations
- ?.map((translation) => translation?.title)
- .join(" ")}`
- }
- paginationItemPerPage={25}
- />
-
- ),
- [keepInfoVisible, posts, searchName, isContentPanelAtLeast4xl]
- );
-
- if (isTerminalMode) {
- return (
- post.attributes.slug
- )}
- />
- );
- }
-
- return (
-
- );
-};
-export default News;
-
-/*
- * ╭──────────────────────╮
- * ───────────────────────────────────╯ NEXT DATA FETCHING ╰──────────────────────────────────────
- */
-
-export const getStaticProps: GetStaticProps = async (context) => {
- const sdk = getReadySdk();
- const langui = getLangui(context.locale);
- const posts = await sdk.getPostsPreview();
- if (!posts.posts) return { notFound: true };
-
- const props: Props = {
- posts: sortPosts(posts.posts.data),
- openGraph: getOpenGraph(langui, langui.news ?? "News"),
- };
- return {
- props: props,
- };
-};
-
-/*
- * ╭───────────────────╮
- * ─────────────────────────────────────╯ PRIVATE METHODS ╰───────────────────────────────────────
- */
-
-const sortPosts = (posts: Props["posts"]): Props["posts"] =>
- posts.sort((a, b) => compareDate(a.attributes?.date, b.attributes?.date)).reverse();
diff --git a/src/pages/wiki/[slug]/index.tsx b/src/pages/wiki/[slug]/index.tsx
deleted file mode 100644
index 3781a76..0000000
--- a/src/pages/wiki/[slug]/index.tsx
+++ /dev/null
@@ -1,318 +0,0 @@
-import { useCallback, useMemo } from "react";
-import { GetStaticPaths, GetStaticPathsResult, GetStaticProps } from "next";
-import { useRouter } from "next/router";
-import { AppLayout, AppLayoutRequired } from "components/AppLayout";
-import { Chip } from "components/Chip";
-import { HorizontalLine } from "components/HorizontalLine";
-import { Img } from "components/Img";
-import { ReturnButton } from "components/PanelComponents/ReturnButton";
-import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
-import { SubPanel } from "components/Containers/SubPanel";
-import DefinitionCard from "components/Wiki/DefinitionCard";
-import { getReadySdk } from "graphql/sdk";
-import { filterHasAttributes, isDefined, isDefinedAndNotEmpty } from "helpers/others";
-import { WikiPageWithTranslations } from "types/types";
-import { useSmartLanguage } from "hooks/useSmartLanguage";
-import { prettySlug, sJoin } from "helpers/formatters";
-import { ImageQuality } from "helpers/img";
-import { getOpenGraph } from "helpers/openGraph";
-import { getDefaultPreferredLanguages, staticSmartLanguage } from "helpers/locales";
-import { getDescription } from "helpers/description";
-import { cIf, cJoin } from "helpers/className";
-import { getLangui } from "graphql/fetchLocalData";
-import { Terminal } from "components/Cli/Terminal";
-import { prettyTerminalBoxedTitle, prettyTerminalUnderlinedTitle } from "helpers/terminal";
-import { atoms } from "contexts/atoms";
-import { useAtomGetter } from "helpers/atoms";
-
-/*
- * ╭────────╮
- * ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
- */
-
-interface Props extends AppLayoutRequired {
- page: WikiPageWithTranslations;
-}
-
-const WikiPage = ({ page, ...otherProps }: Props): JSX.Element => {
- const langui = useAtomGetter(atoms.localData.langui);
- const router = useRouter();
- const isTerminalMode = useAtomGetter(atoms.layout.terminalMode);
- const { showLightBox } = useAtomGetter(atoms.lightBox);
- const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] = useSmartLanguage({
- items: page.translations,
- languageExtractor: useCallback(
- (item: NonNullable) =>
- item.language?.data?.attributes?.code,
- []
- ),
- });
- const is3ColumnsLayout = useAtomGetter(atoms.containerQueries.is3ColumnsLayout);
-
- const subPanel = useMemo(
- () => (
-
-
-
- ),
- [langui]
- );
-
- const contentPanel = useMemo(
- () => (
-
-
-
-
-
{selectedTranslation?.title}
- {selectedTranslation?.aliases && selectedTranslation.aliases.length > 0 && (
-
- {`(${selectedTranslation.aliases.map((alias) => alias?.alias).join("・")})`}
-
- )}
-
-
-
- {selectedTranslation && (
- <>
-
-
-
- {page.thumbnail?.data?.attributes && (
-
{
- if (page.thumbnail?.data?.attributes) {
- showLightBox([page.thumbnail.data.attributes]);
- }
- }}
- />
- )}
-
- {page.categories?.data && page.categories.data.length > 0 && (
- <>
-
{langui.categories}
-
-
- {filterHasAttributes(page.categories.data, ["attributes"] as const).map(
- (category) => (
-
- )
- )}
-
- >
- )}
-
- {page.tags?.data && page.tags.data.length > 0 && (
- <>
-
{langui.tags}
-
- {filterHasAttributes(page.tags.data, ["attributes"] as const).map((tag) => (
-
- ))}
-
- >
- )}
-
-
-
- {isDefinedAndNotEmpty(selectedTranslation.summary) && (
-
-
{langui.summary}
-
{selectedTranslation.summary}
-
- )}
-
- {filterHasAttributes(page.definitions, ["translations"] as const).map(
- (definition, index) => (
-
- ({
- language: translation?.language?.data?.attributes?.code,
- definition: translation?.definition,
- status: translation?.status,
- }))}
- index={index + 1}
- categories={filterHasAttributes(definition.categories?.data, [
- "attributes",
- ] as const).map((category) => category.attributes.short)}
- />
-
- )
- )}
-
- >
- )}
-
- ),
- [
- LanguageSwitcher,
- is3ColumnsLayout,
- languageSwitcherProps,
- langui.categories,
- langui.summary,
- langui.tags,
- langui.wiki,
- page.categories?.data,
- page.definitions,
- page.tags?.data,
- page.thumbnail?.data?.attributes,
- selectedTranslation,
- showLightBox,
- ]
- );
-
- if (isTerminalMode) {
- return (
- 0
- ? ` (${selectedTranslation.aliases.map((alias) => alias?.alias).join(", ")})`
- : ""
- }`
- )}${
- isDefinedAndNotEmpty(selectedTranslation?.summary)
- ? `${prettyTerminalUnderlinedTitle(langui.summary)}${selectedTranslation?.summary}`
- : ""
- }${
- page.definitions && page.definitions.length > 0
- ? `${filterHasAttributes(page.definitions, ["translations"] as const).map(
- (definition, index) =>
- `${prettyTerminalUnderlinedTitle(`${langui.definition} ${index + 1}`)}${
- staticSmartLanguage({
- items: filterHasAttributes(definition.translations, [
- "language.data.attributes.code",
- ] as const),
- languageExtractor: (item) => item.language.data.attributes.code,
- preferredLanguages: getDefaultPreferredLanguages(
- router.locale ?? "en",
- router.locales ?? ["en"]
- ),
- })?.definition
- }`
- )}`
- : ""
- }${
- isDefinedAndNotEmpty(selectedTranslation?.body?.body)
- ? `\n\n${selectedTranslation?.body?.body}`
- : "\n"
- }`}
- />
- );
- }
-
- return ;
-};
-export default WikiPage;
-
-/*
- * ╭──────────────────────╮
- * ───────────────────────────────────╯ NEXT DATA FETCHING ╰──────────────────────────────────────
- */
-
-export const getStaticProps: GetStaticProps = async (context) => {
- const sdk = getReadySdk();
- const langui = getLangui(context.locale);
- const slug =
- context.params && isDefined(context.params.slug) ? context.params.slug.toString() : "";
- const page = await sdk.getWikiPage({
- language_code: context.locale ?? "en",
- slug: slug,
- });
- if (!page.wikiPages?.data[0]?.attributes?.translations) return { notFound: true };
-
- const { title, description } = (() => {
- const chipsGroups = {
- [langui.tags ?? "Tags"]: filterHasAttributes(page.wikiPages.data[0].attributes.tags?.data, [
- "attributes",
- ] as const).map(
- (tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)
- ),
- [langui.categories ?? "Categories"]: filterHasAttributes(
- page.wikiPages.data[0].attributes.categories?.data,
- ["attributes"] as const
- ).map((category) => category.attributes.short),
- };
-
- if (context.locale && context.locales) {
- const selectedTranslation = staticSmartLanguage({
- items: page.wikiPages.data[0].attributes.translations,
- languageExtractor: (item) => item.language?.data?.attributes?.code,
- preferredLanguages: getDefaultPreferredLanguages(context.locale, context.locales),
- });
- if (selectedTranslation) {
- return {
- title: selectedTranslation.title,
- description: getDescription(selectedTranslation.summary, chipsGroups),
- };
- }
- }
-
- return {
- title: prettySlug(page.wikiPages.data[0].attributes.slug),
- description: getDescription(undefined, chipsGroups),
- };
- })();
-
- const thumbnail = page.wikiPages.data[0].attributes.thumbnail?.data?.attributes;
-
- const props: Props = {
- page: page.wikiPages.data[0].attributes as WikiPageWithTranslations,
- openGraph: getOpenGraph(langui, title, description, thumbnail),
- };
- return {
- props: props,
- };
-};
-
-// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
-
-export const getStaticPaths: GetStaticPaths = async (context) => {
- const sdk = getReadySdk();
- const contents = await sdk.getWikiPagesSlugs();
- const paths: GetStaticPathsResult["paths"] = [];
- filterHasAttributes(contents.wikiPages?.data, ["attributes"] as const).map((wikiPage) => {
- context.locales?.map((local) =>
- paths.push({
- params: { slug: wikiPage.attributes.slug },
- locale: local,
- })
- );
- });
- return {
- paths,
- fallback: "blocking",
- };
-};
diff --git a/src/pages/wiki/chronology.tsx b/src/pages/wiki/chronology.tsx
deleted file mode 100644
index d164917..0000000
--- a/src/pages/wiki/chronology.tsx
+++ /dev/null
@@ -1,393 +0,0 @@
-import { GetStaticProps } from "next";
-import { Fragment, useCallback, useMemo } from "react";
-import { useRouter } from "next/router";
-import { AppLayout, AppLayoutRequired } from "components/AppLayout";
-import { InsetBox } from "components/Containers/InsetBox";
-import { ReturnButton } from "components/PanelComponents/ReturnButton";
-import { ContentPanel } from "components/Containers/ContentPanel";
-import { SubPanel } from "components/Containers/SubPanel";
-import {
- Enum_Componenttranslationschronologyitem_Status,
- GetChronologyItemsQuery,
- GetErasQuery,
-} from "graphql/generated";
-import { getReadySdk } from "graphql/sdk";
-import { prettySlug } from "helpers/formatters";
-import {
- filterHasAttributes,
- getStatusDescription,
- isDefined,
- isDefinedAndNotEmpty,
-} from "helpers/others";
-import { getOpenGraph } from "helpers/openGraph";
-import { useSmartLanguage } from "hooks/useSmartLanguage";
-import { ToolTip } from "components/ToolTip";
-import { Chip } from "components/Chip";
-import { Ico, Icon } from "components/Ico";
-import { AnchorShare } from "components/AnchorShare";
-import { datePickerToDate } from "helpers/date";
-import { TranslatedProps } from "types/TranslatedProps";
-import { TranslatedNavOption } from "components/PanelComponents/NavOption";
-import { useIntersectionList } from "hooks/useIntersectionList";
-import { HorizontalLine } from "components/HorizontalLine";
-import { getLangui } from "graphql/fetchLocalData";
-import { atoms } from "contexts/atoms";
-import { useAtomGetter } from "helpers/atoms";
-
-/*
- * ╭────────╮
- * ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
- */
-
-interface Props extends AppLayoutRequired {
- chronologyItems: NonNullable["data"];
- chronologyEras: NonNullable["data"];
-}
-
-const Chronology = ({ chronologyItems, chronologyEras, ...otherProps }: Props): JSX.Element => {
- const langui = useAtomGetter(atoms.localData.langui);
- const ids = useMemo(
- () =>
- filterHasAttributes(chronologyEras, ["attributes"] as const).map(
- (era) => era.attributes.slug
- ),
- [chronologyEras]
- );
-
- const currentIntersection = useIntersectionList(ids);
-
- const subPanel = useMemo(
- () => (
-
-
-
-
-
- {filterHasAttributes(chronologyEras, ["attributes", "id"] as const).map((era, index) => (
-
- ({
- language: translation.language.data.attributes.code,
- title: translation.title,
- subtitle: `${era.attributes.starting_year} → ${era.attributes.ending_year}`,
- }))}
- fallback={{
- title: prettySlug(era.attributes.slug),
- subtitle: `${era.attributes.starting_year} → ${era.attributes.ending_year}`,
- }}
- url={`#${era.attributes.slug}`}
- border
- active={currentIntersection === index}
- />
-
- ))}
-
- ),
- [chronologyEras, currentIntersection, langui]
- );
-
- const contentPanel = useMemo(
- () => (
-
-
-
- {filterHasAttributes(chronologyEras, ["attributes"] as const).map((era) => (
- ({
- language: translation.language.data.attributes.code,
- title: translation.title,
- description: translation.description,
- }))}
- fallback={{ title: prettySlug(era.attributes.slug) }}
- chronologyItems={filterHasAttributes(chronologyItems, ["attributes"] as const).filter(
- (item) =>
- item.attributes.year >= era.attributes.starting_year &&
- item.attributes.year < era.attributes.ending_year
- )}
- />
- ))}
-
- ),
- [chronologyEras, chronologyItems, langui]
- );
-
- return ;
-};
-export default Chronology;
-
-/*
- * ╭──────────────────────╮
- * ───────────────────────────────────╯ NEXT DATA FETCHING ╰──────────────────────────────────────
- */
-
-export const getStaticProps: GetStaticProps = async (context) => {
- const sdk = getReadySdk();
- const langui = getLangui(context.locale);
- const chronologyItems = await sdk.getChronologyItems();
- const chronologyEras = await sdk.getEras();
- if (!chronologyItems.chronologyItems || !chronologyEras.chronologyEras) return { notFound: true };
-
- const props: Props = {
- chronologyItems: chronologyItems.chronologyItems.data,
- chronologyEras: chronologyEras.chronologyEras.data,
- openGraph: getOpenGraph(langui, langui.chronology ?? "Chronology"),
- };
- return {
- props: props,
- };
-};
-
-/*
- * ╭──────────────────────╮
- * ───────────────────────────────────╯ PRIVATE COMPONENTS ╰──────────────────────────────────────
- */
-
-interface ChronologyEraProps {
- id: string;
- title: string;
- description?: string | null | undefined;
- chronologyItems: Props["chronologyItems"];
-}
-
-const ChronologyEra = ({ id, title, description, chronologyItems }: ChronologyEraProps) => {
- const yearGroups = useMemo(() => {
- const memo: Props["chronologyItems"][] = [];
- let currentYear = -Infinity;
- filterHasAttributes(chronologyItems, ["attributes"] as const).forEach((item) => {
- if (currentYear === item.attributes.year) {
- memo[memo.length - 1].push(item);
- } else {
- currentYear = item.attributes.year;
- memo.push([item]);
- }
- });
- return memo;
- }, [chronologyItems]);
-
- return (
-
-
-
- {title}
-
-
-
- {isDefinedAndNotEmpty(description) && {description}
}
-
-
- {yearGroups.map((item, index) => (
-
- ))}
-
-
- );
-};
-
-// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
-
-const TranslatedChronologyEra = ({
- translations,
- fallback,
- ...otherProps
-}: TranslatedProps[0], "description" | "title">): JSX.Element => {
- const [selectedTranslation] = useSmartLanguage({
- items: translations,
- languageExtractor: (item: { language: string }): string => item.language,
- });
-
- return (
-
- );
-};
-
-// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
-
-interface ChronologyYearProps {
- items: NonNullable;
-}
-
-const ChronologyYear = ({ items }: ChronologyYearProps) => (
-
- {filterHasAttributes(items, ["attributes.events"] as const).map((item, index) => (
-
- ))}
-
-);
-
-// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
-
-interface ChronologyDateProps {
- date: {
- year: number;
- month: number | null | undefined;
- day: number | null | undefined;
- displayYear: boolean;
- overwriteYear?: string | null | undefined;
- };
- events: NonNullable<
- NonNullable[number]["attributes"]>["events"]
- >;
-}
-
-export const ChronologyDate = ({ date, events }: ChronologyDateProps): JSX.Element => {
- const router = useRouter();
- return (
-
- {date.displayYear && (
-
- {isDefinedAndNotEmpty(date.overwriteYear) ? date.overwriteYear : date.year}
-
- )}
-
-
- {isDefined(date.month)
- ? isDefined(date.day)
- ? datePickerToDate({
- year: date.year,
- month: date.month,
- day: date.day,
- }).toLocaleDateString(router.locale, {
- month: "short",
- day: "numeric",
- })
- : datePickerToDate({
- year: date.year,
- month: date.month,
- day: date.day,
- }).toLocaleDateString(router.locale, {
- month: "short",
- })
- : ""}
-
-
-
- {filterHasAttributes(events, ["id", "translations"] as const).map((event) => (
-
- ))}
-
-
- );
-};
-
-// ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─
-
-interface ChronologyEventProps {
- event: NonNullable<
- NonNullable<
- NonNullable[number]["attributes"]>["events"]
- >[number]
- >;
-
- id: string;
-}
-
-export const ChronologyEvent = ({ event, id }: ChronologyEventProps): JSX.Element => {
- const langui = useAtomGetter(atoms.localData.langui);
- const [selectedTranslation, LanguageSwitcher, languageSwitcherProps] = useSmartLanguage({
- items: event.translations ?? [],
- languageExtractor: useCallback(
- (item: NonNullable[number]) =>
- item?.language?.data?.attributes?.code,
- []
- ),
- });
-
- return (
-
- {selectedTranslation && (
- <>
-
-
-
- {selectedTranslation.status !==
- Enum_Componenttranslationschronologyitem_Status.Done && (
-
-
-
- )}
-
-
- {event.source?.data ? (
- `(${event.source.data.attributes?.name})`
- ) : (
-
-
- {langui.no_source_warning}
-
- )}
-
-
-
-
-
-
-
- {selectedTranslation.title && (
-
-
{selectedTranslation.title}
-
- )}
-
- {selectedTranslation.description && (
-
{selectedTranslation.description}
- )}
-
- {selectedTranslation.note &&
{`${langui.notes}: ${selectedTranslation.note}`} }
- >
- )}
-
- );
-};
-
-/*
- * ╭───────────────────╮
- * ─────────────────────────────────────╯ PRIVATE METHODS ╰───────────────────────────────────────
- */
-
-const generateAnchor = (
- year: number | undefined,
- month?: number | null | undefined,
- day?: number | null | undefined
-): string => {
- let result = "";
- if (isDefined(year)) result += year;
- if (isDefined(month)) result += `-${month.toString().padStart(2, "0")}`;
- if (isDefined(day)) result += `-${day.toString().padStart(2, "0")}`;
- return result;
-};
diff --git a/src/pages/wiki/index.tsx b/src/pages/wiki/index.tsx
deleted file mode 100644
index 86f4b09..0000000
--- a/src/pages/wiki/index.tsx
+++ /dev/null
@@ -1,289 +0,0 @@
-import { GetStaticProps } from "next";
-import { useCallback, useMemo, useState } from "react";
-import { useBoolean } from "usehooks-ts";
-import { AppLayout, AppLayoutRequired } from "components/AppLayout";
-import { NavOption } from "components/PanelComponents/NavOption";
-import { PanelHeader } from "components/PanelComponents/PanelHeader";
-import { SubPanel } from "components/Containers/SubPanel";
-import { Icon } from "components/Ico";
-import { getReadySdk } from "graphql/sdk";
-import { GetWikiPageQuery, GetWikiPagesPreviewsQuery } from "graphql/generated";
-import { ContentPanel, ContentPanelWidthSizes } from "components/Containers/ContentPanel";
-import { HorizontalLine } from "components/HorizontalLine";
-import { Button } from "components/Inputs/Button";
-import { Switch } from "components/Inputs/Switch";
-import { TextInput } from "components/Inputs/TextInput";
-import { WithLabel } from "components/Inputs/WithLabel";
-import { useDeviceSupportsHover } from "hooks/useMediaQuery";
-import { filterDefined, filterHasAttributes, isDefinedAndNotEmpty } from "helpers/others";
-import { SmartList } from "components/SmartList";
-import { Select } from "components/Inputs/Select";
-import { SelectiveNonNullable } from "types/SelectiveNonNullable";
-import { prettySlug } from "helpers/formatters";
-import { getOpenGraph } from "helpers/openGraph";
-import { TranslatedPreviewCard } from "components/PreviewCard";
-import { cIf } from "helpers/className";
-import { getLangui } from "graphql/fetchLocalData";
-import { sendAnalytics } from "helpers/analytics";
-import { Terminal } from "components/Cli/Terminal";
-import { atoms } from "contexts/atoms";
-import { useAtomGetter } from "helpers/atoms";
-
-/*
- * ╭─────────────╮
- * ────────────────────────────────────────╯ CONSTANTS ╰──────────────────────────────────────────
- */
-
-const DEFAULT_FILTERS_STATE = {
- searchName: "",
- keepInfoVisible: true,
- groupingMethod: -1,
-};
-
-/*
- * ╭────────╮
- * ──────────────────────────────────────────╯ PAGE ╰─────────────────────────────────────────────
- */
-
-interface Props extends AppLayoutRequired {
- pages: NonNullable["data"];
-}
-
-const Wiki = ({ pages, ...otherProps }: Props): JSX.Element => {
- const hoverable = useDeviceSupportsHover();
- const langui = useAtomGetter(atoms.localData.langui);
- const isContentPanelAtLeast4xl = useAtomGetter(atoms.containerQueries.isContentPanelAtLeast4xl);
- const isTerminalMode = useAtomGetter(atoms.layout.terminalMode);
-
- const [searchName, setSearchName] = useState(DEFAULT_FILTERS_STATE.searchName);
-
- const [groupingMethod, setGroupingMethod] = useState(
- DEFAULT_FILTERS_STATE.groupingMethod
- );
-
- const {
- value: keepInfoVisible,
- toggle: toggleKeepInfoVisible,
- setValue: setKeepInfoVisible,
- } = useBoolean(DEFAULT_FILTERS_STATE.keepInfoVisible);
-
- const subPanel = useMemo(
- () => (
-
-
-
-
-
- {
- setSearchName(name);
- if (isDefinedAndNotEmpty(name)) {
- sendAnalytics("Wiki", "Change search term");
- } else {
- sendAnalytics("Wiki", "Clear search term");
- }
- }}
- />
-
-
- {
- setGroupingMethod(value);
- sendAnalytics("Wiki", `Change grouping method (${["none", "category"][value + 1]})`);
- }}
- allowEmpty
- />
-
-
- {hoverable && (
-
- {
- toggleKeepInfoVisible();
- sendAnalytics("Wiki", `Always ${keepInfoVisible ? "hide" : "show"} info`);
- }}
- />
-
- )}
-
- {
- setSearchName(DEFAULT_FILTERS_STATE.searchName);
- setGroupingMethod(DEFAULT_FILTERS_STATE.groupingMethod);
- setKeepInfoVisible(DEFAULT_FILTERS_STATE.keepInfoVisible);
- sendAnalytics("Wiki", "Reset all filters");
- }}
- />
-
-
-
- {langui.special_pages}
-
-
-
- ),
- [
- groupingMethod,
- hoverable,
- keepInfoVisible,
- langui,
- searchName,
- setKeepInfoVisible,
- toggleKeepInfoVisible,
- ]
- );
-
- const groupingFunction = useCallback(
- (
- item: SelectiveNonNullable<
- NonNullable["data"][number],
- "attributes" | "id"
- >
- ): string[] => {
- switch (groupingMethod) {
- case 0: {
- const categories = filterHasAttributes(item.attributes.categories?.data, [
- "attributes",
- ] as const);
- if (categories.length > 0) {
- return categories.map((category) => category.attributes.name);
- }
- return [langui.no_category ?? "No category"];
- }
- default: {
- return [""];
- }
- }
- },
- [groupingMethod, langui]
- );
-
- const contentPanel = useMemo(
- () => (
-
- item.id}
- renderItem={({ item }) => (
- ({
- title: translation.title,
- subtitle:
- translation.aliases && translation.aliases.length > 0
- ? translation.aliases.map((alias) => alias?.alias).join("・")
- : undefined,
- description: translation.summary,
- language: translation.language.data.attributes.code,
- }))}
- fallback={{ title: prettySlug(item.attributes.slug) }}
- thumbnail={item.attributes.thumbnail?.data?.attributes}
- thumbnailAspectRatio={"4/3"}
- thumbnailRounded
- thumbnailForceAspectRatio
- keepInfoVisible={keepInfoVisible}
- topChips={filterHasAttributes(item.attributes.tags?.data, [
- "attributes",
- ] as const).map(
- (tag) => tag.attributes.titles?.[0]?.title ?? prettySlug(tag.attributes.slug)
- )}
- bottomChips={filterHasAttributes(item.attributes.categories?.data, [
- "attributes",
- ] as const).map((category) => category.attributes.short)}
- />
- )}
- className={cIf(
- isContentPanelAtLeast4xl,
- "grid-cols-[repeat(auto-fill,minmax(15rem,1fr))] gap-x-6 gap-y-8",
- "grid-cols-2 gap-x-3 gap-y-5"
- )}
- searchingTerm={searchName}
- searchingBy={(item) =>
- filterDefined(item.attributes.translations)
- .map(
- (translation) =>
- `${translation.title} ${filterDefined(translation.aliases)
- .map((alias) => alias.alias)
- .join(" ")}`
- )
- .join(" ")
- }
- groupingFunction={groupingFunction}
- paginationItemPerPage={25}
- />
-
- ),
- [groupingFunction, keepInfoVisible, pages, searchName, isContentPanelAtLeast4xl]
- );
-
- if (isTerminalMode) {
- return (
- page.attributes.slug
- )}
- />
- );
- }
-
- return (
-
- );
-};
-export default Wiki;
-
-/*
- * ╭──────────────────────╮
- * ───────────────────────────────────╯ NEXT DATA FETCHING ╰──────────────────────────────────────
- */
-
-export const getStaticProps: GetStaticProps = async (context) => {
- const sdk = getReadySdk();
- const langui = getLangui(context.locale);
- const pages = await sdk.getWikiPagesPreviews({
- language_code: context.locale ?? "en",
- });
- if (!pages.wikiPages?.data) return { notFound: true };
-
- const props: Props = {
- pages: sortPages(pages.wikiPages.data),
- openGraph: getOpenGraph(langui, langui.wiki ?? "Wiki"),
- };
- return {
- props: props,
- };
-};
-
-/*
- * ╭───────────────────╮
- * ─────────────────────────────────────╯ PRIVATE METHODS ╰───────────────────────────────────────
- */
-
-const sortPages = (pages: Props["pages"]): Props["pages"] =>
- pages.sort((a, b) => {
- const slugA = a.attributes?.slug ?? "";
- const slugB = b.attributes?.slug ?? "";
- return slugA.localeCompare(slugB);
- });
diff --git a/src/styles/others.css b/src/styles/others.css
index 354d548..7270abc 100644
--- a/src/styles/others.css
+++ b/src/styles/others.css
@@ -2,10 +2,6 @@
@tailwind components;
@tailwind utilities;
-#__next {
- @apply bg-light font-body font-medium text-black;
-}
-
* {
@apply box-border scroll-m-[40vh] scroll-smooth scrollbar-thin ![-webkit-tap-highlight-color:transparent];
}
diff --git a/src/types/next.d.ts b/src/types/next.d.ts
new file mode 100644
index 0000000..e8e2db6
--- /dev/null
+++ b/src/types/next.d.ts
@@ -0,0 +1,20 @@
+export {};
+
+declare global {
+ type Params = Record;
+ type SearchParams = Record;
+
+ type Layout = (props: { children: React.ReactNode; params: Params }) => JSX.Element;
+ type Template = Layout;
+
+ type Page = (props: { params: Params; searchParams: SearchParams }) => JSX.Element;
+
+ type Loading = () => JSX.Element;
+ type NotFound = () => Loading;
+
+ type Head = (props: { params: Params }) => JSX.Element;
+
+ type Error = (props: { error: Error; reset: () => void }) => JSX.Element;
+
+ type GenerateStaticParams = () => Record[];
+}
diff --git a/tsconfig.json b/tsconfig.json
index 5fb3c5d..f0083d6 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,7 +1,11 @@
{
"compilerOptions": {
"target": "ES6",
- "lib": ["dom", "dom.iterable", "esnext"],
+ "lib": [
+ "dom",
+ "dom.iterable",
+ "esnext"
+ ],
"importHelpers": true,
"allowJs": true,
"skipLibCheck": true,
@@ -17,7 +21,20 @@
"incremental": true,
"baseUrl": "src"
// "noUncheckedIndexedAccess": true
+ ,
+ "plugins": [
+ {
+ "name": "next"
+ }
+ ]
},
- "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
- "exclude": ["node_modules"]
+ "include": [
+ "next-env.d.ts",
+ "**/*.ts",
+ "**/*.tsx",
+ ".next/types/**/*.ts"
+ ],
+ "exclude": [
+ "node_modules"
+ ]
}