diff --git a/apps/desktop/src/api/commands/mod.rs b/apps/desktop/src/api/commands/mod.rs index 3604f618..8b4b8233 100644 --- a/apps/desktop/src/api/commands/mod.rs +++ b/apps/desktop/src/api/commands/mod.rs @@ -56,6 +56,8 @@ macro_rules! collect_commands { set_settings, // Metadata get_minecraft_versions, + // Launcher Packages (Instances) + import_launcher_instances, // Provider Packages get_provider_package, get_provider_packages, diff --git a/apps/desktop/src/api/commands/package.rs b/apps/desktop/src/api/commands/package.rs index 9e9126db..e50a9dc5 100644 --- a/apps/desktop/src/api/commands/package.rs +++ b/apps/desktop/src/api/commands/package.rs @@ -1,9 +1,27 @@ +use std::path::PathBuf; + use onelauncher::cluster::content::package; use onelauncher::data::{Loader, ManagedPackage, ManagedUser, ManagedVersion, PackageType}; use onelauncher::package::content::Providers; +use onelauncher::package::import::{default_launcher_path, ImportType}; use onelauncher::store::{Author, ClusterPath, Package, PackagePath, ProviderSearchResults}; use uuid::Uuid; +#[specta::specta] +#[tauri::command] +pub async fn import_launcher_instances(launcher: ImportType, path: Option) -> Result<(), String> { + onelauncher::api::package::import::import_instances( + launcher, + path.unwrap_or( + default_launcher_path(launcher) + .ok_or( + "couldn't get a default path for this launcher" + )? + ) + ).await?; + Ok(()) +} + #[specta::specta] #[tauri::command] pub async fn get_provider_package( diff --git a/apps/frontend/src/RootLayout.tsx b/apps/frontend/src/RootLayout.tsx index ed95d709..6a50c7b7 100644 --- a/apps/frontend/src/RootLayout.tsx +++ b/apps/frontend/src/RootLayout.tsx @@ -1,5 +1,5 @@ import { PROGRAM_INFO } from '@onelauncher/client/bindings'; -import type { ParentProps } from 'solid-js'; +import { onMount, type ParentProps } from 'solid-js'; import { MultiProvider } from './ui/components/MultiProvider'; import { AccountControllerProvider } from './ui/components/overlay/account/AddAccountModal'; import { ClusterModalControllerProvider } from './ui/components/overlay/cluster/ClusterCreationModal'; @@ -10,8 +10,10 @@ import { BrowserProvider } from './ui/hooks/useBrowser'; import { SettingsProvider } from './ui/hooks/useSettings'; function RootLayout(props: ParentProps) { - if (PROGRAM_INFO.dev_build !== true) - document.addEventListener('contextmenu', e => e.preventDefault()); + onMount(() => { + if (PROGRAM_INFO.dev_build !== true) + document.addEventListener('contextmenu', e => e.preventDefault()); + }); return ( diff --git a/apps/frontend/src/assets/illustrations/onboarding/import_from_others.svg b/apps/frontend/src/assets/illustrations/onboarding/import_from_others.svg new file mode 100644 index 00000000..7ab893e1 --- /dev/null +++ b/apps/frontend/src/assets/illustrations/onboarding/import_from_others.svg @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/apps/frontend/src/ui/pages/App.tsx b/apps/frontend/src/ui/pages/App.tsx index e09f9b44..578ccd2b 100644 --- a/apps/frontend/src/ui/pages/App.tsx +++ b/apps/frontend/src/ui/pages/App.tsx @@ -1,3 +1,5 @@ +import { useNavigate } from '@solidjs/router'; +import useSettings from '~ui/hooks/useSettings'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-solid'; import type { ParentProps } from 'solid-js'; import AnimatedRoutes from '../components/AnimatedRoutes'; @@ -5,6 +7,12 @@ import ErrorBoundary from '../components/ErrorBoundary'; import Navbar from '../components/Navbar'; function App(props: ParentProps) { + const { settings } = useSettings(); + const navigate = useNavigate(); + + if (settings().onboarding_completed !== true) + navigate('/onboarding'); + return ( <>
diff --git a/apps/frontend/src/ui/pages/onboarding/Onboarding.tsx b/apps/frontend/src/ui/pages/onboarding/Onboarding.tsx index 70e7e440..d2b3c5c1 100644 --- a/apps/frontend/src/ui/pages/onboarding/Onboarding.tsx +++ b/apps/frontend/src/ui/pages/onboarding/Onboarding.tsx @@ -2,8 +2,9 @@ import { Route, useLocation, useNavigate } from '@solidjs/router'; import { ChevronLeftIcon, ChevronRightIcon } from '@untitled-theme/icons-solid'; import AnimatedRoutes from '~ui/components/AnimatedRoutes'; import Button from '~ui/components/base/Button'; -import PolyfrostFull from '~ui/components/logos/PolyfrostFull'; -import { type JSX, type ParentProps } from 'solid-js'; +import type { JSX, ParentProps } from 'solid-js'; +import OnboardingComplete from './OnboardingComplete'; +import OnboardingImport from './OnboardingImport'; import OnboardingLanguage from './OnboardingLanguage'; import OnboardingWelcome from './OnboardingWelcome'; @@ -11,6 +12,8 @@ const basePath = '/onboarding'; const OnboardingSteps = [ ['/', OnboardingWelcome], ['/language', OnboardingLanguage], + ['/import', OnboardingImport], + ['/complete', OnboardingComplete], ] as const; function Onboarding(props: ParentProps) { @@ -32,33 +35,42 @@ function Onboarding(props: ParentProps) { navigate(basePath + OnboardingSteps[step() - 1]![0]); }; + const percentage = () => (step() / (OnboardingSteps.length - 1)) * 100; + return ( -
-
- +
+
+
-
- - {props.children} - -
+
+
+ + {props.children} + +
-
-
-
@@ -85,13 +97,13 @@ export function OnboardingStep(props: OnboardingStepProps) { {props.illustration}
-
-
+
+

{props.title}

{props.paragraph}

-
+
{props.children}
diff --git a/apps/frontend/src/ui/pages/onboarding/OnboardingComplete.tsx b/apps/frontend/src/ui/pages/onboarding/OnboardingComplete.tsx new file mode 100644 index 00000000..f4d7f542 --- /dev/null +++ b/apps/frontend/src/ui/pages/onboarding/OnboardingComplete.tsx @@ -0,0 +1,13 @@ +function OnboardingComplete() { + return ( +
+

+ You're all set +

+ +

OneLauncher is ready to be used.

+
+ ); +} + +export default OnboardingComplete; diff --git a/apps/frontend/src/ui/pages/onboarding/OnboardingImport.tsx b/apps/frontend/src/ui/pages/onboarding/OnboardingImport.tsx new file mode 100644 index 00000000..5a175782 --- /dev/null +++ b/apps/frontend/src/ui/pages/onboarding/OnboardingImport.tsx @@ -0,0 +1,33 @@ +import Illustration from '~assets/illustrations/onboarding/import_from_others.svg?component-solid'; +import Image from '~assets/logos/vanilla.png'; +import { LAUNCHER_IMPORT_TYPES } from '~utils'; +import { OverlayScrollbarsComponent } from 'overlayscrollbars-solid'; +import { For } from 'solid-js'; +import { OnboardingStep } from './Onboarding'; + +function OnboardingImport() { + return ( + } + paragraph="Import your profiles from other launchers." + title="Import" + > +
+ +
+ + {type => ( +
+ {type} + {type} +
+ )} +
+
+
+
+
+ ); +} + +export default OnboardingImport; diff --git a/apps/frontend/src/ui/pages/onboarding/OnboardingLanguage.tsx b/apps/frontend/src/ui/pages/onboarding/OnboardingLanguage.tsx index e85622ac..0a480c8b 100644 --- a/apps/frontend/src/ui/pages/onboarding/OnboardingLanguage.tsx +++ b/apps/frontend/src/ui/pages/onboarding/OnboardingLanguage.tsx @@ -1,14 +1,72 @@ +import { TRANSLATION_WEBSITE } from '@onelauncher/client'; import Illustration from '~assets/illustrations/onboarding/language.svg?component-solid'; +import Link from '~ui/components/base/Link'; +import { OverlayScrollbarsComponent } from 'overlayscrollbars-solid'; +import { For } from 'solid-js'; import { OnboardingStep } from './Onboarding'; function OnboardingLanguage() { + const languages: [string, number][] = [ + ['English', 100], + ['German', 21], + ['Spanish', 12], + ['Polish', 0], + ['Russian', 0], + ['German', 21], + ['Spanish', 12], + ['Polish', 0], + ['Russian', 0], + ['German', 21], + ['Spanish', 12], + ['Polish', 0], + ['Russian', 0], + ['German', 21], + ['Spanish', 12], + ['Polish', 0], + ['Russian', 0], + ['German', 21], + ['Spanish', 12], + ['Polish', 0], + ['Russian', 0], + ]; + + const selected = () => languages[0]; + return ( } paragraph="Choose your preferred language." title="Language" > -

lol

+
+
+ +
+ b[1] - a[1])}> + {language => ( +
+
{language[0]}
+
+ {language[1]} + % +
+
+ )} +
+
+
+
+ +
+ Help translate OneLauncher +
+
); } diff --git a/apps/frontend/src/ui/pages/onboarding/OnboardingWelcome.tsx b/apps/frontend/src/ui/pages/onboarding/OnboardingWelcome.tsx index c7a69a4f..6649ee3b 100644 --- a/apps/frontend/src/ui/pages/onboarding/OnboardingWelcome.tsx +++ b/apps/frontend/src/ui/pages/onboarding/OnboardingWelcome.tsx @@ -1,12 +1,14 @@ -import { OnboardingStep } from './Onboarding'; - function OnboardingWelcome() { return ( - todo :(} - paragraph="OneLauncher is a powerful and easy-to-use launcher for your applications." - title="Welcome to OneLauncher!" - /> +
+

+ Welcome to + {' '} + OneLauncher +

+ +

A powerful yet easy to use launcher for Minecraft.

+
); } diff --git a/apps/frontend/src/utils/index.ts b/apps/frontend/src/utils/index.ts index e710f2d6..14966590 100644 --- a/apps/frontend/src/utils/index.ts +++ b/apps/frontend/src/utils/index.ts @@ -1,6 +1,6 @@ import { DurationFormat } from '@formatjs/intl-durationformat'; import { open } from '@tauri-apps/plugin-shell'; -import type { Cluster, License, Loader, PackageType, Providers, VersionType } from '@onelauncher/client/bindings'; +import type { Cluster, ImportType, License, Loader, PackageType, Providers, VersionType } from '@onelauncher/client/bindings'; export function supportsMods(loader?: Cluster | Loader): boolean { if (loader === undefined) @@ -153,3 +153,4 @@ export function getPackageUrl(provider: Providers, id: string, package_type: Pac export const LOADERS: Loader[] = ['vanilla', 'fabric', 'forge', 'neoforge', 'quilt'] as const; export const PROVIDERS: Providers[] = ['Modrinth'] as const; export const PACKAGE_TYPES: PackageType[] = ['mod', 'resourcepack', 'datapack', 'shaderpack'] as const; +export const LAUNCHER_IMPORT_TYPES: ImportType[] = ['PrismLauncher', 'Curseforge', 'Modrinth', 'ATLauncher', 'GDLauncher', 'FTBLauncher', 'MultiMC', 'TLauncher', 'Technic'] as const; diff --git a/packages/client/src/constants.ts b/packages/client/src/constants.ts index 8173384c..d8437a9e 100644 --- a/packages/client/src/constants.ts +++ b/packages/client/src/constants.ts @@ -1 +1,2 @@ export const WEBSITE = 'https://polyfrost.org/'; +export const TRANSLATION_WEBSITE = 'https://polyfrost.org/'; diff --git a/packages/core/src/store/settings.rs b/packages/core/src/store/settings.rs index 4585ed7f..be403573 100644 --- a/packages/core/src/store/settings.rs +++ b/packages/core/src/store/settings.rs @@ -66,6 +66,9 @@ pub struct Settings { /// Enable/disable advanced rendering and window decorations. #[serde(default)] pub rendering: bool, + /// Completed onboarding. + #[serde(default)] + pub onboarding_completed: bool, } impl Settings { @@ -125,6 +128,7 @@ impl Settings { config_dir: Directories::init_settings_dir(), hide_on_launch: false, rendering: true, + onboarding_completed: false, }; if recovered_corruption {