mirror of
https://github.com/LCE-Hub/LCE-Emerald-Launcher.git
synced 2026-09-24 09:03:44 +00:00
feat(ui): use LCE textinput
This commit is contained in:
@@ -433,7 +433,9 @@ const SkinViewer = memo(function SkinViewer({
|
||||
renderer.domElement.addEventListener("mousedown", onMouseDown);
|
||||
window.addEventListener("mousemove", onMouseMove);
|
||||
window.addEventListener("mouseup", onMouseUp);
|
||||
renderer.domElement.addEventListener("touchstart", onTouchStart, { passive: true });
|
||||
renderer.domElement.addEventListener("touchstart", onTouchStart, {
|
||||
passive: true,
|
||||
});
|
||||
window.addEventListener("touchmove", onTouchMove, { passive: false });
|
||||
window.addEventListener("touchend", onTouchEnd);
|
||||
return () => {
|
||||
@@ -692,6 +694,7 @@ const SkinViewer = memo(function SkinViewer({
|
||||
data-focus="0"
|
||||
tabIndex={0}
|
||||
>
|
||||
<div>
|
||||
<input
|
||||
type="text"
|
||||
value={username}
|
||||
@@ -704,9 +707,10 @@ const SkinViewer = memo(function SkinViewer({
|
||||
e.stopPropagation();
|
||||
}
|
||||
}}
|
||||
className="bg-transparent text-white focus:text-[#FFFF55] outline-none border-none text-center font-[var(--font-base)] mc-text-shadow tracking-widest text-xl cursor-text"
|
||||
className="text-white focus:text-[#FFFF55] outline-none text-center font-[var(--font-base)] tracking-widest text-xl cursor-text"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
{!legacyMode && (
|
||||
<div className="w-[220px] h-[380px] relative flex items-center justify-center">
|
||||
|
||||
@@ -144,6 +144,7 @@ export default function CustomTUModal({
|
||||
<label className="text-gray text-sm mc-text-shadow uppercase tracking-widest">
|
||||
{t("modals.customTu.tuName")}
|
||||
</label>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
autoFocus
|
||||
@@ -151,54 +152,61 @@ export default function CustomTUModal({
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
onFocus={() => setFocusIndex(0)}
|
||||
placeholder={t("modals.customTu.namePlaceholder")}
|
||||
className="w-full h-10 px-3 bg-black/40 border-2 border-[#373737] text-white text-base outline-none font-[var(--font-base)]"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-gray text-sm mc-text-shadow uppercase tracking-widest">
|
||||
{t("modals.customTu.description")}
|
||||
</label>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
value={desc}
|
||||
onChange={(e) => setDesc(e.target.value)}
|
||||
onFocus={() => setFocusIndex(1)}
|
||||
placeholder={t("modals.customTu.descPlaceholder")}
|
||||
className="w-full h-10 px-3 bg-black/40 border-2 border-[#373737] text-white text-base outline-none font-[var(--font-base)]"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-gray text-sm mc-text-shadow uppercase tracking-widest">
|
||||
{t("modals.customTu.downloadUrl")}
|
||||
</label>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
value={url}
|
||||
onChange={(e) => setUrl(e.target.value)}
|
||||
onFocus={() => setFocusIndex(2)}
|
||||
placeholder={t("modals.customTu.urlPlaceholder")}
|
||||
className="w-full h-10 px-3 bg-black/40 border-2 border-[#373737] text-white text-base outline-none font-[var(--font-base)]"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{path && (
|
||||
<div className="flex flex-col gap-1">
|
||||
<label className="text-gray text-sm mc-text-shadow uppercase tracking-widest">
|
||||
{t("modals.customTu.localPath")}
|
||||
</label>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
readOnly
|
||||
value={path}
|
||||
className="w-full h-10 px-3 bg-black/20 border-2 border-[#222] text-black text-xs outline-none font-[var(--font-base)] cursor-not-allowed"
|
||||
className="mc-textinput w-full h-10 px-3 text-black text-xs outline-none font-[var(--font-base)] cursor-not-allowed"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{error && (
|
||||
|
||||
@@ -255,6 +255,7 @@ export default function OptionsModal({
|
||||
case "int":
|
||||
case "number":
|
||||
return (
|
||||
<div className="mc-textinput-outer w-24">
|
||||
<input
|
||||
ref={(el) => {
|
||||
inputRefs.current[index] = el;
|
||||
@@ -273,14 +274,16 @@ export default function OptionsModal({
|
||||
}));
|
||||
}}
|
||||
onFocus={() => setFocusIndex(index)}
|
||||
className={`w-24 h-8 bg-black/40 border-2 border-[#373737] text-white text-sm px-2 outline-none text-center font-[var(--font-base)] focus:border-[#FFFF55] [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none ${
|
||||
className={`mc-textinput w-full h-10 px-3 text-white text-sm outline-none text-center font-[var(--font-base)] [appearance:textfield] [&::-webkit-outer-spin-button]:appearance-none [&::-webkit-inner-spin-button]:appearance-none ${
|
||||
disabled ? "opacity-40 cursor-not-allowed" : ""
|
||||
}`}
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
case "string":
|
||||
return (
|
||||
<div className="mc-textinput-outer w-44">
|
||||
<input
|
||||
ref={(el) => {
|
||||
inputRefs.current[index] = el;
|
||||
@@ -293,11 +296,12 @@ export default function OptionsModal({
|
||||
setValues((prev) => ({ ...prev, [option.id]: e.target.value }));
|
||||
}}
|
||||
onFocus={() => setFocusIndex(index)}
|
||||
className={`w-44 h-8 bg-black/40 border-2 border-[#373737] text-white text-sm px-2 outline-none font-[var(--font-base)] focus:border-[#FFFF55] ${
|
||||
className={`mc-textinput w-full h-10 px-3 text-white text-sm outline-none font-[var(--font-base)] ${
|
||||
disabled ? "opacity-40 cursor-not-allowed" : ""
|
||||
}`}
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
case "choice":
|
||||
return (
|
||||
|
||||
@@ -183,6 +183,7 @@ export default function SetUidModal({
|
||||
<label className="text-gray text-xs mc-text-shadow uppercase tracking-widest text-[#AAAAAA]">
|
||||
{t("modals.setUid.enterUid")}
|
||||
</label>
|
||||
<div className="mc-textinput-outer w-full">
|
||||
<input
|
||||
type="text"
|
||||
autoFocus
|
||||
@@ -190,10 +191,11 @@ export default function SetUidModal({
|
||||
onChange={(e) => setUid(e.target.value)}
|
||||
onFocus={() => setFocusIndex(2)}
|
||||
placeholder="0xFF02F0C87E8AC1F2"
|
||||
className={`w-full h-10 px-3 bg-black/40 border-2 ${focusIndex === 2 ? 'border-white' : 'border-[#373737]'} text-white text-base outline-none font-[var(--font-base)] text-center`}
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)] text-center"
|
||||
style={{ imageRendering: "pixelated", filter: focusIndex === 2 ? 'brightness(1.2)' : 'none' }}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="flex flex-col gap-1 items-center w-full relative">
|
||||
<label className="text-gray text-xs mc-text-shadow uppercase tracking-widest text-[#AAAAAA]">
|
||||
|
||||
@@ -387,13 +387,15 @@ export const ArcEditorView: React.FC = () => {
|
||||
<div className="flex h-full overflow-hidden">
|
||||
<div className="w-2/3 flex flex-col p-4 border-r-2 border-black/20">
|
||||
<div className="mb-4 flex gap-4">
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t("arcEditor.searchEntries")}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="flex-1 bg-black/40 border-2 border-[#373737] text-white px-4 py-2 outline-none focus:border-[#FFFF55] transition-colors"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setIsAddModalOpen(true)}
|
||||
className="px-6 py-2 text-white mc-text-shadow text-sm"
|
||||
@@ -506,13 +508,15 @@ export const ArcEditorView: React.FC = () => {
|
||||
<option key={idx} value={idx}>{lang.id} {lang.isStatic ? `[${t("arcEditor.static")}]` : `[${t("arcEditor.keyed")}]`}</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t("arcEditor.searchStrings")}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="flex-1 bg-black/40 border-2 border-[#373737] text-white px-4 py-2 outline-none focus:border-[#FFFF55] transition-colors"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setIsLocEditModalOpen({ langIdx: selectedLocLangIdx, strIdx: -1, isNew: true })}
|
||||
className="px-6 py-2 text-white mc-text-shadow text-sm"
|
||||
@@ -665,13 +669,15 @@ function RenameModal({ initialName, initialCompressed, onClose, onConfirm }: { i
|
||||
<div className="flex flex-col gap-4">
|
||||
<div>
|
||||
<label className="text-white/40 text-xs uppercase mb-2 block">{t("arcEditor.newArchivePath")}</label>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
className="w-full bg-black/40 border-2 border-[#373737] text-white px-4 py-3 outline-none focus:border-[#FFFF55] transition-colors"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<label className="flex items-center gap-3 cursor-pointer group">
|
||||
<input type="checkbox" checked={comp} onChange={(e) => setComp(e.target.checked)} className="w-5 h-5 accent-[#FFFF55]" />
|
||||
<span className="text-white group-hover:text-[#FFFF55] transition-colors">{t("arcEditor.markAsCompressed")}</span>
|
||||
@@ -704,13 +710,15 @@ function LocEditModal({ data, lang, onClose, onConfirm }: { data: { langIdx: num
|
||||
{!lang.isStatic ? (
|
||||
<div>
|
||||
<label className="text-white/40 text-xs uppercase mb-2 block">{t("arcEditor.stringKey")}</label>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
value={key}
|
||||
onChange={(e) => setKey(e.target.value)}
|
||||
className="w-full bg-black/40 border-2 border-[#373737] text-white px-4 py-3 outline-none focus:border-[#FFFF55] transition-colors font-mono"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)] font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-white/40 italic mb-2">{t("arcEditor.staticEntry", { index: data.isNew ? lang.strings.length : data.strIdx })}</div>
|
||||
)}
|
||||
|
||||
@@ -183,13 +183,15 @@ export default function ColEditorView() {
|
||||
|
||||
<div className="flex-1 flex flex-col p-4 overflow-hidden">
|
||||
<div className="mb-4 flex gap-4">
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t("colEditor.searchColors")}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="flex-1 bg-black/40 border-2 border-[#373737] text-white px-4 py-2 outline-none focus:border-[#FFFF55] transition-colors"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={activeTab === "colors" ? handleAddColor : handleAddWorldColor}
|
||||
className="px-6 py-2 text-white mc-text-shadow text-sm"
|
||||
@@ -219,12 +221,14 @@ export default function ColEditorView() {
|
||||
{activeTab === "colors" && currentColors.map((c) => (
|
||||
<tr key={c.originalIdx} className="border-b border-[#373737]/30 group">
|
||||
<td className="p-2">
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
value={c.name}
|
||||
onChange={(e) => handleUpdateColor(c.originalIdx, "name", e.target.value)}
|
||||
className="w-full bg-black/40 border border-[#373737] px-2 py-1 outline-none focus:border-[#FFFF55] text-white text-sm"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-sm outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-2">
|
||||
<div className="flex items-center gap-3">
|
||||
@@ -239,6 +243,7 @@ export default function ColEditorView() {
|
||||
}}
|
||||
className="w-8 h-8 p-0 cursor-pointer shrink-0 border border-[#373737] rounded-sm bg-transparent"
|
||||
/>
|
||||
<div className="mc-textinput-outer w-24">
|
||||
<input
|
||||
type="text"
|
||||
value={argbToHex(c.color)}
|
||||
@@ -249,10 +254,11 @@ export default function ColEditorView() {
|
||||
if (!isNaN(parsed)) handleUpdateColor(c.originalIdx, "color", parsed >>> 0);
|
||||
}
|
||||
}}
|
||||
className="bg-black/40 border border-[#373737] w-24 px-2 py-1 outline-none focus:border-[#FFFF55] text-white font-mono text-sm uppercase"
|
||||
className="mc-textinput w-full h-10 px-3 text-white font-mono text-sm uppercase outline-none font-[var(--font-base)]"
|
||||
maxLength={8}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-2 text-right">
|
||||
<button onClick={() => handleDeleteColor(c.originalIdx)} className="p-1 hover:text-red-500 opacity-60">
|
||||
@@ -265,12 +271,14 @@ export default function ColEditorView() {
|
||||
{activeTab === "worldColors" && currentWorldColors.map((w) => (
|
||||
<tr key={w.originalIdx} className="border-b border-[#373737]/30 group">
|
||||
<td className="p-2">
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
value={w.name}
|
||||
onChange={(e) => handleUpdateWorldColor(w.originalIdx, "name", e.target.value)}
|
||||
className="w-full bg-black/40 border border-[#373737] px-2 py-1 outline-none focus:border-[#FFFF55] text-white text-sm"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-sm outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-2">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -284,6 +292,7 @@ export default function ColEditorView() {
|
||||
}}
|
||||
className="w-6 h-6 p-0 cursor-pointer shrink-0 border border-[#373737] rounded-sm bg-transparent"
|
||||
/>
|
||||
<div className="mc-textinput-outer w-20">
|
||||
<input
|
||||
type="text"
|
||||
value={argbToHex(w.waterColor)}
|
||||
@@ -294,10 +303,11 @@ export default function ColEditorView() {
|
||||
if (!isNaN(parsed)) handleUpdateWorldColor(w.originalIdx, "waterColor", parsed >>> 0);
|
||||
}
|
||||
}}
|
||||
className="bg-black/40 border border-[#373737] w-20 px-2 py-1 outline-none focus:border-[#FFFF55] text-white font-mono text-xs uppercase"
|
||||
className="mc-textinput w-full h-10 px-3 text-white font-mono text-xs uppercase outline-none font-[var(--font-base)]"
|
||||
maxLength={8}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-2">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -311,6 +321,7 @@ export default function ColEditorView() {
|
||||
}}
|
||||
className="w-6 h-6 p-0 cursor-pointer shrink-0 border border-[#373737] rounded-sm bg-transparent"
|
||||
/>
|
||||
<div className="mc-textinput-outer w-20">
|
||||
<input
|
||||
type="text"
|
||||
value={argbToHex(w.underwaterColor)}
|
||||
@@ -321,10 +332,11 @@ export default function ColEditorView() {
|
||||
if (!isNaN(parsed)) handleUpdateWorldColor(w.originalIdx, "underwaterColor", parsed >>> 0);
|
||||
}
|
||||
}}
|
||||
className="bg-black/40 border border-[#373737] w-20 px-2 py-1 outline-none focus:border-[#FFFF55] text-white font-mono text-xs uppercase"
|
||||
className="mc-textinput w-full h-10 px-3 text-white font-mono text-xs uppercase outline-none font-[var(--font-base)]"
|
||||
maxLength={8}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-2">
|
||||
<div className="flex items-center gap-2">
|
||||
@@ -338,6 +350,7 @@ export default function ColEditorView() {
|
||||
}}
|
||||
className="w-6 h-6 p-0 cursor-pointer shrink-0 border border-[#373737] rounded-sm bg-transparent"
|
||||
/>
|
||||
<div className="mc-textinput-outer w-20">
|
||||
<input
|
||||
type="text"
|
||||
value={argbToHex(w.fogColor)}
|
||||
@@ -348,10 +361,11 @@ export default function ColEditorView() {
|
||||
if (!isNaN(parsed)) handleUpdateWorldColor(w.originalIdx, "fogColor", parsed >>> 0);
|
||||
}
|
||||
}}
|
||||
className="bg-black/40 border border-[#373737] w-20 px-2 py-1 outline-none focus:border-[#FFFF55] text-white font-mono text-xs uppercase"
|
||||
className="mc-textinput w-full h-10 px-3 text-white font-mono text-xs uppercase outline-none font-[var(--font-base)]"
|
||||
maxLength={8}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
</td>
|
||||
<td className="p-2 text-right">
|
||||
<button onClick={() => handleDeleteWorldColor(w.originalIdx)} className="p-1 hover:text-red-500 opacity-60">
|
||||
|
||||
@@ -354,7 +354,7 @@ const GoldMapperView = memo(function GoldMapperView() {
|
||||
? handleToggleEnabled
|
||||
: () => openBind(row.id)
|
||||
}
|
||||
className={`w-full h-10 flex items-center pl-6 pr-4 outline-none border-none shrink-0 transition-colors ${
|
||||
className={`w-full h-10 flex items-center ${!isEnable ? "pl-6" : "pl-2"} pr-4 outline-none border-none shrink-0 transition-colors ${
|
||||
focused
|
||||
? "text-[#ffff00]"
|
||||
: isEnable
|
||||
@@ -386,7 +386,7 @@ const GoldMapperView = memo(function GoldMapperView() {
|
||||
</div>
|
||||
)}
|
||||
<span
|
||||
className={`tracking-widest text-lg mc-text-shadow truncate ${
|
||||
className={`tracking-widest text-lg truncate ${
|
||||
isReset ? "" : "flex-1 text-left"
|
||||
}`}
|
||||
>
|
||||
@@ -425,9 +425,9 @@ const GoldMapperView = memo(function GoldMapperView() {
|
||||
<button
|
||||
onMouseEnter={() => setFocusIndex(null)}
|
||||
onClick={handleBack}
|
||||
className="w-40 h-10 flex items-center justify-center transition-colors text-xl mc-text-shadow outline-none border-none hover:text-[#ffff00] mt-4 text-white"
|
||||
className="w-40 h-10 flex items-center justify-center transition-colors text-xl outline-none border-none hover:text-[#ffff00] mt-4 text-white"
|
||||
style={{
|
||||
backgroundImage: "url('/images/Layout_Button_Bmp.png')",
|
||||
backgroundImage: "url('/images/Button_Background.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
@@ -443,13 +443,13 @@ const GoldMapperView = memo(function GoldMapperView() {
|
||||
}}
|
||||
>
|
||||
<div className="relative w-[620px] max-w-[95vw] h-[580px] max-h-[88vh] p-5 flex flex-col font-[var(--font-base)] mc-options-bg">
|
||||
<h2 className="text-xl text-black mc-text-shadow mb-4 text-center">
|
||||
<h2 className="text-xl text-black mb-4 text-center">
|
||||
{t("goldMapper.assign", { name: displayName(editing) })}
|
||||
</h2>
|
||||
|
||||
<div className="w-full flex-1 min-h-0 overflow-y-auto custom-scrollbar mb-4">
|
||||
<div className="mb-3">
|
||||
<h3 className="text-[#333333] mc-text-shadow uppercase tracking-widest text-sm px-3 pt-2 pb-1">
|
||||
<h3 className="text-[#333333] tracking-widest text-sm px-3 pt-2 pb-1">
|
||||
{t("goldMapper.mouse")}
|
||||
</h3>
|
||||
<div className="grid grid-cols-4 gap-2 p-1 content-start">
|
||||
@@ -472,7 +472,7 @@ const GoldMapperView = memo(function GoldMapperView() {
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<h3 className="text-[#333333] mc-text-shadow uppercase tracking-widest text-sm px-3 pt-2 pb-1">
|
||||
<h3 className="text-[#333333] tracking-widest text-sm px-3 pt-2 pb-1">
|
||||
{t("goldMapper.controller")}
|
||||
</h3>
|
||||
<div className="grid grid-cols-4 gap-2 p-1 content-start">
|
||||
@@ -500,9 +500,10 @@ const GoldMapperView = memo(function GoldMapperView() {
|
||||
</div>
|
||||
|
||||
<div className="mb-3">
|
||||
<h3 className="text-[#333333] mc-text-shadow uppercase tracking-widest text-sm px-3 pt-2 pb-1">
|
||||
<h3 className="text-[#333333] tracking-widest text-sm px-3 pt-2 pb-1">
|
||||
{t("goldMapper.keyboard")}
|
||||
</h3>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
data-modal-index={MOUSE_IDS.length + controllerIds.length}
|
||||
value={keyInput}
|
||||
@@ -520,13 +521,12 @@ const GoldMapperView = memo(function GoldMapperView() {
|
||||
if (e.key === "Enter") submitKeyInput();
|
||||
}}
|
||||
placeholder={t("goldMapper.typeKeyName")}
|
||||
className={`w-full h-10 px-3 bg-black/40 border-2 text-white text-base outline-none text-center ${
|
||||
keyInputError
|
||||
? "border-red-600"
|
||||
: "border-[#373737] focus:border-[#FFFF55]"
|
||||
className={`mc-textinput w-full h-10 px-3 text-white text-base outline-none text-center font-[var(--font-base)] ${
|
||||
keyInputError ? "" : ""
|
||||
}`}
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</div>
|
||||
{keyInputError && (
|
||||
<p className="text-red-600 text-xs mt-1 px-3">
|
||||
{keyInputError}
|
||||
@@ -544,7 +544,7 @@ const GoldMapperView = memo(function GoldMapperView() {
|
||||
setModalFocusIndex(MOUSE_IDS.length + controllerIds.length + 1)
|
||||
}
|
||||
onClick={closeModal}
|
||||
className={`w-full h-12 flex items-center justify-center text-xl mc-text-shadow transition-colors outline-none border-none cursor-pointer ${
|
||||
className={`w-full h-12 flex items-center justify-center text-xl transition-colors outline-none border-none cursor-pointer ${
|
||||
modalFocusIndex === MOUSE_IDS.length + controllerIds.length + 1
|
||||
? "text-[#ffff00]"
|
||||
: "text-white"
|
||||
|
||||
@@ -291,13 +291,15 @@ function GrfNodeView({ node, level, path, onUpdate }: { node: GrfNode, level: nu
|
||||
{node.parameters.map((p, i) => (
|
||||
<div key={i} className="flex gap-4 border-b border-[#373737]/30 py-2 text-sm items-center">
|
||||
<span className="text-[#AAAAAA] w-1/3 truncate">{p.name}</span>
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
type="text"
|
||||
value={p.value}
|
||||
onChange={(e) => onUpdate(currentPath, i, e.target.value)}
|
||||
className="flex-1 bg-white/5 border border-white/10 px-2 py-1 text-white outline-none focus:border-[#FFFF55]/50 font-mono transition-colors"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)] font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
)}
|
||||
|
||||
@@ -821,14 +821,16 @@ const LceOnlineView = memo(function LceOnlineView({
|
||||
<h2 className="text-[#FFFF55] text-3xl mc-text-shadow mb-6 border-b-2 border-[#373737] pb-2 w-full text-center uppercase tracking-widest">
|
||||
{t("lceOnline.addFriend")}
|
||||
</h2>
|
||||
<div className="mc-textinput-outer w-full mb-6">
|
||||
<input
|
||||
ref={addFriendInputRef}
|
||||
type="text"
|
||||
className="bg-black/20 border-4 border-[#555] text-white p-4 w-full text-2xl font-bold outline-none focus:border-[#FFFF55] transition-colors placeholder:text-[#888] mb-6 mc-text-shadow"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)] text-2xl font-bold placeholder:text-[#888] mc-text-shadow"
|
||||
placeholder={t("lceOnline.username")}
|
||||
value={addFriendUsername}
|
||||
onChange={(e) => setAddFriendUsername(e.target.value)}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-4 w-full">
|
||||
<button
|
||||
className="h-12 flex-1 flex items-center justify-center text-white mc-text-shadow text-xl font-bold uppercase tracking-widest hover:text-[#FFFF55] outline-none border-none"
|
||||
|
||||
@@ -150,13 +150,15 @@ export default function LocEditorView() {
|
||||
<option key={idx} value={idx}>{lang.id} {lang.isStatic ? `[${t("locEditor.static")}]` : `[${t("locEditor.keyed")}]`}</option>
|
||||
))}
|
||||
</select>
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t("locEditor.searchStrings")}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="flex-1 bg-black/40 border-2 border-[#373737] text-white px-4 py-2 outline-none focus:border-[#FFFF55] transition-colors"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => setIsLocEditModalOpen({ langIdx: selectedLocLangIdx, strIdx: -1, isNew: true })}
|
||||
className="px-6 py-2 text-white mc-text-shadow text-sm"
|
||||
@@ -250,13 +252,15 @@ function LocEditModal({ data, lang, onClose, onConfirm }: { data: { langIdx: num
|
||||
{!lang.isStatic ? (
|
||||
<div>
|
||||
<label className="text-white/40 text-xs uppercase mb-2 block">{t("locEditor.stringKey")}</label>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
value={key}
|
||||
onChange={(e) => setKey(e.target.value)}
|
||||
className="w-full bg-black/40 border-2 border-[#373737] text-white px-4 py-3 outline-none focus:border-[#FFFF55] transition-colors font-mono"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)] font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<div className="text-white/40 italic mb-2">{t("locEditor.staticEntry", { index: data.isNew ? lang.strings.length : data.strIdx })}</div>
|
||||
)}
|
||||
|
||||
@@ -865,14 +865,16 @@ function PartEditModal({
|
||||
<label className="text-white/40 text-[10px] uppercase tracking-widest mb-1 block">
|
||||
{t("modelEditor.name")}
|
||||
</label>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
value={name}
|
||||
onChange={(e) => setName(e.target.value)}
|
||||
className="w-full bg-black/40 border-2 border-[#373737] text-white px-4 py-2 outline-none focus:border-[#FFFF55] transition-colors"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label className="text-white/40 text-[10px] uppercase tracking-widest mb-1 block">
|
||||
{t("modelEditor.translation")}
|
||||
@@ -883,6 +885,7 @@ function PartEditModal({
|
||||
<span className="text-white/40 text-xs font-mono">
|
||||
{axis}
|
||||
</span>
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
type="number"
|
||||
step={0.5}
|
||||
@@ -893,9 +896,10 @@ function PartEditModal({
|
||||
else if (axis === "Y") setTy(v);
|
||||
else setTz(v);
|
||||
}}
|
||||
className="w-full bg-black/40 border border-[#373737] text-white px-2 py-1 outline-none focus:border-[#FFFF55] text-sm"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-sm outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -985,6 +989,7 @@ function BoxEditModal({
|
||||
<span className="text-white/40 text-xs font-mono">
|
||||
{axis}
|
||||
</span>
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
type="number"
|
||||
step={0.5}
|
||||
@@ -995,9 +1000,10 @@ function BoxEditModal({
|
||||
else if (axis === "Y") setPosY(v);
|
||||
else setPosZ(v);
|
||||
}}
|
||||
className="w-full bg-black/40 border border-[#373737] text-white px-2 py-1 outline-none focus:border-[#FFFF55] text-sm"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-sm outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1011,6 +1017,7 @@ function BoxEditModal({
|
||||
<span className="text-white/40 text-xs font-mono">
|
||||
{axis}
|
||||
</span>
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
type="number"
|
||||
step={0.5}
|
||||
@@ -1022,9 +1029,10 @@ function BoxEditModal({
|
||||
else if (axis === "Y") setSizeY(v);
|
||||
else setSizeZ(v);
|
||||
}}
|
||||
className="w-full bg-black/40 border border-[#373737] text-white px-2 py-1 outline-none focus:border-[#FFFF55] text-sm"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-sm outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1038,6 +1046,7 @@ function BoxEditModal({
|
||||
<span className="text-white/40 text-xs font-mono">
|
||||
{axis}
|
||||
</span>
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
type="number"
|
||||
min={0}
|
||||
@@ -1047,9 +1056,10 @@ function BoxEditModal({
|
||||
if (axis === "X") setUvX(v);
|
||||
else setUvY(v);
|
||||
}}
|
||||
className="w-full bg-black/40 border border-[#373737] text-white px-2 py-1 outline-none focus:border-[#FFFF55] text-sm"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-sm outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
@@ -1057,14 +1067,16 @@ function BoxEditModal({
|
||||
<label className="text-white/40 text-[10px] uppercase tracking-widest">
|
||||
{t("modelEditor.inflate")}
|
||||
</label>
|
||||
<div className="mc-textinput-outer w-20">
|
||||
<input
|
||||
type="number"
|
||||
step={0.1}
|
||||
value={inflate}
|
||||
onChange={(e) => setInflate(parseFloat(e.target.value) || 0)}
|
||||
className="w-20 bg-black/40 border border-[#373737] text-white px-2 py-1 outline-none focus:border-[#FFFF55] text-sm"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-sm outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-3 justify-end">
|
||||
<label className="text-white/40 text-[10px] uppercase tracking-widest">
|
||||
{t("modelEditor.mirrorUv")}
|
||||
|
||||
@@ -161,28 +161,34 @@ export default function OptionsEditorView() {
|
||||
<div className="flex flex-col gap-8 max-w-xl mx-auto">
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-white/80 uppercase tracking-widest">{t("optionsEditor.chosenSkinId")}</span>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="number" value={opt.chosenSkin} onChange={(e) => updateSetting("chosenSkin", parseInt(e.target.value) || 0)}
|
||||
className="bg-black/40 border border-[#373737] p-2 text-white outline-none focus:border-[#FFFF55] font-mono text-lg"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-lg outline-none font-[var(--font-base)] font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-white/80 uppercase tracking-widest">{t("optionsEditor.playerCapeId")}</span>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="number" value={opt.playerCape} onChange={(e) => updateSetting("playerCape", parseInt(e.target.value) || 0)}
|
||||
className="bg-black/40 border border-[#373737] p-2 text-white outline-none focus:border-[#FFFF55] font-mono text-lg"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-lg outline-none font-[var(--font-base)] font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-col gap-2">
|
||||
<span className="text-white/80 uppercase tracking-widest">{t("optionsEditor.favoriteSkins")}</span>
|
||||
{opt.favoriteSkins.map((s, i) => (
|
||||
<div key={i} className="flex items-center gap-4">
|
||||
<span className="text-white/40 w-8">{i + 1}.</span>
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
type="number" value={s} onChange={(e) => updateFavSkin(i, parseInt(e.target.value) || 0)}
|
||||
className="bg-black/40 flex-1 border border-[#373737] p-2 text-white outline-none focus:border-[#FFFF55] font-mono"
|
||||
className="mc-textinput w-full h-10 px-3 text-white outline-none font-[var(--font-base)] font-mono"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -646,13 +646,15 @@ export default function PckEditorView() {
|
||||
}}
|
||||
>
|
||||
<div className="mb-4 flex gap-4">
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t("pckEditor.searchAssets")}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="flex-1 bg-black/40 border-2 border-[#373737] text-white px-4 py-2 outline-none focus:border-[#FFFF55] transition-colors"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => addAssetInputRef.current?.click()}
|
||||
className="px-4 py-2 text-white mc-text-shadow text-sm shrink-0"
|
||||
@@ -848,14 +850,16 @@ export default function PckEditorView() {
|
||||
className="flex flex-col gap-1 group/prop"
|
||||
>
|
||||
<div className="flex justify-between items-center px-1">
|
||||
<div className="mc-textinput-outer w-2/3">
|
||||
<input
|
||||
type="text"
|
||||
value={prop.key}
|
||||
onChange={(e) =>
|
||||
handlePropertyEdit(idx, e.target.value, true)
|
||||
}
|
||||
className="bg-transparent text-white/40 text-[10px] outline-none hover:text-white/60 focus:text-[#FFFF55] w-2/3"
|
||||
className="mc-textinput w-full h-8 px-2 text-white/60 text-[10px] outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
<button
|
||||
onClick={() => handleRemoveProperty(idx)}
|
||||
className="text-red-500/0 group-hover/prop:text-red-500/40 hover:text-red-500 transition-colors text-[10px] uppercase"
|
||||
@@ -864,15 +868,17 @@ export default function PckEditorView() {
|
||||
</button>
|
||||
</div>
|
||||
<div className="relative">
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
value={prop.value}
|
||||
onChange={(e) =>
|
||||
handlePropertyEdit(idx, e.target.value)
|
||||
}
|
||||
className="w-full bg-black/40 p-2 text-white border border-[#373737] text-sm focus:border-[#FFFF55] outline-none transition-colors"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)] text-sm"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{prop.key === "ANIM" && (
|
||||
<div className="mt-2 p-3 bg-black/30 border border-[#373737]/50 grid grid-cols-2 gap-x-4 gap-y-2">
|
||||
@@ -1175,14 +1181,16 @@ function RenameAssetModal({
|
||||
<label className="text-white/40 text-[10px] uppercase tracking-widest mb-1 block">
|
||||
{t("pckEditor.newAssetPath")}
|
||||
</label>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
value={path}
|
||||
onChange={(e) => setPath(e.target.value)}
|
||||
className="w-full bg-black/40 border-2 border-[#373737] text-white px-4 py-3 outline-none focus:border-[#FFFF55] transition-colors"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex justify-end gap-4 mt-4">
|
||||
<button
|
||||
onClick={onClose}
|
||||
|
||||
@@ -798,6 +798,13 @@ const SettingsView = memo(function SettingsView() {
|
||||
useEffect(() => {
|
||||
const handleKeyDown = (e: KeyboardEvent) => {
|
||||
if (e.key === "Escape") {
|
||||
if (
|
||||
document.activeElement instanceof HTMLInputElement &&
|
||||
document.activeElement.type === "text"
|
||||
) {
|
||||
document.activeElement.blur();
|
||||
return;
|
||||
}
|
||||
if (showModal) {
|
||||
playBackSound();
|
||||
setShowModal(null);
|
||||
@@ -848,6 +855,11 @@ const SettingsView = memo(function SettingsView() {
|
||||
const item = settingsItems[focusIndex];
|
||||
if (item.type === "button") {
|
||||
item.onClick();
|
||||
} else if (item.type === "textinput") {
|
||||
const el = containerRef.current?.querySelector(
|
||||
`[data-index="${focusIndex}"] input`,
|
||||
) as HTMLInputElement | null;
|
||||
el?.focus();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -955,6 +967,7 @@ const SettingsView = memo(function SettingsView() {
|
||||
<div
|
||||
key={item.id}
|
||||
data-index={index}
|
||||
tabIndex={0}
|
||||
onMouseEnter={() => setFocusIndex(index)}
|
||||
className="relative w-[480px] flex flex-col cursor-pointer transition-all outline-none shrink-0"
|
||||
>
|
||||
@@ -1116,6 +1129,7 @@ const SettingsView = memo(function SettingsView() {
|
||||
<div
|
||||
key={item.id}
|
||||
data-index={index}
|
||||
tabIndex={0}
|
||||
onMouseEnter={() => setFocusIndex(index)}
|
||||
className="relative w-[600px] flex flex-col cursor-pointer transition-all outline-none shrink-0"
|
||||
>
|
||||
@@ -1238,14 +1252,16 @@ const SettingsView = memo(function SettingsView() {
|
||||
<p className="text-[#AAAAAA] text-xs mb-4 text-center mc-text-shadow">
|
||||
{t("settings.extraLaunchArgsDesc")}
|
||||
</p>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
autoFocus
|
||||
value={argsInput}
|
||||
onChange={(e) => setArgsInput(e.target.value)}
|
||||
placeholder="e.g. -quitondisconnect -ip 127.0.0.1"
|
||||
className="w-full h-10 px-3 bg-black/40 border-2 border-[#373737] text-white text-base outline-none font-[var(--font-base)] text-center"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)] text-center"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-4 mt-6 w-full justify-center">
|
||||
<button
|
||||
onClick={() => {
|
||||
@@ -1318,14 +1334,16 @@ const SettingsView = memo(function SettingsView() {
|
||||
<p className="text-[#AAAAAA] text-xs mb-4 text-center mc-text-shadow">
|
||||
{t("settings.launchPrefixDesc")}
|
||||
</p>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
autoFocus
|
||||
value={prefixInput}
|
||||
onChange={(e) => setPrefixInput(e.target.value)}
|
||||
placeholder="e.g. gamemoderun"
|
||||
className="w-full h-10 px-3 bg-black/40 border-2 border-[#373737] text-white text-base outline-none font-[var(--font-base)] text-center"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)] text-center"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
</div>
|
||||
<div className="flex gap-4 mt-6 w-full justify-center">
|
||||
<button
|
||||
onClick={() => {
|
||||
|
||||
@@ -273,6 +273,7 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
{t("setup.username")}
|
||||
</span>
|
||||
<div className="relative">
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
ref={(el) => {
|
||||
@@ -293,7 +294,7 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
const caret =
|
||||
document.getElementById("custom-caret");
|
||||
if (caret) {
|
||||
caret.style.left = `${cursorPosition + 16}px`;
|
||||
caret.style.left = `${cursorPosition + 14}px`;
|
||||
}
|
||||
}
|
||||
}}
|
||||
@@ -321,29 +322,28 @@ const SetupView: React.FC<SetupViewProps> = ({ onComplete }) => {
|
||||
const caret =
|
||||
document.getElementById("custom-caret");
|
||||
if (caret) {
|
||||
caret.style.left = `${cursorPosition + 16}px`;
|
||||
caret.style.left = `${cursorPosition + 14}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]"}`}
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base tracking-widest outline-none font-[var(--font-base)]"
|
||||
style={{
|
||||
imageRendering: "pixelated",
|
||||
fontFamily: "'Mojangles', monospace",
|
||||
backgroundColor: "#646464",
|
||||
caretColor: "transparent",
|
||||
}}
|
||||
placeholder={t("setup.enterUsername")}
|
||||
maxLength={16}
|
||||
autoFocus
|
||||
/>
|
||||
</div>
|
||||
{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",
|
||||
left: "14px",
|
||||
}}
|
||||
>
|
||||
_
|
||||
|
||||
@@ -641,6 +641,7 @@ const SkinEditorView = memo(function SkinEditorView() {
|
||||
style={{ boxShadow: "inset 2px 2px 0 #000, inset -1px -1px 0 #555" }}
|
||||
>
|
||||
<span className="pl-2 text-white/50 text-sm mc-text-shadow">#</span>
|
||||
<div className="mc-textinput-outer w-full h-8">
|
||||
<input
|
||||
type="text"
|
||||
value={hexValue}
|
||||
@@ -651,9 +652,10 @@ const SkinEditorView = memo(function SkinEditorView() {
|
||||
setHexValue(hex.toUpperCase());
|
||||
if (hex.length === 6) setColorFromHex(`#${hex}`);
|
||||
}}
|
||||
className="w-full h-full px-1 text-sm text-white tracking-widest uppercase mc-text-shadow bg-transparent"
|
||||
className="mc-textinput w-full h-full px-1 text-sm text-white tracking-widest uppercase outline-none"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="relative w-full h-10 flex items-center justify-center" style={sliderBg}>
|
||||
<span className="absolute z-10 text-sm text-white mc-text-shadow tracking-widest pointer-events-none">
|
||||
|
||||
@@ -561,7 +561,9 @@ const SkinsView = memo(function SkinsView() {
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
{viewMode === "skin" ? t("skins.importSkin") : t("skins.importCape")}
|
||||
{viewMode === "skin"
|
||||
? t("skins.importSkin")
|
||||
: t("skins.importCape")}
|
||||
</button>
|
||||
|
||||
<button
|
||||
@@ -596,7 +598,9 @@ const SkinsView = memo(function SkinsView() {
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
{viewMode === "skin" ? t("skins.deleteSkin") : t("skins.deleteCape")}
|
||||
{viewMode === "skin"
|
||||
? t("skins.deleteSkin")
|
||||
: t("skins.deleteCape")}
|
||||
</button>
|
||||
|
||||
{viewMode === "skin" && (
|
||||
@@ -708,17 +712,21 @@ const SkinsView = memo(function SkinsView() {
|
||||
>
|
||||
<HeadPreview src={skin.url} />
|
||||
</div>
|
||||
<div className="w-full">
|
||||
<input
|
||||
type="text"
|
||||
value={skin.name}
|
||||
maxLength={16}
|
||||
onChange={(e) => handleNameChange(skin.id, e.target.value)}
|
||||
className={`bg-transparent text-center outline-none border-none text-base mc-text-shadow w-full truncate transition-colors relative z-10 ${isActive || isFocused ? "text-[#FFFF55]" : "text-white"} ${isDefaultSkin(skin.id) ? "pointer-events-none" : ""}`}
|
||||
onChange={(e) =>
|
||||
handleNameChange(skin.id, e.target.value)
|
||||
}
|
||||
className={`w-full h-10 px-3 text-base text-center truncate outline-none relative z-10 font-[var(--font-base)] ${isActive || isFocused ? "text-[#FFFF55]" : "text-white"} ${isDefaultSkin(skin.id) ? "pointer-events-none" : ""}`}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
spellCheck={false}
|
||||
readOnly={isDefaultSkin(skin.id)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})
|
||||
) : (
|
||||
@@ -779,6 +787,7 @@ const SkinsView = memo(function SkinsView() {
|
||||
>
|
||||
<CapePreview src={cape.url} />
|
||||
</div>
|
||||
<div className="mc-textinput-outer w-full">
|
||||
<input
|
||||
type="text"
|
||||
value={cape.name}
|
||||
@@ -786,12 +795,13 @@ const SkinsView = memo(function SkinsView() {
|
||||
onChange={(e) =>
|
||||
handleCapeNameChange(cape.id, e.target.value)
|
||||
}
|
||||
className={`bg-transparent text-center outline-none border-none text-base mc-text-shadow w-full truncate transition-colors relative z-10 ${isActive || isFocused ? "text-[#FFFF55]" : "text-white"} ${isDefaultCape(cape.id) ? "pointer-events-none" : ""}`}
|
||||
className={`mc-textinput w-full h-10 px-3 text-base text-center truncate outline-none relative z-10 font-[var(--font-base)] ${isActive || isFocused ? "text-[#FFFF55]" : "text-white"} ${isDefaultCape(cape.id) ? "pointer-events-none" : ""}`}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
spellCheck={false}
|
||||
readOnly={isDefaultCape(cape.id)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
);
|
||||
})}
|
||||
</>
|
||||
@@ -896,6 +906,7 @@ const SkinsView = memo(function SkinsView() {
|
||||
</div>
|
||||
) : importMode === "username" ? (
|
||||
<div className="flex flex-col gap-4 w-full px-4 mb-2">
|
||||
<div className="mc-textinput-outer w-full">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t("skins.minecraftUsername")}
|
||||
@@ -904,8 +915,9 @@ const SkinsView = memo(function SkinsView() {
|
||||
onFocus={() => setModalFocusIndex(0)}
|
||||
autoFocus
|
||||
spellCheck={false}
|
||||
className={`w-full h-12 bg-black/50 border-2 text-white px-4 text-xl outline-none transition-colors relative z-10 ${modalFocusIndex === 0 ? "border-[#FFFF55]" : "border-[#373737]"}`}
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-xl outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
|
||||
{importError && (
|
||||
<span className="text-red-400 text-sm text-center mc-text-shadow">
|
||||
|
||||
@@ -218,14 +218,16 @@ export default function SwfView() {
|
||||
<div className="flex-1 w-full flex gap-4 overflow-hidden">
|
||||
<div className="w-1/3 flex flex-col p-4" style={{ backgroundImage: "url('/images/frame_background.png')", backgroundSize: "100% 100%", imageRendering: "pixelated" }}>
|
||||
<div className="mb-4">
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t("swfEditor.searchAssets")}
|
||||
value={searchTerm}
|
||||
onChange={(e) => setSearchTerm(e.target.value)}
|
||||
className="w-full bg-black/40 border-2 border-[#373737] text-white px-4 py-2 outline-none focus:border-[#FFFF55] transition-colors"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)]"
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex-1 overflow-y-auto pr-2 custom-scrollbar space-y-1">
|
||||
{filteredImages.map(img => (
|
||||
<div
|
||||
|
||||
@@ -843,14 +843,8 @@ const WorkshopView = memo(function WorkshopView({
|
||||
{showSearch ? (
|
||||
<div className="absolute inset-0 flex flex-col pt-2">
|
||||
<div className="flex items-center gap-3 px-6 pb-4">
|
||||
<div
|
||||
className="flex items-center flex-1 h-12 px-4 border-2 border-[#444] bg-black/40 rounded shadow-inner"
|
||||
style={{
|
||||
backgroundImage: "url('/images/Button_Background2.png')",
|
||||
backgroundSize: "100% 100%",
|
||||
imageRendering: "pixelated",
|
||||
}}
|
||||
>
|
||||
<div className="flex items-center flex-1 h-12 px-4 rounded">
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
ref={searchRef}
|
||||
type="text"
|
||||
@@ -874,15 +868,16 @@ const WorkshopView = memo(function WorkshopView({
|
||||
}
|
||||
spellCheck={false}
|
||||
autoFocus={isSearchTab}
|
||||
className="bg-transparent border-none outline-none text-white text-lg mc-text-shadow w-full placeholder-white/40 font-[var(--font-base)] tracking-widest"
|
||||
className="mc-textinput w-full h-10 px-3 text-white text-base outline-none font-[var(--font-base)] placeholder-white/40 tracking-widest"
|
||||
/>
|
||||
</div>
|
||||
{search && (
|
||||
<button
|
||||
onClick={() => {
|
||||
setSearch("");
|
||||
searchRef.current?.focus();
|
||||
}}
|
||||
className="text-white/60 hover:text-white text-lg ml-2 bg-transparent border-none outline-none cursor-pointer mc-text-shadow"
|
||||
className="text-white/60 hover:text-white text-lg mx-2 border-none outline-none cursor-pointer"
|
||||
>
|
||||
✕
|
||||
</button>
|
||||
@@ -901,7 +896,9 @@ const WorkshopView = memo(function WorkshopView({
|
||||
: "text-[#A0A0A0] bg-black/30 border-[#444] hover:text-white hover:border-[#888]"
|
||||
}`}
|
||||
>
|
||||
{cat === "all" ? t("common.all").toUpperCase() : cat.toUpperCase()}
|
||||
{cat === "all"
|
||||
? t("common.all").toUpperCase()
|
||||
: cat.toUpperCase()}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
@@ -918,7 +915,9 @@ const WorkshopView = memo(function WorkshopView({
|
||||
: "text-[#A0A0A0] bg-black/30 border-[#444] hover:text-white hover:border-[#888]"
|
||||
}`}
|
||||
>
|
||||
{cat === "all" ? t("common.all").toUpperCase() : cat.toUpperCase()}
|
||||
{cat === "all"
|
||||
? t("common.all").toUpperCase()
|
||||
: cat.toUpperCase()}
|
||||
</button>
|
||||
))}
|
||||
</div>
|
||||
|
||||
+2
-1
@@ -453,7 +453,8 @@ body {
|
||||
image-rendering: pixelated;
|
||||
}
|
||||
|
||||
.mc-textinput-outer:focus-within {
|
||||
.mc-textinput-outer:focus-within,
|
||||
:focus > .mc-textinput-outer {
|
||||
border: 2px solid #ffff00;
|
||||
}
|
||||
|
||||
|
||||
+1
-6
@@ -1,11 +1,6 @@
|
||||
import { useEffect, useState, useMemo, useCallback, useRef } from "react";
|
||||
import { useTranslation } from "react-i18next";
|
||||
import {
|
||||
motion,
|
||||
AnimatePresence,
|
||||
MotionConfig,
|
||||
getDefaultTransition,
|
||||
} from "framer-motion";
|
||||
import { motion, AnimatePresence, MotionConfig } from "framer-motion";
|
||||
import "../css/App.css";
|
||||
import HomeView from "../components/views/HomeView";
|
||||
import SettingsView from "../components/views/SettingsView";
|
||||
|
||||
Reference in New Issue
Block a user