Add support for resource packs + shaders + datapacks
This commit is contained in:
parent
3bcf55907c
commit
6a2352c5dd
9 changed files with 175 additions and 27 deletions
|
|
@ -303,15 +303,10 @@ export type VersionType =
|
||||||
*/
|
*/
|
||||||
"old_beta"
|
"old_beta"
|
||||||
|
|
||||||
const ARGS_MAP = { 'debug':'{"getArch":[],"openDevTools":[],"getType":[],"getPackageVersion":[],"getGitCommitHash":[],"getFamily":[],"getPlatform":[],"getLocale":[],"getOsVersion":[],"isInDev":[],"getBuildTimestamp":[]}', 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}', 'events':'{"ingress":["event"],"message":["event"],"process":["event"]}', 'oneclient':'{"getClustersGroupedByMajor":[],"checkForUpdate":[],"extractBundleOverrides":["bundle_path","cluster_id"],"installUpdate":[],"getBundlesFor":["cluster_id"],"getVersions":[]}', 'core':'{"getRunningProcesses":[],"installModpack":["modpack","cluster_id"],"removeCluster":["id"],"launchCluster":["id","uuid","search_for_java"],"setDefaultUser":["uuid"],"killProcess":["pid"],"getWorlds":["id"],"createSettingsProfile":["name"],"removeCape":["access_token"],"getScreenshots":["id"],"getLoadersForVersion":["mc_version"],"getLogs":["id"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"refreshAccount":["uuid"],"getGameVersions":[],"getRunningProcessesByClusterId":["cluster_id"],"updateClusterProfile":["name","profile"],"getUser":["uuid"],"isClusterRunning":["cluster_id"],"readSettings":[],"downloadExternalPackage":["package","cluster_id","force","skip_compatibility"],"getClusterById":["id"],"getGlobalProfile":[],"fetchMinecraftProfile":["uuid"],"convertUsernameUUID":["username_uuid"],"openMsaLogin":[],"createCluster":["options"],"getLogByName":["id","name"],"getProfileOrDefault":["name"],"getPackage":["provider","slug"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"updateClusterById":["id","request"],"getUsersFromAuthor":["provider","author"],"getClusters":[],"getPackageBody":["provider","body"],"removePackage":["cluster_id","package_hash"],"changeCape":["access_token","cape_uuid"],"open":["input"],"refreshAccounts":[],"writeSettings":["setting"],"searchPackages":["provider","query"],"getMultiplePackages":["provider","slugs"],"getDefaultUser":["fallback"],"getUsers":[],"getLinkedPackages":["cluster_id"],"changeSkin":["access_token","skin_url","skin_variant"],"setClusterStage":["id","stage"],"fetchLoggedInProfile":["access_token"],"setDiscordRPCMessage":["message"],"removeUser":["uuid"],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"]}' }
|
const ARGS_MAP = { 'oneclient':'{"getClustersGroupedByMajor":[],"checkForUpdate":[],"extractBundleOverrides":["bundle_path","cluster_id"],"installUpdate":[],"getBundlesFor":["cluster_id"],"getVersions":[]}', 'core':'{"getRunningProcesses":[],"installModpack":["modpack","cluster_id"],"removeCluster":["id"],"launchCluster":["id","uuid","search_for_java"],"setDefaultUser":["uuid"],"killProcess":["pid"],"getWorlds":["id"],"createSettingsProfile":["name"],"removeCape":["access_token"],"getScreenshots":["id"],"getLoadersForVersion":["mc_version"],"getLogs":["id"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"refreshAccount":["uuid"],"getGameVersions":[],"getRunningProcessesByClusterId":["cluster_id"],"updateClusterProfile":["name","profile"],"getUser":["uuid"],"isClusterRunning":["cluster_id"],"readSettings":[],"downloadExternalPackage":["package","cluster_id","force","skip_compatibility"],"getClusterById":["id"],"getGlobalProfile":[],"fetchMinecraftProfile":["uuid"],"convertUsernameUUID":["username_uuid"],"openMsaLogin":[],"createCluster":["options"],"getLogByName":["id","name"],"getProfileOrDefault":["name"],"getPackage":["provider","slug"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"updateClusterById":["id","request"],"getUsersFromAuthor":["provider","author"],"getClusters":[],"getPackageBody":["provider","body"],"removePackage":["cluster_id","package_hash"],"changeCape":["access_token","cape_uuid"],"open":["input"],"refreshAccounts":[],"writeSettings":["setting"],"searchPackages":["provider","query"],"getMultiplePackages":["provider","slugs"],"getDefaultUser":["fallback"],"getUsers":[],"getLinkedPackages":["cluster_id"],"changeSkin":["access_token","skin_url","skin_variant"],"setClusterStage":["id","stage"],"fetchLoggedInProfile":["access_token"],"setDiscordRPCMessage":["message"],"removeUser":["uuid"],"uploadSkinBytes":["access_token","skin_data","image_format","skin_variant"]}', 'events':'{"ingress":["event"],"message":["event"],"process":["event"]}', 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}', 'debug':'{"getArch":[],"openDevTools":[],"getType":[],"getPackageVersion":[],"getGitCommitHash":[],"getFamily":[],"getPlatform":[],"getLocale":[],"getOsVersion":[],"isInDev":[],"getBuildTimestamp":[]}' }
|
||||||
export type Router = { 'oneclient': { getClustersGroupedByMajor: () => Promise<Partial<{ [key in number]: ClusterModel[] }>>,
|
export type Router = { 'events': { ingress: (event: IngressPayload) => Promise<void>,
|
||||||
getBundlesFor: (clusterId: number) => Promise<ModpackArchive[]>,
|
message: (event: MessagePayload) => Promise<void>,
|
||||||
getVersions: () => Promise<OnlineClusterManifest>,
|
process: (event: ProcessPayload) => Promise<void> },
|
||||||
extractBundleOverrides: (bundlePath: string, clusterId: number) => Promise<null>,
|
|
||||||
checkForUpdate: () => Promise<Update | null>,
|
|
||||||
installUpdate: () => Promise<null> },
|
|
||||||
'folders': { fromCluster: (folderName: string) => Promise<string>,
|
|
||||||
openCluster: (folderName: string) => Promise<null> },
|
|
||||||
'core': { getClusters: () => Promise<ClusterModel[]>,
|
'core': { getClusters: () => Promise<ClusterModel[]>,
|
||||||
getClusterById: (id: number) => Promise<ClusterModel | null>,
|
getClusterById: (id: number) => Promise<ClusterModel | null>,
|
||||||
removeCluster: (id: number) => Promise<null>,
|
removeCluster: (id: number) => Promise<null>,
|
||||||
|
|
@ -363,9 +358,14 @@ removeCape: (accessToken: string) => Promise<MojangFullPlayerProfile>,
|
||||||
convertUsernameUUID: (usernameUuid: string) => Promise<MowojangProfile>,
|
convertUsernameUUID: (usernameUuid: string) => Promise<MowojangProfile>,
|
||||||
setDiscordRPCMessage: (message: string) => Promise<null>,
|
setDiscordRPCMessage: (message: string) => Promise<null>,
|
||||||
open: (input: string) => Promise<null> },
|
open: (input: string) => Promise<null> },
|
||||||
'events': { ingress: (event: IngressPayload) => Promise<void>,
|
'oneclient': { getClustersGroupedByMajor: () => Promise<Partial<{ [key in number]: ClusterModel[] }>>,
|
||||||
message: (event: MessagePayload) => Promise<void>,
|
getBundlesFor: (clusterId: number) => Promise<ModpackArchive[]>,
|
||||||
process: (event: ProcessPayload) => Promise<void> },
|
getVersions: () => Promise<OnlineClusterManifest>,
|
||||||
|
extractBundleOverrides: (bundlePath: string, clusterId: number) => Promise<null>,
|
||||||
|
checkForUpdate: () => Promise<Update | null>,
|
||||||
|
installUpdate: () => Promise<null> },
|
||||||
|
'folders': { fromCluster: (folderName: string) => Promise<string>,
|
||||||
|
openCluster: (folderName: string) => Promise<null> },
|
||||||
'debug': { openDevTools: () => Promise<void>,
|
'debug': { openDevTools: () => Promise<void>,
|
||||||
isInDev: () => Promise<boolean>,
|
isInDev: () => Promise<boolean>,
|
||||||
getArch: () => Promise<string>,
|
getArch: () => Promise<string>,
|
||||||
|
|
|
||||||
|
|
@ -93,14 +93,11 @@ export interface ModCardContextApi {
|
||||||
installedPackages?: Array<PackageModel>;
|
installedPackages?: Array<PackageModel>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const DEFAULT_MOD_CARD_CONTEXT: ModCardContextApi = {};
|
||||||
|
|
||||||
export const ModCardContext = createContext<ModCardContextApi | null>(null);
|
export const ModCardContext = createContext<ModCardContextApi | null>(null);
|
||||||
export function useModCardContext() {
|
export function useModCardContext() {
|
||||||
const ctx = useContext(ModCardContext);
|
return useContext(ModCardContext) ?? DEFAULT_MOD_CARD_CONTEXT;
|
||||||
|
|
||||||
if (!ctx)
|
|
||||||
throw new Error('useModCardContext must be used within a ModCardContext.Provider');
|
|
||||||
|
|
||||||
return ctx;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ModCard({ file, cluster }: ModCardProps) {
|
export function ModCard({ file, cluster }: ModCardProps) {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,8 @@
|
||||||
import type { ClusterModel, ModpackArchive } from '@/bindings.gen';
|
import type { ClusterModel, ModpackArchive } from '@/bindings.gen';
|
||||||
import { Bundle, useModCardContext } from '@/components';
|
import { Bundle, ModCardContext } from '@/components';
|
||||||
import { useSettings } from '@/hooks/useSettings';
|
import { useSettings } from '@/hooks/useSettings';
|
||||||
import { Button, Tab, TabContent, TabList, TabPanel, Tabs } from '@onelauncher/common/components';
|
import { Button, Tab, TabContent, TabList, TabPanel, Tabs } from '@onelauncher/common/components';
|
||||||
|
import { useContext } from 'react';
|
||||||
|
|
||||||
function getBundleName(name: string): string {
|
function getBundleName(name: string): string {
|
||||||
return (name.match(/\[(.*?)\]/)?.[1]) ?? 'Loading...';
|
return (name.match(/\[(.*?)\]/)?.[1]) ?? 'Loading...';
|
||||||
|
|
@ -15,15 +16,18 @@ interface ModListProps {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function ModList({ bundles, cluster, selectedTab, onTabChange }: ModListProps) {
|
export function ModList({ bundles, cluster, selectedTab, onTabChange }: ModListProps) {
|
||||||
const { useVerticalGridLayout } = useModCardContext();
|
const ctx = useContext(ModCardContext);
|
||||||
|
const useVerticalGridLayout = ctx?.useVerticalGridLayout ?? false;
|
||||||
const { createSetting } = useSettings();
|
const { createSetting } = useSettings();
|
||||||
const [useGridLayout, setUseGrid] = createSetting('mod_list_use_grid');
|
const [useGridLayout, setUseGrid] = createSetting('mod_list_use_grid');
|
||||||
|
|
||||||
|
const nonEmptyBundles = bundles.filter(b => b.manifest.files.length > 0);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Tabs defaultValue={selectedTab ?? getBundleName(bundles[0].manifest.name)} onTabChange={onTabChange}>
|
<Tabs defaultValue={selectedTab ?? getBundleName(nonEmptyBundles[0]?.manifest.name ?? bundles[0].manifest.name)} onTabChange={onTabChange}>
|
||||||
<TabList className="justify-between px-4 py-3" height={false}>
|
<TabList className="justify-between px-4 py-3" height={false}>
|
||||||
<div className="flex flex-row gap-6 px-2">
|
<div className="flex flex-row gap-6 px-2">
|
||||||
{bundles.map(bundle => <Tab key={bundle.path} value={getBundleName(bundle.manifest.name)}>{getBundleName(bundle.manifest.name)}</Tab>)}
|
{nonEmptyBundles.map(bundle => <Tab key={bundle.path} value={getBundleName(bundle.manifest.name)}>{getBundleName(bundle.manifest.name)}</Tab>)}
|
||||||
</div>
|
</div>
|
||||||
{!useVerticalGridLayout && (
|
{!useVerticalGridLayout && (
|
||||||
<Button onPress={() => setUseGrid(!useGridLayout)}>
|
<Button onPress={() => setUseGrid(!useGridLayout)}>
|
||||||
|
|
@ -33,7 +37,7 @@ export function ModList({ bundles, cluster, selectedTab, onTabChange }: ModListP
|
||||||
</TabList>
|
</TabList>
|
||||||
|
|
||||||
<TabContent className={useVerticalGridLayout ? 'pt-0' : ''}>
|
<TabContent className={useVerticalGridLayout ? 'pt-0' : ''}>
|
||||||
{bundles.map(bundleData => (
|
{nonEmptyBundles.map(bundleData => (
|
||||||
<TabPanel className={useVerticalGridLayout ? 'max-w-192' : ''} key={getBundleName(bundleData.manifest.name)} value={getBundleName(bundleData.manifest.name)}>
|
<TabPanel className={useVerticalGridLayout ? 'max-w-192' : ''} key={getBundleName(bundleData.manifest.name)} value={getBundleName(bundleData.manifest.name)}>
|
||||||
<Bundle cluster={cluster} files={bundleData.manifest.files} />
|
<Bundle cluster={cluster} files={bundleData.manifest.files} />
|
||||||
</TabPanel>
|
</TabPanel>
|
||||||
|
|
|
||||||
|
|
@ -40,6 +40,9 @@ const ResolvedPathNames: Record<URLPath, string> = {
|
||||||
'/app/cluster/browser/package': 'Browsing {packageName}',
|
'/app/cluster/browser/package': 'Browsing {packageName}',
|
||||||
'/app/cluster/logs': 'Viewing {clusterName}\'s logs',
|
'/app/cluster/logs': 'Viewing {clusterName}\'s logs',
|
||||||
'/app/cluster/mods': 'Viewing {clusterName}\'s mods',
|
'/app/cluster/mods': 'Viewing {clusterName}\'s mods',
|
||||||
|
'/app/cluster/resource-packs': 'Viewing {clusterName}\'s resource packs',
|
||||||
|
'/app/cluster/shaders': 'Viewing {clusterName}\'s shaders',
|
||||||
|
'/app/cluster/datapacks': 'Viewing {clusterName}\'s data packs',
|
||||||
'/app/cluster/process': 'Viewing {clusterName}',
|
'/app/cluster/process': 'Viewing {clusterName}',
|
||||||
'/app/cluster/settings': 'Viewing {clusterName}\'s settings',
|
'/app/cluster/settings': 'Viewing {clusterName}\'s settings',
|
||||||
'/app/settings': 'Viewing Settings',
|
'/app/settings': 'Viewing Settings',
|
||||||
|
|
@ -71,7 +74,9 @@ function useDiscordRPC() {
|
||||||
const { data: cluster } = useCommand(['getClusterById', clusterId], () => bindings.core.getClusterById(clusterId));
|
const { data: cluster } = useCommand(['getClusterById', clusterId], () => bindings.core.getClusterById(clusterId));
|
||||||
const { data: managedPackage } = useCommand(['getPackage', provider, packageId], () => bindings.core.getPackage(provider!, packageId!), { enabled: provider != null && packageId != null });
|
const { data: managedPackage } = useCommand(['getPackage', provider, packageId], () => bindings.core.getPackage(provider!, packageId!), { enabled: provider != null && packageId != null });
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
bindings.core.setDiscordRPCMessage(ReplaceVariables(ResolvedPathNames[location.pathname as URLPath], { clusterName: cluster?.name ?? 'UNKNOWN', packageName: managedPackage?.name ?? 'UNKNOWN' }));
|
const template = ResolvedPathNames[location.pathname as URLPath];
|
||||||
|
if (template)
|
||||||
|
bindings.core.setDiscordRPCMessage(ReplaceVariables(template, { clusterName: cluster?.name ?? 'UNKNOWN', packageName: managedPackage?.name ?? 'UNKNOWN' }));
|
||||||
}, [location.pathname, location.search.clusterId, cluster?.name, managedPackage?.name]);
|
}, [location.pathname, location.search.clusterId, cluster?.name, managedPackage?.name]);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
42
apps/oneclient/frontend/src/routes/app/cluster/datapacks.tsx
Normal file
42
apps/oneclient/frontend/src/routes/app/cluster/datapacks.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import type { ModCardContextApi } from '@/components';
|
||||||
|
import { ModCardContext, ModList } from '@/components';
|
||||||
|
import { getFilePackageType } from '@/routes/app/cluster/mods';
|
||||||
|
import { bindings } from '@/main';
|
||||||
|
import { useCommandSuspense } from '@onelauncher/common';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/app/cluster/datapacks')({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
const { cluster } = Route.useRouteContext();
|
||||||
|
const { data: bundles } = useCommandSuspense(['getBundlesFor', cluster.id], () => bindings.oneclient.getBundlesFor(cluster.id));
|
||||||
|
const { data: installedPackages } = useCommandSuspense(['getLinkedPackages', cluster.id], () => bindings.core.getLinkedPackages(cluster.id));
|
||||||
|
|
||||||
|
const filteredBundles = useMemo(() =>
|
||||||
|
bundles.map(b => ({
|
||||||
|
...b,
|
||||||
|
manifest: { ...b.manifest, files: b.manifest.files.filter(f => getFilePackageType(f) === 'datapack') },
|
||||||
|
})), [bundles]);
|
||||||
|
|
||||||
|
const context = useMemo<ModCardContextApi>(() => ({
|
||||||
|
enableClickToDownload: true,
|
||||||
|
installedPackages,
|
||||||
|
}), [installedPackages]);
|
||||||
|
|
||||||
|
if (filteredBundles.every(b => b.manifest.files.length === 0))
|
||||||
|
return <p className="p-4 text-fg-secondary">No data packs found in {cluster.name}</p>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OverlayScrollbarsComponent className="bg-none">
|
||||||
|
<div className="min-h-148">
|
||||||
|
<ModCardContext.Provider value={context}>
|
||||||
|
<ModList bundles={filteredBundles} cluster={cluster} />
|
||||||
|
</ModCardContext.Provider>
|
||||||
|
</div>
|
||||||
|
</OverlayScrollbarsComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { ModpackFile } from '@/bindings.gen';
|
||||||
import type { ModCardContextApi } from '@/components';
|
import type { ModCardContextApi } from '@/components';
|
||||||
import { ModCardContext, ModList } from '@/components';
|
import { ModCardContext, ModList } from '@/components';
|
||||||
import { bindings } from '@/main';
|
import { bindings } from '@/main';
|
||||||
|
|
@ -10,24 +11,36 @@ export const Route = createFileRoute('/app/cluster/mods')({
|
||||||
component: RouteComponent,
|
component: RouteComponent,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
export function getFilePackageType(file: ModpackFile) {
|
||||||
|
if ('Managed' in file.kind)
|
||||||
|
return file.kind.Managed[0].package_type;
|
||||||
|
return file.kind.External.package_type;
|
||||||
|
}
|
||||||
|
|
||||||
function RouteComponent() {
|
function RouteComponent() {
|
||||||
const { cluster } = Route.useRouteContext();
|
const { cluster } = Route.useRouteContext();
|
||||||
const { data: bundles } = useCommandSuspense(['getBundlesFor', cluster.id], () => bindings.oneclient.getBundlesFor(cluster.id));
|
const { data: bundles } = useCommandSuspense(['getBundlesFor', cluster.id], () => bindings.oneclient.getBundlesFor(cluster.id));
|
||||||
const { data: installedPackages } = useCommandSuspense(['getLinkedPackages', cluster.id], () => bindings.core.getLinkedPackages(cluster.id));
|
const { data: installedPackages } = useCommandSuspense(['getLinkedPackages', cluster.id], () => bindings.core.getLinkedPackages(cluster.id));
|
||||||
|
|
||||||
|
const filteredBundles = useMemo(() =>
|
||||||
|
bundles.map(b => ({
|
||||||
|
...b,
|
||||||
|
manifest: { ...b.manifest, files: b.manifest.files.filter(f => getFilePackageType(f) === 'mod') },
|
||||||
|
})), [bundles]);
|
||||||
|
|
||||||
const context = useMemo<ModCardContextApi>(() => ({
|
const context = useMemo<ModCardContextApi>(() => ({
|
||||||
enableClickToDownload: true,
|
enableClickToDownload: true,
|
||||||
installedPackages,
|
installedPackages,
|
||||||
}), [installedPackages]);
|
}), [installedPackages]);
|
||||||
|
|
||||||
if (bundles.length === 0)
|
if (filteredBundles.every(b => b.manifest.files.length === 0))
|
||||||
return <p>No bundles found {cluster.name}</p>;
|
return <p className="p-4 text-fg-secondary">No mods found in {cluster.name}</p>;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<OverlayScrollbarsComponent className="bg-none">
|
<OverlayScrollbarsComponent className="bg-none">
|
||||||
<div className="min-h-148">
|
<div className="min-h-148">
|
||||||
<ModCardContext.Provider value={context}>
|
<ModCardContext.Provider value={context}>
|
||||||
<ModList bundles={bundles} cluster={cluster} />
|
<ModList bundles={filteredBundles} cluster={cluster} />
|
||||||
</ModCardContext.Provider>
|
</ModCardContext.Provider>
|
||||||
</div>
|
</div>
|
||||||
</OverlayScrollbarsComponent>
|
</OverlayScrollbarsComponent>
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,42 @@
|
||||||
|
import type { ModCardContextApi } from '@/components';
|
||||||
|
import { ModCardContext, ModList } from '@/components';
|
||||||
|
import { getFilePackageType } from '@/routes/app/cluster/mods';
|
||||||
|
import { bindings } from '@/main';
|
||||||
|
import { useCommandSuspense } from '@onelauncher/common';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/app/cluster/resource-packs')({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
const { cluster } = Route.useRouteContext();
|
||||||
|
const { data: bundles } = useCommandSuspense(['getBundlesFor', cluster.id], () => bindings.oneclient.getBundlesFor(cluster.id));
|
||||||
|
const { data: installedPackages } = useCommandSuspense(['getLinkedPackages', cluster.id], () => bindings.core.getLinkedPackages(cluster.id));
|
||||||
|
|
||||||
|
const filteredBundles = useMemo(() =>
|
||||||
|
bundles.map(b => ({
|
||||||
|
...b,
|
||||||
|
manifest: { ...b.manifest, files: b.manifest.files.filter(f => getFilePackageType(f) === 'resourcepack') },
|
||||||
|
})), [bundles]);
|
||||||
|
|
||||||
|
const context = useMemo<ModCardContextApi>(() => ({
|
||||||
|
enableClickToDownload: true,
|
||||||
|
installedPackages,
|
||||||
|
}), [installedPackages]);
|
||||||
|
|
||||||
|
if (filteredBundles.every(b => b.manifest.files.length === 0))
|
||||||
|
return <p className="p-4 text-fg-secondary">No resource packs found in {cluster.name}</p>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OverlayScrollbarsComponent className="bg-none">
|
||||||
|
<div className="min-h-148">
|
||||||
|
<ModCardContext.Provider value={context}>
|
||||||
|
<ModList bundles={filteredBundles} cluster={cluster} />
|
||||||
|
</ModCardContext.Provider>
|
||||||
|
</div>
|
||||||
|
</OverlayScrollbarsComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
@ -79,6 +79,9 @@ function RouteComponent() {
|
||||||
>
|
>
|
||||||
<TabList floating={floating} ref={tabListRef}>
|
<TabList floating={floating} ref={tabListRef}>
|
||||||
<Tab from={Route.id} search={search} to="/app/cluster/mods">Mods</Tab>
|
<Tab from={Route.id} search={search} to="/app/cluster/mods">Mods</Tab>
|
||||||
|
<Tab from={Route.id} search={search} to="/app/cluster/resource-packs">Resource Packs</Tab>
|
||||||
|
<Tab from={Route.id} search={search} to="/app/cluster/shaders">Shaders</Tab>
|
||||||
|
<Tab from={Route.id} search={search} to="/app/cluster/datapacks">Data Packs</Tab>
|
||||||
<Tab from={Route.id} search={search} to="/app/cluster/logs">Logs</Tab>
|
<Tab from={Route.id} search={search} to="/app/cluster/logs">Logs</Tab>
|
||||||
<Tab from={Route.id} search={{ ...search, packageType: 'mod' }} to="/app/cluster/browser">Browser</Tab>
|
<Tab from={Route.id} search={{ ...search, packageType: 'mod' }} to="/app/cluster/browser">Browser</Tab>
|
||||||
<Tab from={Route.id} search={search} to="/app/cluster/settings">Settings</Tab>
|
<Tab from={Route.id} search={search} to="/app/cluster/settings">Settings</Tab>
|
||||||
|
|
|
||||||
42
apps/oneclient/frontend/src/routes/app/cluster/shaders.tsx
Normal file
42
apps/oneclient/frontend/src/routes/app/cluster/shaders.tsx
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
import type { ModCardContextApi } from '@/components';
|
||||||
|
import { ModCardContext, ModList } from '@/components';
|
||||||
|
import { getFilePackageType } from '@/routes/app/cluster/mods';
|
||||||
|
import { bindings } from '@/main';
|
||||||
|
import { useCommandSuspense } from '@onelauncher/common';
|
||||||
|
import { createFileRoute } from '@tanstack/react-router';
|
||||||
|
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
||||||
|
import { useMemo } from 'react';
|
||||||
|
|
||||||
|
export const Route = createFileRoute('/app/cluster/shaders')({
|
||||||
|
component: RouteComponent,
|
||||||
|
});
|
||||||
|
|
||||||
|
function RouteComponent() {
|
||||||
|
const { cluster } = Route.useRouteContext();
|
||||||
|
const { data: bundles } = useCommandSuspense(['getBundlesFor', cluster.id], () => bindings.oneclient.getBundlesFor(cluster.id));
|
||||||
|
const { data: installedPackages } = useCommandSuspense(['getLinkedPackages', cluster.id], () => bindings.core.getLinkedPackages(cluster.id));
|
||||||
|
|
||||||
|
const filteredBundles = useMemo(() =>
|
||||||
|
bundles.map(b => ({
|
||||||
|
...b,
|
||||||
|
manifest: { ...b.manifest, files: b.manifest.files.filter(f => getFilePackageType(f) === 'shader') },
|
||||||
|
})), [bundles]);
|
||||||
|
|
||||||
|
const context = useMemo<ModCardContextApi>(() => ({
|
||||||
|
enableClickToDownload: true,
|
||||||
|
installedPackages,
|
||||||
|
}), [installedPackages]);
|
||||||
|
|
||||||
|
if (filteredBundles.every(b => b.manifest.files.length === 0))
|
||||||
|
return <p className="p-4 text-fg-secondary">No shaders found in {cluster.name}</p>;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<OverlayScrollbarsComponent className="bg-none">
|
||||||
|
<div className="min-h-148">
|
||||||
|
<ModCardContext.Provider value={context}>
|
||||||
|
<ModList bundles={filteredBundles} cluster={cluster} />
|
||||||
|
</ModCardContext.Provider>
|
||||||
|
</div>
|
||||||
|
</OverlayScrollbarsComponent>
|
||||||
|
);
|
||||||
|
}
|
||||||
Loading…
Add table
Reference in a new issue