diff --git a/index.html b/index.html new file mode 100644 index 0000000..f01f050 --- /dev/null +++ b/index.html @@ -0,0 +1,448 @@ +import { useState, useRef, useCallback } from "react"; + +const CARD_TYPES = ["Creature", "Instant", "Sorcery", "Enchantment", "Artifact", "Land", "Planeswalker", "Battle"]; +const COLORS = [ + { id: "W", label: "White", symbol: "โ˜€", bg: "#f9f6d5", border: "#c8b87a", text: "#333" }, + { id: "U", label: "Blue", symbol: "๐Ÿ’ง", bg: "#c6d9e8", border: "#3a6b9c", text: "#fff" }, + { id: "B", label: "Black", symbol: "๐Ÿ’€", bg: "#1a1a1a", border: "#5a4a6e", text: "#d0c8e0" }, + { id: "R", label: "Red", symbol: "๐Ÿ”ฅ", bg: "#e87040", border: "#8b2500", text: "#fff" }, + { id: "G", label: "Green", symbol: "๐ŸŒฒ", bg: "#3a7a48", border: "#1a4025", text: "#d4f5d0" }, + { id: "C", label: "Colorless", symbol: "โ—‡", bg: "#c0bdb5", border: "#7a7068", text: "#333" }, + { id: "M", label: "Multi", symbol: "โ˜…", bg: "linear-gradient(135deg,#f9f6d5,#c6d9e8,#1a1a1a,#e87040,#3a7a48)", border: "#b8960c", text: "#fff" }, +]; + +const RARITY_COLORS = { Common: "#aaa", Uncommon: "#a0c0d0", Rare: "#d4af37", "Mythic Rare": "#e07020" }; + +const DEFAULT_CARD = { + name: "Blazing Champion", + manaCost: "{2}{R}{R}", + type: "Creature", + subtype: "Human Warrior", + color: "R", + rarity: "Rare", + power: "4", + toughness: "3", + rulesText: "Haste\nWhen Blazing Champion enters the battlefield, it deals 2 damage to any target.", + flavorText: "\"No retreat. No mercy. Only fire.\"", + artist: "Proxy Artist", + setSymbol: "โ˜…", + loyalty: "", +}; + +function CardPreview({ card, imageUrl }) { + const colorObj = COLORS.find(c => c.id === card.color) || COLORS[5]; + const isMulti = card.color === "M"; + const isLand = card.type === "Land"; + const isPW = card.type === "Planeswalker"; + + const frameBg = isMulti + ? "linear-gradient(160deg,#f9f6d5 0%,#c6d9e8 25%,#1a1a1a 50%,#e87040 75%,#3a7a48 100%)" + : colorObj.bg; + + const rarityColor = RARITY_COLORS[card.rarity] || "#aaa"; + + return ( +
+ {/* Header */} +
+
+ {card.name || "Card Name"} +
+
+ {card.manaCost || ""} +
+
+ + {/* Art Frame */} +
+ {imageUrl ? ( + card art + ) : ( +
+ {colorObj.symbol} +
+ )} + {/* Set & rarity */} +
+ {card.setSymbol || "โ˜…"} {card.rarity ? card.rarity[0] : ""} +
+
+ + {/* Type Line */} +
+ {[card.type, card.subtype].filter(Boolean).join(" โ€” ") || "Type"} + {card.setSymbol || "โ˜…"} +
+ + {/* Text Box */} +
+
+ {card.rulesText || ""} +
+ {card.flavorText && ( +
+ {card.flavorText} +
+ )} +
+ + {/* Footer */} +
+ โœฆ {card.artist || "Unknown"} + {(card.type === "Creature" || card.type === "Battle") && ( +
+ {card.power}/{card.toughness} +
+ )} + {isPW && card.loyalty && ( +
+ {card.loyalty} +
+ )} +
+
+ ); +} + +function Field({ label, children }) { + return ( +
+ + {children} +
+ ); +} + +const inputStyle = { + background: "#1e1a14", + border: "1px solid #3a3020", + borderRadius: 6, + color: "#e8dfc8", + padding: "7px 10px", + fontSize: 13, + fontFamily: "inherit", + outline: "none", + width: "100%", + boxSizing: "border-box", + transition: "border-color 0.2s", +}; + +export default function App() { + const [card, setCard] = useState(DEFAULT_CARD); + const [imageUrl, setImageUrl] = useState(""); + const [imageInput, setImageInput] = useState(""); + const [tab, setTab] = useState("basic"); + const previewRef = useRef(); + const fileInputRef = useRef(); + + const update = useCallback((field, val) => setCard(c => ({ ...c, [field]: val })), []); + + const handleImageFile = (e) => { + const file = e.target.files?.[0]; + if (!file) return; + const reader = new FileReader(); + reader.onload = (ev) => setImageUrl(ev.target.result); + reader.readAsDataURL(file); + }; + + const handleImageUrl = () => { + setImageUrl(imageInput.trim()); + }; + + const handlePrint = () => window.print(); + + const isPW = card.type === "Planeswalker"; + const isCreature = card.type === "Creature" || card.type === "Battle"; + + return ( +
+ {/* Header */} +
+
๐Ÿƒ
+
+
MTG Proxy Maker
+
Design ยท Print ยท Play
+
+ +
+ +
+ {/* Editor Panel */} +
+ {/* Tabs */} +
+ {["basic", "art", "stats"].map(t => ( + + ))} +
+ +
+ {tab === "basic" && <> + + update("name", e.target.value)} placeholder="e.g. Blazing Champion" /> + + + update("manaCost", e.target.value)} placeholder="{2}{R}{R}" /> + +
+ + + + + update("subtype", e.target.value)} placeholder="e.g. Wizard" /> + +
+ +
+ {COLORS.map(c => ( + + ))} +
+
+ + + + +