From eb820e45ff714523dcc6a3171829c47d1be88014 Mon Sep 17 00:00:00 2001
From: LynithDev <61880709+LynithDev@users.noreply.github.com>
Date: Sun, 15 Jun 2025 20:27:44 +0200
Subject: [PATCH 1/2] feat: finished home page and did lots of stuff
---
apps/oneclient/desktop/src/lib.rs | 9 ++
.../src/components/GameBackground.tsx | 8 +-
.../frontend/src/components/Loader.tsx | 68 ++++++++++
.../frontend/src/components/Navbar.tsx | 2 +-
.../frontend/src/components/Spinner.tsx | 32 +++++
.../frontend/src/components/index.ts | 2 +
apps/oneclient/frontend/src/routes/__root.tsx | 3 -
.../frontend/src/routes/app/index.tsx | 126 +++++++++++++++++-
.../frontend/src/routes/app/route.tsx | 40 +++---
.../stores/{appFrameStore.ts => appStore.ts} | 18 ++-
.../frontend/src/styles/animations.css | 18 +++
apps/oneclient/frontend/src/styles/global.css | 14 ++
apps/oneclient/frontend/src/types/global.d.ts | 9 ++
apps/oneclient/frontend/src/utils/motion.ts | 44 ++++++
.../frontend/src/utils/versionMap.ts | 40 ++++++
apps/onelauncher/desktop/src/lib.rs | 9 ++
.../frontend/src/styles/global.css | 11 ++
.../core/src/api/proxy/impl/proxy_tauri.rs | 3 +
packages/core/src/api/tauri/commands.rs | 31 +++--
packages/core/src/logger.rs | 22 ++-
packages/core/src/store/core_options.rs | 6 +-
packages/web_common/package.json | 1 +
.../src/components/AnimatedOutlet.tsx | 2 +-
packages/web_common/src/components/Button.tsx | 3 +-
packages/web_common/src/hooks/useCommand.ts | 63 ++++++---
packages/web_common/src/theme.css | 14 +-
packages/web_common/vite.config.ts | 5 +-
27 files changed, 519 insertions(+), 84 deletions(-)
create mode 100644 apps/oneclient/frontend/src/components/Loader.tsx
create mode 100644 apps/oneclient/frontend/src/components/Spinner.tsx
rename apps/oneclient/frontend/src/stores/{appFrameStore.ts => appStore.ts} (51%)
create mode 100644 apps/oneclient/frontend/src/styles/animations.css
create mode 100644 apps/oneclient/frontend/src/types/global.d.ts
create mode 100644 apps/oneclient/frontend/src/utils/motion.ts
create mode 100644 apps/oneclient/frontend/src/utils/versionMap.ts
diff --git a/apps/oneclient/desktop/src/lib.rs b/apps/oneclient/desktop/src/lib.rs
index d46bfc5c..4e8f7c21 100644
--- a/apps/oneclient/desktop/src/lib.rs
+++ b/apps/oneclient/desktop/src/lib.rs
@@ -20,6 +20,12 @@ pub struct SingleInstancePayload {
#[tracing::instrument]
async fn initialize_core() -> LauncherResult<()> {
+ let level = if cfg!(debug_assertions) {
+ tracing::Level::DEBUG
+ } else {
+ tracing::Level::INFO
+ };
+
let opts = CoreOptions {
curseforge_api_key: Some(constants::CURSEFORGE_API_KEY.to_string()),
launcher_name: "OneClient".to_string(),
@@ -27,6 +33,9 @@ async fn initialize_core() -> LauncherResult<()> {
launcher_website: "https://polyfrost.org/".to_string(),
discord_client_id: None, //Some(constants::DISCORD_CLIENT_ID.to_string()), // disabled for now
fetch_attempts: 3,
+ logger_filter: Some(
+ format!("{}={level},onelauncher_core={level}", env!("CARGO_PKG_NAME")),
+ ),
..Default::default()
};
diff --git a/apps/oneclient/frontend/src/components/GameBackground.tsx b/apps/oneclient/frontend/src/components/GameBackground.tsx
index aea2413d..ef7cebd1 100644
--- a/apps/oneclient/frontend/src/components/GameBackground.tsx
+++ b/apps/oneclient/frontend/src/components/GameBackground.tsx
@@ -1,3 +1,4 @@
+import type { CSSProperties } from 'react';
import { twMerge } from 'tailwind-merge';
import HypixelSkyblockHub from '../assets/backgrounds/HypixelSkyblockHub.png';
@@ -5,20 +6,21 @@ const GameBackgrounds = {
HypixelSkyblockHub,
};
-type GameBackgroundName = keyof typeof GameBackgrounds;
+export type GameBackgroundName = keyof typeof GameBackgrounds;
interface GameBackgroundProps {
name: GameBackgroundName;
className?: string;
+ style?: CSSProperties;
}
-export function GameBackground({ name, className = '' }: GameBackgroundProps) {
+export function GameBackground({ name, className = '', style = undefined }: GameBackgroundProps) {
const BackgroundImage = GameBackgrounds[name];
return (
);
}
diff --git a/apps/oneclient/frontend/src/components/Loader.tsx b/apps/oneclient/frontend/src/components/Loader.tsx
new file mode 100644
index 00000000..5c273593
--- /dev/null
+++ b/apps/oneclient/frontend/src/components/Loader.tsx
@@ -0,0 +1,68 @@
+import type { HTMLAttributes, ReactNode } from 'react';
+import type { SpinnerProps } from './Spinner';
+import { motion } from 'motion/react';
+import { Suspense } from 'react';
+import { twMerge } from 'tailwind-merge';
+import { Spinner } from './Spinner';
+
+interface LoaderProps extends HTMLAttributes {
+ children?: ReactNode;
+ spinner?: SpinnerProps;
+}
+
+export function LoaderContainer({
+ loading = false,
+ children,
+ spinner,
+ className,
+}: LoaderProps & {
+ loading?: boolean;
+}) {
+ return loading ? : {children};
+}
+
+export function LoaderSuspense({
+ children,
+ spinner,
+ className,
+}: LoaderProps) {
+ return (
+ }>
+
+ {children}
+
+
+ );
+}
+
+function Fallback({
+ spinner,
+ className,
+}: {
+ spinner?: SpinnerProps;
+ className?: string;
+}) {
+ return (
+
+
+
+ );
+}
+
+function LoadedChildren({
+ children,
+ className,
+}: {
+ children: ReactNode;
+ className?: string;
+}) {
+ return (
+
+ {children}
+
+ );
+}
diff --git a/apps/oneclient/frontend/src/components/Navbar.tsx b/apps/oneclient/frontend/src/components/Navbar.tsx
index ee07e236..505ad7a7 100644
--- a/apps/oneclient/frontend/src/components/Navbar.tsx
+++ b/apps/oneclient/frontend/src/components/Navbar.tsx
@@ -24,7 +24,7 @@ export function Navbar() {
Accounts
-
+
}
onClick={onMinimize}
diff --git a/apps/oneclient/frontend/src/components/Spinner.tsx b/apps/oneclient/frontend/src/components/Spinner.tsx
new file mode 100644
index 00000000..af8794e7
--- /dev/null
+++ b/apps/oneclient/frontend/src/components/Spinner.tsx
@@ -0,0 +1,32 @@
+import type { HTMLAttributes } from 'react';
+import type { VariantProps } from 'tailwind-variants';
+import { tv } from 'tailwind-variants';
+
+const spinnerVariants = tv({
+ base: 'inline-block relative opacity-0 animate-delay-1000 animate-fade animate-fill-forwards',
+ variants: {
+ size: {
+ small: 'w-8 h-8',
+ medium: 'w-12 h-12',
+ large: 'w-16 h-16',
+ },
+ },
+});
+
+type SpinnerVariantsProps = VariantProps
;
+
+export interface SpinnerProps extends HTMLAttributes {
+ size?: SpinnerVariantsProps['size'];
+};
+
+export function Spinner({
+ size = 'medium',
+ className,
+}: SpinnerProps) {
+ return (
+
+ );
+}
diff --git a/apps/oneclient/frontend/src/components/index.ts b/apps/oneclient/frontend/src/components/index.ts
index b50eb89f..9ca292a7 100644
--- a/apps/oneclient/frontend/src/components/index.ts
+++ b/apps/oneclient/frontend/src/components/index.ts
@@ -1,2 +1,4 @@
export * from './GameBackground';
+export * from './Loader';
export * from './Navbar';
+export * from './Spinner';
diff --git a/apps/oneclient/frontend/src/routes/__root.tsx b/apps/oneclient/frontend/src/routes/__root.tsx
index 87e628bd..e014e607 100644
--- a/apps/oneclient/frontend/src/routes/__root.tsx
+++ b/apps/oneclient/frontend/src/routes/__root.tsx
@@ -1,6 +1,5 @@
import type { QueryClient } from '@tanstack/react-query';
import type { NavigateOptions, ToOptions } from '@tanstack/react-router';
-import { Navbar } from '@/components';
import { AnimatedOutletProvider } from '@onelauncher/common/components';
import { createRootRouteWithContext, Outlet, useRouter } from '@tanstack/react-router';
import { TanStackRouterDevtools } from '@tanstack/react-router-devtools';
@@ -30,8 +29,6 @@ function RootRoute() {
useHref={to => router.buildLocation({ to }).href}
>
-
-
diff --git a/apps/oneclient/frontend/src/routes/app/index.tsx b/apps/oneclient/frontend/src/routes/app/index.tsx
index b74e6a66..bce289b7 100644
--- a/apps/oneclient/frontend/src/routes/app/index.tsx
+++ b/apps/oneclient/frontend/src/routes/app/index.tsx
@@ -1,21 +1,133 @@
+import type { ClusterModel } from '@/bindings.gen';
+import type { HTMLAttributes } from 'react';
+import { GameBackground } from '@/components';
+import { bindings } from '@/main';
+import { animations, transitions } from '@/utils/motion';
+import { getVersionInfo } from '@/utils/versionMap';
+import { useCommandSuspense } from '@onelauncher/common';
+import { Button } from '@onelauncher/common/components';
import { createFileRoute } from '@tanstack/react-router';
+import { DotsGridIcon, Settings04Icon } from '@untitled-theme/icons-react';
+import { motion } from 'motion/react';
+import { twMerge } from 'tailwind-merge';
export const Route = createFileRoute('/app/')({
component: RouteComponent,
});
function RouteComponent() {
+ const { data: clusters } = useCommandSuspense
>(
+ 'getClusters',
+ async () => {
+ await new Promise(resolve => setTimeout(resolve, 3000)); // Simulate loading delay
+ return bindings.core.getClusters();
+ },
+ {
+ select: ((data: Array) => {
+ const sorted = data.sort((a, b) => {
+ if (a.last_played && b.last_played)
+ return new Date(b.last_played).getTime() - new Date(a.last_played).getTime();
+ else if (a.last_played)
+ return -1; // a has last_played, b does not
+ else if (b.last_played)
+ return 1; // b has last_played, a does not
+
+ const aVersion = a.mc_version.replaceAll('.', '');
+ const bVersion = b.mc_version.replaceAll('.', '');
+ return Number.parseInt(bVersion) - Number.parseInt(aVersion);
+ });
+
+ return [
+ sorted[0],
+ sorted[1],
+ undefined,
+ ];
+ }) as (data: Array) => Array,
+ },
+ );
+
return (
-
-
1.8.9
-
-
-
-
+
+ 1.8.9
+ The Bountiful Update
+
+
+
-
+
+
+
+ {clusters.map(cluster => (
+
+ ))}
+
+
+
+
+
+
+ );
+}
+
+interface RecentsCardProps {
+ version: string | undefined;
+}
+
+const BLUR = '30px';
+function RecentsCard({ version }: RecentsCardProps) {
+ const versionInfo = getVersionInfo(version);
+
+ return (
+
+ {versionInfo && (
+
+ )}
+
+ );
+}
+
+function Card({
+ blur = true,
+ children,
+ className,
+ style,
+}: {
+ blur?: boolean;
+ children?: React.ReactNode;
+} & HTMLAttributes
) {
+ return (
+
+ {children}
);
}
diff --git a/apps/oneclient/frontend/src/routes/app/route.tsx b/apps/oneclient/frontend/src/routes/app/route.tsx
index 1dfeeb3b..e4cf6791 100644
--- a/apps/oneclient/frontend/src/routes/app/route.tsx
+++ b/apps/oneclient/frontend/src/routes/app/route.tsx
@@ -1,6 +1,7 @@
+import { LoaderSuspense, Navbar } from '@/components';
import { GameBackground } from '@/components/GameBackground';
import { AnimatedOutlet } from '@onelauncher/common/components';
-import { createFileRoute } from '@tanstack/react-router';
+import { createFileRoute, Outlet } from '@tanstack/react-router';
export const Route = createFileRoute('/app')({
component: RouteComponent,
@@ -8,24 +9,29 @@ export const Route = createFileRoute('/app')({
function RouteComponent() {
return (
-
-
+
+
+
);
}
diff --git a/apps/oneclient/frontend/src/stores/appFrameStore.ts b/apps/oneclient/frontend/src/stores/appStore.ts
similarity index 51%
rename from apps/oneclient/frontend/src/stores/appFrameStore.ts
rename to apps/oneclient/frontend/src/stores/appStore.ts
index 6bbcb87d..f91847fc 100644
--- a/apps/oneclient/frontend/src/stores/appFrameStore.ts
+++ b/apps/oneclient/frontend/src/stores/appStore.ts
@@ -2,17 +2,27 @@ import type { ClusterModel } from '@/bindings.gen';
import type { FileRoutesByFullPath } from '@/routeTree.gen';
import { create } from 'zustand';
-interface AppFrameStore {
- previousPage: FileRoutesByFullPath | null;
+interface AppStore {
activeCluster: ClusterModel | null;
+ previousPage: FileRoutesByFullPath | null;
}
-const useAppFrameStore = create
()(set => ({
+interface AppStoreActions {
+ setInitialData: (data: AppStore) => void;
+ setActiveCluster: (cluster: ClusterModel | null) => void;
+ setPreviousPage: (page: FileRoutesByFullPath) => void;
+}
+
+const useAppStore = create()(set => ({
activeCluster: null,
previousPage: null,
+ setInitialData: (data: AppStore) => set({
+ activeCluster: data.activeCluster,
+ previousPage: data.previousPage,
+ }),
setPreviousPage: (page: FileRoutesByFullPath) => set({ previousPage: page }),
setActiveCluster: (cluster: ClusterModel | null) => set({ activeCluster: cluster }),
}));
-export default useAppFrameStore;
+export default useAppStore;
diff --git a/apps/oneclient/frontend/src/styles/animations.css b/apps/oneclient/frontend/src/styles/animations.css
new file mode 100644
index 00000000..1fd64fb9
--- /dev/null
+++ b/apps/oneclient/frontend/src/styles/animations.css
@@ -0,0 +1,18 @@
+@layer utilities {
+ @keyframes custom-anim-fade-scale {
+ 0% {
+ transform: scale(0);
+ opacity: 1;
+ }
+ 100% {
+ transform: scale(1);
+ opacity: 0;
+ }
+ }
+}
+
+@utility animate-fade-scale {
+ transform: scale(0);
+ opacity: 1;
+ animation: custom-anim-fade-scale var(--default-animation-duration, 1s) var(--default-animation-timing-function, cubic-bezier(0, 0, 0.2, 1)) var(--default-animation-delay, 0s) forwards;
+}
diff --git a/apps/oneclient/frontend/src/styles/global.css b/apps/oneclient/frontend/src/styles/global.css
index 113e4de1..d0f8814a 100644
--- a/apps/oneclient/frontend/src/styles/global.css
+++ b/apps/oneclient/frontend/src/styles/global.css
@@ -2,6 +2,7 @@
@plugin "tailwindcss-react-aria-components";
@plugin "tailwindcss-animated";
@import "../../node_modules/@onelauncher/common/dist/theme.css";
+@import "./animations.css";
@utility partial-underline-* {
position: relative;
@@ -18,3 +19,16 @@
border-radius: 10px;
}
}
+
+@theme {
+ /** border */
+ --color-component-border: #ffffff1A;
+
+ /** rounding */
+ --radius-sm: 0.25rem;
+ --radius-md: 0.438rem;
+ --radius-lg: 0.625rem;
+ --radius-xl: 1rem;
+ --radius-2xl: 1.5rem;
+ --radius-3xl: 2rem;
+}
diff --git a/apps/oneclient/frontend/src/types/global.d.ts b/apps/oneclient/frontend/src/types/global.d.ts
new file mode 100644
index 00000000..871e7fd1
--- /dev/null
+++ b/apps/oneclient/frontend/src/types/global.d.ts
@@ -0,0 +1,9 @@
+import type { bindings } from '@/main';
+
+export type BindingCommands = (keyof typeof bindings.core) | (keyof typeof bindings.oneclient);
+
+declare module '@onelauncher/common' {
+ interface Register {
+ commands: Array;
+ }
+}
diff --git a/apps/oneclient/frontend/src/utils/motion.ts b/apps/oneclient/frontend/src/utils/motion.ts
new file mode 100644
index 00000000..44ceedac
--- /dev/null
+++ b/apps/oneclient/frontend/src/utils/motion.ts
@@ -0,0 +1,44 @@
+import type { MotionProps } from 'motion/react';
+
+export const transitions = {
+ spring: {
+ duration: 0.3,
+ bounce: 0.1,
+ power: 0.2,
+ type: 'spring',
+ },
+} as const satisfies Record;
+
+export const animations = {
+ slideInRight: {
+ initial: {
+ right: '-100%',
+ },
+ animate: {
+ right: '0',
+ },
+ transition: transitions.spring,
+ },
+
+ slideInLeft: {
+ initial: {
+ position: 'relative',
+ left: '-100%',
+ },
+ animate: {
+ position: 'relative',
+ left: '0',
+ },
+ },
+
+ slideInUp: {
+ initial: {
+ position: 'relative',
+ bottom: '-100%',
+ },
+ animate: {
+ position: 'relative',
+ bottom: '0',
+ },
+ },
+} as const satisfies Record;
diff --git a/apps/oneclient/frontend/src/utils/versionMap.ts b/apps/oneclient/frontend/src/utils/versionMap.ts
new file mode 100644
index 00000000..e232f3db
--- /dev/null
+++ b/apps/oneclient/frontend/src/utils/versionMap.ts
@@ -0,0 +1,40 @@
+import type { GameBackgroundName } from '@/components';
+
+export interface VersionInfo {
+ backgroundName: GameBackgroundName;
+ description: string;
+}
+
+const VERSION_MAP: Record = {
+ [-1]: {
+ backgroundName: 'HypixelSkyblockHub',
+ description: 'Unknown Version',
+ },
+ 8: {
+ backgroundName: 'HypixelSkyblockHub',
+ description: 'The Bountiful Update',
+ },
+} as const;
+
+export function getVersionInfo(version: number | string | null | undefined): VersionInfo | undefined {
+ if (version === undefined || version === null)
+ return undefined;
+
+ let majorVersion;
+
+ if (typeof version === 'string') {
+ const parts = version.split('.');
+ if (parts.length >= 2)
+ majorVersion = Number.parseInt(parts[1], 10);
+ }
+
+ if (majorVersion)
+ return VERSION_MAP[majorVersion];
+ else
+ return undefined;
+}
+
+export function getVersionInfoOrDefault(version: number | string): VersionInfo {
+ const info = getVersionInfo(version);
+ return info ?? VERSION_MAP[-1];
+}
diff --git a/apps/onelauncher/desktop/src/lib.rs b/apps/onelauncher/desktop/src/lib.rs
index fee5c801..7bc4dad5 100644
--- a/apps/onelauncher/desktop/src/lib.rs
+++ b/apps/onelauncher/desktop/src/lib.rs
@@ -20,6 +20,12 @@ pub struct SingleInstancePayload {
#[tracing::instrument]
async fn initialize_core() -> LauncherResult<()> {
+ let level = if cfg!(debug_assertions) {
+ tracing::Level::DEBUG
+ } else {
+ tracing::Level::INFO
+ };
+
let opts = CoreOptions {
curseforge_api_key: Some(constants::CURSEFORGE_API_KEY.to_string()),
launcher_name: "OneLauncher".to_string(),
@@ -27,6 +33,9 @@ async fn initialize_core() -> LauncherResult<()> {
launcher_website: "https://polyfrost.org/".to_string(),
discord_client_id: Some(constants::DISCORD_CLIENT_ID.to_string()),
fetch_attempts: 3,
+ logger_filter: Some(
+ format!("{}={level},onelauncher_core={level}", env!("CARGO_PKG_NAME")),
+ ),
..Default::default()
};
diff --git a/apps/onelauncher/frontend/src/styles/global.css b/apps/onelauncher/frontend/src/styles/global.css
index 4b3b8ec7..34cfceb8 100644
--- a/apps/onelauncher/frontend/src/styles/global.css
+++ b/apps/onelauncher/frontend/src/styles/global.css
@@ -2,3 +2,14 @@
@plugin "tailwindcss-react-aria-components";
@plugin "tailwindcss-animated";
@import "../../node_modules/@onelauncher/common/dist/theme.css";
+
+@theme {
+ --radius-xs: 0.125rem;
+ --radius-sm: 0.25rem;
+ --radius-md: 0.375rem;
+ --radius-lg: 0.5rem;
+ --radius-xl: 0.75rem;
+ --radius-2xl: 1rem;
+ --radius-3xl: 1.5rem;
+ --radius-4xl: 2rem;
+}
diff --git a/packages/core/src/api/proxy/impl/proxy_tauri.rs b/packages/core/src/api/proxy/impl/proxy_tauri.rs
index f38d0558..46d89fe1 100644
--- a/packages/core/src/api/proxy/impl/proxy_tauri.rs
+++ b/packages/core/src/api/proxy/impl/proxy_tauri.rs
@@ -12,6 +12,9 @@ pub struct ProxyTauri {
impl ProxyTauri {
#[must_use]
pub fn new(handle: AppHandle) -> Self {
+ tracing::debug!("using tauri bridge");
+ tracing::debug!("webview version: {}", tauri::webview_version().unwrap_or("unknown".into()));
+
Self {
emitter: LauncherEventEmitter::new(handle.clone()),
handle,
diff --git a/packages/core/src/api/tauri/commands.rs b/packages/core/src/api/tauri/commands.rs
index e7444efe..6959941e 100644
--- a/packages/core/src/api/tauri/commands.rs
+++ b/packages/core/src/api/tauri/commands.rs
@@ -1,6 +1,5 @@
use interpulse::api::minecraft::Version;
-use onelauncher_entity::{clusters, icon::Icon, loader::GameLoader, prelude::entity};
-use sea_orm::ActiveValue::Set;
+use onelauncher_entity::{icon::Icon, loader::GameLoader};
use tauri::{AppHandle, Runtime};
use crate::{api::{self, cluster::dao::ClusterId}, error::LauncherResult, store::{credentials::MinecraftCredentials, Core}};
@@ -26,8 +25,8 @@ pub trait TauriLauncherApi {
#[taurpc(alias = "launchCluster")]
async fn launch_cluster(id: ClusterId, uuid: Option) -> LauncherResult<()>;
- #[taurpc(alias = "updateClusterById")]
- async fn update_cluster_by_id(id: ClusterId, request: Cluster) -> LauncherResult<()>;
+ // #[taurpc(alias = "updateClusterById")]
+ // async fn update_cluster_by_id(id: ClusterId, request: Cluster) -> LauncherResult<()>;
// Setting Profiles
@@ -120,21 +119,21 @@ impl TauriLauncherApi for TauriLauncherApiImpl {
Ok(())
}
- async fn update_cluster_by_id(id: ClusterId, request: clusters::ActiveModel) -> LauncherResult<()> {
- let updated_cluster = api::cluster::dao::update_cluster_by_id(id, |mut active_model| async move {
- if let Some(name) = request.name {
- active_model.name = Set(name);
- }
+ // async fn update_cluster_by_id(self, id: ClusterId, request: clusters::ActiveModel) -> LauncherResult<()> {
+ // // let updated_cluster = api::cluster::dao::update_cluster_by_id(id, |mut active_model| async move {
+ // // if let Some(name) = request.name {
+ // // active_model.name = Set(name);
+ // // }
- active_model.updated_at = Set(chrono::Utc::now().naive_utc());
+ // // active_model.updated_at = Set(chrono::Utc::now().naive_utc());
- Ok(active_model)
- })
- .await
- .map_err(|e| e.to_string())?;
+ // // Ok(active_model)
+ // // })
+ // // .await
+ // // .map_err(|e| e.to_string())?;
- Ok(())
- }
+ // Ok(())
+ // }
// Setting Profiles
diff --git a/packages/core/src/logger.rs b/packages/core/src/logger.rs
index e7740b80..fd0b74e2 100644
--- a/packages/core/src/logger.rs
+++ b/packages/core/src/logger.rs
@@ -6,7 +6,15 @@ use crate::store::Core;
#[cfg(debug_assertions)]
pub async fn start_logger() {
let filter = tracing_subscriber::EnvFilter::try_from_default_env()
- .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(format!("{}=info", env!("CARGO_PKG_NAME"))));
+ .unwrap_or_else(|_| {
+ tracing_subscriber::EnvFilter::new(
+ Core::get().logger_filter
+ .as_ref()
+ .unwrap_or(
+ &format!("{}=info", env!("CARGO_PKG_NAME"))
+ )
+ )
+ });
let mut fmt_layer = tracing_subscriber::fmt::layer()
.with_ansi(true)
@@ -16,7 +24,7 @@ pub async fn start_logger() {
.with_thread_names(true)
.pretty();
- if let Some(span) = Core::get().span_formatting.clone() {
+ if let Some(span) = Core::get().logger_span_formatting.clone() {
fmt_layer = fmt_layer.with_span_events(span);
}
@@ -62,7 +70,15 @@ pub async fn start_logger() {
};
let filter = tracing_subscriber::EnvFilter::try_from_default_env()
- .unwrap_or_else(|_| tracing_subscriber::EnvFilter::new(format!("{}=info", env!("CARGO_PKG_NAME"))));
+ .unwrap_or_else(|_| {
+ tracing_subscriber::EnvFilter::new(
+ Core::get().logger_filter
+ .as_ref()
+ .unwrap_or(
+ &format!("{}=info", env!("CARGO_PKG_NAME"))
+ )
+ )
+ });
let mut fmt_layer = tracing_subscriber::fmt::layer()
.compact()
diff --git a/packages/core/src/store/core_options.rs b/packages/core/src/store/core_options.rs
index 2df8568c..e44c23a5 100644
--- a/packages/core/src/store/core_options.rs
+++ b/packages/core/src/store/core_options.rs
@@ -16,11 +16,12 @@ pub struct CoreOptions {
pub launcher_version: String,
pub launcher_website: String,
pub fetch_attempts: usize,
- pub span_formatting: Option,
/// Default client id is the same as the one used by the official launcher
pub msa_client_id: String,
pub msa_redirect_uri: String,
pub curseforge_api_key: Option,
+ pub logger_span_formatting: Option,
+ pub logger_filter: Option,
}
impl Default for CoreOptions {
@@ -31,10 +32,11 @@ impl Default for CoreOptions {
launcher_version: String::from(env!("CARGO_PKG_VERSION")),
launcher_website: String::from("https://polyfrost.org/"),
fetch_attempts: 3,
- span_formatting: None,
msa_client_id: String::from("00000000402b5328"),
msa_redirect_uri: String::from("https://login.live.com/oauth20_desktop.srf"),
curseforge_api_key: None,
+ logger_span_formatting: None,
+ logger_filter: None,
}
}
}
diff --git a/packages/web_common/package.json b/packages/web_common/package.json
index 52c8abd4..18c0cf6d 100644
--- a/packages/web_common/package.json
+++ b/packages/web_common/package.json
@@ -24,6 +24,7 @@
"peerDependencies": {
"@tanstack/react-query": "^5.66.5",
"@tanstack/react-router": "^1.114.3",
+ "@untitled-theme/icons-react": "^0.14.0",
"motion": "^12.10.5",
"react": "^19.0.0",
"react-aria-components": "^1.8.0",
diff --git a/packages/web_common/src/components/AnimatedOutlet.tsx b/packages/web_common/src/components/AnimatedOutlet.tsx
index 2c6cecc5..bfa4801b 100644
--- a/packages/web_common/src/components/AnimatedOutlet.tsx
+++ b/packages/web_common/src/components/AnimatedOutlet.tsx
@@ -7,7 +7,7 @@
import type { AnyRoute } from '@tanstack/react-router';
import type { MotionProps } from 'motion/react';
import { Outlet, useMatch, useRouter } from '@tanstack/react-router';
-import { motion } from 'motion/react';
+import { AnimatePresence, motion } from 'motion/react';
import { createContext, useContext, useEffect, useRef, useState } from 'react';
interface TransitionProps {
diff --git a/packages/web_common/src/components/Button.tsx b/packages/web_common/src/components/Button.tsx
index c6c72b1e..1fefb9c7 100644
--- a/packages/web_common/src/components/Button.tsx
+++ b/packages/web_common/src/components/Button.tsx
@@ -29,8 +29,9 @@ export const buttonVariants = tv({
},
size: {
normal: 'py-1.5 px-3',
+ large: 'py-2 px-6 text-lg',
icon: 'p-1.5 aspect-square box-border w-8 h-8',
- iconLarge: 'w-9 h-9 [&>*]:p-0.5',
+ iconLarge: 'w-10 h-10 [&>*]:p-0.5',
},
},
});
diff --git a/packages/web_common/src/hooks/useCommand.ts b/packages/web_common/src/hooks/useCommand.ts
index 752218db..a9322841 100644
--- a/packages/web_common/src/hooks/useCommand.ts
+++ b/packages/web_common/src/hooks/useCommand.ts
@@ -1,5 +1,6 @@
-import type { UndefinedInitialDataOptions, UseQueryResult } from '@tanstack/react-query';
-import { useQuery } from '@tanstack/react-query';
+/* eslint-disable query/exhaustive-deps -- False */
+import type { UndefinedInitialDataOptions, UseMutationOptions, UseMutationResult, UseQueryResult, UseSuspenseQueryOptions, UseSuspenseQueryResult } from '@tanstack/react-query';
+import { useMutation, useQuery, useSuspenseQuery } from '@tanstack/react-query';
// this gets overwritten by the consumer project
export interface Register {
@@ -10,24 +11,52 @@ type RegisterConfig = Register extends {
commands: infer Keys;
} ? Keys : never;
-export function useCommand(cacheKey: RegisterConfig[number] | (string & {}) | false, command: () => Promise, options?: Omit, 'queryKey' | 'queryFn'>): UseQueryResult {
+async function fetchCommand(command: () => Promise): Promise {
+ try {
+ const result = await command();
+ return result;
+ }
+ // TODO: (lynith) handle errors better (requires modifications to TauRPC)
+ catch (e) {
+ console.error(e);
+ if (e instanceof Error)
+ return Promise.reject(e);
+ else
+ return Promise.reject(new Error('Unknown error'));
+ }
+}
+
+export function useCommand(
+ cacheKey: RegisterConfig[number] | (string & {}) | false,
+ command: () => Promise,
+ options?: Omit, 'queryKey' | 'queryFn'>,
+): UseQueryResult {
return useQuery({
queryKey: cacheKey === false ? [] : [cacheKey],
- queryFn: async () => {
- try {
- const result = await command();
- return result;
- }
- // TODO: (lynith) handle errors better (requires modifications to TauRPC)
- catch (e) {
- console.error(e);
- if (e instanceof Error)
- return Promise.reject(e);
- else
- return Promise.reject(new Error('Unknown error'));
- }
- },
+ queryFn: () => fetchCommand(command),
enabled: true,
...options,
});
}
+
+export function useCommandSuspense(
+ cacheKey: RegisterConfig[number] | (string & {}) | false,
+ command: () => Promise,
+ options?: Omit, 'queryKey' | 'queryFn'>,
+): UseSuspenseQueryResult {
+ return useSuspenseQuery({
+ queryKey: cacheKey === false ? [] : [cacheKey],
+ queryFn: () => fetchCommand(command),
+ ...options,
+ });
+}
+
+export function useCommandMut(
+ command: () => Promise,
+ options?: Omit, 'mutationFn'>,
+): UseMutationResult {
+ return useMutation({
+ mutationFn: () => fetchCommand(command),
+ ...options,
+ });
+}
diff --git a/packages/web_common/src/theme.css b/packages/web_common/src/theme.css
index c1631c37..74ee89cc 100644
--- a/packages/web_common/src/theme.css
+++ b/packages/web_common/src/theme.css
@@ -3,7 +3,7 @@
@plugin "tailwindcss-animated";
@theme {
- /* foreground colors */
+ /** foreground colors */
--color-fg-primary: #d5dbff;
--color-fg-primary-hover: #dae0ff;
--color-fg-primary-pressed: #e1e5ff;
@@ -19,7 +19,7 @@
--color-link-pressed: #72afff;
--color-link-disabled: #7597b3;
- /* background colors */
+ /** background colors */
--color-brand: #2b4bff;
--color-brand-hover: #2843dd;
--color-brand-pressed: #3957ff;
@@ -35,7 +35,7 @@
--color-page-overlay: #ffffff1a;
--color-window-frame: #151b20;
- /* general colors */
+ /** general colors */
--color-danger: #ff4444;
--color-danger-hover: #d63434;
--color-danger-pressed: #ff5656;
@@ -52,12 +52,12 @@
--color-code-debug: #2b4bff;
--color-code-trace: #fdfdfd;
- /* border */
+ /** border */
--color-component-border: rgba(255, 255, 255, 0.05);
--color-component-border-hover: rgba(255, 255, 255, 0.10);
--color-component-border-pressed: rgba(255, 255, 255, 0.15);
- /* overlay */
+ /** overlay */
--color-ghost-overlay: rgba(255, 255, 255, 0.05);
--color-ghost-overlay-hover: rgba(255, 255, 255, 0.10);
--color-ghost-overlay-pressed: rgba(255, 255, 255, 0.15);
@@ -66,11 +66,11 @@
--color-scrollbar-bg-hover: rgba(255, 255, 255, 0.10);
--color-scrollbar-bg-pressed: rgba(255, 255, 255, 0.15);
- /* other */
+ /** other */
--font-sans: "Poppins", sans-serif;
--text-xs: 0.688rem;
--text-sm: 0.75rem;
- --text-base: 0.875rem;
+ --text-base: 0.875rem; /** body text is 14px */
--text-lg: 1rem;
--text-2lg: 1.125rem;
--text-xl: 1.25rem;
diff --git a/packages/web_common/vite.config.ts b/packages/web_common/vite.config.ts
index 926b3f73..c4962b2c 100644
--- a/packages/web_common/vite.config.ts
+++ b/packages/web_common/vite.config.ts
@@ -25,8 +25,8 @@ export default defineConfig({
minify: false,
lib: {
entry: {
- 'index': path.resolve(__dirname, 'src/index.ts'),
- 'components': path.resolve(__dirname, 'src/components/index.ts'),
+ index: path.resolve(__dirname, 'src/index.ts'),
+ components: path.resolve(__dirname, 'src/components/index.ts'),
},
formats: ['es'],
fileName: (_, entryName) => `${entryName}.js`,
@@ -44,6 +44,7 @@ export default defineConfig({
'tailwindcss',
'tailwind-merge',
'tailwind-variants',
+ '@untitled-theme/icons-react',
// 'tailwindcss-animated',
// 'tailwindcss-react-aria-components',
],
From 4e8b03f86b4ec9454268d1b3f5d32a8ceaf4fce9 Mon Sep 17 00:00:00 2001
From: LynithDev <61880709+LynithDev@users.noreply.github.com>
Date: Tue, 17 Jun 2025 21:42:42 +0200
Subject: [PATCH 2/2] temp: cluster pages
---
.../frontend/src/components/Navbar.tsx | 2 +-
.../app/{test.tsx => clusters/index.tsx} | 4 +-
.../src/routes/app/clusters/route.tsx | 57 +++++++++++++++++
.../frontend/src/routes/app/index.tsx | 61 +++++++++++--------
.../frontend/src/routes/app/route.tsx | 15 +++--
packages/web_common/src/theme.css | 1 +
6 files changed, 102 insertions(+), 38 deletions(-)
rename apps/oneclient/frontend/src/routes/app/{test.tsx => clusters/index.tsx} (54%)
create mode 100644 apps/oneclient/frontend/src/routes/app/clusters/route.tsx
diff --git a/apps/oneclient/frontend/src/components/Navbar.tsx b/apps/oneclient/frontend/src/components/Navbar.tsx
index 505ad7a7..74913b2c 100644
--- a/apps/oneclient/frontend/src/components/Navbar.tsx
+++ b/apps/oneclient/frontend/src/components/Navbar.tsx
@@ -20,7 +20,7 @@ export function Navbar() {
Home
- Clusters
+ Clusters
Accounts
diff --git a/apps/oneclient/frontend/src/routes/app/test.tsx b/apps/oneclient/frontend/src/routes/app/clusters/index.tsx
similarity index 54%
rename from apps/oneclient/frontend/src/routes/app/test.tsx
rename to apps/oneclient/frontend/src/routes/app/clusters/index.tsx
index 9f1b1495..08b49803 100644
--- a/apps/oneclient/frontend/src/routes/app/test.tsx
+++ b/apps/oneclient/frontend/src/routes/app/clusters/index.tsx
@@ -1,9 +1,9 @@
import { createFileRoute } from '@tanstack/react-router';
-export const Route = createFileRoute('/app/test')({
+export const Route = createFileRoute('/app/clusters/')({
component: RouteComponent,
});
function RouteComponent() {
- return Hello "/app/test"!
;
+ return Hello "/app/clusters/"!
;
}
diff --git a/apps/oneclient/frontend/src/routes/app/clusters/route.tsx b/apps/oneclient/frontend/src/routes/app/clusters/route.tsx
new file mode 100644
index 00000000..66b2e11f
--- /dev/null
+++ b/apps/oneclient/frontend/src/routes/app/clusters/route.tsx
@@ -0,0 +1,57 @@
+import { AnimatedOutlet, AnimatedOutletProvider } from '@onelauncher/common/components';
+import { createFileRoute } from '@tanstack/react-router';
+
+export const Route = createFileRoute('/app/clusters')({
+ component: RouteComponent,
+});
+
+function RouteComponent() {
+ return (
+
+ );
+}
+
+function BackgroundGradients() {
+ return (
+
+ );
+}
diff --git a/apps/oneclient/frontend/src/routes/app/index.tsx b/apps/oneclient/frontend/src/routes/app/index.tsx
index bce289b7..6d36a199 100644
--- a/apps/oneclient/frontend/src/routes/app/index.tsx
+++ b/apps/oneclient/frontend/src/routes/app/index.tsx
@@ -15,36 +15,43 @@ export const Route = createFileRoute('/app/')({
component: RouteComponent,
});
+const clusters = [
+ {
+ mc_version: '1.8.9',
+ },
+ undefined,
+ {
+ mc_version: '1.21.4',
+ },
+];
+
function RouteComponent() {
- const { data: clusters } = useCommandSuspense>(
- 'getClusters',
- async () => {
- await new Promise(resolve => setTimeout(resolve, 3000)); // Simulate loading delay
- return bindings.core.getClusters();
- },
- {
- select: ((data: Array) => {
- const sorted = data.sort((a, b) => {
- if (a.last_played && b.last_played)
- return new Date(b.last_played).getTime() - new Date(a.last_played).getTime();
- else if (a.last_played)
- return -1; // a has last_played, b does not
- else if (b.last_played)
- return 1; // b has last_played, a does not
+ // const { data: clusters } = useCommandSuspense>(
+ // 'getClusters',
+ // bindings.core.getClusters,
+ // {
+ // select: ((data: Array) => {
+ // const sorted = data.sort((a, b) => {
+ // if (a.last_played && b.last_played)
+ // return new Date(b.last_played).getTime() - new Date(a.last_played).getTime();
+ // else if (a.last_played)
+ // return -1; // a has last_played, b does not
+ // else if (b.last_played)
+ // return 1; // b has last_played, a does not
- const aVersion = a.mc_version.replaceAll('.', '');
- const bVersion = b.mc_version.replaceAll('.', '');
- return Number.parseInt(bVersion) - Number.parseInt(aVersion);
- });
+ // const aVersion = a.mc_version.replaceAll('.', '');
+ // const bVersion = b.mc_version.replaceAll('.', '');
+ // return Number.parseInt(bVersion) - Number.parseInt(aVersion);
+ // });
- return [
- sorted[0],
- sorted[1],
- undefined,
- ];
- }) as (data: Array) => Array,
- },
- );
+ // return [
+ // sorted[0],
+ // sorted[1],
+ // undefined,
+ // ];
+ // }) as (data: Array) => Array,
+ // },
+ // );
return (
diff --git a/apps/oneclient/frontend/src/routes/app/route.tsx b/apps/oneclient/frontend/src/routes/app/route.tsx
index e4cf6791..269c75ad 100644
--- a/apps/oneclient/frontend/src/routes/app/route.tsx
+++ b/apps/oneclient/frontend/src/routes/app/route.tsx
@@ -1,7 +1,7 @@
import { LoaderSuspense, Navbar } from '@/components';
import { GameBackground } from '@/components/GameBackground';
import { AnimatedOutlet } from '@onelauncher/common/components';
-import { createFileRoute, Outlet } from '@tanstack/react-router';
+import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/app')({
component: RouteComponent,
@@ -16,19 +16,18 @@ function RouteComponent() {
diff --git a/packages/web_common/src/theme.css b/packages/web_common/src/theme.css
index 74ee89cc..f0be6864 100644
--- a/packages/web_common/src/theme.css
+++ b/packages/web_common/src/theme.css
@@ -83,6 +83,7 @@
* {
user-select: none !important;
-webkit-user-select: none !important;
+ -webkit-user-drag: none !important;
cursor: default !important;
}