202 lines
5.8 KiB
TypeScript
202 lines
5.8 KiB
TypeScript
import type { ClusterModel } from '@/bindings.gen';
|
|
import DefaultBanner from '@/assets/images/default_banner.png';
|
|
import DefaultInstancePhoto from '@/assets/images/default_instance_cover.jpg';
|
|
import { NewClusterCreate } from '@/components/launcher/cluster/ClusterCreation';
|
|
import useRecentCluster from '@/hooks/useCluster';
|
|
import { bindings } from '@/main';
|
|
import { upperFirst } from '@/utils';
|
|
import { useCommand } from '@onelauncher/common';
|
|
import { Button, Show, TextField } from '@onelauncher/common/components';
|
|
import { createFileRoute, Link } from '@tanstack/react-router';
|
|
import { PlayIcon, Server01Icon } from '@untitled-theme/icons-react';
|
|
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
|
|
|
|
export const Route = createFileRoute('/app/')({
|
|
component: RouteComponent,
|
|
});
|
|
|
|
/*
|
|
Please note this route has a very big issue related to scrolling
|
|
and i am very angry rn so i will not be fixing it rn
|
|
|
|
hey future sassan here i guess the issue is solved idk
|
|
|
|
hey future sassan here i guess the issue is solved idk
|
|
*/
|
|
function RouteComponent() {
|
|
const result = useCommand('getClusters', bindings.core.getClusters);
|
|
|
|
return (
|
|
<div className="h-full flex flex-col gap-y-4 text-fg-primary">
|
|
<Banner />
|
|
|
|
<div className="flex flex-row items-center justify-between">
|
|
<NewClusterCreate />
|
|
</div>
|
|
|
|
<div className="flex flex-col">
|
|
<ClusterGroup clusters={result.data} isFetching={result.isFetching} />
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function Banner() {
|
|
/**
|
|
* If there are any clusters, display the most recent cluster name + some statistics as the "description".
|
|
* The background would prioritise
|
|
* any screenshots taken from the cluster, if there are none, it would display the cluster cover if it has been set.
|
|
* The button would launch the cluster.
|
|
*
|
|
* If there are no clusters, display a generic background with the button action creating a new cluster.
|
|
*/
|
|
const cluster = useRecentCluster();
|
|
|
|
// const launch = useLaunchCluster(() => cluster()?.uuid);
|
|
// const navigate = useNavigate();
|
|
|
|
return (
|
|
<div className="relative h-52 min-h-52 w-full overflow-hidden rounded-xl border border-component-border">
|
|
<div className="absolute h-52 min-h-52 w-full">
|
|
<img
|
|
alt="Default Banner"
|
|
className="top-0 left-0 h-full rounded-xl w-full object-cover"
|
|
src={cluster?.icon_url || DefaultBanner}
|
|
/>
|
|
</div>
|
|
|
|
<div className="relative z-10 h-full flex flex-col items-start justify-between px-8 py-6">
|
|
<div className="theme-OneLauncher-Dark flex flex-col gap-y-2 text-fg-primary">
|
|
<h1 className="text-2xl font-medium text-shadow-black text-shadow-2xs">Create a cluster</h1>
|
|
<Show when={cluster !== undefined}>
|
|
<p>
|
|
You've played
|
|
{' '}
|
|
<strong>
|
|
{cluster?.name}
|
|
{' '}
|
|
{upperFirst(cluster?.mc_loader || 'Unknown')}
|
|
</strong>
|
|
{' '}
|
|
for
|
|
{' '}
|
|
<strong>{cluster?.overall_played || 0}</strong>
|
|
.
|
|
</p>
|
|
</Show>
|
|
</div>
|
|
<div className="w-full flex flex-row items-end justify-between">
|
|
<div className="flex flex-row items-center gap-x-4">
|
|
{/* <Show when={cluster() !== undefined}>
|
|
<Button
|
|
buttonStyle="primary"
|
|
children={`Launch ${cluster()!.meta.mc_version}`}
|
|
iconLeft={<PlayIcon />}
|
|
onClick={launch}
|
|
/>
|
|
<Button
|
|
buttonStyle="iconSecondary"
|
|
children={<Settings01Icon />}
|
|
className="theme-OneLauncher-Dark bg-op-10!"
|
|
onClick={() => ClusterRoot.open(navigate, cluster()!.uuid)}
|
|
/>
|
|
</Show> */}
|
|
</div>
|
|
<div className="flex flex-row gap-x-2">
|
|
{/* TODO: These tags */}
|
|
{/* <Tag iconLeft={<OneConfigLogo />} />
|
|
<Tag iconLeft={<CheckIcon />}>Verified</Tag> */}
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
interface ClusterGroupProps {
|
|
clusters: Array<ClusterModel> | undefined;
|
|
isFetching?: boolean;
|
|
}
|
|
|
|
function ClusterGroup({
|
|
isFetching,
|
|
clusters,
|
|
}: ClusterGroupProps) {
|
|
if (isFetching)
|
|
return (
|
|
<div className="flex items-center justify-center h-full">
|
|
<div className="w-8 h-8 border-4 border-brand rounded-full border-t-transparent animate-spin" />
|
|
</div>
|
|
);
|
|
|
|
return (
|
|
<div className="h-full w-full">
|
|
<OverlayScrollbarsComponent
|
|
className="h-full w-full"
|
|
>
|
|
<div className="grid grid-cols-4 gap-4 max-h-96 2xl:grid-cols-6 pb-4">
|
|
{clusters?.map(data => (
|
|
<ClusterCard key={data.id} {...data} />
|
|
))}
|
|
</div>
|
|
</OverlayScrollbarsComponent>
|
|
</div>
|
|
);
|
|
}
|
|
|
|
function ClusterCard({
|
|
id,
|
|
name,
|
|
mc_loader,
|
|
mc_version,
|
|
}: ClusterModel) {
|
|
const launch = useCommand('launchCluster', () => bindings.core.launchCluster(id, null), {
|
|
enabled: false,
|
|
subscribed: false,
|
|
});
|
|
|
|
const handleLaunch = () => {
|
|
launch.refetch();
|
|
|
|
if (launch.error)
|
|
console.error(launch.error.message);
|
|
};
|
|
|
|
return (
|
|
<>
|
|
<Link
|
|
search={{
|
|
id,
|
|
}} to="/app/cluster"
|
|
>
|
|
<div
|
|
className="group relative h-[152px] flex flex-col rounded-xl border border-component-border/5 bg-component-bg active:bg-component-bg-pressed hover:bg-component-bg-hover"
|
|
>
|
|
<div className="relative flex-1 overflow-hidden rounded-t-xl">
|
|
<div
|
|
className="absolute h-full w-full transition-transform group-hover:!scale-110"
|
|
>
|
|
<img
|
|
className="h-full w-full object-cover"
|
|
src={DefaultInstancePhoto}
|
|
/>
|
|
</div>
|
|
</div>
|
|
<div className="z-10 flex flex-row items-center justify-between gap-x-3 p-3">
|
|
<div className="h-full flex flex-col gap-1.5 overflow-hidden">
|
|
<p className="h-4 text-ellipsis whitespace-nowrap font-medium">{name}</p>
|
|
<p className="h-4 text-xs">
|
|
{mc_loader}
|
|
{' '}
|
|
{mc_version}
|
|
</p>
|
|
</div>
|
|
|
|
{/* <LaunchButton cluster={props} iconOnly /> */}
|
|
<Button onClick={handleLaunch} size="icon"><PlayIcon /></Button>
|
|
</div>
|
|
</div>
|
|
</Link>
|
|
</>
|
|
);
|
|
}
|