refactor: begin migration to reactjs

This commit is contained in:
LynithDev 2025-05-11 20:34:30 +02:00
parent 303ac31756
commit df26bdb95e
192 changed files with 4177 additions and 2149 deletions

View file

@ -4,7 +4,8 @@
},
"files.readonlyInclude": {
"**/node_modules/**": true,
"**/routeTree.gen.ts": true
"**/routeTree.gen.ts": true,
"**/bindings.gen.ts": true
},
"files.watcherExclude": {
"**/_build": true,
@ -46,6 +47,7 @@
"source.organizeImports": "never"
},
"eslint.runtime": "node",
// Silent the stylistic rules in you IDE, but still auto fix them
"eslint.rules.customizations": [
{ "rule": "style/*", "severity": "off", "fixable": true },
@ -86,6 +88,9 @@
"flags": ["unstable_ts_config"]
},
// Tailwind CSS intellisense
"tailwindCSS.classFunctions": ["tv"],
// updated 2024-08-26 15:46
// https://github.com/antfu/vscode-file-nesting-config
"explorer.fileNesting.enabled": true,

View file

@ -1,142 +1,22 @@
// use interpulse::api::minecraft::Version;
// use tauri::{AppHandle, Manager};
pub mod cluster;
pub mod users;
pub mod processor;
pub mod package;
pub mod other;
mod cluster;
// pub use crate::api::commands::cluster::*;
mod users;
// pub use crate::api::commands::users::*;
mod processor;
// pub use crate::api::commands::processor::*;
mod package;
// pub use crate::api::commands::package::*;
#[macro_export]
#[macro_export(local_inner_macros)]
macro_rules! collect_commands {
() => {{
// use $crate::api::commands::*;
// use $crate::ext::updater::*;
use $crate::api::commands::*;
tauri_specta::collect_commands![
// User
// auth_login,
// get_users,
// get_user,
// get_default_user,
// set_default_user,
// remove_user,
// Cluster
// create_cluster,
// edit_game_settings,
// edit_cluster_meta,
// remove_cluster,
// get_cluster,
// get_clusters,
// get_clusters_grouped,
// run_cluster,
// get_cluster_logs,
// get_cluster_log,
// upload_log,
// get_screenshots,
// get_worlds,
// get_optimal_java_version,
// repair_cluster,
// Processor
// get_running_clusters,
// get_processes_by_path,
// kill_process,
// is_cluster_running,
// get_pid_by_uuid,
// get_user_by_process,
// get_process_started_at,
// get_processes_detailed_by_path,
// get_process_detailed_by_id,
// Settings
// get_settings,
// set_settings,
// Metadata
// get_minecraft_versions,
// Launcher Packages (Instances)
// get_launcher_instances,
// import_instances,
// Provider Packages
// get_provider_package,
// get_provider_packages,
// get_all_provider_package_versions,
// get_provider_package_versions,
// search_provider_packages,
// get_provider_authors,
// get_package_body,
// download_provider_package,
// Cluster Packages
// get_cluster_package,
// get_cluster_packages,
// add_cluster_package,
// remove_cluster_package,
// set_cluster_package_enabled,
// sync_cluster_packages,
// sync_cluster_packages_by_type,
// updater
// check_for_update,
// install_update,
// other
// set_window_style,
// get_program_info,
// get_featured_packages,
// get_zulu_packages,
// install_java_from_package,
// open_dev_tools,
users::get_users,
users::get_user,
users::remove_user,
users::get_default_user,
users::set_default_user,
users::begin_ms_flow,
other::open_dev_tools,
]
}};
}
#[onelauncher_core::command]
#[allow(unused_parens)]
pub fn open_dev_tools(webview: &tauri::WebviewWindow) {
#[cfg(feature = "devtools")]
webview.open_devtools();
}
// #[onelauncher_core::command]
// pub async fn get_zulu_packages() -> Result<Vec<onelauncher::java::JavaZuluPackage>, String> {
// Ok(onelauncher::java::get_zulu_packages().await?)
// }
// #[onelauncher_core::command]
// pub async fn install_java_from_package(download: onelauncher::java::JavaZuluPackage) -> Result<std::path::PathBuf, String> {
// Ok(onelauncher::java::install_java_from_package(download).await?)
// }
// #[onelauncher_core::command]
// pub async fn get_featured_packages() -> Result<Vec<onelauncher::package::content::FeaturedPackage>, String> {
// Ok(onelauncher::package::content::get_featured_packages().await?)
// }
// #[onelauncher_core::command]
// pub fn get_program_info() -> Result<super::statics::ProgramInfo, String> {
// Ok(super::statics::get_program_info())
// }
// #[onelauncher_core::command]
// pub async fn get_minecraft_versions() -> Result<Vec<Version>, String> {
// Ok(onelauncher::api::metadata::get_minecraft_versions()
// .await?
// .versions)
// }
// #[onelauncher_core::command]
// pub async fn get_settings() -> Result<Settings, String> {
// Ok(settings::get().await?)
// }
// #[onelauncher_core::command]
// pub async fn set_settings(settings: Settings) -> Result<(), String> {
// Ok(settings::set(settings).await?)
// }
// #[onelauncher_core::command]
// pub fn set_window_style(handle: AppHandle, custom: bool) -> Result<(), String> {
// let window = handle.get_webview_window("main").unwrap();
// onelauncher::utils::window::set_window_styling(&window, custom).map_err(|e| e.to_string())
// }

View file

@ -0,0 +1,6 @@
#[onelauncher_core::command]
#[allow(unused_parens)]
pub fn open_dev_tools(webview: tauri::WebviewWindow) {
#[cfg(feature = "devtools")]
webview.open_devtools();
}

View file

@ -1,119 +1,112 @@
// use onelauncher::data::MinecraftCredentials;
// use onelauncher::minecraft;
// use onelauncher::store::MinecraftLogin;
// use tauri::{AppHandle, Manager};
// use uuid::Uuid;
use onelauncher_core::{api::credentials, error::LauncherResult, store::{credentials::{MinecraftCredentials, MinecraftLogin}, Core}};
use tauri::{AppHandle, Manager};
use uuid::Uuid;
// #[specta::specta]
// #[tauri::command]
// pub async fn get_users() -> Result<Vec<MinecraftCredentials>, String> {
// Ok(minecraft::users().await?)
// }
use crate::api::error::SerializableResult;
// #[specta::specta]
// #[tauri::command]
// pub async fn get_user(uuid: Uuid) -> Result<MinecraftCredentials, String> {
// Ok(minecraft::get_user(uuid).await?)
// }
#[specta::specta]
#[tauri::command]
pub async fn get_users() -> SerializableResult<Vec<MinecraftCredentials>> {
Ok(credentials::users().await?)
}
// #[specta::specta]
// #[tauri::command]
// pub async fn remove_user(uuid: Uuid) -> Result<(), String> {
// Ok(minecraft::remove_user(uuid).await?)
// }
#[specta::specta]
#[tauri::command]
pub async fn get_user(uuid: Uuid) -> SerializableResult<MinecraftCredentials> {
Ok(credentials::get_user(uuid).await?)
}
// #[specta::specta]
// #[tauri::command]
// pub async fn get_default_user(
// fallback: Option<bool>,
// ) -> Result<Option<MinecraftCredentials>, String> {
// let uuid = minecraft::get_default_user().await?;
#[specta::specta]
#[tauri::command]
pub async fn remove_user(uuid: Uuid) -> SerializableResult<()> {
Ok(credentials::remove_user(uuid).await?)
}
// if let Some(fallback) = fallback {
// if fallback && uuid.is_none() {
// return Ok(minecraft::users().await?.first().cloned());
// }
// }
#[specta::specta]
#[tauri::command]
pub async fn get_default_user(
fallback: Option<bool>,
) -> SerializableResult<Option<MinecraftCredentials>> {
let uuid = credentials::get_default_user().await?;
// match uuid {
// Some(uuid) => Ok(Some(minecraft::get_user(uuid).await?)),
// None => Ok(None),
// }
// }
if fallback.is_some_and(|fallback| fallback) && uuid.is_none() {
return Ok(credentials::users().await?.first().cloned());
}
// #[specta::specta]
// #[tauri::command]
// pub async fn set_default_user(uuid: Option<Uuid>) -> Result<(), String> {
// minecraft::set_default_user(uuid).await?;
// Ok(())
// }
match uuid {
Some(uuid) => Ok(Some(credentials::get_user(uuid).await?)),
None => Ok(None),
}
}
// #[specta::specta]
// #[tauri::command]
// pub async fn auth_login(handle: AppHandle) -> Result<Option<MinecraftCredentials>, String> {
// let flow = minecraft::begin().await?;
// let result = spawn_webview(handle, flow).await?;
#[specta::specta]
#[tauri::command]
pub async fn set_default_user(uuid: Option<Uuid>) -> SerializableResult<()> {
credentials::set_default_user(uuid).await?;
Ok(())
}
// Ok(result)
// }
#[specta::specta]
#[tauri::command]
pub async fn begin_ms_flow(handle: tauri::AppHandle) -> SerializableResult<Option<MinecraftCredentials>> {
let flow = credentials::begin().await?;
let result = spawn_webview(handle, flow).await?;
// async fn spawn_webview(
// handle: AppHandle,
// flow: MinecraftLogin,
// ) -> Result<Option<MinecraftCredentials>, String> {
// let now = chrono::Utc::now();
Ok(result)
}
// if let Some(win) = handle.get_webview_window("login") {
// win.close().map_err(|err| err.to_string())?;
// }
async fn spawn_webview(
handle: AppHandle,
flow: MinecraftLogin,
) -> LauncherResult<Option<MinecraftCredentials>> {
let now = chrono::Utc::now();
// let win = tauri::WebviewWindowBuilder::new(
// &handle,
// "login",
// tauri::WebviewUrl::External(
// flow.redirect_uri
// .parse()
// .map_err(|_| anyhow::anyhow!("failed to parse auth redirect url"))
// .map_err(|err| err.to_string())?,
// ),
// )
// .title("Log into OneLauncher")
// .always_on_top(true)
// .center()
// .build()
// .map_err(|err| err.to_string())?;
if let Some(win) = handle.get_webview_window("login") {
win.close()?;
}
// win.request_user_attention(Some(tauri::UserAttentionType::Critical))
// .map_err(|err| err.to_string())?;
let win = tauri::WebviewWindowBuilder::new(
&handle,
"login",
tauri::WebviewUrl::External(
flow.redirect_uri
.parse()
.map_err(|_| anyhow::anyhow!("failed to parse auth redirect url"))?,
),
)
.title(format!("Login to {}", Core::get().launcher_name))
.center()
.focused(true)
.build()?;
// while (chrono::Utc::now() - now) < chrono::Duration::minutes(10) {
// if win.title().is_err() {
// return Ok(None);
// }
win.request_user_attention(Some(tauri::UserAttentionType::Critical))?;
// if win
// .url()
// .map_err(|err| err.to_string())?
// .as_str()
// .starts_with("https://login.live.com/oauth20_desktop.srf")
// {
// if let Some((_, code)) = win
// .url()
// .map_err(|err| err.to_string())?
// .query_pairs()
// .find(|x| x.0 == "code")
// {
// win.close().map_err(|err| err.to_string())?;
// let value = minecraft::finish(&code.clone(), flow).await?;
while (chrono::Utc::now() - now) < chrono::Duration::minutes(10) {
if win.title().is_err() {
return Ok(None);
}
// return Ok(Some(value));
// }
// }
if win
.url()?
.as_str()
.starts_with("https://login.live.com/oauth20_desktop.srf")
{
if let Some((_, code)) = win
.url()?
.query_pairs()
.find(|x| x.0 == "code")
{
win.close()?;
let value = credentials::finish(&code.clone(), flow).await?;
// tokio::time::sleep(std::time::Duration::from_millis(50)).await;
// }
return Ok(Some(value));
}
}
// win.close().map_err(|err| err.to_string())?;
tokio::time::sleep(std::time::Duration::from_millis(50)).await;
}
// Ok(None)
// }
win.close()?;
Ok(None)
}

View file

@ -0,0 +1,61 @@
use onelauncher_core::error::LauncherError;
use serde::{Serialize, Serializer, ser::SerializeStruct};
use specta::Type;
#[derive(thiserror::Error, Debug, Type)]
#[serde(tag = "kind", content = "data")]
pub enum SerializableError {
#[error(transparent)]
CoreError(#[serde(skip)] #[from] onelauncher_core::error::LauncherError),
}
pub type SerializableResult<T> = std::result::Result<T, SerializableError>;
macro_rules! impl_serialize {
($($variant:ident),* $(,)?) => {
impl Serialize for SerializableError {
fn serialize<S>(&self, serializer: S) -> std::result::Result<S::Ok, S::Error>
where
S: Serializer,
{
match self {
SerializableError::CoreError(error) => {
display_tracing_error(error);
let mut state = serializer.serialize_struct("CoreError", 2)?;
state.serialize_field("field_name", "CoreError")?;
state.serialize_field("message", &error.to_string())?;
state.end()
}
$(
SerializableError::$variant(message) => {
let mut state = serializer.serialize_struct(stringify!($variant), 2)?;
state.serialize_field("field_name", stringify!($variant))?;
state.serialize_field("message", &message.to_string())?;
state.end()
},
)*
}
}
}
};
}
impl_serialize! {}
pub fn display_tracing_error(err: &LauncherError) {
match get_span_trace(err) {
Some(span_trace) => {
tracing::error!(error = %err, span_trace = %span_trace);
}
None => {
tracing::error!(error = %err);
}
}
}
pub fn get_span_trace<'a>(
error: &'a (dyn std::error::Error + 'static),
) -> Option<&'a tracing_error::SpanTrace> {
error.source().and_then(tracing_error::ExtractSpanTrace::span_trace)
}

View file

@ -1,3 +1,4 @@
pub mod commands;
pub mod error;
pub mod events;
pub mod statics;

View file

View file

@ -48,7 +48,7 @@ async fn initialize_tauri(builder: tauri::Builder<tauri::Wry>) -> LauncherResult
specta_typescript::Typescript::default()
.bigint(specta_typescript::BigIntExportBehavior::BigInt)
.formatter(ext::specta::formatter),
"../../frontend/src/bindings.ts",
"../frontend/src/bindings.gen.ts",
)
.expect("failed to export debug bindings!");

5
apps/onelauncher/frontend/.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
node_modules
.DS_Store
dist
dist-ssr
*.local

View file

@ -1,15 +1,20 @@
<!doctype html>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<link rel="icon" href="/favicon.ico" />
<meta name="theme-color" content="#000000" />
<link rel="icon" type="image/svg+xml" href="/src/assets/logo.svg" />
<title>OneLauncher</title>
<meta
name="description"
content="Web site created using create-tsrouter-app"
/>
<link rel="apple-touch-icon" href="/logo192.png" />
<link rel="manifest" href="/manifest.json" />
<title>OneClient</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
<div id="app"></div>
<script type="module" src="/src/main.tsx"></script>
</body>
</html>

View file

