chore: fix merge conflicts

This commit is contained in:
LynithDev 2025-08-18 14:29:18 +02:00
commit f8151421e8
14 changed files with 471 additions and 5 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 MiB

View file

@ -0,0 +1,9 @@
<svg width="565" height="116" viewBox="0 0 565 116" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M82.9609 92V26.9865H93.0904L97.4185 39.9707V92H82.9609ZM127.807 92L89.499 42.9175L93.0904 26.9865L131.399 76.0689L127.807 92ZM127.807 92L123.939 79.0157V26.9865H138.397V92H127.807ZM156.472 92V26.9865H170.93V92H156.472ZM167.523 92V79.4761H203.16V92H167.523ZM167.523 64.8343V52.7709H199.937V64.8343H167.523ZM167.523 39.4182V26.9865H202.7V39.4182H167.523Z" fill="#0A5BE8"/>
<path d="M248.333 93.013C243.483 93.013 238.97 92.1842 234.796 90.5266C230.683 88.8076 227.061 86.4134 223.93 83.3438C220.86 80.2742 218.466 76.7135 216.747 72.6617C215.028 68.5485 214.168 64.1283 214.168 59.4011C214.168 54.674 215.028 50.2845 216.747 46.2327C218.466 42.1194 220.86 38.5587 223.93 35.5506C226.999 32.5424 230.591 30.2095 234.704 28.5519C238.878 26.833 243.391 25.9735 248.241 25.9735C253.397 25.9735 257.971 26.8023 261.962 28.4598C266.013 30.1174 269.543 32.3889 272.552 35.2743L262.882 45.0355C261.163 43.1938 259.076 41.7511 256.621 40.7074C254.226 39.6638 251.433 39.142 248.241 39.142C245.417 39.142 242.807 39.6331 240.413 40.6154C238.08 41.5362 236.054 42.8868 234.335 44.6672C232.678 46.4475 231.358 48.5962 230.376 51.1133C229.455 53.6303 228.994 56.393 228.994 59.4011C228.994 62.4707 229.455 65.264 230.376 67.7811C231.358 70.2981 232.678 72.4468 234.335 74.2272C236.054 76.0075 238.08 77.3888 240.413 78.3711C242.807 79.3534 245.417 79.8445 248.241 79.8445C251.556 79.8445 254.441 79.3227 256.897 78.279C259.352 77.2354 261.47 75.7927 263.251 73.9509L273.012 83.7122C269.881 86.5976 266.29 88.869 262.238 90.5266C258.247 92.1842 253.612 93.013 248.333 93.013ZM286.499 92V26.9865H300.956V92H286.499ZM297.641 92V79.292H329.779V92H297.641ZM343.643 92V26.9865H358.101V92H343.643ZM376.147 92V26.9865H390.604V92H376.147ZM387.197 92V79.4761H422.835V92H387.197ZM387.197 64.8343V52.7709H419.612V64.8343H387.197ZM387.197 39.4182V26.9865H422.375V39.4182H387.197ZM438.327 92V26.9865H448.457L452.785 39.9707V92H438.327ZM483.174 92L444.865 42.9175L448.457 26.9865L486.765 76.0689L483.174 92ZM483.174 92L479.306 79.0157V26.9865H493.764V92H483.174ZM527.77 92V27.9073H542.227V92H527.77ZM507.418 39.6024V26.9865H562.579V39.6024H507.418Z" fill="#0048C5"/>
<path d="M29.1968 26H24.5066C19.1242 26 14.1506 28.8493 11.4594 33.4745L0.956285 51.5255C0.596616 52.1437 0.285016 52.781 0.0214844 53.4323L14.9434 50.7047C20.9687 49.6033 25.6832 44.9253 26.7932 38.9467L29.1968 26Z" fill="#0048C5"/>
<path d="M0 64.5149C0.267976 65.1846 0.586648 65.8397 0.956016 66.4745L11.4591 84.5255C14.1503 89.1507 19.1239 92 24.5063 92H29.2056L26.7929 79.0045C25.6829 73.0259 20.9684 68.3479 14.9431 67.2465L0 64.5149Z" fill="#0048C5"/>
<path d="M41.0508 92H45.5124C50.8948 92 55.8683 89.1507 58.5595 84.5255L69.0627 66.4745C69.4234 65.8545 69.7358 65.2152 69.9998 64.5618L55.3133 67.2465C49.288 68.3479 44.5735 73.0259 43.4635 79.0045L41.0508 92Z" fill="#0048C5"/>
<path d="M69.9782 53.3854C69.7187 52.7504 69.4135 52.1288 69.0625 51.5255L58.5593 33.4745C55.8681 28.8492 50.8946 26 45.5122 26H41.0596L43.4633 38.9467C44.5733 44.9253 49.2878 49.6033 55.3131 50.7047L69.9782 53.3854Z" fill="#0048C5"/>
<path d="M34.9819 27.295C35.0016 27.1215 35.2558 27.1215 35.2755 27.295L36.4373 37.5459C37.6214 47.9936 45.9187 56.2463 56.445 57.4461L68.5861 58.83C68.7606 58.8499 68.7606 59.1013 68.5861 59.1212L56.445 60.5051C45.9187 61.7049 37.6214 69.9576 36.4373 80.4053L35.2755 90.6561C35.2558 90.8297 35.0016 90.8297 34.9819 90.6561L33.822 80.4214C32.637 69.9663 24.3292 61.7104 13.7943 60.5189L1.43566 59.1212C1.26103 59.1014 1.26103 58.8497 1.43566 58.83L13.7943 57.4322C24.3292 56.2407 32.637 47.9848 33.822 37.5298L34.9819 27.295Z" fill="#0A5BE8"/>
</svg>

