fix(content): center letterboxed images and enlarge the AI-disclosure badge
BlurImage's wrapper defaults to w-full/h-full for fill-container usages (feed thumbnails with object-cover) — but in object-contain/letterboxed contexts (story viewer, post detail single-image and carousel) that same wrapper stretched to the full viewing area, defeating the parent's flex-centering and leaving the actual rendered image pinned to the top-left. Fixed by wrapping those three usages in an inline-flex container sized to the actual image (wrapperClassName override), which also gives the AI-disclosure badge a real image-relative anchor instead of floating in the surrounding letterbox space. Bumped the badge's base size (h-5 → h-7, h-8/h-10 in the larger detail/story contexts) per live-test feedback that it was hard to notice.
This commit is contained in:
1 parent
50e2848312
commit
092268b8e7
3 files changed
+41
-26
No files matched your search
@@ -30,7 +30,7 @@ export function AiDisclosureBadge({ value, className }: AiDisclosureBadgeProps)
|
||||
<img
|
||||
src={src}
|
||||
alt={value === "AI_GENERATED" ? t("generatedBadgeAlt") : t("modifiedBadgeAlt")}
|
||||
className={cn("absolute top-2 left-2 h-5 w-auto select-none pointer-events-none", className)}
|
||||
className={cn("absolute top-2 left-2 h-7 w-auto select-none pointer-events-none drop-shadow-md", className)}
|
||||
/>
|
||||
);
|
||||
}
|
||||
@@ -244,14 +244,18 @@ export function PostDetailDialog({ post, open, onClose, onDeleted }: PostDetailD
|
||||
);
|
||||
|
||||
const mediaContent = post.type === "VIDEO" && post.videoPost ? (
|
||||
<VideoCard
|
||||
postId={post.id}
|
||||
initialStatus={post.videoPost.status}
|
||||
initialPlaybackId={post.videoPost.muxPlaybackId}
|
||||
/>
|
||||
<div className="relative h-full w-full">
|
||||
<VideoCard
|
||||
postId={post.id}
|
||||
initialStatus={post.videoPost.status}
|
||||
initialPlaybackId={post.videoPost.muxPlaybackId}
|
||||
/>
|
||||
<AiDisclosureBadge value={post.aiDisclosure} className="h-8" />
|
||||
</div>
|
||||
) : images.length > 0 && (
|
||||
isCarousel ? (
|
||||
<div className="relative w-full h-full">
|
||||
<AiDisclosureBadge value={post.aiDisclosure} className="h-8" />
|
||||
<Carousel setApi={setCarouselApi} className="h-full">
|
||||
<CarouselContent className="h-full">
|
||||
{images.map((img) => (
|
||||
@@ -260,7 +264,8 @@ export function PostDetailDialog({ post, open, onClose, onDeleted }: PostDetailD
|
||||
src={getMediaUrl(img.storageKey) ?? ""}
|
||||
blurhash={img.blurhash}
|
||||
alt={currentCaption ?? `${pet.name}'s post`}
|
||||
className="max-h-full max-w-full object-contain"
|
||||
className="block max-h-full max-w-full object-contain"
|
||||
wrapperClassName="relative block h-auto w-auto"
|
||||
/>
|
||||
</CarouselItem>
|
||||
))}
|
||||
@@ -283,12 +288,16 @@ export function PostDetailDialog({ post, open, onClose, onDeleted }: PostDetailD
|
||||
</div>
|
||||
</div>
|
||||
) : (
|
||||
<BlurImage
|
||||
src={getMediaUrl(images[0].storageKey) ?? ""}
|
||||
blurhash={images[0].blurhash}
|
||||
alt={currentCaption ?? `${pet.name}'s post`}
|
||||
className="max-h-full max-w-full object-contain"
|
||||
/>
|
||||
<div className="relative inline-flex max-h-full max-w-full">
|
||||
<BlurImage
|
||||
src={getMediaUrl(images[0].storageKey) ?? ""}
|
||||
blurhash={images[0].blurhash}
|
||||
alt={currentCaption ?? `${pet.name}'s post`}
|
||||
className="block max-h-full max-w-full object-contain"
|
||||
wrapperClassName="relative block h-auto w-auto"
|
||||
/>
|
||||
<AiDisclosureBadge value={post.aiDisclosure} className="h-8" />
|
||||
</div>
|
||||
)
|
||||
);
|
||||
|
||||
@@ -312,7 +321,6 @@ export function PostDetailDialog({ post, open, onClose, onDeleted }: PostDetailD
|
||||
{/* Image column — fixed 45dvh strip on mobile, flex-1 full-height on desktop */}
|
||||
<div className="relative shrink-0 h-[45dvh] md:h-full md:flex-1 md:min-w-0 bg-black flex items-center justify-center">
|
||||
{mediaContent}
|
||||
<AiDisclosureBadge value={post.aiDisclosure} />
|
||||
</div>
|
||||
|
||||
{/* Right panel: desktop header + scrollable body + sticky input */}
|
||||
|
||||
@@ -155,21 +155,28 @@ export function StoryViewer({
|
||||
))}
|
||||
</div>
|
||||
|
||||
{/* Story image */}
|
||||
{/* Story image — inline-flex wrapper shrinks to the actual rendered
|
||||
image box (not the full-screen overlay) so both the centering
|
||||
and the badge overlay track the real image bounds. BlurImage's
|
||||
own wrapper defaults to w-full/h-full (fine for fill-container
|
||||
usages like feed thumbnails), so it's overridden here via
|
||||
wrapperClassName. */}
|
||||
{mediaUrl && (
|
||||
<BlurImage
|
||||
src={mediaUrl}
|
||||
blurhash={currentStory.blurhash}
|
||||
alt={t("storyAriaLabel", { petName })}
|
||||
className="max-h-screen max-w-full object-contain"
|
||||
/>
|
||||
<div className="relative inline-flex max-h-screen max-w-full">
|
||||
<BlurImage
|
||||
src={mediaUrl}
|
||||
blurhash={currentStory.blurhash}
|
||||
alt={t("storyAriaLabel", { petName })}
|
||||
className="block max-h-screen max-w-full object-contain"
|
||||
wrapperClassName="relative block h-auto w-auto"
|
||||
/>
|
||||
<AiDisclosureBadge
|
||||
value={currentStory.aiDisclosure}
|
||||
className="top-auto left-auto bottom-3 right-3 h-10"
|
||||
/>
|
||||
</div>
|
||||
)}
|
||||
|
||||
<AiDisclosureBadge
|
||||
value={currentStory.aiDisclosure}
|
||||
className="top-auto left-auto bottom-6 right-4"
|
||||
/>
|
||||
|
||||
{/* Pet info — bottom left */}
|
||||
<div className="absolute bottom-6 left-4 flex items-center gap-2">
|
||||
<Avatar className="w-8 h-8 border border-white/50">
|
||||
|
||||
Reference in new issue
Block a user