@ -1,56 +1,49 @@
{
"name": "@onelauncher/frontend",
"type": "module",
"version": "0.1.0-alpha.2",
"private": true,
"description": "Next-generation open source Minecraft launcher frontend",
"license": "GPL-3.0-only",
"repository": {
"type": "git",
"url": "git@github.com:polyfrost/onelauncher",
"directory": "apps/frontend"
},
"bugs": "https://github.com/polyfrost/onelauncher/issues",
"sideEffects": false,
"scripts": {
"dev": "vite",
"build": "vite build",
"typecheck": "tsc --noEmit"
"start": "vite",
"build": "vite build && tsc",
"serve": "vite preview",
"lint": "eslint",
"check": "eslint --fix"
},
"dependencies": {
"@fontsource/poppins": "^5.1.0",
"@formatjs/intl-durationformat": "^0.5.0",
"@leeoniya/ufuzzy": "^1.0.14",
"@onelauncher/client": "workspace:*",
"@solid-primitives/i18n": "^2.1.1",
"@solid-primitives/map": "^0.4.13",
"@solid-primitives/refs": "^1.0.8",
"@solid-primitives/scheduled": "^1.5.0",
"@solidjs/router": "^0.14.7",
"@t3-oss/env-core": "^0.11.0",
"@tanstack/solid-query": "^5.56.2",
"@tauri-apps/api": "^2.0.3",
"@tauri-apps/plugin-clipboard-manager": "^2.0.0",
"@tauri-apps/plugin-dialog": "^2.0.1",
"@tauri-apps/plugin-shell": "^2.0.1",
"@unocss/reset": "^0.63.6",
"@untitled-theme/icons-solid": "^0.11.0",
"overlayscrollbars": "^2.10.0",
"overlayscrollbars-solid": "^0.5.5",
"pathe": "^1.1.2",
"solid-js": "^1.9.1",
"solid-transition-group": "^0.2.3",
"zod": "^3.23.8"
"@fontsource/poppins": "^5.2.6",
"@formatjs/intl-durationformat": "^0.7.4",
"@tailwindcss/vite": "^4.0.6",
"@tanstack/match-sorter-utils": "^8.19.4",
"@tanstack/react-query": "^5.66.5",
"@tanstack/react-query-devtools": "^5.66.5",
"@tanstack/react-router": "^1.114.3",
"@tanstack/react-router-devtools": "^1.114.3",
"@tanstack/react-table": "^8.21.2",
"@tanstack/router-plugin": "^1.114.3",
"@tauri-apps/api": "^2.5.0",
"@tauri-apps/plugin-clipboard-manager": "^2.2.2",
"@tauri-apps/plugin-dialog": "^2.2.1",
"@tauri-apps/plugin-shell": "^2.2.1",
"@untitled-theme/icons-react": "^0.14.0",
"motion": "^12.10.5",
"overlayscrollbars": "^2.11.2",
"overlayscrollbars-react": "^0.5.6",
"react": "^19.0.0",
"react-aria-components": "^1.8.0",
"react-dom": "^19.0.0",
"tailwind-merge": "^3.2.0",
"tailwind-variants": "^1.0.0",
"tailwindcss": "^4.0.6",
"tailwindcss-animated": "^2.0.0",
"tailwindcss-react-aria-components": "^2.0.0"
},
"devDependencies": {
"@sentry/vite-plugin": "^2.22.4",
"@tauri-apps/cli": "^2.0.4",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.79.4",
"unocss": "^0.63.6",
"vite": "^5.4.8",
"vite-plugin-solid": "^2.10.2",
"vite-plugin-solid-svg": "^0.8.1",
"vite-tsconfig-paths": "^5.0.1"
"@tanstack/eslint-config": "^0.1.0",
"@types/react": "^19.0.8",
"@types/react-dom": "^19.0.3",
"@vitejs/plugin-react": "^4.3.4",
"typescript": "^5.7.2",
"vite": "^6.1.0"
}
}

View file

Before

Width:  |  Height:  |  Size: 340 KiB

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.3 KiB

View file

@ -0,0 +1,175 @@
// This file was generated by [tauri-specta](https://github.com/oscartbeaumont/tauri-specta). Do not edit this file manually.
/** user-defined commands */
/** tauri-specta globals */
import type { WebviewWindow as __WebviewWindow__ } from '@tauri-apps/api/webviewWindow';
import {
invoke as TAURI_INVOKE,
} from '@tauri-apps/api/core';
import * as TAURI_API_EVENT from '@tauri-apps/api/event';
export const commands = {
async getUsers(): Promise<Result<Array<MinecraftCredentials>, SerializableError>> {
try {
return { status: 'ok', data: await TAURI_INVOKE('get_users') };
}
catch (e) {
if (e instanceof Error)
throw e;
else return { status: 'error', error: e as any };
}
},
async getUser(uuid: string): Promise<Result<MinecraftCredentials, SerializableError>> {
try {
return { status: 'ok', data: await TAURI_INVOKE('get_user', { uuid }) };
}
catch (e) {
if (e instanceof Error)
throw e;
else return { status: 'error', error: e as any };
}
},
async removeUser(uuid: string): Promise<Result<null, SerializableError>> {
try {
return { status: 'ok', data: await TAURI_INVOKE('remove_user', { uuid }) };
}
catch (e) {
if (e instanceof Error)
throw e;
else return { status: 'error', error: e as any };
}
},
async getDefaultUser(fallback: boolean | null): Promise<Result<MinecraftCredentials | null, SerializableError>> {
try {
return { status: 'ok', data: await TAURI_INVOKE('get_default_user', { fallback }) };
}
catch (e) {
if (e instanceof Error)
throw e;
else return { status: 'error', error: e as any };
}
},
async setDefaultUser(uuid: string | null): Promise<Result<null, SerializableError>> {
try {
return { status: 'ok', data: await TAURI_INVOKE('set_default_user', { uuid }) };
}
catch (e) {
if (e instanceof Error)
throw e;
else return { status: 'error', error: e as any };
}
},
async beginMsFlow(): Promise<Result<MinecraftCredentials | null, SerializableError>> {
try {
return { status: 'ok', data: await TAURI_INVOKE('begin_ms_flow') };
}
catch (e) {
if (e instanceof Error)
throw e;
else return { status: 'error', error: e as any };
}
},
async openDevTools(): Promise<void> {
await TAURI_INVOKE('open_dev_tools');
},
};
/** user-defined events */
export const events = __makeEvents__<{
launcherEvent: LauncherEvent;
}>({
launcherEvent: 'launcher-event',
});
/** user-defined constants */
/** user-defined types */
export interface IngressPayload { id: string; message: string; ingress_type: IngressType; percent: number | null; total: number }
export type IngressType = { Download: { file_name: string } } | 'JavaPrepare' | 'JavaCheck' | 'JavaLocate' | 'MinecraftDownload' | { PrepareCluster: { cluster_name: string } };
export type LauncherEvent = { Ingress: IngressPayload } | { Message: MessagePayload } | { Process: ProcessPayload };
export type MessageLevel = 'Info' | 'Warn' | 'Error';
export interface MessagePayload { level: MessageLevel; message: string }
/**
* A structure of all needed Minecraft credentials for logging in and account management.
*/
export interface MinecraftCredentials {
/**
* The uuid of the credentials.
*/
id: string;
/**
* The username of the Minecraft account.
*/
username: string;
/**
* The access token as a String.
*/
access_token: string;
/**
* The refresh token as a string for [`MinecraftState#refresh`].
*/
refresh_token: string;
/**
* The time that the access token expires as a [`DateTime<Utc>`].
*/
expires: string;
}
export interface Process { pid: number; started_at: string; cluster_id: bigint; post_hook: string | null; account_id: string }
export type ProcessPayload = { Starting: { command: string } } | { Started: { process: Process } } | { Stopped: { pid: number; exit_code: number } } | { Output: { pid: number; output: string } };
export interface SerializableError { kind: 'CoreError' }
interface __EventObj__<T> {
listen: (
cb: TAURI_API_EVENT.EventCallback<T>,
) => ReturnType<typeof TAURI_API_EVENT.listen<T>>;
once: (
cb: TAURI_API_EVENT.EventCallback<T>,
) => ReturnType<typeof TAURI_API_EVENT.once<T>>;
emit: null extends T
? (payload?: T) => ReturnType<typeof TAURI_API_EVENT.emit>
: (payload: T) => ReturnType<typeof TAURI_API_EVENT.emit>;
}
export type Result<T, E> =
| { status: 'ok'; data: T }
| { status: 'error'; error: E };
function __makeEvents__<T extends Record<string, any>>(
mappings: Record<keyof T, string>,
) {
return new Proxy(
{} as unknown as {
[K in keyof T]: __EventObj__<T[K]> & {
(handle: __WebviewWindow__): __EventObj__<T[K]>;
};
},
{
get: (_, event) => {
const name = mappings[event as keyof T];
return new Proxy((() => {}) as any, {
apply: (_, __, [window]: [__WebviewWindow__]) => ({
listen: (arg: any) => window.listen(name, arg),
once: (arg: any) => window.once(name, arg),
emit: (arg: any) => window.emit(name, arg),
}),
get: (_, command: keyof __EventObj__<any>) => {
switch (command) {
case 'listen':
return (arg: any) => TAURI_API_EVENT.listen(name, arg);
case 'once':
return (arg: any) => TAURI_API_EVENT.once(name, arg);
case 'emit':
return (arg: any) => TAURI_API_EVENT.emit(name, arg);
}
},
});
},
},
);
}

View file

@ -0,0 +1,168 @@
/* eslint-disable eslint-comments/require-description -- i trust that one github discussion user on this */
/* eslint-disable react/no-unstable-default-props */
// Taken from https://github.com/TanStack/router/discussions/823#discussioncomment-12765059
// Thank you https://github.com/danielytics
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 { createContext, useContext, useEffect, useRef, useState } from 'react';
interface TransitionProps {
initial?: MotionProps['initial'];
animate?: MotionProps['animate'];
}
interface AnimatedOutletProps {
enter: TransitionProps;
exit: TransitionProps;
transition?: MotionProps['transition'];
from: AnyRoute['id'];
clone?: boolean;
}
interface AnimatedOutletWrapperProps {
children: React.ReactNode;
}
type TakeSnapshotFn = () => void;
type Registry = Map<string, TakeSnapshotFn>;
const AnimatedOutletContext = createContext<Registry>(new Map());
function isDescendant(pathname: string, destinationPath: string) {
return pathname === '/'
|| (destinationPath.startsWith(pathname)
&& (destinationPath.length === pathname.length
|| destinationPath.charAt(pathname.length) === '/'));
}
export function AnimatedOutletProvider({ children }: AnimatedOutletWrapperProps) {
const router = useRouter();
const registry = useRef<Registry>(new Map());
useEffect(() => {
// NOTE: This should be onBeforeNavigate, but due to https://github.com/TanStack/router/issues/3920 it's not working.
// For now, we use onBeforeLoad, which runs right after onBeforeNavigate.
// See: https://github.com/TanStack/router/blob/f8015e7629307499d4d6245077ad84145b6064a7/packages/router-core/src/router.ts#L2027
const unsubscribe = router.subscribe('onBeforeLoad', ({ toLocation, pathChanged }) => {
if (pathChanged) {
const destinationPath = toLocation.pathname;
// Find the outlet with the longest pathname, that is part of the destination route
let takeSnapshot: TakeSnapshotFn | null = null;
let longestLength = 0;
for (const [pathname, snapshotFn] of registry.current.entries())
if (isDescendant(pathname, destinationPath) && pathname.length > longestLength) {
longestLength = pathname.length;
takeSnapshot = snapshotFn;
}
if (takeSnapshot)
// Take a snapshot of the deepest outlet
takeSnapshot();
}
});
return unsubscribe;
}, [router]);
return (
<AnimatedOutletContext value={registry.current}>
{children}
</AnimatedOutletContext>
);
}
export function AnimatedOutlet({
enter,
exit,
transition = { duration: 0.3 },
from,
clone = true,
}: AnimatedOutletProps) {
const [snapshots, setSnapshots] = useState<Array<{ node: HTMLElement; id: number }>>([]);
const [pathname, setPathname] = useState<string | null>(null);
const outletRef = useRef<HTMLDivElement>(null);
const nextId = useRef(0);
const registry = useContext(AnimatedOutletContext);
useEffect(() => {
if (!pathname)
return;
registry.set(pathname, () => {
const outletNode = outletRef.current!;
const snapshotNode = outletNode.firstChild as HTMLElement | null;
if (snapshotNode) {
let node = snapshotNode;
if (clone)
node = snapshotNode.cloneNode(true) as HTMLElement;
else
snapshotNode.remove();
const newSnapshot = { node, id: nextId.current++ };
setSnapshots(prevSnapshots => [...prevSnapshots, newSnapshot]);
}
});
return () => {
registry.delete(pathname);
};
}, [registry, pathname, clone]);
const handleAnimationComplete = (id: number) => {
setSnapshots(prevSnapshots =>
prevSnapshots.filter(snapshot => snapshot.id !== id),
);
};
return (
<>
{pathname === null && <GetPathName from={from} setPathname={setPathname} />}
<div className="relative w-full h-full">
{snapshots.map(snapshot => (
<motion.div
animate={exit.animate}
aria-hidden="true"
className="absolute inset-0 pointer-events-none w-full h-full"
initial={exit.initial}
key={snapshot.id}
onAnimationComplete={() => handleAnimationComplete(snapshot.id)}
ref={(el) => {
if (el)
el.append(snapshot.node);
}}
transition={transition}
/>
))}
<motion.div
animate={enter.animate}
className="relative w-full h-full"
initial={enter.initial}
key={nextId.current}
ref={outletRef}
transition={transition}
>
<div className="w-full h-full">
<Outlet />
</div>
</motion.div>
</div>
</>
);
}
function GetPathName({ from, setPathname }: { from: AnyRoute['id']; setPathname: (pathname: string) => void }) {
const match = useMatch({ from });
useEffect(() => {
setPathname(match.pathname);
}, [match.pathname, setPathname]);
return null;
}

View file

@ -0,0 +1,99 @@
import type { ToOptions } from '@tanstack/react-router';
import useCommand from '@/hooks/useCommand';
import { bindings } from '@/main';
import { Link } from '@tanstack/react-router';
import { Bell01Icon, Cloud01Icon, TerminalBrowserIcon } from '@untitled-theme/icons-react';
import { MenuTrigger } from 'react-aria-components';
import Button from './base/Button';
import Menu from './base/Menu';
import PlayerHead from './content/PlayerHead';
import AccountPopup from './overlay/popups/AccountPopup';
function Navbar() {
const defaultUser = useCommand('getDefaultUser', () => bindings.commands.getDefaultUser(false));
return (
<div className="h-15 min-h-15 flex flex-row items-center *:flex-1">
<div className="flex items-start justify-start">
<div className="flex items-start justify-start transition-transform active:scale-90">
{/* <OneLauncherText width={260} /> */}
</div>
</div>
<div className="flex flex-row items-center gap-x-10 py-1">
<NavbarLink label="Home" path="/app" />
<NavbarLink label="Browser" path="/app/browser" />
<NavbarLink label="Settings" path="/app" />
</div>
<div className="relative flex flex-row items-center justify-end gap-x-2">
<Button color="ghost" size="icon">
<TerminalBrowserIcon />
</Button>
<Button color="ghost" size="icon">
<Cloud01Icon />
</Button>
{/* Notification Manager Button */}
<div className="relative">
<MenuTrigger>
<Button color="ghost" size="icon">
<Bell01Icon />
</Button>
<Menu.Popover placement="bottom right">
<Menu>
<Menu.Item>Hello World</Menu.Item>
</Menu>
</Menu.Popover>
</MenuTrigger>
{/* <NotificationPopup
className="mt-2"
mount={notificationButtonContainer}
ref={el => el.classList.add('right-0')}
setVisible={setNotificationMenuOpen}
visible={notificationMenuOpen}
/> */}
</div>
<MenuTrigger>
<Button className="p-0" color="ghost" size="icon">
<PlayerHead className="h-full rounded-md hover:opacity-70" uuid={defaultUser.data?.id} />
</Button>
<Menu.Popover>
<AccountPopup />
</Menu.Popover>
</MenuTrigger>
</div>
</div>
);
}
export default Navbar;
function NavbarLink({
path,
label,
}: {
path: ToOptions['to'];
label: string;
}) {
return (
<Link
activeOptions={{
exact: true,
}}
activeProps={{
className: 'text-fg-primary',
}}
className="flex-1 text-center rounded-lg px-4 py-1 text-lg hover:bg-component-bg-hover hover:text-fg-primary-hover"
inactiveProps={{
className: 'text-fg-secondary',
}}
to={path}
>
{label}
</Link>
);
}

View file

