feat: oneclient home page almost done

This commit is contained in:
LynithDev 2025-06-13 14:36:55 +02:00
parent 29813acb5a
commit 5a427c0379
35 changed files with 1569 additions and 541 deletions

View file

@ -93,7 +93,7 @@
// updated 2024-08-26 15:46
// https://github.com/antfu/vscode-file-nesting-config
"explorer.fileNesting.enabled": true,
"explorer.fileNesting.enabled": false,
"explorer.fileNesting.expand": false,
"explorer.fileNesting.patterns": {
".clang-tidy": ".clang-format, .clangd, compile_commands.json",

View file

@ -4,4 +4,4 @@ dist
dist-ssr
*.local
*.gen.ts
**/*.gen.ts

View file

@ -39,7 +39,8 @@
"tailwindcss": "^4.0.6",
"tailwindcss-animated": "^2.0.0",
"tailwindcss-react-aria-components": "^2.0.0",
"taurpc": "^1.8.1"
"taurpc": "^1.8.1",
"zustand": "^5.0.5"
},
"devDependencies": {
"@tanstack/eslint-config": "^0.1.0",
@ -47,6 +48,7 @@
"@types/react-dom": "^19.0.3",
"@vitejs/plugin-react": "^4.3.4",
"typescript": "^5.7.2",
"vite": "^6.1.0"
"vite": "^6.1.0",
"vite-plugin-svgr": "^4.3.0"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 MiB

View file

@ -0,0 +1,4 @@
<svg width="156" height="32" viewBox="0 0 156 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10.9398 25.6841C9.60192 25.6841 8.3644 25.447 7.22718 24.9728C6.10671 24.4986 5.12003 23.8381 4.26712 22.9913C3.41424 22.1446 2.75365 21.1623 2.28539 20.0446C1.81714 18.9099 1.58301 17.6905 1.58301 16.3865C1.58301 15.0655 1.81714 13.8461 2.28539 12.7284C2.75365 11.6107 3.40587 10.6368 4.24206 9.80701C5.07821 8.96023 6.05654 8.3082 7.17703 7.85093C8.31422 7.37675 9.55174 7.13965 10.8896 7.13965C12.2108 7.13965 13.4316 7.37675 14.5521 7.85093C15.6893 8.3082 16.676 8.96023 17.5122 9.80701C18.365 10.6368 19.0256 11.6191 19.4939 12.7538C19.9621 13.8715 20.1963 15.0909 20.1963 16.4119C20.1963 17.7159 19.9621 18.9353 19.4939 20.07C19.0256 21.1877 18.3734 22.17 17.5372 23.0168C16.7011 23.8466 15.7144 24.4986 14.5772 24.9728C13.4567 25.447 12.2443 25.6841 10.9398 25.6841ZM10.8896 22.0514C11.9432 22.0514 12.863 21.8143 13.649 21.3401C14.4517 20.8659 15.0705 20.2054 15.5053 19.3587C15.9401 18.495 16.1576 17.5042 16.1576 16.3865C16.1576 15.5397 16.0321 14.7776 15.7813 14.1002C15.5304 13.4058 15.1709 12.8131 14.7026 12.3219C14.2344 11.8139 13.6741 11.4328 13.0219 11.1788C12.3864 10.9078 11.6757 10.7723 10.8896 10.7723C9.83606 10.7723 8.90791 11.0094 8.10518 11.4836C7.31917 11.9409 6.70876 12.5929 6.27395 13.4397C5.83913 14.2695 5.62175 15.2518 5.62175 16.3865C5.62175 17.2332 5.74716 18.0038 5.99802 18.6982C6.24886 19.3925 6.60007 19.9937 7.05159 20.5018C7.51986 20.9929 8.08009 21.374 8.73232 21.645C9.38451 21.9159 10.1036 22.0514 10.8896 22.0514ZM24.2015 25.3793V7.4445H26.9609L28.1399 11.0264V25.3793H24.2015ZM36.4181 25.3793L25.9825 11.8393L26.9609 7.4445L37.3963 20.9845L36.4181 25.3793ZM36.4181 25.3793L35.3644 21.7974V7.4445H39.3029V25.3793H36.4181ZM44.2267 25.3793V7.4445H48.1649V25.3793H44.2267ZM47.2368 25.3793V21.9244H56.9448V25.3793H47.2368ZM47.2368 17.8853V14.5574H56.0669V17.8853H47.2368ZM47.2368 10.8739V7.4445H56.8192V10.8739H47.2368Z" fill="currentColor" fill-opacity="0.85"/>
<path d="M69.2499 25.6588C67.9287 25.6588 66.6996 25.4302 65.5623 24.9729C64.4419 24.4987 63.4552 23.8382 62.6023 22.9915C61.7663 22.1447 61.1139 21.1624 60.6456 20.0447C60.1774 18.91 59.9434 17.6906 59.9434 16.3866C59.9434 15.0825 60.1774 13.8716 60.6456 12.7539C61.1139 11.6192 61.7663 10.6369 62.6023 9.80712C63.4386 8.97727 64.4168 8.33371 65.5373 7.87644C66.6746 7.40227 67.9037 7.16516 69.2248 7.16516C70.6296 7.16516 71.8756 7.3938 72.9625 7.85104C74.0663 8.30831 75.0279 8.93493 75.8473 9.7309L73.2134 12.4236C72.7452 11.9156 72.1766 11.5176 71.5076 11.2297C70.8555 10.9418 70.0946 10.7979 69.2248 10.7979C68.4556 10.7979 67.7448 10.9333 67.0927 11.2043C66.4572 11.4583 65.9053 11.8309 65.437 12.322C64.9854 12.8132 64.626 13.4059 64.3583 14.1003C64.1074 14.7946 63.9821 15.5567 63.9821 16.3866C63.9821 17.2334 64.1074 18.0039 64.3583 18.6983C64.626 19.3926 64.9854 19.9854 65.437 20.4765C65.9053 20.9676 66.4572 21.3487 67.0927 21.6197C67.7448 21.8907 68.4556 22.0261 69.2248 22.0261C70.1279 22.0261 70.914 21.8822 71.5828 21.5943C72.2518 21.3064 72.8288 20.9084 73.3137 20.4003L75.9729 23.0931C75.12 23.8891 74.1415 24.5156 73.0377 24.9729C71.9508 25.4302 70.6882 25.6588 69.2499 25.6588ZM79.6466 25.3794V7.44461H83.5851V25.3794H79.6466ZM82.6821 25.3794V21.8737H91.4367V25.3794H82.6821ZM95.2131 25.3794V7.44461H99.1515V25.3794H95.2131ZM104.067 25.3794V7.44461H108.006V25.3794H104.067ZM107.078 25.3794V21.9245H116.786V25.3794H107.078ZM107.078 17.8854V14.5575H115.908V17.8854H107.078ZM107.078 10.874V7.44461H116.66V10.874H107.078ZM121.006 25.3794V7.44461H123.765L124.944 11.0265V25.3794H121.006ZM133.222 25.3794L122.787 11.8394L123.765 7.44461L134.201 20.9846L133.222 25.3794ZM133.222 25.3794L132.169 21.7975V7.44461H136.107V25.3794H133.222ZM145.371 25.3794V7.69862H149.309V25.3794H145.371ZM139.827 10.9249V7.44461H154.853V10.9249H139.827Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

View file

@ -0,0 +1,24 @@
import { twMerge } from 'tailwind-merge';
import HypixelSkyblockHub from '../assets/backgrounds/HypixelSkyblockHub.png';
const GameBackgrounds = {
HypixelSkyblockHub,
};
type GameBackgroundName = keyof typeof GameBackgrounds;
interface GameBackgroundProps {
name: GameBackgroundName;
className?: string;
}
export function GameBackground({ name, className = '' }: GameBackgroundProps) {
const BackgroundImage = GameBackgrounds[name];
return (
<div
className={twMerge(`absolute -z-50 pointer-events-none inset-0 bg-cover bg-center`, className)}
style={{ backgroundImage: `url(${BackgroundImage})` }}
/>
);
}

View file

@ -1,27 +0,0 @@
import type { Context } from 'react';
import { createContext, useContext } from 'react';
const myContext = createContext(null) as Context<
{
text: string;
} | null
>;
export function MyContextProvider({ children, value }: {
children: React.ReactNode;
value: {
text: string;
} | null;
}) {
// eslint-disable-next-line react/no-context-provider -- ok
return <myContext.Provider value={value}>{children}</myContext.Provider>;
}
export default function useMyContext() {
const context = useContext(myContext);
if (!context)
throw new Error('useMyContext must be used within a MyContextProvider');
return context;
}

View file

@ -0,0 +1,98 @@
import type { ButtonProps } from '@onelauncher/common/components';
import type { LinkProps } from '@tanstack/react-router';
import LauncherLogo from '@/assets/logos/oneclient.svg?react';
import { Button } from '@onelauncher/common/components';
import { Link } from '@tanstack/react-router';
import { Window } from '@tauri-apps/api/window';
import { MinusIcon, SquareIcon, XCloseIcon } from '@untitled-theme/icons-react';
import { twMerge } from 'tailwind-merge';
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" data-tauri-drag-region="true">
<div className="flex flex-1 pointer-events-none">
<LauncherLogo height={47} width={230} />
</div>
<div className="flex flex-1 items-center justify-center pointer-events-none gap-6">
<NavbarLink to="/app">Home</NavbarLink>
<NavbarLink to="/app/test">Clusters</NavbarLink>
<NavbarLink to="/">Accounts</NavbarLink>
</div>
<div className="flex flex-1 items-center justify-end gap-2">
<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>
);
}
function NavbarLink({
to,
children,
}: LinkProps) {
return (
<div className="flex-1 flex justify-center items-center">
<Link
activeOptions={{
exact: true,
}}
activeProps={{
className: 'text-fg-primary font-semibold partial-underline-75% pointer-events-none',
}}
className="text-center text-2lg transition-all duration-100 after:duration-100 after:transition-all"
inactiveProps={{
className: 'text-fg-secondary font-normal partial-underline-0% hover:partial-underline-50% hover:font-medium hover:text-fg-secondary-hover after:text-fg-secondary-hover pointer-events-auto',
}}
to={to}
>
{children}
</Link>
</div>
);
}
function NavbarButton({
children,
color = 'ghost',
size = 'iconLarge',
onClick,
className = '',
...rest
}: ButtonProps) {
return (
<Button
className={twMerge('flex items-center justify-center w-12 h-12 pointer-events-auto', className)}
color={color}
onClick={onClick}
size={size}
{...rest}
>
{children}
</Button>
);
}

View file

@ -0,0 +1,2 @@
export * from './GameBackground';
export * from './Navbar';

View file

@ -1,20 +1,42 @@
import type { QueryClient } from '@tanstack/react-query';
import { createRootRouteWithContext, Outlet } from '@tanstack/react-router';
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';
import { RouterProvider } from 'react-aria-components';
interface MyRouterContext {
queryClient: QueryClient;
}
declare module 'react-aria-components' {
interface RouterConfig {
href: ToOptions['to'];
routerOptions: Omit<NavigateOptions, keyof ToOptions>;
}
}
export const Route = createRootRouteWithContext<MyRouterContext>()({
component: RootLayout,
component: RootRoute,
});
function RootLayout() {
function RootRoute() {
const router = useRouter();
return (
<>
<Outlet />
<TanStackRouterDevtools />
</>
<AnimatedOutletProvider>
<RouterProvider
navigate={(to, options) => router.navigate({ to, ...options })}
useHref={to => router.buildLocation({ to }).href}
>
<div className="h-screen flex flex-col overflow-hidden text-fg-primary px-12">
<Navbar />
<Outlet />
<TanStackRouterDevtools />
</div>
</RouterProvider>
</AnimatedOutletProvider>
);
}

View file

@ -0,0 +1,21 @@
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/app/')({
component: RouteComponent,
});
function RouteComponent() {
return (
<div className="flex h-full w-full flex-col justify-center">
<div className="flex flex-1 flex-col justify-center">
<h1 className="text-5xl font-semibold text-fg-primary">1.8.9</h1>
</div>
<div className="flex flex-row h-56">
<div className="flex-1 rounded-xl border border-solid border-component-border bg-page-overlay">
</div>
</div>
</div>
);
}

View file

@ -0,0 +1,63 @@
import { GameBackground } from '@/components/GameBackground';
import { AnimatedOutlet } from '@onelauncher/common/components';
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/app')({
component: RouteComponent,
});
function RouteComponent() {
return (
<div className="h-full w-full">
<Background />
<div className="h-full w-full">
<AnimatedOutlet
enter={{
initial: { opacity: 0, transform: 'translateX(-20%)' },
animate: { opacity: 1, transform: 'translateX(0)' },
}}
exit={{
initial: { opacity: 1, transform: 'translateX(0)' },
animate: { opacity: 0, transform: 'translateX(-20%)' },
}}
from={Route.id}
transition={{ duration: 0.3, bounce: 0.1, power: 0.2, type: 'spring' }}
/>
</div>
</div>
);
}
function Background() {
return (
<div>
{/* Linear 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 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 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>
<GameBackground name="HypixelSkyblockHub" />
</div>
);
}

View file

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

View file

@ -1,55 +1,9 @@
import type { LauncherError } from '@/bindings.gen';
import { bindings } from '@/main';
import { Button } from '@onelauncher/common/components';
import { createFileRoute } from '@tanstack/react-router';
import { createFileRoute, Navigate } from '@tanstack/react-router';
export const Route = createFileRoute('/')({
component: App,
component: RouteComponent,
});
function App() {
const onClick = async () => {
// const result = await bindings.core.createCluster({
// name: 'Test 1.8.9 Forge',
// mc_loader: 'forge',
// mc_version: '1.8.9',
// icon: null,
// mc_loader_version: '11.15.1.2318',
// });
try {
// await bindings.core.launchCluster(9 as unknown as bigint, null);
await bindings.core.removeCluster(9 as unknown as bigint);
const unlisten = await bindings.events.process.on((e) => {
if (e.type === 'Output') { console.log(e.output); }
else if (e.type === 'Stopped') {
console.log(e.exit_code);
unlisten();
}
});
}
catch (err: unknown) {
let error = err as LauncherError;
// console.log(error);
// if (error.type === 'DaoError')
// if (error.data.type === 'NotFound')
// console.log(error.data.data);
if (error.type === 'TauriError')
console.error(error.data);
else if (error.type === 'IOError')
console.error(error.data.data);
else if (error.type === 'DaoError')
console.error(error.data);
console.log(error);
}
};
return (
<div className="text-center">
<h1>test</h1>
<Button onClick={onClick}>Click Me!</Button>
</div>
);
function RouteComponent() {
return <Navigate to="/app" />;
}

View file

@ -1,21 +0,0 @@
import useMyContext from '@/components/MyContext';
import { createFileRoute } from '@tanstack/react-router';
export const Route = createFileRoute('/test/app')({
component: RouteComponent,
});
function RouteComponent() {
const myContext = useMyContext();
return (
<div>
<div>Hello "/test/app"!</div>
<div>
Value from MyContext:
{' '}
{myContext.text}
</div>
</div>
);
}

View file

@ -1,15 +0,0 @@
import { MyContextProvider } from '@/components/MyContext';
import { createFileRoute, Outlet } from '@tanstack/react-router';
export const Route = createFileRoute('/test')({
component: RouteComponent,
});
function RouteComponent() {
return (
<MyContextProvider value={{ text: 'Hello from cool!' }}>
<div>Hello "/test"!</div>
<Outlet />
</MyContextProvider>
);
}

View file

@ -0,0 +1,18 @@
import type { ClusterModel } from '@/bindings.gen';
import type { FileRoutesByFullPath } from '@/routeTree.gen';
import { create } from 'zustand';
interface AppFrameStore {
previousPage: FileRoutesByFullPath | null;
activeCluster: ClusterModel | null;
}
const useAppFrameStore = create<AppFrameStore>()(set => ({
activeCluster: null,
previousPage: null,
setPreviousPage: (page: FileRoutesByFullPath) => set({ previousPage: page }),
setActiveCluster: (cluster: ClusterModel | null) => set({ activeCluster: cluster }),
}));
export default useAppFrameStore;

View file

@ -1,15 +0,0 @@
@import "tailwindcss";
body {
@apply m-0;
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen",
"Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue",
sans-serif;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
code {
font-family: source-code-pro, Menlo, Monaco, Consolas, "Courier New",
monospace;
}

View file

@ -1,108 +1,20 @@
@import "tailwindcss";
@plugin "tailwindcss-react-aria-components";
@plugin "tailwindcss-animated";
@source "../../node_modules/@onelauncher/common";
@import "../../node_modules/@onelauncher/common/dist/theme.css";
@theme {
/* foreground colors */
--color-fg-primary: #d5dbff;
--color-fg-primary-hover: #dae0ff;
--color-fg-primary-pressed: #e1e5ff;
--color-fg-primary-disabled: #cdd1eb;
@utility partial-underline-* {
position: relative;
--color-fg-secondary: #78818d;
--color-fg-secondary-hover: #5f6874;
--color-fg-secondary-pressed: #828d9b;
--color-fg-secondary-disabled: #646d79;
--color-link: #61afef;
--color-link-hover: #5f87ff;
--color-link-pressed: #72afff;
--color-link-disabled: #7597b3;
/* background colors */
--color-brand: #2b4bff;
--color-brand-hover: #2843dd;
--color-brand-pressed: #3957ff;
--color-brand-disabled: #2543eb;
--color-component-bg: #1a2228;
--color-component-bg-hover: #1d242b;
--color-component-bg-pressed: #222c35;
--color-component-bg-disabled: #10181f;
--color-page: #11171c;
--color-page-elevated: #151c22;
--color-window-frame: #151b20;
/* general colors */
--color-danger: #ff4444;
--color-danger-hover: #d63434;
--color-danger-pressed: #ff5656;
--color-danger-disabled: #eb3030;
--color-success: #239a60;
--color-success-hover: #1a8752;
--color-success-pressed: #2cac6e;
--color-success-disabled: #0f864c;
--color-code-info: #61afef;
--color-code-warn: #e5c07b;
--color-code-error: #be5046;
--color-code-debug: #2b4bff;
--color-code-trace: #fdfdfd;
/* 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 */
--color-ghost-overlay: rgba(255, 255, 255, 0.05);
--color-ghost-overlay-hover: rgba(255, 255, 255, 0.10);
--color-scrollbar-bg: rgba(255, 255, 255, 0.05);
--color-scrollbar-bg-hover: rgba(255, 255, 255, 0.10);
--color-scrollbar-bg-pressed: rgba(255, 255, 255, 0.15);
/* other */
--font-sans: "Poppins", sans-serif;
--text-xs: 0.688rem;
--text-sm: 0.75rem;
--text-base: 0.875rem;
--text-lg: 1rem;
--text-2lg: 1.125rem;
--text-xl: 1.25rem;
--text-xxl: 1.5rem;
--text-2xl: 2rem;
--text-3xl: 2.5rem;
--text-4xl: 3rem;
}
* {
user-select: none !important;
-webkit-user-select: none !important;
}
body {
@apply bg-page text-fg-primary text-base;
}
.os-scrollbar {
--os-size: 10px;
--os-track-border-radius: var(--border-radius-lg);
--os-handle-bg: var(--color-scrollbar-bg);
--os-handle-bg-hover: var(--color-scrollbar-bg-hover);
--os-handle-bg-active: var(--color-scrollbar-bg-pressed);
--os-handle-perpendicular-size-hover: 140%;
--os-handle-perpendicular-size-active: 140%;
--os-handle-interactive-area-offset: 4px;
}
.os-scrollbar-offset-right {
--os-padding-axis: 10;
}
.os-hide-horizontal-scrollbar > .os-scrollbar-horizontal {
display: none;
&::after {
content: "";
background: none repeat scroll 0 0 currentColor;
bottom: 1px;
display: block;
height: 3px;
position: absolute;
width: --spacing(--value(integer));
width: --value(percentage, [percentage]);
border-radius: 10px;
}
}

View file

@ -0,0 +1,2 @@
/// <reference types="vite-plugin-svgr/client" />
/// <reference types="vite/client" />

View file

@ -1,14 +1,16 @@
import { resolve } from 'node:path';
import process from 'node:process';
import tailwindcss from '@tailwindcss/vite';
import { TanStackRouterVite } from '@tanstack/router-plugin/vite';
import viteReact from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import svgr from 'vite-plugin-svgr';
export default defineConfig({
plugins: [
svgr(),
TanStackRouterVite({ autoCodeSplitting: true }),
viteReact(),
tailwindcss(),

View file

@ -4,4 +4,4 @@ dist
dist-ssr
*.local
*.gen.ts
**/*.gen.ts

View file

@ -1,108 +1,4 @@
@import "tailwindcss";
@plugin "tailwindcss-react-aria-components";
@plugin "tailwindcss-animated";
@source "../../node_modules/@onelauncher/common";
@theme {
/* foreground colors */
--color-fg-primary: #d5dbff;
--color-fg-primary-hover: #dae0ff;
--color-fg-primary-pressed: #e1e5ff;
--color-fg-primary-disabled: #cdd1eb;
--color-fg-secondary: #78818d;
--color-fg-secondary-hover: #5f6874;
--color-fg-secondary-pressed: #828d9b;
--color-fg-secondary-disabled: #646d79;
--color-link: #61afef;
--color-link-hover: #5f87ff;
--color-link-pressed: #72afff;
--color-link-disabled: #7597b3;
/* background colors */
--color-brand: #2b4bff;
--color-brand-hover: #2843dd;
--color-brand-pressed: #3957ff;
--color-brand-disabled: #2543eb;
--color-component-bg: #1a2228;
--color-component-bg-hover: #1d242b;
--color-component-bg-pressed: #222c35;
--color-component-bg-disabled: #10181f;
--color-page: #11171c;
--color-page-elevated: #151c22;
--color-window-frame: #151b20;
/* general colors */
--color-danger: #ff4444;
--color-danger-hover: #d63434;
--color-danger-pressed: #ff5656;
--color-danger-disabled: #eb3030;
--color-success: #239a60;
--color-success-hover: #1a8752;
--color-success-pressed: #2cac6e;
--color-success-disabled: #0f864c;
--color-code-info: #61afef;
--color-code-warn: #e5c07b;
--color-code-error: #be5046;
--color-code-debug: #2b4bff;
--color-code-trace: #fdfdfd;
/* 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 */
--color-ghost-overlay: rgba(255, 255, 255, 0.05);
--color-ghost-overlay-hover: rgba(255, 255, 255, 0.10);
--color-scrollbar-bg: rgba(255, 255, 255, 0.05);
--color-scrollbar-bg-hover: rgba(255, 255, 255, 0.10);
--color-scrollbar-bg-pressed: rgba(255, 255, 255, 0.15);
/* other */
--font-sans: "Poppins", sans-serif;
--text-xs: 0.688rem;
--text-sm: 0.75rem;
--text-base: 0.875rem;
--text-lg: 1rem;
--text-2lg: 1.125rem;
--text-xl: 1.25rem;
--text-xxl: 1.5rem;
--text-2xl: 2rem;
--text-3xl: 2.5rem;
--text-4xl: 3rem;
}
* {
user-select: none !important;
-webkit-user-select: none !important;
}
body {
@apply bg-page text-fg-primary text-base;
}
.os-scrollbar {
--os-size: 10px;
--os-track-border-radius: var(--border-radius-lg);
--os-handle-bg: var(--color-scrollbar-bg);
--os-handle-bg-hover: var(--color-scrollbar-bg-hover);
--os-handle-bg-active: var(--color-scrollbar-bg-pressed);
--os-handle-perpendicular-size-hover: 140%;
--os-handle-perpendicular-size-active: 140%;
--os-handle-interactive-area-offset: 4px;
}
.os-scrollbar-offset-right {
--os-padding-axis: 10;
}
.os-hide-horizontal-scrollbar > .os-scrollbar-horizontal {
display: none;
}
@import "../../node_modules/@onelauncher/common/dist/theme.css";

View file

@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "cluster_groups")]
#[serde(rename = "ClusterGroupModel")]
#[onelauncher_macro::specta]
pub struct Model {
#[sea_orm(primary_key)]

View file

@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "cluster_packages")]
#[serde(rename = "ClusterPackageModel")]
#[onelauncher_macro::specta]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]

