// NEKO — Site core: constants, theme, shared tweaks, toast, navbar, footer // Loads after React/Babel + tweaks-panel.jsx. Exports to window. // One-time localStorage migration for the Troya → Neko rename. Any value still // stored under an old `troya-*` key is copied to its new `neko-*` key (without // clobbering newer data) and the stale key is removed. Idempotent — no-ops once // migrated, so it is safe to run on every load. Keeps saved cart/tweaks/theme/ // joined-events intact across the rename; Midnight-only behaviour is unaffected // because the theme value is still normalised below. (function nekoMigrateStorage() { try { var map = { "troya-theme": "neko-theme", "troya-tweaks": "neko-tweaks", "troya-cart-v1": "neko-cart-v1", "troya-ev-joined": "neko-ev-joined", }; for (var oldKey in map) { var oldVal = localStorage.getItem(oldKey); if (oldVal === null) continue; if (localStorage.getItem(map[oldKey]) === null) localStorage.setItem(map[oldKey], oldVal); localStorage.removeItem(oldKey); } } catch (e) {} })(); const NEKO = { ip: "mc.nekocraft.net", version: "1.13 – 26.1.2", discord: "discord.gg/Nm4uYfpaPn", online: 184, }; // --------------------------------------------------------------- // Theme — Midnight is the ONLY active site theme for now. The slider sun/moon // toggle is retired from public chrome; Sunlight lives only in the design // system as a passive/future reference. Lock forces Midnight and ignores any // previously-saved "sunlight" preference, so a refresh never resurfaces it. // --------------------------------------------------------------- const NEKO_THEME_LOCK = "midnight"; // null = switchable; "midnight" = locked function useNekoTheme() { const [theme, setThemeRaw] = React.useState(() => { if (NEKO_THEME_LOCK) return NEKO_THEME_LOCK; // ignore any saved preference for now try { return localStorage.getItem("neko-theme") || "midnight"; } catch (e) { return "midnight"; } }); React.useEffect(() => { document.body.classList.remove("theme-sunlight", "theme-midnight"); document.body.classList.add("theme-" + theme); // When locked, normalise any stale stored value back to the locked theme // so nothing accidentally reactivates Sunlight on the next visit. try { localStorage.setItem("neko-theme", NEKO_THEME_LOCK || theme); } catch (e) {} }, [theme]); const setTheme = (t) => { if (NEKO_THEME_LOCK) return; setThemeRaw(t); }; return [theme, setTheme]; } // --------------------------------------------------------------- // Shared design tweaks — persisted in localStorage (cross-page) // --------------------------------------------------------------- const NEKO_TWEAK_DEFAULTS = { navVariant: "B", // A: Saray Camı, B: Kale Burcu (aktif), C: Yüzen Adalar cardVariant: "auto", // auto: kategoriye göre A/B/C — A/B/C: tek tip taslak varyant heroVariant: "1", // 1: Sinematik Merkez (aktif), 2: Bölünmüş Çerçeve headingFont: "minecraft", // minecraft | pixelify glassBlur: 18, // px — liquid-glass varsayılanı (katmanlı cam hissi geri yüklendi) decor: "2", // 0 yok, 1 az, 2 normal }; // One-time migration: the active site now uses Hero 1 + Navbar B and // category-based product cards ("auto"). Older saved tweak values are // re-pointed once; the variants themselves remain selectable as drafts. // v4: glassBlur'u 0'dan 18'e taşı (liquid-glass geri yüklendi); tema kilidi // Midnight. Eski kayıtlar bir kez yeniden eşlenir; varyantlar taslak kalır. const NEKO_TWEAKS_VERSION = 4; function nekoReadTweaks() { let saved = {}; try { saved = JSON.parse(localStorage.getItem("neko-tweaks") || "{}"); } catch (e) { saved = {}; } if (saved.__v !== NEKO_TWEAKS_VERSION) { saved = { ...saved, navVariant: "B", heroVariant: "1", cardVariant: "auto", glassBlur: 18, __v: NEKO_TWEAKS_VERSION }; try { localStorage.setItem("neko-tweaks", JSON.stringify(saved)); } catch (e) {} } return { ...NEKO_TWEAK_DEFAULTS, ...saved }; } function useNekoTweaks() { const [tw, setTwState] = React.useState(nekoReadTweaks); const setTw = (key, val) => { setTwState((p) => { const next = { ...p, [key]: val, __v: NEKO_TWEAKS_VERSION }; try { localStorage.setItem("neko-tweaks", JSON.stringify(next)); } catch (e) {} return next; }); }; // Side effects: fonts, glass intensity, decor density React.useEffect(() => { const root = document.documentElement; root.style.setProperty("--font-hero", tw.headingFont === "minecraft" ? '"MinecraftTTF", "Pixelify Sans", monospace' : '"Pixelify Sans", monospace'); root.style.setProperty("--glass-blur", "blur(" + tw.glassBlur + "px) saturate(150%)"); root.style.setProperty("--frost-blur", "blur(" + Math.max(6, Math.round(tw.glassBlur * 0.6)) + "px) saturate(135%)"); document.body.classList.remove("decor-0", "decor-1", "decor-2"); document.body.classList.add("decor-" + tw.decor); // Bulanıklık düşükken cam yüzeyler okunabilirliğini kenar/parlama/opaklıkla korur document.body.classList.toggle("glass-flat", (tw.glassBlur || 0) < 6); }, [tw]); return [tw, setTw]; } // --------------------------------------------------------------- // Toast // --------------------------------------------------------------- function nekoToast(msg) { window.dispatchEvent(new CustomEvent("neko:toast", { detail: msg })); } function ToastHost() { const [msg, setMsg] = React.useState(null); React.useEffect(() => { let t; const on = (e) => { setMsg(e.detail); clearTimeout(t); t = setTimeout(() => setMsg(null), 2200); }; window.addEventListener("neko:toast", on); return () => { window.removeEventListener("neko:toast", on); clearTimeout(t); }; }, []); if (!msg) return null; return (
{msg}
); } // --------------------------------------------------------------- // Clipboard helper + Copy-IP button (toast + inline feedback) // --------------------------------------------------------------- function nekoCopy(text) { try { if (navigator.clipboard && navigator.clipboard.writeText) { return navigator.clipboard.writeText(text).then(() => true, () => false); } } catch (e) {} try { const ta = document.createElement("textarea"); ta.value = text; ta.style.position = "fixed"; ta.style.opacity = "0"; document.body.appendChild(ta); ta.select(); const ok = document.execCommand("copy"); document.body.removeChild(ta); return Promise.resolve(ok); } catch (e) { return Promise.resolve(false); } } function CopyIpButton({ small, ghost }) { const [copied, setCopied] = React.useState(false); const onCopy = () => { nekoCopy(NEKO.ip).then(() => { setCopied(true); nekoToast("Sunucu adresi kopyalandı: " + NEKO.ip); setTimeout(() => setCopied(false), 1900); }); }; return ( ); } // --------------------------------------------------------------- // Theme toggle (CANONICAL sliding pixel sun/moon) — recovered from the // design system. Slides between Sunlight (sun, left) and Midnight (moon, // right); the knob carries the active celestial body. Persists via // useNekoTheme. The old 2-square segment version is archived in the DS. // --------------------------------------------------------------- function ThemeToggle({ theme, setTheme, small }) { const next = theme === "midnight" ? "sunlight" : "midnight"; return ( ); } // --------------------------------------------------------------- // Navbar — variants A/B/C, active page, mobile menu, optional cart // --------------------------------------------------------------- const NEKO_NAV = [ { id: "home", label: "Anasayfa", href: "Anasayfa.html" }, { id: "store", label: "Mağaza", href: "Magaza.html" }, { id: "pazar", label: "Pazar", href: "Pazar.html" }, { id: "duyurular", label: "Duyurular", href: "Duyurular.html" }, // sayfa başlığı: "Duyurular & Güncellemeler" { id: "credits", label: "Krediler", href: "Krediler.html" }, { id: "support", label: "Destek", href: "Destek.html" }, ]; function NavLinksRow({ active }) { return ( ); } function NavActions({ theme, setTheme, cartCount, onCartOpen, active }) { return (
{/* Online player counter removed from navbar (kept elsewhere on site) */} {/* Tema anahtarı kaldırıldı — site şimdilik yalnız Midnight; Sunlight tasarım sisteminde pasif/gelecek referans olarak duruyor */} {/* Prototip aşamasında herkese görünür — sayfa başlığı: "Admin Yönetim Paneli" */} Admin {onCartOpen && ( )} Giriş Yap
); } function SiteNavbar({ active, theme, setTheme, variant, cartCount, onCartOpen }) { const [open, setOpen] = React.useState(false); const v = variant || "A"; const actions = ; const burger = ( ); const mobileMenu = (
{NEKO_NAV.map((n) => ( {n.label} ))} Admin Paneli Giriş Yap
); if (v === "B") { return (
NEKO
{actions}{burger}
{mobileMenu}
); } if (v === "C") { return (
NEKO
{actions}{burger}
{mobileMenu}
); } // Variant A — Saray Camı (default) return (
{theme === "midnight" ? : } NEKO
{actions}{burger}
{mobileMenu}
); } // --------------------------------------------------------------- // Section helpers // --------------------------------------------------------------- function SectionHead({ title, sub, cta }) { return (