@ -0,0 +1,71 @@
import type { ComponentType, JSX } from 'react';
import type { PressEvent } from 'react-aria-components';
import { Window } from '@tauri-apps/api/window';
import { ChevronLeftIcon, Maximize02Icon, Minimize01Icon, MinusIcon, XCloseIcon } from '@untitled-theme/icons-react';
import { useEffect, useState } from 'react';
import { twMerge } from 'tailwind-merge';
import Button from './base/Button';
function WindowFrame() {
const [isMaximized, setIsMaximized] = useState(false);
const back = () => history.back();
const minimize = () => Window.getCurrent().minimize();
const toggleMaximize = () => Window.getCurrent().toggleMaximize();
const quit = () => Window.getCurrent().close();
useEffect(() => {
let unlisten: (() => void) | undefined;
(async () => {
unlisten = await Window.getCurrent().onResized(() => {
Window.getCurrent().isMaximized().then(setIsMaximized);
});
})();
return () => unlisten?.();
}, []);
return (
<div className="z-[99999] w-screen flex flex-row items-center justify-between gap-0.5 bg-window-frame" data-tauri-drag-region>
<div className="flex-1 flex flex-row items-center pointer-events-none">
<TitlebarButton icon={ChevronLeftIcon} onClick={back} />
</div>
<div className="flex-1 flex flex-row items-center justify-center pointer-events-none">
<span className="text-base text-center">OneLauncher</span>
</div>
<div className="flex-1 flex flex-row items-center justify-end pointer-events-none">
<TitlebarButton icon={MinusIcon} onClick={minimize} />
<TitlebarButton icon={isMaximized ? Minimize01Icon : Maximize02Icon} onClick={toggleMaximize} />
<TitlebarButton danger icon={XCloseIcon} onClick={quit} />
</div>
</div>
);
}
export default WindowFrame;
function TitlebarButton({
icon: Icon,
onClick,
danger = false,
}: {
icon: ComponentType<JSX.IntrinsicElements['svg']>;
onClick: (e: PressEvent) => void;
danger?: boolean;
}) {
return (
<Button
className="h-full aspect-square p-1 group flex items-center justify-center pointer-events-auto hover:bg-transparent"
color="ghost"
onPress={onClick}
size="icon"
>
<div className={twMerge('rounded-lg h-full aspect-square flex justify-center items-center', danger ? 'group-hover:bg-danger-hover' : 'group-hover:bg-component-bg-hover')}>
<Icon className="w-5 h-5 stroke-fg-primary group-hover:stroke-fg-primary-hover" />
</div>
</Button>
);
}

View file

@ -0,0 +1,60 @@
import type { RefAttributes } from 'react';
import type { ButtonProps as AriaButtonProps } from 'react-aria-components';
import type { VariantProps } from 'tailwind-variants';
import { Button as AriaButton } from 'react-aria-components';
import { tv } from 'tailwind-variants';
export const buttonVariants = tv({
base: [
'flex flex-row justify-center items-center gap-x-2.5 rounded-lg disabled:pointer-events-none',
],
variants: {
color: {
primary: [
'text-fg-primary hover:text-fg-primary-hover pressed:text-fg-primary-pressed disabled:text-fg-primary-disabled',
'bg-brand hover:bg-brand-hover pressed:bg-brand-pressed disabled:bg-brand-disabled',
],
secondary: [
'border box-border border-component-border hover:border-component-border-hover pressed:border-component-border-pressed',
'text-fg-primary hover:text-fg-primary-hover pressed:text-fg-primary-pressed disabled:text-fg-primary-disabled',
'bg-component-bg hover:bg-component-bg-hover active:bg-component-bg-pressed disabled:bg-component-bg-disabled',
],
danger: [
'text-fg-primary hover:text-fg-primary-hover pressed:text-fg-primary-pressed disabled:text-fg-primary-disabled',
'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',
],
},
size: {
normal: 'py-1.5 px-3',
icon: 'p-1.5 aspect-square box-border w-8 h-8',
iconLarge: 'w-9 h-9 [&>*]:p-0.5',
},
},
});
export type ButtonVariants = VariantProps<typeof buttonVariants>;
export type ButtonProps = AriaButtonProps & RefAttributes<HTMLButtonElement> & {
color?: ButtonVariants['color'];
size?: ButtonVariants['size'];
className?: string;
};
function Button({
color = 'primary',
size = 'normal',
className,
...props
}: ButtonProps) {
return (
<AriaButton
className={buttonVariants({ color, size, className })}
{...props}
/>
);
}
export default Button;

View file

@ -0,0 +1,92 @@
import type { RefObject } from 'react';
import type { MenuItemProps, MenuProps } from 'react-aria-components';
import { useEffect, useRef, useState } from 'react';
import { Menu, MenuItem, Popover } from 'react-aria-components';
import { twMerge } from 'tailwind-merge';
interface ContextMenuProps<T extends object> extends MenuProps<T> {
className?: string;
isOpen: boolean;
setOpen: (open: boolean) => void;
triggerRef: RefObject<HTMLElement | null>;
}
function ContextMenu<T extends object>({
className,
isOpen,
setOpen,
triggerRef,
children,
...rest
}: ContextMenuProps<T>) {
const [position, setPosition] = useState({ x: 0, y: 0 });
const menuRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const trigger = triggerRef.current;
if (!trigger)
return;
const onContextMenu = (e: MouseEvent) => {
e.preventDefault();
e.stopPropagation();
if (isOpen) {
setOpen(false);
return;
}
setPosition({
x: e.clientX,
y: e.clientY,
});
setOpen(true);
};
trigger.addEventListener('contextmenu', onContextMenu);
return () => {
trigger.removeEventListener('contextmenu', onContextMenu);
};
}, [isOpen, setOpen, triggerRef]);
useEffect(() => {
const onClick = (e: MouseEvent) => {
if (e.target && menuRef.current?.contains(e.target as Node))
return;
setOpen(false);
};
window.addEventListener('click', onClick);
return () => {
window.removeEventListener('click', onClick);
};
}, [setOpen, triggerRef]);
return (
<Popover
isNonModal
isOpen={isOpen}
onOpenChange={setOpen}
shouldFlip
triggerRef={triggerRef}
>
<Menu
aria-label="contextmenu"
autoFocus
className={twMerge('rounded-lg bg-page-elevated border border-component-border p-2', className)}
ref={menuRef}
style={{ left: position.x, top: position.y }}
{...rest}
>
{children}
</Menu>
</Popover>
);
}
export default ContextMenu;
ContextMenu.Item = <T extends object>({ className, ...rest }: MenuItemProps<T>) => <MenuItem {...rest} />;

View file

@ -0,0 +1,41 @@
import type { ClassNameString } from '@/types/global';
import type { MenuItemProps as AriaMenuItemProps, MenuProps as AriaMenuProps, PopoverProps as AriaPopoverProps } from 'react-aria-components';
import { Menu as AriaMenu, MenuItem as AriaMenuItem, Popover as AriaPopover } from 'react-aria-components';
import { twMerge } from 'tailwind-merge';
function Menu<T extends object>({
className,
...rest
}: AriaMenuProps<T> & ClassNameString) {
return (
<AriaMenu
className={twMerge(
'flex flex-col gap-0.5 rounded-lg border border-component-border bg-page-elevated p-2 shadow-md',
className,
)}
{...rest}
/>
);
}
export default Menu;
Menu.Popover = ({
className,
...rest
}: AriaPopoverProps & ClassNameString) => (
<AriaPopover
className={twMerge('animate-fade animate-duration-75', className)}
{...rest}
/>
);
Menu.Item = ({
className,
...rest
}: AriaMenuItemProps & ClassNameString) => (
<AriaMenuItem
className={className}
{...rest}
/>
);

View file

@ -0,0 +1,24 @@
import type { RefAttributes } from 'react';
import type { ToggleButtonProps as AriaToggleButtonProps } from 'react-aria-components';
import type { ButtonVariants } from './Button';
import { ToggleButton as AriaToggleButton } from 'react-aria-components';
import { buttonVariants } from './Button';
export type ToggleButtonProps = AriaToggleButtonProps & RefAttributes<HTMLButtonElement> & {
color?: ButtonVariants['color'];
size?: ButtonVariants['size'];
className?: string;
};
function ToggleButton({
color = 'ghost',
size = 'normal',
className,
...props
}: ToggleButtonProps) {
return (
<AriaToggleButton className={buttonVariants({ color, size, className })} {...props} />
);
}
export default ToggleButton;

View file

@ -0,0 +1,33 @@
import type { ImgHTMLAttributes } from 'react';
import SteveHead from '@/assets/images/steve.jpg';
import { useMemo } from 'react';
interface PlayerHeadProps {
uuid?: string | undefined | null;
}
function PlayerHead({
uuid,
src: _src, // ignore src prop to prevent overriding the generated src
...rest
}: PlayerHeadProps & ImgHTMLAttributes<HTMLImageElement>) {
const src = useMemo(() => {
return uuid
? `https://crafatar.com/avatars/${uuid}?overlay&size=8`
: SteveHead;
}, [uuid]);
return (
<img
{...rest}
alt="Player Head"
onError={(e) => {
(e.target as HTMLImageElement).src = SteveHead;
}}
src={src}
style={{ imageRendering: 'pixelated' }}
/>
);
}
export default PlayerHead;

View file

@ -0,0 +1,9 @@
// function ClusterCover({
// cluster,
// }: {
// cluster:
// }) {
// }
// export default ClusterCover;

View file

@ -0,0 +1,87 @@
import Button from '@/components/base/Button';
import Menu from '@/components/base/Menu';
import PlayerHead from '@/components/content/PlayerHead';
import useCommand from '@/hooks/useCommand';
import { bindings } from '@/main';
import { PlusIcon, Settings01Icon } from '@untitled-theme/icons-react';
import { Separator } from 'react-aria-components';
import { twMerge } from 'tailwind-merge';
function AccountPopup() {
const users = useCommand('getUsers', bindings.commands.getUsers);
const defaultUser = useCommand('getDefaultUser', () => bindings.commands.getDefaultUser(false));
const setDefaultUser = (user: bindings.MinecraftCredentials) => {
bindings.commands.setDefaultUser(user.id);
};
return (
<Menu className="min-w-3xs">
{defaultUser.data && (
<Menu.Item>
<AccountEntry
loggedIn
onClick={() => {}}
user={defaultUser.data}
/>
</Menu.Item>
)}
{users.data?.filter(user => user.id === defaultUser.data?.id).map(user => (
<Menu.Item key={user.id}>
<AccountEntry
onClick={() => setDefaultUser(user)}
user={user}
/>
</Menu.Item>
))}
{(users.data?.length ?? 0) > 0 && (
<Separator />
)}
<Menu.Item className="flex flex-row justify-between">
<div>
<Button color="ghost">
<PlusIcon />
Add Account
</Button>
</div>
<div className="flex flex-row">
<Button color="ghost" size="iconLarge">
<Settings01Icon className="stroke-fg-primary" />
</Button>
</div>
</Menu.Item>
</Menu>
);
}
export default AccountPopup;
function AccountEntry({
onClick,
user,
loggedIn = false,
}: {
onClick: () => void;
user: bindings.MinecraftCredentials;
loggedIn?: boolean;
}) {
return (
<div
className={twMerge('flex flex-row justify-between p-2 rounded-lg', !loggedIn && 'hover:bg-component-bg-hover active:bg-component-bg-pressed hover:text-fg-primary-hover')}
onClick={onClick}
>
<div className="flex flex-1 flex-row justify-start gap-x-3">
<PlayerHead className="h-8 w-8 rounded-md" uuid={user.id} />
<div className="flex flex-col items-center justify-center">
<div className="flex flex-col items-start justify-between">
<p className="h-[18px] font-semibold">{user.username}</p>
{loggedIn && <p className="text-xs">Logged in</p>}
</div>
</div>
</div>
</div>
);
}

View file

@ -0,0 +1,14 @@
import '@fontsource/poppins/300.css';
import '@fontsource/poppins/300-italic.css';
import '@fontsource/poppins/400.css';
import '@fontsource/poppins/400-italic.css';
import '@fontsource/poppins/500.css';
import '@fontsource/poppins/500-italic.css';
import '@fontsource/poppins/600.css';
import '@fontsource/poppins/600-italic.css';
import '@fontsource/poppins/700.css';
import '@fontsource/poppins/700-italic.css';
import '@fontsource/poppins/800.css';
import '@fontsource/poppins/800-italic.css';
import '@fontsource/poppins/900.css';
import '@fontsource/poppins/900-italic.css';

View file

@ -0,0 +1,31 @@
import type { Result } from '@/bindings.gen';
import type { bindings } from '@/main';
import type { UndefinedInitialDataOptions } from '@tanstack/react-query';
import { useQuery } from '@tanstack/react-query';
type CacheKey = keyof typeof bindings.commands;
function useCommand<T, TError>(cacheKey: CacheKey | (string & {}), command: () => Promise<Result<T, TError>>, options?: Omit<UndefinedInitialDataOptions<T>, 'queryKey' | 'queryFn'>) {
return useQuery({
queryKey: [cacheKey],
queryFn: async () => {
try {
const result = await command();
if (result.status === 'error')
return Promise.reject(result.error);
return result.data;
}
catch (e) {
if (e instanceof Error)
return Promise.reject(e);
else
return Promise.reject(new Error('Unknown error'));
}
},
enabled: true,
...options,
});
}
export default useCommand;

