diff --git a/apps/cyberstorm-remix/app/Markdown.module.css b/apps/cyberstorm-remix/app/Markdown.module.css
index ef2dcc0fe..0bd24531d 100644
--- a/apps/cyberstorm-remix/app/Markdown.module.css
+++ b/apps/cyberstorm-remix/app/Markdown.module.css
@@ -103,6 +103,8 @@
font-family: var(--font-family-monospace);
font-style: normal;
line-height: 150%;
+ white-space: break-spaces;
+ overflow-wrap: break-word;
background: #0d0d21;
}
diff --git a/apps/cyberstorm-remix/app/commonComponents/ListingDependency/ListingDependency.css b/apps/cyberstorm-remix/app/commonComponents/ListingDependency/ListingDependency.css
index 01dc213d6..495c68501 100644
--- a/apps/cyberstorm-remix/app/commonComponents/ListingDependency/ListingDependency.css
+++ b/apps/cyberstorm-remix/app/commonComponents/ListingDependency/ListingDependency.css
@@ -12,12 +12,6 @@
.nimbus-commoncomponents-listingdependency__image {
flex-shrink: 0;
width: 80px;
-
- > svg {
- width: 40px;
- height: 40px;
- color: var(--color-surface-a10);
- }
}
.nimbus-commoncomponents-listingdependency__info {
diff --git a/apps/cyberstorm-remix/app/p/packageListing.css b/apps/cyberstorm-remix/app/p/packageListing.css
index b3cd5c7f7..96639601a 100644
--- a/apps/cyberstorm-remix/app/p/packageListing.css
+++ b/apps/cyberstorm-remix/app/p/packageListing.css
@@ -10,6 +10,7 @@
flex-direction: column;
flex-grow: 1;
gap: var(--space-32);
+ min-width: 0;
}
.nimbus-packagelisting__sidebar {
diff --git a/apps/cyberstorm-remix/app/p/tabs/Required/Required.css b/apps/cyberstorm-remix/app/p/tabs/Required/Required.css
index f54a62539..26193817e 100644
--- a/apps/cyberstorm-remix/app/p/tabs/Required/Required.css
+++ b/apps/cyberstorm-remix/app/p/tabs/Required/Required.css
@@ -1,29 +1,29 @@
.nimbus-packagelisting__tabs__required {
display: flex;
flex-direction: column;
- gap: 1rem;
+ gap: var(--gap-md);
}
.nimbus-packagelisting__tabs__required__title {
display: flex;
flex-direction: column;
- gap: 16px;
+ gap: var(--gap-md);
align-items: flex-start;
align-self: stretch;
- padding-bottom: 24px;
+ padding-bottom: var(--space-24);
}
.nimbus-packagelisting__tabs__required__title__description {
color: var(--color-text-secondary);
- font-weight: 400;
- line-height: 150%;
+ font-weight: var(--font-weight-regular);
+ line-height: var(--line-height-md);
}
.nimbus-packagelisting__tabs__required__body {
display: flex;
flex-direction: column;
- gap: 2px;
+ gap: var(--gap-xxxs);
align-items: flex-start;
align-self: stretch;
- padding-bottom: 32px;
+ padding-bottom: var(--space-32);
}
diff --git a/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.css b/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.css
new file mode 100644
index 000000000..95e62de8c
--- /dev/null
+++ b/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.css
@@ -0,0 +1,34 @@
+.nimbus-packagelisting__tabs__versions {
+ display: flex;
+ flex-direction: column;
+ gap: 1rem;
+}
+
+.nimbus-packagelisting__tabs__versions__actionscell {
+ display: flex;
+ gap: 24px;
+ align-items: flex-start;
+ align-self: stretch;
+ justify-content: flex-end;
+}
+
+.nimbus-packagelisting__tabs__versions__columns__version {
+ color: var(--color-text-primary);
+ font-weight: var(--font-weight-bold);
+ font-size: var(--font-size-body-md);
+ line-height: var(--line-height-md);
+}
+
+.nimbus-packagelisting__tabs__versions__columns__uploaddate {
+ color: var(--color-text-tertiary);
+ font-weight: var(--font-weight-regular);
+ font-size: var(--font-size-body-md);
+ line-height: var(--line-height-md);
+}
+
+.nimbus-packagelisting__tabs__versions__columns__downloads {
+ color: var(--color-text-tertiary);
+ font-weight: var(--font-weight-regular);
+ font-size: var(--font-size-body-md);
+ line-height: var(--line-height-md);
+}
diff --git a/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.module.css b/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.module.css
deleted file mode 100644
index ba22c2837..000000000
--- a/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.module.css
+++ /dev/null
@@ -1,5 +0,0 @@
-.main {
- display: flex;
- flex-direction: column;
- gap: 1rem;
-}
diff --git a/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.tsx b/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.tsx
index 2690ffe18..febadeffc 100644
--- a/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.tsx
+++ b/apps/cyberstorm-remix/app/p/tabs/Versions/Versions.tsx
@@ -1,9 +1,18 @@
-import { faCircleExclamation } from "@fortawesome/free-solid-svg-icons";
+import { faDownload } from "@fortawesome/free-solid-svg-icons";
import { faBoltLightning } from "@fortawesome/free-solid-svg-icons";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
-import styles from "./Versions.module.css";
-import { Table, Sort, Alert, Button } from "@thunderstore/cyberstorm";
+import "./Versions.css";
+import {
+ NewTableSort,
+ NewButton,
+ NewIcon,
+ NewTable,
+ NewTableRows,
+ NewTableLabels,
+ Heading,
+ NewAlert,
+} from "@thunderstore/cyberstorm";
import { LoaderFunctionArgs } from "@remix-run/node";
import { getDapper } from "cyberstorm/dapper/sessionUtils";
import { ApiError } from "@thunderstore/thunderstore-api";
@@ -83,73 +92,99 @@ export default function Versions() {
return
{message}
;
}
- const tableRows = versions.map((v) => [
+ const tableRows: NewTableRows = versions.map((v) => [
{ value: v.version_number, sortValue: v.version_number },
{
value: new Date(v.datetime_created).toUTCString(),
sortValue: v.datetime_created,
},
{ value: v.download_count.toLocaleString(), sortValue: v.download_count },
- { value: , sortValue: 0 },
- { value: , sortValue: 0 },
+ {
+ value: (
+
+
+
+
+ ),
+ sortValue: 0,
+ },
]);
return (
-
+
-
+ Versions
+
+ }
headers={columns}
rows={tableRows}
- sortDirection={Sort.ASC}
- variant="itemListSmall"
+ sortDirection={NewTableSort.ASC}
/>
);
}
-const columns = [
- { value: "Version", disableSort: false },
- { value: "Upload date", disableSort: false },
- { value: "Downloads", disableSort: false },
- { value: "", disableSort: true },
- { value: "", disableSort: true },
+const columns: NewTableLabels = [
+ {
+ value: "Version",
+ disableSort: false,
+ columnClasses: "nimbus-packagelisting__tabs__versions__columns__version",
+ },
+ {
+ value: "Upload date",
+ disableSort: false,
+ columnClasses: "nimbus-packagelisting__tabs__versions__columns__uploaddate",
+ },
+ {
+ value: "Downloads",
+ disableSort: false,
+ columnClasses: "nimbus-packagelisting__tabs__versions__columns__downloads",
+ },
+ { value: "Actions", 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={}
- />
+
+ 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.
+
);
const DownloadLink = (props: { download_url: string }) => (
-
-
- Download
-
-
+
+
+
+
+ Download
+
);
const InstallLink = (props: { install_url: string }) => (
-
-
-
-
-
- Install
-
-
+
+
+
+
+ Install
+
);
diff --git a/packages/cyberstorm-theme/src/components.tsx b/packages/cyberstorm-theme/src/components.tsx
index 8382dac42..2d2f2509a 100644
--- a/packages/cyberstorm-theme/src/components.tsx
+++ b/packages/cyberstorm-theme/src/components.tsx
@@ -50,6 +50,14 @@ export {
type SelectModifiers,
SelectModifiersList,
} from "./components/Select/Select";
+export {
+ type TableVariants,
+ TableVariantsList,
+ type TableSizes,
+ TableSizesList,
+ type TableModifiers,
+ TableModifiersList,
+} from "./components/Table/Table";
export {
type TextInputVariants,
TextInputVariantsList,
@@ -75,6 +83,12 @@ export {
type TagModifiers,
TagModifiersList,
} from "./components/Tag/Tag";
+export {
+ type AlertVariants,
+ AlertVariantsList,
+ type AlertSizes,
+ AlertSizesList,
+} from "./components/Alert/Alert";
export {
type MetaItemVariants,
MetaItemVariantsList,
diff --git a/packages/cyberstorm-theme/src/components/Alert/Alert.css b/packages/cyberstorm-theme/src/components/Alert/Alert.css
new file mode 100644
index 000000000..95aa04044
--- /dev/null
+++ b/packages/cyberstorm-theme/src/components/Alert/Alert.css
@@ -0,0 +1,72 @@
+@layer theme-components {
+ /* SIZES */
+ .ts-alert:where(.ts-size--small) {
+ --alert-gap: var(--alert-sm-gap);
+ --alert-padding-block: var(--alert-sm-padding-block);
+ --alert-padding-inline: var(--alert-sm-padding-inline);
+ --alert-font-size: var(--alert-sm-font-size);
+ --alert-font-weight: var(--alert-sm-font-weight);
+ --alert-line-height: var(--alert-sm-line-height);
+ --alert-icon-width: var(--alert-sm-icon-width);
+ --alert-icon-height: var(--alert-sm-icon-height);
+ --alert-border-radius: var(--alert-sm-border-radius);
+ }
+
+ /* VARIANTS */
+ .ts-alert:where(.ts-variant--danger) {
+ --alert-background-color: var(--alert-danger-bg-color--default);
+ --alert-border-color: var(--alert-danger-border-color--default);
+ --alert-icon-color: var(--alert-danger-icon-color--default);
+ --alert-color: var(--alert-danger-text-color--default);
+ }
+
+ .ts-alert:where(.ts-variant--info) {
+ --alert-background-color: var(--alert-info-bg-color--default);
+ --alert-border-color: var(--alert-info-border-color--default);
+ --alert-icon-color: var(--alert-info-icon-color--default);
+ --alert-color: var(--alert-info-text-color--default);
+ }
+
+ .ts-alert:where(.ts-variant--success) {
+ --alert-background-color: var(--alert-success-bg-color--default);
+ --alert-border-color: var(--alert-success-border-color--default);
+ --alert-icon-color: var(--alert-success-icon-color--default);
+ --alert-color: var(--alert-success-text-color--default);
+ }
+
+ .ts-alert:where(.ts-variant--warning) {
+ --alert-background-color: var(--alert-warning-bg-color--default);
+ --alert-border-color: var(--alert-warning-border-color--default);
+ --alert-icon-color: var(--alert-warning-icon-color--default);
+ --alert-color: var(--alert-warning-text-color--default);
+ }
+
+ /* TOKENS */
+ :root {
+ --alert-danger-bg-color--default: var(--color-accent-red-2);
+ --alert-danger-border-color--default: var(--color-accent-red-7);
+ --alert-danger-icon-color--default: var(--color-accent-red-7);
+ --alert-danger-text-color--default: var(--color-accent-red-11);
+ --alert-info-bg-color--default: var(--color-accent-blue-2);
+ --alert-info-border-color--default: var(--color-accent-blue-7);
+ --alert-info-icon-color--default: var(--color-accent-blue-7);
+ --alert-info-text-color--default: var(--color-accent-blue-11);
+ --alert-success-bg-color--default: var(--color-accent-green-2);
+ --alert-success-border-color--default: var(--color-accent-green-7);
+ --alert-success-icon-color--default: var(--color-accent-green-7);
+ --alert-success-text-color--default: var(--color-accent-green-11);
+ --alert-warning-bg-color--default: var(--color-accent-yellow-2);
+ --alert-warning-border-color--default: var(--color-accent-yellow-7);
+ --alert-warning-icon-color--default: var(--color-accent-yellow-7);
+ --alert-warning-text-color--default: var(--color-accent-yellow-11);
+ --alert-sm-gap: var(--space-16);
+ --alert-sm-padding-block: var(--space-16);
+ --alert-sm-padding-inline: var(--space-24);
+ --alert-sm-font-size: var(--font-size-body-md);
+ --alert-sm-font-weight: var(--font-weight-regular);
+ --alert-sm-line-height: var(--line-height-md);
+ --alert-sm-icon-width: 1.125rem;
+ --alert-sm-icon-height: 1.375rem;
+ --alert-sm-border-radius: var(--radius-sm);
+ }
+}
diff --git a/packages/cyberstorm-theme/src/components/Alert/Alert.ts b/packages/cyberstorm-theme/src/components/Alert/Alert.ts
new file mode 100644
index 000000000..6bbaf2f86
--- /dev/null
+++ b/packages/cyberstorm-theme/src/components/Alert/Alert.ts
@@ -0,0 +1,12 @@
+// Variants
+export const AlertVariantsList = [
+ "info",
+ "success",
+ "warning",
+ "danger",
+] as const;
+export type AlertVariants = "info" | "success" | "warning" | "danger";
+
+// Sizes
+export const AlertSizesList = ["small"] as const;
+export type AlertSizes = "small";
diff --git a/packages/cyberstorm-theme/src/components/Table/Table.css b/packages/cyberstorm-theme/src/components/Table/Table.css
new file mode 100644
index 000000000..8a31800a7
--- /dev/null
+++ b/packages/cyberstorm-theme/src/components/Table/Table.css
@@ -0,0 +1,49 @@
+@layer theme-components {
+ /* SELECT */
+
+ /* VARIANTS */
+ .ts-table:where(.ts-variant--default) {
+ --select-background-color: var(--dropdown-bg-color--default);
+ --select-border-color: var(--dropdown-border-color--default);
+ --select-box-shadow: var(--shadow-lg);
+ --select-animation: fade-in var(--animation-duration-md) ease;
+ --select-border: var(--space-px) var(--select-border-color) solid;
+ }
+
+ /* SIZES */
+ .ts-table:where(.ts-size--medium) {
+ --select-border-radius: var(--dropdown-md-border-radius);
+ --select-padding: var(--dropdown-md-padding);
+ }
+
+ :root {
+ --dropdown-bg-color--default: var(--color-surface-4);
+ --dropdown-border-color--default: var(--color-surface-a6);
+ --dropdown-item-bg-color--default: #0000;
+ --dropdown-item-bg-color--hover: var(--color-surface-a7);
+ --dropdown-item-icon-color--default: var(--color-text-tertiary);
+ --dropdown-item-icon-color--hover: var(--color-text-primary);
+ --dropdown-item-text-color--default: var(--color-text-primary);
+ --dropdown-item-text-color--hover: var(--color-text-primary);
+ --dropdown-item-danger-bg-color--default: #0000;
+ --dropdown-item-danger-bg-color--hover: var(--color-accent-red-6);
+ --dropdown-item-danger-icon-color--default: var(--color-accent-red-7);
+ --dropdown-item-danger-icon-color--hover: #fff;
+ --dropdown-item-danger-text-color--default: var(--color-accent-red-7);
+ --dropdown-item-danger-text-color--hover: #fff;
+ --dropdown-item-disabled-bg-color--default: #0000;
+ --dropdown-item-disabled-bg-color--hover: #0000;
+ --dropdown-item-disabled-icon-color--default: var(--color-text-tertiary);
+ --dropdown-item-disabled-icon-color--hover: var(--color-text-tertiary);
+ --dropdown-item-disabled-text-color--default: var(--color-text-tertiary);
+ --dropdown-item-disabled-text-color--hover: var(--color-text-tertiary);
+ --dropdown-md-border-radius: var(--radius-md);
+ --dropdown-md-padding: var(--space-8) 0;
+ --dropdown-item-md-gap: var(--gap-md);
+ --dropdown-item-md-padding: var(--space-12) var(--space-16);
+ --dropdown-item-md-font-weight: var(--font-weight-regular);
+ --dropdown-item-md-font-size: var(--font-size-body-md);
+ --select-trigger-md-font-weight: var(--font-weight-bold);
+ --select-trigger-md-font-size: var(--font-size-body-md);
+ }
+}
diff --git a/packages/cyberstorm-theme/src/components/Table/Table.ts b/packages/cyberstorm-theme/src/components/Table/Table.ts
new file mode 100644
index 000000000..9806c0546
--- /dev/null
+++ b/packages/cyberstorm-theme/src/components/Table/Table.ts
@@ -0,0 +1,15 @@
+// Table ROOT
+// Variants
+export const TableVariantsList = ["default"] as const;
+export type TableVariants = "default";
+
+// Sizes
+export const TableSizesList = ["medium"] as const;
+export type TableSizes = "medium";
+
+// Modifiers
+export const TableModifiersList = [] as const;
+// There is an issue with Typescript (eslint) and prettier disagreeing if
+// the type should have parentheses
+// prettier-ignore
+export type TableModifiers = typeof TableModifiersList[number];
diff --git a/packages/cyberstorm-theme/src/index.tsx b/packages/cyberstorm-theme/src/index.tsx
index ff3bd0386..34efd92de 100644
--- a/packages/cyberstorm-theme/src/index.tsx
+++ b/packages/cyberstorm-theme/src/index.tsx
@@ -10,7 +10,9 @@ import "./components/TextInput/TextInput.css";
import "./components/Icon/Icon.css";
import "./components/BreadCrumbs/BreadCrumbs.css";
import "./components/Select/Select.css";
+import "./components/Table/Table.css";
import "./components/Tag/Tag.css";
+import "./components/Alert/Alert.css";
import "./components/MetaItem/MetaItem.css";
import "./components/Link/Link.css";
import "./components/Image/Image.css";
diff --git a/packages/cyberstorm/src/index.ts b/packages/cyberstorm/src/index.ts
index 3a806b85a..cd240ab5b 100644
--- a/packages/cyberstorm/src/index.ts
+++ b/packages/cyberstorm/src/index.ts
@@ -113,6 +113,7 @@ export {
} from "./newComponents/Select/Select";
export { Icon as NewIcon } from "./newComponents/Icon/Icon";
export { Tag as NewTag } from "./newComponents/Tag/Tag";
+export { Alert as NewAlert } from "./newComponents/Alert/Alert";
export { MetaItem as NewMetaItem } from "./newComponents/MetaItem/MetaItem";
export { Pagination as NewPagination } from "./newComponents/Pagination/Pagination";
export {
@@ -123,3 +124,9 @@ export {
export { Image } from "./newComponents/Image/Image";
export { AdContainer } from "./newComponents/AdContainer/AdContainer";
export { Tabs } from "./newComponents/Tabs/Tabs";
+export {
+ Table as NewTable,
+ TableSort as NewTableSort,
+ type TableRows as NewTableRows,
+ type TableLabels as NewTableLabels,
+} from "./newComponents/Table/Table";
diff --git a/packages/cyberstorm/src/newComponents/Alert/Alert.css b/packages/cyberstorm/src/newComponents/Alert/Alert.css
new file mode 100644
index 000000000..24985637b
--- /dev/null
+++ b/packages/cyberstorm/src/newComponents/Alert/Alert.css
@@ -0,0 +1,30 @@
+@layer components {
+ .ts-alert {
+ display: flex;
+
+ gap: var(--alert-gap);
+ align-items: flex-start;
+ align-self: stretch;
+
+ border-left: 3px solid var(--alert-border-color);
+ border-radius: var(--alert-border-radius);
+ background-color: var(--alert-background-color);
+ padding-block: var(--alert-padding-block);
+ padding-inline: var(--alert-padding-inline);
+
+ > .ts-alert__icon {
+ width: var(--alert-icon-width);
+ height: var(--alert-icon-height);
+
+ --icon-color: var(--alert-icon-color);
+ }
+
+ > .ts-alert__content {
+ min-width: 0;
+ color: var(--alert-color);
+ font-weight: var(--alert-font-weight);
+ font-size: var(--alert-font-size);
+ line-height: var(--alert-line-height);
+ }
+ }
+}
diff --git a/packages/cyberstorm/src/newComponents/Alert/Alert.tsx b/packages/cyberstorm/src/newComponents/Alert/Alert.tsx
new file mode 100644
index 000000000..91c5bfe19
--- /dev/null
+++ b/packages/cyberstorm/src/newComponents/Alert/Alert.tsx
@@ -0,0 +1,62 @@
+import "./Alert.css";
+import React from "react";
+import { classnames, componentClasses } from "../../utils/utils";
+import {
+ AlertSizes,
+ AlertVariants,
+} from "@thunderstore/cyberstorm-theme/src/components";
+import {
+ faCheckCircle,
+ faExclamationCircle,
+ faExclamationTriangle,
+} from "@fortawesome/free-solid-svg-icons";
+import { faOctagonExclamation } from "@fortawesome/pro-solid-svg-icons";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import { NewIcon, PrimitiveComponentDefaultProps } from "../..";
+
+interface AlertProps extends PrimitiveComponentDefaultProps {
+ csVariant?: AlertVariants;
+ csSize?: AlertSizes;
+}
+
+export const Alert = React.forwardRef(
+ (props: AlertProps, forwardedRef) => {
+ const {
+ children,
+ rootClasses,
+ csVariant = "info",
+ csSize = "small",
+ ...forwardedProps
+ } = props;
+
+ const icon = getIcon(csVariant);
+
+ return (
+
+
+
+
+ {children}
+
+ );
+ }
+);
+
+Alert.displayName = "Alert";
+
+const getIcon = (scheme: AlertProps["csVariant"] = "info") => {
+ return {
+ info: faExclamationCircle,
+ success: faCheckCircle,
+ warning: faExclamationTriangle,
+ danger: faOctagonExclamation,
+ }[scheme];
+};
diff --git a/packages/cyberstorm/src/newComponents/Card/CardCommunity/CardCommunity.css b/packages/cyberstorm/src/newComponents/Card/CardCommunity/CardCommunity.css
index 619b6f9bb..86e4fabda 100644
--- a/packages/cyberstorm/src/newComponents/Card/CardCommunity/CardCommunity.css
+++ b/packages/cyberstorm/src/newComponents/Card/CardCommunity/CardCommunity.css
@@ -8,7 +8,7 @@
font-size: var(--font-size-body-lg);
}
- .ts-cardcommunity__imagewrapper:hover {
+ .ts-cardcommunity__image:hover {
filter: brightness(1.2);
}
@@ -18,12 +18,12 @@
outline-offset: 0.5rem;
}
- .ts-cardcommunity .ts-cardcommunity__imagewrapper > div {
+ .ts-cardcommunity .ts-cardcommunity__image > div {
transform-origin: bottom;
}
- .ts-cardcommunity:hover .ts-cardcommunity__imagewrapper > div,
- .ts-cardcommunity:focus-within .ts-cardcommunity__imagewrapper > div {
+ .ts-cardcommunity:hover .ts-cardcommunity__image > div,
+ .ts-cardcommunity:focus-within .ts-cardcommunity__image > div {
transform: scale(1.035);
}
diff --git a/packages/cyberstorm/src/newComponents/Card/CardCommunity/CardCommunity.tsx b/packages/cyberstorm/src/newComponents/Card/CardCommunity/CardCommunity.tsx
index 9834b5e82..01b4296c2 100644
--- a/packages/cyberstorm/src/newComponents/Card/CardCommunity/CardCommunity.tsx
+++ b/packages/cyberstorm/src/newComponents/Card/CardCommunity/CardCommunity.tsx
@@ -53,7 +53,7 @@ export function CardCommunity(props: Props) {
diff --git a/packages/cyberstorm/src/newComponents/Image/Image.css b/packages/cyberstorm/src/newComponents/Image/Image.css
index 0a024a630..7ce80fc79 100644
--- a/packages/cyberstorm/src/newComponents/Image/Image.css
+++ b/packages/cyberstorm/src/newComponents/Image/Image.css
@@ -44,6 +44,8 @@
}
.ts-image__icon {
- width: 100%;
+ width: 50px;
+ height: 50px;
+ color: var(--color-surface-a10);
}
}
diff --git a/packages/cyberstorm/src/newComponents/Table/Table.css b/packages/cyberstorm/src/newComponents/Table/Table.css
new file mode 100644
index 000000000..b11b9f97f
--- /dev/null
+++ b/packages/cyberstorm/src/newComponents/Table/Table.css
@@ -0,0 +1,98 @@
+@layer components {
+ .ts-table {
+ --table-border: 1px solid var(--color-surface-a8);
+
+ width: 100%;
+ border-collapse: separate;
+ border-spacing: 0;
+
+ tr > th,
+ tr > td {
+ padding: 8px 16px;
+ border-bottom: var(--table-border);
+ }
+
+ tr > td:first-child,
+ tr > th:first-child {
+ border-left: var(--table-border);
+ }
+
+ tr > td:last-child,
+ tr > th:last-child {
+ border-right: var(--table-border);
+ }
+
+ tr:first-child > th {
+ border-top: var(--table-border);
+ }
+
+ tr:first-child > th:first-child {
+ border-top-left-radius: var(--radius-md);
+ }
+
+ tr:first-child > th:last-child {
+ border-top-right-radius: var(--radius-md);
+ }
+
+ tr:first-child > th:only-child {
+ border-top-left-radius: var(--radius-md);
+ border-top-right-radius: var(--radius-md);
+ }
+
+ tr:last-child > td:first-child,
+ tr:last-child > th:first-child {
+ border-bottom-left-radius: var(--radius-md);
+ }
+
+ tr:last-child > td:last-child,
+ tr:last-child > th:last-child {
+ border-bottom-right-radius: var(--radius-md);
+ }
+ }
+
+ .ts-table__caption {
+ padding: 1rem;
+ border-top: var(--table-border);
+ border-right: var(--table-border);
+ border-left: var(--table-border);
+ border-top-left-radius: var(--radius-md);
+ border-top-right-radius: var(--radius-md);
+ text-align: left;
+ }
+
+ .ts-table__header {
+ color: var(--color-text-tertiary);
+ font-weight: 700;
+
+ font-size: var(--font-size-body-md);
+ line-height: 150%; /* 21px */
+ text-align: left;
+ background: var(--color-surface-a4);
+ }
+
+ .ts-table__sortbutton {
+ display: flex;
+ gap: 1rem;
+ align-items: center;
+ background: transparent;
+ }
+
+ .ts-table__row {
+ :last-child {
+ text-align: right;
+ }
+
+ :last-child > .ts-table__sortbutton {
+ float: right;
+ text-align: right;
+ }
+ }
+
+ .ts-table__item {
+ padding: 8px 16px;
+ }
+
+ :root {
+ --table-border: 1px solid var(--color-surface-a8);
+ }
+}
diff --git a/packages/cyberstorm/src/newComponents/Table/Table.tsx b/packages/cyberstorm/src/newComponents/Table/Table.tsx
new file mode 100644
index 000000000..3037baede
--- /dev/null
+++ b/packages/cyberstorm/src/newComponents/Table/Table.tsx
@@ -0,0 +1,199 @@
+import { CSSProperties, ReactNode, useState } from "react";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import {
+ faSort,
+ faSortDown,
+ faSortUp,
+} from "@fortawesome/free-solid-svg-icons";
+import "./Table.css";
+import { NewIcon } from "../..";
+import { classnames, componentClasses } from "../../utils/utils";
+import {
+ TableVariants,
+ TableSizes,
+ TableModifiers,
+} from "@thunderstore/cyberstorm-theme/src/components";
+import React from "react";
+
+interface SortButtonProps {
+ identifier: number;
+ current: number;
+ direction: TableSort;
+ hook: React.Dispatch<
+ React.SetStateAction<{ identifier: number; direction: TableSort }>
+ >;
+ label: string;
+}
+
+export enum TableSort {
+ DESC = -1,
+ OFF,
+ ASC,
+}
+
+interface TableItem {
+ value: ReactNode;
+ sortValue: string | number;
+}
+
+export type TableLabels = {
+ value: string;
+ disableSort: boolean;
+ columnClasses?: string;
+}[];
+
+type TableRow = TableItem[];
+
+export type TableRows = TableRow[];
+
+export interface TableProps {
+ titleRowContent?: ReactNode;
+ headers: TableLabels;
+ rows: TableRows;
+ disableSort?: boolean;
+ sortByHeader?: number;
+ sortDirection?: TableSort;
+ gridTemplateColumns?: string;
+ rootClasses?: string;
+ csVariant?: TableVariants;
+ csSize?: TableSizes;
+ csModifiers?: TableModifiers[];
+}
+
+function SortButton(props: SortButtonProps) {
+ const { identifier, current, direction = TableSort.OFF, hook, label } = props;
+
+ const hookParams = { identifier, direction: TableSort.DESC };
+ let icon = faSort;
+
+ if (identifier === current) {
+ hookParams.direction =
+ direction === TableSort.ASC ? TableSort.DESC : TableSort.ASC;
+ icon = direction === TableSort.ASC ? faSortDown : faSortUp;
+ }
+
+ return (
+
+ );
+}
+
+export const Table = React.forwardRef(
+ (props: TableProps, forwardedRef) => {
+ const {
+ titleRowContent,
+ headers,
+ rows,
+ sortByHeader = 0,
+ sortDirection = TableSort.DESC,
+ disableSort = false,
+ gridTemplateColumns,
+ rootClasses,
+ csVariant = "default",
+ csSize = "medium",
+ csModifiers = [],
+ } = props;
+
+ const [sortVariables, setSortVariables] = useState({
+ identifier: sortByHeader,
+ direction: sortDirection,
+ });
+
+ function compare(a: TableRow, b: TableRow) {
+ const column = sortVariables.identifier;
+ if (a[column] && b[column] && a[column].sortValue < b[column].sortValue) {
+ return sortVariables.direction;
+ }
+ if (a[column] && b[column] && a[column].sortValue > b[column].sortValue) {
+ return -sortVariables.direction;
+ }
+ return 0;
+ }
+
+ if (!disableSort) {
+ rows.sort(compare);
+ }
+
+ // const rowCount = { "--row-count": rows.length } as CSSProperties;
+ let columnCSSProps = {};
+ if (gridTemplateColumns) {
+ columnCSSProps = {
+ "--column-count": headers.length,
+ "--dynamic-grid-template-columns": gridTemplateColumns,
+ } as CSSProperties;
+ } else {
+ columnCSSProps = { "--column-count": headers.length } as CSSProperties;
+ }
+
+ return (
+
+
+
+
+ {titleRowContent ? (
+ {titleRowContent}
+ ) : null}
+
+
+ {headers.map((header, headerI) => (
+
+ {header.disableSort ? (
+ header.value
+ ) : (
+
+ )}
+ |
+ ))}
+
+
+
+ {rows.map((row, rowI) => (
+
+ {row.map((col, colI) => (
+
+ {col.value}
+ |
+ ))}
+
+ ))}
+
+
+ );
+ }
+);
+
+Table.displayName = "Table";
diff --git a/packages/cyberstorm/src/utils/utils.ts b/packages/cyberstorm/src/utils/utils.ts
index 2dca67f05..54cfa0dc9 100644
--- a/packages/cyberstorm/src/utils/utils.ts
+++ b/packages/cyberstorm/src/utils/utils.ts
@@ -30,6 +30,7 @@ export const formatFileSize = (bytes: number) => {
}).format(bytes);
};
+// TODO: FIX: Adds a empty space at the end when last item is undefined
export const classnames = (
...classnames: (string | null | undefined)[]
): string => {