fix(ui): resolve 29 native UI/UX inconsistencies from folds design audit
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>
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
import React, { useCallback, useEffect, useRef, useState } from 'react';
|
||||
import { Box, Icon, IconButton, Icons, Text, config, toRem } from 'folds';
|
||||
import { Box, Icon, IconButton, Icons, Text, color, config, toRem } from 'folds';
|
||||
import { useSetting } from '../state/hooks/settings';
|
||||
import { settingsAtom } from '../state/settings';
|
||||
|
||||
@@ -51,6 +51,8 @@ export function VoiceMessageRecorder({ onSend, onError }: VoiceRecorderProps) {
|
||||
|
||||
const previewMimeRef = useRef('audio/ogg;codecs=opus');
|
||||
const previewDurationRef = useRef(0);
|
||||
const previewAudioRef = useRef<HTMLAudioElement | null>(null);
|
||||
const [previewPlaying, setPreviewPlaying] = useState(false);
|
||||
|
||||
const stopAll = useCallback(() => {
|
||||
if (animFrameRef.current) cancelAnimationFrame(animFrameRef.current);
|
||||
@@ -192,7 +194,7 @@ export function VoiceMessageRecorder({ onSend, onError }: VoiceRecorderProps) {
|
||||
alignItems="Center"
|
||||
gap="200"
|
||||
style={{
|
||||
background: 'var(--bg-surface-variant)',
|
||||
background: color.SurfaceVariant.Container,
|
||||
borderRadius: config.radii.R300,
|
||||
padding: `${toRem(4)} ${toRem(8)}`,
|
||||
}}
|
||||
@@ -203,7 +205,7 @@ export function VoiceMessageRecorder({ onSend, onError }: VoiceRecorderProps) {
|
||||
width: toRem(8),
|
||||
height: toRem(8),
|
||||
borderRadius: '50%',
|
||||
background: lotusTerminal ? 'var(--lt-accent-orange)' : 'var(--tc-danger-normal)',
|
||||
background: lotusTerminal ? 'var(--lt-accent-orange)' : color.Critical.Main,
|
||||
flexShrink: 0,
|
||||
animation: 'pttLivePulse 900ms ease-in-out infinite',
|
||||
}}
|
||||
@@ -237,7 +239,7 @@ export function VoiceMessageRecorder({ onSend, onError }: VoiceRecorderProps) {
|
||||
width: toRem(2),
|
||||
height: toRem(2 + (h / barMax) * 16),
|
||||
borderRadius: toRem(1),
|
||||
background: lotusTerminal ? 'var(--lt-accent-green)' : 'var(--tc-primary-normal)',
|
||||
background: lotusTerminal ? 'var(--lt-accent-green)' : color.Primary.Main,
|
||||
flexShrink: 0,
|
||||
}}
|
||||
/>
|
||||
@@ -273,13 +275,36 @@ export function VoiceMessageRecorder({ onSend, onError }: VoiceRecorderProps) {
|
||||
alignItems="Center"
|
||||
gap="200"
|
||||
style={{
|
||||
background: 'var(--bg-surface-variant)',
|
||||
background: color.SurfaceVariant.Container,
|
||||
borderRadius: config.radii.R300,
|
||||
padding: `${toRem(4)} ${toRem(8)}`,
|
||||
}}
|
||||
>
|
||||
{previewUrl && (
|
||||
<audio src={previewUrl} controls style={{ height: toRem(28), maxWidth: toRem(180) }} />
|
||||
<>
|
||||
<audio ref={previewAudioRef} src={previewUrl} onEnded={() => setPreviewPlaying(false)} />
|
||||
<IconButton
|
||||
onClick={() => {
|
||||
const audio = previewAudioRef.current;
|
||||
if (!audio) return;
|
||||
if (previewPlaying) {
|
||||
audio.pause();
|
||||
setPreviewPlaying(false);
|
||||
} else {
|
||||
audio.play();
|
||||
setPreviewPlaying(true);
|
||||
}
|
||||
}}
|
||||
aria-label={previewPlaying ? 'Pause preview' : 'Play preview'}
|
||||
variant="Secondary"
|
||||
fill="Soft"
|
||||
size="300"
|
||||
radii="300"
|
||||
title={previewPlaying ? 'Pause' : 'Play'}
|
||||
>
|
||||
<Icon src={previewPlaying ? Icons.Pause : Icons.Play} size="100" />
|
||||
</IconButton>
|
||||
</>
|
||||
)}
|
||||
<Text size="T200" style={{ fontVariantNumeric: 'tabular-nums', flexShrink: 0 }}>
|
||||
{formatDuration(previewDurationRef.current)}
|
||||
|
||||
Reference in New Issue
Block a user