Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import type { packageListingDependencySchema } from "@thunderstore/thunderstore-api";
import { type PackageVersionDependency } from "@thunderstore/thunderstore-api";
import "./ListingDependency.css";
import { formatToDisplayName, Image, NewLink } from "@thunderstore/cyberstorm";

export interface ListingDependencyProps {
dependency: typeof packageListingDependencySchema._type;
// TODO: Remove when package versiond detail is available
domain: string;
dependency: PackageVersionDependency;
communityId?: string;
}

export function ListingDependency(props: ListingDependencyProps) {
const { dependency, domain } = props;
const { dependency, communityId } = props;

return (
<div className="listing-dependency">
Expand All @@ -23,16 +22,30 @@ export function ListingDependency(props: ListingDependencyProps) {
/>
<div>
<div className="listing-dependency__info">
<NewLink
primitiveType="cyberstormLink"
linkId="Package"
community={dependency.community_identifier}
namespace={dependency.namespace}
package={dependency.name}
rootClasses="listing-dependency__name"
>
{formatToDisplayName(dependency.name)}
</NewLink>
{communityId ? (
<NewLink
primitiveType="cyberstormLink"
linkId="PackageVersion"
community={communityId}
namespace={dependency.namespace}
package={dependency.name}
version={dependency.version_number}
rootClasses="listing-dependency__name"
>
{formatToDisplayName(dependency.name)}
</NewLink>
) : (
<NewLink
primitiveType="cyberstormLink"
linkId="PackageVersionWithoutCommunity"
namespace={dependency.namespace}
package={dependency.name}
version={dependency.version_number}
rootClasses="listing-dependency__name"
>
{formatToDisplayName(dependency.name)}
</NewLink>
)}
<span className="listing-dependency__title">
<span className="listing-dependency__title__by">by</span>
<NewLink
Expand All @@ -50,23 +63,36 @@ export function ListingDependency(props: ListingDependencyProps) {
</div>
<div className="listing-dependency__version">
<span>Version:</span>
<NewLink
// TODO: Remove when package versiond detail is available
primitiveType="link"
href={`${domain}/c/${dependency.community_identifier}/p/${dependency.namespace}/${dependency.name}/v/${dependency.version_number}/`}
// primitiveType="cyberstormLink"
// linkId="PackageVersion"
// community={dependency.community_identifier}
// namespace={dependency.namespace}
// package={dependency.name}
// version={dependency.version_number}
title={`${formatToDisplayName(dependency.name)} - ${
dependency.version_number
}`}
csVariant="cyber"
>
{dependency.version_number}
</NewLink>
{communityId ? (
<NewLink
primitiveType="cyberstormLink"
linkId="PackageVersion"
community={communityId}
namespace={dependency.namespace}
package={dependency.name}
version={dependency.version_number}
title={`${formatToDisplayName(dependency.name)} - ${
dependency.version_number
}`}
csVariant="cyber"
>
{dependency.version_number}
</NewLink>
) : (
<NewLink
primitiveType="cyberstormLink"
linkId="PackageVersionWithoutCommunity"
namespace={dependency.namespace}
package={dependency.name}
version={dependency.version_number}
title={`${formatToDisplayName(dependency.name)} - ${
dependency.version_number
}`}
csVariant="cyber"
>
{dependency.version_number}
</NewLink>
)}
</div>
</div>
</div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ import {
} from "@thunderstore/thunderstore-api";
import { DapperTs } from "@thunderstore/dapper-ts";
import { isPromise } from "cyberstorm/utils/typeChecks";
import { setParamsBlobValue } from "cyberstorm/utils/searchParamsUtils";

const PER_PAGE = 20;

Expand Down Expand Up @@ -721,14 +722,6 @@ export function PackageSearch(props: Props) {
PackageSearch.displayName = "PackageSearch";

// Start setters
function setParamsBlobValue<K extends keyof SearchParamsType>(
setter: (v: SearchParamsType) => void,
oldBlob: SearchParamsType,
key: K
) {
return (v: SearchParamsType[K]) => setter({ ...oldBlob, [key]: v });
}

const setParamsBlobCategories = (
setter: (v: SearchParamsType) => void,
oldBlob: SearchParamsType,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,17 @@
@layer nimbus-layout {
.package-required__skeleton {
height: 500px;
}

.package-required {
@layer nimbus-components {
.paginated-dependencies {
display: flex;
flex-direction: column;
gap: var(--gap-md);
width: 100%;
overflow-x: auto;
}

.package-required__title {
.paginated-dependencies__skeleton {
height: 500px;
}

.paginated-dependencies__title {
display: flex;
flex-direction: column;
gap: var(--gap-md);
Expand All @@ -20,13 +20,13 @@
padding-bottom: var(--space-24);
}

.package-required__description {
.paginated-dependencies__description {
color: var(--color-text-secondary);
font-weight: var(--font-weight-regular);
line-height: var(--line-height-md);
}

.package-required__body {
.paginated-dependencies__body {
display: flex;
flex-direction: column;
gap: var(--gap-3xs);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,175 @@
import { memo, Suspense, useEffect, useMemo, useRef, useState } from "react";
import "./PaginatedDependencies.css";
import { Heading, NewPagination, SkeletonBox } from "@thunderstore/cyberstorm";
import { ListingDependency } from "../ListingDependency/ListingDependency";
import { Await, useNavigationType, useSearchParams } from "react-router";
import { useDebounce } from "use-debounce";
import type { getPackageVersionDetails } from "@thunderstore/dapper-ts/src/methods/packageVersion";
import type { getPackageVersionDependencies } from "@thunderstore/dapper-ts/src/methods/package";
import { setParamsBlobValue } from "cyberstorm/utils/searchParamsUtils";

interface Props {
version:
| Awaited<ReturnType<typeof getPackageVersionDetails>>
| ReturnType<typeof getPackageVersionDetails>;
dependencies:
| Awaited<ReturnType<typeof getPackageVersionDependencies>>
| ReturnType<typeof getPackageVersionDependencies>;
pageSize?: number;
siblingCount?: number;
}

export const PaginatedDependencies = memo(function PaginatedDependencies(
props: Props
) {
const navigationType = useNavigationType();

const [searchParams, setSearchParams] = useSearchParams();

const initialParams = searchParamsToBlob(searchParams);

const [searchParamsBlob, setSearchParamsBlob] =
useState<SearchParamsType>(initialParams);

const [currentPage, setCurrentPage] = useState(
searchParams.get("page") ? Number(searchParams.get("page")) : 1
);

const [debouncedSearchParamsBlob] = useDebounce(searchParamsBlob, 300, {
maxWait: 300,
});

const searchParamsBlobRef = useRef(debouncedSearchParamsBlob);

const searchParamsRef = useRef(searchParams);
useEffect(() => {
if (navigationType === "POP") {
if (searchParamsRef.current !== searchParams) {
const spb = searchParamsToBlob(searchParams);
setSearchParamsBlob(spb);
setCurrentPage(spb.page);
searchParamsRef.current = searchParams;
}
searchParamsBlobRef.current = searchParamsToBlob(searchParams);
}
}, [searchParams]);

useEffect(() => {
if (
navigationType !== "POP" ||
(navigationType === "POP" &&
searchParamsBlobRef.current !== debouncedSearchParamsBlob)
) {
if (searchParamsBlobRef.current !== debouncedSearchParamsBlob) {
const oldPage = searchParams.get("page")
? Number(searchParams.get("page"))
: 1;
// Page number
if (oldPage !== debouncedSearchParamsBlob.page) {
if (debouncedSearchParamsBlob.page === 1) {
searchParams.delete("page");
setCurrentPage(1);
} else {
searchParams.set("page", String(debouncedSearchParamsBlob.page));
setCurrentPage(debouncedSearchParamsBlob.page);
}
}
const uncommittedSearchParams = searchParamsToBlob(searchParams);

if (
navigationType !== "POP" ||
(navigationType === "POP" &&
!compareSearchParamBlobs(
uncommittedSearchParams,
searchParamsBlobRef.current
) &&
compareSearchParamBlobs(
uncommittedSearchParams,
debouncedSearchParamsBlob
))
) {
setSearchParams(searchParams, { preventScrollReset: true });
}
searchParamsBlobRef.current = debouncedSearchParamsBlob;
}
}
}, [debouncedSearchParamsBlob]);

const versionAndDependencies = useMemo(
() => Promise.all([props.version, props.dependencies]),
[currentPage]
);

return (
<div className="paginated-dependencies">
<Suspense
fallback={<SkeletonBox className="paginated-dependencies__skeleton" />}
>
<Await
resolve={versionAndDependencies}
errorElement={
<div>Error occurred while loading required dependencies</div>
}
>
{(resolvedValue) => {
return (
<>
<div className="paginated-dependencies__title">
<Heading csLevel="3" csSize="3">
Required mods ({resolvedValue[0].dependency_count})
</Heading>
<span className="paginated-dependencies__description">
This package requires the following packages to work.
</span>
</div>
<div className="paginated-dependencies__body">
{resolvedValue[1].results.map((dep, key) => {
return <ListingDependency key={key} dependency={dep} />;
})}
</div>
<NewPagination
currentPage={currentPage}
pageSize={props.pageSize ?? 20}
totalCount={resolvedValue[0].dependency_count}
onPageChange={setParamsBlobValue(
setSearchParamsBlob,
searchParamsBlob,
"page"
)}
siblingCount={props.siblingCount ?? 4}
/>
</>
);
}}
</Await>
</Suspense>
</div>
);
});

PaginatedDependencies.displayName = "PaginatedDependencies";

export type SearchParamsType = {
page: number;
};

export const compareSearchParamBlobs = (
b1: SearchParamsType,
b2: SearchParamsType
) => {
if (b1.page !== b2.page) return false;
return true;
};

export const searchParamsToBlob = (searchParams: URLSearchParams) => {
const initialPage = searchParams.get("page");

return {
page:
initialPage &&
!Number.isNaN(Number.parseInt(initialPage)) &&
Number.isSafeInteger(Number.parseInt(initialPage))
? Number.parseInt(initialPage)
: 1,
};
};
2 changes: 1 addition & 1 deletion apps/cyberstorm-remix/app/p/packageListing.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ export function shouldRevalidate(arg: ShouldRevalidateFunctionArgs) {
// If we're staying on the same package page, don't revalidate
if (
oldPath[2] === newPath[2] &&
oldPath[4] === newPath[4] &&
oldPath[3] === newPath[3] &&
oldPath[5] === newPath[5]
) {
return false;
Expand Down
Loading
Loading