feat(video): explicit fullscreen button, simplify download pill sizing
- VideoBubble: add a Maximize2 fullscreen button at the top-right of the inline player (mirrors the download pill on the left), so the user explicitly opts into fullscreen instead of any tile click being promoted to one. Removed the outer onClick that opened fullscreen on any tap. - AttachmentDownloadPill: drop the adaptive (cqw-based) sizing branch and the corresponding 'adaptive' prop. The pill is now a uniform 30px tall in every host (album tile, single image, video tile), matching the design without needing query containers on parents. - AlbumBubble: remove the now-unused 'adaptive' prop and the containerType: inline-size hook that supported it.
This commit is contained in:
@@ -12,14 +12,6 @@ type AttachmentDownloadPillProps = {
|
|||||||
attachment: Attachment;
|
attachment: Attachment;
|
||||||
leadingLabel?: string;
|
leadingLabel?: string;
|
||||||
className?: string;
|
className?: string;
|
||||||
/**
|
|
||||||
* When true, the pill scales with its container's width via container-query
|
|
||||||
* units (clamped to a min/max). The host element must establish a query
|
|
||||||
* container (e.g. `style={{ containerType: "inline-size" }}`). Use this on
|
|
||||||
* album tiles so the pill shrinks on small thumbnails. Defaults to a fixed
|
|
||||||
* size for standalone images/videos.
|
|
||||||
*/
|
|
||||||
adaptive?: boolean;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export function AttachmentDownloadPill({
|
export function AttachmentDownloadPill({
|
||||||
@@ -27,7 +19,6 @@ export function AttachmentDownloadPill({
|
|||||||
attachment,
|
attachment,
|
||||||
leadingLabel,
|
leadingLabel,
|
||||||
className = "absolute left-2 top-2",
|
className = "absolute left-2 top-2",
|
||||||
adaptive = false,
|
|
||||||
}: AttachmentDownloadPillProps) {
|
}: AttachmentDownloadPillProps) {
|
||||||
const { t } = useI18n();
|
const { t } = useI18n();
|
||||||
const { showToast } = useToast();
|
const { showToast } = useToast();
|
||||||
@@ -39,7 +30,6 @@ export function AttachmentDownloadPill({
|
|||||||
setIsDownloading(true);
|
setIsDownloading(true);
|
||||||
try {
|
try {
|
||||||
await downloadAttachment(postId, attachment.id, attachment.filename);
|
await downloadAttachment(postId, attachment.id, attachment.filename);
|
||||||
showToast(t("downloadOk"));
|
|
||||||
} catch {
|
} catch {
|
||||||
showToast(t("downloadFail"), "error");
|
showToast(t("downloadFail"), "error");
|
||||||
} finally {
|
} finally {
|
||||||
@@ -47,42 +37,28 @@ export function AttachmentDownloadPill({
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Fixed default vs. container-query-driven adaptive sizing (clamped).
|
|
||||||
const fontCls = adaptive ? "text-[clamp(10px,5cqw,12px)]" : "text-[12px]";
|
|
||||||
const squareCls = adaptive
|
|
||||||
? "h-[clamp(22px,11cqw,30px)] w-[clamp(22px,11cqw,30px)]"
|
|
||||||
: "h-[30px] w-[30px]";
|
|
||||||
const iconCls = adaptive
|
|
||||||
? "h-[clamp(13px,6.5cqw,18px)] w-[clamp(13px,6.5cqw,18px)]"
|
|
||||||
: "h-[18px] w-[18px]";
|
|
||||||
const textBoxCls = adaptive
|
|
||||||
? "h-[clamp(22px,11cqw,30px)] px-[clamp(6px,3cqw,10px)]"
|
|
||||||
: "h-[30px] px-2.5";
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
type="button"
|
type="button"
|
||||||
onClick={handleDownload}
|
onClick={handleDownload}
|
||||||
disabled={isDownloading}
|
disabled={isDownloading}
|
||||||
className={`group z-10 inline-flex overflow-hidden rounded-full bg-black/80 ${fontCls} text-white shadow-lg ring-1 ring-inset ring-white/20 backdrop-blur-md transition hover:bg-black/90 disabled:cursor-wait ${className}`}
|
className={`group z-10 inline-flex overflow-hidden rounded-full bg-black/80 text-[12px] text-white shadow-lg ring-1 ring-inset ring-white/20 backdrop-blur-md transition hover:bg-black/90 disabled:cursor-wait ${className}`}
|
||||||
aria-label={
|
aria-label={
|
||||||
isDownloading ? t("downloading") : `Download ${attachment.filename}`
|
isDownloading ? t("downloading") : `Download ${attachment.filename}`
|
||||||
}
|
}
|
||||||
aria-busy={isDownloading}
|
aria-busy={isDownloading}
|
||||||
>
|
>
|
||||||
<span
|
<span className="flex h-[30px] w-[30px] items-center justify-center bg-[#545454]/50 transition group-hover:bg-[#545454]/70">
|
||||||
className={`flex ${squareCls} items-center justify-center bg-[#545454]/50 transition group-hover:bg-[#545454]/70`}
|
|
||||||
>
|
|
||||||
{isDownloading ? (
|
{isDownloading ? (
|
||||||
<LoaderCircle
|
<LoaderCircle
|
||||||
className={`${iconCls} animate-spin`}
|
className="h-[18px] w-[18px] animate-spin"
|
||||||
strokeWidth={2.3}
|
strokeWidth={2.3}
|
||||||
/>
|
/>
|
||||||
) : (
|
) : (
|
||||||
<DownloadCloudIcon className={iconCls} />
|
<DownloadCloudIcon className="h-[18px] w-[18px]" />
|
||||||
)}
|
)}
|
||||||
</span>
|
</span>
|
||||||
<span className={`flex ${textBoxCls} items-center gap-0.5`}>
|
<span className="flex h-[30px] items-center gap-0.5 px-2.5">
|
||||||
{isDownloading ? (
|
{isDownloading ? (
|
||||||
t("downloading")
|
t("downloading")
|
||||||
) : (
|
) : (
|
||||||
|
|||||||
@@ -51,8 +51,6 @@ export function AlbumBubble({ post }: { post: Post }) {
|
|||||||
top: `${tile.top * 100}%`,
|
top: `${tile.top * 100}%`,
|
||||||
width: `calc(${tile.width * 100}% - ${ALBUM_GAP}px)`,
|
width: `calc(${tile.width * 100}% - ${ALBUM_GAP}px)`,
|
||||||
height: `calc(${tile.height * 100}% - ${ALBUM_GAP}px)`,
|
height: `calc(${tile.height * 100}% - ${ALBUM_GAP}px)`,
|
||||||
// Query container so the download pill scales with this tile.
|
|
||||||
containerType: "inline-size",
|
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<button
|
<button
|
||||||
@@ -78,11 +76,7 @@ export function AlbumBubble({ post }: { post: Post }) {
|
|||||||
) : null}
|
) : null}
|
||||||
</button>
|
</button>
|
||||||
{!isLastSlot ? (
|
{!isLastSlot ? (
|
||||||
<AttachmentDownloadPill
|
<AttachmentDownloadPill postId={post.id} attachment={att} />
|
||||||
postId={post.id}
|
|
||||||
attachment={att}
|
|
||||||
adaptive
|
|
||||||
/>
|
|
||||||
) : null}
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { LoaderCircle, Play, X } from "lucide-react";
|
import { LoaderCircle, Maximize2, Play, X } from "lucide-react";
|
||||||
import { DownloadCloudIcon } from "../../icons/DownloadCloudIcon";
|
import { DownloadCloudIcon } from "../../icons/DownloadCloudIcon";
|
||||||
import { useEffect, useRef, useState } from "react";
|
import { useEffect, useRef, useState } from "react";
|
||||||
import { createPortal } from "react-dom";
|
import { createPortal } from "react-dom";
|
||||||
@@ -71,12 +71,6 @@ function VideoAttachmentCard({
|
|||||||
: "h-[180px] min-[440px]:h-[210px] md:h-[260px] lg:h-[300px]"
|
: "h-[180px] min-[440px]:h-[210px] md:h-[260px] lg:h-[300px]"
|
||||||
}`}
|
}`}
|
||||||
style={compact ? undefined : { aspectRatio: videoRatio(attachment) }}
|
style={compact ? undefined : { aspectRatio: videoRatio(attachment) }}
|
||||||
onClick={() => {
|
|
||||||
if (playing) {
|
|
||||||
const v = videoRef.current;
|
|
||||||
openVideo(attachment, v?.currentTime ?? 0);
|
|
||||||
}
|
|
||||||
}}
|
|
||||||
>
|
>
|
||||||
{playing && !compact ? (
|
{playing && !compact ? (
|
||||||
<>
|
<>
|
||||||
@@ -96,6 +90,18 @@ function VideoAttachmentCard({
|
|||||||
leadingLabel={duration}
|
leadingLabel={duration}
|
||||||
className="absolute left-2 top-2 z-20"
|
className="absolute left-2 top-2 z-20"
|
||||||
/>
|
/>
|
||||||
|
<button
|
||||||
|
type="button"
|
||||||
|
onClick={(e) => {
|
||||||
|
e.stopPropagation();
|
||||||
|
const v = videoRef.current;
|
||||||
|
openVideo(attachment, v?.currentTime ?? 0);
|
||||||
|
}}
|
||||||
|
className="absolute right-2 top-2 z-20 flex h-9 w-9 items-center justify-center rounded-full bg-black/60 text-white shadow-lg ring-1 ring-white/25 transition hover:bg-black/80"
|
||||||
|
aria-label="Fullscreen"
|
||||||
|
>
|
||||||
|
<Maximize2 className="h-4 w-4" strokeWidth={2.2} />
|
||||||
|
</button>
|
||||||
</>
|
</>
|
||||||
) : (
|
) : (
|
||||||
<>
|
<>
|
||||||
@@ -184,7 +190,6 @@ function AttachmentListDownloadButton({
|
|||||||
setIsDownloading(true);
|
setIsDownloading(true);
|
||||||
try {
|
try {
|
||||||
await downloadAttachment(postId, attachment.id, attachment.filename);
|
await downloadAttachment(postId, attachment.id, attachment.filename);
|
||||||
showToast(t("downloadOk"));
|
|
||||||
} catch {
|
} catch {
|
||||||
showToast(t("downloadFail"), "error");
|
showToast(t("downloadFail"), "error");
|
||||||
} finally {
|
} finally {
|
||||||
|
|||||||
Reference in New Issue
Block a user