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