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 + +
+
+ Mods that depend on{" "} + + {params.package} + + {" by "} + + {params.namespace} + +
+
+
+ +
+ +
+
+ ); +} 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
+
+ +
+
+
+
Edit categories
+ +
+
+ {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} + /> +
+ + + + + Manage + + } + > + TODO: SKELETON packageManagement

}> + {packageManagement} +
+
+ + + + + + + Install + + + +
+
+ ); +} 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.name} + +
+
{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 ( +
+ +
Versions
+ + + ); +} + +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;