|
92 | 92 | const CARD_MAX_HEIGHT = 250; |
93 | 93 | const SKEW = 5; |
94 | 94 | const EXTRACT_DEBOUNCE = 300; |
95 | | - const BUFFER = 6; |
| 95 | + const MIN_BUFFER = 6; |
96 | 96 |
|
97 | 97 | let trackOffset = $derived( |
98 | 98 | areaWidth / 2 - currentIndex * CARD_STEP - ACTIVE_WIDTH / 2 |
99 | 99 | ); |
100 | 100 |
|
| 101 | + let viewportBuffer = $derived( |
| 102 | + Math.max( |
| 103 | + MIN_BUFFER, |
| 104 | + Math.ceil((areaWidth / 2 + ACTIVE_WIDTH) / CARD_STEP) + 2 |
| 105 | + ) |
| 106 | + ); |
| 107 | +
|
101 | 108 | let visibleRange = $derived.by(() => { |
102 | 109 | if (!areaWidth || items.length === 0) return {start: 0, end: 0}; |
103 | | - const halfViewport = areaWidth / 2 + ACTIVE_WIDTH; |
104 | | - const cardsInHalf = Math.ceil(halfViewport / CARD_STEP) + 1; |
105 | | - const start = Math.max(0, currentIndex - cardsInHalf - BUFFER); |
106 | | - const end = Math.min( |
107 | | - items.length, |
108 | | - currentIndex + cardsInHalf + BUFFER + 1 |
109 | | - ); |
| 110 | + const start = Math.max(0, currentIndex - viewportBuffer); |
| 111 | + const end = Math.min(items.length, currentIndex + viewportBuffer + 1); |
110 | 112 | return {start, end}; |
111 | 113 | }); |
112 | 114 |
|
|
240 | 242 | }); |
241 | 243 |
|
242 | 244 | function preloadAround(idx: number) { |
243 | | - for (let d = -BUFFER; d <= BUFFER; d++) { |
| 245 | + const buf = viewportBuffer; |
| 246 | + for (let d = -buf; d <= buf; d++) { |
244 | 247 | const i = idx + d; |
245 | 248 | if (i >= 0 && i < items.length && items[i].imagePath) { |
246 | 249 | loadPreview(items[i].imagePath); |
|
476 | 479 | </div> |
477 | 480 | {:else if !isLoading && items.length > 0} |
478 | 481 | <div |
479 | | - class="flex w-full items-center overflow-hidden" |
| 482 | + class="relative flex w-full items-center overflow-hidden" |
480 | 483 | style="height: {CARD_MAX_HEIGHT + 50}px" |
481 | 484 | bind:clientWidth={areaWidth} |
482 | 485 | > |
|
583 | 586 | </button> |
584 | 587 | {/each} |
585 | 588 | </div> |
| 589 | + |
| 590 | + <!-- Edge fade gradients --> |
| 591 | + <div |
| 592 | + class="pointer-events-none absolute inset-y-0 left-0 z-10" |
| 593 | + style="width: 220px; background: linear-gradient(to right, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.5) 40%, transparent 100%)" |
| 594 | + ></div> |
| 595 | + <div |
| 596 | + class="pointer-events-none absolute inset-y-0 right-0 z-10" |
| 597 | + style="width: 220px; background: linear-gradient(to left, rgba(0,0,0,0.9) 0%, rgba(0,0,0,0.5) 40%, transparent 100%)" |
| 598 | + ></div> |
586 | 599 | </div> |
587 | 600 |
|
588 | 601 | {#if searchVisible} |
|
0 commit comments