38 Commits

Author SHA1 Message Date
jared 79f8fabb1b fix(ui): GIF picker surface tokens + background swatch chrome (N8, N70)
CI / Build & Quality Checks (push) Successful in 10m46s
CI / Trigger Desktop Build (push) Successful in 6s
- N8: GifPicker non-TDS container used undefined var(--bg-surface) + raw
  rgba/12px/boxShadow. Switch to folds tokens (color.Surface.Container,
  config.radii.R400, color.Surface.ContainerLine, color.Other.Shadow).
  TDS branch keeps its --lt-* glow chrome.
- N70: ChatBgGrid/SeasonalBgGrid swatch buttons moved chrome (radius, border,
  hover, keyboard :focus-visible ring, selected via data-selected) into shared
  BgSwatch.css.ts using design tokens; only per-swatch size + live preview
  background stay inline (custom preview tiles, not MenuItem/Chip candidates).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 21:01:57 -04:00
jared dfd2c9c49e fix(ui): mention color picker, send-animation conflict, DM virtualizer (N69,N10,N22)
- N69: @mention highlight color now uses HexColorPickerPopOut + react-colorful
  HexColorPicker behind a folds Button (color swatch); built-in onRemove
  replaces the separate Reset, dropping the OS-native <input type="color">
- N10: mentionPulseKeyframes animates only box-shadow (dropped the imperceptible
  scale(1.003)) so it no longer fights MsgAppearClass over `transform` on
  self-sent @mention messages
- N22: Direct.tsx virtualizer estimateSize 38 -> 52 (two-line DM row height) to
  avoid the initial-render jump before measureElement corrects each row

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 20:54:32 -04:00
jared 5470e25bb0 fix(ui): report category dropdown uses folds menu, not native select (N56)
CI / Build & Quality Checks (push) Successful in 10m52s
CI / Trigger Desktop Build (push) Successful in 7s
Extract a shared ReportCategorySelect: folds Button trigger + PopOut +
FocusTrap + Menu + MenuItem (escape + arrow-key nav, like OrderButton),
replacing the OS-styled native <select> in both ReportRoomModal and
ReportUserModal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 20:41:46 -04:00
jared d0715774a8 fix(ui): ScheduleMessageModal + PollCreator use folds Dialog shell (N15, N29)
Both rendered as <Box as="form" role="dialog"> with manually assembled
background/borderRadius(R400)/boxShadow. Switch to <Dialog as="form"
variant="Surface"> so the surface comes from the design system (R300 radius),
matching the other message-action dialogs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 20:32:16 -04:00
jared 6f544e2b1f fix(ui): report modals use folds Dialog shell (N63)
ReportRoomModal/ReportUserModal rendered as <Box as="form" role="dialog">
with inline background/borderRadius(R400)/boxShadow. Switch both to
<Dialog as="form" variant="Surface"> so the surface (background, R300 radius,
shadow) comes from the design system, matching MessageReportItem and every
other message-action modal.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 20:26:17 -04:00
jared e713d47319 fix(ui): forward-dialog header, notification presets, syntax-highlight tokens
CI / Build & Quality Checks (push) Successful in 10m39s
CI / Trigger Desktop Build (push) Successful in 8s
- N14 ForwardMessageDialog: add folds <Header> with title + close IconButton
  (was closeable only by clicking outside)
- N20 Notification presets: bare <button> with undefined --border-interactive-
  normal / --bg-surface-low vars -> folds <Button variant="Secondary" fill="Soft">
- N68 syntaxHighlight tokenStyle: use the theme-aware --prism-* variable family
  (keyword/selector/boolean/atrule/comment) instead of TDS-only --lt-accent-*
  vars with dark-only Monokai fallbacks; comment uses --prism-comment not opacity

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 18:22:25 -04:00
jared b361d43088 fix(ui): native inputs/checkboxes, QR fallback, focus + report modal cleanup
- N23 RoomServerACL: raw text input -> folds Input; raw checkbox -> folds Checkbox
- N24 PolicyListViewer: raw room-id input -> folds Input (Critical variant on error)
- N25 ExportRoomHistory: raw <input type="date"> x2 -> folds Input
- N26 RoomShareInvite: QR <img> gets loading="lazy" + onError fallback card
  ("QR code unavailable") instead of a broken-image icon
- N27 GifPicker: FocusTrap returnFocusOnDeactivate:false (matches EmojiBoard)
- N76 Report modals: drop redundant Cancel button (dismiss via header x /
  click-outside, like MessageReportItem)