View file

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg id="Layer_1"
xmlns="http://www.w3.org/2000/svg" version="1.1" viewBox="0 0 841.9 595.3">
<!-- Generator: Adobe Illustrator 29.3.0, SVG Export Plug-In . SVG Version: 2.1.0 Build 146) -->
<defs>
<style>
.st0 {
fill: #9ae7fc;
}
.st1 {
fill: #61dafb;
}
</style>
</defs>
<g>
<path class="st1" d="M666.3,296.5c0-32.5-40.7-63.3-103.1-82.4,14.4-63.6,8-114.2-20.2-130.4-6.5-3.8-14.1-5.6-22.4-5.6v22.3c4.6,0,8.3.9,11.4,2.6,13.6,7.8,19.5,37.5,14.9,75.7-1.1,9.4-2.9,19.3-5.1,29.4-19.6-4.8-41-8.5-63.5-10.9-13.5-18.5-27.5-35.3-41.6-50,32.6-30.3,63.2-46.9,84-46.9v-22.3c-27.5,0-63.5,19.6-99.9,53.6-36.4-33.8-72.4-53.2-99.9-53.2v22.3c20.7,0,51.4,16.5,84,46.6-14,14.7-28,31.4-41.3,49.9-22.6,2.4-44,6.1-63.6,11-2.3-10-4-19.7-5.2-29-4.7-38.2,1.1-67.9,14.6-75.8,3-1.8,6.9-2.6,11.5-2.6v-22.3c-8.4,0-16,1.8-22.6,5.6-28.1,16.2-34.4,66.7-19.9,130.1-62.2,19.2-102.7,49.9-102.7,82.3s40.7,63.3,103.1,82.4c-14.4,63.6-8,114.2,20.2,130.4,6.5,3.8,14.1,5.6,22.5,5.6,27.5,0,63.5-19.6,99.9-53.6,36.4,33.8,72.4,53.2,99.9,53.2,8.4,0,16-1.8,22.6-5.6,28.1-16.2,34.4-66.7,19.9-130.1,62-19.1,102.5-49.9,102.5-82.3zm-130.2-66.7c-3.7,12.9-8.3,26.2-13.5,39.5-4.1-8-8.4-16-13.1-24-4.6-8-9.5-15.8-14.4-23.4,14.2,2.1,27.9,4.7,41,7.9zm-45.8,106.5c-7.8,13.5-15.8,26.3-24.1,38.2-14.9,1.3-30,2-45.2,2s-30.2-.7-45-1.9c-8.3-11.9-16.4-24.6-24.2-38-7.6-13.1-14.5-26.4-20.8-39.8,6.2-13.4,13.2-26.8,20.7-39.9,7.8-13.5,15.8-26.3,24.1-38.2,14.9-1.3,30-2,45.2-2s30.2.7,45,1.9c8.3,11.9,16.4,24.6,24.2,38,7.6,13.1,14.5,26.4,20.8,39.8-6.3,13.4-13.2,26.8-20.7,39.9zm32.3-13c5.4,13.4,10,26.8,13.8,39.8-13.1,3.2-26.9,5.9-41.2,8,4.9-7.7,9.8-15.6,14.4-23.7,4.6-8,8.9-16.1,13-24.1zm-101.4,106.7c-9.3-9.6-18.6-20.3-27.8-32,9,.4,18.2.7,27.5.7s18.7-.2,27.8-.7c-9,11.7-18.3,22.4-27.5,32zm-74.4-58.9c-14.2-2.1-27.9-4.7-41-7.9,3.7-12.9,8.3-26.2,13.5-39.5,4.1,8,8.4,16,13.1,24s9.5,15.8,14.4,23.4zm73.9-208.1c9.3,9.6,18.6,20.3,27.8,32-9-.4-18.2-.7-27.5-.7s-18.7.2-27.8.7c9-11.7,18.3-22.4,27.5-32zm-74,58.9c-4.9,7.7-9.8,15.6-14.4,23.7-4.6,8-8.9,16-13,24-5.4-13.4-10-26.8-13.8-39.8,13.1-3.1,26.9-5.8,41.2-7.9zm-90.5,125.2c-35.4-15.1-58.3-34.9-58.3-50.6s22.9-35.6,58.3-50.6c8.6-3.7,18-7,27.7-10.1,5.7,19.6,13.2,40,22.5,60.9-9.2,20.8-16.6,41.1-22.2,60.6-9.9-3.1-19.3-6.5-28-10.2zm53.8,142.9c-13.6-7.8-19.5-37.5-14.9-75.7,1.1-9.4,2.9-19.3,5.1-29.4,19.6,4.8,41,8.5,63.5,10.9,13.5,18.5,27.5,35.3,41.6,50-32.6,30.3-63.2,46.9-84,46.9-4.5-.1-8.3-1-11.3-2.7zm237.2-76.2c4.7,38.2-1.1,67.9-14.6,75.8-3,1.8-6.9,2.6-11.5,2.6-20.7,0-51.4-16.5-84-46.6,14-14.7,28-31.4,41.3-49.9,22.6-2.4,44-6.1,63.6-11,2.3,10.1,4.1,19.8,5.2,29.1zm38.5-66.7c-8.6,3.7-18,7-27.7,10.1-5.7-19.6-13.2-40-22.5-60.9,9.2-20.8,16.6-41.1,22.2-60.6,9.9,3.1,19.3,6.5,28.1,10.2,35.4,15.1,58.3,34.9,58.3,50.6,0,15.7-23,35.6-58.4,50.6zm-264.9-268.7z"/>
<circle class="st1" cx="420.9" cy="296.5" r="45.7"/>
<path class="st1" d="M520.5,78.1"/>
</g>
<circle class="st0" cx="420.8" cy="296.6" r="43"/>
<path class="st1" d="M466.1,296.6c0,25-20.2,45.2-45.2,45.2s-45.2-20.2-45.2-45.2,20.2-45.2,45.2-45.2,45.2,20.2,45.2,45.2ZM386,295.6v-6.3c0-1.1,1.2-5.1,1.8-6.2,1-1.9,2.9-3.5,4.6-4.7l-3.4-3.4c4-3.6,9.4-3.7,13.7-.7,1.9-4.7,6.6-7.1,11.6-6.7l-.8,4.2c5.9.2,13.1,4.1,13.1,10.8s0,.5-.7.7c-1.7.3-3.4-.4-5-.6s-1.2-.4-1.2.3,2.5,4.1,3,5.5,1,3.5.8,5.3c-5.6-.8-10.5-3.2-14.8-6.7.3,2.6,4.1,21.7,5.3,21.9s.8-.6,1-1.1,1.3-6.3,1.3-6.7c0-1-1.7-1.8-2.2-2.8-1.2-2.7,1.3-4.7,3.7-3.3s5.2,6.2,7.5,7.3,13,1.4,14.8,3.3-2.9,4.6-1.5,7.6c6.7-2.6,13.5-3.3,20.6-2.5,3.1-9.7,3.1-20.3-.9-29.8-7.3,0-14.7-3.6-17.2-10.8-2.5-7.2-.7-8.6-1.3-9.3-.8-1-6.3.6-7.4-1.5s.3-1.1-.2-1.4-1.9-.6-2.6-.8c-26-6.4-51.3,15.7-49.7,42.1,0,1.6,1.6,10.3,2.4,11.1s4.8,0,6.3,0,3.7.3,5,.5c2.9.4,7.2,2.4,9.4,2.5s2.4-.8,2.7-2.4c.4-2.6.5-7.4.5-10.1s-1-7.8-1.3-11.6c-.9-.2-.7,0-.9.5-.7,1.3-1.1,3.2-1.9,4.8s-5.2,8.7-5.7,9-.7-.5-.8-.8c-1.6-3.5-2-7.9-1.9-11.8-.9-1-5.4,4.9-6.7,5.3l-.8-.4v-.3h-.2ZM455.6,276.4c1.1-1.2-6-8.9-7.2-10-3-2.7-5.4-4.5-3.5,1.4s5.7,7.8,10.6,8.5h.1ZM410.9,270.1c-.4-.5-6.1,2.9-5.5,4.6,1.9-1.3,5.9-1.7,5.5-4.6ZM400.4,276.4c-.3-2.4-6.3-2.7-7.2-1s1.6,1.4,1.9,1.4c1.8.3,3.5-.6,5.2-.4h.1ZM411.3,276.8c3.8,1.3,6.6,3.6,10.9,3.7s0-3-1.2-3.9c-2.2-1.7-5.1-2.4-7.8-2.4s-1.6-.3-1.4.4c2.8.6,7.3.7,8.4,3.8-2.3-.3-3.9-1.6-6.2-2s-2.5-.5-2.6.3h0ZM420.6,290.3c-.8-5.1-5.7-10.8-10.9-11.6s-1.3-.4-.8.5,4.7,3.2,5.7,4,4.5,4.2,2.1,3.8-8.4-7.8-9.4-6.7c.2.9,1.1,1.9,1.7,2.7,3,3.8,6.9,6.8,11.8,7.4h-.2ZM395.3,279.8c-5,1.1-6.9,6.3-6.7,11,.7.8,5-3.8,5.4-4.5s2.7-4.6,1.1-4-2.9,4.4-4.2,4.6.2-2.1.4-2.5c1.1-1.6,2.9-3.1,4-4.6h0ZM400.4,281.5c-.4-.5-2,1.3-2.3,1.7-2.9,3.9-2.6,10.2-1.5,14.8.8.2.8-.3,1.2-.7,3-3.8,5.5-10.5,4.5-15.4-2.1,3.1-3.1,7.3-3.6,11h-1.3c0-4,1.9-7.7,3-11.4h0ZM426.9,305.9c0-1.7-1.7-1.4-2.5-1.9s-1.3-1.9-3-1.4c1.3,2.1,3,3.2,5.5,3.4h0ZM417.2,308.5c7.6.7,5.5-1.9,1.4-5.5-1.3-.3-1.5,4.5-1.4,5.5ZM437,309.7c-3.5-.3-7.8-2-11.2-2.1s-1.3,0-1.9.7c4,1.3,8.4,1.7,12.1,4l1-2.5h0ZM420.5,312.8c-7.3,0-15.1,3.7-20.4,8.8s-4.8,5.3-4.8,6.2c0,1.8,8.6,6.2,10.5,6.8,12.1,4.8,27.5,3.5,38.2-4.2s3.1-2.7,0-6.2c-5.7-6.6-14.7-11.4-23.4-11.3h-.1ZM398.7,316.9c-1.4-1.4-5-1.9-7-2.1s-5.3-.3-6.9.6l13.9,1.4h0ZM456.9,314.8h-7.4c-.9,0-4.9,1.1-6,1.6s-.8.6,0,.5c2.4,0,5.1-1,7.6-1.3s3.5.2,5.1,0,1.3-.3.6-.8h0Z"/>
<path class="st0" d="M386,295.6l.8.4c1.3-.3,5.8-6.2,6.7-5.3,0,3.9.3,8.3,1.9,11.8s0,1.2.8.8,5.1-7.8,5.7-9,1.3-3.5,1.9-4.8,0-.7.9-.5c.3,3.8,1.2,7.8,1.3,11.6s0,7.5-.5,10.1-1.1,2.4-2.7,2.4-6.5-2.1-9.4-2.5-3.7-.5-5-.5-5.4,1.1-6.3,0-2.2-9.5-2.4-11.1c-1.5-26.4,23.7-48.5,49.7-42.1s2.2.4,2.6.8,0,1,.2,1.4c1.1,2,6.5.5,7.4,1.5s.4,6.9,1.3,9.3c2.5,7.2,10,10.9,17.2,10.8,4,9.4,4,20.1.9,29.8-7.2-.7-13.9,0-20.6,2.5-1.3-3.1,4.1-5.1,1.5-7.6s-11.8-1.9-14.8-3.3-5.4-6.1-7.5-7.3-4.9.6-3.7,3.3,2.1,1.8,2.2,2.8-1,6.2-1.3,6.7-.3,1.3-1,1.1c-1.1-.3-5-19.3-5.3-21.9,4.3,3.5,9.2,5.9,14.8,6.7.2-1.9-.3-3.5-.8-5.3s-3-5.1-3-5.5c0-.8.9-.3,1.2-.3,1.6,0,3.3.8,5,.6s.7.3.7-.7c0-6.6-7.2-10.6-13.1-10.8l.8-4.2c-5.1-.3-9.6,2-11.6,6.7-4.3-3-9.8-3-13.7.7l3.4,3.4c-1.8,1.3-3.5,2.8-4.6,4.7s-1.8,5.1-1.8,6.2v6.6h.2ZM431.6,265c7.8,2.1,8.7-3.5.2-1.3l-.2,1.3ZM432.4,270.9c.3.6,6.4-.4,5.8-2.3s-4.6.6-5.7.6l-.2,1.7h.1ZM434.5,276c.8,1.2,5.7-1.8,5.5-2.7-.4-1.9-6.6,1.2-5.5,2.7ZM442.9,276.4c-.9-.9-5,2.8-4.6,4,.6,2.4,5.7-3,4.6-4ZM445.1,279.9c-.3.2-3.1,4.6-1.5,5s3.5-3.4,3.5-4-1.3-1.3-2-.9h0ZM448.9,287.4c2.1.8,3.8-5.1,2.3-5.5-1.9-.6-2.6,5.1-2.3,5.5ZM457.3,288.6c.5-1.7,1.1-4.7-1-5.5-1,.3-.6,3.9-.6,4.8l.3.5,1.3.2h0Z"/>
<path class="st0" d="M455.6,276.4c-5-.8-9.1-3.6-10.6-8.5s.5-4,3.5-1.4,8.3,8.7,7.2,10h-.1Z"/>
<path class="st0" d="M420.6,290.3c-4.9-.6-8.9-3.6-11.8-7.4s-1.5-1.8-1.7-2.7c1-1,8.5,6.6,9.4,6.7,2.4.4-1.8-3.5-2.1-3.8-1-.8-5.4-3.5-5.7-4-.4-.8.5-.5.8-.5,5.2.8,10.1,6.6,10.9,11.6h.2Z"/>
<path class="st0" d="M400.4,281.5c-1.1,3.7-3,7.3-3,11.4h1.3c.5-3.7,1.5-7.8,3.6-11,1,4.8-1.5,11.6-4.5,15.4s-.4.8-1.2.7c-1.1-4.5-1.3-10.8,1.5-14.8s1.9-2.2,2.3-1.7h0Z"/>
<path class="st0" d="M411.3,276.8c0-.8,2.1-.4,2.6-.3,2.4.4,4,1.7,6.2,2-1.2-3.1-5.7-3.2-8.4-3.8,0-.8.9-.4,1.4-.4,2.8,0,5.6.7,7.8,2.4,2.2,1.7,4,4,1.2,3.9-4.3,0-7.1-2.4-10.9-3.7h0Z"/>
<path class="st0" d="M395.3,279.8c-1.1,1.6-3,3-4,4.6s-1.9,2.8-.4,2.5,2.8-4,4.2-4.6-.9,3.6-1.1,4c-.4.7-4.7,5.2-5.4,4.5-.2-4.6,1.8-9.9,6.7-11h0Z"/>
<path class="st0" d="M437,309.7l-1,2.5c-3.6-2.3-8-2.8-12.1-4,.5-.7,1.1-.7,1.9-.7,3.4,0,7.8,1.8,11.2,2.1h0Z"/>
<path class="st0" d="M417.2,308.5c0-1,0-5.8,1.4-5.5,4,3.5,6.1,6.2-1.4,5.5Z"/>
<path class="st0" d="M400.4,276.4c-1.8-.3-3.5.7-5.2.4s-2.3-.8-1.9-1.4c.8-1.6,6.9-1.4,7.2,1h-.1Z"/>
<path class="st0" d="M410.9,270.1c.4,3-3.6,3.3-5.5,4.6-.6-1.8,5-5.1,5.5-4.6Z"/>
<path class="st0" d="M426.9,305.9c-2.5-.2-4.1-1.3-5.5-3.4,1.7-.4,2,.8,3,1.4s2.6.3,2.5,1.9h0Z"/>
<path class="st1" d="M432.4,270.9l.2-1.7c1.1,0,5.1-2.2,5.7-.6s-5.5,2.9-5.8,2.3h-.1Z"/>
<path class="st1" d="M431.6,265l.2-1.3c8.4-2.1,7.7,3.4-.2,1.3Z"/>
<path class="st1" d="M434.5,276c-1.1-1.5,5.1-4.6,5.5-2.7s-4.6,4-5.5,2.7Z"/>
<path class="st1" d="M442.9,276.4c1.1,1.1-4,6.4-4.6,4s3.7-4.9,4.6-4Z"/>
<path class="st1" d="M445.1,279.9c.7-.4,2.1,0,2,.9s-2.4,4.4-3.5,4,1.3-4.8,1.5-5h0Z"/>
<path class="st1" d="M448.9,287.4c-.3-.3.4-6.1,2.3-5.5,1.4.4-.2,6.2-2.3,5.5Z"/>
<path class="st1" d="M457.3,288.6l-1.3-.2-.3-.5c0-.9-.4-4.6.6-4.8,2.1.8,1.5,3.8,1,5.5h0Z"/>
<path class="st0" d="M420.5,312.8c8.9,0,17.9,4.7,23.4,11.3,5.6,6.6,3.8,3.5,0,6.2-10.7,7.7-26.1,9-38.2,4.2-1.9-.8-10.5-5.1-10.5-6.8s4-5.3,4.8-6.2c5.3-5,13.1-8.6,20.4-8.8h.1Z"/>
<path class="st0" d="M398.7,316.9l-13.9-1.4c1.7-1,5-.8,6.9-.6s5.6.7,7,2.1h0Z"/>
<path class="st0" d="M456.9,314.8c.7.5,0,.8-.6.8-1.6.2-3.5-.2-5.1,0-2.4.3-5.2,1.2-7.6,1.3s-1.1,0,0-.5,5.1-1.6,6-1.6h7.4,0Z"/>
</svg>

After

Width:  |  Height:  |  Size: 8.4 KiB

View file

@ -0,0 +1,55 @@
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { createRouter, RouterProvider } from '@tanstack/react-router';
import { StrictMode } from 'react';
import ReactDOM from 'react-dom/client';
import { routeTree } from './routeTree.gen';
import './fonts';
import './utils/nativeExperience';
import './utils/devExperience';
import './styles/global.css';
export * as bindings from './bindings.gen';
// Tanstack Query Client
const queryClient = new QueryClient({
defaultOptions: {
queries: {
retry: false,
enabled: false,
},
},
});
// Tanstack Router
const router = createRouter({
routeTree,
context: {
queryClient,
},
defaultPreload: 'intent',
scrollRestoration: true,
defaultStructuralSharing: true,
defaultPreloadStaleTime: 0,
defaultNotFoundComponent: () => <div>Not Found</div>,
});
declare module '@tanstack/react-router' {
interface Register {
router: typeof router;
}
}
// Render the app
const rootElement = document.getElementById('app');
if (rootElement && !rootElement.innerHTML) {
const root = ReactDOM.createRoot(rootElement);
root.render(
<StrictMode>
<QueryClientProvider client={queryClient}>
<RouterProvider router={router} />
</QueryClientProvider>
</StrictMode>,
);
}

View file

