import { useState } from “react”; const PACKS = [ { id: “A”, name: “Script Heavy”, emoji: “✍️”, minutes: 80, tasks: [“Script 4 videos — 20 min each”], color: “#FF6B35”, desc: “No camera needed. Just build the backlog.”, }, { id: “B”, name: “Edit + Script”, emoji: “✂️”, minutes: 100, tasks: [“Edit 1 video — 60 min”, “Script 2 videos — 40 min”], color: “#4ECDC4”, desc: “Balanced. Gets a video out and keeps pipeline moving.”, }, { id: “C”, name: “Edit + Record”, emoji: “🎬”, minutes: 85, tasks: [“Edit 1 video — 60 min”, “Record 5 videos — 25 min”], color: “#A855F7”, desc: “Use when scripts are ready and you can record.”, }, { id: “D”, name: “Full Production”, emoji: “🔥”, minutes: 100, tasks: [“Script 2 videos — 40 min”, “Record 4 videos — 20 min”, “Edit half a video — 40 min”], color: “#F59E0B”, desc: “High energy days only.”, }, { id: “E”, name: “Record Blitz”, emoji: “⚡”, minutes: 100, tasks: [“Record 12 videos batch — 60 min”, “Script 2 videos — 40 min”], color: “#EF4444”, desc: “Fri/Sat/Sun when family is out. Max output.”, }, ]; const DAY_RECS = { Monday: “A”, Tuesday: “A”, Wednesday: “B”, Thursday: “B”, Friday: “E”, Saturday: “E”, Sunday: “B”, }; const DAYS = [“Sunday”, “Monday”, “Tuesday”, “Wednesday”, “Thursday”, “Friday”, “Saturday”]; function getTodayKey() { return new Date().toISOString().split(“T”)[0]; } function getTodayName() { return DAYS[new Date().getDay()]; } function getLast7Days() { const days = []; for (let i = 6; i >= 0; i–) { const d = new Date(); d.setDate(d.getDate() - i); days.push(d.toISOString().split(“T”)[0]); } return days; } export default function App() { const [history, setHistory] = useState(() => { try { return JSON.parse(localStorage.getItem(“yasser_packs”) || “{}”); } catch { return {}; } }); const [view, setView] = useState(“today”); const todayKey = getTodayKey(); const todayName = getTodayName(); const todayData = history[todayKey] || {}; const recommendedId = DAY_RECS[todayName]; const selectedId = todayData.packId; const isCompleted = todayData.completed === true; const isFailed = todayData.completed === false && todayData.packId; function save(updates) { const next = { …history, [todayKey]: { …todayData, …updates } }; setHistory(next); try { localStorage.setItem(“yasser_packs”, JSON.stringify(next)); } catch {} } function selectPack(id) { if (isCompleted || isFailed) return; save({ packId: id }); } function markDone(success) { save({ completed: success }); } const streak = (() => { let s = 0; const d = new Date(); for (let i = 0; i < 365; i++) { const k = d.toISOString().split(“T”)[0]; if (history[k]?.completed === true) s++; else break; d.setDate(d.getDate() - 1); } return s; })(); const last7 = getLast7Days(); const selectedPack = PACKS.find(p => p.id === selectedId); const recommendedPack = PACKS.find(p => p.id === recommendedId); return ( <div style={{ minHeight: “100vh”, background: “#0a0a0a”, color: “#f0f0f0”, fontFamily: “‘DM Mono’, ‘Courier New’, monospace”, padding: “24px 16px”, maxWidth: 480, margin: “0 auto”, }}> ``` {/* Header */} <div style={{ marginBottom: 32 }}> <div style={{ fontSize: 11, letterSpacing: 3, color: "#666", textTransform: "uppercase", marginBottom: 4 }}> Content Tracker </div> <div style={{ fontSize: 28, fontWeight: 700, letterSpacing: -1 }}> {todayName} </div> <div style={{ fontSize: 13, color: "#555", marginTop: 2 }}>{todayKey}</div> {streak > 0 && ( <div style={{ display: "inline-block", marginTop: 10, background: "#1a1a1a", border: "1px solid #333", borderRadius: 6, padding: "4px 12px", fontSize: 13, color: "#f59e0b", }}> 🔥 {streak} day streak </div> )} </div> {/* Nav */} <div style={{ display: "flex", gap: 8, marginBottom: 28 }}> {["today", "log"].map(v => ( <button key={v} onClick={() => setView(v)} style={{ background: view === v ? "#f0f0f0" : "#1a1a1a", color: view === v ? "#0a0a0a" : "#666", border: "1px solid #333", borderRadius: 6, padding: "6px 16px", fontSize: 12, letterSpacing: 1, textTransform: "uppercase", cursor: "pointer", fontFamily: "inherit", }}> {v === "today" ? "Today" : "History"} </button> ))} </div> {view === "today" && ( <> {!selectedId && ( <div style={{ background: "#111", border: `1px solid ${recommendedPack.color}44`, borderLeft: `3px solid ${recommendedPack.color}`, borderRadius: 8, padding: "12px 16px", marginBottom: 20, fontSize: 13, }}> <span style={{ color: "#666" }}>Recommended for {todayName}: </span> <span style={{ color: recommendedPack.color, fontWeight: 700 }}> Pack {recommendedPack.id} — {recommendedPack.name} </span> </div> )} {!isCompleted && !isFailed && ( <> <div style={{ fontSize: 11, letterSpacing: 2, color: "#555", textTransform: "uppercase", marginBottom: 12 }}> {selectedId ? "Selected pack — tap to change" : "Choose your pack"} </div> <div style={{ display: "flex", flexDirection: "column", gap: 10, marginBottom: 28 }}> {PACKS.map(pack => { const isSelected = selectedId === pack.id; const isRec = recommendedId === pack.id; return ( <div key={pack.id} onClick={() => selectPack(pack.id)} style={{ background: isSelected ? `${pack.color}18` : "#111", border: isSelected ? `1.5px solid ${pack.color}` : "1.5px solid #222", borderRadius: 10, padding: "14px 16px", cursor: "pointer", position: "relative", }} > {isRec && ( <div style={{ position: "absolute", top: 10, right: 12, fontSize: 9, letterSpacing: 1.5, textTransform: "uppercase", color: pack.color, background: `${pack.color}22`, padding: "2px 7px", borderRadius: 4, }}> Rec </div> )} <div style={{ display: "flex", alignItems: "center", gap: 10, marginBottom: 6 }}> <span style={{ fontSize: 18 }}>{pack.emoji}</span> <span style={{ fontWeight: 700, fontSize: 14 }}>Pack {pack.id}</span> <span style={{ color: "#555", fontSize: 12 }}>— {pack.name}</span> <span style={{ marginLeft: "auto", color: pack.color, fontSize: 13, fontWeight: 700, paddingRight: isRec ? 44 : 0 }}> {pack.minutes}m </span> </div> <div style={{ paddingLeft: 28 }}> {pack.tasks.map((t, i) => ( <div key={i} style={{ fontSize: 12, color: "#666", marginBottom: 2 }}>· {t}</div> ))} <div style={{ fontSize: 11, color: "#444", marginTop: 4 }}>{pack.desc}</div> </div> </div> ); })} </div> </> )} {selectedId && !isCompleted && !isFailed && ( <div style={{ background: `${selectedPack.color}10`, border: `1px solid ${selectedPack.color}55`, borderRadius: 10, padding: 20, marginBottom: 16, }}> <div style={{ fontSize: 13, color: "#888", marginBottom: 6 }}>Did you complete it?</div> <div style={{ fontSize: 18, fontWeight: 700, color: selectedPack.color, marginBottom: 16 }}> {selectedPack.emoji} Pack {selectedPack.id} — {selectedPack.name} </div> <div style={{ display: "flex", gap: 10 }}> <button onClick={() => markDone(true)} style={{ flex: 1, background: "#16a34a", color: "#fff", border: "none", borderRadius: 8, padding: "13px", fontSize: 14, fontWeight: 700, cursor: "pointer", fontFamily: "inherit", }}> ✓ Done </button> <button onClick={() => markDone(false)} style={{ flex: 1, background: "#1a1a1a", color: "#666", border: "1px solid #333", borderRadius: 8, padding: "13px", fontSize: 14, cursor: "pointer", fontFamily: "inherit", }}> ✗ Didn't finish </button> </div> </div> )} {isCompleted && ( <div style={{ background: "#16a34a18", border: "1px solid #16a34a55", borderRadius: 10, padding: 28, textAlign: "center", }}> <div style={{ fontSize: 40, marginBottom: 10 }}>✅</div> <div style={{ fontSize: 18, fontWeight: 700, color: "#16a34a", marginBottom: 6 }}> Pack {selectedId} complete </div> <div style={{ fontSize: 13, color: "#555" }}> {streak > 1 ? `${streak} days in a row. Keep going.` : "Day 1. Let's go."} </div> </div> )} {isFailed && ( <div style={{ background: "#7f1d1d18", border: "1px solid #ef444455", borderRadius: 10, padding: 28, textAlign: "center", }}> <div style={{ fontSize: 40, marginBottom: 10 }}>❌</div> <div style={{ fontSize: 18, fontWeight: 700, color: "#ef4444", marginBottom: 6 }}> Pack {selectedId} — not completed </div> <div style={{ fontSize: 13, color: "#555" }}>Tomorrow is another shot. Don't miss two in a row.</div> </div> )} </> )} {view === "log" && ( <> <div style={{ fontSize: 11, letterSpacing: 2, color: "#555", textTransform: "uppercase", marginBottom: 16 }}> Last 7 Days </div> <div style={{ display: "flex", flexDirection: "column", gap: 8 }}> {last7.map(dateKey => { const d = history[dateKey]; const dayName = DAYS[new Date(dateKey + "T12:00:00").getDay()]; const pack = PACKS.find(p => p.id === d?.packId); const isToday = dateKey === todayKey; return ( <div key={dateKey} style={{ background: "#111", border: `1px solid ${isToday ? "#444" : "#1a1a1a"}`, borderRadius: 8, padding: "12px 16px", display: "flex", alignItems: "center", justifyContent: "space-between", }}> <div> <div style={{ fontSize: 13, fontWeight: 600, color: isToday ? "#f0f0f0" : "#888" }}> {dayName} {isToday && <span style={{ color: "#555", fontSize: 11 }}>(today)</span>} </div> <div style={{ fontSize: 11, color: "#444", marginTop: 2 }}>{dateKey}</div> </div> <div style={{ textAlign: "right" }}> {!d?.packId ? ( <span style={{ fontSize: 12, color: "#333" }}>—</span> ) : ( <> <div style={{ fontSize: 12, color: pack?.color || "#888", marginBottom: 2 }}> Pack {d.packId} — {pack?.name} </div> <div style={{ fontSize: 14 }}> {d.completed === true ? "✅" : d.completed === false ? "❌" : "⏳"} </div> </> )} </div> </div> ); })} </div> <div style={{ marginTop: 20, background: "#111", border: "1px solid #222", borderRadius: 8, padding: "16px", }}> <div style={{ fontSize: 11, letterSpacing: 2, color: "#555", textTransform: "uppercase", marginBottom: 12 }}> This Week </div> <div style={{ display: "flex", gap: 24 }}> <div> <div style={{ fontSize: 24, fontWeight: 700, color: "#16a34a" }}> {last7.filter(k => history[k]?.completed === true).length} </div> <div style={{ fontSize: 11, color: "#555" }}>Completed</div> </div> <div> <div style={{ fontSize: 24, fontWeight: 700, color: "#ef4444" }}> {last7.filter(k => history[k]?.completed === false).length} </div> <div style={{ fontSize: 11, color: "#555" }}>Missed</div> </div> <div> <div style={{ fontSize: 24, fontWeight: 700, color: "#f59e0b" }}> {streak} </div> <div style={{ fontSize: 11, color: "#555" }}>Streak</div> </div> </div> </div> </> )} </div> ``` ); }
Now I'll implement your content tracker app. I'll update the layout for the dark theme and DM Mono font, update the globals.css with a dark color scheme, and create the main page component.
Your content tracker is now live! I've converted your React component to a proper Next.js app with:
The app tracks your daily content packs with streak counting, history view, and persists everything to localStorage.
You can send messages while the preview loads