From 8f216e93c6893eba66e9c60ed84c817abbd86050 Mon Sep 17 00:00:00 2001 From: Stephanie Gredell Date: Mon, 8 Dec 2025 19:52:16 -0800 Subject: [PATCH] swap speech sounds to tailwind --- frontend/src/pages/SpeechSoundsApp.css | 445 ------------------------- frontend/src/pages/SpeechSoundsApp.tsx | 146 +++++--- 2 files changed, 98 insertions(+), 493 deletions(-) delete mode 100644 frontend/src/pages/SpeechSoundsApp.css diff --git a/frontend/src/pages/SpeechSoundsApp.css b/frontend/src/pages/SpeechSoundsApp.css deleted file mode 100644 index e10fef8..0000000 --- a/frontend/src/pages/SpeechSoundsApp.css +++ /dev/null @@ -1,445 +0,0 @@ -.speech-sounds-app { - min-height: calc(100vh - 60px); - background: var(--background); - padding: 24px; - max-width: 900px; - margin: 0 auto; -} - -.app-header { - text-align: center; - margin-bottom: 32px; -} - -.app-header h1 { - margin: 0 0 12px 0; - font-size: 42px; - font-weight: 800; - color: var(--primary); - background: linear-gradient(135deg, var(--primary) 0%, var(--accent) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.app-header p { - margin: 0; - font-size: 18px; - color: var(--foreground); - font-weight: 600; - opacity: 0.8; -} - -.back-to-groups-button { - margin-bottom: 16px; - padding: 12px 24px; - background: var(--card); - border: 3px solid var(--primary); - border-radius: 20px; - color: var(--primary); - font-size: 16px; - font-weight: 700; - cursor: pointer; - transition: all 0.3s; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); -} - -.back-to-groups-button:hover { - background: var(--primary); - color: var(--primary-foreground); - transform: translateY(-2px); - box-shadow: 0 6px 12px rgba(255, 107, 157, 0.3); -} - -.groups-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(250px, 1fr)); - gap: 24px; - margin-top: 32px; -} - -.group-card { - background: var(--card); - border: 4px solid var(--primary); - border-radius: 24px; - padding: 32px 24px; - text-align: center; - cursor: pointer; - transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); - text-decoration: none; - color: var(--foreground); - box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); - position: relative; - overflow: hidden; -} - -.group-card::before { - content: ""; - position: absolute; - top: -50%; - left: -50%; - width: 200%; - height: 200%; - background: radial-gradient( - circle, - rgba(255, 107, 157, 0.1) 0%, - transparent 70% - ); - opacity: 0; - transition: opacity 0.3s; -} - -.group-card:hover { - transform: translateY(-8px) scale(1.05); - box-shadow: 0 12px 32px rgba(255, 107, 157, 0.3); - border-color: var(--secondary); -} - -.group-card:hover::before { - opacity: 1; -} - -.group-card-name { - margin: 0 0 8px 0; - font-size: 28px; - font-weight: 800; - color: var(--primary); - background: linear-gradient(135deg, var(--primary) 0%, var(--accent) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - position: relative; - z-index: 1; -} - -.group-card-count { - margin: 0; - font-size: 18px; - color: var(--muted-foreground); - font-weight: 700; - position: relative; - z-index: 1; -} - -.practice-area { - background: var(--card); - border-radius: 32px; - padding: 40px; - box-shadow: 0 8px 32px rgba(0, 0, 0, 0.1); - border: 4px solid var(--primary); -} - -.word-display { - text-align: center; - margin-bottom: 40px; -} - -.word-text { - font-size: 72px; - font-weight: 900; - color: var(--primary); - background: linear-gradient(135deg, var(--primary) 0%, var(--accent) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; - margin: 0 0 20px 0; - letter-spacing: 4px; - animation: wordBounce 0.5s ease-out; -} - -@keyframes wordBounce { - 0%, - 100% { - transform: scale(1); - } - 50% { - transform: scale(1.1); - } -} - -.practice-stats { - display: flex; - justify-content: center; - gap: 20px; - margin-top: 20px; - flex-wrap: wrap; -} - -.stat-item { - font-size: 18px; - font-weight: 700; - padding: 12px 20px; - border-radius: 25px; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); - border: 3px solid; -} - -.stat-pass { - background: #10b981; - border-color: #10b981; - color: white; -} - -.stat-fail { - background: #ef4444; - border-color: #ef4444; - color: white; -} - -.stat-total { - background: var(--secondary); - border-color: var(--secondary); - color: var(--secondary-foreground); -} - -.practice-container { - margin-bottom: 32px; -} - -.practice-label { - text-align: center; - font-size: 20px; - font-weight: 700; - color: var(--foreground); - margin-bottom: 24px; -} - -.practice-grid { - display: grid; - grid-template-columns: repeat(5, 1fr); - gap: 16px; - margin: 0 auto; -} - -.practice-item { - display: flex; - flex-direction: column; - align-items: center; - gap: 12px; - padding: 20px 16px; - border: 3px solid var(--border); - border-radius: 20px; - background: var(--card); - transition: all 0.3s; -} - -.practice-item:hover { - transform: translateY(-4px); - box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); - border-color: var(--primary); -} - -.practice-number { - font-size: 16px; - font-weight: 700; - color: var(--primary-foreground); - width: 40px; - height: 40px; - display: flex; - align-items: center; - justify-content: center; - border-radius: 50%; - background: var(--primary); - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); -} - -.practice-buttons { - display: flex; - gap: 10px; -} - -.practice-button { - width: 44px; - height: 44px; - border: 3px solid; - border-radius: 12px; - background: white; - font-size: 24px; - font-weight: bold; - cursor: pointer; - transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); - display: flex; - align-items: center; - justify-content: center; - box-shadow: 0 4px 8px rgba(0, 0, 0, 0.1); -} - -.practice-button:hover { - transform: scale(1.15); -} - -.pass-button { - color: #065f46; - border-color: #10b981; -} - -.pass-button:hover { - background: #10b981; - border-color: #10b981; - color: white; - box-shadow: 0 6px 12px rgba(16, 185, 129, 0.3); -} - -.pass-button.active { - background: #10b981; - color: white; - border-color: #10b981; - transform: scale(1.1); - box-shadow: 0 6px 16px rgba(16, 185, 129, 0.4); -} - -.fail-button { - color: #991b1b; - border-color: #ef4444; -} - -.fail-button:hover { - background: #ef4444; - border-color: #ef4444; - color: white; - box-shadow: 0 6px 12px rgba(239, 68, 68, 0.3); -} - -.fail-button.active { - background: #ef4444; - color: white; - border-color: #ef4444; - transform: scale(1.1); - box-shadow: 0 6px 16px rgba(239, 68, 68, 0.4); -} - -.word-navigation { - display: flex; - justify-content: space-between; - align-items: center; - margin-bottom: 24px; - padding-top: 24px; - border-top: 3px dashed #e0e0e0; -} - -.nav-button { - padding: 16px 32px; - background: var(--primary); - color: var(--primary-foreground); - border: 3px solid var(--primary); - border-radius: 25px; - font-size: 18px; - font-weight: 700; - cursor: pointer; - transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); - box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1); -} - -.nav-button:hover:not(:disabled) { - transform: translateY(-4px) scale(1.05); - box-shadow: 0 8px 20px rgba(255, 107, 157, 0.4); - border-color: var(--secondary); -} - -.nav-button:disabled { - opacity: 0.4; - cursor: not-allowed; - transform: none; -} - -.word-counter { - font-size: 20px; - color: var(--secondary-foreground); - font-weight: 700; - padding: 12px 24px; - background: var(--secondary); - border-radius: 20px; - border: 3px solid var(--secondary); - box-shadow: 0 4px 8px rgba(255, 165, 0, 0.3); -} - -.word-actions { - text-align: center; -} - -.reset-button { - padding: 12px 24px; - background: var(--card); - color: #ef4444; - border: 3px solid #ef4444; - border-radius: 20px; - font-size: 16px; - font-weight: 700; - cursor: pointer; - transition: all 0.3s; - box-shadow: 0 4px 8px rgba(239, 68, 68, 0.2); -} - -.reset-button:hover { - background: #ef4444; - color: white; - transform: translateY(-2px); - box-shadow: 0 6px 12px rgba(239, 68, 68, 0.3); -} - -.loading-state, -.error-state, -.empty-state { - text-align: center; - padding: 48px 24px; - background: var(--card); - border-radius: 24px; - margin-top: 32px; - border: 4px solid var(--primary); - box-shadow: 0 8px 16px rgba(0, 0, 0, 0.1); -} - -.empty-state h2 { - margin: 0 0 12px 0; - font-size: 32px; - color: var(--primary); - font-weight: 800; - background: linear-gradient(135deg, var(--primary) 0%, var(--accent) 100%); - -webkit-background-clip: text; - -webkit-text-fill-color: transparent; - background-clip: text; -} - -.empty-state p { - margin: 0; - color: var(--muted-foreground); - font-size: 18px; - font-weight: 600; -} - -@media (max-width: 768px) { - .speech-sounds-app { - padding: 16px; - } - - .word-text { - font-size: 48px; - } - - .practice-grid { - grid-template-columns: repeat(3, 1fr); - gap: 12px; - } - - .practice-stats { - gap: 12px; - } - - .stat-item { - font-size: 14px; - padding: 6px 12px; - } - - .practice-area { - padding: 24px; - } - - .word-navigation { - flex-direction: column; - gap: 16px; - } - - .nav-button { - width: 100%; - } -} diff --git a/frontend/src/pages/SpeechSoundsApp.tsx b/frontend/src/pages/SpeechSoundsApp.tsx index bd239c5..9cc88e1 100644 --- a/frontend/src/pages/SpeechSoundsApp.tsx +++ b/frontend/src/pages/SpeechSoundsApp.tsx @@ -1,6 +1,5 @@ import { useState, useEffect } from 'react'; import { wordGroupsApi } from '../services/apiClient'; -import './SpeechSoundsApp.css'; interface Word { id: number; @@ -128,9 +127,9 @@ export function SpeechSoundsApp() { if (loading) { return ( -
-
-

Loading word groups...

+
+
+

Loading word groups...

); @@ -138,9 +137,9 @@ export function SpeechSoundsApp() { if (error) { return ( -
-
-

Error: {error}

+
+
+

Error: {error}

); @@ -148,10 +147,12 @@ export function SpeechSoundsApp() { if (groups.length === 0) { return ( -
-
-

No Word Groups Available

-

Please add word groups in the admin panel.

+
+
+

+ No Word Groups Available +

+

Please add word groups in the admin panel.

); @@ -160,53 +161,80 @@ export function SpeechSoundsApp() { // Show word practice screen if group is selected if (showWordPractice && selectedGroup && currentWord) { return ( -
-
- -

{selectedGroup.name}

-

Practice your speech sounds by checking off each time you say the word

+

+ {selectedGroup.name} +

+

+ Practice your speech sounds by checking off each time you say the word +

-
-
-

{currentWord.word}

-
- +
+
+

+ {currentWord.word} +

+
+ ✓ {passCount} Pass - + ✗ {failCount} Fail - + {totalCount} / 10 Total
-
-
Mark each practice attempt:
-
+
+
Mark each practice attempt:
+
{Array.from({ length: 10 }, (_, i) => { const result = practiceResults[i]; const isPass = result === 'pass'; const isFail = result === 'fail'; return ( -
- {i + 1} -
+
+ + {i + 1} + +
-
+
- + Word {currentWordIndex + 1} of {selectedGroup.words.length}
-
+
+ +
); } // Show group selection screen return ( -
-
-

Speech Sounds Practice

-

Choose a word group to start practicing

+
+
+

+ Speech Sounds Practice +

+

+ Choose a word group to start practicing +

{groups.length === 0 ? ( -
-

No Word Groups Available

-

Please add word groups in the admin panel.

+
+

+ No Word Groups Available +

+

Please add word groups in the admin panel.

) : ( -
+
{groups.map(group => ( ))}