@ -0,0 +1,170 @@
/* eslint-disable */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// This file was automatically generated by TanStack Router.
// You should NOT make any changes in this file as it will be overwritten.
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
// Import Routes
import { Route as rootRoute } from './routes/__root'
import { Route as AppRouteImport } from './routes/app/route'
import { Route as IndexImport } from './routes/index'
import { Route as AppIndexImport } from './routes/app/index'
import { Route as AppBrowserIndexImport } from './routes/app/browser/index'
// Create/Update Routes
const AppRouteRoute = AppRouteImport.update({
id: '/app',
path: '/app',
getParentRoute: () => rootRoute,
} as any)
const IndexRoute = IndexImport.update({
id: '/',
path: '/',
getParentRoute: () => rootRoute,
} as any)
const AppIndexRoute = AppIndexImport.update({
id: '/',
path: '/',
getParentRoute: () => AppRouteRoute,
} as any)
const AppBrowserIndexRoute = AppBrowserIndexImport.update({
id: '/browser/',
path: '/browser/',
getParentRoute: () => AppRouteRoute,
} as any)
// Populate the FileRoutesByPath interface
declare module '@tanstack/react-router' {
interface FileRoutesByPath {
'/': {
id: '/'
path: '/'
fullPath: '/'
preLoaderRoute: typeof IndexImport
parentRoute: typeof rootRoute
}
'/app': {
id: '/app'
path: '/app'
fullPath: '/app'
preLoaderRoute: typeof AppRouteImport
parentRoute: typeof rootRoute
}
'/app/': {
id: '/app/'
path: '/'
fullPath: '/app/'
preLoaderRoute: typeof AppIndexImport
parentRoute: typeof AppRouteImport
}
'/app/browser/': {
id: '/app/browser/'
path: '/browser'
fullPath: '/app/browser'
preLoaderRoute: typeof AppBrowserIndexImport
parentRoute: typeof AppRouteImport
}
}
}
// Create and export the route tree
interface AppRouteRouteChildren {
AppIndexRoute: typeof AppIndexRoute
AppBrowserIndexRoute: typeof AppBrowserIndexRoute
}
const AppRouteRouteChildren: AppRouteRouteChildren = {
AppIndexRoute: AppIndexRoute,
AppBrowserIndexRoute: AppBrowserIndexRoute,
}
const AppRouteRouteWithChildren = AppRouteRoute._addFileChildren(
AppRouteRouteChildren,
)
export interface FileRoutesByFullPath {
'/': typeof IndexRoute
'/app': typeof AppRouteRouteWithChildren
'/app/': typeof AppIndexRoute
'/app/browser': typeof AppBrowserIndexRoute
}
export interface FileRoutesByTo {
'/': typeof IndexRoute
'/app': typeof AppIndexRoute
'/app/browser': typeof AppBrowserIndexRoute
}
export interface FileRoutesById {
__root__: typeof rootRoute
'/': typeof IndexRoute
'/app': typeof AppRouteRouteWithChildren
'/app/': typeof AppIndexRoute
'/app/browser/': typeof AppBrowserIndexRoute
}
export interface FileRouteTypes {
fileRoutesByFullPath: FileRoutesByFullPath
fullPaths: '/' | '/app' | '/app/' | '/app/browser'
fileRoutesByTo: FileRoutesByTo
to: '/' | '/app' | '/app/browser'
id: '__root__' | '/' | '/app' | '/app/' | '/app/browser/'
fileRoutesById: FileRoutesById
}
export interface RootRouteChildren {
IndexRoute: typeof IndexRoute
AppRouteRoute: typeof AppRouteRouteWithChildren
}
const rootRouteChildren: RootRouteChildren = {
IndexRoute: IndexRoute,
AppRouteRoute: AppRouteRouteWithChildren,
}
export const routeTree = rootRoute
._addFileChildren(rootRouteChildren)
._addFileTypes<FileRouteTypes>()
/* ROUTE_MANIFEST_START
{
"routes": {
"__root__": {
"filePath": "__root.tsx",
"children": [
"/",
"/app"
]
},
"/": {
"filePath": "index.tsx"
},
"/app": {
"filePath": "app/route.tsx",
"children": [
"/app/",
"/app/browser/"
]
},
"/app/": {
"filePath": "app/index.tsx",
"parent": "/app"
},
"/app/browser/": {
"filePath": "app/browser/index.tsx",
"parent": "/app"
}
}
}
ROUTE_MANIFEST_END */

View file

@ -0,0 +1,40 @@
import type { QueryClient } from '@tanstack/react-query';
import type { NavigateOptions, ToOptions } from '@tanstack/react-router';
import { AnimatedOutletProvider } from '@/components/AnimatedOutlet';
import WindowFrame from '@/components/WindowFrame';
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: RootRoute,
});
function RootRoute() {
const router = useRouter();
return (
<AnimatedOutletProvider>
<RouterProvider
navigate={(to, options) => router.navigate({ to, ...options })}
useHref={to => router.buildLocation({ to }).href}
>
<WindowFrame />
<Outlet />
<TanStackRouterDevtools />
</RouterProvider>
</AnimatedOutletProvider>
);
}

View file

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

View file

@ -0,0 +1,85 @@
import DefaultBanner from '@/assets/images/default_banner.png';
import { createFileRoute, useNavigate } from '@tanstack/react-router';
export const Route = createFileRoute('/app/')({
component: RouteComponent,
});
function RouteComponent() {
return (
<div className="h-full flex flex-col gap-y-4 text-fg-primary">
<Banner />
</div>
);
}
function Banner() {
/**
* If there are any clusters, display the most recent cluster name + some statistics as the "description".
* The background would prioritise
* any screenshots taken from the cluster, if there are none, it would display the cluster cover if it has been set.
* The button would launch the cluster.
*
* If there are no clusters, display a generic background with the button action creating a new cluster.
*/
// const cluster = useRecentCluster();
// const launch = useLaunchCluster(() => cluster()?.uuid);
const navigate = useNavigate();
return (
<div className="relative h-52 min-h-52 w-full overflow-hidden rounded-xl border border-component-border">
<div className="absolute h-52 min-h-52 w-full">
<img
alt="Default Banner"
className="top-0 left-0 h-full w-full object-cover"
src={DefaultBanner}
/>
</div>
<div className="relative z-10 h-full flex flex-col items-start justify-between px-8 py-6">
<div className="theme-OneLauncher-Dark flex flex-col gap-y-2 text-fg-primary">
<h1 className="text-2xl font-medium text-shadow-black text-shadow-2xs">Create a cluster</h1>
{/* <Show when={cluster() !== undefined}>
<p>
You've played
{' '}
<strong>
{cluster()!.meta.mc_version}
{' '}
{upperFirst(cluster()!.meta.loader || 'Unknown')}
</strong>
{' '}
for
{' '}
<strong>{formatAsDuration((cluster()!.meta.overall_played || 0))}</strong>
.
</p>
</Show> */}
</div>
<div className="w-full flex flex-row items-end justify-between">
<div className="flex flex-row items-center gap-x-4">
{/* <Show when={cluster() !== undefined}>
<Button
buttonStyle="primary"
children={`Launch ${cluster()!.meta.mc_version}`}
iconLeft={<PlayIcon />}
onClick={launch}
/>
<Button
buttonStyle="iconSecondary"
children={<Settings01Icon />}
className="theme-OneLauncher-Dark bg-op-10!"
onClick={() => ClusterRoot.open(navigate, cluster()!.uuid)}
/>
</Show> */}
</div>
<div className="flex flex-row gap-x-2">
{/* TODO: These tags */}
{/* <Tag iconLeft={<OneConfigLogo />} />
<Tag iconLeft={<CheckIcon />}>Verified</Tag> */}
</div>
</div>
</div>
</div>
);
}

View file

@ -0,0 +1,41 @@
import { AnimatedOutlet } from '@/components/AnimatedOutlet';
import Navbar from '@/components/Navbar';
import { createFileRoute } from '@tanstack/react-router';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-react';
export const Route = createFileRoute('/app')({
component: RouteComponent,
});
function RouteComponent() {
return (
<div className="h-full flex flex-col">
<div className="flex flex-col px-4">
<Navbar />
</div>
<div className="h-full w-full overflow-hidden">
<div className="relative h-full w-full flex flex-col overflow-x-hidden pb-8">
<OverlayScrollbarsComponent className="h-full w-full flex flex-col overflow-x-hidden overflow-y-auto">
<div className="h-full flex-1 px-4">
<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>
</OverlayScrollbarsComponent>
</div>
</div>
</div>
);
}

View file

@ -0,0 +1,12 @@
import { createFileRoute, Navigate } from '@tanstack/react-router';
export const Route = createFileRoute('/')({
component: App,
});
function App() {
// TODO: This will decide if we need to show onboarding or not.
return (
<Navigate to="/app" />
);
}

View file

@ -0,0 +1,85 @@
@import "tailwindcss";
@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-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);
/* 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;
}

View file

@ -0,0 +1,3 @@
export interface ClassNameString {
className?: string;
}

View file

@ -0,0 +1,11 @@
(() => {
if (location.hostname !== 'localhost')
return;
window.addEventListener('keypress', (e) => {
if (e.getModifierState('Control') && e.key === 'r') {
e.preventDefault();
window.location.reload(); // tauri disables this i think
}
});
})();

View file

@ -0,0 +1,3 @@
document.addEventListener('contextmenu', (e) => {
e.preventDefault();
});

View file

@ -1,37 +1,31 @@
{
"extends": "../../../tsconfig.base.json",
"compilerOptions": {
"target": "ESNext",
"jsx": "preserve",
"jsxImportSource": "solid-js",
"lib": ["ESNext", "DOM", "DOM.Iterable"],
"useDefineForClassFields": true,
"rootDir": ".",
"target": "ES2022",
"jsx": "react-jsx",
"lib": ["ES2022", "DOM", "DOM.Iterable"],
"baseUrl": ".",
"module": "ESNext",
"moduleResolution": "Bundler",
/* Bundler mode */
"moduleResolution": "bundler",
"paths": {
"~*": ["./src/*"]
"@/*": ["./src/*"]
},
"resolveJsonModule": true,
"types": [
"vite-plugin-solid-svg/types"
],
/* Project */
"types": ["vite/client"],
"allowImportingTsExtensions": true,
"strict": true,
"noFallthroughCasesInSwitch": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noEmit": true,
"sourceMap": false,
"esModuleInterop": true,
"isolatedModules": true,
"verbatimModuleSyntax": true,
"skipLibCheck": true
/* Linting */
"skipLibCheck": true,
"noUncheckedSideEffectImports": true
},
"references": [{ "path": "./tsconfig.node.json" }],
"include": [
"./src/**/*.ts",
"./src/**/*.d.ts",
"./src/**/*.tsx"
]
"include": ["**/*.ts", "**/*.tsx", "prettier.config.js", "vite.config.js"]
}

View file

@ -0,0 +1,32 @@
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';
export default defineConfig({
plugins: [
TanStackRouterVite({ autoCodeSplitting: true }),
viteReact(),
tailwindcss(),
],
clearScreen: false,
server: {
port: 8001,
strictPort: true,
},
resolve: {
alias: {
'@': resolve(__dirname, './src'),
},
},
envPrefix: ['VITE_', 'TAURI_ENV_'],
build: {
target: process.env.TAURI_ENV_PLATFORM === 'windows' ? 'chrome105' : 'safari13',
minify: !process.env.TAURI_ENV_DEBUG ? 'esbuild' : false,
sourcemap: !!process.env.TAURI_ENV_DEBUG,
},
});

View file

@ -0,0 +1,15 @@
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="theme-color" content="#000000" />
<link rel="icon" type="image/svg+xml" href="/src/assets/logo.svg" />
<title>OneLauncher</title>
</head>
<body>
<div id="root"></div>
<script type="module" src="/src/index.tsx"></script>
</body>
</html>

View file

@ -0,0 +1,56 @@
{
"name": "@onelauncher/old_frontend",
"type": "module",
"version": "0.1.0-alpha.2",
"private": true,
"description": "Next-generation open source Minecraft launcher frontend",
"license": "GPL-3.0-only",
"repository": {
"type": "git",
"url": "git@github.com:polyfrost/onelauncher",
"directory": "apps/frontend"
},
"bugs": "https://github.com/polyfrost/onelauncher/issues",
"sideEffects": false,
"scripts": {
"dev": "vite",
"build": "vite build",
"typecheck": "tsc --noEmit"
},
"dependencies": {
"@fontsource/poppins": "^5.1.0",
"@formatjs/intl-durationformat": "^0.5.0",
"@leeoniya/ufuzzy": "^1.0.14",
"@onelauncher/client": "workspace:*",
"@solid-primitives/i18n": "^2.1.1",
"@solid-primitives/map": "^0.4.13",
"@solid-primitives/refs": "^1.0.8",
"@solid-primitives/scheduled": "^1.5.0",
"@solidjs/router": "^0.14.7",
"@t3-oss/env-core": "^0.11.0",
"@tanstack/solid-query": "^5.56.2",
"@tauri-apps/api": "^2.0.3",
"@tauri-apps/plugin-clipboard-manager": "^2.0.0",
"@tauri-apps/plugin-dialog": "^2.0.1",
"@tauri-apps/plugin-shell": "^2.0.1",
"@unocss/reset": "^0.63.6",
"@untitled-theme/icons-solid": "^0.11.0",
"overlayscrollbars": "^2.10.0",
"overlayscrollbars-solid": "^0.5.5",
"pathe": "^1.1.2",
"solid-js": "^1.9.1",
"solid-transition-group": "^0.2.3",
"zod": "^3.23.8"
},
"devDependencies": {
"@sentry/vite-plugin": "^2.22.4",
"@tauri-apps/cli": "^2.0.4",
"rollup-plugin-visualizer": "^5.12.0",
"sass": "^1.79.4",
"unocss": "^0.63.6",
"vite": "^5.4.8",
"vite-plugin-solid": "^2.10.2",
"vite-plugin-solid-svg": "^0.8.1",
"vite-tsconfig-paths": "^5.0.1"
}
}

View file

@ -1,7 +1,7 @@
import { getProgramInfo } from '@onelauncher/client';
import { type ParentProps, onMount } from 'solid-js';
import AnimatedRoutes from '~ui/components/AnimatedRoutes';
import { NotificationProvider } from '~ui/hooks/useNotifications';
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';

View file

