This commit is contained in:
@@ -7,10 +7,11 @@
|
|||||||
* @property {(photoId: number, previewSrc: string) => void} [onUpgradeQuality]
|
* @property {(photoId: number, previewSrc: string) => void} [onUpgradeQuality]
|
||||||
* @property {boolean} [borderLess]
|
* @property {boolean} [borderLess]
|
||||||
* @property {boolean} [waterfall]
|
* @property {boolean} [waterfall]
|
||||||
|
* @property {number} [index]
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/** @type {PhotoCardProps} */
|
/** @type {PhotoCardProps} */
|
||||||
let { photo, onUpgradeQuality, borderLess = false, waterfall = false } = $props();
|
let { photo, onUpgradeQuality, borderLess = false, waterfall = false, index = 0 } = $props();
|
||||||
|
|
||||||
// 使用 $derived 确保响应式更新
|
// 使用 $derived 确保响应式更新
|
||||||
let previewSrc = $derived(`/api/v1/photo/${photo.id}/preview`);
|
let previewSrc = $derived(`/api/v1/photo/${photo.id}/preview`);
|
||||||
@@ -18,10 +19,13 @@
|
|||||||
// 根据原始宽高比计算瀑布流显示比例,防止图片加载前容器塌陷
|
// 根据原始宽高比计算瀑布流显示比例,防止图片加载前容器塌陷
|
||||||
let aspectRatioStyle = $derived(
|
let aspectRatioStyle = $derived(
|
||||||
waterfall && photo.width && photo.height
|
waterfall && photo.width && photo.height
|
||||||
? `aspect-ratio: ${photo.width} / ${photo.height};`
|
? `${photo.width} / ${photo.height}`
|
||||||
: ''
|
: ''
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// 砖块模式:交错延迟(按网格行顺序);瀑布模式:同时入场(避免列填充顺序与延迟不匹配)
|
||||||
|
let animationDelay = $derived(waterfall ? '0ms' : `${Math.min(index, 20) * 35}ms`);
|
||||||
|
|
||||||
function handleMouseEnter() {
|
function handleMouseEnter() {
|
||||||
if (onUpgradeQuality) {
|
if (onUpgradeQuality) {
|
||||||
onUpgradeQuality(photo.id, previewSrc);
|
onUpgradeQuality(photo.id, previewSrc);
|
||||||
@@ -35,8 +39,8 @@
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<a href={resolve(`/photo/${photo.id}`)} class="photo-card" class:photo-card-waterfall={waterfall} class:photo-card-compact-waterfall={borderLess && waterfall}>
|
<a href={resolve(`/photo/${photo.id}`)} class="photo-card" class:photo-card-waterfall={waterfall} class:photo-card-compact-waterfall={borderLess && waterfall} style={`--wf-aspect: ${aspectRatioStyle}; --wf-delay: ${animationDelay};`}>
|
||||||
<div class="photo-wrapper" class:photo-borderless={borderLess} class:photo-waterfall={waterfall} style={aspectRatioStyle}>
|
<div class="photo-wrapper" class:photo-borderless={borderLess} class:photo-waterfall={waterfall}>
|
||||||
{#if photo.mimeType?.startsWith('video/')}
|
{#if photo.mimeType?.startsWith('video/')}
|
||||||
<div class="video-indicator">🎬</div>
|
<div class="video-indicator">🎬</div>
|
||||||
<div class="photo-placeholder">
|
<div class="photo-placeholder">
|
||||||
@@ -65,6 +69,19 @@
|
|||||||
display: block;
|
display: block;
|
||||||
text-decoration: none;
|
text-decoration: none;
|
||||||
color: inherit;
|
color: inherit;
|
||||||
|
animation: card-enter 0.35s cubic-bezier(0.4, 0, 0.2, 1) both;
|
||||||
|
animation-delay: var(--wf-delay, 0ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes card-enter {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: translateY(12px) scale(0.96);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: translateY(0) scale(1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* 瀑布流模式:防止卡片被列截断,并添加间距 */
|
/* 瀑布流模式:防止卡片被列截断,并添加间距 */
|
||||||
@@ -97,7 +114,7 @@
|
|||||||
|
|
||||||
/* 瀑布流模式:保持原始宽高比 */
|
/* 瀑布流模式:保持原始宽高比 */
|
||||||
.photo-waterfall {
|
.photo-waterfall {
|
||||||
aspect-ratio: auto;
|
aspect-ratio: var(--wf-aspect, auto);
|
||||||
height: auto;
|
height: auto;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -136,7 +153,6 @@
|
|||||||
/* 瀑布流模式下 placeholder 默认 4:3 */
|
/* 瀑布流模式下 placeholder 默认 4:3 */
|
||||||
.photo-waterfall .photo-placeholder {
|
.photo-waterfall .photo-placeholder {
|
||||||
aspect-ratio: 4/3;
|
aspect-ratio: 4/3;
|
||||||
height: 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.video-indicator {
|
.video-indicator {
|
||||||
|
|||||||
@@ -40,11 +40,13 @@
|
|||||||
<Empty message={m.no_photos()} icon="📷" />
|
<Empty message={m.no_photos()} icon="📷" />
|
||||||
{:else}
|
{:else}
|
||||||
<div class="photo-scroll-container" bind:this={scrollContainer}>
|
<div class="photo-scroll-container" bind:this={scrollContainer}>
|
||||||
|
{#key waterfall + '_' + borderLess}
|
||||||
<div class="photo-grid" class:photo-grid-borderless={borderLess} class:photo-grid-waterfall={waterfall}>
|
<div class="photo-grid" class:photo-grid-borderless={borderLess} class:photo-grid-waterfall={waterfall}>
|
||||||
{#each getVisiblePhotos() as photo (photo.id)}
|
{#each getVisiblePhotos() as photo, i (photo.id)}
|
||||||
<PhotoCard {photo} {onUpgradeQuality} {borderLess} {waterfall} />
|
<PhotoCard {photo} {onUpgradeQuality} {borderLess} {waterfall} index={i} />
|
||||||
{/each}
|
{/each}
|
||||||
</div>
|
</div>
|
||||||
|
{/key}
|
||||||
|
|
||||||
{#if isLoading}
|
{#if isLoading}
|
||||||
<div class="loading-trigger">
|
<div class="loading-trigger">
|
||||||
|
|||||||
Reference in New Issue
Block a user