mirror of
https://github.com/LCE-Hub/LCE-Emerald-Launcher.git
synced 2026-07-18 00:07:09 +00:00
fix: screenshots:// on windows again
This commit is contained in:
parent
87e841f565
commit
60c8e016da
BIN
public/Skins/700.png
Normal file
BIN
public/Skins/700.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.6 KiB |
|
|
@ -1,14 +1,23 @@
|
|||
import { useState, useEffect, memo } from "react";
|
||||
import { motion, AnimatePresence } from "framer-motion";
|
||||
import { useUI, useAudio, useGame, useConfig } from "../../context/LauncherContext";
|
||||
import { ScreenshotService, ScreenshotInfo } from "../../services/ScreenshotService";
|
||||
import {
|
||||
useUI,
|
||||
useAudio,
|
||||
useGame,
|
||||
useConfig,
|
||||
} from "../../context/LauncherContext";
|
||||
import {
|
||||
ScreenshotService,
|
||||
ScreenshotInfo,
|
||||
} from "../../services/ScreenshotService";
|
||||
const ScreenshotsView = memo(function ScreenshotsView() {
|
||||
const { setActiveView } = useUI();
|
||||
const { playPressSound, playBackSound } = useAudio();
|
||||
const { editions } = useGame();
|
||||
const { animationsEnabled } = useConfig();
|
||||
const [screenshots, setScreenshots] = useState<ScreenshotInfo[]>([]);
|
||||
const [selectedScreenshot, setSelectedScreenshot] = useState<ScreenshotInfo | null>(null);
|
||||
const [selectedScreenshot, setSelectedScreenshot] =
|
||||
useState<ScreenshotInfo | null>(null);
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [gridFocusIndex, setGridFocusIndex] = useState(0);
|
||||
const [modalFocusIndex, setModalFocusIndex] = useState(0);
|
||||
|
|
@ -35,7 +44,9 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
if (!selectedScreenshot) return;
|
||||
playPressSound();
|
||||
await ScreenshotService.deleteScreenshot(selectedScreenshot.path);
|
||||
setScreenshots((prev) => prev.filter((s) => s.path !== selectedScreenshot.path));
|
||||
setScreenshots((prev) =>
|
||||
prev.filter((s) => s.path !== selectedScreenshot.path),
|
||||
);
|
||||
setSelectedScreenshot(null);
|
||||
setShowDeleteConfirm(false);
|
||||
};
|
||||
|
|
@ -47,7 +58,11 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
if (e.key === "Escape" || e.key === "Backspace") {
|
||||
playBackSound();
|
||||
setShowDeleteConfirm(false);
|
||||
} else if (e.key === "ArrowLeft" || e.key === "ArrowRight" || e.key === "Tab") {
|
||||
} else if (
|
||||
e.key === "ArrowLeft" ||
|
||||
e.key === "ArrowRight" ||
|
||||
e.key === "Tab"
|
||||
) {
|
||||
e.preventDefault();
|
||||
playPressSound();
|
||||
setDeleteConfirmFocusIndex((prev) => (prev === 0 ? 1 : 0));
|
||||
|
|
@ -78,8 +93,7 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
playPressSound();
|
||||
setDeleteConfirmFocusIndex(0);
|
||||
setShowDeleteConfirm(true);
|
||||
}
|
||||
else if (modalFocusIndex === 2) {
|
||||
} else if (modalFocusIndex === 2) {
|
||||
playBackSound();
|
||||
setSelectedScreenshot(null);
|
||||
}
|
||||
|
|
@ -87,17 +101,22 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
return;
|
||||
}
|
||||
|
||||
const cols = window.innerWidth >= 1024 ? 4 : window.innerWidth >= 768 ? 3 : 2;
|
||||
const cols =
|
||||
window.innerWidth >= 1024 ? 4 : window.innerWidth >= 768 ? 3 : 2;
|
||||
if (e.key === "Escape" || e.key === "Backspace") {
|
||||
handleBack();
|
||||
} else if (e.key === "ArrowLeft") {
|
||||
setGridFocusIndex((prev) => (prev > 0 ? prev - 1 : prev));
|
||||
} else if (e.key === "ArrowRight") {
|
||||
setGridFocusIndex((prev) => (prev < screenshots.length - 1 ? prev + 1 : prev));
|
||||
setGridFocusIndex((prev) =>
|
||||
prev < screenshots.length - 1 ? prev + 1 : prev,
|
||||
);
|
||||
} else if (e.key === "ArrowUp") {
|
||||
setGridFocusIndex((prev) => (prev >= cols ? prev - cols : prev));
|
||||
} else if (e.key === "ArrowDown") {
|
||||
setGridFocusIndex((prev) => (prev <= screenshots.length - 1 - cols ? prev + cols : prev));
|
||||
setGridFocusIndex((prev) =>
|
||||
prev <= screenshots.length - 1 - cols ? prev + cols : prev,
|
||||
);
|
||||
} else if (e.key === "Enter") {
|
||||
if (screenshots[gridFocusIndex]) {
|
||||
playPressSound();
|
||||
|
|
@ -109,7 +128,15 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
|
||||
window.addEventListener("keydown", handleKeyDown);
|
||||
return () => window.removeEventListener("keydown", handleKeyDown);
|
||||
}, [loading, selectedScreenshot, gridFocusIndex, modalFocusIndex, screenshots, showDeleteConfirm, deleteConfirmFocusIndex]);
|
||||
}, [
|
||||
loading,
|
||||
selectedScreenshot,
|
||||
gridFocusIndex,
|
||||
modalFocusIndex,
|
||||
screenshots,
|
||||
showDeleteConfirm,
|
||||
deleteConfirmFocusIndex,
|
||||
]);
|
||||
|
||||
useEffect(() => {
|
||||
if (!selectedScreenshot) {
|
||||
|
|
@ -139,12 +166,18 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
<div className="absolute inset-0 overflow-y-auto p-6 scroll-smooth custom-scrollbar">
|
||||
{loading ? (
|
||||
<div className="flex flex-col items-center justify-center h-full gap-4">
|
||||
<span className="text-3xl text-[#FFFF55] mc-text-shadow tracking-widest animate-pulse uppercase">Scanning Archives...</span>
|
||||
<span className="text-3xl text-[#FFFF55] mc-text-shadow tracking-widest animate-pulse uppercase">
|
||||
Scanning Archives...
|
||||
</span>
|
||||
</div>
|
||||
) : screenshots.length === 0 ? (
|
||||
<div className="flex flex-col items-center justify-center h-full space-y-4 opacity-40">
|
||||
<span className="text-2xl mc-text-shadow uppercase tracking-widest">No screenshots found</span>
|
||||
<span className="text-sm mc-text-shadow tracking-widest italic">Take some in-game with F2</span>
|
||||
<span className="text-2xl mc-text-shadow uppercase tracking-widest">
|
||||
No screenshots found
|
||||
</span>
|
||||
<span className="text-sm mc-text-shadow tracking-widest italic">
|
||||
Take some in-game with F2
|
||||
</span>
|
||||
</div>
|
||||
) : (
|
||||
<div className="grid grid-cols-2 md:grid-cols-3 lg:grid-cols-4 gap-6">
|
||||
|
|
@ -165,19 +198,23 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
`}
|
||||
style={{
|
||||
backgroundImage: "url('/images/frame_background.png')",
|
||||
backgroundSize: '100% 100%',
|
||||
imageRendering: 'pixelated',
|
||||
boxShadow: gridFocusIndex === index ? '0 0 20px rgba(255, 255, 85, 0.2)' : 'none',
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
boxShadow:
|
||||
gridFocusIndex === index
|
||||
? "0 0 20px rgba(255, 255, 85, 0.2)"
|
||||
: "none",
|
||||
}}
|
||||
>
|
||||
<div className="w-full h-full relative overflow-hidden bg-black/50">
|
||||
<img
|
||||
src={`screenshots://localhost/${ss.path}`}
|
||||
src={`screenshots://localhost/${ss.path.replace(/\\/g, "/")}`}
|
||||
className="w-full h-full object-cover transition-transform duration-500 group-hover:scale-110"
|
||||
loading="lazy"
|
||||
alt={ss.name}
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).src = "/images/Folder_Icon.png";
|
||||
(e.target as HTMLImageElement).src =
|
||||
"/images/Folder_Icon.png";
|
||||
}}
|
||||
/>
|
||||
<div className="absolute inset-0 bg-gradient-to-t from-black/80 via-transparent to-transparent opacity-60" />
|
||||
|
|
@ -212,11 +249,17 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
`}
|
||||
style={{
|
||||
backgroundImage: "url('/images/Button_Background.png')",
|
||||
backgroundSize: '100% 100%',
|
||||
imageRendering: 'pixelated'
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
onMouseEnter={(e) => {
|
||||
(e.currentTarget as HTMLButtonElement).style.backgroundImage =
|
||||
"url('/images/button_highlighted.png')";
|
||||
}}
|
||||
onMouseLeave={(e) => {
|
||||
(e.currentTarget as HTMLButtonElement).style.backgroundImage =
|
||||
"url('/images/Button_Background.png')";
|
||||
}}
|
||||
onMouseEnter={(e) => { (e.currentTarget as HTMLButtonElement).style.backgroundImage = "url('/images/button_highlighted.png')"; }}
|
||||
onMouseLeave={(e) => { (e.currentTarget as HTMLButtonElement).style.backgroundImage = "url('/images/Button_Background.png')"; }}
|
||||
>
|
||||
Back
|
||||
</button>
|
||||
|
|
@ -239,17 +282,18 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
className="relative max-w-5xl w-full flex flex-col items-center border-2 border-[#555] rounded-sm p-2"
|
||||
style={{
|
||||
backgroundImage: "url('/images/frame_background.png')",
|
||||
backgroundSize: '100% 100%',
|
||||
imageRendering: 'pixelated',
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<div className="relative w-full aspect-video bg-black/60 overflow-hidden border border-[#444] rounded-sm">
|
||||
<img
|
||||
src={`screenshots://localhost/${selectedScreenshot.path}`}
|
||||
src={`screenshots://localhost/${selectedScreenshot.path.replace(/\\/g, "/")}`}
|
||||
className="w-full h-full object-contain"
|
||||
onError={(e) => {
|
||||
(e.target as HTMLImageElement).src = "/images/Pack_Icon.png";
|
||||
(e.target as HTMLImageElement).src =
|
||||
"/images/Pack_Icon.png";
|
||||
}}
|
||||
/>
|
||||
<div className="absolute bottom-4 left-6 right-6 flex items-end justify-between pointer-events-none">
|
||||
|
|
@ -258,7 +302,10 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
{selectedScreenshot.name}
|
||||
</span>
|
||||
<span className="text-sm text-[#FFFF55] mc-text-shadow uppercase tracking-widest opacity-90">
|
||||
Captured on {new Date(selectedScreenshot.date * 1000).toLocaleString()}
|
||||
Captured on{" "}
|
||||
{new Date(
|
||||
selectedScreenshot.date * 1000,
|
||||
).toLocaleString()}
|
||||
</span>
|
||||
</div>
|
||||
{getEditionLogo(selectedScreenshot.instanceId) && (
|
||||
|
|
@ -280,9 +327,12 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
${modalFocusIndex === 0 ? "text-[#FFFF55] scale-105" : "text-white"}
|
||||
`}
|
||||
style={{
|
||||
backgroundImage: modalFocusIndex === 0 ? "url('/images/button_highlighted.png')" : "url('/images/Button_Background.png')",
|
||||
backgroundSize: '100% 100%',
|
||||
imageRendering: 'pixelated',
|
||||
backgroundImage:
|
||||
modalFocusIndex === 0
|
||||
? "url('/images/button_highlighted.png')"
|
||||
: "url('/images/Button_Background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
OPEN FOLDER
|
||||
|
|
@ -299,9 +349,12 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
${modalFocusIndex === 1 ? "text-[#FF5555] scale-105" : "text-white"}
|
||||
`}
|
||||
style={{
|
||||
backgroundImage: modalFocusIndex === 1 ? "url('/images/button_highlighted.png')" : "url('/images/Button_Background.png')",
|
||||
backgroundSize: '100% 100%',
|
||||
imageRendering: 'pixelated',
|
||||
backgroundImage:
|
||||
modalFocusIndex === 1
|
||||
? "url('/images/button_highlighted.png')"
|
||||
: "url('/images/Button_Background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
DELETE
|
||||
|
|
@ -314,9 +367,12 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
${modalFocusIndex === 2 ? "text-[#FFFF55] scale-105" : "text-white"}
|
||||
`}
|
||||
style={{
|
||||
backgroundImage: modalFocusIndex === 2 ? "url('/images/button_highlighted.png')" : "url('/images/Button_Background.png')",
|
||||
backgroundSize: '100% 100%',
|
||||
imageRendering: 'pixelated',
|
||||
backgroundImage:
|
||||
modalFocusIndex === 2
|
||||
? "url('/images/button_highlighted.png')"
|
||||
: "url('/images/Button_Background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
CLOSE
|
||||
|
|
@ -342,8 +398,8 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
className="w-[420px] p-6 border-2 border-[#555] rounded-sm flex flex-col items-center"
|
||||
style={{
|
||||
backgroundImage: "url('/images/frame_background.png')",
|
||||
backgroundSize: '100% 100%',
|
||||
imageRendering: 'pixelated',
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
|
|
@ -354,15 +410,21 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
<div className="flex gap-4 w-full">
|
||||
<button
|
||||
onMouseEnter={() => setDeleteConfirmFocusIndex(0)}
|
||||
onClick={() => { playBackSound(); setShowDeleteConfirm(false); }}
|
||||
onClick={() => {
|
||||
playBackSound();
|
||||
setShowDeleteConfirm(false);
|
||||
}}
|
||||
className={`
|
||||
flex-1 h-10 flex items-center justify-center text-lg mc-text-shadow border-none outline-none cursor-pointer transition-all
|
||||
${deleteConfirmFocusIndex === 0 ? "text-[#FFFF55] scale-105" : "text-white"}
|
||||
`}
|
||||
style={{
|
||||
backgroundImage: deleteConfirmFocusIndex === 0 ? "url('/images/button_highlighted.png')" : "url('/images/Button_Background.png')",
|
||||
backgroundSize: '100% 100%',
|
||||
imageRendering: 'pixelated',
|
||||
backgroundImage:
|
||||
deleteConfirmFocusIndex === 0
|
||||
? "url('/images/button_highlighted.png')"
|
||||
: "url('/images/Button_Background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
CANCEL
|
||||
|
|
@ -375,9 +437,12 @@ const ScreenshotsView = memo(function ScreenshotsView() {
|
|||
${deleteConfirmFocusIndex === 1 ? "text-[#FF5555] scale-105" : "text-white"}
|
||||
`}
|
||||
style={{
|
||||
backgroundImage: deleteConfirmFocusIndex === 1 ? "url('/images/button_highlighted.png')" : "url('/images/Button_Background.png')",
|
||||
backgroundSize: '100% 100%',
|
||||
imageRendering: 'pixelated',
|
||||
backgroundImage:
|
||||
deleteConfirmFocusIndex === 1
|
||||
? "url('/images/button_highlighted.png')"
|
||||
: "url('/images/Button_Background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
DELETE
|
||||
|
|
|
|||
|
|
@ -46,6 +46,7 @@ const DEFAULT_SKINS: SavedSkin[] = [
|
|||
},
|
||||
{ id: "peter", name: "Peter", url: "/Skins/Peter.png", isSlim: false },
|
||||
{ id: "piebot", name: "piebot", url: "/Skins/piebot.png", isSlim: false },
|
||||
{ id: "sevenhundred", name: "700", url: "/Skins/700.png", isSlim: false },
|
||||
];
|
||||
|
||||
const SkinsView = memo(function SkinsView() {
|
||||
|
|
|
|||
|
|
@ -2,7 +2,12 @@ import { useState, useEffect, useRef, memo } from "react";
|
|||
import { motion } from "framer-motion";
|
||||
import { TauriService } from "../../services/TauriService";
|
||||
import CustomTUModal from "../modals/CustomTUModal";
|
||||
import { useUI, useConfig, useAudio, useGame } from "../../context/LauncherContext";
|
||||
import {
|
||||
useUI,
|
||||
useConfig,
|
||||
useAudio,
|
||||
useGame,
|
||||
} from "../../context/LauncherContext";
|
||||
interface DeleteConfirmButtonProps {
|
||||
label: string;
|
||||
onClick: () => void;
|
||||
|
|
@ -21,8 +26,9 @@ const DeleteConfirmButton = memo(function DeleteConfirmButton({
|
|||
onClick={onClick}
|
||||
onMouseEnter={() => setIsHovered(true)}
|
||||
onMouseLeave={() => setIsHovered(false)}
|
||||
className={`w-24 h-10 flex items-center justify-center mc-text-shadow transition-colors ${isDanger ? "text-red-500" : "text-white"
|
||||
} ${isHovered ? (isDanger ? "text-red-400" : "text-[#FFFF55]") : ""}`}
|
||||
className={`w-24 h-10 flex items-center justify-center mc-text-shadow transition-colors ${
|
||||
isDanger ? "text-red-500" : "text-white"
|
||||
} ${isHovered ? (isDanger ? "text-red-400" : "text-[#FFFF55]") : ""}`}
|
||||
style={{
|
||||
backgroundImage: isHovered
|
||||
? "url('/images/button_highlighted.png')"
|
||||
|
|
@ -38,15 +44,33 @@ const DeleteConfirmButton = memo(function DeleteConfirmButton({
|
|||
|
||||
const VersionsView = memo(function VersionsView() {
|
||||
const { setActiveView } = useUI();
|
||||
const { profile: selectedProfile, setProfile: setSelectedProfile, animationsEnabled } = useConfig();
|
||||
const {
|
||||
profile: selectedProfile,
|
||||
setProfile: setSelectedProfile,
|
||||
animationsEnabled,
|
||||
} = useConfig();
|
||||
const { playPressSound, playBackSound } = useAudio();
|
||||
const { editions, installs: installedVersions, toggleInstall, handleUninstall, handleCancelDownload, deleteCustomEdition: onDeleteEdition, addCustomEdition: onAddEdition, updateCustomEdition: onUpdateEdition, downloadingId, downloadProgress } = useGame();
|
||||
const {
|
||||
editions,
|
||||
installs: installedVersions,
|
||||
toggleInstall,
|
||||
handleUninstall,
|
||||
handleCancelDownload,
|
||||
deleteCustomEdition: onDeleteEdition,
|
||||
addCustomEdition: onAddEdition,
|
||||
updateCustomEdition: onUpdateEdition,
|
||||
downloadingId,
|
||||
downloadProgress,
|
||||
} = useGame();
|
||||
const [focusIndex, setFocusIndex] = useState<number>(0);
|
||||
const [focusBtn, setFocusBtn] = useState<number>(0);
|
||||
const [isImportModalOpen, setIsImportModalOpen] = useState(false);
|
||||
const [editingEdition, setEditingEdition] = useState<any>(null);
|
||||
const [initialPath, setInitialPath] = useState<string>("");
|
||||
const [hoveredBtn, setHoveredBtn] = useState<{ row: number, btn: string } | null>(null);
|
||||
const [hoveredBtn, setHoveredBtn] = useState<{
|
||||
row: number;
|
||||
btn: string;
|
||||
} | null>(null);
|
||||
const [deleteConfirmEdition, setDeleteConfirmEdition] = useState<any>(null);
|
||||
const containerRef = useRef<HTMLDivElement>(null);
|
||||
const listRef = useRef<HTMLDivElement>(null);
|
||||
|
|
@ -164,7 +188,9 @@ const VersionsView = memo(function VersionsView() {
|
|||
|
||||
useEffect(() => {
|
||||
if (focusIndex < editions.length && listRef.current) {
|
||||
const el = listRef.current.querySelector(`[data-index="${focusIndex}"]`) as HTMLElement;
|
||||
const el = listRef.current.querySelector(
|
||||
`[data-index="${focusIndex}"]`,
|
||||
) as HTMLElement;
|
||||
if (el) {
|
||||
el.scrollIntoView({ behavior: "smooth", block: "nearest" });
|
||||
}
|
||||
|
|
@ -223,7 +249,8 @@ const VersionsView = memo(function VersionsView() {
|
|||
{editions.map((edition: any, i: number) => {
|
||||
const isInstalled = installedVersions.includes(edition.id);
|
||||
const hasAnyInstall = installedVersions.length > 0;
|
||||
const isSelected = hasAnyInstall && selectedProfile === edition.id;
|
||||
const isSelected =
|
||||
hasAnyInstall && selectedProfile === edition.id;
|
||||
const isFocused = focusIndex === i;
|
||||
const isCustom = edition.id.startsWith("custom_");
|
||||
const isDownloading = downloadingId === edition.id;
|
||||
|
|
@ -233,9 +260,11 @@ const VersionsView = memo(function VersionsView() {
|
|||
<div
|
||||
key={edition.id}
|
||||
data-index={i}
|
||||
className={`w-[calc(100%-16px)] mx-2 flex items-center gap-3 p-2 rounded-sm ${isSelected && !isComingSoon ? "bg-[#404040]/50" : ""
|
||||
} ${isFocused && !isComingSoon ? "ring-2 ring-white" : ""} ${isComingSoon ? "opacity-50 cursor-not-allowed" : ""
|
||||
}`}
|
||||
className={`w-[calc(100%-16px)] mx-2 flex items-center gap-3 p-2 rounded-sm ${
|
||||
isSelected && !isComingSoon ? "bg-[#404040]/50" : ""
|
||||
} ${isFocused && !isComingSoon ? "ring-2 ring-white" : ""} ${
|
||||
isComingSoon ? "opacity-50 cursor-not-allowed" : ""
|
||||
}`}
|
||||
onMouseEnter={() => !isComingSoon && setFocusIndex(i)}
|
||||
>
|
||||
<div className="w-6 flex items-center justify-center flex-shrink-0">
|
||||
|
|
@ -268,40 +297,58 @@ const VersionsView = memo(function VersionsView() {
|
|||
</div>
|
||||
|
||||
<button
|
||||
onClick={() => !isComingSoon && handleEditionClick(edition, i)}
|
||||
onClick={() =>
|
||||
!isComingSoon && handleEditionClick(edition, i)
|
||||
}
|
||||
disabled={isComingSoon}
|
||||
className={`flex-1 text-left min-w-0 outline-none rounded ${focusIndex === i && focusBtn === 0 && !isComingSoon ? "ring-2 ring-white" : ""
|
||||
} ${isComingSoon ? "cursor-not-allowed" : ""}`}
|
||||
className={`flex-1 text-left min-w-0 outline-none rounded ${
|
||||
focusIndex === i && focusBtn === 0 && !isComingSoon
|
||||
? "ring-2 ring-white"
|
||||
: ""
|
||||
} ${isComingSoon ? "cursor-not-allowed" : ""}`}
|
||||
>
|
||||
<div className="flex items-center gap-2">
|
||||
{edition.logo && (
|
||||
<img
|
||||
src={edition.logo.startsWith('http') || edition.logo.startsWith('/images') ? edition.logo : `screenshots://localhost/${edition.logo}`}
|
||||
src={
|
||||
edition.logo.startsWith("http") ||
|
||||
edition.logo.startsWith("/images")
|
||||
? edition.logo
|
||||
: `screenshots://localhost/${edition.logo.replace(/\\/g, "/")}`
|
||||
}
|
||||
alt=""
|
||||
className="w-5 h-5 object-contain flex-shrink-0"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
)}
|
||||
<span
|
||||
className={`text-xl tracking-wide truncate ${isSelected ? "text-white" : "text-black"
|
||||
}`}
|
||||
className={`text-xl tracking-wide truncate ${
|
||||
isSelected ? "text-white" : "text-black"
|
||||
}`}
|
||||
style={{ textShadow: "none" }}
|
||||
>
|
||||
{edition.name}
|
||||
</span>
|
||||
{edition.category && edition.category.map((cat: string) => (
|
||||
<span key={cat} className="text-[9px] px-1.5 py-0.5 bg-[#444] text-[#aaa] font-bold uppercase border border-[#555] mc-text-shadow">
|
||||
{cat}
|
||||
</span>
|
||||
))}
|
||||
{edition.category &&
|
||||
edition.category.map((cat: string) => (
|
||||
<span
|
||||
key={cat}
|
||||
className="text-[9px] px-1.5 py-0.5 bg-[#444] text-[#aaa] font-bold uppercase border border-[#555] mc-text-shadow"
|
||||
>
|
||||
{cat}
|
||||
</span>
|
||||
))}
|
||||
{isCustom && !edition.category && (
|
||||
<span className="text-[10px] px-1.5 py-0.5 bg-[#777] text-[#222] font-bold uppercase">
|
||||
Custom
|
||||
</span>
|
||||
)}
|
||||
</div>
|
||||
<p className={`text-base font-medium leading-tight ${isSelected ? "text-[#DDDDDD]" : "text-[#666666]"
|
||||
}`}>
|
||||
<p
|
||||
className={`text-base font-medium leading-tight ${
|
||||
isSelected ? "text-[#DDDDDD]" : "text-[#666666]"
|
||||
}`}
|
||||
>
|
||||
{edition.desc}
|
||||
</p>
|
||||
</button>
|
||||
|
|
@ -314,18 +361,31 @@ const VersionsView = memo(function VersionsView() {
|
|||
e.stopPropagation();
|
||||
handleCancelDownload();
|
||||
}}
|
||||
onMouseEnter={() => setHoveredBtn({ row: i, btn: 'cancel' })}
|
||||
onMouseEnter={() =>
|
||||
setHoveredBtn({ row: i, btn: "cancel" })
|
||||
}
|
||||
onMouseLeave={() => setHoveredBtn(null)}
|
||||
className="w-8 h-8 flex items-center justify-center text-red-600"
|
||||
style={{
|
||||
backgroundImage: (hoveredBtn?.row === i && hoveredBtn?.btn === 'cancel') || (focusIndex === i && focusBtn === 1)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundImage:
|
||||
(hoveredBtn?.row === i &&
|
||||
hoveredBtn?.btn === "cancel") ||
|
||||
(focusIndex === i && focusBtn === 1)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="square">
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="square"
|
||||
>
|
||||
<path d="M18 6L6 18M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
|
|
@ -337,13 +397,18 @@ const VersionsView = memo(function VersionsView() {
|
|||
e.stopPropagation();
|
||||
if (!downloadingId) toggleInstall(edition.id);
|
||||
}}
|
||||
onMouseEnter={() => setHoveredBtn({ row: i, btn: 'download' })}
|
||||
onMouseEnter={() =>
|
||||
setHoveredBtn({ row: i, btn: "download" })
|
||||
}
|
||||
onMouseLeave={() => setHoveredBtn(null)}
|
||||
className={`w-8 h-8 flex items-center justify-center ${downloadingId ? "text-gray-400 cursor-not-allowed" : "text-[#3a3a3a]"}`}
|
||||
style={{
|
||||
backgroundImage: (hoveredBtn?.row === i && hoveredBtn?.btn === 'download') || (focusIndex === i && focusBtn === 1)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundImage:
|
||||
(hoveredBtn?.row === i &&
|
||||
hoveredBtn?.btn === "download") ||
|
||||
(focusIndex === i && focusBtn === 1)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
opacity: downloadingId ? 0.5 : 1,
|
||||
|
|
@ -366,18 +431,31 @@ const VersionsView = memo(function VersionsView() {
|
|||
e.stopPropagation();
|
||||
handleCancelDownload();
|
||||
}}
|
||||
onMouseEnter={() => setHoveredBtn({ row: i, btn: 'cancel' })}
|
||||
onMouseEnter={() =>
|
||||
setHoveredBtn({ row: i, btn: "cancel" })
|
||||
}
|
||||
onMouseLeave={() => setHoveredBtn(null)}
|
||||
className="w-8 h-8 flex items-center justify-center text-red-600"
|
||||
style={{
|
||||
backgroundImage: (hoveredBtn?.row === i && hoveredBtn?.btn === 'cancel') || (focusIndex === i && focusBtn === 1)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundImage:
|
||||
(hoveredBtn?.row === i &&
|
||||
hoveredBtn?.btn === "cancel") ||
|
||||
(focusIndex === i && focusBtn === 1)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="square">
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="square"
|
||||
>
|
||||
<path d="M18 6L6 18M6 6l12 12" />
|
||||
</svg>
|
||||
</button>
|
||||
|
|
@ -388,13 +466,18 @@ const VersionsView = memo(function VersionsView() {
|
|||
e.stopPropagation();
|
||||
if (!downloadingId) toggleInstall(edition.id);
|
||||
}}
|
||||
onMouseEnter={() => setHoveredBtn({ row: i, btn: 'update' })}
|
||||
onMouseEnter={() =>
|
||||
setHoveredBtn({ row: i, btn: "update" })
|
||||
}
|
||||
onMouseLeave={() => setHoveredBtn(null)}
|
||||
className={`w-8 h-8 flex items-center justify-center ${downloadingId ? "text-gray-400 cursor-not-allowed" : "text-[#3a3a3a]"}`}
|
||||
style={{
|
||||
backgroundImage: (hoveredBtn?.row === i && hoveredBtn?.btn === 'update') || (focusIndex === i && focusBtn === 1)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundImage:
|
||||
(hoveredBtn?.row === i &&
|
||||
hoveredBtn?.btn === "update") ||
|
||||
(focusIndex === i && focusBtn === 1)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
opacity: downloadingId ? 0.5 : 1,
|
||||
|
|
@ -414,13 +497,18 @@ const VersionsView = memo(function VersionsView() {
|
|||
playPressSound();
|
||||
TauriService.openInstanceFolder(edition.id);
|
||||
}}
|
||||
onMouseEnter={() => setHoveredBtn({ row: i, btn: 'folder' })}
|
||||
onMouseEnter={() =>
|
||||
setHoveredBtn({ row: i, btn: "folder" })
|
||||
}
|
||||
onMouseLeave={() => setHoveredBtn(null)}
|
||||
className="w-8 h-8 flex items-center justify-center text-[#3a3a3a]"
|
||||
style={{
|
||||
backgroundImage: (hoveredBtn?.row === i && hoveredBtn?.btn === 'folder') || (focusIndex === i && focusBtn === 2)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundImage:
|
||||
(hoveredBtn?.row === i &&
|
||||
hoveredBtn?.btn === "folder") ||
|
||||
(focusIndex === i && focusBtn === 2)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
|
|
@ -438,13 +526,18 @@ const VersionsView = memo(function VersionsView() {
|
|||
playBackSound();
|
||||
setDeleteConfirmEdition(edition);
|
||||
}}
|
||||
onMouseEnter={() => setHoveredBtn({ row: i, btn: 'delete' })}
|
||||
onMouseEnter={() =>
|
||||
setHoveredBtn({ row: i, btn: "delete" })
|
||||
}
|
||||
onMouseLeave={() => setHoveredBtn(null)}
|
||||
className="w-8 h-8 flex items-center justify-center text-[#3a3a3a]"
|
||||
style={{
|
||||
backgroundImage: (hoveredBtn?.row === i && hoveredBtn?.btn === 'delete') || (focusIndex === i && focusBtn === 3)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundImage:
|
||||
(hoveredBtn?.row === i &&
|
||||
hoveredBtn?.btn === "delete") ||
|
||||
(focusIndex === i && focusBtn === 3)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
|
|
@ -465,18 +558,31 @@ const VersionsView = memo(function VersionsView() {
|
|||
setEditingEdition(edition);
|
||||
setIsImportModalOpen(true);
|
||||
}}
|
||||
onMouseEnter={() => setHoveredBtn({ row: i, btn: 'edit' })}
|
||||
onMouseEnter={() =>
|
||||
setHoveredBtn({ row: i, btn: "edit" })
|
||||
}
|
||||
onMouseLeave={() => setHoveredBtn(null)}
|
||||
className="w-8 h-8 flex items-center justify-center text-[#3a3a3a]"
|
||||
style={{
|
||||
backgroundImage: (hoveredBtn?.row === i && hoveredBtn?.btn === 'edit') || (focusIndex === i && focusBtn === 4)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundImage:
|
||||
(hoveredBtn?.row === i &&
|
||||
hoveredBtn?.btn === "edit") ||
|
||||
(focusIndex === i && focusBtn === 4)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="square">
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.5"
|
||||
strokeLinecap="square"
|
||||
>
|
||||
<path d="M12 20h9" />
|
||||
<path d="M16.5 3.5a2.121 2.121 0 0 1 3 3L7 19l-4 1 1-4L16.5 3.5z" />
|
||||
</svg>
|
||||
|
|
@ -487,18 +593,31 @@ const VersionsView = memo(function VersionsView() {
|
|||
playBackSound();
|
||||
onDeleteEdition(edition.id);
|
||||
}}
|
||||
onMouseEnter={() => setHoveredBtn({ row: i, btn: 'delete' })}
|
||||
onMouseEnter={() =>
|
||||
setHoveredBtn({ row: i, btn: "delete" })
|
||||
}
|
||||
onMouseLeave={() => setHoveredBtn(null)}
|
||||
className="w-8 h-8 flex items-center justify-center text-red-600"
|
||||
style={{
|
||||
backgroundImage: (hoveredBtn?.row === i && hoveredBtn?.btn === 'delete') || (focusIndex === i && focusBtn === 3)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundImage:
|
||||
(hoveredBtn?.row === i &&
|
||||
hoveredBtn?.btn === "delete") ||
|
||||
(focusIndex === i && focusBtn === 3)
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="square">
|
||||
<svg
|
||||
width="14"
|
||||
height="14"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="2.5"
|
||||
strokeLinecap="square"
|
||||
>
|
||||
<polyline points="3 6 5 6 21 6" />
|
||||
<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" />
|
||||
</svg>
|
||||
|
|
@ -525,14 +644,25 @@ const VersionsView = memo(function VersionsView() {
|
|||
onMouseLeave={() => setHoveredBtn(null)}
|
||||
className="w-8 h-8 flex items-center justify-center text-[#3a3a3a]"
|
||||
style={{
|
||||
backgroundImage: (hoveredBtn?.row === editions.length && hoveredBtn?.btn === 'add') || focusIndex === editions.length
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundImage:
|
||||
(hoveredBtn?.row === editions.length &&
|
||||
hoveredBtn?.btn === "add") ||
|
||||
focusIndex === editions.length
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="3" strokeLinecap="square">
|
||||
<svg
|
||||
width="16"
|
||||
height="16"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
strokeWidth="3"
|
||||
strokeLinecap="square"
|
||||
>
|
||||
<path d="M12 5v14M5 12h14" />
|
||||
</svg>
|
||||
</button>
|
||||
|
|
@ -547,9 +677,12 @@ const VersionsView = memo(function VersionsView() {
|
|||
title="Import Custom TU"
|
||||
className="w-8 h-8 flex items-center justify-center text-[#3a3a3a]"
|
||||
style={{
|
||||
backgroundImage: (hoveredBtn?.row === editions.length && hoveredBtn?.btn === 'folder_import') || focusIndex === editions.length + 1
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundImage:
|
||||
(hoveredBtn?.row === editions.length &&
|
||||
hoveredBtn?.btn === "folder_import") ||
|
||||
focusIndex === editions.length + 1
|
||||
? "url('/images/Button_Square_Highlighted.png')"
|
||||
: "url('/images/Button_Square.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
|
|
@ -576,9 +709,10 @@ const VersionsView = memo(function VersionsView() {
|
|||
}}
|
||||
className="w-48 h-10 flex items-center justify-center text-xl mc-text-shadow outline-none border-none text-white"
|
||||
style={{
|
||||
backgroundImage: focusIndex === editions.length + 2
|
||||
? "url('/images/button_highlighted.png')"
|
||||
: "url('/images/Button_Background.png')",
|
||||
backgroundImage:
|
||||
focusIndex === editions.length + 2
|
||||
? "url('/images/button_highlighted.png')"
|
||||
: "url('/images/Button_Background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
|
|
@ -623,7 +757,8 @@ const VersionsView = memo(function VersionsView() {
|
|||
Delete {deleteConfirmEdition.name}?
|
||||
</h3>
|
||||
<p className="text-sm text-white mb-6 text-center leading-relaxed">
|
||||
Warning: All your saves and worlds for this version will be permanently deleted!
|
||||
Warning: All your saves and worlds for this version will be
|
||||
permanently deleted!
|
||||
</p>
|
||||
<div className="flex justify-center gap-4">
|
||||
<DeleteConfirmButton
|
||||
|
|
|
|||
Loading…
Reference in a new issue