mirror of
https://github.com/LCE-Hub/LCE-Emerald-Launcher.git
synced 2026-07-15 23:10:48 +00:00
refractor(ui): optimized App.txs animations and extract CSS
This commit is contained in:
@@ -1 +1,55 @@
|
||||
/* empty :P */
|
||||
@keyframes splashPulse {
|
||||
0% { transform: scale(0.95) rotate(-20deg); }
|
||||
100% { transform: scale(1.08) rotate(-20deg); }
|
||||
}
|
||||
|
||||
.mc-splash {
|
||||
animation: splashPulse 0.45s ease-in-out infinite alternate;
|
||||
transform-origin: center;
|
||||
}
|
||||
|
||||
.mc-slider-custom {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
background: transparent;
|
||||
height: 100%;
|
||||
outline: none;
|
||||
border: none;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
|
||||
.mc-slider-custom::-webkit-slider-thumb {
|
||||
-webkit-appearance: none;
|
||||
appearance: none;
|
||||
width: 14px;
|
||||
height: 44px;
|
||||
background: url('/images/Slider_Handle.png') no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
z-index: 30;
|
||||
}
|
||||
|
||||
*:focus {
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
button, input {
|
||||
border-radius: 0 !important;
|
||||
border: none !important;
|
||||
outline: none !important;
|
||||
box-shadow: none !important;
|
||||
}
|
||||
|
||||
.mc-sq-btn {
|
||||
background: url('/images/Button_Square.png') no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.mc-sq-btn:hover {
|
||||
background: url('/images/Button_Square_Highlighted.png') no-repeat center;
|
||||
background-size: 100% 100%;
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
import { useEffect, useState } from "react";
|
||||
import { useEffect, useState, useMemo } from "react";
|
||||
import { motion, AnimatePresence, MotionConfig } from "framer-motion";
|
||||
import "../css/App.css";
|
||||
import HomeView from "../components/views/HomeView";
|
||||
import SettingsView from "../components/views/SettingsView";
|
||||
import VersionsView from "../components/views/VersionsView";
|
||||
@@ -35,6 +36,7 @@ import { useLceLiveNotifications } from "../hooks/useLceLiveNotifications";
|
||||
import type { Edition } from "../types/edition";
|
||||
import pkg from "../../package.json";
|
||||
export default function App() {
|
||||
const ui = useUI();
|
||||
const {
|
||||
showIntro,
|
||||
setShowIntro,
|
||||
@@ -49,24 +51,24 @@ export default function App() {
|
||||
updateMessage,
|
||||
updateUrl,
|
||||
clearUpdateMessage,
|
||||
} = useUI();
|
||||
connected,
|
||||
} = ui;
|
||||
const config = useConfig();
|
||||
const audio = useAudio();
|
||||
const game = useGame();
|
||||
const { skinUrl, setSkinUrl, capeUrl } = useSkin();
|
||||
const skin = useSkin();
|
||||
const { skinUrl, setSkinUrl, capeUrl } = skin;
|
||||
const notifications = useLceLiveNotifications();
|
||||
const {
|
||||
friendRequestMessage,
|
||||
gameInviteMessage,
|
||||
clearFriendRequestMessage,
|
||||
clearGameInviteMessage,
|
||||
} = useLceLiveNotifications();
|
||||
} = notifications;
|
||||
const [showSetup, setShowSetup] = useState(false);
|
||||
const [displayIsDay, setDisplayIsDay] = useState(config.isDayTime);
|
||||
const [isSetupChecked, setIsSetupChecked] = useState(false);
|
||||
const displayIsDay = config.isDayTime;
|
||||
|
||||
useEffect(() => {
|
||||
setDisplayIsDay(config.isDayTime);
|
||||
}, [config.isDayTime]);
|
||||
|
||||
useEffect(() => {
|
||||
if (config.isLoaded) {
|
||||
@@ -76,14 +78,13 @@ export default function App() {
|
||||
}
|
||||
}, [config.isLoaded]);
|
||||
|
||||
const selectedEdition = game.editions.find(
|
||||
(e: Edition) => e.instanceId === config.profile,
|
||||
const selectedEdition = useMemo(() =>
|
||||
game.editions.find((e: Edition) => e.instanceId === config.profile),
|
||||
[game.editions, config.profile]
|
||||
);
|
||||
const selectedVersionName = selectedEdition?.name || "";
|
||||
const selectedVersionName = selectedEdition?.name ?? "";
|
||||
const hasAnyInstall = game.installs.length > 0;
|
||||
const titleImage = hasAnyInstall
|
||||
? selectedEdition?.titleImage || "/images/MenuTitle.png"
|
||||
: "/images/MenuTitle.png";
|
||||
const titleImage = selectedEdition?.titleImage ?? "/images/MenuTitle.png";
|
||||
|
||||
useEffect(() => {
|
||||
const handleContextMenu = (e: MouseEvent) => e.preventDefault();
|
||||
@@ -91,19 +92,20 @@ export default function App() {
|
||||
return () => document.removeEventListener("contextmenu", handleContextMenu);
|
||||
}, []);
|
||||
|
||||
const uiFade = {
|
||||
const animDuration = config.animationsEnabled ? undefined : { duration: 0 };
|
||||
const uiFade = useMemo(() => ({
|
||||
initial: { opacity: 0 },
|
||||
animate: { opacity: 1 },
|
||||
exit: { opacity: 0 },
|
||||
transition: { duration: config.animationsEnabled ? 0.5 : 0 },
|
||||
};
|
||||
transition: animDuration ?? { duration: 0.5 },
|
||||
}), [animDuration]);
|
||||
|
||||
const backgroundFade = {
|
||||
const backgroundFade = useMemo(() => ({
|
||||
initial: { opacity: 0 },
|
||||
animate: { opacity: 1 },
|
||||
exit: { opacity: 0 },
|
||||
transition: { duration: config.animationsEnabled ? 0.8 : 0 },
|
||||
};
|
||||
transition: animDuration ?? { duration: 0.8 },
|
||||
}), [animDuration]);
|
||||
|
||||
if (!config.isLoaded || !isSetupChecked) {
|
||||
return <div className="w-screen h-screen bg-black" />;
|
||||
@@ -140,16 +142,6 @@ export default function App() {
|
||||
<div
|
||||
className={`w-screen h-screen overflow-hidden select-none flex flex-col relative bg-black text-white font-['Mojangles'] outline-none focus:outline-none ${!config.animationsEnabled ? "no-animations" : ""}`}
|
||||
>
|
||||
<style>{`
|
||||
@keyframes splashPulse { 0% { transform: scale(0.95) rotate(-20deg); } 100% { transform: scale(1.08) rotate(-20deg); } }
|
||||
.mc-splash { animation: splashPulse 0.45s ease-in-out infinite alternate; transform-origin: center; }
|
||||
.mc-slider-custom { -webkit-appearance: none; appearance: none; background: transparent; height: 100%; outline: none; border: none; margin: 0; padding: 0; }
|
||||
.mc-slider-custom::-webkit-slider-thumb { -webkit-appearance: none; appearance: none; width: 14px; height: 44px; background: url('/images/Slider_Handle.png') no-repeat center; background-size: 100% 100%; cursor: pointer; position: relative; z-index: 30; }
|
||||
*:focus { outline: none !important; box-shadow: none !important; }
|
||||
button, input { border-radius: 0 !important; border: none !important; outline: none !important; box-shadow: none !important; }
|
||||
.mc-sq-btn { background: url('/images/Button_Square.png') no-repeat center; background-size: 100% 100%; image-rendering: pixelated; }
|
||||
.mc-sq-btn:hover { background: url('/images/Button_Square_Highlighted.png') no-repeat center; background-size: 100% 100%; }
|
||||
`}</style>
|
||||
|
||||
<div className="absolute inset-0">
|
||||
<AnimatePresence>
|
||||
@@ -179,13 +171,11 @@ export default function App() {
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<AnimatePresence>
|
||||
<DownloadOverlay
|
||||
downloadProgress={game.downloadProgress}
|
||||
downloadingId={game.downloadingId}
|
||||
editions={game.editions}
|
||||
/>
|
||||
</AnimatePresence>
|
||||
<DownloadOverlay
|
||||
downloadProgress={game.downloadProgress}
|
||||
downloadingId={game.downloadingId}
|
||||
editions={game.editions}
|
||||
/>
|
||||
|
||||
<AchievementToast
|
||||
message={game.error}
|
||||
@@ -223,243 +213,220 @@ export default function App() {
|
||||
variant="steam"
|
||||
/>
|
||||
|
||||
<AnimatePresence>
|
||||
<motion.div
|
||||
key="dashboard"
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
className="flex flex-col h-full z-10 w-full relative"
|
||||
>
|
||||
<AnimatePresence>
|
||||
<>
|
||||
{!config.legacyMode && (
|
||||
<motion.div
|
||||
key="hideBtn"
|
||||
{...uiFade}
|
||||
className="absolute top-4 left-8 z-50"
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
audio.playPressSound();
|
||||
setIsUiHidden(!isUiHidden);
|
||||
}}
|
||||
className="hover:scale-110 active:scale-95 transition-transform outline-none bg-transparent border-none"
|
||||
>
|
||||
<img
|
||||
src={
|
||||
isUiHidden
|
||||
? "/images/Unhide_UI_Button.png"
|
||||
: "/images/Hide_UI_Button.png"
|
||||
}
|
||||
className="w-10 h-10 cursor-pointer object-contain"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</button>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{!config.legacyMode && (
|
||||
<motion.div
|
||||
key="dayToggle"
|
||||
{...uiFade}
|
||||
className="absolute bottom-6 right-8 z-50 flex items-center gap-3"
|
||||
>
|
||||
<span className="text-[#E0E0E0] text-[10px] mc-text-shadow tracking-widest uppercase opacity-70 mt-1">
|
||||
{displayIsDay ? "Day" : "Night"}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
audio.playPressSound();
|
||||
config.setIsDayTime(!config.isDayTime);
|
||||
}}
|
||||
className="hover:scale-110 active:scale-95 transition-transform outline-none bg-transparent border-none"
|
||||
>
|
||||
<img
|
||||
src={
|
||||
displayIsDay
|
||||
? "/images/Day_Toggle.png"
|
||||
: "/images/Night_Toggle.png"
|
||||
}
|
||||
alt="Toggle Time"
|
||||
className="w-12 h-12 cursor-pointer block object-contain"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</button>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{isUiHidden &&
|
||||
!displayIsDay &&
|
||||
activeView == "devtools" && (
|
||||
<motion.div
|
||||
key="secret-swf-btn"
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.8 }}
|
||||
className="absolute inset-0 z-[100] flex items-center justify-center pointer-events-none"
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
audio.playPressSound();
|
||||
setIsUiHidden(false);
|
||||
setActiveView("swf-editor");
|
||||
}}
|
||||
className="pointer-events-auto hover:scale-110 active:scale-95 transition-transform outline-none bg-transparent border-none flex flex-col items-center gap-2 group"
|
||||
>
|
||||
<img
|
||||
src="/images/tools/pck.png"
|
||||
className="w-16 h-16 cursor-pointer object-contain opacity-50 group-hover:opacity-100 drop-shadow-[0_4px_4px_rgba(0,0,0,1)] grayscale group-hover:grayscale-0"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).src =
|
||||
"/images/Button_Background.png";
|
||||
}}
|
||||
/>
|
||||
<span className="text-[#FFFF55] text-sm mc-text-shadow opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
SWF Editor
|
||||
</span>
|
||||
</button>
|
||||
</motion.div>
|
||||
)}
|
||||
</>
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="shrink-0 flex justify-center py-4 relative w-full pt-4">
|
||||
<div className="relative w-full max-w-135 flex justify-center">
|
||||
<motion.img
|
||||
layoutId="mainLogo"
|
||||
src={titleImage}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 300,
|
||||
damping: 25,
|
||||
}}
|
||||
className="w-full drop-shadow-[0_8px_6px_rgba(0,0,0,0.8)] pointer-events-none"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
<AnimatePresence>
|
||||
<>
|
||||
<motion.div
|
||||
key="splash"
|
||||
{...uiFade}
|
||||
className="absolute bottom-[20%] right-[5%] w-0 h-0 flex items-center justify-center"
|
||||
>
|
||||
<div
|
||||
onClick={audio.cycleSplash}
|
||||
className="mc-splash text-[#FFFF55] text-[28px] z-100 cursor-pointer whitespace-nowrap"
|
||||
style={{ textShadow: "2px 2px 0px #3F3F00" }}
|
||||
>
|
||||
{audio.splashIndex === -1
|
||||
? `Welcome ${config.username}!`
|
||||
: audio.splashes[audio.splashIndex]}
|
||||
</div>
|
||||
</motion.div>
|
||||
{activeView === "main" &&
|
||||
hasAnyInstall &&
|
||||
titleImage === "/images/MenuTitle.png" && (
|
||||
<motion.div
|
||||
key="tu-subtitle"
|
||||
{...uiFade}
|
||||
className="absolute -bottom-6 text-[#A0A0A0] text-sm mc-text-shadow tracking-widest uppercase opacity-80 font-['Mojangles']"
|
||||
>
|
||||
{selectedVersionName}
|
||||
</motion.div>
|
||||
)}
|
||||
</>
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main className="flex-1 w-full relative">
|
||||
<div
|
||||
className={`w-full h-full flex flex-col items-center justify-center ${isUiHidden ? "opacity-0 pointer-events-none" : "opacity-100"}`}
|
||||
>
|
||||
<AnimatePresence mode="wait">
|
||||
{activeView === "main" && (
|
||||
<SkinViewer
|
||||
key="skin-viewer"
|
||||
username={config.username}
|
||||
setUsername={config.setUsername}
|
||||
playPressSound={audio.playPressSound}
|
||||
skinUrl={skinUrl}
|
||||
capeUrl={config.legacyMode ? null : capeUrl}
|
||||
setSkinUrl={setSkinUrl}
|
||||
setActiveView={setActiveView}
|
||||
isFocusedSection={focusSection === "skin"}
|
||||
onNavigateRight={onNavigateToMenu}
|
||||
/>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="w-full h-full max-w-4xl relative flex justify-center items-center overflow-hidden">
|
||||
<AnimatePresence mode="wait">
|
||||
{activeView === "main" && <HomeView key="main-view" />}
|
||||
{activeView === "settings" && (
|
||||
<SettingsView key="settings-view" />
|
||||
)}
|
||||
{activeView === "versions" && (
|
||||
<VersionsView key="versions-view" />
|
||||
)}
|
||||
{activeView === "workshop" && (
|
||||
<WorkshopView key="workshop-view" />
|
||||
)}
|
||||
{activeView === "devtools" && (
|
||||
<DevtoolsView key="devtools-view" />
|
||||
)}
|
||||
{activeView === "pck-editor" && (
|
||||
<PckEditorView key="pck-editor-view" />
|
||||
)}
|
||||
{activeView === "arc-editor" && (
|
||||
<ArcEditorView key="arc-editor-view" />
|
||||
)}
|
||||
{activeView === "loc-editor" && (
|
||||
<LocEditorView key="loc-editor-view" />
|
||||
)}
|
||||
{activeView === "grf-editor" && (
|
||||
<GrfEditorView key="grf-editor-view" />
|
||||
)}
|
||||
{activeView === "col-editor" && (
|
||||
<ColEditorView key="col-editor-view" />
|
||||
)}
|
||||
{activeView === "options-editor" && (
|
||||
<OptionsEditorView key="options-editor-view" />
|
||||
)}
|
||||
{activeView === "swf-editor" && (
|
||||
<SwfView key="swf-editor-view" />
|
||||
)}
|
||||
{activeView === "lcelive" && (
|
||||
<LceLiveView key="lcelive-view" />
|
||||
)}
|
||||
{activeView === "skins" && <SkinsView key="skins-view" />}
|
||||
{activeView === "screenshots" && (
|
||||
<ScreenshotsView key="screenshots-view" />
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<AnimatePresence>
|
||||
<motion.footer
|
||||
key="footer"
|
||||
{...uiFade}
|
||||
className="shrink-0 p-4 flex justify-between items-end text-[10px] text-[#A0A0A0] mc-text-shadow bg-gradient-to-t from-black/80 to-transparent uppercase tracking-widest opacity-60 font-['Mojangles']"
|
||||
style={{ fontWeight: "normal" }}
|
||||
>
|
||||
<div className="flex-1 text-left whitespace-nowrap">
|
||||
Version: {pkg.version} ({__BUILD_DATE__})
|
||||
</div>
|
||||
<div className="flex-[2] text-center whitespace-nowrap">
|
||||
Not affiliated with Mojang AB or Microsoft. "Minecraft" is
|
||||
a trademark of Mojang Synergies AB.
|
||||
</div>
|
||||
<div className="flex-1 text-right whitespace-nowrap">
|
||||
{useUI().connected && "CONTROLLER CONNECTED"}
|
||||
</div>
|
||||
</motion.footer>
|
||||
</AnimatePresence>
|
||||
<motion.div
|
||||
initial={{ opacity: 0 }}
|
||||
animate={{ opacity: 1 }}
|
||||
className="flex flex-col h-full z-10 w-full relative"
|
||||
>
|
||||
{!config.legacyMode && (
|
||||
<motion.div
|
||||
{...uiFade}
|
||||
className="absolute top-4 left-8 z-50"
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
audio.playPressSound();
|
||||
setIsUiHidden(!isUiHidden);
|
||||
}}
|
||||
className="hover:scale-110 active:scale-95 transition-transform outline-none bg-transparent border-none"
|
||||
>
|
||||
<img
|
||||
src={
|
||||
isUiHidden
|
||||
? "/images/Unhide_UI_Button.png"
|
||||
: "/images/Hide_UI_Button.png"
|
||||
}
|
||||
className="w-10 h-10 cursor-pointer object-contain"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</button>
|
||||
</motion.div>
|
||||
</AnimatePresence>
|
||||
)}
|
||||
|
||||
{!config.legacyMode && (
|
||||
<motion.div
|
||||
{...uiFade}
|
||||
className="absolute bottom-6 right-8 z-50 flex items-center gap-3"
|
||||
>
|
||||
<span className="text-[#E0E0E0] text-[10px] mc-text-shadow tracking-widest uppercase opacity-70 mt-1">
|
||||
{displayIsDay ? "Day" : "Night"}
|
||||
</span>
|
||||
<button
|
||||
onClick={() => {
|
||||
audio.playPressSound();
|
||||
config.setIsDayTime(!config.isDayTime);
|
||||
}}
|
||||
className="hover:scale-110 active:scale-95 transition-transform outline-none bg-transparent border-none"
|
||||
>
|
||||
<img
|
||||
src={
|
||||
displayIsDay
|
||||
? "/images/Day_Toggle.png"
|
||||
: "/images/Night_Toggle.png"
|
||||
}
|
||||
alt="Toggle Time"
|
||||
className="w-12 h-12 cursor-pointer block object-contain"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</button>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
{isUiHidden && !displayIsDay && activeView === "devtools" && (
|
||||
<motion.div
|
||||
initial={{ opacity: 0, scale: 0.8 }}
|
||||
animate={{ opacity: 1, scale: 1 }}
|
||||
exit={{ opacity: 0, scale: 0.8 }}
|
||||
className="absolute inset-0 z-[100] flex items-center justify-center pointer-events-none"
|
||||
>
|
||||
<button
|
||||
onClick={() => {
|
||||
audio.playPressSound();
|
||||
setIsUiHidden(false);
|
||||
setActiveView("swf-editor");
|
||||
}}
|
||||
className="pointer-events-auto hover:scale-110 active:scale-95 transition-transform outline-none bg-transparent border-none flex flex-col items-center gap-2 group"
|
||||
>
|
||||
<img
|
||||
src="/images/tools/pck.png"
|
||||
className="w-16 h-16 cursor-pointer object-contain opacity-50 group-hover:opacity-100 drop-shadow-[0_4px_4px_rgba(0,0,0,1)] grayscale group-hover:grayscale-0"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).src =
|
||||
"/images/Button_Background.png";
|
||||
}}
|
||||
/>
|
||||
<span className="text-[#FFFF55] text-sm mc-text-shadow opacity-0 group-hover:opacity-100 transition-opacity">
|
||||
SWF Editor
|
||||
</span>
|
||||
</button>
|
||||
</motion.div>
|
||||
)}
|
||||
|
||||
<div className="shrink-0 flex justify-center py-4 relative w-full pt-4">
|
||||
<div className="relative w-full max-w-135 flex justify-center">
|
||||
<motion.img
|
||||
layoutId="mainLogo"
|
||||
src={titleImage}
|
||||
transition={{
|
||||
type: "spring",
|
||||
stiffness: 300,
|
||||
damping: 25,
|
||||
}}
|
||||
className="w-full drop-shadow-[0_8px_6px_rgba(0,0,0,0.8)] pointer-events-none"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
<motion.div
|
||||
{...uiFade}
|
||||
className="absolute bottom-[20%] right-[5%] w-0 h-0 flex items-center justify-center"
|
||||
>
|
||||
<div
|
||||
onClick={audio.cycleSplash}
|
||||
className="mc-splash text-[#FFFF55] text-[28px] z-100 cursor-pointer whitespace-nowrap"
|
||||
style={{ textShadow: "2px 2px 0px #3F3F00" }}
|
||||
>
|
||||
{audio.splashIndex === -1
|
||||
? `Welcome ${config.username}!`
|
||||
: audio.splashes[audio.splashIndex]}
|
||||
</div>
|
||||
</motion.div>
|
||||
{activeView === "main" && hasAnyInstall && titleImage === "/images/MenuTitle.png" && (
|
||||
<motion.div
|
||||
{...uiFade}
|
||||
className="absolute -bottom-6 text-[#A0A0A0] text-sm mc-text-shadow tracking-widest uppercase opacity-80 font-['Mojangles']"
|
||||
>
|
||||
{selectedVersionName}
|
||||
</motion.div>
|
||||
)}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<main className="flex-1 w-full relative">
|
||||
<div
|
||||
className={`w-full h-full flex flex-col items-center justify-center ${isUiHidden ? "opacity-0 pointer-events-none" : "opacity-100"}`}
|
||||
>
|
||||
<AnimatePresence mode="wait">
|
||||
{activeView === "main" && (
|
||||
<SkinViewer
|
||||
key="skin-viewer"
|
||||
username={config.username}
|
||||
setUsername={config.setUsername}
|
||||
playPressSound={audio.playPressSound}
|
||||
skinUrl={skinUrl}
|
||||
capeUrl={config.legacyMode ? null : capeUrl}
|
||||
setSkinUrl={setSkinUrl}
|
||||
setActiveView={setActiveView}
|
||||
isFocusedSection={focusSection === "skin"}
|
||||
onNavigateRight={onNavigateToMenu}
|
||||
/>
|
||||
)}
|
||||
</AnimatePresence>
|
||||
|
||||
<div className="w-full h-full max-w-4xl relative flex justify-center items-center overflow-hidden">
|
||||
<AnimatePresence mode="wait">
|
||||
{activeView === "main" && <HomeView key="main-view" />}
|
||||
{activeView === "settings" && (
|
||||
<SettingsView key="settings-view" />
|
||||
)}
|
||||
{activeView === "versions" && (
|
||||
<VersionsView key="versions-view" />
|
||||
)}
|
||||
{activeView === "workshop" && (
|
||||
<WorkshopView key="workshop-view" />
|
||||
)}
|
||||
{activeView === "devtools" && (
|
||||
<DevtoolsView key="devtools-view" />
|
||||
)}
|
||||
{activeView === "pck-editor" && (
|
||||
<PckEditorView key="pck-editor-view" />
|
||||
)}
|
||||
{activeView === "arc-editor" && (
|
||||
<ArcEditorView key="arc-editor-view" />
|
||||
)}
|
||||
{activeView === "loc-editor" && (
|
||||
<LocEditorView key="loc-editor-view" />
|
||||
)}
|
||||
{activeView === "grf-editor" && (
|
||||
<GrfEditorView key="grf-editor-view" />
|
||||
)}
|
||||
{activeView === "col-editor" && (
|
||||
<ColEditorView key="col-editor-view" />
|
||||
)}
|
||||
{activeView === "options-editor" && (
|
||||
<OptionsEditorView key="options-editor-view" />
|
||||
)}
|
||||
{activeView === "swf-editor" && (
|
||||
<SwfView key="swf-editor-view" />
|
||||
)}
|
||||
{activeView === "lcelive" && (
|
||||
<LceLiveView key="lcelive-view" />
|
||||
)}
|
||||
{activeView === "skins" && <SkinsView key="skins-view" />}
|
||||
{activeView === "screenshots" && (
|
||||
<ScreenshotsView key="screenshots-view" />
|
||||
)}
|
||||
</AnimatePresence>
|
||||
</div>
|
||||
</div>
|
||||
</main>
|
||||
|
||||
<motion.footer
|
||||
{...uiFade}
|
||||
className="shrink-0 p-4 flex justify-between items-end text-[10px] text-[#A0A0A0] mc-text-shadow bg-gradient-to-t from-black/80 to-transparent uppercase tracking-widest opacity-60 font-['Mojangles']"
|
||||
style={{ fontWeight: "normal" }}
|
||||
>
|
||||
<div className="flex-1 text-left whitespace-nowrap">
|
||||
Version: {pkg.version} ({__BUILD_DATE__})
|
||||
</div>
|
||||
<div className="flex-[2] text-center whitespace-nowrap">
|
||||
Not affiliated with Mojang AB or Microsoft. "Minecraft" is
|
||||
a trademark of Mojang Synergies AB.
|
||||
</div>
|
||||
<div className="flex-1 text-right whitespace-nowrap">
|
||||
{connected && "CONTROLLER CONNECTED"}
|
||||
</div>
|
||||
</motion.footer>
|
||||
</motion.div>
|
||||
|
||||
<AchievementToast
|
||||
message={friendRequestMessage}
|
||||
|
||||
Reference in New Issue
Block a user