View file

@ -5,6 +5,7 @@ use crate::{cluster_stage::ClusterStage, icon::Icon, loader::GameLoader};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "clusters")]
#[serde(rename = "ClusterModel")]
#[onelauncher_macro::specta]
pub struct Model {
#[sea_orm(primary_key)]

View file

@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "java_versions")]
#[serde(rename = "JavaVersionModel")]
#[onelauncher_macro::specta]
pub struct Model {
#[sea_orm(primary_key)]

View file

@ -7,6 +7,7 @@ use crate::{icon::Icon, loader::GameLoader, package::{PackageType, Provider}, ut
#[derive(Clone, Debug, PartialEq, DeriveEntityModel, Eq, Serialize, Deserialize)]
#[sea_orm(table_name = "packages")]
#[serde(rename = "PackageModel")]
#[onelauncher_macro::specta]
pub struct Model {
#[sea_orm(primary_key, auto_increment = false)]

View file

@ -6,18 +6,20 @@
"authors": "Polyfrost",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./lib/index.js"
"types": "./dist/index.d.ts",
"import": "./dist/index.js"
},
"./components": {
"types": "./lib/components.d.ts",
"import": "./lib/components.js"
"types": "./dist/components.d.ts",
"import": "./dist/components.js"
}
},
"main": "./lib/index.js",
"typings": "./lib/index.d.ts",
"main": "./dist/index.js",
"typings": "./dist/src/index.d.ts",
"style": "./dist/theme.css",
"scripts": {
"build": "rollup -c"
"dev": "vite",
"build": "vite build"
},
"peerDependencies": {
"@tanstack/react-query": "^5.66.5",
@ -32,11 +34,12 @@
"tailwindcss-react-aria-components": "^2.0.0"
},
"devDependencies": {
"@tailwindcss/vite": "^4.0.6",
"@types/react": "^19.0.8",
"esbuild": "^0.25.5",
"rollup": "^4.41.1",
"rollup-plugin-dts": "^6.2.1",
"rollup-plugin-esbuild": "^6.2.1",
"typescript": "^5.8.3"
"@vitejs/plugin-react": "^4.3.4",
"typescript": "^5.8.3",
"vite": "^6.1.0",
"vite-plugin-dts": "^4.5.4",
"vite-plugin-static-copy": "^3.0.0"
}
}

