feat: Add Launcher icons and begin work on importing instances

This commit is contained in:
LynithDev 2024-10-27 17:22:25 +01:00
parent 451987a326
commit 23ff953f64
20 changed files with 231 additions and 42 deletions

View file

@ -188,6 +188,7 @@
"*.vue": "$(capture).*.ts, $(capture).*.js, $(capture).story.vue", "*.vue": "$(capture).*.ts, $(capture).*.js, $(capture).story.vue",
"*.w": "$(capture).*.w, I$(capture).w", "*.w": "$(capture).*.w, I$(capture).w",
"*.xaml": "$(capture).xaml.cs" "*.xaml": "$(capture).xaml.cs"
}, },
"typescript.tsdk": "node_modules/typescript/lib" "typescript.tsdk": "node_modules/typescript/lib",
"svg.preview.background": "editor"
} }

View file

@ -58,7 +58,8 @@ macro_rules! collect_commands {
// Metadata // Metadata
get_minecraft_versions, get_minecraft_versions,
// Launcher Packages (Instances) // Launcher Packages (Instances)
import_launcher_instances, get_launcher_instances,
import_instances,
// Provider Packages // Provider Packages
get_provider_package, get_provider_package,
get_provider_packages, get_provider_packages,

View file

@ -3,7 +3,7 @@ use std::path::PathBuf;
use onelauncher::cluster::content::package; use onelauncher::cluster::content::package;
use onelauncher::data::{Loader, ManagedPackage, ManagedUser, ManagedVersion, PackageType}; use onelauncher::data::{Loader, ManagedPackage, ManagedUser, ManagedVersion, PackageType};
use onelauncher::package::content::Providers; use onelauncher::package::content::Providers;
use onelauncher::package::import::{default_launcher_path, ImportType}; use onelauncher::package::import::ImportType;
use onelauncher::store::{ use onelauncher::store::{
Author, ClusterPath, Package, PackageBody, PackagePath, ProviderSearchResults, Author, ClusterPath, Package, PackageBody, PackagePath, ProviderSearchResults,
}; };
@ -12,18 +12,25 @@ use uuid::Uuid;
#[specta::specta] #[specta::specta]
#[tauri::command] #[tauri::command]
pub async fn import_launcher_instances( pub async fn get_launcher_instances(
launcher: ImportType, launcher: ImportType,
path: Option<PathBuf>, path: Option<PathBuf>,
) -> Result<(String, Vec<String>), String> {
let (dir, instances) = onelauncher::api::package::import::get_launcher_instances(launcher, path).await?;
Ok((
dir.to_str().ok_or("could not convert pathbuf to string")?.to_string(),
instances
))
}
#[specta::specta]
#[tauri::command]
pub async fn import_instances(
launcher: ImportType,
base_path: PathBuf,
instances: Vec<String>,
) -> Result<(), String> { ) -> Result<(), String> {
onelauncher::api::package::import::import_instances( onelauncher::api::package::import::import_instances(launcher, base_path, instances).await?;
launcher,
path.unwrap_or(
default_launcher_path(launcher)
.ok_or("couldn't get a default path for this launcher")?,
),
)
.await?;
Ok(()) Ok(())
} }

View file

@ -1,4 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 53.5"> <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 53.5">
<path fill="currentColor" fill-rule="evenodd" <path fill="#F16436" fill-rule="evenodd"
d="M0 6.9082l27.9532.0756L26.269 0h73.7449l-.0164 8.1433C87.5 10.6348 78.6726 16.775 74.825 36.34H72.046l-1.5815 4.359h2.3079l3.9906 12.8087H37.961l3.9184-12.8086h2.325l-1.6467-4.359h-2.7642l-5.1516-13.7535C13.5203 21.3437 2.6748 16.9042 0 6.9082zM58.6772 39.062c-3.082-5.6216-5.1058-1.197-11.4454-6.9496-2.4727-2.2436-3.4588-8.8199 2.097-10.8301-2.5255 5.5749 4.0297 7.8558 5.5898 4.6685.709-1.4486 1.6039-4.1204-.9798-5.9518-1.392-.9867-1.9281-3.9125-.7364-5.5388.3837 1.2093 1.5938 2.5013 3.916 1.5411-4.9192-8.1404 2.934-10.9457 6.7104-10.5817-3.9686.441-6.025 3.977-4.2196 7.8269 1.15 2.452 2.9006 3.6589 3.4097 5.6657-1.6952.1263-2.1852.9065-2.1495 2.362.0268 1.0895 2.5496 2.6646 2.9494-.4456 1.175 2.4245-.2407 3.8496-1.0129 4.9984-1.7824 2.6515-.1036 5.4107 2.1097 3.3067.9547-.9074 1.6155-2.5812.4048-5.318 2.229 1.776 4.5057 6.5447.9079 10.677-1.756 2.017-6.9514 1.391-7.551 4.5693z" /> d="M0 6.9082l27.9532.0756L26.269 0h73.7449l-.0164 8.1433C87.5 10.6348 78.6726 16.775 74.825 36.34H72.046l-1.5815 4.359h2.3079l3.9906 12.8087H37.961l3.9184-12.8086h2.325l-1.6467-4.359h-2.7642l-5.1516-13.7535C13.5203 21.3437 2.6748 16.9042 0 6.9082zM58.6772 39.062c-3.082-5.6216-5.1058-1.197-11.4454-6.9496-2.4727-2.2436-3.4588-8.8199 2.097-10.8301-2.5255 5.5749 4.0297 7.8558 5.5898 4.6685.709-1.4486 1.6039-4.1204-.9798-5.9518-1.392-.9867-1.9281-3.9125-.7364-5.5388.3837 1.2093 1.5938 2.5013 3.916 1.5411-4.9192-8.1404 2.934-10.9457 6.7104-10.5817-3.9686.441-6.025 3.977-4.2196 7.8269 1.15 2.452 2.9006 3.6589 3.4097 5.6657-1.6952.1263-2.1852.9065-2.1495 2.362.0268 1.0895 2.5496 2.6646 2.9494-.4456 1.175 2.4245-.2407 3.8496-1.0129 4.9984-1.7824 2.6515-.1036 5.4107 2.1097 3.3067.9547-.9074 1.6155-2.5812.4048-5.318 2.229 1.776 4.5057 6.5447.9079 10.677-1.756 2.017-6.9514 1.391-7.551 4.5693z" />
</svg> </svg>

Before

Width:  |  Height:  |  Size: 1 KiB

After

Width:  |  Height:  |  Size: 1,022 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

View file

@ -1,8 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 514"> <svg width="64" height="64" viewBox="0 0 512 514" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" <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"/>
d="M503.16 323.56c11.39-42.09 12.16-87.65.04-132.8C466.57 54.2299 326.04-26.8001 189.33 9.77991 83.8101 38.0199 11.3899 128.07.689941 230.47H43.99c10.3-83.14 69.75-155.7402 155.76-178.7602 106.3-28.45 215.38 28.9601 253.42 129.6702l-42.14 11.27c-19.39-46.85-58.46-81.2-104.73-95.8302l-7.74 43.8402c36.53 13.47 66.16 43.84 77 84.25 15.8 58.89-13.62 119.23-67 144.26l11.53 42.99c70.16-28.95 112.31-101.86 102.34-177.02l41.98-11.23c4.5 28.71 2.94 57.25-3.86 84.16l42.61 15.49Z" <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"/>
fill="currentColor" /> </svg>
<path
d="M321.99 504.22C185.27 540.8 44.7501 459.77 8.11011 323.24 3.84011 307.31 1.17 291.33 0 275.46h43.27c1.09 11.91 3.1999 23.89 6.4099 35.83 3.36 12.51 7.7701 24.46 13.1101 35.78l38.59-23.15c-3.2501-7.5-5.99-15.32-8.17-23.45-24.04-89.6 29.2-181.7 118.92-205.7099 17-4.55 34.1-6.32 50.8-5.61L255.19 133c-10.46.05-21.08 1.42-31.66 4.25-66.22 17.73-105.52 85.7-87.78 151.84 1.1 4.07 2.38 8.04 3.84 11.9l49.35-29.61-14.87-39.43 46.6-47.87 58.9-12.69 17.05 20.99-27.15 27.5-23.68 7.45-16.92 17.39 8.29 23.07s16.79 17.84 16.82 17.85l23.72-6.31 16.88-18.54 36.86-11.67 10.98 24.7-38.03 46.63-63.73 20.18-28.58-31.82-49.82 29.89c25.54 29.08 63.94 45.23 103.75 41.86l11.53 42.99c-59.41 7.86-117.44-16.73-153.49-61.91l-38.4101 23.04C136.25 451.17 223.84 484.11 309.61 461.16c61.74-16.52 109.79-58.6 135.81-111.78l42.64 15.5c-30.89 66.28-89.84 118.94-166.07 139.34Z"
fill="currentColor" />
</svg>

Before

Width:  |  Height:  |  Size: 1.5 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

View file

@ -0,0 +1,60 @@
import type { ImportType } from '@onelauncher/client/bindings';
import CurseforgeIcon from '~assets/logos/curseforge.svg?component-solid';
import AtLauncherIcon from '~assets/logos/launchers/atlauncher.svg?component-solid';
import FTBIcon from '~assets/logos/launchers/ftb.svg?component-solid';
import GDLauncherImage from '~assets/logos/launchers/gdlauncher.png';
import MultiMCImage from '~assets/logos/launchers/multimc.png';
import PrismIcon from '~assets/logos/launchers/prismlauncher.svg?component-solid';
import TechnicImage from '~assets/logos/launchers/technic.png';
import TLauncherImage from '~assets/logos/launchers/tlauncher.png';
import ModrinthIcon from '~assets/logos/modrinth.svg?component-solid';
import UnknownImage from '~assets/logos/vanilla.png';
import { type JSX, type JSXElement, Show, splitProps } from 'solid-js';
type ElementType = (props: any) => JSXElement;
export function getLauncherLogoElement(launcher: ImportType): ElementType {
const providerName = launcher.toLowerCase() as Lowercase<ImportType>;
const image = (src: string, props: any) => <img {...props} alt={providerName} src={src} />;
// [provider logo, is svg]
const mapping: Record<Lowercase<ImportType>, ElementType | string> = {
modrinth: ModrinthIcon,
curseforge: CurseforgeIcon,
prismlauncher: PrismIcon,
atlauncher: AtLauncherIcon,
gdlauncher: GDLauncherImage,
ftblauncher: FTBIcon,
multimc: MultiMCImage,
tlauncher: TLauncherImage,
technic: TechnicImage,
unknown: UnknownImage,
};
const logo = mapping[providerName] || UnknownImage;
if (typeof logo === 'function')
return logo;
return props => image(logo, props);
}
type LauncherIconProps = JSX.HTMLAttributes<HTMLImageElement> & {
launcher: ImportType | undefined;
};
function LauncherIcon(props: LauncherIconProps) {
const [split, rest] = splitProps(props, ['launcher', 'class']);
return (
<Show
children={getLauncherLogoElement(split.launcher!)({ ...rest, ...(split.class ? { class: split.class } : {}) })}
fallback={(
<div class={`bg-gray-05 ${split.class || ''}`} {...rest as JSX.HTMLAttributes<HTMLDivElement>} />
)}
when={split.launcher !== undefined}
/>
);
}
export default LauncherIcon;

View file

@ -1,4 +1,5 @@
import type { ManagedPackage, Providers } from '@onelauncher/client/bindings'; import type { ManagedPackage, Providers } from '@onelauncher/client/bindings';
import CurseforgeIcon from '~assets/logos/curseforge.svg?component-solid';
import ModrinthImage from '~assets/logos/modrinth.svg?component-solid'; import ModrinthImage from '~assets/logos/modrinth.svg?component-solid';
import { type Component, type JSX, Match, Show, splitProps, Switch } from 'solid-js'; import { type Component, type JSX, Match, Show, splitProps, Switch } from 'solid-js';
@ -8,6 +9,7 @@ export function getProviderLogoElement(provider: ManagedPackage | Providers): st
// [provider logo, is svg] // [provider logo, is svg]
const mapping: Record<Lowercase<Providers>, string | Component> = { const mapping: Record<Lowercase<Providers>, string | Component> = {
modrinth: ModrinthImage, modrinth: ModrinthImage,
curseforge: CurseforgeIcon,
}; };
return mapping[providerName]; return mapping[providerName];

View file

@ -32,7 +32,7 @@ export const enum OnboardingTaskStage {
interface OnboardingContextType { interface OnboardingContextType {
setLanguage: (language: Language) => void; setLanguage: (language: Language) => void;
setImportTypes: (types: ImportType[]) => void; setImportTypeInstances: (type: ImportType, instances: string[]) => void;
getTasks: () => string[]; getTasks: () => string[];
@ -51,7 +51,7 @@ function Onboarding(props: ParentProps) {
const [forwardButtonEnabled, setForwardButtonEnabled] = createSignal(true); const [forwardButtonEnabled, setForwardButtonEnabled] = createSignal(true);
const [language, setLanguage] = createSignal<Language>('en'); const [language, setLanguage] = createSignal<Language>('en');
const [importTypes, setImportTypes] = createSignal<ImportType[]>([]); const [importTypes, setImportTypes] = createSignal<Map<ImportType, string[]>>(new Map());
const [tasksStage, setTasksStage] = createSignal<OnboardingTaskStage>(OnboardingTaskStage.NotStarted); const [tasksStage, setTasksStage] = createSignal<OnboardingTaskStage>(OnboardingTaskStage.NotStarted);
const [tasksMessage, setTasksMessage] = createSignal<string>(''); const [tasksMessage, setTasksMessage] = createSignal<string>('');
@ -140,7 +140,13 @@ function Onboarding(props: ParentProps) {
const ctx: OnboardingContextType = { const ctx: OnboardingContextType = {
setLanguage, setLanguage,
setImportTypes, setImportTypeInstances(type, instances) {
setImportTypes((importTypes) => {
const newMap = new Map(importTypes);
newMap.set(type, instances);
return newMap;
});
},
getTasks, getTasks,

View file

@ -1,18 +1,24 @@
import { useBeforeLeave } from '@solidjs/router'; import type { ImportType } from '@onelauncher/client/bindings';
import Illustration from '~assets/illustrations/onboarding/import_from_others.svg?component-solid'; import Illustration from '~assets/illustrations/onboarding/import_from_others.svg?component-solid';
import Image from '~assets/logos/vanilla.png'; import LauncherIcon from '~ui/components/content/LauncherIcon';
import { LAUNCHER_IMPORT_TYPES } from '~utils'; import { LAUNCHER_IMPORT_TYPES } from '~utils';
import { OverlayScrollbarsComponent } from 'overlayscrollbars-solid'; import { OverlayScrollbarsComponent } from 'overlayscrollbars-solid';
import { For } from 'solid-js'; import { For } from 'solid-js';
import Onboarding, { OnboardingStep } from './Onboarding'; import Onboarding, { OnboardingStep } from './Onboarding';
import { createModal } from '~ui/components/overlay/Modal';
function OnboardingImport() { function OnboardingImport() {
const ctx = Onboarding.useContext(); const ctx = Onboarding.useContext();
useBeforeLeave(() => { const modal = createModal((props) => {
ctx.setImportTypes([]);
}); });
function displayImport(type: ImportType) {
}
return ( return (
<OnboardingStep <OnboardingStep
illustration={<Illustration />} illustration={<Illustration />}
@ -24,10 +30,10 @@ function OnboardingImport() {
<div class="grid grid-cols-3"> <div class="grid grid-cols-3">
<For each={LAUNCHER_IMPORT_TYPES}> <For each={LAUNCHER_IMPORT_TYPES}>
{type => ( {type => (
<div class="flex flex-col items-center justify-center gap-y-4 rounded-md p-4 active:bg-gray-10 hover:bg-gray-05"> <button class="flex flex-col items-center justify-center gap-y-4 rounded-md p-4 active:bg-gray-10 hover:bg-gray-05" onClick={() => displayImport(type)}>
<img alt={type} class="h-16" src={Image} /> <LauncherIcon class="h-16 max-w-22 min-w-16" launcher={type} />
<span class="text-lg font-medium">{type}</span> <span class="text-lg font-medium">{type}</span>
</div> </button>
)} )}
</For> </For>
</div> </div>
@ -38,3 +44,7 @@ function OnboardingImport() {
} }
export default OnboardingImport; export default OnboardingImport;
function InstancesPickerModal() {
}

View file

@ -16,7 +16,7 @@ function OnboardingSummary() {
<AnimatedRoutes> <AnimatedRoutes>
<Switch> <Switch>
<Match when={ctx.tasksStage() === OnboardingTaskStage.NotStarted}> <Match when={ctx.tasksStage() === OnboardingTaskStage.NotStarted}>
<div class="my-8 max-h-36 w-full flex flex-1 flex-col gap-y-2 rounded-lg bg-page-elevated p-4"> <div class="my-8 max-h-36 w-full flex flex-1 flex-col gap-y-2 rounded-lg bg-page-elevated p-4 font-mono">
<For each={ctx.getTasks()}> <For each={ctx.getTasks()}>
{task => ( {task => (
<span class="text-lg text-fg-primary"> <span class="text-lg text-fg-primary">

View file

@ -1,4 +1,5 @@
import { CodeBrowserIcon, GitMergeIcon, LinkExternal01Icon, RefreshCcw05Icon } from '@untitled-theme/icons-solid'; import { useNavigate } from '@solidjs/router';
import { CodeBrowserIcon, EyeIcon, GitMergeIcon, LinkExternal01Icon, RefreshCcw05Icon } from '@untitled-theme/icons-solid';
import Button from '~ui/components/base/Button'; import Button from '~ui/components/base/Button';
import Toggle from '~ui/components/base/Toggle'; import Toggle from '~ui/components/base/Toggle';
import ScrollableContainer from '~ui/components/ScrollableContainer'; import ScrollableContainer from '~ui/components/ScrollableContainer';
@ -7,7 +8,13 @@ import Sidebar from '~ui/components/Sidebar';
import useSettings from '~ui/hooks/useSettings'; import useSettings from '~ui/hooks/useSettings';
function SettingsDeveloper() { function SettingsDeveloper() {
const { settings } = useSettings(); const { settings, saveOnLeave } = useSettings();
const navigate = useNavigate();
saveOnLeave(() => ({
debug_mode: settings().debug_mode!,
onboarding_completed: settings().onboarding_completed!,
}));
return ( return (
<Sidebar.Page> <Sidebar.Page>
@ -44,7 +51,22 @@ function SettingsDeveloper() {
<Button <Button
children="Reload" children="Reload"
iconLeft={<RefreshCcw05Icon />} iconLeft={<RefreshCcw05Icon />}
onClick={() => location.href = '/'} onClick={() => location.reload()}
/>
</SettingsRow>
<SettingsRow
description="Enter onboarding mode"
icon={<EyeIcon />}
title="Onboarding"
>
<Button
children="Open"
iconLeft={<EyeIcon />}
onClick={() => {
settings().onboarding_completed = false;
navigate('/onboarding');
}}
/> />
</SettingsRow> </SettingsRow>

View file

@ -324,9 +324,19 @@ export const commands = {
else return { status: 'error', error: e as any }; else return { status: 'error', error: e as any };
} }
}, },
async importLauncherInstances(launcher: ImportType, path: string | null): Promise<Result<null, string>> { async getLauncherInstances(launcher: ImportType, path: string | null): Promise<Result<[string, string[]], string>> {
try { try {
return { status: 'ok', data: await TAURI_INVOKE('import_launcher_instances', { launcher, path }) }; return { status: 'ok', data: await TAURI_INVOKE('get_launcher_instances', { launcher, path }) };
}
catch (e) {
if (e instanceof Error)
throw e;
else return { status: 'error', error: e as any };
}
},
async importInstances(launcher: ImportType, basePath: string, instances: string[]): Promise<Result<null, string>> {
try {
return { status: 'ok', data: await TAURI_INVOKE('import_instances', { launcher, basePath, instances }) };
} }
catch (e) { catch (e) {
if (e instanceof Error) if (e instanceof Error)

View file

@ -92,8 +92,14 @@ impl ImportType {
} }
} }
pub async fn import_instances(import: ImportType, path: PathBuf) -> crate::Result<Vec<String>> { pub async fn get_launcher_instances(import: ImportType, path: Option<PathBuf>) -> crate::Result<(PathBuf, Vec<String>)> {
let instances_dir = import.get_instances_subpath(&path).await?; let instances_dir = import.get_instances_subpath(
&path.unwrap_or(
default_launcher_path(import)
.ok_or(anyhow::anyhow!("could not get launcher base path for {import}")
)?
)).await?;
let mut instances = Vec::new(); let mut instances = Vec::new();
let mut dir = io::read_dir(&instances_dir) let mut dir = io::read_dir(&instances_dir)
.await .await
@ -113,7 +119,21 @@ pub async fn import_instances(import: ImportType, path: PathBuf) -> crate::Resul
} }
} }
Ok(instances) Ok((instances_dir, instances))
}
#[tracing::instrument]
pub async fn import_instances(
import: ImportType,
base_path: PathBuf,
instances: Vec<String>,
) -> crate::Result<()> {
for instance in instances {
let cluster_path = ClusterPath::new(&instance);
import_instance(cluster_path, import, base_path.clone(), instance).await?;
}
Ok(())
} }
#[tracing::instrument] #[tracing::instrument]