diff --git a/LOTUS_BUGS.md b/LOTUS_BUGS.md index be7b3f696..14ae6251d 100644 --- a/LOTUS_BUGS.md +++ b/LOTUS_BUGS.md @@ -19,10 +19,10 @@ This document tracks identified bugs, edge cases, and architectural discrepancie ### 2. Chat Background Animation Flickering - **File:** `cinny/src/app/features/lotus/chatBackground.ts` -- **Status:** **OPEN** +- **Status:** **FIXED ⚠️ UNTESTED** — needs verification on a real device with an animated background active - **Issue:** Animated background properties cause visible flickering on message text and the composer area, particularly on browsers/GPUs susceptible to repaint-induced artifacts. - **Root Cause:** Animation triggers excessive repaints or layout recalculations on descendant elements, likely due to animating non-GPU accelerated properties on parent containers without proper rendering context isolation. -- **Proposed Fix:** Promote background container to a compositor layer using `will-change: transform`, strictly limit animations to `transform` and `opacity` properties, and utilize `contain: paint;` to isolate the background rendering context. +- **Fix Applied:** `getChatBg()` now injects `willChange: 'background-position'` and `contain: 'paint'` for any animated variant. This promotes the element to its own compositor layer and isolates repaints from descendants. Background-position animation is already GPU-hinted on modern browsers; `contain: paint` prevents descendant elements from being invalidated during each frame. ### 3. Avatar Decorations in Element Call @@ -60,7 +60,7 @@ This document tracks identified bugs, edge cases, and architectural discrepancie ### 6. Exclusive Background vs. Seasonal Choice - **File:** `cinny/src/app/state/settings.ts` -- **Status:** **FIXED** +- **Status:** **FIXED ⚠️ UNTESTED** — needs verification: (a) pick a background, confirm seasonal theme auto-clears; (b) pick a seasonal theme, confirm background auto-clears; (c) set both via old localStorage data and reload, confirm SeasonalEffect guard suppresses the overlay - **Issue:** Concurrent application of both Chat Backgrounds and Seasonal Themes causes visual clutter and high GPU usage. - **Root Cause:** These are currently handled as independent settings in the `settingsAtom` and applied simultaneously without mutual exclusion. - **Fix Applied:** Mutual exclusion enforced at two layers: (1) `General.tsx` — ChatBgGrid clears seasonalThemeOverride→'off' when any non-'none' background is picked; SeasonalBgGrid clears chatBackground→'none' when any real seasonal theme is selected. (2) `SeasonalEffect.tsx` — runtime guard returns null if `chatBackground !== 'none'`, protecting against legacy persisted state. @@ -68,34 +68,31 @@ This document tracks identified bugs, edge cases, and architectural discrepancie ### 7. Tiny Touch Targets in Composer Toolbar - **File:** `cinny/src/app/features/room/RoomInput.tsx` -- **Status:** **OPEN** +- **Status:** **FIXED ⚠️ UNTESTED** — needs verification on a real mobile device: open composer, confirm all toolbar buttons are tappable without mis-taps - **Issue:** Toolbar buttons have hit areas smaller than the WCAG-recommended 44x44px for touch, hindering mobile accessibility. -- **Root Cause:** The `IconButton` component does not explicitly enforce a 44x44px touch target, and the default size is too small for mobile touch precision. -- **Proposed Fix:** Apply CSS `min-width: 44px; min-height: 44px;` to all toolbar icons, potentially via a dedicated `MobileTouchTarget` style wrapper or by overriding the `IconButton` component's style for mobile viewports using media queries. +- **Fix Applied:** Added `touchTarget = { minWidth: '44px', minHeight: '44px' }` computed from `mobileOrTablet()` and applied as `style={touchTarget}` to all 8 composer toolbar `IconButton` elements (attach, format, sticker, emoji, GIF, location, poll, schedule, send). ### 8. Horizontal Overflow in Room Settings -- **File:** `cinny/src/app/features/room-settings/RoomSettings.tsx` -- **Status:** **OPEN** +- **File:** `cinny/src/app/components/page/style.css.ts` +- **Status:** **FIXED ⚠️ UNTESTED** — needs verification: open Room Settings on a narrow mobile screen, confirm nav panel fills full width and no horizontal scrollbar appears - **Issue:** Wide tables and input elements in room settings cause horizontal overflow on mobile viewports. -- **Root Cause:** A fixed-width constraint applied to the `PageNav` component in `cinny/src/app/components/page/style.css.ts` overrides responsive layout attempts on smaller screens. -- **Proposed Fix:** Update the `PageNav` style definition to be responsive, setting its width to `100%` on mobile viewports using CSS media queries, and ensure all child containers in `RoomSettings` use `flex-wrap: wrap` or similar overflow-handling layouts. +- **Fix Applied:** Added `@media (max-width: 750px) { width: '100%' }` to both `'400'` and `'300'` size variants of the `PageNav` vanilla-extract recipe in `style.css.ts`. ### 9. Modal Float-Style Responsiveness -- **File:** `cinny/src/app/components/modal/Modal.tsx` -- **Status:** **OPEN** +- **File:** Multiple modal files +- **Status:** **PARTIALLY FIXED ⚠️ UNTESTED** — applied to 7 modals; ~13 remaining modal files still need the hook applied - **Issue:** Modals appear as floating boxes on mobile, creating navigation and readability challenges. -- **Root Cause:** Missing viewport-dependent styling in the base modal component. -- **Proposed Fix:** Implement media-query-based responsiveness in the base `Modal` wrapper. For viewports below a certain threshold, override floating styles with full-screen layout: `width: 100vw; height: 100vh; border-radius: 0;`. +- **Fix Applied:** Created `useModalStyle(desktopMaxWidth)` hook (`src/app/hooks/useModalStyle.ts`) that returns fullscreen styles on mobile (no border-radius, no max-width, `height: 100%`) and desktop box styles otherwise. Applied to: `LeaveRoomPrompt`, `LeaveSpacePrompt`, `ReportRoomModal`, `ReportUserModal`, `DeviceVerification`, `InviteUserPrompt`, `LogoutDialog`. +- **Remaining:** Apply `useModalStyle` to: `DeviceVerificationSetup`, `UIAFlowOverlay`, `JoinAddressPrompt`, `JoinRulesSwitcher`, `RoomNotificationSwitcher`, and others that render floating dialogs. ### 10. Composer Keyboard Obscurity -- **File:** `cinny/src/app/features/room/RoomInput.tsx` -- **Status:** **OPEN** +- **File:** `src/index.css` +- **Status:** **FIXED ⚠️ UNTESTED** — needs verification on iOS Safari specifically (the worst offender); on Android Chrome `100dvh` has been standard since Chrome 108 - **Issue:** The chat composer is often partially or fully obscured by the virtual keyboard on mobile. -- **Root Cause:** Use of `vh` units for container height does not adapt when the virtual keyboard appears, pushing the `RoomInput` container off-screen. -- **Proposed Fix:** Adopt modern viewport units (`100svh`) for main layout containers to ensure the height adapts dynamically. Optionally, use `scrollIntoView` on the `RoomInput` container when it receives focus. +- **Fix Applied:** Added `height: 100dvh` (dynamic viewport height) to `html` alongside the existing `height: 100%` fallback. `dvh` updates when the software keyboard appears, ensuring the layout shrinks correctly and the composer stays visible. ### 11. Inline Jotai atom creation @@ -151,7 +148,7 @@ This document tracks identified bugs, edge cases, and architectural discrepancie | Hardcoded inline style `cursor: 'pointer'` | `cinny/src/app/plugins/react-custom-html-parser.tsx` | | Hardcoded color `#00D4FF`, `#FFB300` ✅ **VERIFIED COMPLIANT** | `cinny/src/app/components/event-readers/EventReaders.tsx` | | Hardcoded color `#EE1D52`, `#9146ff`, `#ff4500`, `#cb3837`, `#f48024` ⚠️ **BRAND EXCEPTION** | `cinny/src/app/components/url-preview/UrlPreviewCard.tsx` + `UrlPreview.css.tsx` — official third-party brand colors in SVG logos and site badge backgrounds; cannot convert to CSS variables without inventing new tokens (violates TDS rule 3) | -| Massive number of hardcoded `backgroundColor` values | `cinny/src/app/features/lotus/chatBackground.ts` | +| Massive number of hardcoded `backgroundColor` values ⚠️ **PATTERN CONTENT EXCEPTION** | `cinny/src/app/features/lotus/chatBackground.ts` — each background's base color is aesthetic content that defines the pattern identity; converting requires inventing 40+ CSS variables (violates TDS rule 3) or using CSS4 `relative-color-syntax` in inline styles (insufficient browser support); these are visual content, not UI chrome | | Hardcoded colors `#00FF88`, `#FF6B00` ✅ **VERIFIED COMPLIANT** | `cinny/src/app/features/call/CallControls.tsx` | | Hardcoded fallback hexes in toast colors ✅ **FIXED** | `cinny/src/app/features/toast/LotusToastContainer.tsx` | diff --git a/src/app/components/DeviceVerification.tsx b/src/app/components/DeviceVerification.tsx index b80292658..28130b151 100644 --- a/src/app/components/DeviceVerification.tsx +++ b/src/app/components/DeviceVerification.tsx @@ -30,6 +30,7 @@ import { } from '../hooks/useVerificationRequest'; import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback'; import { ContainerColor } from '../styles/ContainerColor.css'; +import { useModalStyle } from '../hooks/useModalStyle'; const DialogHeaderStyles: CSSProperties = { padding: `0 ${config.space.S200} 0 ${config.space.S400}`, @@ -232,6 +233,7 @@ type DeviceVerificationProps = { }; export function DeviceVerification({ request, onExit }: DeviceVerificationProps) { const phase = useVerificationRequestPhase(request); + const modalStyle = useModalStyle(480); const handleCancel = useCallback(() => { if (request.phase !== VerificationPhase.Done && request.phase !== VerificationPhase.Cancelled) { @@ -255,7 +257,7 @@ export function DeviceVerification({ request, onExit }: DeviceVerificationProps) escapeDeactivates: false, }} > - +
diff --git a/src/app/components/LogoutDialog.tsx b/src/app/components/LogoutDialog.tsx index 3b474704e..bfa604f4d 100644 --- a/src/app/components/LogoutDialog.tsx +++ b/src/app/components/LogoutDialog.tsx @@ -3,6 +3,7 @@ import { Dialog, Header, config, Box, Text, Button, Spinner, color } from 'folds import { AsyncStatus, useAsyncCallback } from '../hooks/useAsyncCallback'; import { logoutClient } from '../../client/initMatrix'; import { useMatrixClient } from '../hooks/useMatrixClient'; +import { useModalStyle } from '../hooks/useModalStyle'; import { useCrossSigningActive } from '../hooks/useCrossSigning'; import { InfoCard } from './info-card'; import { @@ -16,6 +17,7 @@ type LogoutDialogProps = { export const LogoutDialog = forwardRef( ({ handleClose }, ref) => { const mx = useMatrixClient(); + const modalStyle = useModalStyle(480); const hasEncryptedRoom = !!mx.getRooms().find((room) => room.hasEncryptionStateEvent()); const crossSigningActive = useCrossSigningActive(); const verificationStatus = useDeviceVerificationStatus( @@ -33,7 +35,7 @@ export const LogoutDialog = forwardRef( const ongoingLogout = logoutState.status === AsyncStatus.Loading; return ( - +
- +