Spaces:
Running
Running
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8"> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> | |
| <title>Phonics Flash Cards - 100 Patterns</title> | |
| <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css"> | |
| <style> | |
| :root { | |
| --primary: #6a11cb; | |
| --secondary: #2575fc; | |
| --accent: #ff416c; | |
| --success: #38ef7d; | |
| --warning: #ffb347; | |
| --light: #f8f9fa; | |
| --dark: #212529; | |
| --card-front: linear-gradient(135deg, #6a11cb 0%, #2575fc 100%); | |
| --card-back: linear-gradient(135deg, #ff416c 0%, #ff4b2b 100%); | |
| --border-radius: 20px; | |
| --shadow: 0 10px 30px rgba(0, 0, 0, 0.15); | |
| --transition: all 0.5s cubic-bezier(0.175, 0.885, 0.32, 1.275); | |
| } | |
| * { | |
| margin: 0; | |
| padding: 0; | |
| box-sizing: border-box; | |
| font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif; | |
| } | |
| body { | |
| background: linear-gradient(135deg, #f5f7fa 0%, #c3cfe2 100%); | |
| color: var(--dark); | |
| min-height: 100vh; | |
| padding: 20px; | |
| } | |
| .container { | |
| max-width: 1400px; | |
| margin: 0 auto; | |
| } | |
| header { | |
| text-align: center; | |
| margin-bottom: 40px; | |
| padding: 30px 20px; | |
| background: white; | |
| border-radius: var(--border-radius); | |
| box-shadow: var(--shadow); | |
| position: relative; | |
| overflow: hidden; | |
| } | |
| header::before { | |
| content: ''; | |
| position: absolute; | |
| top: 0; | |
| left: 0; | |
| right: 0; | |
| height: 5px; | |
| background: linear-gradient(90deg, var(--primary), var(--secondary), var(--accent)); | |
| } | |
| .header-content { | |
| max-width: 800px; | |
| margin: 0 auto; | |
| } | |
| h1 { | |
| font-size: 2.8rem; | |
| background: linear-gradient(90deg, var(--primary), var(--secondary)); | |
| -webkit-background-clip: text; | |
| background-clip: text; | |
| color: transparent; | |
| margin-bottom: 10px; | |
| } | |
| .subtitle { | |
| font-size: 1.2rem; | |
| color: #666; | |
| margin-bottom: 25px; | |
| } | |
| .stats-bar { | |
| display: flex; | |
| justify-content: center; | |
| gap: 30px; | |
| flex-wrap: wrap; | |
| margin-top: 25px; | |
| } | |
| .stat-item { | |
| background: var(--light); | |
| padding: 15px 25px; | |
| border-radius: 15px; | |
| text-align: center; | |
| box-shadow: 0 5px 15px rgba(0,0,0,0.05); | |
| min-width: 140px; | |
| } | |
| .stat-number { | |
| font-size: 2.2rem; | |
| font-weight: bold; | |
| color: var(--primary); | |
| } | |
| .stat-label { | |
| font-size: 0.9rem; | |
| color: #666; | |
| margin-top: 5px; | |
| } | |
| .controls { | |
| display: flex; | |
| justify-content: center; | |
| gap: 15px; | |
| flex-wrap: wrap; | |
| margin-bottom: 30px; | |
| } | |
| .btn { | |
| padding: 14px 28px; | |
| background: white; | |
| border: none; | |
| border-radius: 50px; | |
| font-weight: 600; | |
| font-size: 1rem; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| display: flex; | |
| align-items: center; | |
| gap: 10px; | |
| box-shadow: var(--shadow); | |
| } | |
| .btn-primary { | |
| background: linear-gradient(90deg, var(--primary), var(--secondary)); | |
| color: white; | |
| } | |
| .btn-secondary { | |
| background: white; | |
| color: var(--dark); | |
| } | |
| .btn:hover { | |
| transform: translateY(-5px); | |
| box-shadow: 0 15px 30px rgba(0, 0, 0, 0.2); | |
| } | |
| .btn:active { | |
| transform: translateY(-2px); | |
| } | |
| .filter-tags { | |
| display: flex; | |
| justify-content: center; | |
| flex-wrap: wrap; | |
| gap: 10px; | |
| margin-bottom: 30px; | |
| } | |
| .tag { | |
| padding: 10px 20px; | |
| background: white; | |
| border-radius: 50px; | |
| cursor: pointer; | |
| transition: var(--transition); | |
| font-weight: 500; | |
| box-shadow: 0 5px 15px rgba(0,0,0,0.05); | |
| } | |
| .tag.active { | |
| background: linear-gradient(90deg, var(--primary), var(--secondary)); | |
| color: white; | |
| } | |
| .tag:hover { | |
| transform: translateY(-3px); | |
| } | |
| .flashcards-grid { | |
| display: grid; | |
| grid-template-columns: repeat(auto-fill, minmax(300px, 1fr)); | |
| gap: 25px; | |
| margin-bottom: 40px; | |
| } | |
| @media (max-width: 768px) { | |
| .flashcards-grid { | |
| grid-template-columns: repeat(auto-fill, minmax(280px, 1fr)); | |
| } | |
| } | |
| .flashcard { | |
| height: 320px; | |
| perspective: 1500px; | |
| cursor: pointer; | |
| } | |
| .flashcard-inner { | |
| position: relative; | |
| width: 100%; | |
| height: 100%; | |
| text-align: center; | |
| transition: var(--transition); | |
| transform-style: preserve-3d; | |
| border-radius: var(--border-radius); | |
| box-shadow: var(--shadow); | |
| } | |
| .flashcard.flipped .flashcard-inner { | |
| transform: rotateY(180deg); | |
| } | |
| .flashcard-front, .flashcard-back { | |
| position: absolute; | |
| width: 100%; | |
| height: 100%; | |
| -webkit-backface-visibility: hidden; | |
| backface-visibility: hidden; | |
| border-radius: var(--border-radius); | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: center; | |
| align-items: center; | |
| padding: 30px; | |
| } | |
| .flashcard-front { | |
| background: var(--card-front); | |
| color: white; | |
| } | |
| .flashcard-back { | |
| background: var(--card-back); | |
| color: white; | |
| transform: rotateY(180deg); | |
| } | |
| .pattern { | |
| font-size: 4rem; | |
| font-weight: bold; | |
| margin-bottom: 20px; | |
| font-family: 'Comic Sans MS', 'Chalkboard SE', cursive; | |
| text-shadow: 0 5px 15px rgba(0,0,0,0.2); | |
| } | |
| .pronunciation { | |
| font-size: 2.5rem; | |
| font-weight: bold; | |
| margin-bottom: 20px; | |
| text-shadow: 0 5px 15px rgba(0,0,0,0.2); | |
| } | |
| .hint { | |
| font-size: 1rem; | |
| opacity: 0.9; | |
| margin-top: 20px; | |
| font-style: italic; | |
| } | |
| .examples { | |
| display: flex; | |
| flex-direction: column; | |
| gap: 15px; | |
| width: 100%; | |
| margin-top: 20px; | |
| } | |
| .example-word { | |
| background: rgba(255, 255, 255, 0.2); | |
| padding: 12px; | |
| border-radius: 12px; | |
| font-size: 1.2rem; | |
| font-weight: 600; | |
| backdrop-filter: blur(10px); | |
| border: 1px solid rgba(255, 255, 255, 0.3); | |
| } | |
| .category-badge { | |
| position: absolute; | |
| top: 15px; | |
| right: 15px; | |
| background: rgba(255, 255, 255, 0.2); | |
| padding: 5px 15px; | |
| border-radius: 20px; | |
| font-size: 0.8rem; | |
| font-weight: 600; | |
| backdrop-filter: blur(5px); | |
| } | |
| .flip-icon { | |
| position: absolute; | |
| bottom: 20px; | |
| font-size: 1.5rem; | |
| opacity: 0.7; | |
| } | |
| .instructions { | |
| text-align: center; | |
| margin: 30px 0; | |
| padding: 20px; | |
| background: white; | |
| border-radius: var(--border-radius); | |
| box-shadow: var(--shadow); | |
| } | |
| .instructions p { | |
| font-size: 1.1rem; | |
| color: #666; | |
| margin-bottom: 10px; | |
| } | |
| .instructions strong { | |
| color: var(--primary); | |
| } | |
| footer { | |
| text-align: center; | |
| margin-top: 50px; | |
| padding: 20px; | |
| color: #666; | |
| font-size: 0.9rem; | |
| } | |
| .progress-container { | |
| width: 100%; | |
| max-width: 500px; | |
| height: 10px; | |
| background: #e0e0e0; | |
| border-radius: 5px; | |
| margin: 20px auto; | |
| overflow: hidden; | |
| } | |
| .progress-bar { | |
| height: 100%; | |
| background: linear-gradient(90deg, var(--primary), var(--secondary)); | |
| width: 0%; | |
| transition: width 0.5s ease; | |
| } | |
| .card-counter { | |
| position: absolute; | |
| top: 15px; | |
| left: 15px; | |
| background: rgba(0,0,0,0.2); | |
| color: white; | |
| padding: 5px 12px; | |
| border-radius: 20px; | |
| font-size: 0.9rem; | |
| font-weight: 600; | |
| } | |
| .thinking-time { | |
| margin-top: 15px; | |
| font-size: 0.9rem; | |
| opacity: 0.8; | |
| } | |
| .thinking-timer { | |
| font-weight: bold; | |
| color: #ffd166; | |
| } | |
| .completed-badge { | |
| position: absolute; | |
| top: 50%; | |
| left: 50%; | |
| transform: translate(-50%, -50%); | |
| background: rgba(255, 255, 255, 0.9); | |
| color: var(--success); | |
| padding: 10px 20px; | |
| border-radius: 50px; | |
| font-weight: bold; | |
| font-size: 1.5rem; | |
| display: none; | |
| z-index: 10; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.3); | |
| } | |
| .flashcard.completed .completed-badge { | |
| display: block; | |
| } | |
| </style> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <header> | |
| <div class="header-content"> | |
| <h1><i class="fas fa-lightbulb"></i> Phonics Flash Cards</h1> | |
| <p class="subtitle">Flip cards to reveal pronunciation and example words. Think of your own examples first!</p> | |
| <div class="stats-bar"> | |
| <div class="stat-item"> | |
| <div class="stat-number" id="totalCards">100</div> | |
| <div class="stat-label">Total Cards</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-number" id="flippedCards">0</div> | |
| <div class="stat-label">Flipped</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-number" id="completedCards">0</div> | |
| <div class="stat-label">Mastered</div> | |
| </div> | |
| <div class="stat-item"> | |
| <div class="stat-number" id="remainingCards">100</div> | |
| <div class="stat-label">Remaining</div> | |
| </div> | |
| </div> | |
| <div class="progress-container"> | |
| <div class="progress-bar" id="progressBar"></div> | |
| </div> | |
| </div> | |
| </header> | |
| <div class="instructions"> | |
| <p><strong>How to use:</strong> Look at the phonics pattern on the front of the card. Think of at least 3 words that use this pattern. Then flip the card to check the pronunciation and example words.</p> | |
| <p>Mark cards as "Mastered" when you can think of examples without flipping.</p> | |
| </div> | |
| <div class="controls"> | |
| <button class="btn btn-primary" id="flipAllBtn"> | |
| <i class="fas fa-sync-alt"></i> Flip All Back | |
| </button> | |
| <button class="btn btn-secondary" id="shuffleBtn"> | |
| <i class="fas fa-random"></i> Shuffle Cards | |
| </button> | |
| <button class="btn btn-secondary" id="resetBtn"> | |
| <i class="fas fa-redo"></i> Reset Progress | |
| </button> | |
| <button class="btn btn-secondary" id="markAllBtn"> | |
| <i class="fas fa-check-double"></i> Mark All Mastered | |
| </button> | |
| </div> | |
| <div class="filter-tags" id="filterTags"> | |
| <!-- Filter tags will be added by JavaScript --> | |
| </div> | |
| <div class="flashcards-grid" id="flashcardsGrid"> | |
| <!-- Flashcards will be added by JavaScript --> | |
| </div> | |
| <footer> | |
| <p>Phonics Flash Cards - 100 Essential 2nd Grade Patterns | Designed for Active Learning</p> | |
| <p>Try to think of your own examples before flipping each card!</p> | |
| </footer> | |
| </div> | |
| <script> | |
| // 100 Phonics Patterns - Even 100! | |
| const phonicsData = [ | |
| // Consonant Digraphs (15) | |
| { pattern: "sh", pronunciation: "shh", examples: ["ship", "wish", "shell"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "ch", pronunciation: "ch", examples: ["chat", "chip", "lunch"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "th", pronunciation: "th (soft)", examples: ["thin", "think", "bath"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "th", pronunciation: "th (hard)", examples: ["this", "that", "mother"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "wh", pronunciation: "wh", examples: ["when", "whale", "whisper"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "ph", pronunciation: "f", examples: ["phone", "graph", "elephant"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "ng", pronunciation: "ng", examples: ["song", "king", "ring"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "ck", pronunciation: "k", examples: ["duck", "clock", "sock"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "tch", pronunciation: "ch", examples: ["catch", "watch", "patch"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "dge", pronunciation: "j", examples: ["bridge", "fudge", "badge"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "gh", pronunciation: "f", examples: ["enough", "laugh", "rough"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "gn", pronunciation: "n", examples: ["gnaw", "sign", "gnome"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "kn", pronunciation: "n", examples: ["knee", "know", "knock"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "wr", pronunciation: "r", examples: ["write", "wrong", "wrap"], category: "Consonant", color: "#6a11cb" }, | |
| { pattern: "mb", pronunciation: "m", examples: ["comb", "thumb", "climb"], category: "Consonant", color: "#6a11cb" }, | |
| // Vowel Teams (30) | |
| { pattern: "ai", pronunciation: "ay", examples: ["rain", "train", "wait"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ay", pronunciation: "ay", examples: ["day", "play", "say"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ee", pronunciation: "ee", examples: ["tree", "see", "sleep"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ea", pronunciation: "ee", examples: ["eat", "sea", "team"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ie", pronunciation: "ee", examples: ["piece", "chief", "field"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "y", pronunciation: "ee", examples: ["happy", "baby", "funny"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "y", pronunciation: "eye", examples: ["cry", "fly", "my"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "igh", pronunciation: "eye", examples: ["night", "light", "high"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "oa", pronunciation: "oh", examples: ["boat", "coat", "road"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "oe", pronunciation: "oh", examples: ["toe", "hoe", "foe"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ow", pronunciation: "oh", examples: ["snow", "grow", "show"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ou", pronunciation: "ow", examples: ["out", "cloud", "found"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ow", pronunciation: "ow", examples: ["cow", "town", "down"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "oi", pronunciation: "oy", examples: ["coin", "boil", "soil"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "oy", pronunciation: "oy", examples: ["toy", "boy", "enjoy"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "oo", pronunciation: "oo (long)", examples: ["moon", "spoon", "tooth"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "oo", pronunciation: "oo (short)", examples: ["book", "look", "foot"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ew", pronunciation: "yoo", examples: ["few", "dew", "new"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ue", pronunciation: "yoo", examples: ["blue", "true", "clue"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "au", pronunciation: "aw", examples: ["haul", "autumn", "launch"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "aw", pronunciation: "aw", examples: ["saw", "draw", "claw"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ei", pronunciation: "ay", examples: ["veil", "eight", "weigh"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ey", pronunciation: "ay", examples: ["they", "prey", "grey"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ei", pronunciation: "ee", examples: ["receive", "ceiling", "deceive"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ey", pronunciation: "ee", examples: ["key", "monkey", "honey"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ie", pronunciation: "eye", examples: ["pie", "tie", "die"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ea", pronunciation: "eh", examples: ["bread", "head", "ready"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ou", pronunciation: "oo", examples: ["soup", "group", "youth"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ui", pronunciation: "oo", examples: ["fruit", "juice", "suit"], category: "Vowels", color: "#ff416c" }, | |
| { pattern: "ew", pronunciation: "oo", examples: ["blew", "grew", "flew"], category: "Vowels", color: "#ff416c" }, | |
| // Word Endings (15) | |
| { pattern: "tion", pronunciation: "shun", examples: ["action", "station", "nation"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "sion", pronunciation: "zhun", examples: ["vision", "decision", "confusion"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "sion", pronunciation: "shun", examples: ["mission", "passion", "session"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "cian", pronunciation: "shun", examples: ["musician", "magician", "physician"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "ture", pronunciation: "chur", examples: ["picture", "future", "nature"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "le", pronunciation: "ul", examples: ["table", "candle", "little"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "ous", pronunciation: "us", examples: ["famous", "nervous", "dangerous"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "cious", pronunciation: "shus", examples: ["delicious", "suspicious", "precious"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "tious", pronunciation: "shus", examples: ["ambitious", "cautious", "nutritious"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "cial", pronunciation: "shul", examples: ["special", "social", "official"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "tial", pronunciation: "shul", examples: ["partial", "essential", "initial"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "age", pronunciation: "ij", examples: ["cage", "page", "stage"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "age", pronunciation: "azh", examples: ["garage", "massage", "mirage"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "ine", pronunciation: "in", examples: ["engine", "imagine", "medicine"], category: "Endings", color: "#38ef7d" }, | |
| { pattern: "ine", pronunciation: "ine", examples: ["pine", "fine", "line"], category: "Endings", color: "#38ef7d" }, | |
| // R-Controlled (15) | |
| { pattern: "ar", pronunciation: "ar", examples: ["car", "star", "farm"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "er", pronunciation: "ur", examples: ["her", "fern", "verb"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "ir", pronunciation: "ur", examples: ["bird", "girl", "first"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "or", pronunciation: "or", examples: ["fork", "corn", "sport"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "ur", pronunciation: "ur", examples: ["burn", "turn", "surf"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "air", pronunciation: "air", examples: ["chair", "fair", "stair"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "are", pronunciation: "air", examples: ["care", "share", "dare"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "ear", pronunciation: "eer", examples: ["hear", "fear", "near"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "ear", pronunciation: "air", examples: ["bear", "wear", "pear"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "ear", pronunciation: "ur", examples: ["earth", "learn", "pearl"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "eer", pronunciation: "eer", examples: ["deer", "cheer", "peer"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "ier", pronunciation: "eer", examples: ["pier", "tier", "fierier"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "ore", pronunciation: "or", examples: ["more", "store", "before"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "ure", pronunciation: "yoor", examples: ["cure", "pure", "secure"], category: "R-Controlled", color: "#ffb347" }, | |
| { pattern: "our", pronunciation: "or", examples: ["four", "pour", "your"], category: "R-Controlled", color: "#ffb347" }, | |
| // Blends & Special (25) | |
| { pattern: "sc", pronunciation: "s", examples: ["scene", "science", "scissors"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "sch", pronunciation: "sk", examples: ["school", "scheme", "schedule"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "scr", pronunciation: "scr", examples: ["scrub", "scream", "scroll"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "shr", pronunciation: "shr", examples: ["shrink", "shred", "shrimp"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "spl", pronunciation: "spl", examples: ["splash", "split", "splinter"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "spr", pronunciation: "spr", examples: ["spring", "spray", "spread"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "squ", pronunciation: "skw", examples: ["square", "squash", "squirrel"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "str", pronunciation: "str", examples: ["string", "street", "strong"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "thr", pronunciation: "thr", examples: ["three", "throw", "thread"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "bl", pronunciation: "bl", examples: ["blue", "black", "blanket"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "cl", pronunciation: "cl", examples: ["clap", "clock", "cloud"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "fl", pronunciation: "fl", examples: ["flag", "flower", "fly"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "gl", pronunciation: "gl", examples: ["glad", "glue", "globe"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "pl", pronunciation: "pl", examples: ["play", "plant", "plane"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "sl", pronunciation: "sl", examples: ["sleep", "slide", "slow"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "br", pronunciation: "br", examples: ["bread", "brick", "brother"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "cr", pronunciation: "cr", examples: ["crab", "cry", "cross"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "dr", pronunciation: "dr", examples: ["dress", "drink", "drive"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "fr", pronunciation: "fr", examples: ["frog", "fruit", "friend"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "gr", pronunciation: "gr", examples: ["green", "grass", "grow"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "pr", pronunciation: "pr", examples: ["pray", "prince", "present"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "tr", pronunciation: "tr", examples: ["tree", "truck", "train"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "sw", pronunciation: "sw", examples: ["swim", "sweet", "swing"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "tw", pronunciation: "tw", examples: ["twin", "twelve", "twist"], category: "Blends", color: "#2575fc" }, | |
| { pattern: "qu", pronunciation: "kw", examples: ["queen", "quick", "quiet"], category: "Blends", color: "#2575fc" } | |
| ]; | |
| // App state | |
| let flashcards = []; | |
| let currentFilter = 'all'; | |
| let masteredCards = JSON.parse(localStorage.getItem('phonicsMastered')) || []; | |
| let flippedCards = JSON.parse(localStorage.getItem('phonicsFlipped')) || []; | |
| let thinkingTimers = {}; | |
| // DOM Elements | |
| const flashcardsGrid = document.getElementById('flashcardsGrid'); | |
| const filterTags = document.getElementById('filterTags'); | |
| const totalCardsEl = document.getElementById('totalCards'); | |
| const flippedCardsEl = document.getElementById('flippedCards'); | |
| const completedCardsEl = document.getElementById('completedCards'); | |
| const remainingCardsEl = document.getElementById('remainingCards'); | |
| const progressBar = document.getElementById('progressBar'); | |
| const flipAllBtn = document.getElementById('flipAllBtn'); | |
| const shuffleBtn = document.getElementById('shuffleBtn'); | |
| const resetBtn = document.getElementById('resetBtn'); | |
| const markAllBtn = document.getElementById('markAllBtn'); | |
| // Initialize app | |
| function initApp() { | |
| // Verify we have 100 cards | |
| totalCardsEl.textContent = phonicsData.length; | |
| // Initialize flashcards | |
| createFlashcards(); | |
| renderFlashcards(); | |
| renderFilterTags(); | |
| updateStats(); | |
| // Event listeners | |
| flipAllBtn.addEventListener('click', flipAllBack); | |
| shuffleBtn.addEventListener('click', shuffleFlashcards); | |
| resetBtn.addEventListener('click', resetProgress); | |
| markAllBtn.addEventListener('click', markAllMastered); | |
| } | |
| // Create flashcards from data | |
| function createFlashcards() { | |
| flashcards = phonicsData.map((item, index) => { | |
| return { | |
| id: index, | |
| pattern: item.pattern, | |
| pronunciation: item.pronunciation, | |
| examples: item.examples, | |
| category: item.category, | |
| color: item.color, | |
| isFlipped: flippedCards.includes(index), | |
| isMastered: masteredCards.includes(index) | |
| }; | |
| }); | |
| } | |
| // Render flashcards to grid | |
| function renderFlashcards() { | |
| flashcardsGrid.innerHTML = ''; | |
| const filteredCards = currentFilter === 'all' | |
| ? flashcards | |
| : flashcards.filter(card => card.category === currentFilter); | |
| filteredCards.forEach((card, index) => { | |
| const flashcard = document.createElement('div'); | |
| flashcard.className = `flashcard ${card.isFlipped ? 'flipped' : ''} ${card.isMastered ? 'completed' : ''}`; | |
| flashcard.dataset.id = card.id; | |
| // Start thinking timer when card is shown | |
| if (!thinkingTimers[card.id]) { | |
| thinkingTimers[card.id] = 0; | |
| } | |
| flashcard.innerHTML = ` | |
| <div class="card-counter">${index + 1}/${filteredCards.length}</div> | |
| <div class="completed-badge"><i class="fas fa-check-circle"></i> MASTERED</div> | |
| <div class="flashcard-inner"> | |
| <div class="flashcard-front"> | |
| <div class="category-badge">${card.category}</div> | |
| <div class="pattern">${card.pattern}</div> | |
| <div class="hint">Think of 3 words with this pattern...</div> | |
| <div class="flip-icon"><i class="fas fa-hand-point-up"></i></div> | |
| <div class="thinking-time"> | |
| Thinking time: <span class="thinking-timer" id="timer-${card.id}">0</span>s | |
| </div> | |
| </div> | |
| <div class="flashcard-back"> | |
| <div class="category-badge">${card.category}</div> | |
| <div class="pronunciation">"${card.pronunciation}"</div> | |
| <div class="examples"> | |
| ${card.examples.map(example => ` | |
| <div class="example-word">${example}</div> | |
| `).join('')} | |
| </div> | |
| <div class="hint">Did you think of these?</div> | |
| <div class="flip-icon"><i class="fas fa-undo"></i></div> | |
| </div> | |
| </div> | |
| `; | |
| // Add click event for flipping | |
| flashcard.addEventListener('click', (e) => { | |
| if (!e.target.closest('.btn')) { | |
| toggleFlashcard(card.id); | |
| } | |
| }); | |
| // Add right-click for marking as mastered | |
| flashcard.addEventListener('contextmenu', (e) => { | |
| e.preventDefault(); | |
| toggleMastered(card.id); | |
| }); | |
| flashcardsGrid.appendChild(flashcard); | |
| }); | |
| // Start thinking timers for visible cards | |
| startThinkingTimers(filteredCards); | |
| } | |
| // Start thinking timers for cards | |
| function startThinkingTimers(cards) { | |
| cards.forEach(card => { | |
| const timerElement = document.getElementById(`timer-${card.id}`); | |
| if (timerElement && !card.isFlipped && !card.isMastered) { | |
| // Update timer every second | |
| const timerInterval = setInterval(() => { | |
| thinkingTimers[card.id]++; | |
| timerElement.textContent = thinkingTimers[card.id]; | |
| // If card gets flipped or mastered, stop timer | |
| const currentCard = flashcards.find(c => c.id === card.id); | |
| if (currentCard.isFlipped || currentCard.isMastered) { | |
| clearInterval(timerInterval); | |
| } | |
| }, 1000); | |
| } | |
| }); | |
| } | |
| // Toggle flashcard flip state | |
| function toggleFlashcard(cardId) { | |
| const card = flashcards.find(c => c.id === cardId); | |
| card.isFlipped = !card.isFlipped; | |
| // Update flipped cards in localStorage | |
| if (card.isFlipped && !flippedCards.includes(cardId)) { | |
| flippedCards.push(cardId); | |
| } else if (!card.isFlipped && flippedCards.includes(cardId)) { | |
| flippedCards = flippedCards.filter(id => id !== cardId); | |
| } | |
| localStorage.setItem('phonicsFlipped', JSON.stringify(flippedCards)); | |
| // Update UI | |
| const cardElement = document.querySelector(`[data-id="${cardId}"]`); | |
| if (cardElement) { | |
| cardElement.classList.toggle('flipped'); | |
| } | |
| updateStats(); | |
| } | |
| // Toggle mastered state | |
| function toggleMastered(cardId) { | |
| const card = flashcards.find(c => c.id === cardId); | |
| card.isMastered = !card.isMastered; | |
| // Update mastered cards in localStorage | |
| if (card.isMastered && !masteredCards.includes(cardId)) { | |
| masteredCards.push(cardId); | |
| } else if (!card.isMastered && masteredCards.includes(cardId)) { | |
| masteredCards = masteredCards.filter(id => id !== cardId); | |
| } | |
| localStorage.setItem('phonicsMastered', JSON.stringify(masteredCards)); | |
| // Update UI | |
| const cardElement = document.querySelector(`[data-id="${cardId}"]`); | |
| if (cardElement) { | |
| cardElement.classList.toggle('completed'); | |
| } | |
| updateStats(); | |
| } | |
| // Flip all cards back to front | |
| function flipAllBack() { | |
| flashcards.forEach(card => { | |
| card.isFlipped = false; | |
| }); | |
| flippedCards = []; | |
| localStorage.setItem('phonicsFlipped', JSON.stringify([])); | |
| renderFlashcards(); | |
| updateStats(); | |
| } | |
| // Shuffle flashcards | |
| function shuffleFlashcards() { | |
| // Fisher-Yates shuffle | |
| for (let i = flashcards.length - 1; i > 0; i--) { | |
| const j = Math.floor(Math.random() * (i + 1)); | |
| [flashcards[i], flashcards[j]] = [flashcards[j], flashcards[i]]; | |
| } | |
| renderFlashcards(); | |
| } | |
| // Reset all progress | |
| function resetProgress() { | |
| if (confirm('Are you sure you want to reset all progress? This will unflip all cards and clear mastered status.')) { | |
| flashcards.forEach(card => { | |
| card.isFlipped = false; | |
| card.isMastered = false; | |
| }); | |
| flippedCards = []; | |
| masteredCards = []; | |
| thinkingTimers = {}; | |
| localStorage.setItem('phonicsFlipped', JSON.stringify([])); | |
| localStorage.setItem('phonicsMastered', JSON.stringify([])); | |
| renderFlashcards(); | |
| updateStats(); | |
| } | |
| } | |
| // Mark all cards as mastered | |
| function markAllMastered() { | |
| if (confirm('Mark all cards as mastered?')) { | |
| flashcards.forEach(card => { | |
| card.isMastered = true; | |
| if (!masteredCards.includes(card.id)) { | |
| masteredCards.push(card.id); | |
| } | |
| }); | |
| localStorage.setItem('phonicsMastered', JSON.stringify(masteredCards)); | |
| renderFlashcards(); | |
| updateStats(); | |
| } | |
| } | |
| // Render filter tags | |
| function renderFilterTags() { | |
| filterTags.innerHTML = ''; | |
| const categories = ['all', ...new Set(phonicsData.map(item => item.category))]; | |
| categories.forEach(category => { | |
| const tag = document.createElement('div'); | |
| tag.className = `tag ${currentFilter === category ? 'active' : ''}`; | |
| tag.textContent = category === 'all' ? 'All Cards' : category; | |
| tag.dataset.category = category; | |
| tag.addEventListener('click', () => { | |
| currentFilter = category; | |
| renderFilterTags(); | |
| renderFlashcards(); | |
| }); | |
| filterTags.appendChild(tag); | |
| }); | |
| } | |
| // Update statistics | |
| function updateStats() { | |
| const total = flashcards.length; | |
| const flipped = flashcards.filter(card => card.isFlipped).length; | |
| const completed = flashcards.filter(card => card.isMastered).length; | |
| const remaining = total - completed; | |
| flippedCardsEl.textContent = flipped; | |
| completedCardsEl.textContent = completed; | |
| remainingCardsEl.textContent = remaining; | |
| // Update progress bar | |
| const progress = (completed / total) * 100; | |
| progressBar.style.width = `${progress}%`; | |
| } | |
| // Initialize when page loads | |
| document.addEventListener('DOMContentLoaded', initApp); | |
| </script> | |
| </body> | |
| </html> |