View file

@ -1,82 +0,0 @@
import process from 'node:process';
import dts from 'rollup-plugin-dts';
import esbuild from 'rollup-plugin-esbuild';
/**
* @param {string} id
* @returns {boolean} true if the id is an external module
*/
const isExternal
= process.platform === 'win32'
? (/** @type {string} */ id) => !/^(?:[a-z]:\\|[.\\])/i.test(id)
: (/** @type {string} */ id) => !/^[./]/.test(id);
/**
* @param {string} input
* @param {import('rollup').RollupOptions} config
* @returns {import('rollup').RollupOptions} bundle options
*/
function bundle(input, config) {
return {
...config,
input,
external: isExternal,
};
}
export default [
// Output for NodeJS
bundle('./src/index.ts', {
plugins: [esbuild({ target: 'es2020' })],
output: {
file: `./lib/index.js`,
format: 'esm',
sourcemap: false,
compact: false,
},
}),
// Output for Typescript's .d.ts
bundle('./src/index.ts', {
plugins: [dts()],
output: {
file: `./lib/index.d.ts`,
format: 'esm',
},
}),
// Output for React components
bundle('./src/components/index.ts', {
plugins: [esbuild({ target: 'es2020' })],
output: {
file: `./lib/components.js`,
format: 'esm',
sourcemap: false,
compact: false,
},
jsx: 'react-jsx',
}),
// Output for React components .d.ts
bundle('./src/components/index.ts', {
plugins: [dts()],
output: {
file: `./lib/components.d.ts`,
format: 'esm',
},
jsx: 'react-jsx',
}),
// Output for browser
// bundle({
// plugins: [esbuild({ target: 'es2020', minify: true })],
// output: {
// file: `./dist/${name}-v${version}.js`,
// format: 'esm',
// name: camelCaseName,
// sourcemap: true,
// compact: true,
// },
// jsx: 'react-jsx',
// }),
];

