phonics / index.html
AptlyDigital's picture
Update index.html
b50bc23 verified
<!DOCTYPE html>
<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>