From b85b12d792796da1074013695214e2764b0312fc Mon Sep 17 00:00:00 2001 From: emirsassan Date: Fri, 16 May 2025 17:44:16 +0300 Subject: [PATCH] feat: add new onboarding routes and components --- .../frontend/src/components/base/Show.tsx | 33 +++++++ .../src/routes/onboarding/complete.tsx | 9 ++ .../frontend/src/routes/onboarding/import.tsx | 9 ++ .../src/routes/onboarding/language.tsx | 52 +++++++++++ .../frontend/src/routes/onboarding/login.tsx | 43 +++++++++ .../frontend/src/routes/onboarding/route.tsx | 87 +++++++++++++++---- .../src/routes/onboarding/summary.tsx | 9 ++ 7 files changed, 226 insertions(+), 16 deletions(-) create mode 100644 apps/onelauncher/frontend/src/components/base/Show.tsx create mode 100644 apps/onelauncher/frontend/src/routes/onboarding/complete.tsx create mode 100644 apps/onelauncher/frontend/src/routes/onboarding/import.tsx create mode 100644 apps/onelauncher/frontend/src/routes/onboarding/language.tsx create mode 100644 apps/onelauncher/frontend/src/routes/onboarding/login.tsx create mode 100644 apps/onelauncher/frontend/src/routes/onboarding/summary.tsx diff --git a/apps/onelauncher/frontend/src/components/base/Show.tsx b/apps/onelauncher/frontend/src/components/base/Show.tsx new file mode 100644 index 00000000..6b6f0745 --- /dev/null +++ b/apps/onelauncher/frontend/src/components/base/Show.tsx @@ -0,0 +1,33 @@ +import React, { type JSX } from 'react'; + +interface ShowProps { + /** + * Condition to evaluate. + * If truthy, `children` are rendered. + * If T is a value (not just boolean), you might want to use it in children, + * but this basic version doesn't automatically pass it like SolidJS does for type narrowing. + */ + when: T | boolean | undefined | null; + /** + * Content to render if `when` is falsy. + */ + fallback?: React.ReactNode; + /** + * Content to render if `when` is truthy. + */ + children: React.ReactNode | ((item: NonNullable) => React.ReactNode); +} + +const ShowComponent = ({ when, fallback = null, children }: ShowProps): JSX.Element | null => { + if (Boolean(when)) { + if (typeof children === 'function') { + // Ensure 'when' is not null or undefined before calling the function. + // This mimics Solid's behavior where children can be a function that receives the truthy 'when' value. + return <>{children(when as NonNullable)}; + } + return <>{children}; + } + return <>{fallback}; +}; + +export const Show = React.memo(ShowComponent) as (props: ShowProps) => JSX.Element | null; \ No newline at end of file diff --git a/apps/onelauncher/frontend/src/routes/onboarding/complete.tsx b/apps/onelauncher/frontend/src/routes/onboarding/complete.tsx new file mode 100644 index 00000000..264e3687 --- /dev/null +++ b/apps/onelauncher/frontend/src/routes/onboarding/complete.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/onboarding/complete')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/onboarding/complete"!
+} diff --git a/apps/onelauncher/frontend/src/routes/onboarding/import.tsx b/apps/onelauncher/frontend/src/routes/onboarding/import.tsx new file mode 100644 index 00000000..c5c0e174 --- /dev/null +++ b/apps/onelauncher/frontend/src/routes/onboarding/import.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/onboarding/import')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/onboarding/import"!
+} diff --git a/apps/onelauncher/frontend/src/routes/onboarding/language.tsx b/apps/onelauncher/frontend/src/routes/onboarding/language.tsx new file mode 100644 index 00000000..0abef23f --- /dev/null +++ b/apps/onelauncher/frontend/src/routes/onboarding/language.tsx @@ -0,0 +1,52 @@ +import { createFileRoute } from '@tanstack/react-router' +import { OnboardingStep } from './route' +import Illustration from '../../assets/illustrations/onboarding/language.svg'; + +export const Route = createFileRoute('/onboarding/language')({ + component: RouteComponent, +}) + +const languages = [ + { + lang: "English", + percentage: 100 + }, +] + +function RouteComponent() { + return ( + <> + } + paragraph="Choose your preferred language." + title="Language"> +
+
+
+
+ +
+
+
+ +
+

Help translate OneLauncher

+
+
+
+ + ) +} diff --git a/apps/onelauncher/frontend/src/routes/onboarding/login.tsx b/apps/onelauncher/frontend/src/routes/onboarding/login.tsx new file mode 100644 index 00000000..871d3a8c --- /dev/null +++ b/apps/onelauncher/frontend/src/routes/onboarding/login.tsx @@ -0,0 +1,43 @@ +import type { MinecraftCredentials } from '@/bindings.gen' +import Button from '@/components/base/Button' +import { Show } from '@/components/base/Show' +import PlayerHead from '@/components/content/PlayerHead' +import { createFileRoute } from '@tanstack/react-router' +import { useState } from 'react' + +export const Route = createFileRoute('/onboarding/login')({ + component: RouteComponent, +}) + +function RouteComponent() { + const [profile, setProfile] = useState() + const [errorMessage, setErrorMessage] = useState('') + + return ( + <> + {/* trust me i'll fix ui issues later */} +
+

Login

+ +

Before you continue, we require you to own a copy of Minecraft: Java Edition.

+ + +
+ +
+

{profile?.username}

+

{profile?.id}

+
+
+
+ +
+ + ) +} diff --git a/apps/onelauncher/frontend/src/routes/onboarding/route.tsx b/apps/onelauncher/frontend/src/routes/onboarding/route.tsx index 1722640e..8b20c03f 100644 --- a/apps/onelauncher/frontend/src/routes/onboarding/route.tsx +++ b/apps/onelauncher/frontend/src/routes/onboarding/route.tsx @@ -1,39 +1,66 @@ import Button from '@/components/base/Button' import { createFileRoute, Outlet, useNavigate, useRouterState } from '@tanstack/react-router' +import type { JSX } from 'react'; export const Route = createFileRoute('/onboarding')({ component: RouteComponent, }) +const steps = [ + '/onboarding', // done + '/onboarding/language', // done (only ui) + '/onboarding/login', // wip + '/onboarding/import', // wip + + '/onboarding/summary', // wip + '/onboarding/complete', // wip +] as const; + function RouteComponent() { const navigate = useNavigate() const routerState = useRouterState() - const steps = [ - '/onboarding/', - ] - const currentPath = routerState.location.pathname const currentStepIndex = steps.findIndex(path => currentPath === path || currentPath.startsWith(path)) - const progressPercentage = steps.length > 1 - ? ((currentStepIndex + 1) / steps.length) * 100 - : (currentStepIndex === 0 ? 100 : 0) + const progressPercentage = + currentStepIndex >= 0 && steps.length > 1 + ? (currentStepIndex / (steps.length - 1)) * 100 + : 0; const handleBack = () => { + console.log("Geri için mevcut yol:", currentPath); + console.log("Geri için mevcut adım indeksi:", currentStepIndex); + if (currentStepIndex > 0) { - navigate({ to: steps[currentStepIndex - 1] }) + const previousStep = steps[currentStepIndex - 1]; + console.log("Geri gidiliyor:", previousStep); + navigate({ to: previousStep as any }); + } else { + console.log("Zaten ilk adımda veya adım bulunamadı, geri gidilemez."); } - } + }; const handleNext = () => { - if (currentStepIndex < steps.length - 1) { - navigate({ to: steps[currentStepIndex + 1] }) - } else { - // if completed navigate to main - navigate({ to: '/app' }) + console.log("İleri için mevcut yol:", currentPath); + console.log("İleri için mevcut adım indeksi:", currentStepIndex); + + if (currentStepIndex === -1) { + navigate({ to: steps[0] as any }); + return; } - } + + if (currentStepIndex < steps.length - 1) { + const nextStep = steps[currentStepIndex + 1]; + console.log("İleri gidiliyor:", nextStep); + navigate({ to: nextStep as any }); + } else if (currentStepIndex === steps.length - 1) { + console.log("Onboarding tamamlandı, /app adresine gidiliyor"); + navigate({ to: '/app' as any }); + } else { + console.log("Bir sonraki adım belirlenemedi."); + } + }; return ( // remind me 2 hours! i'll fix this @@ -54,10 +81,38 @@ function RouteComponent() {
- +
) } + +export interface OnboardingStepProps { + title: string; + paragraph: string; + illustration: JSX.Element; + children: JSX.Element; +} + +export function OnboardingStep(props: OnboardingStepProps) { + return ( +
+
+ {props.illustration} +
+ +
+
+

{props.title}

+

{props.paragraph}

+
+ +
+ {props.children} +
+
+
+ ); +} \ No newline at end of file diff --git a/apps/onelauncher/frontend/src/routes/onboarding/summary.tsx b/apps/onelauncher/frontend/src/routes/onboarding/summary.tsx new file mode 100644 index 00000000..40063d1d --- /dev/null +++ b/apps/onelauncher/frontend/src/routes/onboarding/summary.tsx @@ -0,0 +1,9 @@ +import { createFileRoute } from '@tanstack/react-router' + +export const Route = createFileRoute('/onboarding/summary')({ + component: RouteComponent, +}) + +function RouteComponent() { + return
Hello "/onboarding/summary"!
+}