PromptBase
Upgrade
Close icon
General
Home
Marketplace
Create
Hire
Login
Chat
Sell
Explore

Prompt Details

Model
(gemini-3.1-pro)
Token size
3,853
Example input
[5th Grade]: 5th Grade [Spotting Fake News in Viral Posts]: Spotting Fake News in Viral Posts [Media Literacy]: Media Literacy [Evaluate source credibility and identify misleading claims]: Evaluate source credibility and identify misleading claims [Mixed reading levels, high social media exposure, 40 minute classroom activity]: Mixed reading levels, high social media exposure, 40 minute classroom activity
Example output
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>QuestLoom: Spotting Fake News</title> <style> /* CSS Variables for Premium 5th Grade Theme */ :root { --primary: #4F46E5; /* Indigo */ --primary-hover: #4338CA; --primary-light: #E0E7FF; --secondary: #10B981; /* Emerald */ --secondary-hover: #059669; --secondary-light: #D1FAE5; --accent: #F59E0B; /* Amber */ --danger: #EF4444; --bg-color: #F3F4F6; --surface: #FFFFFF; --text-main: #1F2937; --text-light: #6B7280; --border: #E5E7EB; --radius-md: 8px; --radius-lg: 12px; --radius-xl: 16px; --shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05); --shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06); --shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05); --font-main: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; --transition: all 0.2s ease-in-out; } /* Reset & Base */ * { box-sizing: border-box; margin: 0; padding: 0; } body { font-family: var(--font-main); background-color: var(--bg-color); color: var(--text-main); line-height: 1.6; display: flex; height: 100vh; overflow: hidden; } h1, h2, h3, h4 { line-height: 1.2; color: var(--text-main); } button { cursor: pointer; font-family: inherit; border: none; outline: none; transition: var(--transition); } input, textarea, select { font-family: inherit; padding: 0.75rem; border: 1px solid var(--border); border-radius: var(--radius-md); width: 100%; transition: var(--transition); } input:focus, textarea:focus, select:focus { border-color: var(--primary); box-shadow: 0 0 0 3px var(--primary-light); } textarea { resize: vertical; min-height: 100px; } /* Layout */ .sidebar { width: 280px; background-color: var(--surface); border-right: 1px solid var(--border); display: flex; flex-direction: column; z-index: 10; } .sidebar-header { padding: 1.5rem; border-bottom: 1px solid var(--border); background-color: var(--primary); color: white; } .sidebar-header h1 { font-size: 1.25rem; font-weight: bold; margin-bottom: 0.5rem; } .badges { display: flex; gap: 0.5rem; flex-wrap: wrap; } .badge { background: rgba(255,255,255,0.2); font-size: 0.75rem; padding: 0.25rem 0.5rem; border-radius: 999px; font-weight: 500; } .nav-links { flex: 1; overflow-y: auto; padding: 1rem 0; } .nav-link { display: flex; align-items: center; padding: 0.75rem 1.5rem; color: var(--text-light); text-decoration: none; font-weight: 500; transition: var(--transition); width: 100%; text-align: left; background: none; } .nav-link:hover { background-color: var(--bg-color); color: var(--primary); } .nav-link.active { background-color: var(--primary-light); color: var(--primary); border-right: 4px solid var(--primary); } .nav-icon { margin-right: 0.75rem; font-size: 1.25rem; } .mode-toggle { padding: 1rem; border-top: 1px solid var(--border); display: flex; justify-content: space-between; align-items: center; background: var(--surface); } .switch { position: relative; display: inline-block; width: 44px; height: 24px; } .switch input { opacity: 0; width: 0; height: 0; } .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; transition: .4s; border-radius: 34px; } .slider:before { position: absolute; content: ""; height: 18px; width: 18px; left: 3px; bottom: 3px; background-color: white; transition: .4s; border-radius: 50%; } input:checked + .slider { background-color: var(--primary); } input:checked + .slider:before { transform: translateX(20px); } .main-content { flex: 1; overflow-y: auto; padding: 2rem; scroll-behavior: smooth; position: relative; } .view-section { display: none; max-width: 900px; margin: 0 auto; animation: fadeIn 0.3s ease-in-out; } .view-section.active { display: block; } @keyframes fadeIn { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } /* Typography & Utilities */ .section-title { font-size: 2rem; font-weight: bold; margin-bottom: 1.5rem; color: var(--primary); display: flex; align-items: center; gap: 0.75rem; } .card { background-color: var(--surface); border-radius: var(--radius-lg); padding: 1.5rem; box-shadow: var(--shadow-md); margin-bottom: 1.5rem; border: 1px solid var(--border); } .text-center { text-align: center; } .mb-2 { margin-bottom: 0.5rem; } .mb-4 { margin-bottom: 1rem; } .mt-4 { margin-top: 1rem; } .flex-between { display: flex; justify-content: space-between; align-items: center; } /* Buttons */ .btn { display: inline-flex; align-items: center; justify-content: center; padding: 0.75rem 1.5rem; border-radius: var(--radius-md); font-weight: 600; font-size: 1rem; transition: var(--transition); gap: 0.5rem; } .btn:hover { transform: translateY(-1px); box-shadow: var(--shadow-sm); } .btn:active { transform: translateY(0); } .btn-primary { background-color: var(--primary); color: white; } .btn-primary:hover { background-color: var(--primary-hover); } .btn-secondary { background-color: var(--secondary); color: white; } .btn-secondary:hover { background-color: var(--secondary-hover); } .btn-outline { background-color: transparent; border: 2px solid var(--primary); color: var(--primary); } .btn-outline:hover { background-color: var(--primary-light); } .btn-danger { background-color: var(--danger); color: white; } .btn-sm { padding: 0.4rem 0.8rem; font-size: 0.875rem; } /* Dashboard Specific */ .stats-grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 1rem; margin-bottom: 2rem; } .stat-card { background: var(--surface); border-radius: var(--radius-md); padding: 1.5rem; border: 1px solid var(--border); box-shadow: var(--shadow-sm); text-align: center; } .stat-value { font-size: 2rem; font-weight: bold; color: var(--primary); } .stat-label { color: var(--text-light); font-size: 0.875rem; font-weight: 500; text-transform: uppercase; letter-spacing: 0.05em; } /* Quest Specific */ .story-box { background-color: #fff; padding: 2rem; border-radius: var(--radius-lg); border-left: 6px solid var(--primary); box-shadow: var(--shadow-md); font-size: 1.1rem; line-height: 1.8; } .choice-container { display: grid; grid-template-columns: 1fr 1fr; gap: 1.5rem; margin-top: 2rem; } .choice-card { background: var(--surface); border: 2px solid var(--border); border-radius: var(--radius-lg); padding: 1.5rem; cursor: pointer; transition: var(--transition); display: flex; flex-direction: column; align-items: center; text-align: center; } .choice-card:hover { border-color: var(--primary); transform: translateY(-3px); box-shadow: var(--shadow-md); } .choice-icon { font-size: 3rem; margin-bottom: 1rem; } .path-result { display: none; background: var(--primary-light); padding: 2rem; border-radius: var(--radius-lg); margin-top: 2rem; animation: fadeIn 0.5s; border: 1px solid #C7D2FE; } .path-result h3 { color: var(--primary-hover); margin-bottom: 1rem; } /* Vocab Specific */ .vocab-controls { display: flex; gap: 1rem; margin-bottom: 1.5rem; flex-wrap: wrap; } .vocab-grid { display: grid; grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); gap: 1.5rem; } .vocab-card { perspective: 1000px; height: 260px; cursor: pointer; } .vocab-inner { position: relative; width: 100%; height: 100%; text-align: center; transition: transform 0.6s; transform-style: preserve-3d; } .vocab-card.flipped .vocab-inner { transform: rotateY(180deg); } .vocab-front, .vocab-back { position: absolute; width: 100%; height: 100%; -webkit-backface-visibility: hidden; backface-visibility: hidden; border-radius: var(--radius-lg); box-shadow: var(--shadow-md); padding: 1.5rem; display: flex; flex-direction: column; justify-content: center; align-items: center; border: 1px solid var(--border); background: var(--surface); } .vocab-front { background: linear-gradient(135deg, var(--surface) 0%, #F9FAFB 100%); } .vocab-front h3 { font-size: 1.5rem; color: var(--primary); } .vocab-tier { position: absolute; top: 1rem; right: 1rem; font-size: 0.75rem; background: var(--bg-color); padding: 0.2rem 0.5rem; border-radius: 4px; color: var(--text-light); } .vocab-back { transform: rotateY(180deg); background-color: var(--surface); text-align: left; align-items: flex-start; overflow-y: auto; } .vocab-back h4 { color: var(--primary); margin-bottom: 0.5rem; } .vocab-back p { font-size: 0.9rem; margin-bottom: 0.5rem; } .btn-learned { margin-top: auto; width: 100%; background: var(--secondary); color: white; padding: 0.5rem; border-radius: 4px; } .vocab-card.is-learned .vocab-front { border: 2px solid var(--secondary); } .vocab-card.is-learned .vocab-front::after { content: 'βœ“ Learned'; position: absolute; bottom: 1rem; color: var(--secondary); font-weight: bold; } /* Ladder Specific */ .ladder-step { background: var(--surface); border: 1px solid var(--border); border-radius: var(--radius-lg); margin-bottom: 1rem; overflow: hidden; } .step-header { background: var(--bg-color); padding: 1rem 1.5rem; display: flex; justify-content: space-between; align-items: center; font-weight: bold; border-bottom: 1px solid var(--border); } .step-level { background: var(--primary); color: white; padding: 0.25rem 0.75rem; border-radius: 999px; font-size: 0.875rem; } .step-content { padding: 1.5rem; } .guidance-panel { display: none; background: var(--secondary-light); padding: 1rem; border-radius: var(--radius-md); margin: 1rem 0; border-left: 4px solid var(--secondary); font-size: 0.9rem; } .teacher-note-panel { display: none; background: #FEF3C7; padding: 1rem; border-radius: var(--radius-md); margin-bottom: 1rem; border-left: 4px solid var(--accent); font-size: 0.9rem; } .teacher-mode .teacher-note-panel { display: block; } /* Quiz Specific */ .quiz-question { display: none; animation: fadeIn 0.3s; } .quiz-question.active { display: block; } .quiz-options { display: flex; flex-direction: column; gap: 0.75rem; margin-top: 1rem; } .quiz-option { padding: 1rem; border: 2px solid var(--border); border-radius: var(--radius-md); cursor: pointer; transition: var(--transition); display: flex; align-items: center; } .quiz-option:hover { border-color: var(--primary); background: var(--primary-light); } .quiz-option.selected { border-color: var(--primary); background: var(--primary-light); font-weight: bold; } .quiz-option.correct { border-color: var(--secondary); background: var(--secondary-light); } .quiz-option.incorrect { border-color: var(--danger); background: #FEE2E2; } .quiz-feedback { margin-top: 1rem; padding: 1rem; border-radius: var(--radius-md); display: none; font-weight: 500; } .quiz-progress { display: flex; gap: 0.5rem; margin-bottom: 1.5rem; justify-content: center; } .progress-dot { width: 12px; height: 12px; border-radius: 50%; background: var(--border); } .progress-dot.active { background: var(--primary); } .progress-dot.correct { background: var(--secondary); } .progress-dot.incorrect { background: var(--danger); } /* Journal Specific */ .journal-grid { display: grid; grid-template-columns: 1fr; gap: 1rem; } .journal-entry { background: #FFFBCC; padding: 1.5rem; border-radius: 4px; border-left: 6px solid #FDE047; box-shadow: var(--shadow-sm); position: relative; font-family: 'Comic Sans MS', cursive, sans-serif; /* subtle fun font for journal */ } .journal-meta { display: flex; justify-content: space-between; font-size: 0.8rem; color: var(--text-light); margin-bottom: 0.5rem; font-family: var(--font-main); } .entry-actions { position: absolute; top: 1rem; right: 1rem; display: flex; gap: 0.5rem; } /* Data/Empty States */ .empty-state { text-align: center; padding: 3rem; color: var(--text-light); } .empty-icon { font-size: 3rem; margin-bottom: 1rem; opacity: 0.5; } /* Toast Notification */ #toast-container { position: fixed; bottom: 20px; right: 20px; z-index: 9999; display: flex; flex-direction: column; gap: 10px; } .toast { background: var(--surface); color: var(--text-main); padding: 1rem 1.5rem; border-radius: var(--radius-md); box-shadow: var(--shadow-lg); border-left: 4px solid var(--primary); animation: slideIn 0.3s, fadeOut 0.3s 2.7s forwards; display: flex; align-items: center; gap: 0.75rem; } .toast.success { border-left-color: var(--secondary); } .toast.error { border-left-color: var(--danger); } @keyframes slideIn { from { transform: translateX(100%); opacity: 0; } to { transform: translateX(0); opacity: 1; } } @keyframes fadeOut { from { opacity: 1; } to { opacity: 0; } } /* Teacher Mode Overrides */ .teacher-only { display: none; } .teacher-mode .teacher-only { display: block; } .teacher-mode .student-only { display: none; } .teacher-mode .sidebar-header { background-color: var(--accent); } /* Responsive & Print */ @media (max-width: 768px) { body { flex-direction: column; } .sidebar { width: 100%; height: auto; border-right: none; border-bottom: 1px solid var(--border); display: none; } .sidebar.mobile-open { display: flex; position: absolute; width: 100%; height: 100%; background: white; z-index: 100; } .choice-container { grid-template-columns: 1fr; } .mobile-nav-toggle { display: block; position: fixed; top: 10px; right: 10px; z-index: 101; background: var(--primary); color: white; border-radius: 4px; padding: 0.5rem; } } @media (min-width: 769px) { .mobile-nav-toggle { display: none; } } @media print { .sidebar, .mode-toggle, .btn, .vocab-controls, .mobile-nav-toggle { display: none !important; } .main-content { padding: 0; overflow: visible; } .view-section { display: block !important; margin-bottom: 2rem; page-break-inside: avoid; } .card, .story-box, .vocab-card { border: 1px solid #000; box-shadow: none; break-inside: avoid; } .vocab-back { display: block; position: relative; transform: none; box-shadow: none; border-top: 1px dashed #ccc;} .vocab-front { display: none;} .vocab-card { height: auto; margin-bottom: 1rem;} body { background: white; } * { color: black !important; } } </style> </head> <body> <button class="mobile-nav-toggle" onclick="document.querySelector('.sidebar').classList.toggle('mobile-open')">☰ Menu</button> <aside class="sidebar"> <div class="sidebar-header"> <h1>QuestLoom</h1> <div class="badges"> <span class="badge">5th Grade</span> <span class="badge">Media Literacy</span> </div> </div> <nav class="nav-links"> <button class="nav-link active" data-target="dashboard"><span class="nav-icon">πŸ“Š</span> Dashboard</button> <button class="nav-link" data-target="quest"><span class="nav-icon">πŸ—ΊοΈ</span> Reading Quest</button> <button class="nav-link" data-target="vocab"><span class="nav-icon">πŸ—ƒοΈ</span> Vocab Vault</button> <button class="nav-link" data-target="ladder"><span class="nav-icon">πŸͺœ</span> Thinking Ladder</button> <button class="nav-link" data-target="quiz"><span class="nav-icon">βœ…</span> Comp Check</button> <button class="nav-link student-only" data-target="journal"><span class="nav-icon">πŸ““</span> My Journal</button> <div class="teacher-only" style="margin-top: 1rem; border-top: 1px solid var(--border); padding-top: 1rem;"> <span style="padding-left: 1.5rem; font-size: 0.75rem; color: var(--text-light); text-transform: uppercase;">Teacher Tools</span> <button class="nav-link" data-target="differentiation"><span class="nav-icon">πŸ› οΈ</span> Differentiation</button> <button class="nav-link" data-target="teacher-panel"><span class="nav-icon">πŸ‘¨β€πŸ«</span> Lesson Plan</button> <button class="nav-link" data-target="exit-tickets"><span class="nav-icon">🎟️</span> Exit Tickets</button> <button class="nav-link" data-target="rubric"><span class="nav-icon">πŸ“‹</span> Mini Rubric</button> <button class="nav-link" data-target="export"><span class="nav-icon">πŸ’Ύ</span> Data & Export</button> </div> </nav> <div class="mode-toggle"> <span style="font-size: 0.9rem; font-weight: 500;">Student</span> <label class="switch"> <input type="checkbox" id="roleToggle" onchange="toggleMode()"> <span class="slider"></span> </label> <span style="font-size: 0.9rem; font-weight: 500;">Teacher</span> </div> </aside> <main class="main-content" id="main-content"> <!-- DASHBOARD --> <section id="dashboard" class="view-section active"> <h2 class="section-title">✨ Welcome to Your Literacy Studio</h2> <div class="card mb-4" style="background: linear-gradient(135deg, var(--primary) 0%, var(--primary-hover) 100%); color: white;"> <h3 class="mb-2">Today's Mission: Spotting Fake News</h3> <p><strong>Goal:</strong> Learn how to evaluate source credibility and identify misleading claims in viral posts.</p> <p><strong>Time:</strong> ~40 Minutes</p> <div class="teacher-only mt-4" style="background: rgba(0,0,0,0.2); padding: 1rem; border-radius: var(--radius-md);"> <strong>Classroom Context:</strong> Mixed reading levels, high social media exposure. Focus on practical verification skills over complex terminology. </div> </div> <h3 class="mb-4">Your Progress Tracker</h3> <div class="stats-grid"> <div class="stat-card"> <div class="stat-value" id="stat-vocab">0/10</div> <div class="stat-label">Words Learned</div> </div> <div class="stat-card"> <div class="stat-value" id="stat-ladder">0/6</div> <div class="stat-label">Bloom's Steps</div> </div> <div class="stat-card"> <div class="stat-value" id="stat-quiz">--</div> <div class="stat-label">Best Quiz Score</div> </div> <div class="stat-card"> <div class="stat-value" id="stat-journal">0</div> <div class="stat-label">Journal Entries</div> </div> </div> <div class="flex-between card"> <div> <h4>Quick Start</h4> <p class="text-light">Start with the Reading Quest to begin your mission.</p> </div> <div> <button class="btn btn-outline mb-2" onclick="resetAppData()">Reset Session</button> <button class="btn btn-primary" onclick="navTo('quest')">Start Quest πŸš€</button> </div> </div> </section> <!-- READING QUEST --> <section id="quest" class="view-section"> <h2 class="section-title">πŸ—ΊοΈ The Case of the Glowing Gamers</h2> <div id="quest-start"> <div class="story-box mb-4"> <p>You are scrolling through your feed after school when a video suddenly grabs your attention. It has 2 million views and growing fast!</p> <br> <p>In the video, a kid chugs a bright green drink called <strong>"Neon Burst."</strong> Suddenly, the screen flashes. The kid turns around, blindfolded, and dodges three dodgeballs thrown at them perfectly. The text on the screen reads in huge flashing letters:</p> <br> <blockquote style="font-size: 1.2rem; font-style: italic; text-align: center; color: var(--danger); font-weight: bold;">"SCIENTISTS PROVE: Neon Burst gives you SUPERPOWER REFLEXES! Drink it to become a gaming god! Link in bio to buy before it's banned! #NoFilter #BuyNow"</blockquote> <br> <p>The comments are going crazy. Your friend Sam tags you and writes, <em>"Bro we need this for the tournament this weekend! I'm buying a case!"</em></p> <br> <p><strong>You have a choice to make. What do you do next?</strong></p> </div> <div class="choice-container"> <div class="choice-card" onclick="selectPath('A')"> <div class="choice-icon">πŸ“€</div> <h3>Path A: The Quick Share</h3> <p>Share the post with your gaming group immediately. If it has 2 million views, it must be real, right? Better tell everyone so you all get the reflex boost.</p> <button class="btn btn-outline mt-4">Choose Path A</button> </div> <div class="choice-card" onclick="selectPath('B')"> <div class="choice-icon">πŸ”</div> <h3>Path B: The Detective</h3> <p>Pause. Tell Sam to wait. You open a new tab to look up "Neon Burst" and try to find the "scientists" the video is talking about before anyone spends money.</p> <button class="btn btn-outline mt-4">Choose Path B</button> </div> </div> </div> <div id="quest-result" class="path-result"> <div id="result-A" style="display:none;"> <h3>Consequence: The Quick Share</h3> <p>You share the link. Sam and three other friends buy a case for $40 each. When it arrives, it's just green-colored sugar water. It tastes awful and makes everyone jittery, ruining your tournament focus.</p> <br> <p>Later, the social media platform deletes the original video because it was a scam created by a fake company. Your friends are mad at you for hyping it up, and you realize you spread false information.</p> <br> <div class="card mt-4" style="background: white;"> <strong>Reflection:</strong> Why is it dangerous to assume a post is true just because it has millions of views? </div> </div> <div id="result-B" style="display:none;"> <h3>Consequence: The Detective</h3> <p>You pause. You search for "Neon Burst Science Reflexes." The only results are from the company selling it. You search for the creator's profileβ€”they just created the account yesterday and have no other videos.</p> <br> <p>You find an article from a real gaming news site titled: <em>"Scam Alert: Fake 'Neon Burst' Drink Uses Edited Video."</em> You send this link to Sam. He cancels his order just in time. You saved your friends $40 and a bad stomachache!</p> <br> <div class="card mt-4" style="background: white;"> <strong>Reflection:</strong> What were two warning signs (red flags) that the original video might have been fake? </div> </div> <div class="mt-4"> <label for="quest-reflection" class="font-bold">Your Reflection:</label> <textarea id="quest-reflection" class="mt-2" placeholder="Type your thoughts here..."></textarea> <div class="flex-between mt-2"> <button class="btn btn-outline btn-sm" onclick="resetQuest()">Go Back & Change Path</button> <button class="btn btn-primary" onclick="saveQuestReflection()">Save Response</button> </div> </div> </div> </section> <!-- VOCAB VAULT --> <section id="vocab" class="view-section"> <h2 class="section-title">πŸ—ƒοΈ Vocabulary Vault</h2> <div class="vocab-controls card"> <input type="text" id="vocab-search" placeholder="Search words..." style="flex: 1; min-width: 200px;" oninput="renderVocab()"> <select id="vocab-filter" style="width: auto;" onchange="renderVocab()"> <option value="all">All Tiers</option> <option value="tier2">Tier 2 (Academic)</option> <option value="tier3">Tier 3 (Domain)</option> </select> <button class="btn btn-outline" onclick="resetVocab()">Reset Progress</button> </div> <div class="vocab-grid" id="vocab-container"> <!-- Cards generated via JS --> </div> </section> <!-- THINKING LADDER --> <section id="ladder" class="view-section"> <h2 class="section-title">πŸͺœ Bloom's Thinking Ladder</h2> <p class="mb-4">Climb the ladder by answering these questions based on the Neon Burst story.</p> <div id="ladder-container"> <!-- Generated via JS --> </div> </section> <!-- COMPREHENSION CHECK (QUIZ) --> <section id="quiz" class="view-section"> <h2 class="section-title">βœ… Credibility Check</h2> <div class="card text-center" id="quiz-intro"> <h3>Ready to test your skills?</h3> <p class="mb-4 text-light">5 questions to see if you can spot the fake.</p> <p>Best Score: <span id="quiz-best-display" class="font-bold text-primary">--</span></p> <button class="btn btn-primary mt-4" onclick="startQuiz()">Start Quiz</button> </div> <div class="card" id="quiz-active" style="display: none;"> <div class="quiz-progress" id="quiz-progress"> <!-- Dots --> </div> <h3 id="quiz-q-text" class="mb-4">Question text</h3> <div class="quiz-options" id="quiz-options-container"> <!-- Options --> </div> <div id="quiz-feedback" class="quiz-feedback"></div> <div class="flex-between mt-4"> <span id="quiz-counter" class="text-light text-sm">1 of 5</span> <button class="btn btn-primary" id="quiz-next-btn" style="display:none;" onclick="nextQuizQuestion()">Next Question</button> </div> </div> <div class="card text-center" id="quiz-result-view" style="display:none;"> <h3>Quiz Complete!</h3> <div class="stat-value my-4" id="quiz-final-score">0/5</div> <p id="quiz-final-message" class="mb-4"></p> <button class="btn btn-outline" onclick="startQuiz()">Try Again</button> </div> </section> <!-- JOURNAL --> <section id="journal" class="view-section"> <h2 class="section-title">πŸ““ My Response Journal</h2> <div class="card"> <h4 class="mb-2">New Entry</h4> <div style="display: flex; gap: 1rem; margin-bottom: 1rem;"> <select id="journal-category" style="width: auto;"> <option value="Reflection">Reflection</option> <option value="Evidence">Evidence Collection</option> <option value="Vocabulary">Vocabulary Use</option> <option value="Question">My Question</option> </select> </div> <textarea id="journal-text" placeholder="Write your thoughts, paste evidence from the web, or write down questions you have..."></textarea> <div class="flex-between mt-2"> <span class="text-light text-sm">Saved automatically to this device.</span> <button class="btn btn-primary" onclick="addJournalEntry()">Save Entry</button> </div> </div> <div class="vocab-controls mb-4"> <input type="text" id="journal-search" placeholder="Search entries..." oninput="renderJournal()"> <select id="journal-filter-cat" onchange="renderJournal()"> <option value="all">All Categories</option> <option value="Reflection">Reflection</option> <option value="Evidence">Evidence</option> <option value="Vocabulary">Vocabulary</option> <option value="Question">Question</option> </select> <button class="btn btn-danger btn-sm" onclick="clearJournal()">Clear All</button> </div> <div class="journal-grid" id="journal-container"> <!-- Generated via JS --> </div> </section> <!-- TEACHER PANELS --> <section id="differentiation" class="view-section teacher-only"> <h2 class="section-title">πŸ› οΈ Differentiation Studio</h2> <div class="vocab-controls card"> <select id="diff-filter" style="flex: 1;" onchange="renderDiff()"> <option value="all">All Support Types</option> <option value="struggling">Struggling Readers</option> <option value="el">English Learners</option> <option value="advanced">Advanced Learners</option> </select> </div> <div id="diff-container" class="journal-grid"> <!-- Generated via JS --> </div> </section> <section id="teacher-panel" class="view-section teacher-only"> <h2 class="section-title">πŸ‘¨β€πŸ« Lesson Plan & Facilitation</h2> <div class="card"> <h3>Lesson Overview</h3> <ul style="margin-left: 1.5rem; margin-top: 1rem;"> <li><strong>Objective:</strong> Students will evaluate source credibility and identify misleading claims in a fictional viral media post.</li> <li><strong>Materials:</strong> Devices for interactive app, projector for modeling.</li> <li><strong>Before Reading:</strong> Ask students: "Have you ever bought something because you saw it on TikTok/YouTube? Did it work as advertised?"</li> <li><strong>Misconception Watchlist:</strong> Students often equate "number of views" or "likes" with "truth." Emphasize that popularity does not equal credibility.</li> </ul> </div> <div class="card"> <h3>Assumptions & Context</h3> <div class="teacher-note-panel" style="display: block;"> <em>Based on inputs:</em> Assumes students have basic familiarity with social media feeds (scrolling, likes, sharing). The text complexity is targeted at early 5th grade to accommodate mixed reading levels, focusing cognitive load on the critical thinking task rather than decoding. </div> </div> <div class="card"> <div class="flex-between mb-2"> <h3>My Teaching Notes</h3> <button class="btn btn-outline btn-sm" onclick="copyToClipboard(document.getElementById('teacher-notes').value)">Copy Notes</button> </div> <textarea id="teacher-notes" placeholder="Jot down notes about how this lesson went, which students need more help, etc." onchange="saveTeacherNotes()"></textarea> </div> </section> <section id="exit-tickets" class="view-section teacher-only"> <h2 class="section-title">🎟️ Exit Ticket Generator</h2> <p class="mb-4">Use these prompts to check understanding at the end of the 40-minute block.</p> <div id="exit-tickets-container"> <!-- Generated via JS --> </div> <button class="btn btn-primary mt-4" onclick="window.print()">Print Exit Tickets</button> </section> <section id="rubric" class="view-section teacher-only"> <h2 class="section-title">πŸ“‹ Mini Rubric</h2> <div class="card" style="overflow-x: auto;"> <table style="width: 100%; border-collapse: collapse; min-width: 600px;"> <thead> <tr style="background: var(--bg-color); border-bottom: 2px solid var(--border);"> <th style="padding: 1rem; text-align: left;">Skill</th> <th style="padding: 1rem; text-align: left;">1 - Beginning</th> <th style="padding: 1rem; text-align: left;">2 - Developing</th> <th style="padding: 1rem; text-align: left;">3 - Proficient</th> <th style="padding: 1rem; text-align: left;">4 - Advanced</th> </tr> </thead> <tbody id="rubric-body"> <!-- Generated via JS --> </tbody> </table> </div> <button class="btn btn-outline" onclick="copyRubric()">Copy Rubric Text</button> </section> <section id="export" class="view-section teacher-only"> <h2 class="section-title">πŸ’Ύ Data & Export Center</h2> <div class="card mb-4"> <h3>Export Content</h3> <p class="text-light mb-4">Copy text formats for your Learning Management System (LMS).</p> <div class="flex-between flex-wrap gap-2" style="gap: 1rem;"> <button class="btn btn-outline" onclick="exportData('teacher-pack')">Copy Lesson Plan Text</button> <button class="btn btn-outline" onclick="exportData('student-pack')">Copy Reading Quest Text</button> </div> </div> <div class="card border-danger"> <h3>Student Data Management</h3> <p class="text-light mb-4">This app saves data locally to the browser (localStorage). You can export it or clear it between classes.</p> <div style="display: flex; gap: 1rem; flex-wrap: wrap;"> <button class="btn btn-secondary" onclick="downloadJSON()">Download JSON Backup</button> <button class="btn btn-danger" onclick="hardReset()">Clear ALL App Data</button> </div> </div> </section> </main> <div id="toast-container"></div> <script> /* --- STATE MANAGEMENT --- */ const STORAGE_KEY = 'QuestLoom_FakeNews_5th_V1'; const defaultState = { mode: 'student', quest: { path: null, reflection: '' }, vocab: {}, ladder: {}, quiz: { bestScore: null, attempts: 0 }, journal: [], teacherNotes: '', exitTickets: {}, favorites: [] }; let appState = JSON.parse(JSON.stringify(defaultState)); function loadState() { try { const saved = localStorage.getItem(STORAGE_KEY); if (saved) { // Merge saved with default to ensure new keys exist appState = { ...defaultState, ...JSON.parse(saved) }; // Fix nested objects that might be overwritten by shallow merge appState.quest = { ...defaultState.quest, ...(JSON.parse(saved).quest || {}) }; } } catch (e) { console.error("Could not load state", e); showToast("Notice: Saving is disabled in this environment.", "error"); } } function saveState() { try { localStorage.setItem(STORAGE_KEY, JSON.stringify(appState)); updateDashboard(); } catch (e) { console.error("Could not save state", e); } } /* --- CONTENT DATA --- */ const vocabData = [ { word: "Evaluate", tier: "tier2", def: "To carefully look at something to decide if it is good, true, or useful.", sentence: "You must evaluate the website before using it for your report.", why: "Helps you stop and think instead of just accepting information." }, { word: "Source", tier: "tier2", def: "Where information comes from (like a person, website, or book).", sentence: "The source of the rumor was a joke account on social media.", why: "Knowing who wrote it tells you if they are an expert." }, { word: "Misleading", tier: "tier2", def: "Giving the wrong idea or impression on purpose.", sentence: "The misleading title made it sound like school was cancelled.", why: "Protects you from being tricked by tricky wording." }, { word: "Claim", tier: "tier2", def: "A statement saying something is true, even if there isn't proof yet.", sentence: "The ad made a claim that the shoes make you jump higher.", why: "You need to recognize claims so you know what needs to be proven." }, { word: "Verify", tier: "tier2", def: "To make sure something is true by checking facts.", sentence: "She decided to verify the news by checking a real news channel.", why: "The main tool for busting fake news." }, { word: "Evidence", tier: "tier2", def: "Facts or proof that show something is true.", sentence: "The scientist showed evidence that the formula worked.", why: "Opinions aren't enough; you need proof." }, { word: "Clickbait", tier: "tier3", def: "A title or picture designed to make you click, usually using extreme emotion.", sentence: "The title 'YOU WON'T BELIEVE THIS' was just clickbait.", why: "Helps you avoid falling for emotional traps online." }, { word: "Viral", tier: "tier3", def: "Spreading very quickly online through sharing.", sentence: "The funny cat video went viral and got 10 million views.", why: "Reminds us that popular doesn't mean true." }, { word: "Bias", tier: "tier3", def: "A strong feeling for or against something, usually unfairly.", sentence: "The article had a bias against video games.", why: "Helps you see if an author is trying to manipulate you." }, { word: "Credibility", tier: "tier3", def: "The quality of being trusted and believed in.", sentence: "A doctor has more credibility about health than a random YouTuber.", why: "The ultimate goal: finding sources you can trust." } ]; const ladderData = [ { level: "Remember", q: "What did the viral post claim the 'Neon Burst' drink could do?", note: "Assesses literal recall of the text." }, { level: "Understand", q: "Explain in your own words why someone might create a fake post selling a fake drink.", note: "Assesses comprehension of motive (profit/scam)." }, { level: "Apply", q: "If you see a post with an amazing claim but NO author name, what should you do?", note: "Assesses transfer of skills to a new hypothetical situation." }, { level: "Analyze", q: "Compare the 'evidence' in the video (dodging balls) to what a real scientist would need to prove reflexes improved.", note: "Assesses ability to break down weak evidence vs strong evidence." }, { level: "Evaluate", q: "Do you think social media platforms are responsible for deleting posts like Neon Burst? Why or why not?", note: "Assesses ability to form and defend a judgment." }, { level: "Create", q: "Write a short 2-sentence warning comment you could post under the fake video to help other kids.", note: "Assesses ability to synthesize learning into a new product." } ]; const quizData = [ { q: "What does it mean to 'evaluate' a source?", type: "mc", options: ["To share it quickly", "To look at it carefully to see if it's true", "To make it go viral", "To delete it immediately"], correct: 1, feedback: "Evaluating means taking time to check the facts carefully." }, { q: "True or False: If a video has 2 million views, the information in it is definitely true.", type: "tf", options: ["True", "False"], correct: 1, feedback: "False! Fake videos can go viral very quickly because they use strong emotions." }, { q: "Which of these is the BEST way to verify a wild claim online?", type: "mc", options: ["Ask your friends if they believe it", "Read the comments on the post", "Open a new tab and search for the topic on trusted news sites", "Watch the video three more times"], correct: 2, feedback: "Opening a new tab to 'read laterally' is the best way to verify." }, { q: "What is 'clickbait' trying to do?", type: "mc", options: ["Teach you a lesson", "Make you use strong emotions so you click without thinking", "Provide boring facts", "Show you cute animals"], correct: 1, feedback: "Clickbait uses all caps or shocking words to bypass your critical thinking." }, { q: "Why did the creator of Neon Burst want you to 'Buy before it's banned!'?", type: "mc", options: ["Because it was actually dangerous", "To make you panic and buy it quickly without checking facts", "Because they were running out of bottles", "Because scientists liked it"], correct: 1, feedback: "Creating a sense of false urgency is a common scam tactic." } ]; const diffData = [ { type: "struggling", title: "Sentence Starters for Ladder", content: "Provide sentence frames: 'The post claimed the drink could...', 'I think someone made this fake post because...', 'A warning sign I noticed was...'" }, { type: "struggling", title: "Chunked Reading", content: "Have students read the first 3 paragraphs of the quest, pause, and summarize to a partner before making the choice." }, { type: "el", title: "Visual Dictionary", content: "Before the lesson, show images representing 'Viral' (a spreading web), 'Source' (a well of water/information), and 'Verify' (a magnifying glass with a checkmark)." }, { type: "advanced", title: "Lateral Reading Extension", content: "Ask advanced students to open a real safe search engine and find a real-world example of a debunked viral claim, then report back to the class." } ]; const exitTicketData = [ { type: "Literal", q: "Name one red flag from the story that showed the post might be fake." }, { type: "Inference", q: "Why is it important to check the date and the author profile of a viral video?" }, { type: "Transfer", q: "What is one rule you will use next time you see a surprising claim online?" } ]; const rubricData = [ { skill: "Evaluating Credibility", l1: "Cannot identify fake features.", l2: "Identifies 1 warning sign with help.", l3: "Identifies multiple warning signs independently.", l4: "Identifies warning signs and explains why they trick people." }, { skill: "Using Evidence", l1: "Answers without evidence.", l2: "Uses weak or general evidence.", l3: "Uses specific evidence from the text.", l4: "Uses strong evidence and connects it clearly to the claim." }, { skill: "Vocabulary", l1: "Does not use target words.", l2: "Uses 1-2 words, sometimes incorrectly.", l3: "Uses target words correctly in responses.", l4: "Uses Tier 2/3 words naturally and precisely." } ]; /* --- UI UTILITIES --- */ function showToast(message, type = 'success') { const container = document.getElementById('toast-container'); const toast = document.createElement('div'); toast.className = `toast ${type}`; toast.innerHTML = `<span style="font-size:1.2rem;">${type === 'success' ? 'βœ…' : '⚠️'}</span> ${message}`; container.appendChild(toast); setTimeout(() => { toast.remove(); }, 3000); } function navTo(targetId) { document.querySelectorAll('.view-section').forEach(el => el.classList.remove('active')); document.querySelectorAll('.nav-link').forEach(el => el.classList.remove('active')); document.getElementById(targetId).classList.add('active'); document.querySelector(`[data-target="${targetId}"]`).classList.add('active'); // Close mobile menu document.querySelector('.sidebar').classList.remove('mobile-open'); } function toggleMode() { const isTeacher = document.getElementById('roleToggle').checked; appState.mode = isTeacher ? 'teacher' : 'student'; if (isTeacher) { document.body.classList.add('teacher-mode'); } else { document.body.classList.remove('teacher-mode'); // Auto-nav away from teacher screens if active const activeSection = document.querySelector('.view-section.active').id; if (['differentiation', 'teacher-panel', 'exit-tickets', 'rubric', 'export'].includes(activeSection)) { navTo('dashboard'); } } saveState(); } /* --- FEATURE IMPLEMENTATIONS --- */ // DASHBOARD function updateDashboard() { const learnedVocab = Object.values(appState.vocab).filter(v => v).length; document.getElementById('stat-vocab').innerText = `${learnedVocab}/${vocabData.length}`; const answeredLadder = Object.values(appState.ladder).filter(v => v.trim() !== '').length; document.getElementById('stat-ladder').innerText = `${answeredLadder}/${ladderData.length}`; document.getElementById('stat-quiz').innerText = appState.quiz.bestScore !== null ? `${appState.quiz.bestScore}/5` : '--'; document.getElementById('quiz-best-display').innerText = appState.quiz.bestScore !== null ? `${appState.quiz.bestScore}/5` : 'Not taken yet'; document.getElementById('stat-journal').innerText = appState.journal.length; } // QUEST function selectPath(path) { appState.quest.path = path; renderQuest(); saveState(); } function resetQuest() { if(confirm("Reset your quest progress? Your reflection will be saved in your journal before clearing.")) { if(appState.quest.reflection) { addJournalEntry(appState.quest.reflection, "Reflection"); } appState.quest.path = null; appState.quest.reflection = ''; renderQuest(); saveState(); showToast("Quest reset."); } } function saveQuestReflection() { const val = document.getElementById('quest-reflection').value; if(!val.trim()) { showToast("Please write something before saving.", "error"); return; } appState.quest.reflection = val; saveState(); showToast("Reflection saved!"); } function renderQuest() { const start = document.getElementById('quest-start'); const result = document.getElementById('quest-result'); const resA = document.getElementById('result-A'); const resB = document.getElementById('result-B'); const refText = document.getElementById('quest-reflection'); if (!appState.quest.path) { start.style.display = 'block'; result.style.display = 'none'; } else { start.style.display = 'none'; result.style.display = 'block'; resA.style.display = appState.quest.path === 'A' ? 'block' : 'none'; resB.style.display = appState.quest.path === 'B' ? 'block' : 'none'; refText.value = appState.quest.reflection || ''; } } // VOCAB function renderVocab() { const container = document.getElementById('vocab-container'); const search = document.getElementById('vocab-search').value.toLowerCase(); const filter = document.getElementById('vocab-filter').value; container.innerHTML = ''; let filtered = vocabData.filter(v => { const matchSearch = v.word.toLowerCase().includes(search) || v.def.toLowerCase().includes(search); const matchFilter = filter === 'all' || v.tier === filter; return matchSearch && matchFilter; }); if(filtered.length === 0) { container.innerHTML = `<div class="empty-state">No vocabulary words found.</div>`; return; } filtered.forEach(v => { const isLearned = appState.vocab[v.word]; const card = document.createElement('div'); card.className = `vocab-card ${isLearned ? 'is-learned' : ''}`; card.innerHTML = ` <div class="vocab-inner"> <div class="vocab-front"> <span class="vocab-tier">${v.tier === 'tier2' ? 'Tier 2' : 'Tier 3'}</span> <h3>${v.word}</h3> <p class="text-light text-sm mt-2">Click to flip</p> </div> <div class="vocab-back"> <h4>${v.word}</h4> <p><strong>Definition:</strong> ${v.def}</p> <p><strong>Example:</strong> <em>"${v.sentence}"</em></p> <p class="text-sm" style="color: var(--text-light);"><strong>Why it matters:</strong> ${v.why}</p> <button class="btn-learned" onclick="toggleVocab('${v.word}', event)"> ${isLearned ? 'Mark as Needs Review' : 'Mark as Learned βœ“'} </button> </div> </div> `; card.addEventListener('click', function(e) { if(!e.target.classList.contains('btn-learned')) { this.classList.toggle('flipped'); } }); container.appendChild(card); }); } function toggleVocab(word, event) { event.stopPropagation(); appState.vocab[word] = !appState.vocab[word]; saveState(); renderVocab(); } function resetVocab() { if(confirm("Clear all vocabulary progress?")) { appState.vocab = {}; saveState(); renderVocab(); showToast("Vocabulary progress reset."); } } // LADDER function renderLadder() { const container = document.getElementById('ladder-container'); container.innerHTML = ''; ladderData.forEach((item, index) => { const step = document.createElement('div'); step.className = 'ladder-step'; const ans = appState.ladder[item.level] || ''; step.innerHTML = ` <div class="step-header"> <span>Step ${index + 1}: ${item.q}</span> <span class="step-level">${item.level}</span> </div> <div class="step-content"> <div class="teacher-note-panel"><strong>Teacher Note:</strong> ${item.note}</div> <button class="btn btn-outline btn-sm mb-2 student-only" onclick="this.nextElementSibling.style.display='block'; this.style.display='none'">Need a hint?</button> <div class="guidance-panel">Think about the story carefully. Look back at the quest if needed.</div> <textarea id="ladder-${item.level}" placeholder="Type your answer here...">${ans}</textarea> <div class="flex-between mt-2"> <button class="btn btn-outline btn-sm" onclick="document.getElementById('ladder-${item.level}').value=''">Clear</button> <button class="btn btn-primary" onclick="saveLadder('${item.level}')">Save Step</button> </div> </div> `; container.appendChild(step); }); } function saveLadder(level) { const val = document.getElementById(`ladder-${level}`).value; if(!val.trim()) { showToast("Answer cannot be empty", "error"); return; } appState.ladder[level] = val; saveState(); showToast(`${level} step saved!`); } // QUIZ let currentQuizIndex = 0; let currentQuizScore = 0; function startQuiz() { currentQuizIndex = 0; currentQuizScore = 0; document.getElementById('quiz-intro').style.display = 'none'; document.getElementById('quiz-result-view').style.display = 'none'; document.getElementById('quiz-active').style.display = 'block'; // Build progress dots const prog = document.getElementById('quiz-progress'); prog.innerHTML = ''; quizData.forEach((_, i) => { prog.innerHTML += `<div class="progress-dot" id="dot-${i}"></div>`; }); loadQuizQuestion(); } function loadQuizQuestion() { const q = quizData[currentQuizIndex]; document.getElementById('quiz-q-text').innerText = `${currentQuizIndex + 1}. ${q.q}`; document.getElementById('quiz-counter').innerText = `Question ${currentQuizIndex + 1} of ${quizData.length}`; // Update dots document.querySelectorAll('.progress-dot').forEach((el, i) => { el.className = 'progress-dot' + (i === currentQuizIndex ? ' active' : (i < currentQuizIndex ? ' completed' : '')); }); const opts = document.getElementById('quiz-options-container'); opts.innerHTML = ''; q.options.forEach((opt, i) => { const btn = document.createElement('div'); btn.className = 'quiz-option'; btn.innerText = opt; btn.onclick = () => selectQuizOption(i, btn); opts.appendChild(btn); }); document.getElementById('quiz-feedback').style.display = 'none'; document.getElementById('quiz-next-btn').style.display = 'none'; } function selectQuizOption(selectedIndex, btnElement) { if(document.getElementById('quiz-next-btn').style.display === 'block') return; // already answered const q = quizData[currentQuizIndex]; const isCorrect = selectedIndex === q.correct; const options = document.querySelectorAll('.quiz-option'); options[selectedIndex].classList.add('selected'); options[q.correct].classList.add('correct'); if(!isCorrect) { options[selectedIndex].classList.add('incorrect'); document.getElementById(`dot-${currentQuizIndex}`).classList.add('incorrect'); } else { currentQuizScore++; document.getElementById(`dot-${currentQuizIndex}`).classList.add('correct'); } const feedback = document.getElementById('quiz-feedback'); feedback.style.display = 'block'; feedback.style.backgroundColor = isCorrect ? 'var(--secondary-light)' : '#FEE2E2'; feedback.style.color = isCorrect ? 'var(--secondary-hover)' : 'var(--danger)'; feedback.innerText = isCorrect ? `Correct! ${q.feedback}` : `Not quite. ${q.feedback}`; document.getElementById('quiz-next-btn').style.display = 'block'; } function nextQuizQuestion() { currentQuizIndex++; if(currentQuizIndex < quizData.length) { loadQuizQuestion(); } else { finishQuiz(); } } function finishQuiz() { document.getElementById('quiz-active').style.display = 'none'; const resView = document.getElementById('quiz-result-view'); resView.style.display = 'block'; document.getElementById('quiz-final-score').innerText = `${currentQuizScore}/${quizData.length}`; let msg = ""; if(currentQuizScore === 5) msg = "Expert Detective! You spotted all the signs."; else if(currentQuizScore >= 3) msg = "Good job! You're learning the red flags."; else msg = "Keep practicing! Fake news can be tricky."; document.getElementById('quiz-final-message').innerText = msg; appState.quiz.attempts++; if(appState.quiz.bestScore === null || currentQuizScore > appState.quiz.bestScore) { appState.quiz.bestScore = currentQuizScore; showToast("New Best Score!"); } saveState(); } // JOURNAL function addJournalEntry(text = null, category = null) { const txt = text || document.getElementById('journal-text').value; const cat = category || document.getElementById('journal-category').value; if(!txt.trim()) { showToast("Cannot save empty entry.", "error"); return; } const entry = { id: Date.now().toString(), date: new Date().toLocaleDateString(), category: cat, text: txt }; appState.journal.unshift(entry); saveState(); renderJournal(); if(!text) document.getElementById('journal-text').value = ''; showToast("Journal entry saved."); } function renderJournal() { const container = document.getElementById('journal-container'); const search = document.getElementById('journal-search').value.toLowerCase(); const filter = document.getElementById('journal-filter-cat').value; container.innerHTML = ''; let filtered = appState.journal.filter(j => { const matchSearch = j.text.toLowerCase().includes(search); const matchFilter = filter === 'all' || j.category === filter; return matchSearch && matchFilter; }); if(filtered.length === 0) { container.innerHTML = `<div class="empty-state">No journal entries found. Time to write!</div>`; return; } filtered.forEach(j => { const el = document.createElement('div'); el.className = 'journal-entry'; el.innerHTML = ` <div class="journal-meta"> <span><strong>${j.category}</strong></span> <span>${j.date}</span> </div> <p style="white-space: pre-wrap; padding-right: 60px;">${j.text}</p> <div class="entry-actions"> <button class="btn btn-outline btn-sm" onclick="editJournal('${j.id}')">Edit</button> <button class="btn btn-danger btn-sm" onclick="deleteJournal('${j.id}')">βœ•</button> </div> `; container.appendChild(el); }); } function deleteJournal(id) { if(confirm("Delete this entry?")) { appState.journal = appState.journal.filter(j => j.id !== id); saveState(); renderJournal(); } } function editJournal(id) { const entry = appState.journal.find(j => j.id === id); if(entry) { const newText = prompt("Edit your entry:", entry.text); if(newText !== null && newText.trim() !== "") { entry.text = newText; saveState(); renderJournal(); } } } function clearJournal() { if(confirm("Are you sure you want to clear ALL journal entries?")) { appState.journal = []; saveState(); renderJournal(); showToast("Journal cleared."); } } // TEACHER TOOLS function renderDiff() { const container = document.getElementById('diff-container'); const filter = document.getElementById('diff-filter').value; container.innerHTML = ''; const filtered = diffData.filter(d => filter === 'all' || d.type === filter); filtered.forEach((d, i) => { const el = document.createElement('div'); el.className = 'card mb-2'; el.innerHTML = ` <div class="flex-between mb-2"> <h4 style="color: var(--primary);">${d.title} <span class="badge" style="background: var(--bg-color); color: var(--text-main); border: 1px solid var(--border);">${d.type}</span></h4> <button class="btn btn-outline btn-sm" onclick="copyToClipboard('${d.content.replace(/'/g, "\\'")}')">Copy Strategy</button> </div> <p>${d.content}</p> `; container.appendChild(el); }); } function renderExitTickets() { const container = document.getElementById('exit-tickets-container'); container.innerHTML = ''; exitTicketData.forEach((t, i) => { container.innerHTML += ` <div class="card mb-4" style="page-break-inside: avoid;"> <div class="flex-between mb-2"> <span class="badge" style="background: var(--primary); color: white;">${t.type}</span> <button class="btn btn-outline btn-sm teacher-only" onclick="copyToClipboard('${t.q}')">Copy Question</button> </div> <p class="font-bold mb-2">Q: ${t.q}</p> <div class="teacher-only text-sm text-light mb-2">Expected concept: ${i===0?'Glowing eyes, dodgeball, no author':'To see if it is old, or from a fake account.'}</div> <textarea placeholder="Student Answer..." style="min-height: 80px;"></textarea> </div> `; }); } function renderRubric() { const body = document.getElementById('rubric-body'); body.innerHTML = ''; rubricData.forEach(r => { body.innerHTML += ` <tr style="border-bottom: 1px solid var(--border);"> <td style="padding: 1rem; font-weight: bold;">${r.skill}</td> <td style="padding: 1rem; background: #FEE2E2;">${r.l1}</td> <td style="padding: 1rem; background: #FEF3C7;">${r.l2}</td> <td style="padding: 1rem; background: #D1FAE5;">${r.l3}</td> <td style="padding: 1rem; background: var(--primary-light);">${r.l4}</td> </tr> `; }); } function saveTeacherNotes() { appState.teacherNotes = document.getElementById('teacher-notes').value; saveState(); showToast("Teacher notes saved."); } function copyRubric() { let text = "Mini Rubric: Spotting Fake News\n\n"; rubricData.forEach(r => { text += `${r.skill}:\n1: ${r.l1}\n2: ${r.l2}\n3: ${r.l3}\n4: ${r.l4}\n\n`; }); copyToClipboard(text); } // EXPORT / UTILS function copyToClipboard(text) { const el = document.createElement('textarea'); el.value = text; document.body.appendChild(el); el.select(); document.execCommand('copy'); document.body.removeChild(el); showToast("Copied to clipboard!"); } function exportData(type) { let text = ""; if(type === 'teacher-pack') { text = `LESSON: Spotting Fake News (5th Grade)\nGoal: Evaluate credibility.\n\nSTORY:\nA viral video claims "Neon Burst" gives superpower reflexes. Friends want to buy it.\n\nVOCABULARY:\n`; vocabData.forEach(v => text += `- ${v.word}: ${v.def}\n`); } else if (type === 'student-pack') { text = `QUEST: The Case of the Glowing Gamers\nRead the story and answer the questions.\n\nStory: A video shows a kid drinking "Neon Burst" and dodging dodgeballs perfectly. The caption says scientists prove it gives superpower reflexes.\n\nQuestions:\n`; ladderData.forEach(l => text += `- ${l.q}\n`); } copyToClipboard(text); } function downloadJSON() { const dataStr = "data:text/json;charset=utf-8," + encodeURIComponent(JSON.stringify(appState, null, 2)); const downloadAnchorNode = document.createElement('a'); downloadAnchorNode.setAttribute("href", dataStr); downloadAnchorNode.setAttribute("download", "QuestLoom_Data.json"); document.body.appendChild(downloadAnchorNode); downloadAnchorNode.click(); downloadAnchorNode.remove(); } function resetAppData() { if(confirm("This will clear your current session progress. Continue?")) { appState = JSON.parse(JSON.stringify(defaultState)); // maintain mode appState.mode = document.getElementById('roleToggle').checked ? 'teacher' : 'student'; saveState(); initApp(); showToast("Session reset."); } } function hardReset() { if(confirm("DANGER: This completely wipes all saved data from the browser. Are you sure?")) { localStorage.removeItem(STORAGE_KEY); location.reload(); } } /* --- INITIALIZATION --- */ function initApp() { loadState(); // Set role toggle const isTeacher = appState.mode === 'teacher'; document.getElementById('roleToggle').checked = isTeacher; if(isTeacher) document.body.classList.add('teacher-mode'); // Setup Navigation Listeners document.querySelectorAll('.nav-link').forEach(btn => { btn.addEventListener('click', (e) => { navTo(e.currentTarget.dataset.target); }); }); // Init values document.getElementById('teacher-notes').value = appState.teacherNotes; // Render specific views renderQuest(); renderVocab(); renderLadder(); renderJournal(); renderDiff(); renderExitTickets(); renderRubric(); updateDashboard(); } // Run on load document.addEventListener('DOMContentLoaded', initApp); </script> </body> </html>
β™ŠοΈ Gemini

Vocabulary Web App Builder

Add to Cart
Instant accessInstant access
Usage rightsCommercial use
Money-back guaranteeMoney‑back
By purchasing this prompt, you agree to our terms of service
GEMINI-3.1-PRO
Tested icon
Guide icon
4 examples icon
Free credits icon
Interactive Vocabulary web apps in minutes without coding.
...more
Added 6 days ago
Report
Browse Marketplace