View file

@ -24,7 +24,7 @@ export const buttonVariants = tv({
'bg-danger hover:bg-danger-hover pressed:bg-danger-pressed disabled:bg-danger-disabled',
],
ghost: [
'hover:bg-component-bg-hover pressed:bg-component-bg-pressed checked:selected:bg-component-bg-hover',
'hover:bg-ghost-overlay-hover pressed:bg-ghost-overlay-pressed checked:selected:bg-ghost-overlay-pressed',
],
},
size: {

View file

@ -0,0 +1,110 @@
@source "./**/*.{js,jsx,ts,tsx}";
@plugin "tailwindcss-react-aria-components";
@plugin "tailwindcss-animated";
@theme {
/* foreground colors */
--color-fg-primary: #d5dbff;
--color-fg-primary-hover: #dae0ff;
--color-fg-primary-pressed: #e1e5ff;
--color-fg-primary-disabled: #cdd1eb;
--color-fg-secondary: #78818d;
--color-fg-secondary-hover: #5f6874;
--color-fg-secondary-pressed: #828d9b;
--color-fg-secondary-disabled: #646d79;
--color-link: #61afef;
--color-link-hover: #5f87ff;
--color-link-pressed: #72afff;
--color-link-disabled: #7597b3;
/* background colors */
--color-brand: #2b4bff;
--color-brand-hover: #2843dd;
--color-brand-pressed: #3957ff;
--color-brand-disabled: #2543eb;
--color-component-bg: #1a2228;
--color-component-bg-hover: #1d242b;
--color-component-bg-pressed: #222c35;
--color-component-bg-disabled: #10181f;
--color-page: #11171c;
--color-page-elevated: #151c22;
--color-page-overlay: #ffffff1a;
--color-window-frame: #151b20;
/* general colors */
--color-danger: #ff4444;
--color-danger-hover: #d63434;
--color-danger-pressed: #ff5656;
--color-danger-disabled: #eb3030;
--color-success: #239a60;
--color-success-hover: #1a8752;
--color-success-pressed: #2cac6e;
--color-success-disabled: #0f864c;
--color-code-info: #61afef;
--color-code-warn: #e5c07b;
--color-code-error: #be5046;
--color-code-debug: #2b4bff;
--color-code-trace: #fdfdfd;
/* 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 */
--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);
--color-scrollbar-bg: rgba(255, 255, 255, 0.05);
--color-scrollbar-bg-hover: rgba(255, 255, 255, 0.10);
--color-scrollbar-bg-pressed: rgba(255, 255, 255, 0.15);
/* other */
--font-sans: "Poppins", sans-serif;
--text-xs: 0.688rem;
--text-sm: 0.75rem;
--text-base: 0.875rem;
--text-lg: 1rem;
--text-2lg: 1.125rem;
--text-xl: 1.25rem;
--text-xxl: 1.5rem;
--text-2xl: 2rem;
--text-3xl: 2.5rem;
--text-4xl: 3rem;
}
* {
user-select: none !important;
-webkit-user-select: none !important;
cursor: default !important;
}
body {
@apply bg-page text-fg-primary text-base;
}
.os-scrollbar {
--os-size: 10px;
--os-track-border-radius: var(--border-radius-lg);
--os-handle-bg: var(--color-scrollbar-bg);
--os-handle-bg-hover: var(--color-scrollbar-bg-hover);
--os-handle-bg-active: var(--color-scrollbar-bg-pressed);
--os-handle-perpendicular-size-hover: 140%;
--os-handle-perpendicular-size-active: 140%;
--os-handle-interactive-area-offset: 4px;
}
.os-scrollbar-offset-right {
--os-padding-axis: 10;
}
.os-hide-horizontal-scrollbar > .os-scrollbar-horizontal {
display: none;
}

