mirror of
https://github.com/LCE-Hub/LCE-Emerald-Launcher.git
synced 2026-09-24 17:11:00 +00:00
feat(ui): use LCE textinput
This commit is contained in:
@@ -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,12 +669,14 @@ 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]" />
|
||||
@@ -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,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"
|
||||
/>
|
||||
<input
|
||||
type="text"
|
||||
value={argbToHex(c.color)}
|
||||
onChange={(e) => {
|
||||
const s = e.target.value.replace(/[^0-9A-Fa-f]/g, '');
|
||||
if (s.length <= 8) {
|
||||
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}
|
||||
/>
|
||||
<div className="mc-textinput-outer w-24">
|
||||
<input
|
||||
type="text"
|
||||
value={argbToHex(c.color)}
|
||||
onChange={(e) => {
|
||||
const s = e.target.value.replace(/[^0-9A-Fa-f]/g, '');
|
||||
if (s.length <= 8) {
|
||||
const parsed = parseInt(s, 16);
|
||||
if (!isNaN(parsed)) handleUpdateColor(c.originalIdx, "color", parsed >>> 0);
|
||||
}
|
||||
}}
|
||||
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">
|
||||
@@ -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,9 +303,10 @@ 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">
|
||||
@@ -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,9 +332,10 @@ 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">
|
||||
@@ -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,9 +361,10 @@ 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">
|
||||
|
||||
@@ -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,12 +291,14 @@ 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,12 +252,14 @@ 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,13 +865,15 @@ 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">
|
||||
@@ -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,8 +896,9 @@ 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>
|
||||
@@ -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,8 +1000,9 @@ 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>
|
||||
@@ -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,8 +1029,9 @@ 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>
|
||||
@@ -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,8 +1056,9 @@ 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>
|
||||
@@ -1057,13 +1067,15 @@ 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">
|
||||
|
||||
@@ -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-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>
|
||||
|
||||
@@ -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,14 +868,16 @@ 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" && (
|
||||
@@ -1175,13 +1181,15 @@ 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
|
||||
|
||||
@@ -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>
|
||||
<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"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
<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="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>
|
||||
<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"
|
||||
style={{ imageRendering: "pixelated" }}
|
||||
/>
|
||||
<div className="mc-textinput-outer">
|
||||
<input
|
||||
autoFocus
|
||||
value={prefixInput}
|
||||
onChange={(e) => setPrefixInput(e.target.value)}
|
||||
placeholder="e.g. gamemoderun"
|
||||
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,8 +652,9 @@ 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}>
|
||||
|
||||
@@ -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,16 +712,20 @@ const SkinsView = memo(function SkinsView() {
|
||||
>
|
||||
<HeadPreview src={skin.url} />
|
||||
</div>
|
||||
<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" : ""}`}
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
spellCheck={false}
|
||||
readOnly={isDefaultSkin(skin.id)}
|
||||
/>
|
||||
<div className="w-full">
|
||||
<input
|
||||
type="text"
|
||||
value={skin.name}
|
||||
maxLength={16}
|
||||
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,18 +787,20 @@ const SkinsView = memo(function SkinsView() {
|
||||
>
|
||||
<CapePreview src={cape.url} />
|
||||
</div>
|
||||
<input
|
||||
type="text"
|
||||
value={cape.name}
|
||||
maxLength={16}
|
||||
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()}
|
||||
spellCheck={false}
|
||||
readOnly={isDefaultCape(cape.id)}
|
||||
/>
|
||||
<div className="mc-textinput-outer w-full">
|
||||
<input
|
||||
type="text"
|
||||
value={cape.name}
|
||||
maxLength={16}
|
||||
onChange={(e) =>
|
||||
handleCapeNameChange(cape.id, e.target.value)
|
||||
}
|
||||
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,16 +906,18 @@ const SkinsView = memo(function SkinsView() {
|
||||
</div>
|
||||
) : importMode === "username" ? (
|
||||
<div className="flex flex-col gap-4 w-full px-4 mb-2">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t("skins.minecraftUsername")}
|
||||
value={importUsername}
|
||||
onChange={(e) => setImportUsername(e.target.value)}
|
||||
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]"}`}
|
||||
/>
|
||||
<div className="mc-textinput-outer w-full">
|
||||
<input
|
||||
type="text"
|
||||
placeholder={t("skins.minecraftUsername")}
|
||||
value={importUsername}
|
||||
onChange={(e) => setImportUsername(e.target.value)}
|
||||
onFocus={() => setModalFocusIndex(0)}
|
||||
autoFocus
|
||||
spellCheck={false}
|
||||
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,13 +218,15 @@ 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 => (
|
||||
|
||||
@@ -843,46 +843,41 @@ 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",
|
||||
}}
|
||||
>
|
||||
<input
|
||||
ref={searchRef}
|
||||
type="text"
|
||||
value={search}
|
||||
onChange={(e) => {
|
||||
setSearch(e.target.value);
|
||||
setFocusedIdx(null);
|
||||
}}
|
||||
placeholder={
|
||||
isInstalledTab
|
||||
? t("workshop.filterInstalled")
|
||||
: isVersionTab
|
||||
? t("workshop.filterVersions")
|
||||
: isPluginTab
|
||||
? t("workshop.filterPlugins")
|
||||
: activeTab === "Server Plugins"
|
||||
<div className="flex items-center flex-1 h-12 px-4 rounded">
|
||||
<div className="mc-textinput-outer flex-1">
|
||||
<input
|
||||
ref={searchRef}
|
||||
type="text"
|
||||
value={search}
|
||||
onChange={(e) => {
|
||||
setSearch(e.target.value);
|
||||
setFocusedIdx(null);
|
||||
}}
|
||||
placeholder={
|
||||
isInstalledTab
|
||||
? t("workshop.filterInstalled")
|
||||
: isVersionTab
|
||||
? t("workshop.filterVersions")
|
||||
: isPluginTab
|
||||
? t("workshop.filterPlugins")
|
||||
: activeTab === "Server"
|
||||
? t("workshop.filterServers")
|
||||
: t("workshop.enterKeywords")
|
||||
}
|
||||
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"
|
||||
/>
|
||||
: activeTab === "Server Plugins"
|
||||
? t("workshop.filterPlugins")
|
||||
: activeTab === "Server"
|
||||
? t("workshop.filterServers")
|
||||
: t("workshop.enterKeywords")
|
||||
}
|
||||
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 && (
|
||||
<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>
|
||||
|
||||
Reference in New Issue
Block a user