mirror of
https://github.com/LCE-Hub/LCE-Emerald-Launcher.git
synced 2026-07-15 23:10:48 +00:00
feat: better setup view, will be even more improved
This commit is contained in:
@@ -12,11 +12,9 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
const {
|
||||
username, setUsername,
|
||||
setHasCompletedSetup,
|
||||
setVfxEnabled: setConfigVfx,
|
||||
setRpcEnabled: setConfigRpc,
|
||||
setLinuxRunner,
|
||||
linuxRunner: configLinuxRunner,
|
||||
vfxEnabled: configVfx,
|
||||
rpcEnabled: configRpc,
|
||||
animationsEnabled,
|
||||
} = useConfig();
|
||||
@@ -30,7 +28,6 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
const [isSettingUpRuntime, setIsSettingUpRuntime] = useState(false);
|
||||
const [setupProgress, setSetupProgress] = useState<{ stage: string; message: string; percent?: number } | null>(null);
|
||||
const [runtimeAlreadyInstalled, setRuntimeAlreadyInstalled] = useState(false);
|
||||
const [enableVfx, setEnableVfx] = useState(configVfx);
|
||||
const [enableDiscordRPC, setEnableDiscordRPC] = useState(configRpc);
|
||||
const totalSteps = 4;
|
||||
useEffect(() => {
|
||||
@@ -86,7 +83,6 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
setCurrentStep(2);
|
||||
setFocusIndex(0);
|
||||
} else if (currentStep === 2) {
|
||||
setConfigVfx(enableVfx);
|
||||
setConfigRpc(enableDiscordRPC);
|
||||
setCurrentStep(3);
|
||||
setFocusIndex(0);
|
||||
@@ -139,8 +135,8 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
else if (focusIndex === 1) handleNext();
|
||||
}
|
||||
} else if (currentStep === 2) {
|
||||
if (focusIndex === 0) { setEnableVfx(!enableVfx); playPressSound(); }
|
||||
else if (focusIndex === 1) { setEnableDiscordRPC(!enableDiscordRPC); playPressSound(); }
|
||||
if (focusIndex === 0) { setEnableDiscordRPC(!enableDiscordRPC); playPressSound(); }
|
||||
else if (focusIndex === 1) { playPressSound(); }
|
||||
else if (focusIndex === 2) handleBack();
|
||||
else if (focusIndex === 3) handleNext();
|
||||
} else if (currentStep === 3) {
|
||||
@@ -151,7 +147,7 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
};
|
||||
window.addEventListener("keydown", handleKey);
|
||||
return () => window.removeEventListener("keydown", handleKey);
|
||||
}, [currentStep, focusIndex, runners, enableVfx, enableDiscordRPC, isLinux, isMac, tempUsername]);
|
||||
}, [currentStep, focusIndex, runners, enableDiscordRPC, isLinux, isMac, tempUsername]);
|
||||
|
||||
const handleMacosSetup = async () => {
|
||||
playPressSound();
|
||||
@@ -179,7 +175,6 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
return true;
|
||||
};
|
||||
|
||||
const stepTitles = ["Welcome", "Compatibility", "Preferences", "Ready"];
|
||||
const navBtnStyle = (isFocused: boolean) => ({
|
||||
backgroundImage: isFocused
|
||||
? "url('/images/button_highlighted.png')"
|
||||
@@ -200,71 +195,110 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
/>
|
||||
</div>
|
||||
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
key={currentStep}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: animationsEnabled ? 0.2 : 0 }}
|
||||
className="max-w-xl w-full mx-auto flex flex-col items-center"
|
||||
>
|
||||
<div
|
||||
className="max-w-xl w-full mx-auto flex flex-col items-center"
|
||||
>
|
||||
<div
|
||||
className="relative p-8 flex flex-col w-full"
|
||||
style={{
|
||||
backgroundImage: "url('/images/frame_background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
backgroundRepeat: "no-repeat",
|
||||
imageRendering: "pixelated",
|
||||
maxHeight: "85vh",
|
||||
}}
|
||||
>
|
||||
<div className="flex justify-center gap-3 mb-6">
|
||||
{Array.from({ length: totalSteps }, (_, i) => (
|
||||
<div
|
||||
key={i}
|
||||
className={`h-1.5 w-12 transition-all duration-300 ${i <= currentStep ? "bg-white" : "bg-white/20"}`}
|
||||
/>
|
||||
))}
|
||||
</div>
|
||||
<h2 className="text-2xl text-white mc-text-shadow mb-1 border-b-2 border-[#373737] pb-2 text-center tracking-widest uppercase opacity-80 font-bold">
|
||||
{stepTitles[currentStep]}
|
||||
</h2>
|
||||
<AnimatePresence mode="wait">
|
||||
<motion.div
|
||||
key={`content-${currentStep}`}
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
exit={{ opacity: 0 }}
|
||||
transition={{ duration: animationsEnabled ? 0.2 : 0, delay: animationsEnabled ? 0.05 : 0 }}
|
||||
className="mt-4 overflow-y-auto flex-1"
|
||||
style={{ scrollbarWidth: "thin", scrollbarColor: "#555 transparent" }}
|
||||
>
|
||||
{currentStep === 0 && (
|
||||
<p className="text-white text-sm tracking-widest text-center uppercase mb-4">
|
||||
Let's configure your launcher
|
||||
</p>
|
||||
)}
|
||||
{currentStep === 1 && (
|
||||
<p className="text-white text-xs tracking-widest text-center uppercase mb-4">
|
||||
Compatibility Runtime
|
||||
</p>
|
||||
)}
|
||||
{currentStep === 2 && (
|
||||
<p className="text-white text-xs tracking-widest text-center uppercase mb-4">
|
||||
Choose your preferred options and behaviors
|
||||
</p>
|
||||
)}
|
||||
<div
|
||||
className="mt-4 overflow-y-auto flex-1"
|
||||
style={{ scrollbarWidth: "thin", scrollbarColor: "#555 transparent" }}
|
||||
>
|
||||
|
||||
{currentStep === 0 && (
|
||||
<div
|
||||
className="p-5 flex flex-col gap-4 mc-options-bg"
|
||||
>
|
||||
<p className="text-white/70 text-sm tracking-widest text-center uppercase">
|
||||
Let's configure your launcher
|
||||
</p>
|
||||
<label className="block">
|
||||
<span className="text-white font-bold uppercase tracking-widest text-sm mc-text-shadow block mb-2">Username</span>
|
||||
<input
|
||||
type="text"
|
||||
value={tempUsername}
|
||||
onChange={(e) => setTempUsername(e.target.value)}
|
||||
onFocus={() => setFocusIndex(0)}
|
||||
className={`w-full px-4 py-2 bg-black/60 focus:outline-none transition-colors text-white tracking-widest
|
||||
${focusIndex === 0 ? "border-2 border-[#FFFF55] text-[#FFFF55]" : "border-2 border-white/30"}`}
|
||||
style={{ imageRendering: "pixelated", fontFamily: "'Mojangles', monospace" }}
|
||||
placeholder="Enter your username"
|
||||
maxLength={16}
|
||||
autoFocus
|
||||
/>
|
||||
<label className="block relative">
|
||||
<span className="text-black font-bold uppercase tracking-widest text-sm block mb-2">Username</span>
|
||||
<div className="relative">
|
||||
<input
|
||||
type="text"
|
||||
ref={(el) => {
|
||||
if (el) {
|
||||
const selectionStart = el.selectionStart ?? 0;
|
||||
const textBeforeCursor = tempUsername.substring(0, selectionStart);
|
||||
const span = document.createElement('span');
|
||||
span.style.font = getComputedStyle(el).font;
|
||||
span.style.letterSpacing = getComputedStyle(el).letterSpacing;
|
||||
span.textContent = textBeforeCursor;
|
||||
document.body.appendChild(span);
|
||||
const cursorPosition = span.offsetWidth;
|
||||
document.body.removeChild(span);
|
||||
const caret = document.getElementById('custom-caret');
|
||||
if (caret) {
|
||||
caret.style.left = `${cursorPosition + 16}px`;
|
||||
}
|
||||
}
|
||||
}}
|
||||
value={tempUsername}
|
||||
onChange={(e) => setTempUsername(e.target.value)}
|
||||
onFocus={() => setFocusIndex(0)}
|
||||
onSelect={() => {
|
||||
const el = document.querySelector('input[type="text"]') as HTMLInputElement;
|
||||
if (el) {
|
||||
const selectionStart = el.selectionStart ?? 0;
|
||||
const textBeforeCursor = tempUsername.substring(0, selectionStart);
|
||||
const span = document.createElement('span');
|
||||
span.style.font = getComputedStyle(el).font;
|
||||
span.style.letterSpacing = getComputedStyle(el).letterSpacing;
|
||||
span.textContent = textBeforeCursor;
|
||||
document.body.appendChild(span);
|
||||
const cursorPosition = span.offsetWidth;
|
||||
document.body.removeChild(span);
|
||||
const caret = document.getElementById('custom-caret');
|
||||
if (caret) {
|
||||
caret.style.left = `${cursorPosition + 16}px`;
|
||||
}
|
||||
}
|
||||
}}
|
||||
className={`w-full px-4 py-2 focus:outline-none transition-colors text-white tracking-widest
|
||||
${focusIndex === 0 ? "border-4 border-[#FFFF55] text-[#FFFF55]" : "border-4 border-[#323232]"}`}
|
||||
style={{
|
||||
imageRendering: "pixelated",
|
||||
fontFamily: "'Mojangles', monospace",
|
||||
backgroundColor: "#646464",
|
||||
caretColor: "transparent"
|
||||
}}
|
||||
placeholder="Enter your username"
|
||||
maxLength={16}
|
||||
autoFocus
|
||||
/>
|
||||
{focusIndex === 0 && (
|
||||
<span
|
||||
id="custom-caret"
|
||||
className="absolute top-1/2 -translate-y-1/2 text-white blink-caret"
|
||||
style={{
|
||||
fontFamily: "'Mojangles', monospace",
|
||||
left: "16px"
|
||||
}}
|
||||
>
|
||||
_
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
</label>
|
||||
{tempUsername.trim().length === 0 && (
|
||||
<p className="text-white/40 text-xs text-center uppercase tracking-widest">A username is required to continue</p>
|
||||
<p className="text-gray-500 text-xs text-center uppercase tracking-widest">A username is required to continue</p>
|
||||
)}
|
||||
</div>
|
||||
)}
|
||||
@@ -273,35 +307,36 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
<div
|
||||
className="p-5 flex flex-col gap-4 mc-options-bg"
|
||||
>
|
||||
<p className="text-white/70 text-xs tracking-widest text-center uppercase">
|
||||
{runtimeAlreadyInstalled
|
||||
? "Compatibility runtime is already installed"
|
||||
: "Emerald needs a compatibility runtime to run on macOS"
|
||||
}
|
||||
</p>
|
||||
|
||||
<div className={`flex items-center gap-3 p-3 border-2 ${runtimeAlreadyInstalled ? "border-green-400/60 bg-green-900/10" : "border-yellow-400/60 bg-yellow-900/10"}`}>
|
||||
<span className={`text-xl ${runtimeAlreadyInstalled ? "text-green-400" : "text-yellow-400"}`}>
|
||||
{runtimeAlreadyInstalled ? "✓" : "⚠"}
|
||||
</span>
|
||||
<div className={`flex items-center gap-3 p-3 border-2 ${runtimeAlreadyInstalled ? "border-green-400/60 bg-green-100" : "border-yellow-400/60 bg-yellow-100"}`}>
|
||||
{runtimeAlreadyInstalled ? (
|
||||
<img
|
||||
src="/images/check.png"
|
||||
alt="checked"
|
||||
className="w-6 h-6"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
) : (
|
||||
<span className="text-xl text-yellow-600">⚠</span>
|
||||
)}
|
||||
<div>
|
||||
<p className={`font-bold text-sm uppercase tracking-widest ${runtimeAlreadyInstalled ? "text-green-400" : "text-yellow-400"}`}>
|
||||
<p className={`font-bold text-sm uppercase tracking-widest ${runtimeAlreadyInstalled ? "text-green-700" : "text-yellow-700"}`}>
|
||||
{runtimeAlreadyInstalled ? "Runtime Detected" : "Runtime Not Detected"}
|
||||
</p>
|
||||
<p className="text-white/60 text-xs mt-0.5">
|
||||
<p className="text-gray-700 text-xs mt-0.5">
|
||||
{runtimeAlreadyInstalled
|
||||
? "Ready to use — you can proceed."
|
||||
? "Game Porting Toolkit 3 and Wine installed"
|
||||
: "You must install the runtime before proceeding."}
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{setupProgress && (
|
||||
<div className="p-3 bg-black/40 border border-white/10">
|
||||
<p className="text-yellow-400 text-xs font-bold uppercase tracking-widest mb-1">{setupProgress.stage}</p>
|
||||
<p className="text-white/70 text-xs">{setupProgress.message}</p>
|
||||
<div className="p-3 bg-gray-100 border border-gray-300">
|
||||
<p className="text-yellow-600 text-xs font-bold uppercase tracking-widest mb-1">{setupProgress.stage}</p>
|
||||
<p className="text-gray-700 text-xs">{setupProgress.message}</p>
|
||||
{setupProgress.percent !== undefined && (
|
||||
<div className="w-full bg-white/10 h-1.5 mt-2">
|
||||
<div className="w-full bg-gray-300 h-1.5 mt-2">
|
||||
<div
|
||||
className="h-full bg-green-400 transition-all duration-300"
|
||||
style={{ width: `${setupProgress.percent}%` }}
|
||||
@@ -332,12 +367,9 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
<div
|
||||
className="p-5 flex flex-col gap-3 mc-options-bg"
|
||||
>
|
||||
<p className="text-white/70 text-xs tracking-widest text-center uppercase">
|
||||
Choose your preferred compatibility layer
|
||||
</p>
|
||||
{runners.length === 0 ? (
|
||||
<div className="p-3 border-2 border-yellow-400/50 bg-yellow-900/10">
|
||||
<p className="text-yellow-400 text-sm text-center">No compatible runners found. Please install Wine or Proton.</p>
|
||||
<div className="p-3 border-2 border-yellow-400/50 bg-yellow-50">
|
||||
<p className="text-yellow-600 text-sm text-center">No compatible runners found. Please install Wine or Proton.</p>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col gap-2">
|
||||
@@ -347,11 +379,11 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
onClick={() => handleRunnerSelect(runner.id)}
|
||||
onMouseEnter={() => setFocusIndex(idx)}
|
||||
className={`w-full h-10 flex items-center justify-between px-4 transition-all outline-none border-none
|
||||
${selectedRunner === runner.id ? "bg-white/10" : "bg-transparent"}
|
||||
${focusIndex === idx ? "text-[#FFFF55]" : "text-white/80"} hover:text-[#FFFF55] hover:bg-black/10`}
|
||||
${selectedRunner === runner.id ? "bg-gray-200" : "bg-transparent"}
|
||||
${focusIndex === idx ? "text-[#FFFF55]" : "text-gray-800"} hover:text-[#FFFF55] hover:bg-gray-200`}
|
||||
style={navBtnStyle(focusIndex === idx)}
|
||||
>
|
||||
<span className="tracking-widest uppercase text-lg mc-text-shadow">{runner.name}</span>
|
||||
<span className="tracking-widest uppercase text-lg text-gray-800">{runner.name}</span>
|
||||
{selectedRunner === runner.id && (
|
||||
<span className="text-[#FFFF55] text-sm">✓</span>
|
||||
)}
|
||||
@@ -359,7 +391,7 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
<p className="text-xs text-white/40 text-center uppercase tracking-widest mt-1">You can change this later in settings</p>
|
||||
<p className="text-xs text-gray-500 text-center uppercase tracking-widest mt-1">You can change this later in settings</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -367,14 +399,11 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
<div
|
||||
className="p-5 flex flex-col gap-4 mc-options-bg"
|
||||
>
|
||||
<p className="text-white/70 text-xs tracking-widest text-center uppercase">
|
||||
Everything is ready to go!
|
||||
</p>
|
||||
<div className="flex items-center gap-3 p-3 border-2 border-green-400/60 bg-green-900/10">
|
||||
<div className="flex items-center gap-3 p-3 border-2 border-green-400/60 bg-green-50">
|
||||
<span className="text-green-400 text-xl">✓</span>
|
||||
<div>
|
||||
<p className="text-green-400 font-bold text-sm uppercase tracking-widest">Windows Native Support</p>
|
||||
<p className="text-white/60 text-xs mt-0.5">Emerald Legacy runs natively on Windows without additional requirements.</p>
|
||||
<p className="text-green-600 font-bold text-sm uppercase tracking-widest">Windows Native Support</p>
|
||||
<p className="text-gray-600 text-xs mt-0.5">Emerald Legacy runs natively on Windows without additional requirements.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -384,48 +413,18 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
<div
|
||||
className="p-5 flex flex-col gap-2 mc-options-bg"
|
||||
>
|
||||
<p className="text-white/70 text-xs tracking-widest text-center uppercase mb-2">
|
||||
Choose your preferred launcher settings
|
||||
</p>
|
||||
|
||||
<button
|
||||
onClick={() => { playPressSound(); setEnableVfx(!enableVfx); }}
|
||||
onMouseEnter={() => setFocusIndex(0)}
|
||||
className={`w-full h-10 flex items-center justify-between px-4 transition-all outline-none border-none rounded
|
||||
${focusIndex === 0 ? "bg-black/10" : "bg-transparent"} hover:bg-black/15`}
|
||||
>
|
||||
<span className={`tracking-widest uppercase text-lg mc-text-shadow ${focusIndex === 0 ? "text-[#FFFF55]" : "text-white/80"}`}>
|
||||
Click effects
|
||||
</span>
|
||||
<div className="relative w-6 h-6 shrink-0">
|
||||
<img
|
||||
src={focusIndex === 0 ? "/images/checkbox_highlighted.png" : "/images/checkbox.png"}
|
||||
alt="checkbox"
|
||||
className="w-full h-full object-contain"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
{enableVfx && (
|
||||
<img
|
||||
src="/images/check.png"
|
||||
alt="checked"
|
||||
className="absolute inset-0 w-full h-full object-contain"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => { playPressSound(); setEnableDiscordRPC(!enableDiscordRPC); }}
|
||||
onMouseEnter={() => setFocusIndex(1)}
|
||||
onMouseEnter={() => setFocusIndex(0)}
|
||||
className={`w-full h-10 flex items-center justify-between px-4 transition-all outline-none border-none rounded
|
||||
${focusIndex === 1 ? "bg-black/10" : "bg-transparent"} hover:bg-black/15`}
|
||||
${focusIndex === 0 ? "bg-gray-200" : "bg-transparent"} hover:bg-gray-200`}
|
||||
>
|
||||
<span className={`tracking-widest uppercase text-lg mc-text-shadow ${focusIndex === 1 ? "text-[#FFFF55]" : "text-white/80"}`}>
|
||||
<span className={`tracking-widest uppercase text-lg ${focusIndex === 0 ? "text-[#FFFF55]" : "text-gray-800"}`}>
|
||||
Discord RPC
|
||||
</span>
|
||||
<div className="relative w-6 h-6 shrink-0">
|
||||
<img
|
||||
src={focusIndex === 1 ? "/images/checkbox_highlighted.png" : "/images/checkbox.png"}
|
||||
src={focusIndex === 0 ? "/images/checkbox_highlighted.png" : "/images/checkbox.png"}
|
||||
alt="checkbox"
|
||||
className="w-full h-full object-contain"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
@@ -440,8 +439,34 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
<button
|
||||
onClick={() => { playPressSound(); }}
|
||||
onMouseEnter={() => setFocusIndex(1)}
|
||||
className={`w-full h-10 flex items-center justify-between px-4 transition-all outline-none border-none rounded
|
||||
${focusIndex === 1 ? "bg-gray-200" : "bg-transparent"} hover:bg-gray-200`}
|
||||
>
|
||||
<span className={`tracking-widest uppercase text-lg ${focusIndex === 1 ? "text-[#FFFF55]" : "text-gray-800"}`}>
|
||||
Animations
|
||||
</span>
|
||||
<div className="relative w-6 h-6 shrink-0">
|
||||
<img
|
||||
src={focusIndex === 1 ? "/images/checkbox_highlighted.png" : "/images/checkbox.png"}
|
||||
alt="checkbox"
|
||||
className="w-full h-full object-contain"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
{animationsEnabled && (
|
||||
<img
|
||||
src="/images/check.png"
|
||||
alt="checked"
|
||||
className="absolute inset-0 w-full h-full object-contain"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
)}
|
||||
</div>
|
||||
</button>
|
||||
|
||||
<p className="text-xs text-white/40 text-center uppercase tracking-widest mt-2">You can change these later in settings</p>
|
||||
<p className="text-xs text-gray-500 text-center uppercase tracking-widest mt-2">You can change these later in settings</p>
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -449,29 +474,29 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
<div
|
||||
className="p-5 flex flex-col gap-3 mc-options-bg"
|
||||
>
|
||||
<p className="text-white/70 text-xs tracking-widest text-center uppercase">
|
||||
<p className="text-gray-700 text-xs tracking-widest text-center uppercase">
|
||||
Emerald Launcher is now configured and ready to use!
|
||||
</p>
|
||||
|
||||
<div className="flex flex-col gap-1 mt-1">
|
||||
<div className="flex items-center justify-between px-4 h-10 border-b border-white/10">
|
||||
<span className="text-white/60 text-sm uppercase tracking-widest">Username</span>
|
||||
<span className="text-gray-600 text-sm uppercase tracking-widest">Username</span>
|
||||
<span className="text-[#FFFF55] font-bold mc-text-shadow">{tempUsername}</span>
|
||||
</div>
|
||||
{isMac && (
|
||||
<div className="flex items-center justify-between px-4 h-10 border-b border-white/10">
|
||||
<span className="text-white/60 text-sm uppercase tracking-widest">Runtime</span>
|
||||
<span className="text-gray-600 text-sm uppercase tracking-widest">Runtime</span>
|
||||
<span className="text-green-400 font-bold">Ready</span>
|
||||
</div>
|
||||
)}
|
||||
{isLinux && selectedRunner && (
|
||||
<div className="flex items-center justify-between px-4 h-10 border-b border-white/10">
|
||||
<span className="text-white/60 text-sm uppercase tracking-widest">Runner</span>
|
||||
<span className="text-gray-600 text-sm uppercase tracking-widest">Runner</span>
|
||||
<span className="text-green-400 font-bold">{runners.find(r => r.id === selectedRunner)?.name}</span>
|
||||
</div>
|
||||
)}
|
||||
<div className="flex items-center justify-between px-4 h-10 border-b border-white/10">
|
||||
<span className="text-white/60 text-sm uppercase tracking-widest">Click Effects</span>
|
||||
<span className="text-gray-600 text-sm uppercase tracking-widest">Animations</span>
|
||||
<div className="relative w-5 h-5">
|
||||
<img
|
||||
src="/images/checkbox.png"
|
||||
@@ -479,7 +504,7 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
className="w-full h-full object-contain"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
{enableVfx && (
|
||||
{animationsEnabled && (
|
||||
<img
|
||||
src="/images/check.png"
|
||||
alt="checked"
|
||||
@@ -490,7 +515,7 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center justify-between px-4 h-10">
|
||||
<span className="text-white/60 text-sm uppercase tracking-widest">Discord RPC</span>
|
||||
<span className="text-gray-600 text-sm uppercase tracking-widest">Discord RPC</span>
|
||||
<div className="relative w-5 h-5">
|
||||
<img
|
||||
src="/images/checkbox.png"
|
||||
@@ -511,8 +536,7 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
|
||||
<div className="flex justify-between mt-5 gap-3">
|
||||
{currentStep > 0 ? (
|
||||
@@ -568,8 +592,7 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
|
||||
@@ -155,6 +155,19 @@ body {
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes blink-caret {
|
||||
0%, 50% {
|
||||
opacity: 1;
|
||||
}
|
||||
51%, 100% {
|
||||
opacity: 0;
|
||||
}
|
||||
}
|
||||
|
||||
.blink-caret {
|
||||
animation: blink-caret 1s step-end infinite;
|
||||
}
|
||||
|
||||
.particle-burst {
|
||||
animation: sga-burst 0.8s ease-out forwards;
|
||||
filter: drop-shadow(0 0 8px rgba(180, 100, 255, 0.9));
|
||||
|
||||
Reference in New Issue
Block a user