@ -0,0 +1,41 @@
<svg width="252" height="277" viewBox="0 0 252 277" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_3343_6980)">
<path d="M67.788 0H209.21C211.07 0 212.854 0.738831 214.169 2.05396C215.484 3.36909 216.223 5.15279 216.223 7.01266V97.0084C216.223 98.8683 215.484 100.652 214.169 101.967C212.854 103.282 211.07 104.021 209.21 104.021H67.788C65.9282 104.021 64.1445 103.282 62.8294 101.967C61.5142 100.652 60.7754 98.8683 60.7754 97.0084V7.01266C60.7754 5.15279 61.5142 3.36909 62.8294 2.05396C64.1445 0.738831 65.9282 0 67.788 0Z" fill="#BADDF6"/>
<path d="M25.7119 24.5444H167.134C168.994 24.5444 170.777 25.2833 172.093 26.5984C173.408 27.9135 174.146 29.6972 174.146 31.5571V121.553C174.146 123.413 173.408 125.196 172.093 126.512C170.777 127.827 168.994 128.566 167.134 128.566H25.7119C23.852 128.566 22.0683 127.827 20.7532 126.512C19.4381 125.196 18.6992 123.413 18.6992 121.553V31.5571C18.6992 29.6972 19.4381 27.9135 20.7532 26.5984C22.0683 25.2833 23.852 24.5444 25.7119 24.5444Z" fill="url(#paint0_linear_3343_6980)"/>
<path d="M23.3745 262.974C17.175 262.974 11.2294 260.512 6.84561 256.128C2.46185 251.745 -0.000976562 245.799 -0.000976562 239.599V139.084C-0.000976562 132.885 2.46185 126.938 6.84561 122.555C11.2294 118.171 17.175 115.709 23.3745 115.709H111.383C126.171 115.637 126.227 101.007 126.227 101.007V100.515C126.227 96.7948 127.704 93.2274 130.335 90.5971C132.965 87.9668 136.532 86.4893 140.252 86.4893H219.729C223.449 86.4893 227.016 87.9668 229.646 90.5971C232.277 93.2274 233.754 96.7948 233.754 100.515V239.599C233.754 245.799 231.291 251.745 226.908 256.128C222.524 260.512 216.578 262.974 210.379 262.974H23.3745Z" fill="url(#paint1_linear_3343_6980)"/>
<path opacity="0.81" d="M33.8933 142.59H92.3322C94.502 142.59 96.583 143.452 98.1173 144.987C99.6516 146.521 100.514 148.602 100.514 150.772V156.616C100.514 158.785 99.6516 160.866 98.1173 162.401C96.583 163.935 94.502 164.797 92.3322 164.797H33.8933C31.7235 164.797 29.6425 163.935 28.1082 162.401C26.5739 160.866 25.7119 158.785 25.7119 156.616V150.772C25.7119 148.602 26.5739 146.521 28.1082 144.987C29.6425 143.452 31.7235 142.59 33.8933 142.59Z" fill="url(#paint2_linear_3343_6980)"/>
<path d="M225.573 155.447H155.446C141.246 155.447 129.733 166.959 129.733 181.16V251.287C129.733 265.488 141.246 277 155.446 277H225.573C239.774 277 251.286 265.488 251.286 251.287V181.16C251.286 166.959 239.774 155.447 225.573 155.447Z" fill="url(#paint3_linear_3343_6980)"/>
<path d="M225.573 156.032H155.446C141.568 156.032 130.317 167.282 130.317 181.16V251.287C130.317 265.165 141.568 276.416 155.446 276.416H225.573C239.451 276.416 250.701 265.165 250.701 251.287V181.16C250.701 167.282 239.451 156.032 225.573 156.032Z" stroke="white" stroke-opacity="0.5"/>
<path opacity="0.75" d="M186.124 241.362L171.808 223.505C171.164 222.693 170.764 221.714 170.655 220.683C170.546 219.652 170.732 218.611 171.192 217.682C171.651 216.753 172.365 215.974 173.25 215.435C174.135 214.895 175.155 214.618 176.192 214.636H184.232V192.508C184.232 191.578 184.601 190.686 185.259 190.029C185.916 189.371 186.808 189.001 187.738 189.001H193.98C194.91 189.001 195.802 189.371 196.46 190.029C197.117 190.686 197.486 191.578 197.486 192.508V214.629H204.827C205.863 214.611 206.884 214.888 207.769 215.427C208.655 215.966 209.368 216.746 209.828 217.675C210.287 218.605 210.473 219.645 210.363 220.676C210.254 221.707 209.855 222.685 209.211 223.497L194.894 241.356C194.365 242.008 193.696 242.535 192.937 242.896C192.178 243.258 191.348 243.445 190.507 243.445C189.667 243.445 188.836 243.258 188.077 242.896C187.318 242.535 186.65 242.008 186.12 241.356L186.124 241.362Z" fill="#2B4BFF"/>
<path opacity="0.83" d="M40.3217 39.7383H83.5664C85.5812 39.7383 87.5136 40.5387 88.9383 41.9634C90.363 43.3881 91.1634 45.3205 91.1634 47.3353C91.1634 49.3502 90.363 51.2825 88.9383 52.7073C87.5136 54.132 85.5812 54.9324 83.5664 54.9324H40.3217C38.3068 54.9324 36.3745 54.132 34.9497 52.7073C33.525 51.2825 32.7246 49.3502 32.7246 47.3353C32.7246 45.3205 33.525 43.3881 34.9497 41.9634C36.3745 40.5387 38.3068 39.7383 40.3217 39.7383Z" fill="url(#paint4_linear_3343_6980)"/>
<path opacity="0.5" d="M35.6466 67.7891H85.9039C86.6789 67.7891 87.4221 68.0969 87.9701 68.6449C88.518 69.1928 88.8259 69.9361 88.8259 70.711C88.8259 71.486 88.518 72.2292 87.9701 72.7771C87.4221 73.3251 86.6789 73.6329 85.9039 73.6329H35.6466C34.8716 73.6329 34.1284 73.3251 33.5804 72.7771C33.0325 72.2292 32.7246 71.486 32.7246 70.711C32.7246 69.9361 33.0325 69.1928 33.5804 68.6449C34.1284 68.0969 34.8716 67.7891 35.6466 67.7891Z" fill="#11171C"/>
<path opacity="0.5" d="M35.6466 79.4771H71.8786C72.6536 79.4771 73.3968 79.7849 73.9447 80.3329C74.4927 80.8808 74.8006 81.624 74.8006 82.399C74.8006 83.1739 74.4927 83.9171 73.9447 84.4651C73.3968 85.0131 72.6536 85.3209 71.8786 85.3209H35.6466C34.8716 85.3209 34.1284 85.0131 33.5804 84.4651C33.0325 83.9171 32.7246 83.1739 32.7246 82.399C32.7246 81.624 33.0325 80.8808 33.5804 80.3329C34.1284 79.7849 34.8716 79.4771 35.6466 79.4771Z" fill="#11171C"/>
<path opacity="0.5" d="M99.9288 67.7891H111.617C112.391 67.7891 113.135 68.0969 113.683 68.6449C114.231 69.1928 114.538 69.9361 114.538 70.711C114.538 71.486 114.231 72.2292 113.683 72.7771C113.135 73.3251 112.391 73.6329 111.617 73.6329H99.9288C99.1538 73.6329 98.4106 73.3251 97.8627 72.7771C97.3147 72.2292 97.0068 71.486 97.0068 70.711C97.0068 69.9361 97.3147 69.1928 97.8627 68.6449C98.4106 68.0969 99.1538 67.7891 99.9288 67.7891Z" fill="#11171C"/>
<path opacity="0.5" d="M35.6466 91.1646H43.828C44.6029 91.1646 45.3461 91.4724 45.8941 92.0204C46.4421 92.5683 46.7499 93.3115 46.7499 94.0865C46.7499 94.8614 46.4421 95.6046 45.8941 96.1526C45.3461 96.7006 44.6029 97.0084 43.828 97.0084H35.6466C34.8716 97.0084 34.1284 96.7006 33.5804 96.1526C33.0325 95.6046 32.7246 94.8614 32.7246 94.0865C32.7246 93.3115 33.0325 92.5683 33.5804 92.0204C34.1284 91.4724 34.8716 91.1646 35.6466 91.1646Z" fill="#11171C"/>
</g>
<defs>
<linearGradient id="paint0_linear_3343_6980" x1="79.6345" y1="25.8967" x2="94.7541" y2="122.592" gradientUnits="userSpaceOnUse">
<stop stop-color="#E4F3FE"/>
<stop offset="1" stop-color="#D1E5F3"/>
</linearGradient>
<linearGradient id="paint1_linear_3343_6980" x1="6" y1="125.5" x2="103.202" y2="251.784" gradientUnits="userSpaceOnUse">
<stop stop-color="#747DFF"/>
<stop offset="1" stop-color="#2B4BFF"/>
</linearGradient>
<linearGradient id="paint2_linear_3343_6980" x1="51.8925" y1="142.08" x2="54.2642" y2="166.92" gradientUnits="userSpaceOnUse">
<stop stop-color="white"/>
<stop offset="1" stop-color="#E1F2FF"/>
</linearGradient>
<linearGradient id="paint3_linear_3343_6980" x1="172.277" y1="152.652" x2="212.268" y2="277" gradientUnits="userSpaceOnUse">
<stop stop-color="#EAF6FF"/>
<stop offset="1" stop-color="#C6E1F5"/>
</linearGradient>
<linearGradient id="paint4_linear_3343_6980" x1="34.1856" y1="40.8323" x2="40.9981" y2="67.1476" gradientUnits="userSpaceOnUse">
<stop stop-color="#A191FF"/>
<stop offset="1" stop-color="#516CFF"/>
</linearGradient>
<clipPath id="clip0_3343_6980">
<rect width="251.286" height="277" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 7 KiB

View file