{title}

{sub ?

{sub}

: null}
{cta ?
{cta}
: null}
); } function PixelDivider() { return ( ); } // --------------------------------------------------------------- // Status strip (hero) // --------------------------------------------------------------- function StatusStrip() { const cell = { display: "flex", alignItems: "center", gap: 8, fontFamily: "var(--font-body)", fontSize: 13, whiteSpace: "nowrap" }; const div = ; return (
{NEKO.online} oyuncu çevrimiçi {div} {NEKO.ip} {div} Sürüm {NEKO.version} {div} e.preventDefault()} style={{ ...cell, color: "var(--c-accent)", fontWeight: 700, textDecoration: "none" }}>Discord'a Katıl →
); } // --------------------------------------------------------------- // Footer // --------------------------------------------------------------- function SiteFooter() { return ( ); } // --------------------------------------------------------------- // Tweaks panel (prototype-only) // --------------------------------------------------------------- function NekoTweaks({ theme, setTheme, tw, setTw, page }) { return ( {/* Tema seçimi kaldırıldı — site Midnight-only; Sunlight yalnız tasarım sisteminde pasif referans */} setTw("headingFont", v)} /> setTw("glassBlur", v)} /> setTw("decor", v)} /> setTw("navVariant", v)} /> {page === "home" && setTw("heroVariant", v)} />} {(page === "home" || page === "store") && setTw("cardVariant", v)} />} ); } Object.assign(window, { NEKO, NEKO_NAV, useNekoTheme, useNekoTweaks, nekoToast, nekoCopy, ToastHost, CopyIpButton, ThemeToggle, SiteNavbar, SectionHead, PixelDivider, StatusStrip, SiteFooter, NekoTweaks, });