- N5 ReadReceiptAvatars: hover/focus moved to co-located css :hover/:focus-visible
  (removed JS onMouseEnter/Leave .style mutation)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 18:12:25 -04:00
jared 4a4dede105 fix(media-gallery): dock as a flex sibling like MembersDrawer (was floating)
CI / Build & Quality Checks (push) Successful in 10m34s
CI / Trigger Desktop Build (push) Successful in 6s
The real reason the gallery didn't look or function like the Members drawer
or Saved Messages: it was a position:fixed overlay floating over the timeline,
mounted from RoomViewHeader. Now it docks into the room layout row exactly like
MembersDrawer.

- new mediaGalleryAtom (mirrors bookmarksPanelAtom) holds the open state
- RoomViewHeader toggles the atom instead of local useState and no longer
  renders the panel
- Room.tsx renders <MediaGallery> as a flex sibling of the timeline with a
  vertical Line separator on desktop and key={room.roomId} to reset per room
- MediaGallery.css: static width on desktop, position:fixed inset:0 full-screen
  only on mobile (identical strategy to MembersDrawer.css); root Box shrink="No"

The panel now shares the row with the timeline instead of overlapping it.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 16:14:50 -04:00
jared b818d3fc5a refactor(media-gallery): redesign chrome to match native folds conventions
CI / Build & Quality Checks (push) Successful in 10m25s
CI / Trigger Desktop Build (push) Successful in 11s
The Media Gallery panel worked but didn't look like a first-party Cinny
drawer. Redesign the chrome to match MembersDrawer / Saved Messages and the
PolicyListViewer tab precedent:

- panel + header: Surface -> Background variant; header uses Text size="H4"
  and a plain close IconButton (dropped the bespoke tooltip-wrapped button)
- tabs: moved into a bordered toolbar strip; adopt the repo's
  variant={active?'Primary':'Secondary'} fill={active?'Solid':'Soft'} pattern
  and show per-tab counts (Images (N) / Videos (N) / Files (N))
- month grouping: replaced the centered "lines + label" divider with a
  left-aligned group label (the Cinny group-label pattern)
- thumbnail tiles: hover/focus border + caption overlay are now CSS-driven
  (:hover / :focus-visible) instead of React state, and live in
  MediaGallery.css.ts; grid + file rows tokenized
- caption overlay also reveals on keyboard focus (a11y)

All styling consolidated into MediaGallery.css.ts; no inline grid/tile styles.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 13:07:51 -04:00
jared cf839e7345 fix(ui): avatar-decoration reliability, Saved Messages + Media Gallery redesign
CI / Build & Quality Checks (push) Successful in 10m30s
CI / Trigger Desktop Build (push) Successful in 9s
Avatar decorations: useAvatarDecoration cached ALL profile-field fetch
failures as "no decoration" permanently for the session. The member list
and timeline mount many avatars at once, so one rate-limited (429) burst
would wipe everyone's decoration until a full reload. Now only a genuine
404 (field unset) is cached; transient errors retry on the next mount.

Saved Messages panel — full redesign to match the canonical MembersDrawer:
- co-located BookmarksPanel.css.ts: toRem(266) + max-width:750px full-screen
  media query, replacing the old position:absolute/zIndex:100 mobile "modal"
  that had no backdrop or escape
- variant="Background" header; room avatars on each item (was a generic hash)
- priority tokens replace all raw opacity hacks; 3px borderLeft accent removed
- Escape-to-close; multi-line preview is now a proper folds Button (N38)

Media Gallery (N12): moved fixed positioning + width into MediaGallery.css.ts
using toRem(320) + a full-screen media query; border/header use config tokens;
added Escape-to-close on the panel (previously only the lightbox handled it).

Presence (SettingsTab / useUserPresence):
- N16: wrap presence-dot trigger in TooltipProvider; replace undefined
  --bg-surface with color.Background.Container
- N17: add escapeDeactivates + isKeyForward/isKeyBackward to the FocusTrap
- N19: align reader labels (usePresenceLabel) to the setter vocabulary
  (Online/Idle/Offline) so a chosen status matches the tooltip others see

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 11:21:29 -04:00
jared c54cb126ff fix(ui): settings modal sizing regression + 17 more folds audit findings
CI / Build & Quality Checks (push) Successful in 10m47s
CI / Trigger Desktop Build (push) Successful in 5s
Fix settings modal regression: Modal500 was wrapped in useModalStyle(560),
forcing maxWidth 560px and squishing the two-pane Settings layout (folds
size="500" is ~50rem). Restore desktop width to the folds recipe while
keeping mobile fullscreen.

