diff --git a/app/page.tsx b/app/page.tsx index cd4b7e1..d0487f7 100644 --- a/app/page.tsx +++ b/app/page.tsx @@ -4,7 +4,7 @@ import { useState, useEffect, useMemo } from 'react'; import { useInventoryStore } from '@/store/useInventoryStore'; import styles from '../styles/Home.module.css'; import { isNamedDLC } from '@/lib/utils'; -import { fetchCharacters, fetchItems, fetchOfferings, fetchCustomizations, fetchDLCs } from '@/lib/db'; +import { fetchCharacters, fetchItems, fetchOfferings, fetchCustomizations, fetchDLCs, fetchAddons, fetchPerks } from '@/lib/db'; export default function Home() { const store = useInventoryStore(); @@ -14,6 +14,8 @@ export default function Home() { const [itemsCount, setItemsCount] = useState(0); const [offeringsCount, setOfferingsCount] = useState(0); const [dlcsCount, setDlcsCount] = useState(0); + const [addonsCount, setAddonsCount] = useState(0); + const [perksCount, setPerksCount] = useState(0); const [importText, setImportText] = useState(''); @@ -23,13 +25,17 @@ export default function Home() { fetchItems(), fetchOfferings(), fetchCustomizations(), - fetchDLCs() - ]).then(([chars, items, offerings, customizations, dlcs]) => { + fetchDLCs(), + fetchAddons(), + fetchPerks() + ]).then(([chars, items, offerings, customizations, dlcs, addons, perks]) => { setCharCount(chars.length); setItemsCount(items.length); setOfferingsCount(offerings.length); setCustCount(customizations.length); setDlcsCount(dlcs.filter(isNamedDLC).length); + setAddonsCount(addons.length); + setPerksCount(perks.length); }); }, []); @@ -55,25 +61,33 @@ export default function Home() { unlockedCharacters: store.unlockedCharacters, unlockedCustomizations: store.unlockedCustomizations, unlockedDLCs: store.unlockedDLCs, + unlockedPerks: store.unlockedPerks, items: store.items, - offerings: store.offerings + offerings: store.offerings, + addons: store.addons }, null, 2); }; const handleImport = async () => { - const parsed = JSON.parse(importText); - store.importProfile(parsed); + try { + const parsed = JSON.parse(importText); + store.importProfile(parsed); + } catch (e) { + console.error("Invalid JSON", e); + } }; useEffect(() => { setImportText(getExportText()); - }, [store.unlockedCharacters, store.unlockedCustomizations, store.unlockedDLCs, store.items, store.offerings]); + }, [store.unlockedCharacters, store.unlockedCustomizations, store.unlockedDLCs, store.unlockedPerks, store.items, store.offerings, store.addons]); /* stats */ const unlockedItems = useMemo(() => Object.values(store.items).filter(qty => qty > 0).length, [store.items]); const unlockedOfferings = useMemo(() => Object.values(store.offerings).filter(qty => qty > 0).length, [store.offerings]); + const unlockedAddons = useMemo(() => Object.values(store.addons).filter(qty => qty > 0).length, [store.addons]); + const unlockedPerks = store.unlockedPerks.length; return (
@@ -85,27 +99,35 @@ export default function Home() {
Characters
-
{store.unlockedCharacters.length} / {charCount || '-'}
+
{store.unlockedCharacters.length} / {charCount || '-'}
Customizations
-
{store.unlockedCustomizations.length} / {custCount || '-'}
+
{store.unlockedCustomizations.length} / {custCount || '-'}
DLCs
-
{store.unlockedDLCs.length} / {dlcsCount || '-'}
+
{store.unlockedDLCs.length} / {dlcsCount || '-'}
Items
-
{unlockedItems} / {itemsCount || '-'}
+
{unlockedItems} / {itemsCount || '-'}
Offerings
-
{unlockedOfferings} / {offeringsCount || '-'}
+
{unlockedOfferings} / {offeringsCount || '-'}
+
+
+
Addons
+
{unlockedAddons} / {addonsCount || '-'}
+
+
+
Perks
+
{unlockedPerks} / {perksCount || '-'}
- {/* profile import export stuff */} + {/* Control panels */}

Profile Import / Export

diff --git a/styles/Home.module.css b/styles/Home.module.css index 332edb1..e07d782 100644 --- a/styles/Home.module.css +++ b/styles/Home.module.css @@ -29,11 +29,23 @@ .statsGrid { display: grid; - grid-template-columns: repeat(5, 1fr); + grid-template-columns: repeat(4, 1fr); gap: 1.5rem; margin-bottom: 3rem; } +@media (max-width: 1000px) { + .statsGrid { + grid-template-columns: repeat(3, 1fr); + } +} + +@media (max-width: 600px) { + .statsGrid { + grid-template-columns: repeat(2, 1fr); + } +} + .statCard { background: #0d0d0d; border: 1px solid #1a1a1a; @@ -64,17 +76,30 @@ line-height: 1; } +.statTotal { + font-size: 0.9rem; + color: #555555; +} + .panelGrid { display: grid; - grid-template-columns: 1fr; + grid-template-columns: 1fr 1.2fr; gap: 2rem; } +@media (max-width: 900px) { + .panelGrid { + grid-template-columns: 1fr; + } +} + .card { background: #0d0d0d; border: 1px solid #1a1a1a; border-top: 3px solid #630000; padding: 2rem; + display: flex; + flex-direction: column; } .cardTitle { @@ -83,12 +108,7 @@ color: #ffffff; margin: 0 0 1.5rem 0; letter-spacing: 0.05em; -} - -.formatBtnActive { - background: #a30000; - border-color: #ff0000; - color: #ffffff; + font-family: 'Oswald', sans-serif; } .textarea { @@ -149,26 +169,84 @@ color: #ffffff; } -.toast { - position: fixed; - bottom: 2rem; - right: 2rem; - background: #0d0d0d; - border: 1px solid #00ff66; - color: #00ff66; - padding: 1rem 1.5rem; - font-size: 0.8rem; - text-transform: uppercase; +.toggleRow { + display: flex; + align-items: center; + justify-content: space-between; + padding: 1rem 0; + border-bottom: 1px solid #1a1a1a; +} + +.toggleRow:last-child { + border-bottom: none; +} + +.toggleInfo { + display: flex; + flex-direction: column; + gap: 0.2rem; + padding-right: 1.5rem; +} + +.toggleLabel { + font-size: 0.85rem; font-weight: bold; - animation: slideIn 0.3s ease-out forwards; + text-transform: uppercase; + color: #ffffff; + letter-spacing: 0.05em; + font-family: 'Oswald', sans-serif; } -.toastError { - border-color: #ff0000; - color: #ff0000; +.toggleDesc { + font-size: 0.68rem; + color: #555555; + line-height: 1.3; } -@keyframes slideIn { - from { transform: translateY(20px); opacity: 0; } - to { transform: translateY(0); opacity: 1; } +.switch { + position: relative; + display: inline-block; + width: 48px; + height: 24px; + flex-shrink: 0; +} + +.switch input { + opacity: 0; + width: 0; + height: 0; +} + +.slider { + position: absolute; + cursor: pointer; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: #121212; + border: 1px solid #333333; + transition: 0.2s; +} + +.slider:before { + position: absolute; + content: ""; + height: 16px; + width: 16px; + left: 3px; + bottom: 3px; + background-color: #555555; + transition: 0.2s; +} + +input:checked + .slider { + background-color: #2b0000; + border-color: #a30000; +} + +input:checked + .slider:before { + transform: translateX(24px); + background-color: #a30000; + box-shadow: 0 0 8px rgba(163, 0, 0, 0.7); } \ No newline at end of file