-
} />
-
-
- {sortable => (
- {sortable}
- )}
-
-
+
+
+
+
+ }
+ placeholder="Search for content"
+ />
+
+ }
+ >
+
+ {sortable => (
+ {sortable}
+ )}
+
+
+
+
+
+ }
+ children="From URL"
+ />
+ }
+ children="From File"
+ buttonStyle="secondary"
+ />
+
+
+
+
+ {/* eslint-disable-next-line ts/no-use-before-define -- blh */}
+
+ {row => (
+ <>
+
+
+
+ >
+ )}
+
+
+
+
+ );
+}
+
+const _modRowData: ModsRowProps[] = [
+ {
+ header: 'Highly Endorsed',
+ category: 'endorsed',
+ mods: [
+ {
+ name: 'EvergreenHUD',
+ description: 'Improves your heads up display.',
+ author: 'Polyfrost',
+ icon_url: 'https://cdn.modrinth.com/data/1yIQcc2b/icon.png',
+ page_url: 'https://modrinth.com/mod/evergreenhud',
+ provider: Provider.Modrinth,
+ downloads: 281700,
+ ratings: 220,
+ },
+ ],
+ },
+];
+
+interface ModsRowProps {
+ header: string;
+ category: string;
+ mods: Mod[];
+};
+
+interface Mod {
+ name: string;
+ description: string;
+ author: string;
+ icon_url: string;
+ provider: Provider;
+ page_url: string;
+ downloads: number;
+ ratings: number;
+}
+
+function ModsRow(props: ModsRowProps) {
+ return (
+
+
+
+
+
+ {mod => }
+
+
+
+
+ );
+}
+
+function ModCard(props: Mod) {
+ return (
+
+
+

+

+
+
+
+
{props.name}
+
+ By
+ {' '}
+ {props.author}
+ {' '}
+ on
+ {' '}
+ {Provider[props.provider]}
+
+
+
+
{props.description}
+
+
+
+
+ {abbreviateNumber(props.downloads)}
+
+
+
+
+ {abbreviateNumber(props.ratings)}
+
+
);
diff --git a/desktop/src/ui/pages/browser/BrowserRoot.tsx b/desktop/src/ui/pages/browser/BrowserRoot.tsx
index c8cdde62..bf12b62b 100644
--- a/desktop/src/ui/pages/browser/BrowserRoot.tsx
+++ b/desktop/src/ui/pages/browser/BrowserRoot.tsx
@@ -1,11 +1,13 @@
import { Route } from '@solidjs/router';
import type { ParentProps } from 'solid-js';
import BrowserMain from './BrowserMain';
+import BrowserCategory from './BrowserCategory';
function BrowserRoutes() {
return (
<>
+
>
);
}
diff --git a/desktop/src/ui/pages/cluster/cluster/ClusterOverview.tsx b/desktop/src/ui/pages/cluster/cluster/ClusterOverview.tsx
index 117fd65d..16d285ab 100644
--- a/desktop/src/ui/pages/cluster/cluster/ClusterOverview.tsx
+++ b/desktop/src/ui/pages/cluster/cluster/ClusterOverview.tsx
@@ -5,7 +5,7 @@ import Button from '../../../components/base/Button';
import ScrollableContainer from '~ui/components/ScrollableContainer';
import Sidebar from '~ui/components/Sidebar';
import type { Cluster } from '~bindings';
-import { upperFirst } from '~utils/string';
+import { upperFirst } from '~utils/primitives';
import useClusterContext from '~ui/hooks/useCluster';
function ClusterOverview() {
diff --git a/desktop/src/ui/pages/settings/launcher/SettingsGeneral.tsx b/desktop/src/ui/pages/settings/launcher/SettingsGeneral.tsx
index 1e8395bc..a4f1944b 100644
--- a/desktop/src/ui/pages/settings/launcher/SettingsGeneral.tsx
+++ b/desktop/src/ui/pages/settings/launcher/SettingsGeneral.tsx
@@ -6,6 +6,7 @@ import Toggle from '~ui/components/base/Toggle';
import Sidebar from '~ui/components/Sidebar';
import useSettingsContext from '~ui/hooks/useSettings';
import Button from '~ui/components/base/Button';
+import DiscordIcon from '~assets/logos/discord.svg?component-solid';
function SettingsGeneral() {
const settings = useSettingsContext();
@@ -18,7 +19,7 @@ function SettingsGeneral() {
}
+ icon={
}
>
= 1e3 && n < 1e6)
+ return `${+(n / 1e3).toFixed(1)}K`;
+ if (n >= 1e6 && n < 1e9)
+ return `${+(n / 1e6).toFixed(1)}M`;
+ if (n >= 1e9 && n < 1e12)
+ return `${+(n / 1e9).toFixed(1)}B`;
+ if (n >= 1e12)
+ return `${+(n / 1e12).toFixed(1)}T`;
+};
+
+export default {
+ upperFirst,
+ abbreviateNumber,
+};
diff --git a/desktop/src/utils/string.ts b/desktop/src/utils/string.ts
deleted file mode 100644
index 7eba83a5..00000000
--- a/desktop/src/utils/string.ts
+++ /dev/null
@@ -1,8 +0,0 @@
-export function upperFirst(object: any): string {
- const str = object.toString();
- return str.charAt(0).toUpperCase() + str.slice(1);
-}
-
-export default {
- upperFirst,
-};
diff --git a/desktop/tsconfig.json b/desktop/tsconfig.json
index 68a81e39..a6820e81 100644
--- a/desktop/tsconfig.json
+++ b/desktop/tsconfig.json
@@ -14,7 +14,11 @@
},
"resolveJsonModule": true,
- "types": ["vitest/globals", "@testing-library/jest-dom"],
+ "types": [
+ "vitest/globals",
+ "@testing-library/jest-dom",
+ "vite-plugin-solid-svg/types"
+ ],
"allowImportingTsExtensions": true,
"strict": true,
"noFallthroughCasesInSwitch": true,
diff --git a/desktop/vite.config.ts b/desktop/vite.config.ts
index b3411d90..84d48ac6 100644
--- a/desktop/vite.config.ts
+++ b/desktop/vite.config.ts
@@ -5,6 +5,7 @@ import type { Plugin, UserConfig } from 'vite';
import { defineConfig, loadEnv } from 'vite';
import solid from 'vite-plugin-solid';
+import solidSvg from 'vite-plugin-solid-svg';
import paths from 'vite-tsconfig-paths';
import unocss from 'unocss/vite';
@@ -15,6 +16,9 @@ export default defineConfig(async ({ mode }) => {
plugins: [
unocss(),
solid(),
+ solidSvg({
+ defaultAsComponent: false,
+ }),
paths(),
devtools(),
],
diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml
index 48b62fa4..cf38e9f9 100644
--- a/pnpm-lock.yaml
+++ b/pnpm-lock.yaml
@@ -162,6 +162,9 @@ importers:
vite-plugin-solid:
specifier: ^2.10.2
version: 2.10.2(@testing-library/jest-dom@6.4.6(vitest@1.6.0(@types/node@20.14.3)(@vitest/ui@1.6.0(vitest@1.6.0))(jsdom@24.1.0)(sass@1.77.6)))(solid-js@1.8.17)(vite@5.3.1(@types/node@20.14.3)(sass@1.77.6))
+ vite-plugin-solid-svg:
+ specifier: ^0.8.1
+ version: 0.8.1(solid-js@1.8.17)(vite@5.3.1(@types/node@20.14.3)(sass@1.77.6))
vite-tsconfig-paths:
specifier: ^4.3.2
version: 4.3.2(typescript@5.4.5)(vite@5.3.1(@types/node@20.14.3)(sass@1.77.6))
@@ -1116,6 +1119,10 @@ packages:
peerDependencies:
solid-js: ^1.5
+ '@trysound/sax@0.2.0':
+ resolution: {integrity: sha512-L7z9BgrNEcYyUYtF+HaEfiS5ebkh9jXqbszz7pC0hRBPaatV0XjSD3+eHrpqFemQfgwiFF0QPIarnIihIDn7OA==}
+ engines: {node: '>=10.13.0'}
+
'@tsconfig/node10@1.0.11':
resolution: {integrity: sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==}
@@ -1588,6 +1595,10 @@ packages:
resolution: {integrity: sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==}
engines: {node: '>= 0.8'}
+ commander@7.2.0:
+ resolution: {integrity: sha512-QrWXB+ZQSVPmIWIhtEO9H+gwHaMGYiF5ChvoJ+K9ZGHG/sVsa6yiesAD1GC/x46sET00Xlwo1u49RVVVzvcSkw==}
+ engines: {node: '>= 10'}
+
comment-parser@1.4.1:
resolution: {integrity: sha512-buhp5kePrmda3vhc5B9t7pUQXAb2Tnd0qgpkIhPhkHXxJpiPJ11H0ZEU0oBpJ2QztSbzG/ZxMj/CHsYJqRHmyg==}
engines: {node: '>= 12.0.0'}
@@ -1615,10 +1626,21 @@ packages:
resolution: {integrity: sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==}
engines: {node: '>= 8'}
+ css-select@5.1.0:
+ resolution: {integrity: sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==}
+
+ css-tree@2.2.1:
+ resolution: {integrity: sha512-OA0mILzGc1kCOCSJerOeqDxDQ4HOh+G8NbOJFOTgOCzpw7fCBubk0fEyxp8AgOL/jvLgYA/uV0cMbe43ElF1JA==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
+
css-tree@2.3.1:
resolution: {integrity: sha512-6Fv1DV/TYw//QF5IzQdqsNDjx/wc8TrMBZsqjL9eW01tWb7R7k/mq+/VXfJCl7SoD5emsJop9cOByJZfs8hYIw==}
engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0}
+ css-what@6.1.0:
+ resolution: {integrity: sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==}
+ engines: {node: '>= 6'}
+
css.escape@1.5.1:
resolution: {integrity: sha512-YUifsXXuknHlUsmlgyY0PKzgPOr7/FjCePfHNt0jxm83wHZi44VDMQ7/fGNkjY3/jV1MC+1CmZbaHzugyeRtpg==}
@@ -1627,6 +1649,10 @@ packages:
engines: {node: '>=4'}
hasBin: true
+ csso@5.0.5:
+ resolution: {integrity: sha512-0LrrStPOdJj+SPCCrGhzryycLjwcgUSHBtxNA8aIDxf0GLsRh1cKYhB00Gd1lDOS4yGH69+SNn13+TWbVHETFQ==}
+ engines: {node: ^10 || ^12.20.0 || ^14.13.0 || >=15.0.0, npm: '>=7.0.0'}
+
cssstyle@4.0.1:
resolution: {integrity: sha512-8ZYiJ3A/3OkDd093CBT/0UKDWry7ak4BdPTFP2+QEP7cmhouyq/Up709ASSj2cK02BbZiMgk7kYjZNS4QP5qrQ==}
engines: {node: '>=18'}
@@ -1710,6 +1736,19 @@ packages:
dom-accessibility-api@0.6.3:
resolution: {integrity: sha512-7ZgogeTnjuHbo+ct10G9Ffp0mif17idi0IyWNVA/wcwcm7NPOD/WEHVP3n7n3MhXqxoIYm8d6MuZohYWIZ4T3w==}
+ dom-serializer@2.0.0:
+ resolution: {integrity: sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==}
+
+ domelementtype@2.3.0:
+ resolution: {integrity: sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==}
+
+ domhandler@5.0.3:
+ resolution: {integrity: sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==}
+ engines: {node: '>= 4'}
+
+ domutils@3.1.0:
+ resolution: {integrity: sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==}
+
dotenv@16.4.5:
resolution: {integrity: sha512-ZmdL2rui+eB2YwhsWzjInR8LldtZHGDoQ1ugH85ppHKwpUHL7j7rN0Ti9NCnGiQbhaZ11FpR+7ao1dNsmduNUg==}
engines: {node: '>=12'}
@@ -2409,6 +2448,9 @@ packages:
mdast-util-to-string@2.0.0:
resolution: {integrity: sha512-AW4DRS3QbBayY/jJmD8437V1Gombjf8RSOUCMFBuo5iHi58AGEgVCKQ+ezHkZZDpAQS75hcBMpLqjpJTjtUL7w==}
+ mdn-data@2.0.28:
+ resolution: {integrity: sha512-aylIc7Z9y4yzHYAJNuESG3hfhC+0Ibp/MAMiaOZgNv4pmEdFyfZhhhny4MNiAfWdBQ1RQ2mfDWmM1x8SvGyp8g==}
+
mdn-data@2.0.30:
resolution: {integrity: sha512-GaqWWShW4kv/G9IEucWScBx9G1/vsFZZJUO+tD26M8J8z3Kw5RDQjaoZe03YAClgeS/SWPOcb4nkFBTEi5DUEA==}
@@ -2962,6 +3004,11 @@ packages:
resolution: {integrity: sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==}
engines: {node: '>= 0.4'}
+ svgo@3.3.2:
+ resolution: {integrity: sha512-OoohrmuUlBs8B8o6MB2Aevn+pRIH9zDALSR+6hhqVfa6fRwG/Qw9VUMSMW9VNg2CFc/MTIfabtdOVl9ODIJjpw==}
+ engines: {node: '>=14.0.0'}
+ hasBin: true
+
symbol-tree@3.2.4:
resolution: {integrity: sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw==}
@@ -3159,6 +3206,12 @@ packages:
engines: {node: ^18.0.0 || >=20.0.0}
hasBin: true
+ vite-plugin-solid-svg@0.8.1:
+ resolution: {integrity: sha512-ROGC2ae1eYUCMd+zfJtsbUtuZwsb6DZS0+Sy5/ZXDokOunGi0Ez/cL7OPdsixN3I0/rNYd/3hilo3kpRMAS+IA==}
+ peerDependencies:
+ solid-js: ^1
+ vite: '>=4'
+
vite-plugin-solid@2.10.2:
resolution: {integrity: sha512-AOEtwMe2baBSXMXdo+BUwECC8IFHcKS6WQV/1NEd+Q7vHPap5fmIhLcAzr+DUJ04/KHx/1UBU0l1/GWP+rMAPQ==}
peerDependencies:
@@ -4276,6 +4329,8 @@ snapshots:
dependencies:
solid-js: 1.8.17
+ '@trysound/sax@0.2.0': {}
+
'@tsconfig/node10@1.0.11': {}
'@tsconfig/node12@1.0.11': {}
@@ -4752,8 +4807,7 @@ snapshots:
binary-extensions@2.3.0: {}
- boolbase@1.0.0:
- optional: true
+ boolbase@1.0.0: {}
brace-expansion@1.1.11:
dependencies:
@@ -4902,6 +4956,8 @@ snapshots:
dependencies:
delayed-stream: 1.0.0
+ commander@7.2.0: {}
+
comment-parser@1.4.1: {}
concat-map@0.0.1: {}
@@ -4924,16 +4980,35 @@ snapshots:
shebang-command: 2.0.0
which: 2.0.2
+ css-select@5.1.0:
+ dependencies:
+ boolbase: 1.0.0
+ css-what: 6.1.0
+ domhandler: 5.0.3
+ domutils: 3.1.0
+ nth-check: 2.1.1
+
+ css-tree@2.2.1:
+ dependencies:
+ mdn-data: 2.0.28
+ source-map-js: 1.2.0
+
css-tree@2.3.1:
dependencies:
mdn-data: 2.0.30
source-map-js: 1.2.0
+ css-what@6.1.0: {}
+
css.escape@1.5.1: {}
cssesc@3.0.0:
optional: true
+ csso@5.0.5:
+ dependencies:
+ css-tree: 2.2.1
+
cssstyle@4.0.1:
dependencies:
rrweb-cssom: 0.6.0
@@ -4989,6 +5064,24 @@ snapshots:
dom-accessibility-api@0.6.3: {}
+ dom-serializer@2.0.0:
+ dependencies:
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+ entities: 4.5.0
+
+ domelementtype@2.3.0: {}
+
+ domhandler@5.0.3:
+ dependencies:
+ domelementtype: 2.3.0
+
+ domutils@3.1.0:
+ dependencies:
+ dom-serializer: 2.0.0
+ domelementtype: 2.3.0
+ domhandler: 5.0.3
+
dotenv@16.4.5: {}
duplexer@0.1.2: {}
@@ -5803,6 +5896,8 @@ snapshots:
mdast-util-to-string@2.0.0: {}
+ mdn-data@2.0.28: {}
+
mdn-data@2.0.30: {}
merge-anything@5.1.7:
@@ -5915,7 +6010,6 @@ snapshots:
nth-check@2.1.1:
dependencies:
boolbase: 1.0.0
- optional: true
nwsapi@2.2.10: {}
@@ -6340,6 +6434,16 @@ snapshots:
supports-preserve-symlinks-flag@1.0.0: {}
+ svgo@3.3.2:
+ dependencies:
+ '@trysound/sax': 0.2.0
+ commander: 7.2.0
+ css-select: 5.1.0
+ css-tree: 2.3.1
+ css-what: 6.1.0
+ csso: 5.0.5
+ picocolors: 1.0.1
+
symbol-tree@3.2.4: {}
synckit@0.6.2:
@@ -6548,6 +6652,12 @@ snapshots:
- supports-color
- terser
+ vite-plugin-solid-svg@0.8.1(solid-js@1.8.17)(vite@5.3.1(@types/node@20.14.3)(sass@1.77.6)):
+ dependencies:
+ solid-js: 1.8.17
+ svgo: 3.3.2
+ vite: 5.3.1(@types/node@20.14.3)(sass@1.77.6)
+
vite-plugin-solid@2.10.2(@testing-library/jest-dom@6.4.6(vitest@1.6.0(@types/node@20.14.3)(@vitest/ui@1.6.0(vitest@1.6.0))(jsdom@24.1.0)(sass@1.77.6)))(solid-js@1.8.17)(vite@5.3.1(@types/node@20.14.3)(sass@1.77.6)):
dependencies:
'@babel/core': 7.24.4