View file

@ -11,5 +11,5 @@
"esModuleInterop": true,
"forceConsistentCasingInFileNames": true
},
"include": ["src/**/*", "rollup.config.mjs"]
"include": ["src/**/*", "vite.config.ts"]
}

View file

@ -0,0 +1,60 @@
import path from 'node:path';
import tailwindcss from '@tailwindcss/vite';
import react from '@vitejs/plugin-react';
import { defineConfig } from 'vite';
import dts from 'vite-plugin-dts';
import { viteStaticCopy } from 'vite-plugin-static-copy';
export default defineConfig({
plugins: [
react(),
tailwindcss(),
viteStaticCopy({
targets: [
{
src: path.resolve(__dirname, 'src/theme.css'),
dest: './',
},
],
}),
dts({
insertTypesEntry: true,
}),
],
build: {
minify: false,
lib: {
entry: {
'index': path.resolve(__dirname, 'src/index.ts'),
'components': path.resolve(__dirname, 'src/components/index.ts'),
},
formats: ['es'],
fileName: (_, entryName) => `${entryName}.js`,
},
rollupOptions: {
external: [
'react',
'react/jsx-runtime',
'react-dom',
'react-aria-components',
'motion',
'motion/react',
'@tanstack/react-query',
'@tanstack/react-router',
'tailwindcss',
'tailwind-merge',
'tailwind-variants',
// 'tailwindcss-animated',
// 'tailwindcss-react-aria-components',
],
output: {
globals: {
'react': 'React',
'react/jsx-runtime': 'react/jsx-runtime',
'react-dom': 'ReactDOM',
'tailwindcss': 'tailwindcss',
},
},
},
},
});

1175
pnpm-lock.yaml generated

File diff suppressed because it is too large Load diff