fix: screenshare dismiss, GIF header, PiP resize, call subtitle, CSS vars
- 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:
@@ -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))
|
||||||
|
|||||||
@@ -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',
|
||||||
}}
|
}}
|
||||||
|
|||||||
@@ -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,55 +242,62 @@ export function CallControls({ callEmbed }: CallControlsProps) {
|
|||||||
</Chip>
|
</Chip>
|
||||||
))}
|
))}
|
||||||
{shareConfirm && (
|
{shareConfirm && (
|
||||||
<Box
|
<>
|
||||||
style={{
|
<div
|
||||||
position: 'absolute',
|
style={{ position: 'fixed', inset: 0, zIndex: 99 }}
|
||||||
bottom: '110%',
|
onClick={() => setShareConfirm(false)}
|
||||||
left: '50%',
|
aria-hidden="true"
|
||||||
transform: 'translateX(-50%)',
|
/>
|
||||||
background: 'var(--bg-surface)',
|
<Box
|
||||||
border: '1px solid var(--border-color)',
|
style={{
|
||||||
borderRadius: '0.75rem',
|
position: 'absolute',
|
||||||
padding: '1rem 1.25rem',
|
bottom: '110%',
|
||||||
zIndex: 100,
|
left: '50%',
|
||||||
minWidth: '260px',
|
transform: 'translateX(-50%)',
|
||||||
boxShadow: '0 8px 32px rgba(0,0,0,0.35)',
|
background: 'var(--bg-surface)',
|
||||||
display: 'flex',
|
border: '1px solid var(--bg-surface-border)',
|
||||||
flexDirection: 'column',
|
borderRadius: '0.75rem',
|
||||||
gap: '0.75rem',
|
padding: '1rem 1.25rem',
|
||||||
}}
|
zIndex: 100,
|
||||||
>
|
minWidth: '260px',
|
||||||
<Text size="T300" style={{ fontWeight: 600 }}>
|
boxShadow: '0 8px 32px rgba(0,0,0,0.35)',
|
||||||
Share your screen?
|
display: 'flex',
|
||||||
</Text>
|
flexDirection: 'column',
|
||||||
<Text size="T200" style={{ opacity: 0.75 }}>
|
gap: '0.75rem',
|
||||||
Your screen will be visible to all participants in this call.
|
}}
|
||||||
</Text>
|
>
|
||||||
<Box gap="200">
|
<Text size="T300" style={{ fontWeight: 600 }}>
|
||||||
<Button
|
Share your screen?
|
||||||
size="300"
|
</Text>
|
||||||
variant="Success"
|
<Text size="T200" style={{ opacity: 0.75 }}>
|
||||||
fill="Solid"
|
Your screen will be visible to all participants in this call.
|
||||||
radii="300"
|
</Text>
|
||||||
onClick={() => {
|
<Box gap="200">
|
||||||
callEmbed.control.toggleScreenshare();
|
<Button
|
||||||
setShareConfirm(false);
|
size="300"
|
||||||
}}
|
variant="Success"
|
||||||
>
|
fill="Solid"
|
||||||
<Text size="B300">Share</Text>
|
radii="300"
|
||||||
</Button>
|
onClick={() => {
|
||||||
<Button
|
callEmbed.control.toggleScreenshare();
|
||||||
size="300"
|
setShareConfirm(false);
|
||||||
variant="Secondary"
|
}}
|
||||||
fill="Soft"
|
>
|
||||||
radii="300"
|
<Text size="B300">Share</Text>
|
||||||
outlined
|
</Button>
|
||||||
onClick={() => setShareConfirm(false)}
|
<Button
|
||||||
>
|
size="300"
|
||||||
<Text size="B300">Cancel</Text>
|
variant="Secondary"
|
||||||
</Button>
|
fill="Soft"
|
||||||
|
radii="300"
|
||||||
|
outlined
|
||||||
|
onClick={() => setShareConfirm(false)}
|
||||||
|
>
|
||||||
|
<Text size="B300">Cancel</Text>
|
||||||
|
</Button>
|
||||||
|
</Box>
|
||||||
</Box>
|
</Box>
|
||||||
</Box>
|
</>
|
||||||
)}
|
)}
|
||||||
<SequenceCard
|
<SequenceCard
|
||||||
className={css.ControlCard}
|
className={css.ControlCard}
|
||||||
|
|||||||
@@ -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%);
|
||||||
|
|||||||
@@ -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,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user