After

Width:  |  Height:  |  Size: 3.6 KiB

View file

@ -230,14 +230,14 @@ export type VersionType =
*/
"old_beta"
const ARGS_MAP = { 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}', 'events':'{"ingress":["event"],"message":["event"],"process":["event"]}', 'oneclient':'{"getClustersGroupedByMajor":[],"openDevTools":[]}', 'core':'{"removeUser":["uuid"],"openMsaLogin":[],"getLogByName":["id","name"],"setDefaultUser":["uuid"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"getUser":["uuid"],"getClusters":[],"getProfileOrDefault":["name"],"updateClusterProfile":["name","profile"],"getMultiplePackages":["provider","slugs"],"getWorlds":["id"],"getUsersFromAuthor":["provider","author"],"fetchMinecraftProfile":["uuid"],"getLogs":["id"],"getUsers":[],"launchCluster":["id","uuid"],"writeSettings":["setting"],"getLoadersForVersion":["mc_version"],"getGlobalProfile":[],"getGameVersions":[],"searchPackages":["provider","query"],"removeCluster":["id"],"getDefaultUser":["fallback"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"updateClusterById":["id","request"],"getPackage":["provider","slug"],"getScreenshots":["id"],"readSettings":[],"getClusterById":["id"],"createCluster":["options"],"getPackageBody":["provider","body"]}' }
export type Router = { 'events': { ingress: (event: IngressPayload) => Promise<void>,
const ARGS_MAP = { 'core':'{"getLoadersForVersion":["mc_version"],"getScreenshots":["id"],"getPackageVersions":["provider","slug","mc_version","loader","offset","limit"],"getPackageBody":["provider","body"],"createCluster":["options"],"getLogs":["id"],"getDefaultUser":["fallback"],"getUser":["uuid"],"getProfileOrDefault":["name"],"openMsaLogin":[],"getClusters":[],"getClusterById":["id"],"updateClusterProfile":["name","profile"],"getMultiplePackages":["provider","slugs"],"removeUser":["uuid"],"removeCluster":["id"],"getGlobalProfile":[],"getGameVersions":[],"searchPackages":["provider","query"],"fetchMinecraftProfile":["uuid"],"getLogByName":["id","name"],"downloadPackage":["provider","package_id","version_id","cluster_id","skip_compatibility"],"launchCluster":["id","uuid"],"getWorlds":["id"],"setDefaultUser":["uuid"],"getPackage":["provider","slug"],"writeSettings":["setting"],"getUsersFromAuthor":["provider","author"],"getUsers":[],"updateClusterById":["id","request"],"readSettings":[]}', 'events':'{"process":["event"],"ingress":["event"],"message":["event"]}', 'folders':'{"fromCluster":["folder_name"],"openCluster":["folder_name"]}', 'oneclient':'{"openDevTools":[],"getClustersGroupedByMajor":[]}' }
export type Router = { 'folders': { fromCluster: (folderName: string) => Promise<string>,
openCluster: (folderName: string) => Promise<null> },
'events': { ingress: (event: IngressPayload) => Promise<void>,
message: (event: MessagePayload) => Promise<void>,
process: (event: ProcessPayload) => Promise<void> },
'oneclient': { openDevTools: () => Promise<void>,
getClustersGroupedByMajor: () => Promise<Partial<{ [key in number]: ClusterModel[] }>> },
'folders': { fromCluster: (folderName: string) => Promise<string>,
openCluster: (folderName: string) => Promise<null> },
'core': { getClusters: () => Promise<ClusterModel[]>,
getClusterById: (id: number) => Promise<ClusterModel | null>,
removeCluster: (id: number) => Promise<null>,

View file

@ -4,10 +4,12 @@ import { twMerge } from 'tailwind-merge';
import CavesAndCliffs from '@/assets/backgrounds/CavesAndCliffs.jpg';
import HypixelSkyblockHub from '@/assets/backgrounds/HypixelSkyblockHub.png';
import MinecraftBuilding from '@/assets/backgrounds/MinecraftBuilding.png';
const GameBackgrounds = {
HypixelSkyblockHub,
CavesAndCliffs,
MinecraftBuilding,
};
export type GameBackgroundName = keyof typeof GameBackgrounds;

View file

@ -93,7 +93,7 @@ function NavbarLink({
);
}
function NavbarButton({
export function NavbarButton({
children,
color = 'ghost',
size = 'iconLarge',

View file

@ -0,0 +1,73 @@
import type { OnboardingStep } from '@/routes/onboarding/route';
import { useMatchRoute } from '@tanstack/react-router';
interface VerticalStepperProps {
steps: Array<OnboardingStep>;
linearSteps: Array<Omit<OnboardingStep, 'subSteps'>>;
};
export function Stepper({ steps, linearSteps }: VerticalStepperProps) {
const matchRoute = useMatchRoute();
const currentLinearIndex = linearSteps.findIndex(step =>
matchRoute({ to: step.path }));
const progressHeight = currentLinearIndex >= 0 ? `${(currentLinearIndex / (linearSteps.length - 1)) * 100}%` : '0%';
// const nextStep = () => {
// if (currentStep < steps.length - 1)
// setCurrentStep(currentStep + 1);
// };
// const prevStep = () => {
// if (currentStep > 0)
// setCurrentStep(currentStep - 1);
// };
// const goToStep = (stepIndex: number) => {
// setCurrentStep(stepIndex);
// };
return (
<div>
<div className="max-w-md mx-auto">
<div className="relative">
<div className="absolute left-4 top-0 w-0.5 h-full bg-gray-600"></div>
<div
className="absolute left-4 top-0 w-0.5 bg-brand transition-all duration-500 ease-in-out"
style={{
height: `${progressHeight}`,
}}
>
</div>
<ul className="relative space-y-4">
{steps.map((step, index) => (
<li
className="relative flex items-center cursor-pointer group"
key={index}
// onClick={() => goToStep(index)}
>
<div className="ml-8">
<span className={`
transition-all duration-300 font-medium
${index === currentLinearIndex
? 'text-white text-lg'
: index < currentLinearIndex
? ' text-base'
: 'text-gray-400 text-base'
}
`}
>
{step.title}
</span>
</div>
</li>
))}
</ul>
</div>
</div>
</div>
);
}

View file

@ -0,0 +1,9 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/onboarding/account')({
component: RouteComponent,
})
function RouteComponent() {
return <div>Hello "/onboarding/account"!</div>
}

View file

@ -0,0 +1,9 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/onboarding/finished')({
component: RouteComponent,
})
function RouteComponent() {
return <div>Hello "/onboarding/finished"!</div>
}

View file

@ -0,0 +1,15 @@
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/onboarding/')({
component: RouteComponent,
});
function RouteComponent() {
return (
<>
<div className="absolute top-56 left-32">
<h2 className="text-6xl font-bold">OneClient</h2>
</div>
</>
);
}

View file

@ -0,0 +1,13 @@
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/onboarding/language')({
component: RouteComponent,
});
function RouteComponent() {
return (
<div>
Hello "/onboarding/language"!
</div>
);
}

View file

@ -0,0 +1,9 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/onboarding/preferences/')({
component: RouteComponent,
})
function RouteComponent() {
return <div>Hello "/onboarding/preferences/"!</div>
}

