fix: screenshare dismiss, GIF header, PiP resize, call subtitle, CSS vars
CI / Build & Quality Checks (push) Failing after 5m37s

- CallControls: screenshare confirm now closes on Escape or click-outside
  (transparent fixed backdrop + window keydown listener); cleaned indentation
- GifPicker: TDS header rendered a JSX comment ({/* GIF_SEARCH */}) so the
  // GIF_SEARCH label was invisible; changed to {'// GIF_SEARCH'}
- CallEmbedProvider: PiP resize clamping now works at initial bottom/right
  position by normalising to top/left before parsing el.style.left
- CallEmbedProvider: incoming call subtitle now reads 'Incoming Video Call'
  or 'Incoming Voice Call' based on m.call.intent
- PollContent: progress bar background now uses --bg-surface-active /
  --bg-surface-low instead of hardcoded white (invisible in light mode)
- index.css + lotus-terminal.css.ts: define --bg-surface, --bg-surface-low,
  --bg-surface-active, --bg-surface-border, --text-primary as global CSS vars
  with vanilla fallbacks and TDS dark/light overrides; these were used by
  poll, location map, upload card and GIF picker but never defined

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-05-23 22:51:56 -04:00
parent 2eb5e94aed
commit dd5cede31d
6 changed files with 98 additions and 51 deletions
+5 -1
View File
@@ -190,7 +190,9 @@ function IncomingCall({ dm, info, onIgnore, onAnswer, onReject }: IncomingCallPr
<Text size="H3" align="Center" truncate> <Text size="H3" align="Center" truncate>
{roomName} {roomName}
</Text> </Text>
<Text size="T300">Incoming Call</Text> <Text size="T300">
{info.intent === 'video' ? 'Incoming Video Call' : 'Incoming Voice Call'}
</Text>
</Box> </Box>
</Box> </Box>
{!livekitSupported && ( {!livekitSupported && (
@@ -490,6 +492,8 @@ export function CallEmbedProvider({ children }: CallEmbedProviderProps) {
const onPipWindowResize = (): void => { const onPipWindowResize = (): void => {
const el = callEmbedRef.current; const el = callEmbedRef.current;
if (!el) return; if (!el) return;
// Normalise bottom/right → top/left so clamp math works regardless of initial position.
if (!el.style.left || el.style.left === 'auto') normaliseToTopLeft(el);
const l = parseFloat(el.style.left); const l = parseFloat(el.style.left);
const t = parseFloat(el.style.top); const t = parseFloat(el.style.top);
if (!isNaN(l)) if (!isNaN(l))
+1 -1
View File
@@ -45,7 +45,7 @@ function GifPickerInner({ onSelect, requestClose, lotusTerminal }: GifPickerInne
userSelect: 'none', userSelect: 'none',
}} }}
> >
{/* GIF_SEARCH */} {'// GIF_SEARCH'}
</div> </div>
)} )}
<Box style={{ padding: '8px 8px 4px' }}> <Box style={{ padding: '8px 8px 4px' }}>
@@ -280,7 +280,9 @@ export function PollContent({
position: 'absolute', position: 'absolute',
inset: 0, inset: 0,
width: `${pct}%`, width: `${pct}%`,
background: selected ? 'rgba(255,255,255,0.10)' : 'rgba(255,255,255,0.05)', background: selected
? 'var(--bg-surface-active)'
: 'var(--bg-surface-low)',
borderRadius: '8px', borderRadius: '8px',
pointerEvents: 'none', pointerEvents: 'none',
}} }}
+16 -1
View File
@@ -55,6 +55,14 @@ export function CallControls({ callEmbed }: CallControlsProps) {
const [cords, setCords] = useState<RectCords>(); const [cords, setCords] = useState<RectCords>();
const [shareConfirm, setShareConfirm] = useState(false); const [shareConfirm, setShareConfirm] = useState(false);
useEffect(() => {
if (!shareConfirm) return;
const onKeyDown = (e: KeyboardEvent) => {
if (e.key === 'Escape') setShareConfirm(false);
};
window.addEventListener('keydown', onKeyDown);
return () => window.removeEventListener('keydown', onKeyDown);
}, [shareConfirm]);
const [pttMode] = useSetting(settingsAtom, 'pttMode'); const [pttMode] = useSetting(settingsAtom, 'pttMode');
const [pttKey] = useSetting(settingsAtom, 'pttKey'); const [pttKey] = useSetting(settingsAtom, 'pttKey');
const [lotusTerminal] = useSetting(settingsAtom, 'lotusTerminal'); const [lotusTerminal] = useSetting(settingsAtom, 'lotusTerminal');
@@ -234,6 +242,12 @@ export function CallControls({ callEmbed }: CallControlsProps) {
</Chip> </Chip>
))} ))}
{shareConfirm && ( {shareConfirm && (
<>
<div
style={{ position: 'fixed', inset: 0, zIndex: 99 }}
onClick={() => setShareConfirm(false)}
aria-hidden="true"
/>
<Box <Box
style={{ style={{
position: 'absolute', position: 'absolute',
@@ -241,7 +255,7 @@ export function CallControls({ callEmbed }: CallControlsProps) {
left: '50%', left: '50%',
transform: 'translateX(-50%)', transform: 'translateX(-50%)',
background: 'var(--bg-surface)', background: 'var(--bg-surface)',
border: '1px solid var(--border-color)', border: '1px solid var(--bg-surface-border)',
borderRadius: '0.75rem', borderRadius: '0.75rem',
padding: '1rem 1.25rem', padding: '1rem 1.25rem',
zIndex: 100, zIndex: 100,
@@ -283,6 +297,7 @@ export function CallControls({ callEmbed }: CallControlsProps) {
</Button> </Button>
</Box> </Box>
</Box> </Box>
</>
)} )}
<SequenceCard <SequenceCard
className={css.ControlCard} className={css.ControlCard}
+14
View File
@@ -9,6 +9,13 @@
:root { :root {
--tc-link: hsl(213deg 100% 45%); --tc-link: hsl(213deg 100% 45%);
/* semantic surface vars used by poll, location, upload card, gif picker */
--bg-surface: #ffffff;
--bg-surface-low: rgba(0, 0, 0, 0.04);
--bg-surface-active: rgba(0, 0, 0, 0.10);
--bg-surface-border: rgba(0, 0, 0, 0.14);
--text-primary: #1a1a1a;
/* user mxid colors */ /* user mxid colors */
--mx-uc-1: hsl(208, 100%, 45%); --mx-uc-1: hsl(208, 100%, 45%);
--mx-uc-2: hsl(302, 100%, 30%); --mx-uc-2: hsl(302, 100%, 30%);
@@ -27,6 +34,13 @@
.butter-theme { .butter-theme {
--tc-link: hsl(213deg 100% 80%); --tc-link: hsl(213deg 100% 80%);
/* semantic surface vars — dark overrides */
--bg-surface: #25272e;
--bg-surface-low: rgba(255, 255, 255, 0.05);
--bg-surface-active: rgba(255, 255, 255, 0.10);
--bg-surface-border: rgba(255, 255, 255, 0.12);
--text-primary: #e0e5ed;
--mx-uc-1: hsl(208, 100%, 75%); --mx-uc-1: hsl(208, 100%, 75%);
--mx-uc-2: hsl(301, 100%, 80%); --mx-uc-2: hsl(301, 100%, 80%);
--mx-uc-3: hsl(163, 100%, 70%); --mx-uc-3: hsl(163, 100%, 70%);
+12
View File
@@ -85,6 +85,12 @@ export const lotusTerminalBodyClass = style({
'--lt-font-mono': "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Courier New', monospace", '--lt-font-mono': "'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'Courier New', monospace",
'--lt-font-display': "'JetBrains Mono', 'Fira Code', 'Courier New', monospace", '--lt-font-display': "'JetBrains Mono', 'Fira Code', 'Courier New', monospace",
'--lt-font-crt': "'VT323', 'Courier New', monospace", '--lt-font-crt': "'VT323', 'Courier New', monospace",
// Semantic surface aliases (poll, location, upload card, gif picker)
'--bg-surface': '#07101a',
'--bg-surface-low': '#060c14',
'--bg-surface-active': 'rgba(0,212,255,0.12)',
'--bg-surface-border': 'rgba(0,212,255,0.20)',
'--text-primary': '#c4d9ee',
} as any, } as any,
}); });
@@ -436,6 +442,12 @@ globalStyle(`html[data-theme="light"] body.${lotusTerminalBodyClass}`, {
'--lt-box-glow-green': '0 0 0 2px rgba(0,109,53,0.22), 0 2px 8px rgba(0,109,53,0.12)', '--lt-box-glow-green': '0 0 0 2px rgba(0,109,53,0.22), 0 2px 8px rgba(0,109,53,0.12)',
'--lt-box-glow-red': '0 0 0 2px rgba(181,0,31,0.22), 0 2px 8px rgba(181,0,31,0.12)', '--lt-box-glow-red': '0 0 0 2px rgba(181,0,31,0.22), 0 2px 8px rgba(181,0,31,0.12)',
'--lt-box-glow-amber': '0 0 0 2px rgba(138,90,0,0.22), 0 2px 8px rgba(138,90,0,0.12)', '--lt-box-glow-amber': '0 0 0 2px rgba(138,90,0,0.22), 0 2px 8px rgba(138,90,0,0.12)',
// Semantic surface aliases — light overrides
'--bg-surface': '#ffffff',
'--bg-surface-low': '#e2e7ef',
'--bg-surface-active': 'rgba(0,98,184,0.10)',
'--bg-surface-border': 'rgba(0,98,184,0.22)',
'--text-primary': '#111827',
} as any, } as any,
}); });