feat: add border to image hash placeholder
This commit is contained in:
@@ -73,13 +73,13 @@ export default function Image({
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={cn('relative overflow-hidden', classNames.wrapper)} {...props}>
|
||||
<div className={cn('relative overflow-hidden rounded-xl', classNames.wrapper)} {...props}>
|
||||
{/* Spacer: transparent image to maintain dimensions when image is loading */}
|
||||
{isLoading && dim?.width && dim?.height && (
|
||||
<img
|
||||
src={`data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='${dim.width}' height='${dim.height}'%3E%3C/svg%3E`}
|
||||
className={cn(
|
||||
'object-cover rounded-xl transition-opacity pointer-events-none w-full h-full',
|
||||
'object-cover transition-opacity pointer-events-none w-full h-full',
|
||||
className
|
||||
)}
|
||||
alt=""
|
||||
@@ -91,7 +91,7 @@ export default function Image({
|
||||
<ThumbHashPlaceholder
|
||||
thumbHash={thumbHash}
|
||||
className={cn(
|
||||
'w-full h-full transition-opacity rounded-xl',
|
||||
'w-full h-full transition-opacity',
|
||||
isLoading ? 'opacity-100' : 'opacity-0'
|
||||
)}
|
||||
/>
|
||||
@@ -99,14 +99,14 @@ export default function Image({
|
||||
<BlurHashCanvas
|
||||
blurHash={blurHash}
|
||||
className={cn(
|
||||
'w-full h-full transition-opacity rounded-xl',
|
||||
'w-full h-full transition-opacity',
|
||||
isLoading ? 'opacity-100' : 'opacity-0'
|
||||
)}
|
||||
/>
|
||||
) : (
|
||||
<Skeleton
|
||||
className={cn(
|
||||
'w-full h-full transition-opacity rounded-xl',
|
||||
'w-full h-full transition-opacity',
|
||||
isLoading ? 'opacity-100' : 'opacity-0',
|
||||
classNames.skeleton
|
||||
)}
|
||||
@@ -124,7 +124,7 @@ export default function Image({
|
||||
onLoad={handleLoad}
|
||||
onError={handleError}
|
||||
className={cn(
|
||||
'object-cover rounded-xl transition-opacity pointer-events-none w-full h-full',
|
||||
'object-cover transition-opacity pointer-events-none w-full h-full',
|
||||
isLoading ? 'opacity-0 absolute inset-0' : '',
|
||||
className
|
||||
)}
|
||||
@@ -137,7 +137,7 @@ export default function Image({
|
||||
alt={alt}
|
||||
decoding="async"
|
||||
loading="lazy"
|
||||
className={cn('object-cover rounded-xl w-full h-full transition-opacity', className)}
|
||||
className={cn('object-cover w-full h-full transition-opacity', className)}
|
||||
/>
|
||||
) : (
|
||||
<div
|
||||
|
||||
@@ -94,9 +94,9 @@ export default function ImageGallery({
|
||||
<ImageWithLightbox
|
||||
key={i}
|
||||
image={image}
|
||||
className="max-h-[80vh] sm:max-h-[50vh] object-contain border"
|
||||
className="max-h-[80vh] sm:max-h-[50vh] object-contain"
|
||||
classNames={{
|
||||
wrapper: cn('w-fit max-w-full', className)
|
||||
wrapper: cn('w-fit max-w-full border', className)
|
||||
}}
|
||||
/>
|
||||
))
|
||||
@@ -107,10 +107,10 @@ export default function ImageGallery({
|
||||
imageContent = (
|
||||
<Image
|
||||
key={0}
|
||||
className="max-h-[80vh] sm:max-h-[50vh] object-contain border"
|
||||
className="max-h-[80vh] sm:max-h-[50vh] object-contain"
|
||||
classNames={{
|
||||
errorPlaceholder: 'aspect-square h-[30vh]',
|
||||
wrapper: 'cursor-zoom-in'
|
||||
wrapper: 'cursor-zoom-in border'
|
||||
}}
|
||||
image={displayImages[0]}
|
||||
onClick={(e) => handlePhotoClick(e, 0)}
|
||||
@@ -122,8 +122,8 @@ export default function ImageGallery({
|
||||
{displayImages.map((image, i) => (
|
||||
<Image
|
||||
key={i}
|
||||
className="aspect-square w-full border"
|
||||
classNames={{ wrapper: 'cursor-zoom-in' }}
|
||||
className="aspect-square w-full"
|
||||
classNames={{ wrapper: 'cursor-zoom-in border' }}
|
||||
image={image}
|
||||
onClick={(e) => handlePhotoClick(e, i)}
|
||||
/>
|
||||
@@ -136,8 +136,8 @@ export default function ImageGallery({
|
||||
{displayImages.map((image, i) => (
|
||||
<Image
|
||||
key={i}
|
||||
className="aspect-square w-full border"
|
||||
classNames={{ wrapper: 'cursor-zoom-in' }}
|
||||
className="aspect-square w-full"
|
||||
classNames={{ wrapper: 'cursor-zoom-in border' }}
|
||||
image={image}
|
||||
onClick={(e) => handlePhotoClick(e, i)}
|
||||
/>
|
||||
|
||||
@@ -67,7 +67,7 @@ export default function ImageWithLightbox({
|
||||
key={0}
|
||||
className={className}
|
||||
classNames={{
|
||||
wrapper: cn('rounded-lg border cursor-zoom-in', classNames.wrapper),
|
||||
wrapper: cn('border cursor-zoom-in', classNames.wrapper),
|
||||
errorPlaceholder: 'aspect-square h-[30vh]',
|
||||
skeleton: classNames.skeleton
|
||||
}}
|
||||
|
||||
@@ -26,7 +26,7 @@ export default function FollowPack({ event, className }: { event: Event; classNa
|
||||
{image && (
|
||||
<Image
|
||||
image={{ url: image, pubkey: event.pubkey }}
|
||||
className="w-24 h-20 object-cover rounded-lg"
|
||||
className="w-24 h-20 object-cover"
|
||||
classNames={{
|
||||
wrapper: 'w-24 h-20 flex-shrink-0',
|
||||
errorPlaceholder: 'w-24 h-20'
|
||||
|
||||
@@ -67,7 +67,7 @@ export default function LongFormArticlePreview({
|
||||
{metadata.image && autoLoadMedia && (
|
||||
<Image
|
||||
image={{ url: metadata.image, pubkey: event.pubkey }}
|
||||
className="rounded-lg aspect-[4/3] xl:aspect-video object-cover bg-foreground h-44"
|
||||
className="aspect-[4/3] xl:aspect-video object-cover bg-foreground h-44"
|
||||
hideIfError
|
||||
/>
|
||||
)}
|
||||
|
||||
@@ -40,8 +40,8 @@ export function ReactionNotification({
|
||||
<Image
|
||||
image={{ url: emojiUrl, pubkey: notification.pubkey }}
|
||||
alt={emojiName}
|
||||
className="w-6 h-6 rounded-md"
|
||||
classNames={{ errorPlaceholder: 'bg-transparent' }}
|
||||
className="w-6 h-6"
|
||||
classNames={{ errorPlaceholder: 'bg-transparent', wrapper: 'rounded-md' }}
|
||||
errorPlaceholder={<Heart size={24} className="text-red-400" />}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
import { generateImageByPubkey } from '@/lib/pubkey'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useEffect, useMemo, useState } from 'react'
|
||||
import Image from '../Image'
|
||||
|
||||
@@ -27,7 +26,10 @@ export default function ProfileBanner({
|
||||
<Image
|
||||
image={{ url: bannerUrl, pubkey }}
|
||||
alt={`${pubkey} banner`}
|
||||
className={cn('rounded-none', className)}
|
||||
className={className}
|
||||
classNames={{
|
||||
wrapper: 'rounded-none'
|
||||
}}
|
||||
errorPlaceholder={defaultBanner}
|
||||
/>
|
||||
)
|
||||
|
||||
@@ -36,9 +36,9 @@ export default function RelayInfo({ url, className }: { url: string; className?:
|
||||
<div className="px-4 space-y-4">
|
||||
<div className="space-y-2">
|
||||
<div className="flex items-center gap-2 justify-between">
|
||||
<div className="flex gap-2 items-center truncate">
|
||||
<div className="flex gap-2 items-center flex-1">
|
||||
<RelayIcon url={url} className="w-8 h-8" />
|
||||
<div className="text-2xl font-semibold truncate select-text">
|
||||
<div className="text-2xl font-semibold truncate select-text flex-1 w-0">
|
||||
{relayInfo.name || relayInfo.shortUrl}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -68,9 +68,9 @@ export default function WebPreview({
|
||||
{image && (
|
||||
<Image
|
||||
image={{ url: image }}
|
||||
className="aspect-[4/3] xl:aspect-video bg-foreground h-44 rounded-none border-r"
|
||||
className="aspect-[4/3] xl:aspect-video bg-foreground h-44"
|
||||
classNames={{
|
||||
skeleton: 'rounded-none border-r'
|
||||
wrapper: 'rounded-none border-r'
|
||||
}}
|
||||
hideIfError
|
||||
/>
|
||||
|
||||
Reference in New Issue
Block a user