mirror of
https://github.com/vector-im/element-call.git
synced 2026-06-30 18:02:56 +00:00
Let page background shine through spotlight tiles
By giving spotlight tiles a transparent background in certain layouts.
This commit is contained in:
@@ -26,7 +26,7 @@ export function oneOnOnePortraitLayout(
|
||||
prevTiles: TileStore,
|
||||
): [OneOnOnePortraitLayout, TileStore] {
|
||||
const update = prevTiles.from(media.pip === undefined ? 0 : 1);
|
||||
update.registerSpotlight([media.spotlight], true);
|
||||
update.registerSpotlight([media.spotlight], true, "transparent");
|
||||
if (media.pip !== undefined) update.registerGridTile(media.pip);
|
||||
const tiles = update.build();
|
||||
|
||||
|
||||
@@ -21,6 +21,7 @@ export function pipLayout(
|
||||
update.registerSpotlight(
|
||||
media.spotlight,
|
||||
platform === "desktop" ? false : true,
|
||||
"transparent",
|
||||
);
|
||||
const tiles = update.build();
|
||||
return [
|
||||
|
||||
@@ -23,7 +23,7 @@ export function spotlightExpandedLayout(
|
||||
prevTiles: TileStore,
|
||||
): [SpotlightExpandedLayout, TileStore] {
|
||||
const update = prevTiles.from(1);
|
||||
update.registerSpotlight(media.spotlight, true);
|
||||
update.registerSpotlight(media.spotlight, true, "transparent");
|
||||
if (media.pip !== undefined) update.registerPipTile(media.pip);
|
||||
const tiles = update.build();
|
||||
|
||||
|
||||
@@ -39,12 +39,29 @@ class SpotlightTileData {
|
||||
this.maximised$.next(value);
|
||||
}
|
||||
|
||||
private readonly bgStyle$: BehaviorSubject<"solid" | "transparent">;
|
||||
public get bgStyle(): "solid" | "transparent" {
|
||||
return this.bgStyle$.value;
|
||||
}
|
||||
public set bgStyle(value: "solid" | "transparent") {
|
||||
this.bgStyle$.next(value);
|
||||
}
|
||||
|
||||
public readonly vm: SpotlightTileViewModel;
|
||||
|
||||
public constructor(media: MediaViewModel[], maximised: boolean) {
|
||||
public constructor(
|
||||
media: MediaViewModel[],
|
||||
maximised: boolean,
|
||||
bgStyle: "solid" | "transparent",
|
||||
) {
|
||||
this.media$ = new BehaviorSubject(media);
|
||||
this.maximised$ = new BehaviorSubject(maximised);
|
||||
this.vm = new SpotlightTileViewModel(this.media$, this.maximised$);
|
||||
this.bgStyle$ = new BehaviorSubject(bgStyle);
|
||||
this.vm = new SpotlightTileViewModel(
|
||||
this.media$,
|
||||
this.maximised$,
|
||||
this.bgStyle$,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -157,7 +174,11 @@ export class TileStoreBuilder {
|
||||
* Sets the contents of the spotlight tile. If this is never called, there
|
||||
* will be no spotlight tile.
|
||||
*/
|
||||
public registerSpotlight(media: MediaViewModel[], maximised: boolean): void {
|
||||
public registerSpotlight(
|
||||
media: MediaViewModel[],
|
||||
maximised: boolean,
|
||||
bgStyle: "solid" | "transparent" = "solid",
|
||||
): void {
|
||||
if (DEBUG_ENABLED)
|
||||
logger.debug(
|
||||
`[TileStore, ${this.generation}] register spotlight: ${media.map((m) => m.displayName$.value)}`,
|
||||
@@ -169,11 +190,12 @@ export class TileStoreBuilder {
|
||||
|
||||
// Reuse the previous spotlight tile if it exists
|
||||
if (this.prevSpotlight === null) {
|
||||
this.spotlight = new SpotlightTileData(media, maximised);
|
||||
this.spotlight = new SpotlightTileData(media, maximised, bgStyle);
|
||||
} else {
|
||||
this.spotlight = this.prevSpotlight;
|
||||
this.spotlight.media = media;
|
||||
this.spotlight.maximised = maximised;
|
||||
this.spotlight.bgStyle = bgStyle;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -37,6 +37,7 @@ export class SpotlightTileViewModel {
|
||||
public constructor(
|
||||
public readonly media$: Behavior<MediaViewModel[]>,
|
||||
public readonly maximised$: Behavior<boolean>,
|
||||
public readonly bgStyle$: Behavior<"solid" | "transparent">,
|
||||
) {}
|
||||
}
|
||||
|
||||
|
||||
@@ -41,13 +41,16 @@ Please see LICENSE in the repository root for full details.
|
||||
|
||||
.bg {
|
||||
grid-area: content;
|
||||
background-color: var(--video-tile-background);
|
||||
inline-size: 100%;
|
||||
block-size: 100%;
|
||||
border-radius: inherit;
|
||||
contain: strict;
|
||||
}
|
||||
|
||||
.media[data-bg-style="solid"] .bg {
|
||||
background-color: var(--video-tile-background);
|
||||
}
|
||||
|
||||
.avatar {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
|
||||
@@ -43,6 +43,7 @@ interface Props extends ComponentProps<typeof animated.div> {
|
||||
displayName: string;
|
||||
mxcAvatarUrl: string | undefined;
|
||||
avatarStyle?: "solid" | "translucent";
|
||||
bgStyle?: "solid" | "transparent";
|
||||
focusable: boolean;
|
||||
primaryButton?: ReactNode;
|
||||
raisedHandTime?: Date;
|
||||
@@ -73,6 +74,7 @@ export const MediaView: FC<Props> = ({
|
||||
displayName,
|
||||
mxcAvatarUrl,
|
||||
avatarStyle = "solid",
|
||||
bgStyle = "solid",
|
||||
focusable,
|
||||
primaryButton,
|
||||
status,
|
||||
@@ -118,6 +120,7 @@ export const MediaView: FC<Props> = ({
|
||||
ref={ref}
|
||||
data-testid="videoTile"
|
||||
data-video-fit={videoFit}
|
||||
data-bg-style={bgStyle}
|
||||
{...props}
|
||||
>
|
||||
<div className={styles.bg}>
|
||||
|
||||
@@ -58,7 +58,13 @@ test("SpotlightTile is accessible", async () => {
|
||||
const toggleExpanded = vi.fn();
|
||||
const { container } = render(
|
||||
<SpotlightTile
|
||||
vm={new SpotlightTileViewModel(constant([vm1, vm2]), constant(false))}
|
||||
vm={
|
||||
new SpotlightTileViewModel(
|
||||
constant([vm1, vm2]),
|
||||
constant(false),
|
||||
constant("solid"),
|
||||
)
|
||||
}
|
||||
targetWidth={300}
|
||||
targetHeight={200}
|
||||
expanded={false}
|
||||
@@ -101,7 +107,13 @@ test("Screen share volume UI is shown when screen share has audio", async () =>
|
||||
const { container } = render(
|
||||
<TooltipProvider>
|
||||
<SpotlightTile
|
||||
vm={new SpotlightTileViewModel(constant([vm]), constant(false))}
|
||||
vm={
|
||||
new SpotlightTileViewModel(
|
||||
constant([vm]),
|
||||
constant(false),
|
||||
constant("solid"),
|
||||
)
|
||||
}
|
||||
targetWidth={300}
|
||||
targetHeight={200}
|
||||
expanded={false}
|
||||
@@ -132,7 +144,13 @@ test("Screen share volume UI is hidden when screen share has no audio", async ()
|
||||
const toggleExpanded = vi.fn();
|
||||
const { container } = render(
|
||||
<SpotlightTile
|
||||
vm={new SpotlightTileViewModel(constant([vm]), constant(false))}
|
||||
vm={
|
||||
new SpotlightTileViewModel(
|
||||
constant([vm]),
|
||||
constant(false),
|
||||
constant("solid"),
|
||||
)
|
||||
}
|
||||
targetWidth={300}
|
||||
targetHeight={200}
|
||||
expanded={false}
|
||||
@@ -168,7 +186,13 @@ test("SpotlightTile displays ringing media", async () => {
|
||||
const toggleExpanded = vi.fn();
|
||||
const { container } = render(
|
||||
<SpotlightTile
|
||||
vm={new SpotlightTileViewModel(constant([vm]), constant(false))}
|
||||
vm={
|
||||
new SpotlightTileViewModel(
|
||||
constant([vm]),
|
||||
constant(false),
|
||||
constant("solid"),
|
||||
)
|
||||
}
|
||||
targetWidth={300}
|
||||
targetHeight={200}
|
||||
expanded={false}
|
||||
|
||||
@@ -65,6 +65,7 @@ interface SpotlightItemBaseProps {
|
||||
displayName: string;
|
||||
mxcAvatarUrl: string | undefined;
|
||||
showNameTags: boolean;
|
||||
bgStyle: "solid" | "transparent";
|
||||
focusable: boolean;
|
||||
"aria-hidden"?: boolean;
|
||||
}
|
||||
@@ -243,6 +244,7 @@ interface SpotlightItemProps {
|
||||
targetHeight: number;
|
||||
showNameTags: boolean;
|
||||
showRingingStatus: boolean;
|
||||
bgStyle: "solid" | "transparent";
|
||||
focusable: boolean;
|
||||
intersectionObserver$: Observable<IntersectionObserver>;
|
||||
/**
|
||||
@@ -259,6 +261,7 @@ const SpotlightItem: FC<SpotlightItemProps> = ({
|
||||
targetHeight,
|
||||
showNameTags,
|
||||
showRingingStatus,
|
||||
bgStyle,
|
||||
focusable,
|
||||
intersectionObserver$,
|
||||
snap,
|
||||
@@ -295,6 +298,7 @@ const SpotlightItem: FC<SpotlightItemProps> = ({
|
||||
displayName,
|
||||
mxcAvatarUrl,
|
||||
showNameTags,
|
||||
bgStyle,
|
||||
focusable,
|
||||
"aria-hidden": ariaHidden,
|
||||
};
|
||||
@@ -412,6 +416,7 @@ export const SpotlightTile: FC<Props> = ({
|
||||
const [ourRef, root$] = useObservableRef<HTMLDivElement | null>(null);
|
||||
const ref = useMergedRefs(ourRef, theirRef);
|
||||
const maximised = useBehavior(vm.maximised$);
|
||||
const bgStyle = useBehavior(vm.bgStyle$);
|
||||
const media = useBehavior(vm.media$);
|
||||
const [visibleId, setVisibleId] = useState<string | undefined>(media[0]?.id);
|
||||
const latestMedia = useLatest(media);
|
||||
@@ -516,6 +521,7 @@ export const SpotlightTile: FC<Props> = ({
|
||||
targetHeight={targetHeight}
|
||||
showRingingStatus={showRingingStatus}
|
||||
showNameTags={showNameTags}
|
||||
bgStyle={bgStyle}
|
||||
focusable={focusable}
|
||||
intersectionObserver$={intersectionObserver$}
|
||||
// This is how we get the container to scroll to the right media
|
||||
|
||||
Reference in New Issue
Block a user