diff --git a/apps/oneclient/frontend/src/assets/backgrounds/MinecraftBuilding.png b/apps/oneclient/frontend/src/assets/backgrounds/MinecraftBuilding.png new file mode 100644 index 00000000..94208370 Binary files /dev/null and b/apps/oneclient/frontend/src/assets/backgrounds/MinecraftBuilding.png differ diff --git a/apps/oneclient/frontend/src/assets/logos/oneclient2.svg b/apps/oneclient/frontend/src/assets/logos/oneclient2.svg new file mode 100644 index 00000000..7330f6ce --- /dev/null +++ b/apps/oneclient/frontend/src/assets/logos/oneclient2.svg @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/apps/oneclient/frontend/src/bindings.gen.ts b/apps/oneclient/frontend/src/bindings.gen.ts index 1527efba..c552ce1a 100644 --- a/apps/oneclient/frontend/src/bindings.gen.ts +++ b/apps/oneclient/frontend/src/bindings.gen.ts @@ -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, +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, +openCluster: (folderName: string) => Promise }, +'events': { ingress: (event: IngressPayload) => Promise, message: (event: MessagePayload) => Promise, process: (event: ProcessPayload) => Promise }, 'oneclient': { openDevTools: () => Promise, getClustersGroupedByMajor: () => Promise> }, -'folders': { fromCluster: (folderName: string) => Promise, -openCluster: (folderName: string) => Promise }, 'core': { getClusters: () => Promise, getClusterById: (id: number) => Promise, removeCluster: (id: number) => Promise, diff --git a/apps/oneclient/frontend/src/components/GameBackground.tsx b/apps/oneclient/frontend/src/components/GameBackground.tsx index 6dca5458..281d70fc 100644 --- a/apps/oneclient/frontend/src/components/GameBackground.tsx +++ b/apps/oneclient/frontend/src/components/GameBackground.tsx @@ -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; diff --git a/apps/oneclient/frontend/src/components/Navbar.tsx b/apps/oneclient/frontend/src/components/Navbar.tsx index 0472cad8..de0d3734 100644 --- a/apps/oneclient/frontend/src/components/Navbar.tsx +++ b/apps/oneclient/frontend/src/components/Navbar.tsx @@ -93,7 +93,7 @@ function NavbarLink({ ); } -function NavbarButton({ +export function NavbarButton({ children, color = 'ghost', size = 'iconLarge', diff --git a/apps/oneclient/frontend/src/components/Stepper.tsx b/apps/oneclient/frontend/src/components/Stepper.tsx new file mode 100644 index 00000000..2a2d6850 --- /dev/null +++ b/apps/oneclient/frontend/src/components/Stepper.tsx @@ -0,0 +1,73 @@ +import type { OnboardingStep } from '@/routes/onboarding/route'; +import { useMatchRoute } from '@tanstack/react-router'; + +interface VerticalStepperProps { + steps: Array; + linearSteps: Array>; +}; + +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 ( + + + + + + + + + + {steps.map((step, index) => ( + goToStep(index)} + > + + + {step.title} + + + + ))} + + + + + ); +} diff --git a/apps/oneclient/frontend/src/routes/onboarding/account.tsx b/apps/oneclient/frontend/src/routes/onboarding/account.tsx new file mode 100644 index 00000000..60a283e7 --- /dev/null +++ b/apps/oneclient/frontend/src/routes/onboarding/account.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/onboarding/account')({ + component: RouteComponent, +}) + +function RouteComponent() { + return Hello "/onboarding/account"! +} diff --git a/apps/oneclient/frontend/src/routes/onboarding/finished.tsx b/apps/oneclient/frontend/src/routes/onboarding/finished.tsx new file mode 100644 index 00000000..63221c15 --- /dev/null +++ b/apps/oneclient/frontend/src/routes/onboarding/finished.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/onboarding/finished')({ + component: RouteComponent, +}) + +function RouteComponent() { + return Hello "/onboarding/finished"! +} diff --git a/apps/oneclient/frontend/src/routes/onboarding/index.tsx b/apps/oneclient/frontend/src/routes/onboarding/index.tsx new file mode 100644 index 00000000..75d55f23 --- /dev/null +++ b/apps/oneclient/frontend/src/routes/onboarding/index.tsx @@ -0,0 +1,15 @@ +import { createFileRoute } from '@tanstack/react-router'; + +export const Route = createFileRoute('/onboarding/')({ + component: RouteComponent, +}); + +function RouteComponent() { + return ( + <> + + OneClient + + > + ); +} diff --git a/apps/oneclient/frontend/src/routes/onboarding/language.tsx b/apps/oneclient/frontend/src/routes/onboarding/language.tsx new file mode 100644 index 00000000..eaa4214b --- /dev/null +++ b/apps/oneclient/frontend/src/routes/onboarding/language.tsx @@ -0,0 +1,13 @@ +import { createFileRoute } from '@tanstack/react-router'; + +export const Route = createFileRoute('/onboarding/language')({ + component: RouteComponent, +}); + +function RouteComponent() { + return ( + + Hello "/onboarding/language"! + + ); +} diff --git a/apps/oneclient/frontend/src/routes/onboarding/preferences/index.tsx b/apps/oneclient/frontend/src/routes/onboarding/preferences/index.tsx new file mode 100644 index 00000000..39adfe28 --- /dev/null +++ b/apps/oneclient/frontend/src/routes/onboarding/preferences/index.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/onboarding/preferences/')({ + component: RouteComponent, +}) + +function RouteComponent() { + return Hello "/onboarding/preferences/"! +} diff --git a/apps/oneclient/frontend/src/routes/onboarding/preferences/mods.tsx b/apps/oneclient/frontend/src/routes/onboarding/preferences/mods.tsx new file mode 100644 index 00000000..48e17f3f --- /dev/null +++ b/apps/oneclient/frontend/src/routes/onboarding/preferences/mods.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/onboarding/preferences/mods')({ + component: RouteComponent, +}) + +function RouteComponent() { + return Hello "/onboarding/preferences/mods"! +} diff --git a/apps/oneclient/frontend/src/routes/onboarding/preferences/versions.tsx b/apps/oneclient/frontend/src/routes/onboarding/preferences/versions.tsx new file mode 100644 index 00000000..b02241c2 --- /dev/null +++ b/apps/oneclient/frontend/src/routes/onboarding/preferences/versions.tsx @@ -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 ( + + + Starting Versions + + Something something in corporate style fashion about picking your preferred gamemodes and versions and + optionally loader so that oneclient can pick something for them + + + + {versions.map(version => ( + + ))} + + + + + + + + + ); +} + +interface VersionCardProps { + version: string; + tags: Array; +} + +export function VersionCard({ version, tags }: VersionCardProps) { + return ( + + + + + + {tags.map(tag => ( + + {tag} + + ))} + + + + + + + + {version} + + + + ); +} diff --git a/apps/oneclient/frontend/src/routes/onboarding/route.tsx b/apps/oneclient/frontend/src/routes/onboarding/route.tsx new file mode 100644 index 00000000..b534dc2a --- /dev/null +++ b/apps/oneclient/frontend/src/routes/onboarding/route.tsx @@ -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; +}; + +const ONBOARDING_STEPS: Array = [ + { + 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): Array> { + return steps.flatMap(step => (step.subSteps ? step.subSteps : step)); +} + +const LINEAR_ONBOARDING_STEPS = getLinearSteps(ONBOARDING_STEPS); + +function RouteComponent() { + return ( + + + + + + + + + + + ); +} + +function AppShell({ + children, +}: PropsWithChildren) { + const { isFirstStep } = Route.useLoaderData(); + + return ( + + + + + + + + + + + + + + + + + version info + + + + + {children} + + + + ); +} + +function BackgroundGradient() { + const background = useAppShellStore(state => state.background); + + if (background === 'none') + return undefined; + + return ( + + {/* Linear black gradient: left -> right */} + {/* + */} + + {/* Radial black gradient */} + + + + {/* Linear black gradient: bottom -> 200 px up */} + + + + + + + + ); +} + +export function OnboardingNavigation() { + const { isFirstStep, isLastStep, previousPath, nextPath } = Route.useLoaderData(); + + return ( + + + {!isFirstStep && previousPath && ( + + Back + + )} + + + {nextPath && ( + + {isLastStep ? 'Finish' : 'Next'} + + )} + + + ); +} + +export function Navbar() { + const onMinimize = () => Window.getCurrent().minimize(); + const onMaximize = () => Window.getCurrent().toggleMaximize(); + const onClose = () => Window.getCurrent().close(); + + return ( + + + } + onClick={onMinimize} + /> + } + onClick={onMaximize} + /> + + )} + className="bg-transparent" + color="danger" + onClick={onClose} + /> + + + ); +}
+ Something something in corporate style fashion about picking your preferred gamemodes and versions and + optionally loader so that oneclient can pick something for them +
version info