@ -0,0 +1,38 @@
<svg width="319" height="277" viewBox="0 0 319 277" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M123.043 246.222C190.998 246.222 246.086 191.104 246.086 123.111C246.086 55.1187 190.998 0 123.043 0C55.0882 0 0 55.1187 0 123.111C0 191.104 55.0882 246.222 123.043 246.222Z" fill="url(#paint0_linear_3343_6724)"/>
<mask id="mask0_3343_6724" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="0" y="0" width="247" height="247">
<path d="M123.043 246.222C190.998 246.222 246.086 191.104 246.086 123.111C246.086 55.1187 190.998 0 123.043 0C55.0882 0 0 55.1187 0 123.111C0 191.104 55.0882 246.222 123.043 246.222Z" fill="white"/>
</mask>
<g mask="url(#mask0_3343_6724)">
<path opacity="0.77" d="M206.791 198.326C203.4 187.661 211.376 176.767 203.959 159.122C196.542 141.478 190.524 145.731 184.325 134.945C178.126 124.159 185.887 120.568 179.165 115.976C175.679 113.595 172.615 115.463 169.434 117.33C166.478 119.064 163.422 120.799 159.83 119.132C152.369 115.668 153.317 106.251 147.467 100.365C141.616 94.4799 107.864 101.061 109.737 86.285C111.61 71.5094 161.369 52.1559 168.568 52.1604C175.768 52.165 179.291 64.7588 191.038 66.9406C196.782 68.0075 203.408 65.3447 209.862 62.6739C216.61 59.8868 223.172 57.1008 228.346 58.577C238.469 61.4656 318.417 137.044 318.417 137.044L233.795 216.383C217.533 201.777 210.185 208.99 206.791 198.326ZM89.7868 209.651C81.1954 208.398 67.3428 194.749 59.86 181.648C52.3772 168.547 64.3032 163.962 59.86 157.254C55.4168 150.546 41.7636 140.598 39.9088 136.735C38.0541 132.873 45.6577 126.269 39.9088 118.155C34.16 110.041 25.776 118.292 16.9089 104.291C8.04187 90.2907 4.43945 62.1518 4.43945 62.1518L67.6197 -12.4319L79.4945 6.62298L96.3616 18.6457C96.3616 18.6457 120.111 31.7969 119.16 40.8023C118.209 49.8076 94.4248 52.8979 92.5586 54.6637C90.6925 56.4294 92.9004 63.8138 84.2419 71.2996C75.5833 78.7855 65.0563 75.3201 57.9198 84.607C57.9198 84.607 56.8386 90.2679 56.2849 96.2342C55.7312 102.201 55.7073 108.452 55.7073 108.452C57.7979 111.522 60.5891 110.014 64.2223 108.504C67.8134 107.014 72.2247 105.522 77.5975 108.452C88.4037 114.344 98.9341 132.02 98.9341 132.02C98.9341 132.02 123.043 133.197 125.814 140.613C128.586 148.03 111.874 158.585 110.016 161.686C108.158 164.787 111.47 169.527 107.522 175.765C103.574 182.003 99.2782 177.835 94.222 186.639C89.3595 195.105 97.6911 209.721 90.6993 209.722C90.3938 209.721 90.0889 209.697 89.7868 209.651Z" fill="url(#paint1_linear_3343_6724)" fill-opacity="0.8"/>
</g>
<g filter="url(#filter0_d_3343_6724)">
<path d="M284.821 104.872H173.171C158.7 104.872 146.968 116.611 146.968 131.09V242.802C146.968 257.282 158.7 269.02 173.171 269.02H284.821C299.293 269.02 311.025 257.282 311.025 242.802V131.09C311.025 116.611 299.293 104.872 284.821 104.872Z" fill="url(#paint2_linear_3343_6724)"/>
<path d="M284.821 105.442H173.171C159.014 105.442 147.537 116.925 147.537 131.091V242.802C147.537 256.968 159.014 268.451 173.171 268.451H284.821C298.978 268.451 310.455 256.968 310.455 242.802V131.091C310.455 116.925 298.978 105.442 284.821 105.442Z" stroke="white" stroke-opacity="0.5"/>
</g>
<path d="M266.21 220.077L240.946 150.478C239.852 147.628 238.43 146.867 235.258 146.867H222.79C219.618 146.867 218.196 147.524 217.103 150.697L191.947 220.077C190.853 223.032 191.514 224.564 194.9 224.564H206.384C211.853 224.564 213.275 223.36 214.368 219.968L216.884 212.088H240.503L243.019 219.968C243.899 223.36 245.539 224.564 251.226 224.564H263.039C266.32 224.564 267.304 223.032 266.21 220.077ZM231.54 182.104L235.586 194.908H221.915L225.962 181.995C227.325 177.039 228.024 171.924 228.04 166.784H229.133C229.356 171.965 230.163 177.104 231.54 182.104Z" fill="#2B4BFF" fill-opacity="0.76"/>
<defs>
<filter id="filter0_d_3343_6724" x="138.968" y="96.8723" width="176.058" height="176.148" filterUnits="userSpaceOnUse" color-interpolation-filters="sRGB">
<feFlood flood-opacity="0" result="BackgroundImageFix"/>
<feColorMatrix in="SourceAlpha" type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 127 0" result="hardAlpha"/>
<feOffset dx="-2" dy="-2"/>
<feGaussianBlur stdDeviation="3"/>
<feColorMatrix type="matrix" values="0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0.078 0"/>
<feBlend mode="normal" in2="BackgroundImageFix" result="effect1_dropShadow_3343_6724"/>
<feBlend mode="normal" in="SourceGraphic" in2="effect1_dropShadow_3343_6724" result="shape"/>
</filter>
<linearGradient id="paint0_linear_3343_6724" x1="63.244" y1="2.78205e-06" x2="195.749" y2="233.109" gradientUnits="userSpaceOnUse">
<stop stop-color="#7A64FF"/>
<stop offset="0.481" stop-color="#415EFF"/>
<stop offset="1" stop-color="#2B4BFF"/>
</linearGradient>
<linearGradient id="paint1_linear_3343_6724" x1="102.401" y1="-12.4319" x2="134.26" y2="220.105" gradientUnits="userSpaceOnUse">
<stop stop-color="#EAF6FF"/>
<stop offset="1" stop-color="#C6E1F5"/>
</linearGradient>
<linearGradient id="paint2_linear_3343_6724" x1="190.607" y1="102.082" x2="254.159" y2="268.997" gradientUnits="userSpaceOnUse">
<stop stop-color="#C8D6F5"/>
<stop offset="1" stop-color="#B6CCFC"/>
</linearGradient>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 321 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 340 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 683 B

View file

@ -0,0 +1,3 @@
<svg width="252" height="161" viewBox="0 0 252 161" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M192.422 50.7705C192.422 50.7705 243.874 42.6221 252 18.8572H173.181V0H0L21.3339 24.8619V50.3349C21.3339 50.3349 75.1642 47.5237 95.9867 63.3816C124.489 89.9139 63.9294 125.779 63.9294 125.779L53.5449 160.291C69.7837 144.762 100.733 124.673 157.478 125.641C135.884 132.495 114.171 143.201 97.2667 160.291H211.977L201.175 125.779C201.175 125.779 118.036 76.5444 192.422 50.7736V50.7705Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 529 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 127.14 96.36"><path fill="currentColor" d="M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z"/></svg>

After

Width:  |  Height:  |  Size: 769 B

View file

@ -0,0 +1 @@
<svg viewBox="0 0 2084 2084" xmlns="http://www.w3.org/2000/svg" fill-rule="evenodd" clip-rule="evenodd" stroke-linejoin="round" stroke-miterlimit="2"><g fill-rule="nonzero"><path d="M1041.67 81.38l272.437 159.032-825.246 478.685-272.438-157.971L1041.67 81.38zm87.28 371.074l274.024-159.032 463.937 271.945-276.14 153.73-461.821-266.643z" fill="#3b3b3b"/><path d="M216.42 561.126v961.081l825.247 479.746V1684.95l-551.222-321.774-1.587-644.079L216.42 561.126z" fill="#2e2e2e"/><path d="M1866.91 1517.97l-825.246 483.986v-317.003l550.164-320.714-1.058-645.139 276.14-153.73v952.6z" fill="#333"/><path d="M1590.77 719.097l-549.106 310.112v165.393l214.246-122.984v488.757l138.599-81.106V989.451l196.261-115.563V719.097z" fill="#89c236"/><path d="M488.858 719.097l1.587 644.079 152.353 90.118v-198.79l230.645 132.527v199.319l168.753 98.6v-655.741L488.858 719.097zm383.527 531.166l-227.471-131.466v-150.02l227.471 127.225v154.261z" fill="#7baf31"/></g></svg>

After

Width:  |  Height:  |  Size: 952 B

View file

@ -0,0 +1 @@
<svg fill="none" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1175 889"><path d="m1174.14 355.903-29.88-21.468 9.11-21.068V112.095L1033.12 0H117.189L.139 117.05v535.656l26.974 48.541H.14v187.46h1174v-187.46h-26.97l26.97-48.541V355.903ZM254.706 652.706V485.413h97.634l39.083-70.309V276.235h35.88v376.471l26.973 48.541H227.734l26.972-48.541Zm400.892 48.541 26.973-48.541V276.235h17.465v286.694l25.772 61.453 76.915 76.865H655.598Z" fill="#fff"/><path d="m1119.69 341.239 13.81-31.977V120.751L1025.31 19.865H125.395l-105.39 105.39V647.55l30.876 55.597h153.081l30.876-55.597V465.545h105.84l30.876-55.598v-153.58h75.565V647.55l30.876 55.597h153.781l30.876-55.597V256.367h57.199v302.557l22.669 54.146 90.127 90.077h290.743l30.88-55.597V366.06l-34.58-24.821Z" fill="#322A2A"/><path d="m185.249 433.77 17.815 205.525-17.815 32.077H69.6l-17.815-32.077L69.6 195.617l76.365-76.365h187.46l17.815 73.212-17.815 32.078H185.249v105.99h136.716l17.815 71.161-17.815 32.077H185.249Z" fill="#65ADB9"/><path d="M717.351 224.59H613.112l17.815 414.754-17.815 32.077H496.763l-17.815-32.077 17.815-414.754H388.671l-17.815-32.077 17.815-73.212h328.68l17.815 73.212-17.815 32.077Z" fill="#9FC41E"/><path d="m1104.68 441.374 17.82 197.969-17.82 32.077H845.761l-76.365-76.365-17.815-42.486 17.815-433.219h236.354l78.16 72.862 17.82 110.544-17.82 41.335-54.24 43.487 75.01 53.846v-.05ZM969.616 338.186V224.589h-84.522v113.597h84.522Zm18.716 228.595V441.424H885.144v125.357h103.188Z" fill="#E65014"/><path d="M51.785 138.419v500.927h151.279V401.744H339.78V262.925H203.064v-70.409H351.24V51.646H138.559l-86.774 86.773Z" fill="#0787C1"/><path d="M370.807 192.516h108.092v446.83h151.98v-446.83h104.289V51.646H370.807v140.87Z" fill="#798B2F"/><path d="m1059.14 336.838 42.59-34.179V134.566l-88.93-82.92H751.629v500.876l86.824 86.774h284.097V382.327l-63.36-45.539-.05.05ZM902.908 499.077V409.3h67.608v89.777h-67.608Zm0-228.595v-77.967H951.8v77.967h-48.892Z" fill="#B11917"/><path d="M185.246 383.927v237.602H69.598V145.774l76.365-76.365h187.459V174.7H185.246v105.99h136.717v103.188H185.246v.05ZM717.348 174.748H613.11v446.78H496.761v-446.78H388.668V69.458h328.68v105.29ZM1104.68 391.532v229.996H845.758l-76.365-76.365V69.458h236.347l78.17 72.862v151.829l-54.25 43.487 75.02 53.846v.05ZM969.614 288.344V174.748h-84.522v113.596h84.522Zm18.716 228.595V391.582H885.142v125.357H988.33Z" fill="#fff"/><path d="M1154.27 721.112H20.005v147.726H1154.27V721.112Z" fill="#322A2A"/><path d="M71.45 802.433v38.933H52.483v-77.967l12.511-12.51H95.72v17.214H71.45v17.465h22.419v16.915h-22.42v-.05ZM129.248 750.889h43.937v17.214h-25.171v17.465h23.92v16.915h-23.67v21.768h25.522v17.165h-44.538v-90.527ZM206.364 750.889h43.938v17.214H225.13v17.465h23.921v16.915H225.38v21.768h25.522v17.165h-44.538v-90.527ZM283.481 750.89h38.933l14.563 14.312v63.604l-12.711 12.511h-40.785V750.84v.05Zm34.479 73.312v-56.097h-15.513v56.097h15.513ZM478.849 768.103h-17.065v73.263h-19.066v-73.263h-17.715v-17.214h53.846v17.214ZM531.089 788.07h16.264v-37.181h18.966v90.477h-18.966v-36.181h-16.264v36.181h-18.966v-90.477h18.966v37.181ZM600.049 750.889h43.938v17.214h-25.172v17.465h23.921v16.915h-23.67v21.768h25.521v17.165h-44.538v-90.527ZM786.91 803.684v37.682h-42.436l-12.511-12.511v-77.966h38.783l12.811 11.96v24.921l-8.907 7.156 12.21 8.808.05-.05Zm-22.069-16.915v-18.716H750.93v18.716h13.911Zm3.053 37.432v-20.517H750.93v20.517h16.964ZM820.54 750.889h43.937v17.214h-25.171v17.465h23.92v16.915h-23.67v21.768h25.522v17.165H820.54v-90.527ZM916.668 841.365h-19.017V765.25l14.563-14.312h39.533v90.477h-18.966v-29.726h-16.164v29.726l.051-.05Zm16.163-46.94v-26.323h-16.163v26.323h16.163ZM1035.57 841.367h-49.743v-28.174h18.963v11.009h11.76V809.79l-30.072-22.719V750.84h48.542v26.923h-17.22v-9.658h-12.41v11.81l30.18 22.669V841.367ZM1123.25 768.103h-17.07v73.263h-19.07v-73.263h-17.71v-17.214h53.85v17.214Z" fill="#E0E0E0"/></svg>

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

View file

@ -0,0 +1,52 @@
<svg width="48" height="48" version="1.1" viewBox="0 0 12.7 12.7" xmlns="http://www.w3.org/2000/svg" xmlns:cc="http://creativecommons.org/ns#" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">
<title>Prism Launcher Logo</title>
<metadata>
<rdf:RDF>
<cc:Work rdf:about="">
<dc:title>Prism Launcher Logo</dc:title>
<dc:date>19/10/2022</dc:date>
<dc:creator>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:creator>
<dc:contributor>
<cc:Agent>
<dc:title>AutiOne, Boba, ely, Fulmine, gon sawa, Pankakes, tobimori, Zeke</dc:title>
</cc:Agent>
</dc:contributor>
<dc:source>https://github.com/PrismLauncher/PrismLauncher</dc:source>
<dc:publisher>
<cc:Agent>
<dc:title>Prism Launcher</dc:title>
</cc:Agent>
</dc:publisher>
<cc:license rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/"/>
</cc:Work>
<cc:License rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits rdf:resource="http://creativecommons.org/ns#Reproduction"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#Distribution"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Notice"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#Attribution"/>
<cc:permits rdf:resource="http://creativecommons.org/ns#DerivativeWorks"/>
<cc:requires rdf:resource="http://creativecommons.org/ns#ShareAlike"/>
</cc:License>
</rdf:RDF>
</metadata>
<g stroke-width=".26458">
<g>
<path d="m6.35 0.52917-2.5208 4.3656 2.5208 1.4552 2.5203-1.4552 0.10955-3.0996c-1.1511-0.66459-2.3388-1.2661-2.6298-1.2661z" fill="#df6277"/>
<path d="m8.9798 1.7952-2.6298 4.5548 2.5203 1.4552 2.5208-4.3656c-0.14552-0.25205-1.2601-0.97975-2.4112-1.6443z" fill="#fb9168"/>
<path d="m11.391 3.4396-5.041 2.9104 2.5203 1.4552 2.7389-1.4552c0-1.3292-0.07255-2.6584-0.21808-2.9104z" fill="#f3db6c"/>
<path d="m6.35 6.35v2.9104h5.041c0.14552-0.25205 0.21807-1.5812 0.21808-2.9104z" fill="#7ab392"/>
<path d="m6.35 6.35v2.9104l2.6298 1.6443c1.1511-0.66459 2.2657-1.3923 2.4112-1.6443z" fill="#4b7cbc"/>
<path d="m6.35 6.35-2.5208 1.4552 2.5208 4.3656c0.29104 0 1.4787-0.60148 2.6298-1.2661z" fill="#6f488c"/>
<path d="m3.8292 4.8948-2.5203 4.3656c0.29104 0.5041 4.459 2.9104 5.041 2.9104v-5.8208z" fill="#4d3f33"/>
<path d="m1.309 3.4396c-0.29104 0.5041-0.29104 5.3167 0 5.8208l5.041-2.9104v-2.9104z" fill="#7a573b"/>
<path d="m6.35 0.52917c-0.58208-2e-8 -4.75 2.4063-5.041 2.9104l5.041 2.9104z" fill="#99cd61"/>
</g>
<path transform="matrix(.85338 0 0 .85338 .93132 .93123)" d="m6.3498 2.9393c-0.34105 0-2.7827 1.4099-2.9532 1.7052l2.9532 5.1157 2.9538-5.1157c-0.17052-0.29535-2.6127-1.7052-2.9538-1.7052z" fill="#fff"/>
<path transform="matrix(.88 0 0 .88 -10.906 -1.2421)" d="m16.746 6.9737 2.8639 4.9609c0.33073 0 2.6991-1.3672 2.8644-1.6536 0.16536-0.28642 0.16536-3.0209 0-3.3073l-2.8644 1.6536z" fill="#dfdfdf"/>
<path d="m3.8299 4.8948c-0.14551 0.25205-0.14553 2.6584 0 2.9104 0.14553 0.25204 2.2292 1.4552 2.5203 1.4552v-2.9104z" fill="#d6d2d2"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

View file

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 21 21" width="21" height="21">
<path fill="#f35325" d="M0 0h10v10H0z" />
<path fill="#81bc06" d="M11 0h10v10H11z" />
<path fill="#05a6f0" d="M0 11h10v10H0z" />
<path fill="#ffba08" d="M11 11h10v10H11z" />
</svg>

After

Width:  |  Height:  |  Size: 269 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

View file

@ -0,0 +1,4 @@
<svg width="64" height="64" viewBox="0 0 512 514" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M503.16 323.56C514.55 281.47 515.32 235.91 503.2 190.76C466.57 54.2299 326.04 -26.8001 189.33 9.77991C83.8101 38.0199 11.3899 128.07 0.689941 230.47H43.99C54.29 147.33 113.74 74.7298 199.75 51.7098C306.05 23.2598 415.13 80.6699 453.17 181.38L411.03 192.65C391.64 145.8 352.57 111.45 306.3 96.8198L298.56 140.66C335.09 154.13 364.72 184.5 375.56 224.91C391.36 283.8 361.94 344.14 308.56 369.17L320.09 412.16C390.25 383.21 432.4 310.3 422.43 235.14L464.41 223.91C468.91 252.62 467.35 281.16 460.55 308.07L503.16 323.56Z" fill="#00af5c"/>
<path d="M321.99 504.22C185.27 540.8 44.7501 459.77 8.11011 323.24C3.84011 307.31 1.17 291.33 0 275.46H43.27C44.36 287.37 46.4699 299.35 49.6799 311.29C53.0399 323.8 57.45 335.75 62.79 347.07L101.38 323.92C98.1299 316.42 95.39 308.6 93.21 300.47C69.17 210.87 122.41 118.77 212.13 94.7601C229.13 90.2101 246.23 88.4401 262.93 89.1501L255.19 133C244.73 133.05 234.11 134.42 223.53 137.25C157.31 154.98 118.01 222.95 135.75 289.09C136.85 293.16 138.13 297.13 139.59 300.99L188.94 271.38L174.07 231.95L220.67 184.08L279.57 171.39L296.62 192.38L269.47 219.88L245.79 227.33L228.87 244.72L237.16 267.79C237.16 267.79 253.95 285.63 253.98 285.64L277.7 279.33L294.58 260.79L331.44 249.12L342.42 273.82L304.39 320.45L240.66 340.63L212.08 308.81L162.26 338.7C187.8 367.78 226.2 383.93 266.01 380.56L277.54 423.55C218.13 431.41 160.1 406.82 124.05 361.64L85.6399 384.68C136.25 451.17 223.84 484.11 309.61 461.16C371.35 444.64 419.4 402.56 445.42 349.38L488.06 364.88C457.17 431.16 398.22 483.82 321.99 504.22Z" fill="#00af5c"/>
</svg>

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,5 @@
<svg viewBox="0 0 32 32" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M30.5066 12.693C30.5528 12.7766 30.6013 12.8641 30.6389 12.9553C31.4253 14.606 31.3934 16.9885 30.4923 18.6027L27.2136 24.2779C26.2441 22.7962 24.886 21.5249 23.2535 20.5646C23.2947 20.5007 23.3312 20.4366 23.3632 20.3725C26.2579 14.5146 23.2535 6.77718 16.0008 6.89151C8.62014 6.76804 5.70242 14.6472 8.72531 20.5829C7.10177 21.5433 5.75289 22.8098 4.78784 24.2871C4.76529 24.239 4.4442 23.6872 4.00388 22.9301C2.93343 21.0898 1.15761 18.0374 1.2485 18.0632C0.640255 16.5907 0.649417 14.5785 1.28511 13.1244C1.32329 13.0218 1.37063 12.9229 1.42043 12.8278C1.4481 12.7746 1.47669 12.7226 1.5046 12.6717L6.17803 4.56842C6.18495 4.55916 6.19077 4.54867 6.19656 4.53828C6.20238 4.52812 6.20795 4.51807 6.21465 4.50903C7.17947 2.90392 9.46148 1.60059 11.3226 1.60059H20.6697C22.7915 1.60059 24.7534 2.73468 25.8098 4.56842C25.8205 4.58193 27.4458 7.39536 28.7785 9.70205C29.7019 11.3007 30.4847 12.6558 30.4923 12.6671L30.5066 12.693Z" fill="currentColor"/>
<path d="M11.7015 23.5876C14.157 24.9777 17.8794 24.9731 20.2801 23.5784C22.3289 24.5935 23.8197 26.3222 24.2816 28.3526C23.2709 29.0979 22.027 29.6055 20.9021 29.6604C20.829 29.6696 20.7467 29.6696 20.6735 29.6696C20.6095 29.6679 19.3378 29.6687 17.7459 29.6697H17.6627C14.9349 29.6714 11.3248 29.6736 11.2076 29.665C10.0552 29.6376 8.76098 29.1253 7.72292 28.3526C8.17575 26.3268 9.66196 24.6027 11.7015 23.5876Z" fill="currentColor"/>
<path d="M20.6189 15.6397C20.7788 22.0189 11.2214 22.0143 11.3815 15.6397C11.2946 9.22384 20.7011 9.22384 20.6189 15.6397Z" fill="currentColor"/>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,12 @@
<svg width="256" height="256" viewBox="0 0 256 256" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1_929)">
<path fill-rule="evenodd" clip-rule="evenodd" d="M198.963 132.03C194.735 156.226 182.08 178.145 163.24 193.904L117.79 231.92C115.64 233.718 116.912 237.221 119.715 237.221H163.665C181.886 237.221 198.722 227.501 207.833 211.721L243.388 150.138C252.498 134.358 252.498 114.917 243.388 99.1378L217.826 54.8638C216.425 52.4361 212.755 53.0861 212.273 55.8474L198.963 132.03ZM141.106 12.0544C143.909 12.0544 145.181 15.5571 143.031 17.3556L84.7602 66.0956C65.9197 81.8546 53.2649 103.773 49.0375 127.969L39.0752 184.989C38.5928 187.75 34.9235 188.4 33.5219 185.973L12.8327 150.138C3.72243 134.358 3.72243 114.917 12.8327 99.1378L48.3878 37.5544C57.4981 21.775 74.3346 12.0544 92.5551 12.0544H141.106Z" fill="#0048C5"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M187.195 27.4682C187.797 23.825 183.563 21.3803 180.71 23.724L88.0828 99.7989C81.7655 104.987 82.4025 114.773 89.1711 119.142C101.262 111.22 115.497 109.958 131.362 119.118C147.058 128.179 152.443 140.754 150.95 154.749C157.996 157.877 166.329 153.557 167.625 145.723L187.195 27.4682Z" fill="#0A5BE8"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M112.759 126.51C104.564 137.059 99.292 156.87 100.491 169.357C100.557 170.045 101.291 170.42 101.889 170.074C111.732 164.389 126.758 149.977 132.285 137.756C154.512 165.269 98.975 218.202 66.2935 233.188C64.931 233.812 63.3862 233.023 63.0927 231.554C55.1404 191.715 77.0758 120.558 112.759 126.51Z" fill="#0A5BE8"/>
</g>
<defs>
<clipPath id="clip0_1_929">
<rect width="256" height="256" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 1.6 KiB