View file

@ -0,0 +1,9 @@
import { createFileRoute } from '@tanstack/react-router'
export const Route = createFileRoute('/onboarding/preferences/mods')({
component: RouteComponent,
})
function RouteComponent() {
return <div>Hello "/onboarding/preferences/mods"!</div>
}

View file

@ -0,0 +1,88 @@
import CavesAndCliffs from '@/assets/backgrounds/CavesAndCliffs.jpg';
import { Button } from '@onelauncher/common/components';
import { createFileRoute } from '@tanstack/react-router';
import { DotsVerticalIcon, PlusIcon } from '@untitled-theme/icons-react';
export const Route = createFileRoute('/onboarding/preferences/versions')({
component: RouteComponent,
});
// placeholder
const versions = [
{
version: '1.8.9',
tags: ['PvP', 'Skyblock', 'Bedwars', 'UHC'],
},
{
version: '1.21.4',
tags: ['Nostalgia', 'Survival', 'UHC'],
},
{
version: '1.21.4',
tags: ['PvP', 'Minigames', 'Survival', 'UHC'],
},
];
function RouteComponent() {
return (
<div className="min-h-screen p-8">
<div className="max-w-6xl mx-auto">
<h1 className="text-4xl font-semibold mb-2">Starting Versions</h1>
<p className="text-slate-400 text-lg mb-2">
Something something in corporate style fashion about picking your preferred gamemodes and versions and
optionally loader so that oneclient can pick something for them
</p>
<div className="bg-page-elevated h-full p-4 rounded-xl grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6">
{versions.map(version => (
<VersionCard
key={version.version}
tags={version.tags}
version={version.version}
/>
))}
<div className="border border-component-bg-hover rounded-xl">
<div className="flex items-center justify-center h-46">
<PlusIcon className="text-component-bg-hover size-12" />
</div>
</div>
</div>
</div>
</div>
);
}
interface VersionCardProps {
version: string;
tags: Array<string>;
}
export function VersionCard({ version, tags }: VersionCardProps) {
return (
<div className="overflow-hidden transition-colors cursor-pointer">
<div className="relative">
<img
alt={`Minecraft ${version} landscape`}
className="w-full rounded-xl h-48 object-cover"
src={CavesAndCliffs}
/>
<div className="absolute top-3 left-3 flex flex-wrap gap-1">
{tags.map(tag => (
<div className="bg-[#D0D7F3] rounded-xl text-brand text-sm px-2 py-1" key={tag}>
{tag}
</div>
))}
</div>
<Button className="absolute bottom-3 right-3 p-1 transition-colors" color="ghost" size="icon">
<DotsVerticalIcon className="w-4 h-4 text-white" />
</Button>
<div className="absolute bottom-3 left-3">
<span className="text-white font-bold px-3 py-1">{version}</span>
</div>
</div>
</div>
);
}

