diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/TeamProfileLayout.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(dependants)/dependants/DependantsPage.module.css
similarity index 100%
rename from apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/TeamProfileLayout.module.css
rename to apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(dependants)/dependants/DependantsPage.module.css
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(dependants)/dependants/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(dependants)/dependants/page.tsx
new file mode 100644
index 000000000..5fda18e74
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(dependants)/dependants/page.tsx
@@ -0,0 +1,81 @@
+"use client";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+
+import rootStyles from "../../../../../../../../../../RootLayout.module.css";
+import styles from "./DependantsPage.module.css";
+import {
+ BreadCrumbs,
+ CommunitiesLink,
+ CommunityLink,
+ PackageLink,
+ PackageSearch,
+ TeamLink,
+} from "@thunderstore/cyberstorm";
+
+export default function Page({
+ params,
+}: {
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const community = usePromise(dapper.getCommunity, [params.community]);
+ const filters = usePromise(dapper.getCommunityFilters, [params.community]);
+
+ const listingType = {
+ kind: "package-dependants" as const,
+ communityId: params.community,
+ namespaceId: params.namespace,
+ packageName: params.package,
+ };
+
+ return (
+
+
+ <>
+
+ Communities
+
+ {community.name}
+
+ Packages
+
+ {params.namespace}
+
+
+ {params.package}
+
+ Dependants
+
+
+
+
+
+ >
+
+
+ );
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/@packageManagement/PackageManagementForm.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/@packageManagement/PackageManagementForm.module.css
new file mode 100644
index 000000000..ad8dfc16c
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/@packageManagement/PackageManagementForm.module.css
@@ -0,0 +1,28 @@
+.root {
+ display: flex;
+ flex-direction: column;
+ gap: var(--gap--32);
+ max-height: 70%;
+}
+
+.section {
+ display: flex;
+ flex-direction: column;
+ gap: var(--gap--16);
+}
+
+.statusTag {
+ display: flex;
+}
+
+.title {
+ font-weight: var(--font-weight-bold);
+ font-size: var(--font-size--l);
+ line-height: var(--line-height--l);
+}
+
+.footer {
+ display: flex;
+ flex-direction: row;
+ justify-content: space-between;
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/@packageManagement/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/@packageManagement/page.tsx
new file mode 100644
index 000000000..cabb209d1
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/@packageManagement/page.tsx
@@ -0,0 +1,60 @@
+"use client";
+import { Alert, Button, Tag, TextInput } from "@thunderstore/cyberstorm";
+import styles from "./PackageManagementForm.module.css";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+import { faCircleExclamation } from "@fortawesome/pro-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+
+export default function Page({
+ params,
+}: {
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const packageData = usePromise(dapper.getPackageListingDetails, [
+ params.community,
+ params.namespace,
+ params.package,
+ ]);
+
+ return (
+
+
+
}
+ content={
+ "Changes might take several minutes to show publicly! Info shown below is always up to date."
+ }
+ variant="info"
+ />
+
Package status
+
+
+
+
+
+
+ {packageData.is_deprecated ? (
+
+ Undeprecate
+
+ ) : (
+
+ Deprecate
+
+ )}
+
+ Save changes
+
+
+
+ );
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/PackageDetailLayout.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/PackageDetailLayout.module.css
new file mode 100644
index 000000000..a6aeb4b51
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/PackageDetailLayout.module.css
@@ -0,0 +1,120 @@
+.packageInfo {
+ display: flex;
+ flex-direction: row;
+ gap: var(--gap--32);
+ justify-content: space-between;
+}
+
+.packageInfoDetails {
+ display: flex;
+ flex-direction: column;
+ gap: var(--gap--8);
+}
+
+.packageInfoMeta {
+ display: flex;
+ flex-direction: row;
+ gap: var(--gap--16);
+}
+
+.description {
+ color: var(--color-text--default);
+ white-space: pre-wrap;
+ overflow-wrap: anywhere;
+}
+
+.headerActions {
+ display: flex;
+ flex-basis: 354px;
+ flex-direction: column;
+ align-items: flex-end;
+ justify-content: space-between;
+}
+
+.installButton {
+ position: relative;
+ bottom: -1rem;
+ width: 354px;
+}
+
+.installButtonIcon {
+ max-width: var(--space--24);
+}
+
+.installButtonIcon svg {
+ width: 1.655rem;
+ height: 1.462rem;
+}
+
+.metaButtonWrapper {
+ display: flex;
+ flex-grow: 1;
+ gap: var(--gap--8);
+}
+
+.metaDownloadButton {
+ display: flex;
+ flex-grow: 1;
+}
+
+.metaDownloadButton > div {
+ display: flex;
+ flex-grow: 1;
+}
+
+.metaInfo {
+ display: flex;
+ flex-direction: column;
+ gap: var(--gap--16);
+ min-width: 354px;
+}
+
+.dependencyStringWrapper {
+ display: flex;
+ gap: var(--gap--8);
+ align-items: center;
+ max-width: 180px;
+ max-height: 21px;
+}
+
+.dependencyString {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.dependantsLink {
+ color: var(--color-highlight);
+}
+
+@media (max-width: 60rem) {
+ .packageInfo {
+ flex-direction: column;
+ gap: 0;
+ }
+
+ .headerActions {
+ flex-direction: row;
+ justify-content: space-between;
+ width: 100%;
+ }
+}
+
+.tabIcon {
+ line-height: normal;
+}
+
+.modImage {
+ min-width: 9rem;
+ max-width: 9rem;
+ min-height: 9rem;
+ max-height: 9rem;
+ border-radius: var(--border-radius--8);
+}
+
+.categoriesCard {
+ display: flex;
+ flex-flow: row wrap;
+ gap: 0.5rem;
+ row-gap: 0.5rem;
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/layout.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/layout.tsx
new file mode 100644
index 000000000..50b76785e
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageCard/layout.tsx
@@ -0,0 +1,97 @@
+"use client";
+import { PageHeader, Dialog, Button, TeamLink } from "@thunderstore/cyberstorm";
+import styles from "./PackageDetailLayout.module.css";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+import { ThunderstoreLogo } from "@thunderstore/cyberstorm/src/svg/svg";
+import {
+ faArrowUpRight,
+ faUsers,
+ faCog,
+} from "@fortawesome/pro-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { ReactNode, Suspense } from "react";
+
+export default function PackageCardLayout({
+ packageManagement,
+ params,
+}: {
+ packageManagement: ReactNode;
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const packageData = usePromise(dapper.getPackageListingDetails, [
+ params.community,
+ params.namespace,
+ params.package,
+ ]);
+ const displayName = params.package.replace(/_/g, " ");
+
+ const packageDetailsMeta = [
+
+
+
+
+
+ {packageData.namespace}
+
+ ,
+ ];
+
+ if (packageData.website_url) {
+ packageDetailsMeta.push(
+
+
+ {packageData.website_url}
+
+
+
+
+
+ );
+ }
+
+ return (
+
+
+ }
+ description={packageData.description}
+ meta={packageDetailsMeta}
+ />
+
+
+ );
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/@packageDependencyDialog/PackageDependencyDialog.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/@packageDependencyDialog/PackageDependencyDialog.module.css
new file mode 100644
index 000000000..09858ab82
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/@packageDependencyDialog/PackageDependencyDialog.module.css
@@ -0,0 +1,48 @@
+.root {
+ font-size: var(--font-size--m);
+ line-height: var(--line-height--m);
+}
+
+.image {
+ width: 5rem;
+}
+
+.title {
+ font-weight: var(--font-weight-bold);
+ font-size: var(--font-size--l);
+ line-height: var(--line-height--l);
+}
+
+.description {
+ color: var(--color-text--tertiary);
+ font-weight: var(--font-weight-medium);
+ font-size: var(--font-size--m);
+ line-height: var(--line-height--m);
+}
+
+.item {
+ display: flex;
+ gap: var(--gap--24);
+ padding: var(--space--16) var(--space--32);
+}
+
+.item:hover {
+ gap: var(--gap--24);
+ padding: var(--space--16) var(--space--32);
+ background-color: var(--color-surface--5);
+}
+
+.preferredVersion {
+ padding-top: var(--space--6);
+ color: var(--color-text--accent);
+ font-weight: var(--font-weight-medium);
+ font-size: var(--font-size--s);
+ line-height: var(--line-height--s);
+}
+
+.preferredVersion__version {
+ color: var(--color-highlight);
+ font-weight: var(--font-weight-medium);
+ font-size: var(--font-size--s);
+ line-height: var(--line-height--s);
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/@packageDependencyDialog/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/@packageDependencyDialog/page.tsx
new file mode 100644
index 000000000..829c2af51
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/@packageDependencyDialog/page.tsx
@@ -0,0 +1,61 @@
+"use client";
+import {
+ ImageWithFallback,
+ PackageLink,
+ PackageVersionLink,
+} from "@thunderstore/cyberstorm";
+import styles from "./PackageDependencyDialog.module.css";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+import { ReactNode } from "react";
+
+export default function Page({
+ params,
+}: {
+ packageDependencyDialog: ReactNode;
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const packageData = usePromise(dapper.getPackageListingDetails, [
+ params.community,
+ params.namespace,
+ params.package,
+ ]);
+
+ return (
+
+ {packageData.dependencies.map((depData, index) => (
+
+
+
+
+
+
+
{depData.description}
+
+ Preferred version:{" "}
+
+
+ {depData.version_number}
+
+
+
+
+
+ ))}
+
+ );
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/PackageDependencyList.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/PackageDependencyList.module.css
new file mode 100644
index 000000000..bd71735d6
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/PackageDependencyList.module.css
@@ -0,0 +1,56 @@
+.root {
+ display: flex;
+ flex-direction: column;
+ gap: var(--gap--8);
+ border-radius: 8px;
+}
+
+.countDescription {
+ padding: 0 var(--space--8);
+ color: var(--color-text--tertiary);
+ font-size: var(--font-size--m);
+}
+
+.item {
+ display: flex;
+ gap: var(--gap--16);
+ padding: var(--space--8);
+ border-radius: var(--border-radius--8);
+}
+
+.item:hover {
+ background-color: var(--color-surface--4);
+}
+
+.itemImage {
+ width: 5rem;
+}
+
+.itemTitle {
+ overflow: hidden;
+ font-weight: var(--font-weight-bold);
+ font-size: var(--font-size--m);
+ line-height: var(--line-height--m);
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.itemDescription {
+ overflow: hidden;
+ color: var(--color-text--tertiary);
+ font-size: var(--font-size--m);
+ line-height: var(--line-height--m);
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+@media (min-width: 60rem) {
+ .itemDescription,
+ .itemTitle {
+ max-width: 250px;
+ }
+}
+
+.dependencyDialogTrigger {
+ align-items: center;
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/layout.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/layout.tsx
new file mode 100644
index 000000000..1d197fc44
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageDependencyList/layout.tsx
@@ -0,0 +1,113 @@
+"use client";
+import {
+ Button,
+ Dialog,
+ ImageWithFallback,
+ PackageLink,
+} from "@thunderstore/cyberstorm";
+import { faBoxOpen } from "@fortawesome/pro-regular-svg-icons";
+import { faCaretRight } from "@fortawesome/pro-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import styles from "./PackageDependencyList.module.css";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+import { WrapperCard } from "@thunderstore/cyberstorm/src/components/WrapperCard/WrapperCard";
+import { PackageDependency } from "@thunderstore/dapper/types";
+import { ReactNode, Suspense } from "react";
+
+const PREVIEW_LIMIT = 4;
+
+export default function PackageDependencyListLayout({
+ packageDependencyDialog,
+ params,
+}: {
+ packageDependencyDialog: ReactNode;
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const packageData = usePromise(dapper.getPackageListingDetails, [
+ params.community,
+ params.namespace,
+ params.package,
+ ]);
+
+ let countDescription = "";
+
+ if (packageData.dependency_count === 0) {
+ countDescription = "This mod doesn't depend on other mods.";
+ } else if (packageData.dependency_count > PREVIEW_LIMIT) {
+ countDescription = `+ ${packageData.dependency_count - PREVIEW_LIMIT} more`;
+ }
+
+ return (
+
+
+
+ {packageData.dependencies.slice(0, PREVIEW_LIMIT).map((d) => (
+
+ ))}
+
+
+ {countDescription === "" ? null : (
+ {countDescription}
+ )}
+
+ }
+ headerIcon={}
+ headerRightContent={
+ packageData.dependency_count > PREVIEW_LIMIT ? (
+
+
+
+ See all
+
+
+
+
+
+
+ }
+ >
+ TODO: SKELETON packageTeamMemberList}>
+ {packageDependencyDialog}
+
+
+ ) : null
+ }
+ />
+ );
+}
+
+const PackageDependencyListItem = (props: PackageDependency) => (
+
+
+
+
+
+
+
{props.name}
+
{props.description}
+
+
+
+);
+
+PackageDependencyListItem.displayName = "PackageDependencyListItem";
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageMeta/PackageMeta.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageMeta/PackageMeta.module.css
new file mode 100644
index 000000000..737cf6cdb
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageMeta/PackageMeta.module.css
@@ -0,0 +1,17 @@
+.dependencyStringWrapper {
+ display: flex;
+ gap: var(--gap--8);
+ align-items: center;
+ max-width: 180px;
+ max-height: 21px;
+}
+
+.dependencyString {
+ overflow: hidden;
+ white-space: nowrap;
+ text-overflow: ellipsis;
+}
+
+.dependantsLink {
+ color: var(--color-highlight);
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageMeta/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageMeta/page.tsx
new file mode 100644
index 000000000..37b45f935
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageMeta/page.tsx
@@ -0,0 +1,89 @@
+"use client";
+import {
+ CopyButton,
+ MetaInfoItemList,
+ PackageDependantsLink,
+} from "@thunderstore/cyberstorm";
+import styles from "./PackageMeta.module.css";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+import { RelativeTime } from "@thunderstore/cyberstorm/src/components/RelativeTime/RelativeTime";
+import {
+ formatInteger,
+ formatFileSize,
+} from "@thunderstore/cyberstorm/src/utils/utils";
+
+export default function Page({
+ params,
+}: {
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const packageData = usePromise(dapper.getPackageListingDetails, [
+ params.community,
+ params.namespace,
+ params.package,
+ ]);
+
+ return (
+ ,
+ },
+ {
+ key: "first-uploaded",
+ label: "First Uploaded",
+ content: ,
+ },
+ {
+ key: "downloads",
+ label: "Downloads",
+ content: formatInteger(packageData.download_count),
+ },
+ {
+ key: "likes",
+ label: "Likes",
+ content: formatInteger(packageData.rating_count),
+ },
+ {
+ key: "file-size",
+ label: "Size",
+ content: formatFileSize(packageData.size),
+ },
+ {
+ key: "dependency-string",
+ label: "Dependency string",
+ content: (
+
+
+ {packageData.full_version_name}
+
+
+
+ ),
+ },
+ {
+ key: "dependants",
+ label: "Dependants",
+ content: (
+
+
+ {packageData.dependant_count} other mods
+
+
+ ),
+ },
+ ]}
+ />
+ );
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTagList/PackageTagList.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTagList/PackageTagList.module.css
new file mode 100644
index 000000000..047000c96
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTagList/PackageTagList.module.css
@@ -0,0 +1,5 @@
+.list {
+ display: flex;
+ flex-flow: row wrap;
+ gap: var(--gap--8);
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTagList/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTagList/page.tsx
new file mode 100644
index 000000000..1845c5cf6
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTagList/page.tsx
@@ -0,0 +1,103 @@
+"use client";
+import { Tag } from "@thunderstore/cyberstorm";
+import { WrapperCard } from "@thunderstore/cyberstorm/src/components/WrapperCard/WrapperCard";
+import styles from "./PackageTagList.module.css";
+import { useDapper } from "@thunderstore/dapper";
+import { PackageListingDetails } from "@thunderstore/dapper/types";
+import { usePromise } from "@thunderstore/use-promise";
+import { ReactNode } from "react";
+
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { faTag } from "@fortawesome/pro-regular-svg-icons";
+import {
+ faThumbtack,
+ faWarning,
+ faLips,
+ faSparkles,
+} from "@fortawesome/pro-solid-svg-icons";
+
+export default function Page({
+ params,
+}: {
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const packageData = usePromise(dapper.getPackageListingDetails, [
+ params.community,
+ params.namespace,
+ params.package,
+ ]);
+
+ return (
+ <>
+ {getPackageFlags(packageData)}
+ }
+ headerIcon={}
+ />
+ >
+ );
+}
+
+function getPackageFlags(packageData: PackageListingDetails) {
+ const updateTimeDelta = Math.round(
+ (Date.now() - Date.parse(packageData.last_updated)) / 86400000
+ );
+ const isNew = updateTimeDelta < 3;
+ if (
+ !packageData.is_pinned &&
+ !packageData.is_nsfw &&
+ !packageData.is_deprecated &&
+ !isNew
+ ) {
+ return null;
+ }
+ const flagList: ReactNode[] = [];
+ if (packageData.is_pinned) {
+ flagList.push(
+ }
+ />
+ );
+ }
+ if (packageData.is_deprecated) {
+ flagList.push(
+ }
+ />
+ );
+ }
+ if (packageData.is_nsfw) {
+ flagList.push(
+ }
+ />
+ );
+ }
+ if (isNew) {
+ flagList.push(
+ }
+ />
+ );
+ }
+ return flagList;
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTeamMemberList/PackageTeamMemberList.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTeamMemberList/PackageTeamMemberList.module.css
new file mode 100644
index 000000000..e09485b72
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTeamMemberList/PackageTeamMemberList.module.css
@@ -0,0 +1,54 @@
+.list {
+ position: relative;
+}
+
+.item {
+ display: flex;
+ gap: var(--gap--16);
+ padding: var(--space--8);
+ border-radius: var(--border-radius--8);
+}
+
+.item:hover {
+ background-color: var(--color-surface--4);
+}
+
+.itemTitle {
+ font-weight: var(--font-weight-bold);
+ font-size: var(--font-size--m);
+ line-height: var(--line-height--m);
+}
+
+.itemDescription {
+ color: var(--color-text--tertiary);
+ font-weight: var(--font-weight-medium);
+ font-size: var(--font-size--m);
+ line-height: var(--line-height--m);
+}
+
+.teamLink {
+ display: flex;
+ gap: var(--gap--8);
+ align-items: center;
+ color: var(--color-highlight);
+ font-weight: var(--font-weight-semibold);
+ font-size: var(--font-size--m);
+ line-height: var(--line-height--m);
+}
+
+.teamLinkIcon {
+ width: 1em;
+ height: 1em;
+}
+
+.teamLink:hover {
+ color: var(--color-highlight--hover);
+}
+
+.crown {
+ display: inline-flex;
+ width: 1em;
+ height: 1em;
+ margin-left: var(--space--4);
+ color: var(--color-crown);
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTeamMemberList/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTeamMemberList/page.tsx
new file mode 100644
index 000000000..cd5c918c4
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/@packageTeamMemberList/page.tsx
@@ -0,0 +1,96 @@
+"use client";
+import { Avatar, Icon, TeamLink, UserLink } from "@thunderstore/cyberstorm";
+import {
+ faUsers,
+ faCaretRight,
+ faCrown,
+} from "@fortawesome/pro-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import styles from "./PackageTeamMemberList.module.css";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+import { WrapperCard } from "@thunderstore/cyberstorm/src/components/WrapperCard/WrapperCard";
+import { TeamMember } from "@thunderstore/dapper/types";
+
+export default function Page({
+ params,
+}: {
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const packageData = usePromise(dapper.getPackageListingDetails, [
+ params.community,
+ params.namespace,
+ params.package,
+ ]);
+
+ const mappedPackageTeamList = packageData.team.members
+ .sort(compare)
+ .map((teamMember, index) => {
+ return (
+
+ );
+ });
+
+ return (
+ <>
+ {mappedPackageTeamList}}
+ headerIcon={}
+ headerRightContent={
+ packageData.team ? (
+
+
+ See team
+
+
+
+
+
+ ) : null
+ }
+ />
+ >
+ );
+}
+
+interface PackageTeamListItemProps {
+ teamMember: TeamMember;
+}
+
+function PackageTeamListItem(props: PackageTeamListItemProps) {
+ const { teamMember } = props;
+
+ return (
+
+
+
+
+
+ {teamMember.username}
+ {teamMember.role === "owner" ? (
+
+
+
+ ) : null}
+
+
{teamMember.role}
+
+
+
+ );
+}
+
+function compare(a: TeamMember, b: TeamMember) {
+ if (a.role === b.role) {
+ return a.username.localeCompare(b.username);
+ }
+
+ return a.role === "owner" ? -1 : 1;
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/PackageDetailsLayout.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/PackageDetailsLayout.module.css
new file mode 100644
index 000000000..783731670
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/PackageDetailsLayout.module.css
@@ -0,0 +1,28 @@
+.root {
+ display: flex;
+ flex-direction: column;
+ gap: var(--gap--16);
+ min-width: 354px;
+}
+
+.buttons {
+ display: flex;
+ gap: var(--gap--8);
+}
+
+.download {
+ display: flex;
+ flex-grow: 1;
+}
+
+.download > div {
+ display: flex;
+ flex-grow: 1;
+}
+
+.categories {
+ display: flex;
+ flex-flow: row wrap;
+ gap: 0.5rem;
+ row-gap: 0.5rem;
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/layout.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/layout.tsx
new file mode 100644
index 000000000..d37f0b78b
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageDetail/layout.tsx
@@ -0,0 +1,137 @@
+"use client";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+import {
+ faDonate,
+ faDownload,
+ faThumbsUp,
+ faFlag,
+ faBoxes,
+} from "@fortawesome/pro-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import styles from "./PackageDetailsLayout.module.css";
+import { Button, Icon, Tag } from "@thunderstore/cyberstorm";
+import { ReactNode, Suspense } from "react";
+import { WrapperCard } from "@thunderstore/cyberstorm/src/components/WrapperCard/WrapperCard";
+
+export default function PackageDetailsLayout({
+ packageMeta,
+ packageTagList,
+ packageDependencyList,
+ packageTeamMemberList,
+ params,
+}: {
+ packageMeta: ReactNode;
+ packageTagList: ReactNode;
+ packageDependencyList: ReactNode;
+ packageTeamMemberList: ReactNode;
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const packageData = usePromise(dapper.getPackageListingDetails, [
+ params.community,
+ params.namespace,
+ params.package,
+ ]);
+
+ const mappedPackageTagList = packageData.categories.map((category) => {
+ return (
+
+ );
+ });
+
+ return (
+
+
+
TODO: SKELETON packageMeta}>
+ {packageMeta}
+
+
{mappedPackageTagList}
+ }
+ headerIcon={
+
+
+
+ }
+ />
+ TODO: SKELETON packageTagList}>
+ {packageTagList}
+
+ TODO: SKELETON packageDependencyList}>
+ {packageDependencyList}
+
+ TODO: SKELETON packageTeamMemberList}>
+ {packageTeamMemberList}
+
+
+ );
+}
+
+const TODO = () => Promise.resolve();
+
+interface Clickable {
+ onClick: () => Promise;
+}
+
+const LikeButton = (props: Clickable) => (
+
+
+
+
+
+);
+
+const DonateButton = (props: Clickable) => (
+
+
+
+
+
+);
+
+const ReportButton = (props: Clickable) => (
+
+
+
+
+
+);
+
+const DownloadButton = () => (
+
+
+
+
+ Download
+
+);
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/@packageChangelog/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/@packageChangelog/page.tsx
new file mode 100644
index 000000000..877f820a1
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/@packageChangelog/page.tsx
@@ -0,0 +1,19 @@
+"use client";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+
+import styles from "../Markdown.module.css";
+
+export default function Page({
+ params,
+}: {
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const { html: __html } = usePromise(dapper.getPackageChangelog, [
+ params.namespace,
+ params.package,
+ ]);
+
+ return ;
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/@packageReadme/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/@packageReadme/page.tsx
new file mode 100644
index 000000000..335f2310b
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/@packageReadme/page.tsx
@@ -0,0 +1,19 @@
+"use client";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+
+import styles from "../Markdown.module.css";
+
+export default function Page({
+ params,
+}: {
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const { html: __html } = usePromise(dapper.getPackageReadme, [
+ params.namespace,
+ params.package,
+ ]);
+
+ return ;
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/@packageVersions/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/@packageVersions/page.tsx
new file mode 100644
index 000000000..fe42a4f5a
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/@packageVersions/page.tsx
@@ -0,0 +1,92 @@
+"use client";
+import { faCircleExclamation } from "@fortawesome/free-solid-svg-icons";
+import { faBoltLightning } from "@fortawesome/pro-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+
+import styles from "../Markdown.module.css";
+import { Table, Sort, Alert, Button } from "@thunderstore/cyberstorm";
+
+export default function Page({
+ params,
+}: {
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const versions = usePromise(dapper.getPackageVersions, [
+ params.namespace,
+ params.package,
+ ]);
+
+ const tableRows = versions.map((v) => [
+ { value: v.version_number, sortValue: v.version_number },
+ {
+ value: new Date(v.datetime_created).toLocaleDateString(),
+ sortValue: v.datetime_created,
+ },
+ { value: v.download_count.toLocaleString(), sortValue: v.download_count },
+ { value: , sortValue: 0 },
+ { value: , sortValue: 0 },
+ ]);
+
+ return (
+
+ );
+}
+
+const columns = [
+ { value: "Version", disableSort: false },
+ { value: "Upload date", disableSort: false },
+ { value: "Downloads", disableSort: false },
+ { value: "", disableSort: true },
+ { value: "", disableSort: true },
+];
+
+const ModManagerBanner = () => (
+
+ Please note that the install buttons only work if you have compatible
+ client software installed, such as the{" "}
+
+ Thunderstore Mod Manager.
+ {" "}
+ Otherwise use the zip download links instead.
+
+ }
+ variant={"info"}
+ icon={}
+ />
+);
+
+const DownloadLink = (props: { download_url: string }) => (
+
+
+ Download
+
+
+);
+
+const InstallLink = (props: { install_url: string }) => (
+
+
+
+
+
+ Install
+
+
+);
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/Markdown.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/Markdown.module.css
new file mode 100644
index 000000000..8249431df
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/Markdown.module.css
@@ -0,0 +1,152 @@
+.root {
+ display: flex;
+ flex-direction: column;
+ gap: 1.5rem;
+ color: var(--color-text--default);
+ font: var(--font-body);
+ font-weight: var(--font-weight-medium);
+ line-height: 1.6rem;
+}
+
+.root > :first-child { padding-top: 0; }
+
+/*
+ We can't control the elements inside the Markdown wrapper, e.g. to
+ give them class names, and linting requires pure selectors, so repeat
+ the .root class name on each selector.
+*/
+.root h1,
+.root h2,
+.root h3,
+.root h4,
+.root h5,
+.root h6 {
+ display: flex;
+ gap: 0.5rem;
+ align-items: flex-start;
+ align-self: stretch;
+ font: var(--font-body);
+ font-weight: var(--font-weight-bold);
+ line-height: normal;
+}
+
+.root h1,
+.root h2 {
+ padding: 2rem 0 0.5rem;
+ border-bottom: 1px solid #29295b;
+}
+
+.root h3,
+.root h4,
+.root h5,
+.root h6 {
+ padding-top: 1rem;
+}
+
+.root h1 { font-size: 2.25rem; }
+.root h2 { font-size: 1.75rem; }
+.root h3 { font-size: 1.25rem; }
+.root h4 { font-size: 1rem; }
+.root h5 { font-size: 0.875rem; }
+
+.root h6 {
+ color: #9c9cc4;
+ font-size: 0.875rem;
+}
+
+.root ul li,
+.root ol li {
+ margin-inline-start: 0.75rem;
+}
+
+.root img { display: inline-block; }
+
+.root li > ul,
+.root li > ol {
+ margin-top: 0.25rem;
+}
+
+.root pre {
+ padding: 1rem;
+ border: 1px solid #333370;
+ border-radius: 0.5rem;
+ background: #0f0f1f;
+}
+
+.root code {
+ display: inline-flex;
+ padding: 0 0.35rem;
+ border: 1px solid #333370;
+ border-radius: 0.25rem;
+ color: #39e9aa;
+ font-weight: var(--font-weight-regular);
+
+ font-size: 0.875rem;
+ font-family: var(--font-family-monospace);
+ font-style: normal;
+ line-height: 150%;
+ background: #0d0d21;
+}
+
+.root pre code {
+ display: block;
+ padding: 0;
+ border: 0;
+ border-radius: 0;
+ color: #f5f5f6;
+}
+
+.root a { color: var(--color-cyber-green--50); }
+
+.root blockquote {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+ padding-left: 2rem;
+ border-left: 4px solid #3c3c86;
+}
+
+.root table {
+ border-collapse: separate;
+ border-spacing: 0;
+}
+
+.root tbody tr:nth-child(even) { background: #0d0d21; }
+
+.root tbody tr:nth-child(odd) { background: #15152d; }
+
+.root table tr th,
+.root table tr td {
+ padding: 0.75rem 1rem;
+ border-right: 1px solid #333370;
+ border-bottom: 1px solid #333370;
+ color: #fff;
+}
+
+.root table tr th {
+ border-top: solid 1px #333370;
+ color: #c6c3ff;
+ text-align: left;
+ background: #1f1f42;
+}
+
+.root table tr th:first-child,
+.root table tr td:first-child {
+ border-left: 1px solid #333370;
+}
+
+.root table tr:first-child th:first-child {
+ border-top-left-radius: 0.5rem;
+}
+
+.root table tr:first-child th:last-child {
+ border-top-right-radius: 0.5rem;
+}
+
+.root table tr:last-child td:first-child {
+ border-bottom-left-radius: 0.5rem;
+}
+
+.root table tr:last-child td:last-child {
+ border-bottom-right-radius: 0.5rem;
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/layout.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/layout.tsx
new file mode 100644
index 000000000..e4c1d3e78
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/@packageTabs/layout.tsx
@@ -0,0 +1,56 @@
+"use client";
+import { useDapper } from "@thunderstore/dapper";
+import { usePromise } from "@thunderstore/use-promise";
+import { ReactNode, Suspense } from "react";
+import Tabs from "@thunderstore/cyberstorm/src/components/NewTabs/Tabs";
+import {
+ faFileLines,
+ faFilePlus,
+ faCodeBranch,
+} from "@fortawesome/pro-solid-svg-icons";
+
+export default function PacakgeTabsLayout({
+ packageReadme,
+ packageChangelog,
+ packageVersions,
+ params,
+}: {
+ packageReadme: ReactNode;
+ packageChangelog: ReactNode;
+ packageVersions: ReactNode;
+ params: { community: string; namespace: string; package: string };
+}) {
+ const dapper = useDapper();
+ const packageData = usePromise(dapper.getPackageListingDetails, [
+ params.community,
+ params.namespace,
+ params.package,
+ ]);
+
+ return (
+
+
+ TODO: Readme Skeleton}>
+ {packageReadme}
+
+
+
+
+ TODO: Changelog Skeleton}>
+ {packageChangelog}
+
+
+
+
+ TODO: Versions Skeleton}>
+ {packageVersions}
+
+
+
+ );
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/PackageLayout.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/PackageLayout.module.css
new file mode 100644
index 000000000..6d74e780a
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/PackageLayout.module.css
@@ -0,0 +1,5 @@
+.packageContainer {
+ display: flex;
+ flex-direction: row;
+ gap: 2rem;
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/layout.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/layout.tsx
new file mode 100644
index 000000000..bd26c5a9f
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(packageRoute)/[package]/(pkg)/layout.tsx
@@ -0,0 +1,54 @@
+import rootStyles from "../../../../../../../../../RootLayout.module.css";
+import styles from "./PackageLayout.module.css";
+import {
+ BreadCrumbs,
+ CommunitiesLink,
+ CommunityLink,
+ TeamLink,
+} from "@thunderstore/cyberstorm";
+import { ReactNode, Suspense } from "react";
+
+export default function PackageLayout({
+ packageCard,
+ packageTabs,
+ packageDetail,
+ params,
+}: {
+ packageCard: ReactNode;
+ packageTabs: ReactNode;
+ packageDetail: ReactNode;
+ params: { community: string; namespace: string; package: string };
+}) {
+ const displayName = params.package.replace(/_/g, " ");
+ return (
+
+
+ <>
+
+ Communities
+
+ {params.community}
+
+ {params.namespace}
+ {displayName}
+
+
+ TODO: SKELETON communityCard}>
+ {packageCard}
+
+
+
+
+ TODO: SKELETON packageTabs}>
+ {packageTabs}
+
+ TODO: SKELETON packageDetail}>
+ {packageDetail}
+
+
+
+ >
+
+
+ );
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(teamProfile)/TeamProfileLayout.module.css b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(teamProfile)/TeamProfileLayout.module.css
new file mode 100644
index 000000000..a25ce4730
--- /dev/null
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(teamProfile)/TeamProfileLayout.module.css
@@ -0,0 +1,11 @@
+.header {
+ padding: 0.5rem 0 1.5rem;
+ color: var(--color-text--default);
+ font-weight: var(--font-weight-bold);
+ font-size: 1.75rem;
+ line-height: 120%;
+}
+
+.header a {
+ color: var(--color-cyber-green--60);
+}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(teamProfile)/page.tsx
similarity index 95%
rename from apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/page.tsx
rename to apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(teamProfile)/page.tsx
index 8acf0f8eb..b443c79a4 100644
--- a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/page.tsx
+++ b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/(teamProfile)/page.tsx
@@ -2,7 +2,7 @@
import { useDapper } from "@thunderstore/dapper";
import { usePromise } from "@thunderstore/use-promise";
-import rootStyles from "../../../../../../RootLayout.module.css";
+import rootStyles from "../../../../../../../RootLayout.module.css";
import styles from "./TeamProfileLayout.module.css";
import {
BreadCrumbs,
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/[package]/dependants/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/[package]/dependants/page.tsx
deleted file mode 100644
index 04a8bd510..000000000
--- a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/[package]/dependants/page.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { PackageDependantsLayout } from "@thunderstore/cyberstorm";
-
-export default function Page({
- params,
-}: {
- params: { community: string; namespace: string; package: string };
-}) {
- return (
-
- );
-}
diff --git a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/[package]/page.tsx b/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/[package]/page.tsx
deleted file mode 100644
index b0bc17abe..000000000
--- a/apps/cyberstorm-nextjs/app/c/[community]/(package)/@tspackage/p/[namespace]/[package]/page.tsx
+++ /dev/null
@@ -1,15 +0,0 @@
-import { PackageDetailLayout } from "@thunderstore/cyberstorm";
-
-export default function Page({
- params,
-}: {
- params: { community: string; namespace: string; package: string };
-}) {
- return (
-
- );
-}
diff --git a/packages/cyberstorm/src/components/Markdown/Markdown.module.css b/packages/cyberstorm/src/components/Markdown/Markdown.module.css
index 8249431df..c347f79b7 100644
--- a/packages/cyberstorm/src/components/Markdown/Markdown.module.css
+++ b/packages/cyberstorm/src/components/Markdown/Markdown.module.css
@@ -1,3 +1,7 @@
+/*
+ TODO: NextJS has a copy of this file, figure out a way to import from here to
+ there without relative imports
+*/
.root {
display: flex;
flex-direction: column;