fix(ui): folds primitives for RouteError + PiP fullscreen button (native-cinny audit 5/N)
CI / Build & Quality Checks (push) Successful in 10m33s
CI / Trigger Desktop Build (push) Successful in 21s

- RouteError: raw <div>/<h2>/<p>/<button> (sans-serif, raw px) -> folds
  Box/Text/Button with config tokens.
- CallEmbedProvider PiP fullscreen control: raw <button> with ⊡/⛶ glyphs ->
  folds IconButton reusing the exported FullscreenIcon/ExitFullscreenIcon SVGs
  from Controls (consistent with the main fullscreen button). The intentional
  dark over-video scrim is kept.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
2026-06-28 22:32:19 -04:00
parent 24d6460e4c
commit 349194e7e5
3 changed files with 28 additions and 41 deletions
+9 -12
View File
@@ -9,6 +9,7 @@ import {
config, config,
Dialog, Dialog,
Icon, Icon,
IconButton,
Icons, Icons,
Overlay, Overlay,
OverlayBackdrop, OverlayBackdrop,
@@ -51,6 +52,7 @@ import { mxcUrlToHttp, getMxIdLocalPart } from '../utils/matrix';
import { RoomAvatar, RoomIcon } from './room-avatar'; import { RoomAvatar, RoomIcon } from './room-avatar';
import { useRoomNavigate } from '../hooks/useRoomNavigate'; import { useRoomNavigate } from '../hooks/useRoomNavigate';
import { getChatBg } from '../features/lotus/chatBackground'; import { getChatBg } from '../features/lotus/chatBackground';
import { ExitFullscreenIcon, FullscreenIcon } from '../features/call/Controls';
import { useTheme, ThemeKind } from '../hooks/useTheme'; import { useTheme, ThemeKind } from '../hooks/useTheme';
import { useSetting } from '../state/hooks/settings'; import { useSetting } from '../state/hooks/settings';
import { settingsAtom } from '../state/settings'; import { settingsAtom } from '../state/settings';
@@ -1095,10 +1097,13 @@ export function CallEmbedProvider({ children }: CallEmbedProviderProps) {
> >
<div style={{ display: 'flex', gap: config.space.S100, alignItems: 'center' }}> <div style={{ display: 'flex', gap: config.space.S100, alignItems: 'center' }}>
{document.fullscreenEnabled && ( {document.fullscreenEnabled && (
<button <IconButton
type="button" type="button"
size="300"
radii="300"
variant="Surface"
fill="None"
aria-label={pipIsFullscreen ? 'Exit fullscreen' : 'Fullscreen camera'} aria-label={pipIsFullscreen ? 'Exit fullscreen' : 'Fullscreen camera'}
title={pipIsFullscreen ? 'Exit fullscreen' : 'Fullscreen camera'}
onClick={(e) => { onClick={(e) => {
e.stopPropagation(); e.stopPropagation();
handlePipFullscreen(); handlePipFullscreen();
@@ -1107,19 +1112,11 @@ export function CallEmbedProvider({ children }: CallEmbedProviderProps) {
// Dark scrim is intentional for legibility over arbitrary video. // Dark scrim is intentional for legibility over arbitrary video.
background: 'rgba(0,0,0,0.65)', background: 'rgba(0,0,0,0.65)',
backdropFilter: 'blur(4px)', backdropFilter: 'blur(4px)',
border: 'none',
borderRadius: config.radii.R300,
padding: `${config.space.S100} ${config.space.S200}`,
color: '#fff', color: '#fff',
fontSize: '13px',
cursor: 'pointer',
lineHeight: 1,
display: 'flex',
alignItems: 'center',
}} }}
> >
{pipIsFullscreen ? '⊡' : '⛶'} {pipIsFullscreen ? <ExitFullscreenIcon /> : <FullscreenIcon />}
</button> </IconButton>
)} )}
<div <div
style={{ style={{
+2 -2
View File
@@ -166,13 +166,13 @@ export function ScreenShareButton({ enabled, onToggle }: ScreenShareButtonProps)
); );
} }
const FullscreenIcon = () => ( export const FullscreenIcon = () => (
<svg width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor"> <svg width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor">
<path d="M3 3h6v2H5v4H3V3zm12 0h6v6h-2V5h-4V3zM3 15h2v4h4v2H3v-6zm16 4h-4v2h6v-6h-2v4z" /> <path d="M3 3h6v2H5v4H3V3zm12 0h6v6h-2V5h-4V3zM3 15h2v4h4v2H3v-6zm16 4h-4v2h6v-6h-2v4z" />
</svg> </svg>
); );
const ExitFullscreenIcon = () => ( export const ExitFullscreenIcon = () => (
<svg width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor"> <svg width="1em" height="1em" viewBox="0 0 24 24" fill="currentColor">
<path d="M9 3H7v4H3v2h6V3zm6 0v6h6V7h-4V3h-2zM3 13v2h4v4h2v-6H3zm14 4v-4h2v6h-6v-2h4z" /> <path d="M9 3H7v4H3v2h6V3zm6 0v6h6V7h-4V3h-2zM3 13v2h4v4h2v-6H3zm14 4v-4h2v6h-6v-2h4z" />
</svg> </svg>
+17 -27
View File
@@ -1,5 +1,6 @@
import React from 'react'; import React from 'react';
import { useRouteError, isRouteErrorResponse } from 'react-router-dom'; import { useRouteError, isRouteErrorResponse } from 'react-router-dom';
import { Box, Button, config, Text, toRem } from 'folds';
export function RouteError() { export function RouteError() {
const error = useRouteError(); const error = useRouteError();
@@ -11,33 +12,22 @@ export function RouteError() {
: 'An unexpected error occurred.'; : 'An unexpected error occurred.';
return ( return (
<div <Box
style={{ direction="Column"
display: 'flex', alignItems="Center"
flexDirection: 'column', justifyContent="Center"
alignItems: 'center', gap="400"
justifyContent: 'center', style={{ height: '100dvh', padding: config.space.S700 }}
height: '100dvh',
gap: '16px',
padding: '32px',
fontFamily: 'sans-serif',
}}
> >
<h2 style={{ margin: 0, fontSize: '1.25rem' }}>Something went wrong</h2> <Text size="H3">Something went wrong</Text>
<p style={{ margin: 0, opacity: 0.7, textAlign: 'center' }}>{message}</p> <Text size="T300" priority="300" style={{ textAlign: 'center', maxWidth: toRem(400) }}>
<button {message}
type="button" </Text>
onClick={() => window.location.reload()} <Button variant="Primary" onClick={() => window.location.reload()}>
style={{ <Text as="span" size="B400">
padding: '8px 20px', Reload
borderRadius: '8px', </Text>
border: 'none', </Button>
cursor: 'pointer', </Box>
fontWeight: 600,
}}
>
Reload
</button>
</div>
); );
} }