diff --git a/packages/components/src/templates/next/layouts/Collection/Collection.tsx b/packages/components/src/templates/next/layouts/Collection/Collection.tsx index c3384c62c8..dd422036a8 100644 --- a/packages/components/src/templates/next/layouts/Collection/Collection.tsx +++ b/packages/components/src/templates/next/layouts/Collection/Collection.tsx @@ -1,117 +1,19 @@ import type { Exact } from "type-fest" -import capitalize from "lodash/capitalize" -import type { CollectionPageSchemaType, IsomerSiteProps } from "~/engine" +import type { CollectionPageSchemaType } from "~/engine" import type { AllCardProps, ProcessedCollectionCardProps } from "~/interfaces" import { getBreadcrumbFromSiteMap, - getParsedDate, getReferenceLinkHref, - getSitemapAsArray, isExternalUrl, } from "~/utils" import { Skeleton } from "../Skeleton" import CollectionClient from "./CollectionClient" -import { getAvailableFilters, shouldShowDate } from "./utils" - -const CATEGORY_OTHERS = "Others" - -const getCollectionItems = ( - site: IsomerSiteProps, - permalink: string, -): AllCardProps[] => { - let currSitemap = site.siteMap - const permalinkParts = permalink.split("/") - - for (let i = 2; i <= permalinkParts.length; i++) { - const currPermalink = permalinkParts.slice(0, i).join("/") - - if (!currSitemap.children) { - return [] - } - - const child = currSitemap.children.find( - (child) => child.permalink === currPermalink, - ) - - if (!child) { - return [] - } - - currSitemap = child - } - - if (!currSitemap.children) { - return [] - } - - const items = currSitemap.children.flatMap((child) => - getSitemapAsArray(child), - ) - - const transformedItems = items - .filter( - (item) => - item.layout === "file" || - item.layout === "link" || - item.layout === "article", - ) - .map((item) => { - const date = - item.date !== undefined ? getParsedDate(item.date) : undefined - - const baseItem = { - type: "collectionCard" as const, - rawDate: date, - lastUpdated: date?.toISOString(), - category: item.category || CATEGORY_OTHERS, - title: item.title, - description: item.summary, - image: item.image, - site, - tags: item.tags, - } - - if (item.layout === "file") { - return { - ...baseItem, - variant: "file", - url: item.ref, - fileDetails: item.fileDetails, - } - } else if (item.layout === "link") { - return { - ...baseItem, - variant: "link", - url: item.ref, - } - } - - return { - ...baseItem, - variant: "article", - url: item.permalink, - } - }) satisfies AllCardProps[] - - return transformedItems.sort((a, b) => { - // Sort by last updated date, tiebreaker by title - if (a.rawDate === b.rawDate) { - return a.title > b.title ? 1 : -1 - } - - // Rank items with no dates last - if (a.rawDate === undefined) { - return 1 - } - - if (b.rawDate === undefined) { - return -1 - } - - return a.rawDate < b.rawDate ? 1 : -1 - }) as AllCardProps[] -} +import { + getAvailableFilters, + getCollectionItems, + shouldShowDate, +} from "./utils" const processedCollectionItems = ( items: AllCardProps[], diff --git a/packages/components/src/templates/next/layouts/Collection/utils/getCollectionItems.ts b/packages/components/src/templates/next/layouts/Collection/utils/getCollectionItems.ts new file mode 100644 index 0000000000..6a6c442d44 --- /dev/null +++ b/packages/components/src/templates/next/layouts/Collection/utils/getCollectionItems.ts @@ -0,0 +1,109 @@ +import type { IsomerSiteProps } from "~/engine" +import type { AllCardProps } from "~/interfaces" +import { getParsedDate, getSitemapAsArray } from "~/utils" + +const CATEGORY_OTHERS = "Others" + +export const getCollectionItems = ( + site: IsomerSiteProps, + permalink: string, +): AllCardProps[] => { + let currSitemap = site.siteMap + const permalinkParts = permalink.split("/") + + for (let i = 2; i <= permalinkParts.length; i++) { + const currPermalink = permalinkParts.slice(0, i).join("/") + + if (!currSitemap.children) { + return [] + } + + const child = currSitemap.children.find( + (child) => child.permalink === currPermalink, + ) + + if (!child) { + return [] + } + + currSitemap = child + } + + if (!currSitemap.children) { + return [] + } + + const items = currSitemap.children.flatMap((child) => + getSitemapAsArray(child), + ) + + const transformedItems = items + .filter( + (item) => + item.layout === "file" || + item.layout === "link" || + item.layout === "article", + ) + .map((item) => { + const date = + item.date !== undefined ? getParsedDate(item.date) : undefined + + const baseItem = { + type: "collectionCard" as const, + rawDate: date, + lastUpdated: date?.toISOString(), + category: item.category || CATEGORY_OTHERS, + title: item.title, + description: item.summary, + image: item.image, + site, + tags: item.tags, + } + + if (item.layout === "file") { + return { + ...baseItem, + variant: "file", + url: item.ref, + fileDetails: item.fileDetails, + } + } else if (item.layout === "link") { + return { + ...baseItem, + variant: "link", + url: item.ref, + } + } + + return { + ...baseItem, + variant: "article", + url: item.permalink, + } + }) satisfies AllCardProps[] + + return transformedItems.sort((a, b) => { + // Sort by last updated date, tiebreaker by title + if (a.rawDate && b.rawDate && a.rawDate.getTime() === b.rawDate.getTime()) { + // localeCompare better than > operator as + // it properly handles international and special characters + return a.title.localeCompare(b.title) + } + + // If both items have no dates, sort by title + if (a.rawDate === undefined && b.rawDate === undefined) { + return a.title.localeCompare(b.title) + } + + // Rank items with no dates last + if (a.rawDate === undefined) { + return 1 + } + + if (b.rawDate === undefined) { + return -1 + } + + return a.rawDate.getTime() < b.rawDate.getTime() ? 1 : -1 + }) as AllCardProps[] +} diff --git a/packages/components/src/templates/next/layouts/Collection/utils/index.ts b/packages/components/src/templates/next/layouts/Collection/utils/index.ts index b8292bddf8..4aaaec2d1f 100644 --- a/packages/components/src/templates/next/layouts/Collection/utils/index.ts +++ b/packages/components/src/templates/next/layouts/Collection/utils/index.ts @@ -3,3 +3,4 @@ export * from "./getFilteredItems" export * from "./getPaginatedItems" export * from "./updateAppliedFilters" export * from "./shouldShowDate" +export * from "./getCollectionItems"