N-series fixes:
- N13 ScheduledMessagesTray header: <Box as="button"> -> folds <Button>
- N28 composer char counter: drop undefined --tc-surface-low + opacity,
  use priority="300" and config.space token
- N31 collapsible "Read more" toggle: padded <Button> -> flush inline-button
  pattern matching (edited) link
- N41 UserPrivateNotes "Saving..." now shows a folds <Spinner>
- N43 Night Light slider: add accentColor; label opacity -> priority
- N44 mention-highlight Reset: bare <button> -> folds <Button> (drops
  undefined --border-interactive-normal); Boot button kept (TDS-only)
- N45 SelectTheme trigger variant -> Secondary to match SettingsSelect
- N49 RoomInsights StatTile emoji -> folds <Icon> (Photo/VideoCamera/
  Headphone/File)
- N54/N57 PiP overlay badges + fullscreen button: token discipline
  (config.radii/space, folds Text); dark scrim kept for video legibility
- N60 knock badge: match Pinned Messages pattern (no wrapper div, toRem
  insets, no hardcoded size overrides)
- N62 unverified-device banner: 3px left-accent -> standard border via
  color.Warning.ContainerLine; drop opacity hacks
- N65 Edit History: real "Load more" pagination (accumulate next_batch,
  de-dupe by id, re-sort by ts) replacing passive text
- N66 search date fields: raw <input type="date"> -> folds <Input>
- N67 SeasonalEffect z-index 9999 -> 9997 (below Night Light + modals)
- N73 Pending Requests header uses css.MembersGroupLabel
- N74 remove raw em-sized emoji <span> in RoomNavItem name
- N85/N86 RemindMeDialog: <Box role="dialog"> -> folds <Dialog>; preset
  MenuItems -> Buttons (fixes invalid menuitem-in-dialog ARIA)

Document deliberate WON'T FIX rationale for N9, N51, N61, N71, N75, N77.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-19 00:15:35 -04:00
jared 8dc4c4d072 fix(ui): resolve 29 native UI/UX inconsistencies from folds design audit
CI / Build & Quality Checks (push) Successful in 10m25s
CI / Trigger Desktop Build (push) Successful in 6s
Fixes N1–N94 findings from LOTUS_BUGS.md audit pass. Key changes:

- ProfileDecoration: raw <button> → folds <Button> for save/remove; remove
  undefined --accent-cyan var
- UserRoomProfile: textarea border uses color.SurfaceVariant.ContainerLine
  and config tokens instead of undefined --border-interactive var
- LotusToastContainer: z-index raised from 9997 → 10001 so toasts appear
  above Night Light overlay (9998) and modals (9999)
- Message.tsx: DeliveryStatus replaces Unicode glyphs with Icon components;
  MessageQuickReactions returns null instead of <span />; forward menu item
  gets correct size="100" on after icon
- AudioContent: speed chip variant/radii now matches Play chip (Secondary/300)
- ReadReceiptAvatars: pill border/radius/padding → folds config tokens;
  remove dead receipt-pill-btn className
- EventReaders: Header size 600→500; close button gets radii="300";
  borderBottom shorthand → borderBottomWidth token; remove raw fontSize
- General.tsx: selected background/seasonal picker border uses
  color.Primary.Main instead of color.Critical.Main (error red)
- RoomInsights: SectionHeader drops textTransform/letterSpacing/opacity;
  chart borderRadius → config tokens; remove raw fontSize:9;
  warning banner → SequenceCard
- RoomProfile.tsx: formatting toolbar raw <button> → folds <Button>;
  topic read-mode renders formatted_body via sanitizeCustomHtml
- MsgTypeRenderers: location Open button Chip→Button; opacity:0.65→priority
- UploadCardRenderer: caption raw <input> → folds <Input>
- VoiceMessageRecorder: replace undefined --bg-surface-variant/--tc-*
  vars with color.* tokens; replace bare <audio controls> with
  IconButton play/pause toggle
- App.tsx: mention highlight uses WCAG 2.1 relative luminance (gamma
  linearization) instead of simplified approximation; border now rgba
  semi-transparent instead of same color as background
