From f9edd2023d0a6748abd80dbb2fb85d30c94c7021 Mon Sep 17 00:00:00 2001 From: Jared Vititoe Date: Mon, 15 Jun 2026 01:14:56 -0400 Subject: [PATCH] feat(seasonal): tone down overlays and add visual preview grid in Settings - New Year: replace flashing animBurst rays with gentle falling confetti - Lunar New Year: reduce 9 lanterns to 4, halve sizes, dim silk/shimmer - April Fools: remove all glitch/scanline/watermark effects; replace with a subtle rainbow stripe and falling punctuation symbols - Add SeasonalPreview export (position:absolute, reduced-motion) for use inside contained card elements - Replace SettingsSelect dropdown for Seasonal Theme with SeasonalBgGrid, a visual card grid (matches ChatBgGrid pattern) showing ambient previews Co-Authored-By: Claude Sonnet 4.6 --- LOTUS_BUGS.md | 95 ++--- LOTUS_TODO.md | 111 +----- LOTUS_TODO_REFERENCE.md | 99 ++--- .../components/seasonal/SeasonalEffect.tsx | 342 +++++++++--------- src/app/features/settings/general/General.tsx | 124 +++++-- 5 files changed, 366 insertions(+), 405 deletions(-) diff --git a/LOTUS_BUGS.md b/LOTUS_BUGS.md index c2241f02b..72d0248df 100644 --- a/LOTUS_BUGS.md +++ b/LOTUS_BUGS.md @@ -5,57 +5,68 @@ This document tracks identified bugs, edge cases, and architectural discrepancie --- -## โœ… Resolved Issues +## ๐Ÿšฉ Critical & UI Bugs -- **Ringing Modal Fires in Voice Rooms**: Fixed in `CallEmbedProvider.tsx` โ€” only `notification_type === 'ring'` events now trigger the modal. -- **Avatar Decoration Displacement in Profile**: Fixed in `UserHero.tsx` โ€” `UserAvatarContainer` (position:absolute) now wraps `AvatarDecoration` as the outermost element, keeping the positioning context relative to `UserHeroAvatarContainer`. -- **Export History Broken for E2EE**: Fixed in `ExportRoomHistory.tsx` โ€” `addEvents` is now async and calls `mx.decryptEventIfNeeded()` before inspecting event type/content. -- **Privacy Leak in URL Previews (Google Favicon)**: Fixed in `UrlPreviewCard.tsx` โ€” Google S2 favicon call removed; a generic folds `Icons.Link` icon is shown instead. -- **Status Emoji Picker Doesn't Insert Emoji**: Fixed in `Profile.tsx` โ€” `statusDirtyRef` prevents the server-presence sync `useEffect` from overwriting in-flight user input (cleared on save/clear). -- **Encrypted Search Misses Stickers and Polls**: Fixed in `useLocalMessageSearch.ts` โ€” `m.sticker`, `m.poll.start`, and `org.matrix.msc3381.poll.start` events now included; poll question and answer bodies are indexed. -- **Seasonal Themes Display Behind Chat Background**: Fixed in `SeasonalEffect.tsx` โ€” z-index bumped from 9997 to 9999. -- **Windows Taskbar Badge Black Square**: Fixed in `src-tauri/src/lib.rs` โ€” `std::ptr::write_bytes` zeros the DIB bits buffer immediately after `CreateDIBSection`; previously uninitialized bytes caused garbage pixels with alpha=255. +### 1. Avatar Decoration Displacement in Profile +**File:** `src/app/components/user-profile/UserHero.tsx` +**Status:** **OPEN** ---- +* **Issue:** Avatar decorations appear displaced left of the avatar when viewing the profile modal. +* **Root Cause:** The `AvatarPresence` badge sticking out to the right shifts the center of the `inline-flex` container. The decoration centers on the container, not the avatar. +* **Recommended Fix:** Wrap only the `Avatar` component with `AvatarDecoration`. -## ๐Ÿ›ก๏ธ Pending โ€” Critical Security & Logic - -*(none currently open)* - ---- - -## ๐Ÿšฉ Pending โ€” Functional & UI Bugs - -### 1. Avatar Decoration Images Not Rendering -**File:** `src/app/features/lotus/avatarDecorations.ts` -**Status:** **OPEN โ€” Blocked on infrastructure** - -* **Issue:** Decoration images in Settings do not load. -* **Root Cause:** The Nextcloud WebDAV URL (`public.php/dav/files/โ€ฆ`) returns `Content-Disposition: attachment`, which browsers refuse to render in `` tags. -* **Required Fix:** Move decoration assets to a CDN or file host that returns `Content-Type: image/png` with `Content-Disposition: inline`. Options: Gitea LFS, Cloudflare R2, or a dedicated static file host. Alternatively, reconfigure the Nextcloud share to serve inline. -* **Blocked by:** Infrastructure change (not a code fix). - ---- - -## ๐ŸŽจ Pending โ€” UI/UX & Visual Consistency - -### 1. Inconsistent Settings Dropdown Styling +### 2. Inconsistent Settings Dropdown Styling **Files:** `Profile.tsx`, `SystemNotification.tsx` -**Status:** **OPEN โ€” Low priority** +**Status:** **OPEN** * **Issue:** Dropdowns for Status Expiry and Notification Sounds use raw HTML `` component. Hide this section if `lotusTerminal` is `true`. - -### P5-14 ยท Animated Avatar Overlay -**Mechanism:** CSS Pseudo-element wrapping. - -* **1. Wrapper (src/app/components/user-avatar/UserAvatar.tsx):** - ```tsx - const avatar = ( - - ); - if (!frame) return avatar; - return ( -
- {avatar} -
-
- ); - ``` -* **2. CSS (src/app/components/user-avatar/UserAvatar.css.ts):** - Define animations like `rotate` or `pulse`. Use `position: absolute; inset: -4px` on the effect div to create a glowing ring around the avatar. - ---- - ## ๐Ÿ› ๏ธ Priority 4 โ€” Specialized Features ### P4-4 ยท Math / LaTeX Rendering @@ -108,28 +68,42 @@ This document provides exhaustive, low-level implementation details for the rema ## ๐ŸŽจ Priority 5 โ€” Gamer / Aesthetic / Customization -### P5-12 ยท Seasonal / Event Themes -**Mechanism:** Date-aware global overlays. +### P5-1 ยท Custom Accent Color Picker (Non-TDS only) +**Mechanism:** Dynamic CSS variable injection. -* **1. Component (src/app/components/seasonal/SeasonalEffect.tsx):** - ```tsx - const isHalloween = now.month === 9 && now.day >= 15; // etc. - if (!isHalloween) return null; - return
; +* **1. Setting (src/app/state/settings.ts):** + Add `customAccentColor: string` (hex). +* **2. Manager (src/app/pages/ThemeManager.tsx):** + Inside the `useEffect` that monitors theme changes: + ```typescript + if (!lotusTerminal && customAccentColor) { + document.documentElement.style.setProperty('--lt-accent-orange', customAccentColor); + // Also derive a 'glow' version (e.g. 50% opacity) + document.documentElement.style.setProperty('--lt-accent-orange-glow', `${customAccentColor}80`); + } ``` -* **2. Styles (src/app/styles/Animations.css.ts):** - Use `repeating-linear-gradient` for spider webs or `keyframes` for falling snow. -* **3. Mounting:** Place at the very end of `App.tsx` (above the `LotusToastContainer`) with `pointer-events: none`. +* **3. UI (src/app/features/settings/general/General.tsx):** + Use a `` component. Hide this section if `lotusTerminal` is `true`. -### P5-13 ยท Avatar Frame / Border Decorations -**Mechanism:** Static variant of P5-14. +### P5-40 ยท Desktop โ€” Proactive Update Notifications (Tauri) +**Mechanism:** Global Background Check via `useTauriUpdater`. -* **Implementation:** Use a simple `border` or `box-shadow` in `UserAvatar.tsx` based on the `io.lotus.avatar_frame` account data. Unlike the animated version, this should avoid `keyframes` to save CPU on long member lists. +* **Objective:** Alert users to app updates without requiring a manual check in settings. +* **Key Files:** + * `src/app/hooks/useTauriUpdater.ts`: Logic source. + * `src/app/pages/client/ClientNonUIFeatures.tsx`: Background mounting point. + * `src/app/features/toast/LotusToastContainer.tsx`: UI for notification. +* **Implementation:** + 1. Create a `TauriUpdateFeature` component. + 2. Use `useTauriUpdater()` to get the `check` function and `status`. + 3. In a `useEffect`, call `check()` on mount and then on a `setInterval` (e.g., every 12 hours). + 4. Watch the `status`. When it transitions to `{ state: 'available', version: '...' }`, trigger an in-app **Lotus Toast**. + 5. The toast should say "Lotus Chat v[version] is available!" with an "Update" button that calls the `install()` function from the hook. + 6. **Persistence:** Store the `lastCheck` timestamp in `localStorage` to ensure the background check doesn't fire redundant commands every time the user refreshes or re-opens the app. -### P5-2 ยท Additional Color Theme Presets -**Mechanism:** Standard vanilla-extract theme multiplication. +--- -* **Implementation:** Replicate the `lotusTerminalTheme` object in `src/colors.css.ts` for each new theme (Cyberpunk, Ocean, etc.). Ensure each theme defines all 50+ tokens required by the `folds` library and TDS. +## ๐Ÿ”Š Audio & Communications ### P5-15 ยท In-Call Soundboard **Mechanism:** Local-to-Global Audio Bridge. @@ -183,6 +157,7 @@ This document provides exhaustive, low-level implementation details for the rema * In `CallControl.ts`, intercept the `localStream`. * Pass the stream through the Worklet. * Crucially, you must ensure that the processed stream is used by the `RTCPeerConnection` within the Element Call iframe. + ### P5-31 ยท Granular Voice & Screenshare Quality Controls **Mechanism:** WebRTC Encoding Parameters + Backend Quality Guard. @@ -220,15 +195,3 @@ This document provides exhaustive, low-level implementation details for the rema * **Challenges:** * **LiveKit Compatibility:** Ensuring the SFU doesn't over-compress a high-bitrate stream from a "Pro" user. * **Network Stability:** High bitrates (512kbps audio + 60fps 1080p video) require significant upstream bandwidth. Implement a "Network Warning" UI if packets are dropped. - -### P5-34 ยท User-to-User Private Notes -**Mechanism:** Encrypted account data map. - -* **Objective:** Private, cross-session notes about other users. -* **Key Files:** - * `src/app/hooks/useUserNotes.ts`: New hook for CRUD operations. - * `src/app/components/user-profile/UserRoomProfile.tsx`: UI site. -* **Implementation:** - 1. Store as a single map in `io.lotus.user_notes` account data: `{ "@alice:server": "Cool dev", "@bob:server": "Needs moderation" }`. - 2. Wrap the entire map in E2EE if the client supports local account data encryption, or rely on standard Matrix account data privacy. - 3. Add a "Notes" tab or textarea to the user profile popout. diff --git a/src/app/components/seasonal/SeasonalEffect.tsx b/src/app/components/seasonal/SeasonalEffect.tsx index 9ff2f77f1..d0c09f6bf 100644 --- a/src/app/components/seasonal/SeasonalEffect.tsx +++ b/src/app/components/seasonal/SeasonalEffect.tsx @@ -7,16 +7,12 @@ import { animFloatUp, animBob, animTasselSway, - animGlitch, - animGlitchColor, - animGlitchScan, - animBurst, - animWarp, - animScanline, - animPixelBlink, animGoldShimmer, animCloverDrift, animEarthLeafDrift, + animWarp, + animScanline, + animPixelBlink, } from './Seasonal.css'; export type SeasonTheme = @@ -98,7 +94,7 @@ function HalloweenOverlay({ reduced }: { reduced: boolean }) { particles.map((_, i) => { const isOrange = i % 3 === 0; const size = 4 + (i % 3) * 2; - const left = ((i * 4597 + 137) % 100); + const left = (i * 4597 + 137) % 100; const duration = 8 + (i % 7) * 1.5; const delay = (i * 0.45) % 7; return ( @@ -141,7 +137,7 @@ function ChristmasOverlay({ reduced }: { reduced: boolean }) { {!reduced && flakes.map((_, i) => { const size = 3 + (i % 4) * 2; - const left = ((i * 3571 + 251) % 100); + const left = (i * 3571 + 251) % 100; const duration = 10 + (i % 8) * 2; const delay = (i * 0.55) % 10; const drift = ((i % 5) - 2) * 12; @@ -168,17 +164,10 @@ function ChristmasOverlay({ reduced }: { reduced: boolean }) { ); } +// Replaced flashing burst rays with gentle falling confetti function NewYearOverlay({ reduced }: { reduced: boolean }) { - const bursts = [ - { x: 20, y: 25, color: '#ffd700', delay: 0 }, - { x: 75, y: 15, color: '#ff4466', delay: 1.2 }, - { x: 50, y: 35, color: '#00d4ff', delay: 2.4 }, - { x: 15, y: 60, color: '#ffd700', delay: 3.6 }, - { x: 85, y: 45, color: '#aa44ff', delay: 0.8 }, - { x: 40, y: 20, color: '#ff8800', delay: 2.0 }, - ]; - - const petals = Array.from({ length: 8 }); + const confetti = Array.from({ length: 24 }); + const colors = ['#ffd700', '#ff4466', '#00d4ff', '#aa44ff', '#ff8800', '#ffffff']; return ( <> @@ -187,50 +176,48 @@ function NewYearOverlay({ reduced }: { reduced: boolean }) { style={{ position: 'absolute', inset: 0, - backgroundColor: 'rgba(10,5,0,0.15)', + backgroundColor: 'rgba(10,5,0,0.10)', backgroundImage: 'radial-gradient(ellipse at 50% 50%, rgba(255,200,0,0.04) 0%, transparent 70%)', }} /> + {/* Gentle falling confetti */} {!reduced && - bursts.map((b, bi) => - petals.map((_, pi) => { - const angle = (pi / petals.length) * 360; - const dist = 80 + (pi % 3) * 30; - const duration = 1.6 + (bi % 3) * 0.4; - const period = 3.5 + bi * 0.8; - return ( -