From a89e017be775a63edfef08a036616825d7764881 Mon Sep 17 00:00:00 2001 From: Jens Mohrmann Date: Sat, 27 Dec 2025 12:45:04 +0100 Subject: [PATCH] UI improvements --- src/App.css | 40 +++- src/App.tsx | 38 ++-- src/components/Controls.tsx | 397 ++++++++++++++++++++---------------- src/index.css | 18 +- src/styles/variables.css | 9 +- 5 files changed, 290 insertions(+), 212 deletions(-) diff --git a/src/App.css b/src/App.css index dec5658..9259f2c 100644 --- a/src/App.css +++ b/src/App.css @@ -10,7 +10,7 @@ display: flex; justify-content: space-between; align-items: center; - padding: var(--spacing-md) var(--spacing-xl); + padding: var(--spacing-sm) var(--spacing-xl); background-color: var(--color-surface); box-shadow: var(--shadow-sm); } @@ -183,22 +183,49 @@ button { background-color: var(--color-surface); padding: var(--spacing-md); display: flex; - justify-content: center; + flex-direction: column; + align-items: center; + gap: var(--spacing-md); border-top: 1px solid rgba(0, 0, 0, 0.05); } .controls-container { display: flex; - gap: var(--spacing-xl); - align-items: flex-end; - flex-wrap: wrap; - justify-content: center; + flex-direction: column; + gap: var(--spacing-lg); + width: 100%; + max-width: 800px; +} + +.settings-grid { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--spacing-md); + width: 100%; +} + +.tools-grid { + display: grid; + grid-template-columns: repeat(3, 1fr); + gap: var(--spacing-md); + width: 100%; + align-items: start; +} + +/* Mobile: Stack everything */ +@media (max-width: 600px) { + + .settings-grid, + .tools-grid { + grid-template-columns: 1fr; + } } .control-group { display: flex; flex-direction: column; gap: var(--spacing-xs); + width: 100%; } .control-label { @@ -441,7 +468,6 @@ button { font-size: 0.8rem; font-weight: 500; color: var(--color-text-muted); - margin-top: -4px; } .app-subtitle a { diff --git a/src/App.tsx b/src/App.tsx index 60d3910..d958b85 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -48,7 +48,8 @@ function App() { zenMode: false, gameMode: 'sight_reading', customMinFret: 0, - customMaxFret: 12 + customMaxFret: 12, + autoPlaySightReading: false }); const [matchStartTime, setMatchStartTime] = useState(null); @@ -154,14 +155,16 @@ function App() { // Audio Playback trigger useEffect(() => { - if (settings.gameMode === 'ear_training' && !revealed) { + const shouldAutoPlay = settings.gameMode === 'ear_training' || (settings.gameMode === 'sight_reading' && settings.autoPlaySightReading); + + if (shouldAutoPlay && !revealed) { // Add a small delay to ensure state settles or allow UI to update const timer = setTimeout(() => { playNote(targetMidi, 1.0); // Play for 1 second }, 100); return () => clearTimeout(timer); } - }, [targetMidi, settings.gameMode, revealed, playNote]); + }, [targetMidi, settings.gameMode, settings.autoPlaySightReading, revealed, playNote]); // Initial note, and whenever difficulty/tuning/gamemode changes useEffect(() => { @@ -309,9 +312,6 @@ function App() {
Sheet music trainer
-
- jensmohrmann.de -
@@ -368,18 +368,7 @@ function App() {
)} - {settings.gameMode === 'ear_training' && !settings.zenMode && ( -
- -
- )} + {settings.showHint && (
@@ -404,6 +393,16 @@ function App() { {settings.showHint ? "Hide Hint" : "Show Hint"} + + +
- {settings.rhythm.active && ( -
-
- - -
+ {/* Row 2, Col 2 */} +
+ + +
- {settings.rhythm.mode === 'bpm' ? ( -
- {settings.rhythm.bpm} BPM + {/* Row 3: Fret Range (Full Width) */} + {currentInstrumentDef.ranges.find(r => r.id === settings.difficulty)?.type === 'custom_fret' && ( +
+ +
+
+ Min updateRhythm({ bpm: Number(e.target.value) })} - style={{ flex: 1 }} + type="number" + min="0" + max="24" + value={settings.customMinFret ?? 0} + onChange={(e) => onUpdateSettings({ ...settings, customMinFret: parseInt(e.target.value) || 0 })} + className="control-input" + style={{ width: '100%', padding: '4px', borderRadius: '4px', border: '1px solid rgba(255,255,255,0.2)', background: 'rgba(0,0,0,0.2)', color: 'white' }} />
- ) : ( -
- {settings.rhythm.seconds}s +
+ Max updateRhythm({ seconds: Number(e.target.value) })} - style={{ flex: 1 }} + type="number" + min="0" + max="24" + value={settings.customMaxFret ?? 12} + onChange={(e) => onUpdateSettings({ ...settings, customMaxFret: parseInt(e.target.value) || 0 })} + className="control-input" + style={{ width: '100%', padding: '4px', borderRadius: '4px', border: '1px solid rgba(255,255,255,0.2)', background: 'rgba(0,0,0,0.2)', color: 'white' }} />
- )} - -
- - -
)}
-
- - + + {/* Bottom Section: Tools Grid (3 Columns) */} +
+ {/* Tool 1: Tuner */} +
+
+ + +
+
+ + {/* Tool 2: Metronome */} +
+
+ + +
+ + {settings.rhythm.active && ( +
+
+ + +
+ + {settings.rhythm.mode === 'bpm' ? ( +
+ {settings.rhythm.bpm} + updateRhythm({ bpm: Number(e.target.value) })} + style={{ flex: 1 }} + /> +
+ ) : ( +
+ {settings.rhythm.seconds}s + updateRhythm({ seconds: Number(e.target.value) })} + style={{ flex: 1 }} + /> +
+ )} + +
+ + + +
+
+ )} +
+ + {/* Tool 3: Auto-play */} + {settings.gameMode === 'sight_reading' ? ( +
+
+ + +
+
+ ) : ( +
/* Empty placeholder for grid 3rd column if not sight reading? Or just 2 cols? */ + )}
- -
); }; diff --git a/src/index.css b/src/index.css index 08a3ac9..1b81f90 100644 --- a/src/index.css +++ b/src/index.css @@ -15,11 +15,13 @@ a { font-weight: 500; - color: #646cff; + color: inherit; text-decoration: inherit; } + a:hover { - color: #535bf2; + text-decoration: underline; + color: inherit; } body { @@ -46,12 +48,14 @@ button { cursor: pointer; transition: border-color 0.25s; } + button:hover { - border-color: #646cff; + border-color: #333; } + button:focus, button:focus-visible { - outline: 4px auto -webkit-focus-ring-color; + outline: 4px auto #333; } @media (prefers-color-scheme: light) { @@ -59,10 +63,12 @@ button:focus-visible { color: #213547; background-color: #ffffff; } + a:hover { - color: #747bff; + color: #333; } + button { background-color: #f9f9f9; } -} +} \ No newline at end of file diff --git a/src/styles/variables.css b/src/styles/variables.css index e87b7ed..647b2e8 100644 --- a/src/styles/variables.css +++ b/src/styles/variables.css @@ -13,9 +13,9 @@ /* Warm paper-like bg */ --color-surface: hsl(0, 0%, 100%); - /* Deep Classic Red */ - --color-primary: hsl(var(--hue-primary), 65%, 40%); - --color-primary-dark: hsl(var(--hue-primary), 65%, 30%); + /* Neutral / Black Accent */ + --color-primary: hsl(0, 0%, 20%); + --color-primary-dark: hsl(0, 0%, 0%); --color-text-main: hsl(var(--hue-text), 10%, 20%); --color-text-muted: hsl(var(--hue-text), 5%, 60%); @@ -58,6 +58,9 @@ --color-surface: hsl(30, 20%, 15%); --color-text-main: hsl(30, 10%, 90%); --color-text-muted: hsl(30, 10%, 60%); + /* In dark mode, 'primary' (black) matches background too much, so we invert or use white */ + --color-primary: hsl(0, 0%, 90%); + --color-primary-dark: hsl(0, 0%, 100%); } }