- RoomNavItem: Mute MenuItem icon moved to before prop
- SearchFilters: HasLink chip variant="Success" outlined to match filter bar
- RoomViewHeader: Server Notice chip radii Pill→300; fix jotai import order
- Fix ESLint import/order errors in DeviceVerificationSetup, RoomTopicViewer,
  MediaGallery, and RoomViewHeader

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 22:46:19 -04:00
jared 9deeef6e8d fix(pip): correctly identify whose mic is muted in PiP overlay
Previously PipMuteOverlay fired on useRemoteAllMuted (any remote
muted) and rendered in the bottom-left corner — the conventional
position for local-user mic status — causing users to think their
own mic was muted when it wasn't.

Fix: split into two distinct indicators
- Bottom-left: local mic muted only (from useCallControlState),
  labelled "You" so attribution is unambiguous
- Top-right: "All muted" warning (warning color, not critical) when
  all remote participants are muted

UNTESTED — verify in a real call at chat.lotusguild.org.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 19:23:12 -04:00
jared a77c4b6db5 feat(calls): configurable ringtone volume in Settings (Bug #4 partial)
CI / Build & Quality Checks (push) Successful in 10m29s
CI / Trigger Desktop Build (push) Successful in 15s
Adds 'Ringtone Volume' slider (0–100, default 70%) to Settings → Calls.
The IncomingCall audio element reads the setting and applies it as
audioElement.volume before playing, replacing the implicit browser
default of 1.0.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 18:56:04 -04:00
jared cb3d2c40e5 fix(a11y): descriptive aria-label on reaction buttons (P3-4)
Reaction.tsx now computes aria-label='{shortcode} reaction, N people'
using getShortcodeFor so screen readers announce emoji name and count
instead of an ambiguous button. Custom (mxc://) emoji falls back to
'custom emoji reaction'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 18:50:19 -04:00
jared 8ac42cdbad perf(gallery): gate tile decryption until near-viewport
Adds enabled=true param to useDecryptedMediaUrl in MediaGallery.tsx.
GalleryTile now uses useNearViewport(300px) — decryption is deferred
until the tile approaches the viewport, preventing burst of 100
concurrent decrypt/fetch calls when a pagination batch loads.

Blob revocation was already correct (no actual leak); this fixes the
load-burst performance issue. Full windowing virtualization deferred.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 18:16:15 -04:00
jared 1b4c6cab6d fix(a11y): add missing aria-labels to message buttons
- FallbackContent: '(edited)' button now has aria-label='View edit history'
- Reply: ThreadIndicator as=button gets aria-label='View thread'
- Reply: ReplyLayout as=button gets aria-label='Jump to original message'

Addresses WCAG 2.1 SC 4.1.2 (Name, Role, Value) for icon-only buttons
and polymorphic div-as-button patterns in the message timeline.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 18:14:01 -04:00
jared 176d5d0bb7 fix(mobile): apply useModalStyle to remaining dialog files (Bug #9)
Completes the mobile fullscreen modal pass — adds useModalStyle to
DeviceVerificationSetup, DeviceVerificationReset, AddExistingModal,
RoomEncryption prompt, RoomUpgradeDialog, Modal500, ReadReceiptAvatars,
and RoomTopicViewer. All floating Dialog/Modal components now go
fullscreen on mobile (≤750px). UIAFlowOverlay was already fullscreen
via <Overlay>; JoinRulesSwitcher/RoomNotificationSwitcher are dropdowns.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 18:11:24 -04:00
jared baa12823f7 fix: exponential backoff for 429 retries, cover thumbnails, 2 more modal dialogs
- matrix.ts: rateLimitedActions fallback delay now uses capped exponential
  backoff (min(1000 * 2^n, 30s)) instead of flat 3000ms when server omits
  Retry-After; server header still takes precedence
- RenderMessageContent: add objectFit:cover + 100% fill to video thumbnail
  <Image> so thumbnails fill their container without letterboxing (P5-6)
- CreateRoomModal, CreateSpaceModal: apply useModalStyle(480) for fullscreen
  on mobile
- LOTUS_BUGS: mark usePan memory leak + httpStatus check as FALSE POSITIVE;
  mark rateLimitedActions backoff as FIXED

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 15:32:17 -04:00
jared f5c301d5c6 fix(mobile): useModalStyle on 3 more dialogs, GPU hint animated bg, document untested fixes
- DeviceVerification, InviteUserPrompt, LogoutDialog: apply useModalStyle for
  fullscreen on mobile, capped box on desktop
- chatBackground: inject willChange + contain:paint on animated variants to
  promote compositor layer and prevent descendant repaint flickering (Bug #2)
- LOTUS_BUGS.md: mark #7-#10 FIXED/UNTESTED, #2 FIXED/UNTESTED, chatBackground
  backgroundColor values as PATTERN CONTENT EXCEPTION

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 14:51:28 -04:00
jared c395f7d16e fix(mobile): touch targets, keyboard viewport, PageNav overflow, modal fullscreen
CI / Build & Quality Checks (push) Successful in 10m27s
CI / Trigger Desktop Build (push) Successful in 5s
- Bug #10: use `100dvh` on <html> so layout shrinks when mobile virtual keyboard
  appears (prevents composer from being pushed off-screen)
- Bug #7: add `minWidth/minHeight: 44px` to all 8 composer toolbar IconButtons on
  mobile via mobileOrTablet() check (WCAG 2.1 AA touch target requirement)
- Bug #8: add `@media (max-width: 750px) { width: 100% }` to PageNav recipe
  variants so the nav panel fills full width on mobile instead of overflowing
  with its fixed desktop width
- Bug #9: introduce `useModalStyle(maxWidth)` hook — returns fullscreen styles on
  mobile (no border-radius, no max-width cap, height 100%) and desktop box styles
  otherwise; applied to LeaveRoomPrompt, LeaveSpacePrompt, ReportRoomModal,
  ReportUserModal
- Bug #11: mark as FALSE POSITIVE in LOTUS_BUGS.md — `useState(() => atom(...))`
  is the correct Jotai pattern for stable local atom references
- Scheduled Messages persistence: mark as FIXED — already uses atomWithStorage +
  createJSONStorage with error-safe JSON parsing
- UrlPreviewCard TDS colors: mark as BRAND EXCEPTION — SVG logo fills and site
  badge backgrounds are official third-party brand colors; cannot convert without
  inventing new CSS variables (violates TDS rule 3)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 13:34:40 -04:00
jared 26f900870b feat: MSC4260 Report User, Bug #6 mutual exclusion, TDS toast compliance
CI / Build & Quality Checks (push) Successful in 10m28s
CI / Trigger Desktop Build (push) Successful in 6s
- Add ReportUserModal.tsx — category dropdown + reason input, calls
  POST /_matrix/client/v3/users/{userId}/report via mx.http.authedRequest,
  inline success/error feedback, auto-closes 1500ms after success
- Wire Report User button into UserRoomProfile.tsx between UserModeration
  and UserDeviceSessions (hidden for own profile)
- Bug #6: enforce mutual exclusion between chat backgrounds and seasonal
  themes — ChatBgGrid clears seasonal→'off' on non-'none' pick;
  SeasonalBgGrid clears chatBackground→'none' on real theme pick;
  SeasonalEffect guards against legacy persisted state at render time
- TDS: strip all hardcoded hex/rgba fallbacks from LotusToastContainer.tsx
  (var(--lt-bg-card), --lt-accent-orange, --lt-text-primary/secondary,
  --lt-accent-orange-dim/border, --lt-box-glow-orange)
- Mark Bug #6 FIXED, MSC4260 DONE, toast TDS FIXED in LOTUS_BUGS.md and
  LOTUS_TODO.md; note EventReaders + CallControls already compliant

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-18 10:37:44 -04:00
jared 6c58e25211 style: fix prettier formatting
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 20:37:54 -04:00
jared b24ab838f8 feat: Remind Me Later, mobile bookmarks, bug fixes, and doc cleanup
CI / Build & Quality Checks (push) Successful in 10m37s
CI / Trigger Desktop Build (push) Successful in 8s
Features:
- Remind Me Later: message context menu item opens a preset time picker
  (20 min / 1 hr / 3 hr / tomorrow 9am); reminders persist to Matrix
  account data (io.lotus.reminders); ReminderMonitor fires a Lotus Toast
  when due, checks every 30s and on tab focus
- Mobile Bookmarks: BookmarksPanel now renders on all screen sizes;
  passes isMobile prop for full-screen absolute overlay on mobile

Bug fixes:
- usePan.ts: memory leak from stale closure in document listener cleanup
- EventReaders.tsx: replace hardcoded hex colors with TDS CSS variables
- CallControls.tsx: replace hardcoded hex colors with TDS CSS variables
- CustomHtml.css.ts: replace hardcoded yellow/black highlight with theme tokens

Docs:
- LOTUS_TODO.md: restore deleted content (Confirmed facts table, Pending
  Audits, P5-30 completed status, full feature descriptions), keep new
  additions (P4-7/8/9, P5-41–57, Implementation Reference), eliminate
  duplicate sections
- LOTUS_BUGS.md: merge RESILIENCE_AUDIT.md findings into Architectural &
  Resilience Audit table; delete RESILIENCE_AUDIT.md
- Remove stale LOTUS_DENOISE_ENGINEERING_REVIEW.md and LOTUS_TODO_REFERENCE.md

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 20:26:43 -04:00
jared 6634b2b8a2 fix(calls): make ML denoise build-honest + gate desktop trigger on CI
CI / Build & Quality Checks (push) Successful in 10m41s
CI / Trigger Desktop Build (push) Successful in 6s
Audit/repair of the multi-model denoise work so it actually builds and only
exposes working, self-hosted models.

- Complete the DTLN/DFN3 revert: uninstall @workadventure/noise-suppression
  and deepfilternet3-noise-filter (package.json + lockfile), drop the unused
  DTLN asset-copy block from vite.config.js (was shipping ~2MB of unused
  tflite/wasm), and narrow DenoiseModelId to the bundled models (rnnoise,
  speex). Coerce any retired persisted model value back to the default.
- Fix General.tsx CI typecheck failures introduced by the denoise UI: restore
  three imports the rewrite deleted (useDateFormatItems, SequenceCardStyle,
  useTauriUpdater), add the missing denoise/sound imports, and correct
  hallucinated Folds props (Text has no variant/bold; Box uses
  alignItems/justifyContent). tsc now passes with 0 errors.
- Harden the vite denoise plugin: required RNNoise/Speex/gate assets and the
  shim now fail the build loudly if missing (instead of a silent warn that
  shipped a broken ML feature), and the index.html shim injection is verified.
- CI: move the cinny-desktop submodule bump into ci.yml as a `trigger-desktop`
  job gated on `needs: build`, and delete the standalone trigger-desktop.yml.
  A failing push no longer kicks off the slow Tauri builds in parallel.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-16 01:42:21 -04:00
jared 938ead79f7 added avatar decor to element call, better themes and backgrounds, dm and group message ring issues
Trigger Desktop Build / trigger (push) Successful in 11s
CI / Build & Quality Checks (push) Failing after 13m17s
2026-06-15 23:00:50 -04:00
jared 4a401cf816 fix(calls): harden ML denoise shim against static; fix lint/format
CI / Build & Quality Checks (push) Successful in 10m26s
Trigger Desktop Build / trigger (push) Successful in 17s
ML noise suppression produced loud static on real calls. RNNoise requires
mono 48kHz float input; feeding it stereo or wrong-rate data is the classic
cause of that static. Harden the shim:
- request mono (channelCount:1) + 48kHz capture
- run a 48kHz AudioContext and BAIL to the raw mic if the browser won't
  give a true 48kHz context (wrong-rate data -> static)
- force the worklet node to explicit mono in/out
- use the non-SIMD rnnoise.wasm (SIMD build artifacts on some GPUs)
- share one AudioContext across captures

Also fix the two CI-blocking eslint errors (unused vars in UrlPreviewCard
and useLocalMessageSearch) and apply repo-wide prettier formatting so
check:eslint and check:prettier pass.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-15 20:50:00 -04:00
jared f9edd2023d feat(seasonal): tone down overlays and add visual preview grid in Settings
CI / Build & Quality Checks (push) Successful in 10m27s
Trigger Desktop Build / trigger (push) Successful in 11s
- 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 <noreply@anthropic.com>
2026-06-15 01:14:56 -04:00
jared 6f9bdc4d50 fix: work through LOTUS_BUGS.md audit items
- ExportRoomHistory: make addEvents() async, call decryptEventIfNeeded()
  before inspecting type/content so E2EE rooms export decrypted text
- UrlPreviewCard: remove Google S2 favicon (privacy leak); show
  generic Icons.Link instead — no third-party external calls
- Profile: add statusDirtyRef so server presence sync cannot clobber
  in-flight emoji insertions or keystrokes; cleared on save/clear
- useLocalMessageSearch: include m.sticker, m.poll.start, and
  org.matrix.msc3381.poll.start in encrypted room search; index poll
  question and answer bodies
- SeasonalEffect: z-index 9997 → 9999 so overlays render above
  animated chat backgrounds
- LOTUS_BUGS.md: mark all resolved, document remaining blocked items

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-15 00:09:54 -04:00
jared 6ec0ab78d9 fix: LIGHT variant bg animations, decoration grid spacing, bug doc updates
CI / Build & Quality Checks (push) Successful in 10m30s
Trigger Desktop Build / trigger (push) Successful in 6s
- chatBackground.ts: remove animRainGlowKeyframe and animGridBrightnessKeyframe
  from LIGHT anim-rain and anim-pulse definitions (these were removed from the
  import and from DARK variants in the previous session but the LIGHT variants
  were missed, leaving stale references that would cause a build error)
- ProfileDecoration.tsx: increase decoration grid gap 20→36 (visual gap was
  only 4px due to 8px image overflow beyond each 52×52 button), fix paddingBottom
  4→8 and add paddingRight:8 to prevent edge clipping
- LOTUS_BUGS.md: correct bug #8 root cause (CSP, not lazy-loading), add
  bugs #9 (grid spacing) and #10 (Windows taskbar badge)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 13:19:11 -04:00
jared e9a970a75b fix: settings dropdowns, background animations, ringing, avatar decorations
CI / Build & Quality Checks (push) Successful in 10m22s
Trigger Desktop Build / trigger (push) Successful in 7s
Settings dropdowns (Bug #3):
- Add reusable SettingsSelect component using Menu+PopOut+FocusTrap — exact
  same pattern as Message Layout, so all dropdowns look consistent
- Replace raw <select> for Seasonal Theme, UI Font, AFK Timeout, and
  Join & Leave Sounds with SettingsSelect

Animated chat backgrounds bleeding onto content (Bug #6 / #7):
- Remove filter:brightness() and opacity animations from chatBackground.ts
  (animRainGlowKeyframe, animGridBrightnessKeyframe, animFirefliesGlowKeyframe,
  animFirefliesBlinkKeyframe). These were applied to the Page element which
  caused ALL descendants (messages, composer) to flash in sync.
  Also created a CSS stacking context on Page that pushed SeasonalEffect
  (position:fixed; z-index:9997) behind the animated background layer.
- Only backgroundPosition / backgroundSize animations remain — safe, do not
  affect descendants, and do not create stacking contexts.
- Remove now-unused animation keyframe imports from chatBackground.ts.

Voice ringing in persistent rooms (Bug #5):
- Narrow the ringing condition from (Invite|Knock|Restricted) to only Invite,
  matching exactly the rooms where the call button is visible.
- Add room.isCallRoom() early-exit so m.join_rule:call rooms never ring.

Avatar decoration images not loading (Bug #8):
- Change loading="lazy" → loading="eager" in DecorationPreviewCell.
  Lazy loading does not reliably trigger for images inside nested overflow
  scroll containers (the settings panel scroll area), so images never loaded.

Docs: LOTUS_BUGS.md updated with root cause and resolution for all 5 new bugs.
Docs: LOTUS_TODO.md adds P5-35/P5-36 (deferred desktop notification/jump list).

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 12:20:47 -04:00
jared ca09e8e6ca feat: presence fix, voice ringing fix, user private notes + doc updates
CI / Build & Quality Checks (push) Successful in 10m22s
Trigger Desktop Build / trigger (push) Successful in 5s
- usePresenceUpdater: replace stale closure with readStatus() called at
  invocation time so changing custom status in Profile Settings is never
  silently overwritten by subsequent activity events
- CallEmbedProvider: fix m.space.parent state-key lookup by switching
  getStateEvent → getStateEvents (plural); space channel voice rooms no
  longer trigger the incoming-call ring/animation
- Add useUserNotes hook (io.lotus.user_notes account data, reactive via
  useAccountDataCallback, 500-char limit, cross-device sync)
- UserRoomProfile: add UserPrivateNotes textarea with 800ms debounced
  auto-save, saving indicator, char counter when <100 chars remain;
  shown only when viewing another user's profile
- LOTUS_FEATURES.md: add Private Notes section, Status Revert fix note,
  animation improvements subsection, Seasonal Themes section
- LOTUS_BUGS.md: mark presence revert + voice ringing bugs as resolved
- README.md + landing/index.html: document all new June 2026 features

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 00:47:14 -04:00
jared 6db07f1371 feat: seasonal theme overlays + improved animated chat backgrounds
Adds 11 CSS-only seasonal overlays (Halloween, Christmas, New Year, Autumn,
April Fool's, Lunar New Year, Valentine's Day, St. Patrick's Day, Earth Day,
Deep Space, Retro Arcade) with date-based auto-detection and a manual override
dropdown in Settings → Appearance → Seasonal Theme. All themes respect
prefers-reduced-motion. SeasonalEffect mounts at z-index 9997 in App.tsx.

Also rewrites all 5 animated chat background keyframes for smoother, more
organic motion: Digital Rain gains a phosphor glow flicker; Star Drift now
loops each layer by exactly its own tile size (no more seam); Grid Pulse adds
an independent brightness oscillation at a prime period; Aurora Flow drives
all four gradient layers through distinct paths; Fireflies adds glow-pulse and
opacity-blink animations at prime periods for unsynchronised bioluminescence.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-14 00:33:04 -04:00
jared aa48c9ef8a Fix three open bugs from LOTUS_BUGS.md
CI / Build & Quality Checks (push) Successful in 10m38s
Trigger Desktop Build / trigger (push) Failing after 5s
- EditHistoryModal: decrypt fetched edit events in E2EE rooms via
  mx.decryptEventIfNeeded() before rendering; previously events not
  found in the room cache showed ciphertext or "(no text)"
- CallEmbedProvider: add touch support for PiP resize corners;
  extracted shared applyResize() helper; onTouchStart wired to all
  four corners alongside existing onMouseDown
- RoomView: skip chatBgStyle when glassmorphism is active; document.body
  already carries the background for the blur effect, rendering it twice
  doubled CSS animation work unnecessarily

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-12 18:17:35 -04:00
jared 46567555e1 fix: ESLint errors and Prettier formatting
CI / Build & Quality Checks (push) Successful in 10m27s
Trigger Desktop Build / trigger (push) Successful in 5s
ESLint errors:
- usePresenceUpdater: remove redundant `const userId` inside handlePageHide
  that shadowed the outer declaration (no-shadow)
- RoomViewHeader: prefix unused encryptedRoom with _ (no-unused-vars)

Prettier: reformat 14 files to match project style

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 22:55:32 -04:00
jared 5469740f4c feat: P5-21 mention color, P5-22 font selector, P5-27 notification presets; update docs
CI / Build & Quality Checks (push) Successful in 10m27s
Trigger Desktop Build / trigger (push) Successful in 7s
- P5-21: Custom @mention highlight color picker in Settings → Appearance.
  CSS vars with luminance-computed text color; resets cleanly to theme default.
- P5-22: Font selector (System, Inter, JetBrains Mono, Fira Code) in
  Settings → Appearance. Fira Code added to Google Fonts preload.
- P5-27: Gaming/Work/Sleep preset buttons at top of Settings → Notifications.
  Each atomically applies a group of notification settings.
- AppearanceEffects component in App.tsx applies CSS vars on settings change.
- LOTUS_BUGS.md: mark presence + manifest icon bugs as resolved.
- LOTUS_TODO.md: mark P3-6, P5-21, P5-22, P5-27 as [x].
- LOTUS_FEATURES.md: document all four completed features.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 15:39:35 -04:00
jared 170d22eebb docs: update LOTUS_BUGS.md to reflect all recently fixed items
CI / Build & Quality Checks (push) Successful in 10m39s
Trigger Desktop Build / trigger (push) Failing after 6s
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-10 00:05:25 -04:00
jared ea15db430c docs: add feature reference, bug tracker, and implementation notes
CI / Build & Quality Checks (push) Successful in 11m51s
Trigger Desktop Build / trigger (push) Failing after 4s
- LOTUS_FEATURES.md: full reference of every custom Lotus feature with
  implementation details, file paths, and API notes
- LOTUS_BUGS.md: audit of confirmed bugs with root causes and fixes
- LOTUS_TODO_REFERENCE.md: technical implementation notes for backlog items
- LOTUS_TODO.md: trim completed audit results section, link to FEATURES doc
- README.md: rewrite to marketing-friendly feature list format; fix
  incorrect claim that screenshare auto-reverts view to grid (removed)

Fix: auto-revert spotlight on screenshare was removed (600ms grid-click
caused fullscreen to show avatars); corrected in LOTUS_FEATURES.md and
removed from README.md.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-09 18:41:24 -04:00