From 7a272175d9c680aa51a48184c5e2b1a24c65a44e Mon Sep 17 00:00:00 2001 From: Jens Mohrmann Date: Tue, 30 Dec 2025 20:11:08 +0100 Subject: [PATCH] Improve mobile UI (resizing) --- src/App.css | 103 ++++++++++++++++++++----------- src/App.tsx | 12 +++- src/components/SettingsModal.tsx | 26 +++++++- 3 files changed, 103 insertions(+), 38 deletions(-) diff --git a/src/App.css b/src/App.css index ec8dff6..35c6db3 100644 --- a/src/App.css +++ b/src/App.css @@ -1,9 +1,11 @@ /* App.css */ .app-container { - display: flex; - flex-direction: column; + display: block; + /* Changed from flex to allow natural document flow */ min-height: 100vh; background-color: var(--color-bg); + overflow-x: hidden; + max-width: 100vw; } .app-header { @@ -38,13 +40,16 @@ } .main-stage { - flex: 1; + /* Natural height - not flex to prevent shrinking when footer is present */ display: flex; flex-direction: column; align-items: center; - justify-content: center; + justify-content: flex-start; padding: var(--spacing-md); gap: var(--spacing-xl); + overflow-x: hidden; + max-width: 100%; + box-sizing: border-box; } .card { @@ -58,6 +63,8 @@ width: 100%; max-width: 600px; transition: max-width 0.3s cubic-bezier(0.25, 0.8, 0.25, 1), transform 0.2s ease; + box-sizing: border-box; + overflow-x: hidden; } .card.has-hint { @@ -357,7 +364,8 @@ button { background-color: transparent; border: 2px solid var(--color-primary); color: var(--color-primary); - padding: 0.5rem 1rem; + padding: 0.4rem 0.8rem; + /* Compact padding by default */ border-radius: 30px; font-weight: 600; cursor: pointer; @@ -365,7 +373,8 @@ button { align-items: center; gap: 8px; transition: all 0.2s; - font-size: 0.9rem; + font-size: 0.8rem; + /* Compact font size by default */ } .hint-button:hover { @@ -387,7 +396,8 @@ button { background-color: transparent; border: 2px solid var(--color-text-muted); color: var(--color-text-muted); - padding: 0.5rem 1rem; + padding: 0.4rem 0.8rem; + /* Compact padding by default */ border-radius: 30px; font-weight: 600; cursor: pointer; @@ -395,7 +405,8 @@ button { align-items: center; gap: 8px; transition: all 0.2s; - font-size: 0.9rem; + font-size: 0.8rem; + /* Compact font size by default */ } .zen-button:hover { @@ -608,6 +619,20 @@ button { .header-controls { gap: 4px; } + + /* Fix action row overflow on narrow screens */ + .action-row { + flex-wrap: wrap; + gap: 8px !important; + padding: 0 8px; + max-width: 100%; + box-sizing: border-box; + } + + /* Reduce card padding on mobile */ + .card { + padding: var(--spacing-md); + } } .toggle-option.active { @@ -653,26 +678,29 @@ button { .main-stage { padding: 0; + display: flex; flex-direction: column; align-items: center; - justify-content: center; - /* Center vertically */ + justify-content: flex-start; gap: 0; - /* Allow scrolling */ - height: auto; - min-height: 100vh; - overflow-y: auto; - display: block; + height: 100vh; + overflow: hidden; + /* Prevent scroll - fit everything on one screen */ } .card.sheet-music-card { max-width: 100%; width: 100%; - min-height: 100vh; + height: 100vh; + /* Fit within viewport */ + max-height: 100vh; margin: 0; border-radius: 0; align-items: stretch; box-sizing: border-box; + overflow: hidden; + display: flex; + flex-direction: column; } /* Staff Row: Horizontal Layout for Staff + Note Name */ @@ -701,10 +729,11 @@ button { .sheet-music-container { width: 100%; flex: 0 0 auto; - min-height: 180px; - /* Increased from 150px */ - transform: scale(1.1); - /* Scale UP */ + min-height: 120px; + /* Reduced to allow more space for fretboard */ + max-height: 180px; + transform: scale(1.0); + /* No scaling to prevent overflow */ transform-origin: center center; justify-content: center; margin-bottom: 0; @@ -747,14 +776,17 @@ button { transform: none; max-width: none; width: 100%; - flex-grow: 1; + flex: 1; + /* Take remaining space */ display: flex; align-items: center; justify-content: center; background: #2a2a2a; - /* distinct bg for full width feel */ - min-height: 200px; - padding: 10px 0; + min-height: 100px; + /* Reduced to fit on screen */ + max-height: 50vh; + /* Limit height */ + padding: 5px 0; } /* Hide Instruction Text ("Play note above") */ @@ -784,32 +816,33 @@ button { text-shadow: 0 2px 4px rgba(0, 0, 0, 0.5); } - /* Push settings way down so they don't interfere with main view */ + /* Hide settings footer in landscape - accessible via settings modal */ .settings-footer { - margin-top: 50px; - padding-bottom: 50px; + display: none; } - /* Make main stage scrollable to reach settings */ + /* App container in landscape */ .app-container { - overflow-y: auto; + overflow: hidden; height: 100vh; - display: block; - /* Break flex height lock */ } .action-row { - margin-top: 20px !important; + margin-top: 5px !important; width: 100%; - padding: 20px; + max-width: 100vw; + padding: 5px; position: static; - /* Flow naturally below */ display: flex; flex-direction: row; + flex-wrap: wrap; justify-content: center; - gap: 16px; + gap: 8px; background: var(--color-bg); pointer-events: auto; + box-sizing: border-box; + flex-shrink: 0; + /* Don't shrink */ } .action-row button { diff --git a/src/App.tsx b/src/App.tsx index baacddc..0887ce6 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -75,6 +75,15 @@ function App() { const [hoveredMidi, setHoveredMidi] = useState(null); const feedbackTimeoutRef = useRef | null>(null); const [isFullscreen, setIsFullscreen] = useState(false); + const [windowWidth, setWindowWidth] = useState(window.innerWidth); + + useEffect(() => { + const handleResize = () => { + setWindowWidth(window.innerWidth); + }; + window.addEventListener('resize', handleResize); + return () => window.removeEventListener('resize', handleResize); + }, []); useEffect(() => { const handleFullscreenChange = () => { @@ -485,7 +494,7 @@ function App() { keySignature={settings.keySignature} clef={activeClef} transpose={activeTranspose} - width={Math.min(window.innerWidth - 40, 500)} + width={Math.min(windowWidth - 40, 500)} height={activeClef === 'grand' ? 260 : 180} hideTargetNote={settings.gameMode === 'ear_training' && !revealed} hoverMidi={settings.showHint ? hoveredMidi : null} @@ -708,6 +717,7 @@ function App() { audioLevel={audioLevel} debugInfo={debugInfo} isListening={isListening} + onMicToggle={() => setListening(l => !l)} /> void; } // Level meter component @@ -58,7 +59,8 @@ export const SettingsModal: React.FC = ({ onUpdateSettings, audioLevel = 0, debugInfo, - isListening = false + isListening = false, + onMicToggle }) => { const [showDebugInfo, setShowDebugInfo] = useState(false); @@ -166,6 +168,26 @@ export const SettingsModal: React.FC = ({
+ {/* Microphone Toggle */} +
+
+ + +
+

+ {isListening ? 'Microphone is active and listening for notes.' : 'Enable microphone to detect your playing.'} +

+
+ {/* Mic Sensitivity */}