From 5df0edbc8aa3c19dcbfe154653dc97ed1bff37a1 Mon Sep 17 00:00:00 2001 From: Pedram Amini Date: Sun, 21 Dec 2025 16:09:13 -0600 Subject: [PATCH] ## CHANGES MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Added Windows-path truncation coverage so session lists display correctly everywhere 🪟 - Improved code-fence language parsing to support C++ mapping to cpp 🧠 - Refined About modal stats copy with clearer “Hands-on Time” labeling ⏱️ - Simplified mobile connection timeout typing for safer browser compatibility 🔧 - Centralized haptic triggering into shared constants for cleaner reuse 📦 - Upgraded haptics detection to verify vibrate is an actual function 📳 - Tuned input-mode toggle haptics to a crisp light vibration duration 🎚️ - Strengthened interrupt button feedback with consistent strong haptic pulses 🛑 - Removed redundant default export bundle from CommandInputButtons module 🧹 - Expanded test suite to catch edge cases across platforms and languages ✅ --- .../web/mobile/AllSessionsView.test.tsx | 8 +++++ .../web/mobile/ResponseViewer.test.tsx | 14 ++++++++ src/renderer/components/AboutModal.tsx | 2 +- src/web/mobile/App.tsx | 2 +- src/web/mobile/CommandInputButtons.tsx | 33 +++---------------- src/web/mobile/constants.ts | 2 +- 6 files changed, 29 insertions(+), 32 deletions(-) diff --git a/src/__tests__/web/mobile/AllSessionsView.test.tsx b/src/__tests__/web/mobile/AllSessionsView.test.tsx index 51eef995..1f5a7a41 100644 --- a/src/__tests__/web/mobile/AllSessionsView.test.tsx +++ b/src/__tests__/web/mobile/AllSessionsView.test.tsx @@ -239,6 +239,14 @@ describe('AllSessionsView', () => { expect(screen.getByText(/.+\/src\/components/)).toBeInTheDocument(); }); + it('handles windows paths when truncating', () => { + const windowsPath = 'C:\\Users\\dev\\project\\src\\components'; + const sessions = [createMockSession({ cwd: windowsPath })]; + render(); + + expect(screen.getByText('...\\src\\components')).toBeInTheDocument(); + }); + it('truncates paths with only two components properly', () => { const twoPartPath = 'a'.repeat(50); // Very long single-part path const sessions = [createMockSession({ cwd: twoPartPath })]; diff --git a/src/__tests__/web/mobile/ResponseViewer.test.tsx b/src/__tests__/web/mobile/ResponseViewer.test.tsx index df2d2ee5..50302520 100644 --- a/src/__tests__/web/mobile/ResponseViewer.test.tsx +++ b/src/__tests__/web/mobile/ResponseViewer.test.tsx @@ -429,6 +429,20 @@ describe('ResponseViewer', () => { expect(highlighter).toHaveAttribute('data-language', 'bash'); }); + it('handles languages with non-word characters (c++)', () => { + const textWithCode = '```c++\nint main() { return 0; }\n```'; + render( + + ); + const highlighter = screen.getByTestId('syntax-highlighter'); + expect(highlighter).toHaveAttribute('data-language', 'cpp'); + expect(screen.getByText('cpp')).toBeInTheDocument(); + }); + it('handles empty code blocks gracefully', () => { const textWithEmptyBlock = 'Text before\n```\n \n```\nText after'; render( diff --git a/src/renderer/components/AboutModal.tsx b/src/renderer/components/AboutModal.tsx index 27c7e4b7..7ef65290 100644 --- a/src/renderer/components/AboutModal.tsx +++ b/src/renderer/components/AboutModal.tsx @@ -270,7 +270,7 @@ export function AboutModal({ theme, sessions, autoRunStats, onClose, onOpenLeade {(totalActiveTimeMs > 0 || globalStats.hasCostData) && (
{totalActiveTimeMs > 0 && ( - {formatDuration(totalActiveTimeMs)} + Hands-on Time: {formatDuration(totalActiveTimeMs)} )} {!totalActiveTimeMs && globalStats.hasCostData && ( Total Cost diff --git a/src/web/mobile/App.tsx b/src/web/mobile/App.tsx index 93230ac4..95a1eb2b 100644 --- a/src/web/mobile/App.tsx +++ b/src/web/mobile/App.tsx @@ -479,7 +479,7 @@ export default function MobileApp() { // On mobile browsers, ensure the document is fully loaded before connecting // to avoid race conditions with __MAESTRO_CONFIG__ injection useEffect(() => { - let timeoutId: ReturnType | null = null; + let timeoutId: number | null = null; let cancelled = false; const scheduleAttempt = (delay: number) => { diff --git a/src/web/mobile/CommandInputButtons.tsx b/src/web/mobile/CommandInputButtons.tsx index 60009d66..b49db4b0 100644 --- a/src/web/mobile/CommandInputButtons.tsx +++ b/src/web/mobile/CommandInputButtons.tsx @@ -17,6 +17,7 @@ import React from 'react'; import { useThemeColors } from '../components/ThemeProvider'; import type { InputMode } from './CommandInputBar'; +import { triggerHaptic } from './constants'; /** Minimum touch target size per Apple HIG guidelines (44pt) */ const MIN_TOUCH_TARGET = 44; @@ -24,24 +25,6 @@ const MIN_TOUCH_TARGET = 44; /** Default minimum height for the buttons */ const MIN_INPUT_HEIGHT = 48; -/** - * Trigger haptic feedback using the Vibration API - */ -function triggerHapticFeedback(pattern: 'light' | 'medium' | 'strong' | number = 'medium'): void { - if (typeof navigator !== 'undefined' && 'vibrate' in navigator) { - const duration = - pattern === 'light' ? 10 : - pattern === 'medium' ? 25 : - pattern === 'strong' ? 50 : - pattern; - try { - navigator.vibrate(duration); - } catch { - // Silently fail if vibration is not allowed - } - } -} - /** * Common base styles for all input bar buttons */ @@ -88,7 +71,7 @@ export function InputModeToggleButton({ const isAiMode = inputMode === 'ai'; const handleClick = () => { - triggerHapticFeedback('light'); + triggerHaptic(10); onModeToggle(); }; @@ -334,7 +317,7 @@ export function SendInterruptButton({ const colors = useThemeColors(); const handleInterrupt = () => { - triggerHapticFeedback('strong'); + triggerHaptic(50); onInterrupt(); }; @@ -444,7 +427,7 @@ export function ExpandedModeSendInterruptButton({ const colors = useThemeColors(); const handleInterrupt = () => { - triggerHapticFeedback('strong'); + triggerHaptic(50); onInterrupt(); }; @@ -530,11 +513,3 @@ export function ExpandedModeSendInterruptButton({ ); } - -export default { - InputModeToggleButton, - VoiceInputButton, - SlashCommandButton, - SendInterruptButton, - ExpandedModeSendInterruptButton, -}; diff --git a/src/web/mobile/constants.ts b/src/web/mobile/constants.ts index d24c978b..b80011f7 100644 --- a/src/web/mobile/constants.ts +++ b/src/web/mobile/constants.ts @@ -84,7 +84,7 @@ export function isMobileViewport(): boolean { */ export function supportsHaptics(): boolean { if (typeof window === 'undefined') return false; - return 'vibrate' in navigator; + return typeof navigator.vibrate === 'function'; } /**