From 72b9dc207418cf47b4ca4dfa7193be48c2900d14 Mon Sep 17 00:00:00 2001 From: KayJann Date: Sun, 5 Apr 2026 21:13:17 +0200 Subject: [PATCH] ui: Settings refractor --- public/images/background.png | Bin 0 -> 2084 bytes public/images/notification.png | Bin 0 -> 371 bytes src/components/common/ClickParticles.tsx | 6 +- src/components/common/SkinViewer.tsx | 18 +- src/components/layout/AppHeader.tsx | 10 +- src/components/modals/CustomTUModal.tsx | 13 +- src/components/modals/TeamModal.tsx | 6 +- src/components/views/DevtoolsView.tsx | 8 +- src/components/views/HomeView.tsx | 10 +- src/components/views/SettingsView.tsx | 243 ++++++++++++++++------- src/components/views/SetupView.tsx | 26 +-- src/components/views/SkinsView.tsx | 24 +-- src/components/views/VersionsView.tsx | 30 +-- src/components/views/WorkshopView.tsx | 8 +- src/hooks/useAudioController.ts | 4 +- src/pages/App.tsx | 8 +- 16 files changed, 254 insertions(+), 160 deletions(-) create mode 100644 public/images/background.png create mode 100644 public/images/notification.png diff --git a/public/images/background.png b/public/images/background.png new file mode 100644 index 0000000000000000000000000000000000000000..341ffad468acb6f2cd44fadbfa19a942afbd48c7 GIT binary patch literal 2084 zcmeHIZBP?O7~VVXAeWRT1V}nmOcXRxQ$S&iq9&(?22hhwk$@41711(N&}uOTggc9- zs7TZzjR-_V4P!?UItBcIt6HQ|M_QyBS|Lbj4I>{42!kK#(dkcrb^4<-_Q&q*zPtPG z`#$^b^W8RA69C{D6{+|D0EixfTMT!)kIpQcoM2lb6Se^m6foH!!)bXY03JU_ zDVD|>lKLMcs@5qv?i#iNdCKjq*_#51vyShnV#mK}&{Qgz*eoC@j;v6vxN} zbm(4a{uhiO1cGyA0cJjo9Ak=!GoSHGs3d(HG|r<=Pt&Zxp}WV8@38!fmQ-IVy;iqN=n;qugRJ0TTpU*{3ONT}Y;$}v%(vCknB+h= z2H&Gi#??`3YZ(FCq^t88c{B=N-dYBaB0l(4OSD2Lv4U%{Jg$ufsqc2|ba*|4a?Vtn z@g)$d$vDIHVz9(SNYNgo4-*r{(4x=rcpS>Blmu$%SGZeJsX(s5OySCn(?}x?cIV0& z(>Xj1SU;PE-KCQrO`YvURuM2`bwcF-A-qW_*wLzU%0Msj5^P6@;)|o_(G^$CvX+?@ z2$Qa;Yu9}XC>_1#*aR~2v*e^Nmcpk}BkWW508&ct1PdV8jV?KIZ?6rhMypxW9Z)Sw zk;5!z3ZE#4Bnu=u?`B?e5YhA4t)mc-z4Re{{gDm}Ah$!PS(UaN?qP_Dt*N~g$WL_9 zhgW)H2Li01$x?KL8_CxIXT|)$kb?yL&Zan3v@j8eDvorRsRb}oe>`E~tpB!?$>0Bn z+_kEl@Wis0PcoF}9p?#*6OZGNgh*QfpQ2Nbnb~_B;c+y8W$idjiQyWizQ%swaLYoB z!(h-PMdcjj2t&*?0-NIxMhkT~l(N60kiuaL>Zr|g_q%e6d!LoU12Hh-?%gZ_xe+1v zhy07F9Sqqz$JPm{Z?Zrjkau-;xiYh|oGp=mg=;|IHH@GI+oKEKjL2llf#Sgz-@4B?FEo_P6_gb(D`)=k? z7tCg}lLrR|Wa`1hes;4j@yiPRG}1ZeN}E%6dAJg3kc@B!JL8}$C9UqrE3H1Xh)Qd` z9Rt#XUr+pw2aO(8xhFMh-o#w~M-vg2!kxmxr@`deMM?b&=XNH7EOVN8Ku+F+*9_LF zXAOkE-p$|oAtsux^GgYMiw7+h8c<*g4u??3+nmibq583tx5G@zU)V~MW!Th)M~Dxx z=${JJUl(01r!p_^@-n){~&B)YhwdF~THG;w$h!I=73$3cJt9w+mZY`~HLBYXe q&a;n)<}GZ#1}_*gf?^5KR_-H(b;Db6p`@BS02Ef#42 literal 0 HcmV?d00001 diff --git a/public/images/notification.png b/public/images/notification.png new file mode 100644 index 0000000000000000000000000000000000000000..68a260bb41b98be67d4eb3ffe2f9d991d1af1575 GIT binary patch literal 371 zcmeAS@N?(olHy`uVBq!ia0vp^3xHUGgAGVdtuOuxq&N#aB8wRq^pruEv0|xx83O~O zs;7%%NJZS+IR|;04Fp)6vlfZ2S|VDd#K@V{JZ1h_FXKv=I+u#?X-D+U_teebYEfOn zq^oWq!*9>`+Qe5^|I1Ck2XhYCoWEUJp8q?@?&%A=M(0Db8%}R3;eXsZhqLE##9q$( zsijXJcYFxBygGSmgMaI%xOXff6HePL+R5aW@SrWgLGO3RGcJk7MrkL;oo|$9X(zC- z<#Dh++0>u0u0c>@haz { const [bursts, setBursts] = useState([]); useEffect(() => { - const handleClick = (e: MouseEvent) => { + const handlePressSound = (e: MouseEvent) => { const newParticles: Particle[] = []; const particleCount = 8; @@ -38,8 +38,8 @@ export const ClickParticles: React.FC = React.memo(() => { }, 1000); }; - window.addEventListener("mousedown", handleClick); - return () => window.removeEventListener("mousedown", handleClick); + window.addEventListener("mousedown", handlePressSound); + return () => window.removeEventListener("mousedown", handlePressSound); }, []); return ( diff --git a/src/components/common/SkinViewer.tsx b/src/components/common/SkinViewer.tsx index 9282773..71c8235 100644 --- a/src/components/common/SkinViewer.tsx +++ b/src/components/common/SkinViewer.tsx @@ -7,7 +7,7 @@ import { useConfig } from '../../context/LauncherContext'; interface SkinViewerProps { username: string; setUsername: (name: string) => void; - playClickSound: () => void; + playPressSound: () => void; skinUrl: string; setSkinUrl: (url: string) => void; setActiveView: (view: string) => void; @@ -15,7 +15,7 @@ interface SkinViewerProps { onNavigateRight: () => void; } -const SkinViewer = memo(function SkinViewer({ username, setUsername, playClickSound, skinUrl, setSkinUrl, setActiveView, isFocusedSection, onNavigateRight }: SkinViewerProps) { +const SkinViewer = memo(function SkinViewer({ username, setUsername, playPressSound, skinUrl, setSkinUrl, setActiveView, isFocusedSection, onNavigateRight }: SkinViewerProps) { const mountRef = useRef(null); const containerRef = useRef(null); const [focusIndex, setFocusIndex] = useState(0); @@ -232,13 +232,13 @@ const SkinViewer = memo(function SkinViewer({ username, setUsername, playClickSo if (focusIndex === 0) { (containerRef.current?.querySelector('input') as HTMLElement)?.focus(); } else if (focusIndex === 1) { - playClickSound(); + playPressSound(); setActiveView('skins'); } else if (focusIndex === 2) { - playClickSound(); + playPressSound(); setShowLayers(!showLayers); } else if (focusIndex === 3) { - playClickSound(); + playPressSound(); setSkinUrl('/images/Default.png'); } } @@ -246,7 +246,7 @@ const SkinViewer = memo(function SkinViewer({ username, setUsername, playClickSo window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); - }, [isFocusedSection, focusIndex, onNavigateRight, playClickSound, setActiveView, setShowLayers, showLayers, setSkinUrl, legacyMode]); + }, [isFocusedSection, focusIndex, onNavigateRight, playPressSound, setActiveView, setShowLayers, showLayers, setSkinUrl, legacyMode]); useEffect(() => { if (isFocusedSection) { @@ -289,7 +289,7 @@ const SkinViewer = memo(function SkinViewer({ username, setUsername, playClickSo ); - } + })} + + ) : ( + // Sub-menus - new style with background.png and toggle switches +
+
+ {settingsItems.map((item, index) => { + if (item.id === "back") return null; - const isRed = (item as any).color === "red"; - const isSmall = (item as any).small; + if (item.type === "slider") { + return ( +
setFocusIndex(index)} + className="relative w-[360px] h-10 flex items-center justify-center cursor-pointer transition-all outline-none border-none hover:text-[#FFFF55] shrink-0" + style={getSliderStyle(index)} + > + + {item.label} + +
+ item.onChange(parseInt(e.target.value))} + onMouseUp={playPressSound} + className="mc-slider-custom w-[calc(100%+16px)] h-full opacity-100 cursor-pointer z-20 outline-none m-0" + /> +
+
+ ); + } - return ( - - ); - })} -
+ const isRed = (item as any).color === "red"; + const isSmall = (item as any).small; + const isToggle = isToggleOption(item.label); + const toggleState = isToggle ? getToggleState(item.label) : false; + + return ( + + ); + })} +
+ + )} {(() => { const backIndex = settingsItems.findIndex((i) => i.id === "back"); @@ -557,9 +645,14 @@ const SettingsView = memo(function SettingsView() { data-index={backIndex} onMouseEnter={() => setFocusIndex(backIndex)} onClick={backItem.onClick} - className={`w-72 h-10 flex items-center justify-center transition-colors text-xl mc-text-shadow outline-none border-none hover:text-[#FFFF55] ${focusIndex === backIndex ? "text-[#FFFF55]" : "text-white" - }`} - style={getItemStyle(backIndex)} + className={`w-72 h-10 flex items-center justify-center transition-colors text-xl mc-text-shadow outline-none border-none hover:text-[#FFFF55] mt-4 ${focusIndex === backIndex ? "text-[#FFFF55]" : "text-white"}`} + style={{ + backgroundImage: focusIndex === backIndex + ? "url('/images/button_highlighted.png')" + : "url('/images/Button_Background.png')", + backgroundSize: "100% 100%", + imageRendering: "pixelated", + }} > Back diff --git a/src/components/views/SetupView.tsx b/src/components/views/SetupView.tsx index 8e3a201..7e5b19c 100644 --- a/src/components/views/SetupView.tsx +++ b/src/components/views/SetupView.tsx @@ -25,7 +25,7 @@ const SetupView: React.FC = ({ onComplete }) => { rpcEnabled: configRpc, keepLauncherOpen: configKeepOpen } = useConfig(); - const { playClickSound, playSfx } = useAudio(); + const { playPressSound, playSfx } = useAudio(); const { editions } = useGame(); const titleImage = editions.find(e => e.id === profile)?.titleImage || "/images/MenuTitle.png"; @@ -103,12 +103,12 @@ const SetupView: React.FC = ({ onComplete }) => { }; const handleRunnerSelect = (runnerId: string) => { - playClickSound(); + playPressSound(); setSelectedRunner(runnerId); }; const handleNext = async () => { - playClickSound(); + playPressSound(); if (currentStep === 0) { setUsername(tempUsername); @@ -136,7 +136,7 @@ const SetupView: React.FC = ({ onComplete }) => { }; const handleBack = () => { - playClickSound(); + playPressSound(); if (currentStep > 0) { setCurrentStep(currentStep - 1); setFocusIndex(0); @@ -180,10 +180,10 @@ const SetupView: React.FC = ({ onComplete }) => { else if (focusIndex === 1) handleNext(); } } else if (currentStep === 2) { - if (focusIndex === 0) { setEnableTrayIcon(!enableTrayIcon); playClickSound(); } - else if (focusIndex === 1) { setEnableVfx(!enableVfx); playClickSound(); } - else if (focusIndex === 2) { setEnableDiscordRPC(!enableDiscordRPC); playClickSound(); } - else if (focusIndex === 3) { setKeepLauncherOpen(!keepLauncherOpen); playClickSound(); } + if (focusIndex === 0) { setEnableTrayIcon(!enableTrayIcon); playPressSound(); } + else if (focusIndex === 1) { setEnableVfx(!enableVfx); playPressSound(); } + else if (focusIndex === 2) { setEnableDiscordRPC(!enableDiscordRPC); playPressSound(); } + else if (focusIndex === 3) { setKeepLauncherOpen(!keepLauncherOpen); playPressSound(); } else if (focusIndex === 4) handleBack(); else if (focusIndex === 5) handleNext(); } else if (currentStep === 3) { @@ -197,7 +197,7 @@ const SetupView: React.FC = ({ onComplete }) => { }, [currentStep, focusIndex, runners, enableTrayIcon, enableVfx, enableDiscordRPC, keepLauncherOpen, isLinux, isMac, tempUsername]); const handleMacosSetup = async () => { - playClickSound(); + playPressSound(); setIsSettingUpRuntime(true); setSetupProgress({ stage: "preparing", message: "Preparing macOS runtime setup...", percent: 0 }); @@ -444,7 +444,7 @@ const SetupView: React.FC = ({ onComplete }) => {