Files
element-call/src/components/MediaMuteAndSwitchButton.module.css
T
fkwpandClaude Opus 5.5 fb7c3296b6 Guard what can be added as a background
- Five of one's own at most, so the grid is whole: at the limit the add
  tile goes, and it comes back once one is removed. The store holds the
  limit too.
- An added image is refused if it isn't an image, is animated, or can't
  be decoded; reduced to 1920px on its longest edge; and laid on an opaque
  ground, since a transparent pixel would be a hole in the background.
- Animation is read from the file, as a still and an animated WebP share
  a type. Chromium has no selected track until the decoder's tracks are
  ready; without waiting for them an animated GIF got through.
- A refusal says why, in place of the notice, and is scrolled into view.
  It can be dismissed, is gone once the menu closes, and the next shows
  even if it reads the same. What was in force stays.
- End to end on Chromium and Firefox, from what the device then keeps: an
  animated GIF is refused with its message, a 4000x3000 image is kept at
  1920x1440, and a half transparent one is kept opaque. All three fail
  with the preparation bypassed.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
2026-09-26 07:38:46 +02:00

123 lines
3.3 KiB
CSS

/*
Copyright 2026 Element Creations Ltd.
SPDX-License-Identifier: AGPL-3.0-only OR LicenseRef-Element-Commercial
Please see LICENSE in the repository root for full details.
*/
.container {
display: flex;
flex-direction: row;
align-items: center;
background-color: var(--cpd-color-bg-subtle-secondary);
border-radius: 32px;
transition: background-color 0.2s ease-in-out;
}
.containerOpen {
background-color: var(--cpd-color-bg-action-primary-pressed);
}
.chevronIconOpen > svg {
color: var(--cpd-color-icon-on-solid-primary);
}
.menuButton {
width: 40px;
background-color: transparent !important;
}
.itemIcon {
color: var(--cpd-color-text-secondary);
}
.rotate {
animation: spinner 1.5s linear infinite;
}
@keyframes spinner {
to {
transform: rotate(360deg);
}
}
.menu {
display: flex;
flex-direction: column;
}
/* Only the device lists scroll, bounded by the measured call area: the menu is
portalled out of the root, so CSS can't size it against the call. */
.deviceList {
/* A list that scrolls can paint above the menu's outline, hiding it. */
margin-inline: var(--cpd-border-width-1);
inline-size: calc(
var(--device-list-inline-size) - 2 * var(--cpd-border-width-1)
);
overflow-y: auto;
min-block-size: 0;
max-block-size: var(--device-list-max-height);
/* Keeps a row reached by keyboard clear of the sticky heading and meter. */
scroll-padding-block: var(--device-list-scroll-padding-start, 0)
var(--device-list-scroll-padding-end, 0);
}
/* Compound's heading rule heads each section; the design adds space below it. */
.menu h3 {
margin-block-end: var(--cpd-space-5x);
}
/* And more above a heading that follows another section. */
.deviceList [role="group"] + [role="group"] h3 {
margin-block-start: var(--cpd-space-7x);
}
/* Sticky within its own section. Opaque and inset a border width so it doesn't
paint over the menu's outline; raised, or the positioned tiles scroll over
it. */
.sectionHeading {
position: sticky;
z-index: 1;
inset-block-start: 0;
background: var(--cpd-color-bg-canvas-default);
margin-block-start: var(--cpd-border-width-1);
}
/* Sticky at the foot of the microphone section; opaque and inset as above. */
.stickyMeter {
position: sticky;
inset-block-end: 0;
background: var(--cpd-color-bg-canvas-default);
margin-block-end: var(--cpd-border-width-1);
}
/* Radix focuses whatever the pointer is over, so the browser's ring would
follow the mouse. Replaced by one shown only for keyboard focus. */
.menu [role^="menuitem"]:focus,
.menu [role^="menuitem"]:focus-visible {
outline: none;
}
.menu[data-focus-source="keyboard"] [role^="menuitem"]:focus {
outline: var(--cpd-border-width-2) solid var(--cpd-color-border-focused);
outline-offset: calc(-1 * var(--cpd-border-width-2));
}
.notice {
display: flex;
align-items: flex-start;
gap: var(--cpd-space-3x);
margin: var(--cpd-space-2x)
calc(var(--cpd-space-4x) - var(--cpd-border-width-1)) 0;
padding: var(--cpd-space-3x);
border-radius: var(--cpd-space-2x);
background: var(--cpd-color-bg-subtle-secondary);
color: var(--cpd-color-text-primary);
font: var(--cpd-font-body-md-regular);
}
.notice > svg {
flex-shrink: 0;
color: var(--cpd-color-icon-secondary);
}
.refusal {
margin: var(--cpd-space-2x)
calc(var(--cpd-space-4x) - var(--cpd-border-width-1)) 0;
}