View file

@ -0,0 +1,15 @@
<svg width="227" height="23" viewBox="0 0 227 23" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M27.3184 21.1792V1.66849H30.3582L31.6571 5.56511V21.1792H27.3184ZM40.7767 21.1792L29.2805 6.44945L30.3582 1.66849L41.8544 16.3983L40.7767 21.1792ZM40.7767 21.1792L39.616 17.2826V1.66849H43.9547V21.1792H40.7767Z" fill="#5187F1"/>
<path d="M49.379 21.1792V1.66849H53.7177V21.1792H49.379ZM52.6952 21.1792V17.4208H63.39V21.1792H52.6952ZM52.6952 13.0267V9.40646H62.4228V13.0267H52.6952ZM52.6952 5.3993V1.66849H63.2518V5.3993H52.6952Z" fill="#5187F1"/>
<path d="M68.0392 21.1792V1.66849H72.3779V21.1792H68.0392ZM71.383 21.1792V17.3655H81.0277V21.1792H71.383Z" fill="#1878F1"/>
<path d="M83.1836 21.1792L90.9215 1.66849H94.8457L102.501 21.1792H97.9132L92.0545 4.98476H93.6297L87.6882 21.1792H83.1836ZM87.5776 17.6419V14.1045H98.2172V17.6419H87.5776Z" fill="#1878F1"/>
<path d="M113.856 21.4832C112.253 21.4832 110.834 21.1424 109.6 20.4607C108.384 19.779 107.426 18.8394 106.726 17.6419C106.044 16.4259 105.703 15.0441 105.703 13.4965V1.66849H110.07V13.7452C110.07 14.519 110.235 15.1915 110.567 15.7626C110.899 16.3338 111.35 16.776 111.921 17.0892C112.511 17.3839 113.156 17.5313 113.856 17.5313C114.593 17.5313 115.237 17.3839 115.79 17.0892C116.343 16.776 116.776 16.343 117.089 15.7903C117.421 15.2191 117.586 14.5467 117.586 13.7729V1.66849H121.953V13.5242C121.953 15.0718 121.612 16.4443 120.93 17.6419C120.249 18.8394 119.3 19.779 118.084 20.4607C116.868 21.1424 115.458 21.4832 113.856 21.4832Z" fill="#1878F1"/>
<path d="M127.069 21.1792V1.66849H130.109L131.408 5.56511V21.1792H127.069ZM140.528 21.1792L129.031 6.44945L130.109 1.66849L141.605 16.3983L140.528 21.1792ZM140.528 21.1792L139.367 17.2826V1.66849H143.706V21.1792H140.528Z" fill="#1878F1"/>
<path d="M158.388 21.4832C156.932 21.4832 155.578 21.2345 154.325 20.7371C153.091 20.2212 152.004 19.5027 151.064 18.5815C150.143 17.6603 149.425 16.5917 148.909 15.3757C148.393 14.1414 148.135 12.8148 148.135 11.3962C148.135 9.97759 148.393 8.6603 148.909 7.44433C149.425 6.20994 150.143 5.14137 151.064 4.2386C151.986 3.33584 153.063 2.63574 154.298 2.1383C155.55 1.62243 156.905 1.3645 158.36 1.3645C159.908 1.3645 161.28 1.61322 162.478 2.11066C163.694 2.6081 164.753 3.28978 165.656 4.1557L162.754 7.08507C162.238 6.53236 161.612 6.0994 160.875 5.7862C160.156 5.47299 159.318 5.31639 158.36 5.31639C157.513 5.31639 156.73 5.46378 156.011 5.75856C155.311 6.03492 154.703 6.44024 154.187 6.97453C153.69 7.50882 153.294 8.15365 152.999 8.90902C152.722 9.66439 152.584 10.4935 152.584 11.3962C152.584 12.3174 152.722 13.1557 152.999 13.9111C153.294 14.6664 153.69 15.3113 154.187 15.8456C154.703 16.3798 155.311 16.7944 156.011 17.0892C156.73 17.3839 157.513 17.5313 158.36 17.5313C159.355 17.5313 160.221 17.3747 160.958 17.0615C161.695 16.7483 162.33 16.3154 162.865 15.7626L165.794 18.692C164.854 19.5579 163.777 20.2396 162.561 20.7371C161.363 21.2345 159.972 21.4832 158.388 21.4832Z" fill="#1878F1"/>
<path d="M169.841 21.1792V1.66849H174.18V21.1792H169.841ZM181.918 21.1792V1.66849H186.284V21.1792H181.918ZM172.439 13.0267V9.26828H183.355V13.0267H172.439Z" fill="#1878F1"/>
<path d="M191.686 21.1792V1.66849H196.025V21.1792H191.686ZM195.002 21.1792V17.4208H205.697V21.1792H195.002ZM195.002 13.0267V9.40646H204.73V13.0267H195.002ZM195.002 5.3993V1.66849H205.559V5.3993H195.002Z" fill="#1878F1"/>
<path d="M213.662 13.1373V9.93154H217.78C218.646 9.93154 219.309 9.71045 219.77 9.26828C220.249 8.82611 220.488 8.22734 220.488 7.47197C220.488 6.77187 220.258 6.19152 219.797 5.73093C219.337 5.27033 218.673 5.04003 217.808 5.04003H213.662V1.66849H218.305C219.595 1.66849 220.728 1.91721 221.704 2.41465C222.681 2.89367 223.445 3.56614 223.998 4.43205C224.551 5.29797 224.827 6.29285 224.827 7.4167C224.827 8.55897 224.551 9.56306 223.998 10.429C223.445 11.2765 222.671 11.9397 221.676 12.4187C220.682 12.8978 219.512 13.1373 218.167 13.1373H213.662ZM210.346 21.1792V1.66849H214.685V21.1792H210.346ZM220.958 21.1792L214.878 12.778L218.858 11.7002L226.098 21.1792H220.958Z" fill="#1878F1"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M17.3067 11.8423C16.9275 14.0124 15.7925 15.9783 14.1028 17.3917L10.0261 20.8016C9.83326 20.9629 9.94733 21.2771 10.1987 21.2771H14.1409C15.7751 21.2771 17.2852 20.4052 18.1023 18.99L21.2912 13.4665C22.1083 12.0513 22.1083 10.3076 21.2912 8.89238L18.9985 4.9213C18.8728 4.70357 18.5437 4.76186 18.5004 5.00952L17.3067 11.8423ZM12.1173 1.08179C12.3687 1.08179 12.4828 1.39594 12.29 1.55724L7.06395 5.92856C5.37418 7.34197 4.2392 9.30785 3.86005 11.478L2.96651 16.5923C2.92324 16.8399 2.59414 16.8982 2.46844 16.6805L0.612869 13.4665C-0.204207 12.0513 -0.204209 10.3076 0.612867 8.89238L3.8018 3.3689C4.61889 1.95363 6.12896 1.08179 7.76316 1.08179H12.1173Z" fill="#1878F1"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M16.2512 2.46364C16.3052 2.13689 15.9255 1.91762 15.6695 2.12783L7.36193 8.95102C6.79496 9.41668 6.85255 10.2952 7.46072 10.6867C8.54488 9.97687 9.82114 9.86407 11.2436 10.6853C12.6507 11.4977 13.1339 12.6249 13.0006 13.8795C13.6325 14.16 14.3797 13.7725 14.496 13.0699L16.2512 2.46364Z" fill="#5187F1"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.57397 11.3474C8.83963 12.2939 8.36735 14.0696 8.47482 15.1889C8.48074 15.2506 8.54657 15.2842 8.60023 15.2532C9.48267 14.7436 10.8298 13.4516 11.3259 12.3558C13.3204 14.8233 8.33892 19.5715 5.40756 20.9156C5.28536 20.9716 5.1468 20.9009 5.12048 20.769C4.40733 17.1963 6.37419 10.8152 9.57397 11.3474Z" fill="#5187F1"/>
</svg>

After

Width:  |  Height:  |  Size: 5.4 KiB

View file

@ -0,0 +1,13 @@
<svg width="1037" height="94" viewBox="0 0 1037 94" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M47.84 93.536C41.0133 93.536 34.6987 92.3414 28.896 89.952C23.1787 87.5627 18.144 84.2347 13.792 79.968C9.44001 75.7014 6.06934 70.752 3.68001 65.12C1.29067 59.4027 0.0960083 53.2587 0.0960083 46.688C0.0960083 40.032 1.29067 33.888 3.68001 28.256C6.06934 22.624 9.39734 17.7173 13.664 13.536C17.9307 9.26934 22.9227 5.98401 28.64 3.68001C34.4427 1.29067 40.7573 0.0960083 47.584 0.0960083C54.3253 0.0960083 60.5547 1.29067 66.272 3.68001C72.0747 5.98401 77.1093 9.26934 81.376 13.536C85.728 17.7173 89.0987 22.6667 91.488 28.384C93.8773 34.016 95.072 40.16 95.072 46.816C95.072 53.3867 93.8773 59.5307 91.488 65.248C89.0987 70.88 85.7707 75.8293 81.504 80.096C77.2373 84.2773 72.2027 87.5627 66.4 89.952C60.6827 92.3414 54.496 93.536 47.84 93.536ZM47.584 75.232C52.96 75.232 57.6533 74.0373 61.664 71.648C65.76 69.2587 68.9173 65.9307 71.136 61.664C73.3547 57.312 74.464 52.32 74.464 46.688C74.464 42.4213 73.824 38.5813 72.544 35.168C71.264 31.6693 69.4293 28.6827 67.04 26.208C64.6507 23.648 61.792 21.728 58.464 20.448C55.2213 19.0827 51.5947 18.4 47.584 18.4C42.208 18.4 37.472 19.5947 33.376 21.984C29.3653 24.288 26.2507 27.5733 24.032 31.84C21.8133 36.0213 20.704 40.9707 20.704 46.688C20.704 50.9547 21.344 54.8373 22.624 58.336C23.904 61.8347 25.696 64.864 28 67.424C30.3893 69.8987 33.248 71.8187 36.576 73.184C39.904 74.5493 43.5733 75.232 47.584 75.232Z" fill="#5187F1"/>
<path d="M115.509 92V1.63201H129.589L135.605 19.68V92H115.509ZM177.845 92L124.597 23.776L129.589 1.63201L182.837 69.856L177.845 92ZM177.845 92L172.469 73.952V1.63201H192.565V92H177.845Z" fill="#5187F1"/>
<path d="M217.689 92V1.63201H237.785V92H217.689ZM233.049 92V74.592H282.585V92H233.049ZM233.049 54.24V37.472H278.105V54.24H233.049ZM233.049 18.912V1.63201H281.945V18.912H233.049Z" fill="#5187F1"/>
<path d="M304.119 92V1.63201H324.215V92H304.119ZM319.607 92V74.336H364.279V92H319.607Z" fill="#1878F1"/>
<path d="M374.265 92L410.105 1.63201H428.281L463.737 92H442.489L415.353 16.992H422.649L395.129 92H374.265ZM394.617 75.616V59.232H443.897V75.616H394.617Z" fill="#1878F1"/>
<path d="M516.331 93.408C508.907 93.408 502.336 91.8293 496.619 88.672C490.987 85.5147 486.55 81.1627 483.307 75.616C480.15 69.984 478.571 63.584 478.571 56.416V1.63201H498.795V57.568C498.795 61.152 499.563 64.2667 501.099 66.912C502.635 69.5574 504.726 71.6053 507.371 73.056C510.102 74.4213 513.088 75.104 516.331 75.104C519.744 75.104 522.731 74.4213 525.291 73.056C527.851 71.6053 529.856 69.6 531.307 67.04C532.843 64.3947 533.611 61.28 533.611 57.696V1.63201H553.835V56.544C553.835 63.712 552.256 70.0693 549.099 75.616C545.942 81.1627 541.547 85.5147 535.915 88.672C530.283 91.8293 523.755 93.408 516.331 93.408Z" fill="#1878F1"/>
<path d="M577.534 92V1.63201H591.614L597.63 19.68V92H577.534ZM639.87 92L586.622 23.776L591.614 1.63201L644.862 69.856L639.87 92ZM639.87 92L634.494 73.952V1.63201H654.59V92H639.87Z" fill="#1878F1"/>
<path d="M722.594 93.408C715.853 93.408 709.581 92.256 703.778 89.952C698.061 87.5627 693.026 84.2347 688.674 79.968C684.407 75.7014 681.079 70.752 678.69 65.12C676.301 59.4027 675.106 53.2587 675.106 46.688C675.106 40.1173 676.301 34.016 678.69 28.384C681.079 22.6667 684.407 17.7173 688.674 13.536C692.941 9.35468 697.933 6.11201 703.65 3.80801C709.453 1.41868 715.725 0.224014 722.466 0.224014C729.634 0.224014 735.991 1.37601 741.538 3.68001C747.17 5.98401 752.077 9.14134 756.258 13.152L742.818 26.72C740.429 24.16 737.527 22.1547 734.114 20.704C730.786 19.2533 726.903 18.528 722.466 18.528C718.541 18.528 714.914 19.2107 711.586 20.576C708.343 21.856 705.527 23.7333 703.138 26.208C700.834 28.6827 698.999 31.6693 697.634 35.168C696.354 38.6667 695.714 42.5067 695.714 46.688C695.714 50.9547 696.354 54.8373 697.634 58.336C698.999 61.8347 700.834 64.8213 703.138 67.296C705.527 69.7707 708.343 71.6907 711.586 73.056C714.914 74.4213 718.541 75.104 722.466 75.104C727.074 75.104 731.085 74.3787 734.498 72.928C737.911 71.4773 740.855 69.472 743.33 66.912L756.898 80.48C752.546 84.4907 747.554 87.648 741.922 89.952C736.375 92.256 729.933 93.408 722.594 93.408Z" fill="#1878F1"/>
<path d="M775.644 92V1.63201H795.74V92H775.644ZM831.58 92V1.63201H851.804V92H831.58ZM787.676 54.24V36.832H838.236V54.24H787.676Z" fill="#1878F1"/>
<path d="M876.824 92V1.63201H896.92V92H876.824ZM892.184 92V74.592H941.72V92H892.184ZM892.184 54.24V37.472H937.24V54.24H892.184ZM892.184 18.912V1.63201H941.08V18.912H892.184Z" fill="#1878F1"/>
<path d="M978.614 54.752V39.904H997.686C1001.7 39.904 1004.77 38.88 1006.9 36.832C1009.12 34.784 1010.23 32.0107 1010.23 28.512C1010.23 25.2693 1009.16 22.5813 1007.03 20.448C1004.9 18.3147 1001.82 17.248 997.814 17.248H978.614V1.63201H1000.12C1006.09 1.63201 1011.34 2.78401 1015.86 5.08801C1020.38 7.30668 1023.93 10.4213 1026.49 14.432C1029.05 18.4427 1030.33 23.0507 1030.33 28.256C1030.33 33.5467 1029.05 38.1973 1026.49 42.208C1023.93 46.1333 1020.34 49.2053 1015.73 51.424C1011.13 53.6427 1005.71 54.752 999.478 54.752H978.614ZM963.254 92V1.63201H983.35V92H963.254ZM1012.41 92L984.246 53.088L1002.68 48.096L1036.21 92H1012.41Z" fill="#1878F1"/>
</svg>

After

Width:  |  Height:  |  Size: 5.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 751 B

Some files were not shown because too many files have changed in this diff Show more