View file

@ -0,0 +1,230 @@
import type { PropsWithChildren } from 'react';
import Logo from '@/assets/logos/oneclient2.svg';
import { LoaderSuspense, NavbarButton } from '@/components';
import { GameBackground } from '@/components/GameBackground';
import { Stepper } from '@/components/Stepper';
import useAppShellStore from '@/stores/appShellStore';
import { Button } from '@onelauncher/common/components';
import { createFileRoute, Link, Outlet } from '@tanstack/react-router';
import { Window } from '@tauri-apps/api/window';
import { MinusIcon, SquareIcon, XCloseIcon } from '@untitled-theme/icons-react';
import { MouseParallax } from 'react-just-parallax';
export const Route = createFileRoute('/onboarding')({
component: RouteComponent,
loader: ({ location }) => {
const currentStepIndex = LINEAR_ONBOARDING_STEPS.findIndex(
step => step.path === location.pathname,
);
const isFirstStep = currentStepIndex === 0;
const isLastStep = currentStepIndex === LINEAR_ONBOARDING_STEPS.length - 1;
return {
isFirstStep,
isLastStep,
previousPath:
currentStepIndex > 0
? LINEAR_ONBOARDING_STEPS[currentStepIndex - 1]?.path
: undefined,
nextPath:
currentStepIndex < LINEAR_ONBOARDING_STEPS.length - 1
? LINEAR_ONBOARDING_STEPS[currentStepIndex + 1]?.path
: undefined,
currentStepIndex,
};
},
});
export interface OnboardingStep {
path: string;
title: string;
subSteps?: Array<OnboardingStep>;
};
const ONBOARDING_STEPS: Array<OnboardingStep> = [
{
path: '/onboarding',
title: 'Welcome',
},
{
path: '/onboarding/language',
title: 'Set Language',
},
{
path: '/onboarding/account',
title: 'Account',
},
{
path: '/onboarding/preferences/',
title: 'Preferences',
subSteps: [
{
path: '/onboarding/preferences/versions',
title: 'Versions',
},
{
path: '/onboarding/preferences/mods',
title: 'Mods',
},
],
},
{
path: '/onboarding/finished',
title: 'Finished',
},
];
function getLinearSteps(steps: Array<OnboardingStep>): Array<Omit<OnboardingStep, 'subSteps'>> {
return steps.flatMap(step => (step.subSteps ? step.subSteps : step));
}
const LINEAR_ONBOARDING_STEPS = getLinearSteps(ONBOARDING_STEPS);
function RouteComponent() {
return (
<LoaderSuspense spinner={{ size: 'large' }}>
<AppShell>
<div className="h-full w-full">
<Navbar />
<Outlet />
<OnboardingNavigation />
</div>
</AppShell>
</LoaderSuspense>
);
}
function AppShell({
children,
}: PropsWithChildren) {
const { isFirstStep } = Route.useLoaderData();
return (
<div className="flex flex-col h-full w-full">
<BackgroundGradient />
<div className="h-screen flex overflow-hidden">
<div className={`min-w-64 ${isFirstStep ? 'bg-page' : ''} border-r border-component-border flex flex-col`}>
<div className="p-6">
<div className="flex items-center gap-2">
<img alt="logo" className="w-52 h-12" src={Logo} />
</div>
</div>
<nav className="flex-1 p-4">
<Stepper linearSteps={LINEAR_ONBOARDING_STEPS} steps={ONBOARDING_STEPS} />
</nav>
<div className="p-4 text-xs text-fg-secondary">
<p>version info</p>
</div>
</div>
<div className={`flex-1 flex ${isFirstStep ? '' : 'bg-page'} flex-col relative`}>
{children}
</div>
</div>
</div>
);
}
function BackgroundGradient() {
const background = useAppShellStore(state => state.background);
if (background === 'none')
return undefined;
return (
<div className="relative">
{/* Linear black gradient: left -> right */}
{/* <div
className="absolute top-0 left-0 w-screen h-screen -z-10"
style={{
background: 'linear-gradient(270deg, rgba(0, 0, 0, 0.00) 35%, rgba(0, 0, 0, 0.60) 87.5%)',
}}
>
</div> */}
{/* Radial black gradient */}
<div
className="absolute top-0 left-0 w-screen h-screen -z-10" style={{
background: 'radial-gradient(48.29% 48.29% at 77.29% 50%, rgba(0, 0, 0, 0.00) 0%, rgba(0, 0, 0, 0.64) 100%)',
}}
>
</div>
{/* Linear black gradient: bottom -> 200 px up */}
<div
className="absolute bottom-0 left-0 w-screen h-50 -z-10" style={{
background: 'linear-gradient(180deg, rgba(17, 23, 28, 0.00) 0%, rgba(0, 0, 0, 0.68) 60%)',
}}
>
</div>
<MouseParallax isAbsolutelyPositioned strength={0.01} zIndex={-50}>
<GameBackground
className="absolute left-0 top-0 w-screen h-screen scale-110"
name="MinecraftBuilding"
/>
</MouseParallax>
</div>
);
}
export function OnboardingNavigation() {
const { isFirstStep, isLastStep, previousPath, nextPath } = Route.useLoaderData();
return (
<div className="absolute bottom-2 right-2 flex flex-row gap-2">
<div>
{!isFirstStep && previousPath && (
<Link to={previousPath}>
<Button className="w-32" color="ghost">Back</Button>
</Link>
)}
</div>
<div>
{nextPath && (
<Link to={nextPath}>
<Button className="w-32">{isLastStep ? 'Finish' : 'Next'}</Button>
</Link>
)}
</div>
</div>
);
}
export function Navbar() {
const onMinimize = () => Window.getCurrent().minimize();
const onMaximize = () => Window.getCurrent().toggleMaximize();
const onClose = () => Window.getCurrent().close();
return (
<nav className="flex flex-row items-center justify-between h-20 px-12 z-50" data-tauri-drag-region="true">
<div className="flex flex-1 items-center justify-end gap-2 pointer-events-none">
<NavbarButton
children={<MinusIcon />}
onClick={onMinimize}
/>
<NavbarButton
children={<SquareIcon />}
onClick={onMaximize}
/>
<NavbarButton
children={(
<XCloseIcon
height={28}
strokeWidth={1.5}
width={28}
/>
)}
className="bg-transparent"
color="danger"
onClick={onClose}
/>
</div>
</nav>
);
}