Add a fullscreen button that uses the element request Fullscreen browser api (#3447)

* Add a fullscreen button that uses the element request Fullscreen browser api

Signed-off-by: Timo K <toger5@hotmail.de>

* use body instead of root node

Signed-off-by: Timo K <toger5@hotmail.de>

---------

Signed-off-by: Timo K <toger5@hotmail.de>
This commit is contained in:
Timo
2025-08-08 17:09:25 +02:00
committed by GitHub
parent c0aab96968
commit 6667fc54c0
4 changed files with 67 additions and 14 deletions

View File

@@ -0,0 +1,6 @@
<svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M4 14C4.55228 14 5 14.4477 5 15V19H9C9.55228 19 10 19.4477 10 20C10 20.5523 9.55228 21 9 21H3V15C3 14.4477 3.44772 14 4 14Z"/>
<path d="M20 14C20.5523 14 21 14.4477 21 15V21H15C14.4477 21 14 20.5523 14 20C14 19.4477 14.4477 19 15 19H19V15C19 14.4477 19.4477 14 20 14Z" />
<path d="M9 3C9.55228 3 10 3.44772 10 4C10 4.55228 9.55228 5 9 5H5V9C5 9.55228 4.55228 10 4 10C3.44772 10 3 9.55228 3 9V3H9Z" />
<path d="M21 9C21 9.55228 20.5523 10 20 10C19.4477 10 19 9.55228 19 9V5H15C14.4477 5 14 4.55228 14 4C14 3.44772 14.4477 3 15 3H21V9Z" />
</svg>

After

Width:  |  Height:  |  Size: 658 B

View File

@@ -0,0 +1,6 @@
<svg width="24" height="24" fill="currentColor" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">
<path d="M10 20C10 20.5523 9.55228 21 9 21C8.44772 21 8 20.5523 8 20V16H4C3.44772 16 3 15.5523 3 15C3 14.4477 3.44772 14 4 14H10V20Z" />
<path d="M20 14C20.5523 14 21 14.4477 21 15C21 15.5523 20.5523 16 20 16H16V20C16 20.5523 15.5523 21 15 21C14.4477 21 14 20.5523 14 20V14H20Z" />
<path d="M9 3C9.55228 3 10 3.44772 10 4V10H4C3.44772 10 3 9.55228 3 9C3 8.44772 3.44772 8 4 8H8V4C8 3.44772 8.44772 3 9 3Z" />
<path d="M15 3C15.5523 3 16 3.44772 16 4V8H20C20.5523 8 21 8.44772 21 9C21 9.55228 20.5523 10 20 10H14V4C14 3.44772 14.4477 3 15 3Z" />
</svg>

After

Width:  |  Height:  |  Size: 656 B

View File

@@ -88,40 +88,48 @@ Please see LICENSE in the repository root for full details.
padding: var(--cpd-space-2x);
border: none;
border-radius: var(--cpd-radius-pill-effect);
background: var(--cpd-color-alpha-gray-1400);
background: rgba(from var(--cpd-color-gray-100) r g b / 0.6);
box-shadow: var(--small-drop-shadow);
transition:
opacity 0.15s,
background-color 0.1s;
position: absolute;
z-index: 1;
--inset: 6px;
inset-block-end: var(--inset);
inset-inline-end: var(--inset);
}
.bottomRightButtons {
display: flex;
gap: var(--cpd-space-2x);
position: absolute;
inset-block-end: var(--cpd-space-1x);
inset-inline-end: var(--cpd-space-1x);
z-index: 1;
}
.expand > svg {
display: block;
color: var(--cpd-color-icon-on-solid-primary);
color: var(--cpd-color-icon-primary);
}
@media (hover) {
.expand:hover {
background: var(--cpd-color-bg-action-primary-hovered);
background: var(--cpd-color-gray-400);
}
}
.expand:active {
background: var(--cpd-color-bg-action-primary-pressed);
background: var(--cpd-color-gray-100);
}
@media (hover) {
.tile:hover > button {
.tile:hover > div > button {
opacity: 1;
}
}
.tile:has(:focus-visible) > button {
.tile:has(:focus-visible) > div > button {
opacity: 1;
}

View File

@@ -29,6 +29,8 @@ import classNames from "classnames";
import { type TrackReferenceOrPlaceholder } from "@livekit/components-core";
import { type RoomMember } from "matrix-js-sdk";
import FullScreenMaximiseIcon from "../icons/FullScreenMaximise.svg?react";
import FullScreenMinimiseIcon from "../icons/FullScreenMinimise.svg?react";
import { MediaView } from "./MediaView";
import styles from "./SpotlightTile.module.css";
import {
@@ -210,6 +212,26 @@ export const SpotlightTile: FC<Props> = ({
const canGoBack = visibleIndex > 0;
const canGoToNext = visibleIndex !== -1 && visibleIndex < media.length - 1;
const isFullscreen = useCallback((): boolean => {
const rootElement = document.body;
if (rootElement && document.fullscreenElement) return true;
return false;
}, []);
const FullScreenIcon = isFullscreen()
? FullScreenMinimiseIcon
: FullScreenMaximiseIcon;
const onToggleFullscreen = useCallback(() => {
const rootElement = document.body;
if (!rootElement) return;
if (isFullscreen()) {
void document?.exitFullscreen();
} else {
void rootElement.requestFullscreen();
}
}, [isFullscreen]);
// To keep track of which item is visible, we need an intersection observer
// hooked up to the root element and the items. Because the items will run
// their effects before their parent does, we need to do this dance with an
@@ -292,17 +314,28 @@ export const SpotlightTile: FC<Props> = ({
/>
))}
</div>
{onToggleExpanded && (
<div className={styles.bottomRightButtons}>
<button
className={classNames(styles.expand)}
aria-label={
expanded ? t("video_tile.collapse") : t("video_tile.expand")
}
onClick={onToggleExpanded}
aria-label={"maximise"}
onClick={onToggleFullscreen}
>
<ToggleExpandIcon aria-hidden width={20} height={20} />
<FullScreenIcon aria-hidden width={20} height={20} />
</button>
)}
{onToggleExpanded && (
<button
className={classNames(styles.expand)}
aria-label={
expanded ? t("video_tile.collapse") : t("video_tile.expand")
}
onClick={onToggleExpanded}
>
<ToggleExpandIcon aria-hidden width={20} height={20} />
</button>
)}
</div>
{canGoToNext && (
<button
className={classNames(styles.advance, styles.next)}