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