feat: added grid view
4532bb43
1 file(s) · +70 −12
| 1 | 1 | <script lang="ts"> |
|
| 2 | + | import { browser } from "$app/environment"; |
|
| 2 | 3 | import type { PageData } from "./$types"; |
|
| 3 | 4 | import ProgressiveImage from "$lib/components/ProgressiveImage.svelte"; |
|
| 4 | 5 | type ImageItem = PageData["photos"][number]; |
|
| 5 | 6 | let { data }: { data: PageData } = $props(); |
|
| 6 | 7 | ||
| 8 | + | let viewMode = $state<'feed' | 'grid'>('feed'); |
|
| 7 | 9 | let photos = $state<ImageItem[]>([]); |
|
| 8 | 10 | let loading = $state(false); |
|
| 9 | 11 | let hasMore = $derived(photos.length < data.total); |
|
| 12 | + | ||
| 13 | + | if (browser) { |
|
| 14 | + | const saved = localStorage.getItem('viewMode'); |
|
| 15 | + | if (saved === 'feed' || saved === 'grid') { |
|
| 16 | + | viewMode = saved; |
|
| 17 | + | } |
|
| 18 | + | } |
|
| 19 | + | ||
| 20 | + | function toggleViewMode() { |
|
| 21 | + | viewMode = viewMode === 'feed' ? 'grid' : 'feed'; |
|
| 22 | + | if (browser) { |
|
| 23 | + | localStorage.setItem('viewMode', viewMode); |
|
| 24 | + | } |
|
| 25 | + | } |
|
| 10 | 26 | ||
| 11 | 27 | $effect(() => { |
|
| 12 | 28 | photos = data.photos; |
|
| 49 | 65 | </script> |
|
| 50 | 66 | ||
| 51 | 67 | <div class="bg-[#121113] min-h-screen text-white"> |
|
| 52 | - | <div class="fixed bg-[#121113] w-full py-4 sm:px-8 px-4"> |
|
| 68 | + | <div class="fixed bg-[#121113] w-full py-4 sm:px-8 px-4 flex items-center justify-between z-10"> |
|
| 53 | 69 | <h1 class="text-sm">steve.photo</h1> |
|
| 70 | + | <button onclick={toggleViewMode} class="text-neutral-400 hover:text-white transition-colors" aria-label="Toggle view mode"> |
|
| 71 | + | {#if viewMode === 'feed'} |
|
| 72 | + | <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> |
|
| 73 | + | <rect x="3" y="3" width="7" height="7"></rect> |
|
| 74 | + | <rect x="14" y="3" width="7" height="7"></rect> |
|
| 75 | + | <rect x="3" y="14" width="7" height="7"></rect> |
|
| 76 | + | <rect x="14" y="14" width="7" height="7"></rect> |
|
| 77 | + | </svg> |
|
| 78 | + | {:else} |
|
| 79 | + | <svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"> |
|
| 80 | + | <line x1="3" y1="6" x2="21" y2="6"></line> |
|
| 81 | + | <line x1="3" y1="12" x2="21" y2="12"></line> |
|
| 82 | + | <line x1="3" y1="18" x2="21" y2="18"></line> |
|
| 83 | + | </svg> |
|
| 84 | + | {/if} |
|
| 85 | + | </button> |
|
| 54 | 86 | </div> |
|
| 55 | 87 | ||
| 56 | 88 | {#snippet figure(image: ImageItem)} |
|
| 78 | 110 | </div> |
|
| 79 | 111 | {/snippet} |
|
| 80 | 112 | ||
| 81 | - | <div class="flex flex-col gap-2 pt-12"> |
|
| 82 | - | {#each photos as image} |
|
| 83 | - | {@render figure(image)} |
|
| 84 | - | {/each} |
|
| 113 | + | {#if viewMode === 'feed'} |
|
| 114 | + | <div class="flex flex-col gap-2 pt-12"> |
|
| 115 | + | {#each photos as image} |
|
| 116 | + | {@render figure(image)} |
|
| 117 | + | {/each} |
|
| 118 | + | </div> |
|
| 119 | + | {:else} |
|
| 120 | + | <div class="grid grid-cols-2 sm:grid-cols-3 gap-1 pt-12 sm:px-8 px-4"> |
|
| 121 | + | {#each photos as image} |
|
| 122 | + | <a href="/photo/{image.slug}" class="grid-item block overflow-hidden aspect-[3/2]"> |
|
| 123 | + | <ProgressiveImage |
|
| 124 | + | class="w-full h-full block" |
|
| 125 | + | src={image.image} |
|
| 126 | + | thumb={image.thumb} |
|
| 127 | + | alt={image.title} |
|
| 128 | + | /> |
|
| 129 | + | </a> |
|
| 130 | + | {/each} |
|
| 131 | + | </div> |
|
| 132 | + | {/if} |
|
| 85 | 133 | ||
| 86 | - | <div bind:this={sentinel} class="h-4"></div> |
|
| 134 | + | <div bind:this={sentinel} class="h-4"></div> |
|
| 87 | 135 | ||
| 88 | - | {#if loading} |
|
| 89 | - | <div class="flex justify-center py-8"> |
|
| 90 | - | <div class="text-neutral-400 text-sm">Loading...</div> |
|
| 91 | - | </div> |
|
| 92 | - | {/if} |
|
| 93 | - | </div> |
|
| 136 | + | {#if loading} |
|
| 137 | + | <div class="flex justify-center py-8"> |
|
| 138 | + | <div class="text-neutral-400 text-sm">Loading...</div> |
|
| 139 | + | </div> |
|
| 140 | + | {/if} |
|
| 94 | 141 | </div> |
|
| 142 | + | ||
| 143 | + | <style> |
|
| 144 | + | .grid-item :global(.progressive-container) { |
|
| 145 | + | aspect-ratio: unset !important; |
|
| 146 | + | height: 100%; |
|
| 147 | + | } |
|
| 148 | + | ||
| 149 | + | .grid-item :global(.progressive-image) { |
|
| 150 | + | object-fit: cover; |
|
| 151 | + | } |
|
| 152 | + | </style> |
|