mirror of
https://github.com/LCE-Hub/LCE-Emerald-Launcher.git
synced 2026-09-25 01:20:55 +00:00
revert
This commit is contained in:
@@ -1,98 +0,0 @@
|
||||
import { motion } from "framer-motion";
|
||||
import { useState, useEffect } from "react";
|
||||
|
||||
export default function SpecialThanksModal({
|
||||
isOpen,
|
||||
onClose,
|
||||
playSfx,
|
||||
}: any) {
|
||||
const [focusIndex, setFocusIndex] = useState(0);
|
||||
|
||||
const contributors = [
|
||||
{ name: "smartcmd & LCE Community", desc: "Research & Foundations" },
|
||||
{ name: "Andi_pog & AFanFromWalmart", desc: "Project Testers" }
|
||||
];
|
||||
|
||||
useEffect(() => {
|
||||
if (!isOpen) {
|
||||
setFocusIndex(0);
|
||||
return;
|
||||
}
|
||||
const handleKey = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") {
|
||||
playSfx("close_click.wav");
|
||||
onClose();
|
||||
} else if (e.key === "ArrowDown" || e.key === "Tab") {
|
||||
e.preventDefault();
|
||||
setFocusIndex((prev) => (prev + 1) % (contributors.length + 1));
|
||||
} else if (e.key === "ArrowUp") {
|
||||
e.preventDefault();
|
||||
setFocusIndex((prev) => (prev - 1 + (contributors.length + 1)) % (contributors.length + 1));
|
||||
} else if (e.key === "Enter") {
|
||||
if (focusIndex === contributors.length) {
|
||||
playSfx("close_click.wav");
|
||||
onClose();
|
||||
}
|
||||
}
|
||||
};
|
||||
window.addEventListener("keydown", handleKey);
|
||||
return () => window.removeEventListener("keydown", handleKey);
|
||||
}, [isOpen, focusIndex]);
|
||||
|
||||
if (!isOpen) return null;
|
||||
|
||||
return (
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
className="absolute inset-0 z-[110] flex items-center justify-center bg-black/80 backdrop-blur-sm outline-none border-none"
|
||||
>
|
||||
<div
|
||||
className="relative w-[400px] p-6 flex flex-col items-center shadow-2xl"
|
||||
style={{
|
||||
backgroundImage: "url('/images/frame_background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<h2 className="text-[#FFFF55] text-2xl mc-text-shadow mb-4 border-b-2 border-[#373737] pb-2 w-full text-center uppercase">
|
||||
Special Thanks
|
||||
</h2>
|
||||
<div className="flex flex-col gap-2 w-full items-center max-h-[320px] overflow-y-auto overflow-x-hidden scrollbar-hide py-2">
|
||||
{contributors.map((item, idx) => (
|
||||
<div
|
||||
key={item.name}
|
||||
onMouseEnter={() => setFocusIndex(idx)}
|
||||
className={`w-[90%] p-2 flex flex-col items-center justify-center mc-text-shadow transition-transform outline-none border-none bg-transparent ${focusIndex === idx ? "scale-105 text-[#FFFF55]" : "opacity-80 text-white"}`}
|
||||
>
|
||||
<span className="text-xl">
|
||||
{item.name}
|
||||
</span>
|
||||
<span className="text-[10px] text-[#A0A0A0] uppercase tracking-widest mt-1">
|
||||
{item.desc}
|
||||
</span>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
<button
|
||||
onMouseEnter={() => setFocusIndex(contributors.length)}
|
||||
onClick={() => {
|
||||
playSfx("close_click.wav");
|
||||
onClose();
|
||||
}}
|
||||
className={`mt-6 w-56 h-12 flex items-center justify-center transition-colors text-2xl mc-text-shadow outline-none border-none ${focusIndex === contributors.length ? "text-[#FFFF55]" : "text-white"}`}
|
||||
style={{
|
||||
backgroundImage: focusIndex === contributors.length
|
||||
? "url('/images/button_highlighted.png')"
|
||||
: "url('/images/Button_Background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
Close
|
||||
</button>
|
||||
</div>
|
||||
</motion.div>
|
||||
);
|
||||
}
|
||||
@@ -3,7 +3,7 @@ import { motion } from "framer-motion";
|
||||
import { useUI, useConfig, useAudio, useGame } from "../../context/LauncherContext";
|
||||
|
||||
const HomeView = memo(function HomeView() {
|
||||
const { setActiveView, setShowCredits, setShowSpecialThanks, focusSection, onNavigateToSkin } = useUI();
|
||||
const { setActiveView, setShowCredits, focusSection, onNavigateToSkin } = useUI();
|
||||
const { profile, legacyMode } = useConfig();
|
||||
const { playClickSound, playSfx } = useAudio();
|
||||
const { handleLaunch, isGameRunning, editions, installs, toggleInstall, downloadProgress, downloadingId } = useGame();
|
||||
@@ -155,17 +155,6 @@ const HomeView = memo(function HomeView() {
|
||||
>
|
||||
EMERALD TEAM
|
||||
</button>
|
||||
<button
|
||||
onClick={() => {
|
||||
if (isFocusedSection) {
|
||||
playSfx("orb.ogg");
|
||||
setShowSpecialThanks(true);
|
||||
}
|
||||
}}
|
||||
className={`text-white/60 hover:text-[#FFFF55] text-xs mc-text-shadow tracking-[0.2em] transition-colors bg-transparent border-none outline-none ${!isFocusedSection ? "cursor-default pointer-events-none" : ""}`}
|
||||
>
|
||||
SPECIAL THANKS
|
||||
</button>
|
||||
</div>
|
||||
)}
|
||||
</motion.div>
|
||||
|
||||
@@ -207,13 +207,13 @@ const SettingsView = memo(function SettingsView() {
|
||||
if (currentSubMenu === "main") {
|
||||
items.push({
|
||||
id: "audio_menu",
|
||||
label: "Audio",
|
||||
label: "Audio Settings",
|
||||
type: "button",
|
||||
onClick: () => { playClickSound(); setCurrentSubMenu("audio"); setFocusIndex(0); },
|
||||
});
|
||||
items.push({
|
||||
id: "video_menu",
|
||||
label: "User Interface",
|
||||
label: "Video Settings",
|
||||
type: "button",
|
||||
onClick: () => { playClickSound(); setCurrentSubMenu("video"); setFocusIndex(0); },
|
||||
});
|
||||
@@ -225,23 +225,23 @@ const SettingsView = memo(function SettingsView() {
|
||||
});
|
||||
items.push({
|
||||
id: "launcher_menu",
|
||||
label: "Options",
|
||||
label: "Launcher Settings",
|
||||
type: "button",
|
||||
onClick: () => { playClickSound(); setCurrentSubMenu("launcher"); setFocusIndex(0); },
|
||||
});
|
||||
} else if (currentSubMenu === "audio") {
|
||||
items.push({
|
||||
id: "music",
|
||||
label: `Music: ${musicVolume ?? 50}%`,
|
||||
label: `Music: ${musicVolume}%`,
|
||||
type: "slider",
|
||||
value: musicVolume ?? 50,
|
||||
value: musicVolume,
|
||||
onChange: setMusicVolume,
|
||||
});
|
||||
items.push({
|
||||
id: "sfx",
|
||||
label: `SFX: ${sfxVolume ?? 100}%`,
|
||||
label: `SFX: ${sfxVolume}%`,
|
||||
type: "slider",
|
||||
value: sfxVolume ?? 100,
|
||||
value: sfxVolume,
|
||||
onChange: setSfxVolume,
|
||||
});
|
||||
items.push({
|
||||
@@ -480,7 +480,7 @@ const SettingsView = memo(function SettingsView() {
|
||||
className="flex flex-col items-center w-full max-w-2xl outline-none"
|
||||
>
|
||||
<h2 className="text-2xl text-white mc-text-shadow mt-2 mb-4 border-b-2 border-[#373737] pb-2 w-[40%] max-w-[200px] text-center tracking-widest uppercase opacity-80 font-bold whitespace-nowrap px-4">
|
||||
{currentSubMenu === "main" ? "Settings" : currentSubMenu === "audio" ? "Audio" : currentSubMenu === "video" ? "User Interface" : currentSubMenu === "controls" ? "Controls" : "Options"}
|
||||
{currentSubMenu === "main" ? "Settings" : currentSubMenu === "audio" ? "Audio Settings" : currentSubMenu === "video" ? "Video Settings" : currentSubMenu === "controls" ? "Controls" : "Launcher"}
|
||||
</h2>
|
||||
|
||||
<div className="w-full max-w-[540px] space-y-2 mb-4 p-6 flex flex-col items-center overflow-y-auto max-h-[55vh]">
|
||||
|
||||
@@ -8,7 +8,7 @@ const VersionsView = memo(function VersionsView() {
|
||||
const { setActiveView } = useUI();
|
||||
const { profile: selectedProfile, setProfile: setSelectedProfile } = useConfig();
|
||||
const { playClickSound, playBackSound, playSfx } = useAudio();
|
||||
const { editions, installs: installedVersions, toggleInstall, handleUninstall: onUninstall, deleteCustomEdition: onDeleteEdition, addCustomEdition: onAddEdition, updateCustomEdition: onUpdateEdition, downloadingId } = useGame();
|
||||
const { editions, installs: installedVersions, toggleInstall, handleUninstall: onUninstall, deleteCustomEdition: onDeleteEdition, addCustomEdition: onAddEdition, updateCustomEdition: onUpdateEdition, downloadingId, downloadProgress } = useGame();
|
||||
|
||||
const [focusRow, setFocusRow] = useState<number>(0);
|
||||
const [focusCol, setFocusCol] = useState<number>(0);
|
||||
@@ -35,49 +35,34 @@ const VersionsView = memo(function VersionsView() {
|
||||
setFocusCol(0);
|
||||
} else if (e.key === "ArrowRight") {
|
||||
if (focusRow < editions.length) {
|
||||
const edition = editions[focusRow];
|
||||
const isInstalled = installedVersions.includes(edition.id);
|
||||
const isCustom = edition.id.startsWith("custom_");
|
||||
const hasCredits = !isCustom && edition.credits;
|
||||
|
||||
const id = editions[focusRow].id;
|
||||
const isInstalled = installedVersions.includes(id);
|
||||
const isCustom = id.startsWith("custom_");
|
||||
let maxCol = 1;
|
||||
if (isInstalled) maxCol = 3;
|
||||
if (isCustom) maxCol = isInstalled ? 5 : 3;
|
||||
if (hasCredits) maxCol = Math.max(maxCol, 0); // credits button is at col -1
|
||||
|
||||
setFocusCol((prev) => (prev < maxCol ? prev + 1 : prev));
|
||||
}
|
||||
} else if (e.key === "ArrowLeft") {
|
||||
if (focusRow < editions.length) {
|
||||
const edition = editions[focusRow];
|
||||
const isCustom = edition.id.startsWith("custom_");
|
||||
const hasCredits = !isCustom && edition.credits;
|
||||
|
||||
if (hasCredits && focusCol > -1) {
|
||||
setFocusCol(-1);
|
||||
} else if (focusCol > 0) {
|
||||
setFocusCol((prev) => prev - 1);
|
||||
}
|
||||
} else {
|
||||
setFocusCol((prev) => (prev > 0 ? prev - 1 : prev));
|
||||
}
|
||||
setFocusCol((prev) => (prev > 0 ? prev - 1 : prev));
|
||||
} else if (e.key === "Enter") {
|
||||
if (focusRow < editions.length) {
|
||||
const edition = editions[focusRow];
|
||||
const isInstalled = installedVersions.includes(edition.id);
|
||||
const isCustom = edition.id.startsWith("custom_");
|
||||
|
||||
if (focusCol === -1) {
|
||||
// Credits button
|
||||
if (edition.credits) {
|
||||
if (focusCol === 0) {
|
||||
if (isInstalled) {
|
||||
playClickSound();
|
||||
window.open(edition.credits.url, '_blank');
|
||||
}
|
||||
} else if (focusCol === 1) {
|
||||
if (!downloadingId) {
|
||||
setSelectedProfile(edition.id);
|
||||
} else if (!downloadingId) {
|
||||
playClickSound();
|
||||
toggleInstall(edition.id);
|
||||
}
|
||||
} else if (focusCol === 1 && !downloadingId) {
|
||||
playClickSound();
|
||||
toggleInstall(edition.id);
|
||||
} else if (focusCol === 2) {
|
||||
if (isInstalled) {
|
||||
playClickSound();
|
||||
@@ -116,10 +101,22 @@ const VersionsView = memo(function VersionsView() {
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||
}, [editions, focusRow, focusCol, downloadingId, installedVersions, onUninstall, onDeleteEdition, ITEM_COUNT]);
|
||||
}, [
|
||||
focusRow,
|
||||
focusCol,
|
||||
editions,
|
||||
installedVersions,
|
||||
playClickSound,
|
||||
playBackSound,
|
||||
setSelectedProfile,
|
||||
setActiveView,
|
||||
toggleInstall,
|
||||
onUninstall,
|
||||
onDeleteEdition,
|
||||
ITEM_COUNT,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
const el = containerRef.current?.querySelector(
|
||||
@@ -142,381 +139,304 @@ const VersionsView = memo(function VersionsView() {
|
||||
</h2>
|
||||
|
||||
<div className="w-full max-w-[740px] h-[380px] overflow-y-auto mb-6 p-6 relative">
|
||||
<div
|
||||
className="w-full p-6"
|
||||
style={{
|
||||
backgroundImage: "url('/images/frame_background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
backgroundRepeat: "no-repeat",
|
||||
imageRendering: "pixelated",
|
||||
minHeight: "340px",
|
||||
}}
|
||||
>
|
||||
<div className="flex flex-col gap-3">
|
||||
{editions.map((edition: any, i: number) => {
|
||||
const isInstalled = installedVersions.includes(edition.id);
|
||||
const isSelected = selectedProfile === edition.id;
|
||||
const isRowFocused = focusRow === i;
|
||||
const isCustom = edition.id.startsWith("custom_");
|
||||
const isPlaceholder = edition.id === "lmrp_placeholder";
|
||||
<div className="flex flex-col gap-3">
|
||||
{editions.map((edition: any, i: number) => {
|
||||
const isInstalled = installedVersions.includes(edition.id);
|
||||
const isSelected = selectedProfile === edition.id;
|
||||
const isRowFocused = focusRow === i;
|
||||
const isCustom = edition.id.startsWith("custom_");
|
||||
|
||||
return (
|
||||
return (
|
||||
<div
|
||||
key={edition.id}
|
||||
className={`w-full flex items-center transition-all border-none outline-none overflow-hidden`}
|
||||
style={{
|
||||
backgroundImage:
|
||||
isSelected || (isRowFocused && focusCol === 0)
|
||||
? "url('/images/button_highlighted.png')"
|
||||
: "url('/images/Button_Background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<div
|
||||
key={edition.id}
|
||||
className={`w-full p-4 flex items-center transition-all border-none outline-none overflow-hidden relative ${isPlaceholder ? 'bg-gray-800/50 border-2 border-gray-600 opacity-50' : isSelected ? 'bg-[#50C878]/20 border-2 border-[#50C878]' :
|
||||
isRowFocused ? 'bg-white/5 border-2 border-white/50' :
|
||||
'bg-black/30 border-2 border-transparent hover:bg-white/5'
|
||||
}`}
|
||||
data-row={i}
|
||||
data-col={0}
|
||||
tabIndex={0}
|
||||
onMouseEnter={() => {
|
||||
if (!isPlaceholder) {
|
||||
setFocusRow(i);
|
||||
setFocusCol(0);
|
||||
}
|
||||
setFocusRow(i);
|
||||
setFocusCol(0);
|
||||
}}
|
||||
onClick={() => {
|
||||
if (!isPlaceholder && isInstalled) {
|
||||
if (isInstalled) {
|
||||
playClickSound();
|
||||
setSelectedProfile(edition.id);
|
||||
} else {
|
||||
toggleInstall(edition.id);
|
||||
}
|
||||
}}
|
||||
style={{
|
||||
backdropFilter: 'blur(4px)',
|
||||
cursor: isPlaceholder ? 'not-allowed' : isInstalled ? 'pointer' : 'default',
|
||||
imageRendering: 'pixelated',
|
||||
borderRadius: '0'
|
||||
}}
|
||||
className="flex-1 p-4 flex items-center cursor-pointer outline-none pl-6 text-left relative"
|
||||
>
|
||||
<div className="flex flex-col flex-1">
|
||||
<div className="flex items-center gap-3 mb-1">
|
||||
<div className="flex flex-col">
|
||||
<div className="flex items-center gap-3">
|
||||
<span
|
||||
className={`text-xl mc-text-shadow ${isSelected ? "text-[#50C878]" : "text-white"}`}
|
||||
style={{ imageRendering: 'pixelated' }}
|
||||
className={`text-2xl mc-text-shadow ${isSelected || (isRowFocused && focusCol === 0) ? "text-[#FFFF55]" : "text-white"}`}
|
||||
>
|
||||
{edition.name}
|
||||
</span>
|
||||
{isCustom && (
|
||||
<span
|
||||
className="text-[10px] bg-[#50C878] text-black px-1 font-bold uppercase mc-text-shadow-none"
|
||||
style={{ imageRendering: 'pixelated' }}
|
||||
>
|
||||
<span className="text-[10px] bg-[#FFFF55] text-black px-1 font-bold uppercase mc-text-shadow-none">
|
||||
Custom
|
||||
</span>
|
||||
)}
|
||||
{edition.id === "revelations_edition" && (
|
||||
<>
|
||||
<span
|
||||
className="text-[10px] bg-[#50C878] text-white px-1 font-bold uppercase mc-text-shadow-none"
|
||||
style={{ imageRendering: 'pixelated' }}
|
||||
>
|
||||
New
|
||||
</span>
|
||||
<span
|
||||
className="text-[10px] bg-[#FFD700] text-black px-1 font-bold uppercase mc-text-shadow-none"
|
||||
style={{ imageRendering: 'pixelated' }}
|
||||
>
|
||||
Recommended
|
||||
</span>
|
||||
</>
|
||||
)}
|
||||
{edition.id === "360revived" && (
|
||||
<span
|
||||
className="text-[10px] bg-[#50C878] text-white px-1 font-bold uppercase mc-text-shadow-none"
|
||||
style={{ imageRendering: 'pixelated' }}
|
||||
>
|
||||
New
|
||||
</span>
|
||||
)}
|
||||
{edition.id === "lmrp_placeholder" && (
|
||||
<span
|
||||
className="text-[10px] bg-gray-500 text-white px-1 font-bold uppercase mc-text-shadow-none"
|
||||
style={{ imageRendering: 'pixelated' }}
|
||||
>
|
||||
Coming Soon
|
||||
</span>
|
||||
)}
|
||||
{!isCustom && edition.credits && (
|
||||
<span
|
||||
className="text-xs text-[#B0B0B0] mc-text-shadow"
|
||||
style={{ imageRendering: 'pixelated' }}
|
||||
>
|
||||
by {edition.credits.developer}
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<div
|
||||
className="text-sm text-[#E0E0E0] mc-text-shadow"
|
||||
style={{ imageRendering: 'pixelated' }}
|
||||
>
|
||||
<span className="text-base text-[#E0E0E0] mc-text-shadow truncate w-full">
|
||||
{edition.desc}
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{!isPlaceholder && (
|
||||
<div className="flex items-center gap-2">
|
||||
{!isCustom && edition.credits && (
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={-1}
|
||||
onMouseEnter={(e) => {
|
||||
e.stopPropagation();
|
||||
setFocusRow(i);
|
||||
setFocusCol(-1);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
playClickSound();
|
||||
window.open(edition.credits.url, '_blank');
|
||||
}}
|
||||
className={`mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all`}
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === -1
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
title={`Credits: ${edition.credits.developer} (${edition.credits.platform})`}
|
||||
>
|
||||
{edition.credits?.platform === "codeberg" ? (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="currentColor"
|
||||
className="text-white drop-shadow-md"
|
||||
>
|
||||
<path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-1 17.93c-3.95-.49-7-3.85-7-7.93 0-.62.08-1.21.21-1.79L9 15v1c0 1.1.9 2 2 2v1.93zm6.9-2.54c-.26-.81-1-1.39-1.9-1.39h-1v-3c0-.55-.45-1-1-1H8v-2h2c.55 0 1-.45 1-1V7h2c1.1 0 2-.9 2-2v-.41c2.93 1.19 5 4.06 5 7.41 0 2.08-.8 3.97-2.1 5.39z" />
|
||||
</svg>
|
||||
) : (
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2"
|
||||
strokeLinecap="round"
|
||||
strokeLinejoin="round"
|
||||
className="text-white drop-shadow-md"
|
||||
>
|
||||
<path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
|
||||
</svg>
|
||||
)}
|
||||
</button>
|
||||
)}
|
||||
|
||||
{!isInstalled ? (
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={1}
|
||||
onMouseEnter={(e) => {
|
||||
e.stopPropagation();
|
||||
setFocusRow(i);
|
||||
setFocusCol(1);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (!downloadingId) {
|
||||
playClickSound();
|
||||
toggleInstall(edition.id);
|
||||
}
|
||||
}}
|
||||
className={`mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all ${downloadingId === edition.id ? "opacity-100" : downloadingId ? "opacity-50" : ""}`}
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === 1
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
{downloadingId === edition.id ? (
|
||||
<img
|
||||
src="/images/loading.gif"
|
||||
alt="Loading"
|
||||
className="w-6 h-6 object-contain pointer-events-none drop-shadow-md"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
) : (
|
||||
<img
|
||||
src="/images/Download_Icon.png"
|
||||
alt="Download"
|
||||
className="w-6 h-6 object-contain pointer-events-none drop-shadow-md"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
<div className="flex items-center gap-3 p-3 pr-6">
|
||||
{!isInstalled ? (
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={1}
|
||||
onMouseEnter={() => {
|
||||
setFocusRow(i);
|
||||
setFocusCol(1);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (!downloadingId) {
|
||||
playClickSound();
|
||||
toggleInstall(edition.id);
|
||||
}
|
||||
}}
|
||||
className={`mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all ${downloadingId === edition.id ? "opacity-100" : downloadingId ? "opacity-50" : ""}`}
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === 1
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
{downloadingId === edition.id ? (
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<span className="text-[10px] text-white font-bold leading-none">
|
||||
{Math.floor(downloadProgress || 0)}%
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={2}
|
||||
onMouseEnter={(e) => {
|
||||
e.stopPropagation();
|
||||
setFocusRow(i);
|
||||
setFocusCol(2);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
playClickSound();
|
||||
TauriService.openInstanceFolder(edition.id);
|
||||
}}
|
||||
className="mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all"
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === 2
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="/images/Folder_Icon.png"
|
||||
alt="Folder"
|
||||
className="w-6 h-6 object-contain pointer-events-none drop-shadow-md"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={3}
|
||||
onMouseEnter={(e) => {
|
||||
e.stopPropagation();
|
||||
setFocusRow(i);
|
||||
setFocusCol(3);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
playBackSound();
|
||||
onUninstall(edition.id);
|
||||
}}
|
||||
className="mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all"
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === 3
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.5"
|
||||
strokeLinecap="square"
|
||||
className="text-white drop-shadow-md"
|
||||
>
|
||||
<polyline points="3 6 5 6 21 6"></polyline>
|
||||
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
||||
<line x1="10" y1="11" x2="10" y2="17"></line>
|
||||
<line x1="14" y1="11" x2="14" y2="17"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</>
|
||||
<img
|
||||
src="/images/Download_Icon.png"
|
||||
alt="Download"
|
||||
className="w-8 h-8 object-contain pointer-events-none drop-shadow-md"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
)}
|
||||
{isCustom && (
|
||||
<>
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={isInstalled ? 4 : 2}
|
||||
onMouseEnter={(e) => {
|
||||
e.stopPropagation();
|
||||
setFocusRow(i);
|
||||
setFocusCol(isInstalled ? 4 : 2);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
playClickSound();
|
||||
setEditingEdition(edition);
|
||||
setIsImportModalOpen(true);
|
||||
}}
|
||||
className="mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all"
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === (isInstalled ? 4 : 2)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.5"
|
||||
strokeLinecap="square"
|
||||
className="text-white drop-shadow-md"
|
||||
>
|
||||
<path d="M12 20h9"></path>
|
||||
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={isInstalled ? 5 : 3}
|
||||
onMouseEnter={(e) => {
|
||||
e.stopPropagation();
|
||||
setFocusRow(i);
|
||||
setFocusCol(isInstalled ? 5 : 3);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
playBackSound();
|
||||
onDeleteEdition(edition.id);
|
||||
}}
|
||||
className="mc-sq-btn w-8 h-8 flex items-center justify-center outline-none border-none transition-all"
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === (isInstalled ? 5 : 3)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="20"
|
||||
height="20"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="square"
|
||||
className="text-red-500 drop-shadow-md"
|
||||
>
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
) : (
|
||||
<>
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={1}
|
||||
onMouseEnter={() => {
|
||||
setFocusRow(i);
|
||||
setFocusCol(1);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
if (!downloadingId) {
|
||||
playClickSound();
|
||||
toggleInstall(edition.id);
|
||||
}
|
||||
}}
|
||||
className={`mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all ${downloadingId === edition.id ? "opacity-100" : downloadingId ? "opacity-50" : ""}`}
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === 1
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
{downloadingId === edition.id ? (
|
||||
<div className="flex flex-col items-center justify-center">
|
||||
<span className="text-[10px] text-white font-bold leading-none">
|
||||
{Math.floor(downloadProgress || 0)}%
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<img
|
||||
src="/images/Update_Icon.png"
|
||||
alt="Update"
|
||||
className="w-8 h-8 object-contain pointer-events-none drop-shadow-md"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
)}
|
||||
</button>
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={2}
|
||||
onMouseEnter={() => {
|
||||
setFocusRow(i);
|
||||
setFocusCol(2);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
playClickSound();
|
||||
TauriService.openInstanceFolder(edition.id);
|
||||
}}
|
||||
className="mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all"
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === 2
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<img
|
||||
src="/images/Folder_Icon.png"
|
||||
alt="Folder"
|
||||
className="w-8 h-8 object-contain pointer-events-none drop-shadow-md"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
loading="lazy"
|
||||
decoding="async"
|
||||
/>
|
||||
</button>
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={3}
|
||||
onMouseEnter={() => {
|
||||
setFocusRow(i);
|
||||
setFocusCol(3);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
playBackSound();
|
||||
onUninstall(edition.id);
|
||||
}}
|
||||
className="mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all"
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === 3
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="22"
|
||||
height="22"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.5"
|
||||
strokeLinecap="square"
|
||||
className="text-white drop-shadow-md"
|
||||
>
|
||||
<polyline points="3 6 5 6 21 6"></polyline>
|
||||
<path d="M19 6v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6m3 0V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2"></path>
|
||||
<line x1="10" y1="11" x2="10" y2="17"></line>
|
||||
<line x1="14" y1="11" x2="14" y2="17"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
{isCustom && (
|
||||
<>
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={isInstalled ? 4 : 2}
|
||||
onMouseEnter={() => {
|
||||
setFocusRow(i);
|
||||
setFocusCol(isInstalled ? 4 : 2);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
playClickSound();
|
||||
setEditingEdition(edition);
|
||||
setIsImportModalOpen(true);
|
||||
}}
|
||||
className="mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all"
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === (isInstalled ? 4 : 2)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="22"
|
||||
height="22"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.5"
|
||||
strokeLinecap="square"
|
||||
className="text-white drop-shadow-md"
|
||||
>
|
||||
<path d="M12 20h9"></path>
|
||||
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z"></path>
|
||||
</svg>
|
||||
</button>
|
||||
<button
|
||||
data-row={i}
|
||||
data-col={isInstalled ? 5 : 3}
|
||||
onMouseEnter={() => {
|
||||
setFocusRow(i);
|
||||
setFocusCol(isInstalled ? 5 : 3);
|
||||
}}
|
||||
onClick={(e) => {
|
||||
e.stopPropagation();
|
||||
playBackSound();
|
||||
onDeleteEdition(edition.id);
|
||||
}}
|
||||
className="mc-sq-btn w-10 h-10 flex items-center justify-center outline-none border-none transition-all"
|
||||
style={{
|
||||
backgroundImage:
|
||||
isRowFocused && focusCol === (isInstalled ? 5 : 3)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
width="24"
|
||||
height="24"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="square"
|
||||
className="text-red-500 drop-shadow-md"
|
||||
>
|
||||
<line x1="18" y1="6" x2="6" y2="18"></line>
|
||||
<line x1="6" y1="6" x2="18" y2="18"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</>
|
||||
)}
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -532,7 +452,7 @@ const VersionsView = memo(function VersionsView() {
|
||||
playClickSound();
|
||||
setIsImportModalOpen(true);
|
||||
}}
|
||||
className={`w-72 h-14 flex items-center justify-center transition-colors text-2xl mc-text-shadow outline-none border-none ${focusRow === editions.length ? "text-[#50C878]" : "text-white"}`}
|
||||
className={`w-72 h-14 flex items-center justify-center transition-colors text-2xl mc-text-shadow outline-none border-none ${focusRow === editions.length ? "text-[#FFFF55]" : "text-white"}`}
|
||||
style={{
|
||||
backgroundImage:
|
||||
focusRow === editions.length
|
||||
@@ -556,7 +476,7 @@ const VersionsView = memo(function VersionsView() {
|
||||
playBackSound();
|
||||
setActiveView("main");
|
||||
}}
|
||||
className={`w-72 h-14 flex items-center justify-center transition-colors text-2xl mc-text-shadow outline-none border-none ${focusRow === editions.length + 1 ? "text-[#50C878]" : "text-white"}`}
|
||||
className={`w-72 h-14 flex items-center justify-center transition-colors text-2xl mc-text-shadow outline-none border-none ${focusRow === editions.length + 1 ? "text-[#FFFF55]" : "text-white"}`}
|
||||
style={{
|
||||
backgroundImage:
|
||||
focusRow === editions.length + 1
|
||||
|
||||
Reference in New Issue
Block a user