chore: small adjustments to upload behavior
3a1c2bd3
2 file(s) · +66 −118
| 133 | 133 | ) |
|
| 134 | 134 | .run(); |
|
| 135 | 135 | ||
| 136 | - | throw redirect(302, `/photo/${slug}`); |
|
| 136 | + | return { success: true }; |
|
| 137 | 137 | } catch (err) { |
|
| 138 | 138 | if (isRedirect(err)) { |
|
| 139 | 139 | throw err; // Re-throw redirects |
| 131 | 131 | editingId = null; |
|
| 132 | 132 | editingTitle = ""; |
|
| 133 | 133 | } |
|
| 134 | + | ||
| 135 | + | function resetUploadForm() { |
|
| 136 | + | selectedFile = null; |
|
| 137 | + | if (previewUrl) { |
|
| 138 | + | URL.revokeObjectURL(previewUrl); |
|
| 139 | + | previewUrl = null; |
|
| 140 | + | } |
|
| 141 | + | thumbnailBlob = null; |
|
| 142 | + | title = ""; |
|
| 143 | + | date = ""; |
|
| 144 | + | camera = ""; |
|
| 145 | + | lens = ""; |
|
| 146 | + | aperture = ""; |
|
| 147 | + | exposure = ""; |
|
| 148 | + | focalLength = ""; |
|
| 149 | + | iso = ""; |
|
| 150 | + | make = ""; |
|
| 151 | + | if (fileInput) { |
|
| 152 | + | fileInput.value = ""; |
|
| 153 | + | } |
|
| 154 | + | } |
|
| 134 | 155 | </script> |
|
| 135 | 156 | ||
| 136 | 157 | <svelte:head> |
|
| 138 | 159 | </svelte:head> |
|
| 139 | 160 | ||
| 140 | 161 | <div class="min-h-screen p-4 md:p-8"> |
|
| 141 | - | <div class="max-w-4xl mx-auto"> |
|
| 162 | + | <div class="max-w-4xl mx-auto space-y-4"> |
|
| 142 | 163 | <div class="flex items-center justify-between mb-8"> |
|
| 143 | 164 | <h1 class="text-2xl font-bold">Admin</h1> |
|
| 144 | 165 | <a |
|
| 151 | 172 | ||
| 152 | 173 | <!-- Upload Section --> |
|
| 153 | 174 | <section> |
|
| 154 | - | <h2 class="text-xl font-semibold mb-4">Upload New Photo</h2> |
|
| 175 | + | <h2 class="text-lg font-semibold mb-3">Upload New Photo</h2> |
|
| 155 | 176 | ||
| 156 | 177 | <form |
|
| 157 | 178 | method="POST" |
|
| 162 | 183 | if (thumbnailBlob) { |
|
| 163 | 184 | formData.append("thumbnail", thumbnailBlob, "thumbnail.jpg"); |
|
| 164 | 185 | } |
|
| 165 | - | return async ({ update }) => { |
|
| 186 | + | return async ({ result, update }) => { |
|
| 166 | 187 | isLoading = false; |
|
| 188 | + | if (result.type === "success") { |
|
| 189 | + | resetUploadForm(); |
|
| 190 | + | } |
|
| 167 | 191 | await update(); |
|
| 168 | 192 | }; |
|
| 169 | 193 | }} |
|
| 170 | - | class="space-y-6" |
|
| 194 | + | class="space-y-4" |
|
| 171 | 195 | > |
|
| 172 | 196 | <div> |
|
| 173 | - | <label for="file" class="block text-sm mb-2">Image</label> |
|
| 174 | 197 | <input |
|
| 175 | 198 | type="file" |
|
| 176 | 199 | id="file" |
|
| 179 | 202 | required |
|
| 180 | 203 | bind:this={fileInput} |
|
| 181 | 204 | onchange={handleFileSelect} |
|
| 182 | - | class="w-full px-4 py-2 bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500 file:mr-4 file:py-1 file:px-4 file:rounded file:border-0 file:bg-zinc-700 file:text-white file:cursor-pointer" |
|
| 205 | + | class="w-full text-sm bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500 file:mr-3 file:py-1.5 file:px-3 file:rounded file:border-0 file:bg-zinc-700 file:text-white file:text-sm file:cursor-pointer" |
|
| 183 | 206 | /> |
|
| 184 | 207 | </div> |
|
| 185 | 208 | ||
| 186 | 209 | {#if previewUrl} |
|
| 187 | - | <div class="relative"> |
|
| 210 | + | <div class="flex gap-4"> |
|
| 188 | 211 | <img |
|
| 189 | 212 | src={previewUrl} |
|
| 190 | 213 | alt="Preview" |
|
| 191 | - | class="w-full max-h-64 object-contain rounded bg-zinc-900" |
|
| 214 | + | class="w-32 h-32 object-cover rounded bg-zinc-900 shrink-0" |
|
| 192 | 215 | /> |
|
| 193 | - | </div> |
|
| 194 | - | {/if} |
|
| 195 | - | ||
| 196 | - | <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
|
| 197 | - | <div> |
|
| 198 | - | <label for="title" class="block text-sm mb-2">Title *</label> |
|
| 199 | - | <input |
|
| 200 | - | type="text" |
|
| 201 | - | id="title" |
|
| 202 | - | name="title" |
|
| 203 | - | required |
|
| 204 | - | bind:value={title} |
|
| 205 | - | class="w-full px-4 py-2 bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500" |
|
| 206 | - | /> |
|
| 207 | - | </div> |
|
| 208 | - | ||
| 209 | - | <div> |
|
| 210 | - | <label for="date" class="block text-sm mb-2">Date *</label> |
|
| 211 | - | <input |
|
| 212 | - | type="date" |
|
| 213 | - | id="date" |
|
| 214 | - | name="date" |
|
| 215 | - | required |
|
| 216 | - | bind:value={date} |
|
| 217 | - | class="w-full px-4 py-2 bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500" |
|
| 218 | - | /> |
|
| 219 | - | </div> |
|
| 220 | - | </div> |
|
| 221 | - | ||
| 222 | - | <div class="border-t border-zinc-800 pt-6"> |
|
| 223 | - | <h3 class="text-lg font-medium mb-4">EXIF Data</h3> |
|
| 224 | - | ||
| 225 | - | <div class="grid grid-cols-1 md:grid-cols-2 gap-4"> |
|
| 226 | - | <div> |
|
| 227 | - | <label for="make" class="block text-sm mb-2">Make</label> |
|
| 228 | - | <input |
|
| 229 | - | type="text" |
|
| 230 | - | id="make" |
|
| 231 | - | name="make" |
|
| 232 | - | bind:value={make} |
|
| 233 | - | class="w-full px-4 py-2 bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500" |
|
| 234 | - | /> |
|
| 235 | - | </div> |
|
| 236 | - | ||
| 237 | - | <div> |
|
| 238 | - | <label for="camera" class="block text-sm mb-2">Camera</label> |
|
| 239 | - | <input |
|
| 240 | - | type="text" |
|
| 241 | - | id="camera" |
|
| 242 | - | name="camera" |
|
| 243 | - | bind:value={camera} |
|
| 244 | - | class="w-full px-4 py-2 bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500" |
|
| 245 | - | /> |
|
| 246 | - | </div> |
|
| 216 | + | <div class="flex-1 space-y-3"> |
|
| 217 | + | <div> |
|
| 218 | + | <label for="title" class="block text-xs text-zinc-400 mb-1">Title</label> |
|
| 219 | + | <input |
|
| 220 | + | type="text" |
|
| 221 | + | id="title" |
|
| 222 | + | name="title" |
|
| 223 | + | required |
|
| 224 | + | bind:value={title} |
|
| 225 | + | class="w-full px-3 py-1.5 text-sm bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500" |
|
| 226 | + | /> |
|
| 227 | + | </div> |
|
| 247 | 228 | ||
| 248 | - | <div> |
|
| 249 | - | <label for="lens" class="block text-sm mb-2">Lens</label> |
|
| 250 | - | <input |
|
| 251 | - | type="text" |
|
| 252 | - | id="lens" |
|
| 253 | - | name="lens" |
|
| 254 | - | bind:value={lens} |
|
| 255 | - | class="w-full px-4 py-2 bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500" |
|
| 256 | - | /> |
|
| 257 | - | </div> |
|
| 229 | + | {#if date || camera || lens} |
|
| 230 | + | <div class="text-xs text-zinc-500 space-y-0.5"> |
|
| 231 | + | {#if date}<p>{date}</p>{/if} |
|
| 232 | + | {#if make || camera}<p>{[make, camera].filter(Boolean).join(" ")}</p>{/if} |
|
| 233 | + | {#if lens}<p>{lens}</p>{/if} |
|
| 234 | + | {#if aperture || exposure || focalLength || iso} |
|
| 235 | + | <p>{[aperture, exposure, focalLength, iso ? `ISO ${iso}` : ""].filter(Boolean).join(" | ")}</p> |
|
| 236 | + | {/if} |
|
| 237 | + | </div> |
|
| 238 | + | {/if} |
|
| 258 | 239 | ||
| 259 | - | <div> |
|
| 260 | - | <label for="aperture" class="block text-sm mb-2">Aperture</label> |
|
| 261 | - | <input |
|
| 262 | - | type="text" |
|
| 263 | - | id="aperture" |
|
| 264 | - | name="aperture" |
|
| 265 | - | bind:value={aperture} |
|
| 266 | - | class="w-full px-4 py-2 bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500" |
|
| 267 | - | /> |
|
| 268 | - | </div> |
|
| 269 | - | ||
| 270 | - | <div> |
|
| 271 | - | <label for="exposure" class="block text-sm mb-2">Exposure</label> |
|
| 272 | - | <input |
|
| 273 | - | type="text" |
|
| 274 | - | id="exposure" |
|
| 275 | - | name="exposure" |
|
| 276 | - | bind:value={exposure} |
|
| 277 | - | class="w-full px-4 py-2 bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500" |
|
| 278 | - | /> |
|
| 279 | - | </div> |
|
| 280 | - | ||
| 281 | - | <div> |
|
| 282 | - | <label for="focalLength" class="block text-sm mb-2">Focal Length</label> |
|
| 283 | - | <input |
|
| 284 | - | type="text" |
|
| 285 | - | id="focalLength" |
|
| 286 | - | name="focalLength" |
|
| 287 | - | bind:value={focalLength} |
|
| 288 | - | class="w-full px-4 py-2 bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500" |
|
| 289 | - | /> |
|
| 290 | - | </div> |
|
| 291 | - | ||
| 292 | - | <div> |
|
| 293 | - | <label for="iso" class="block text-sm mb-2">ISO</label> |
|
| 294 | - | <input |
|
| 295 | - | type="text" |
|
| 296 | - | id="iso" |
|
| 297 | - | name="iso" |
|
| 298 | - | bind:value={iso} |
|
| 299 | - | class="w-full px-4 py-2 bg-zinc-900 border border-zinc-700 rounded focus:outline-none focus:border-zinc-500" |
|
| 300 | - | /> |
|
| 240 | + | <!-- Hidden inputs for form submission --> |
|
| 241 | + | <input type="hidden" name="date" value={date} /> |
|
| 242 | + | <input type="hidden" name="make" value={make} /> |
|
| 243 | + | <input type="hidden" name="camera" value={camera} /> |
|
| 244 | + | <input type="hidden" name="lens" value={lens} /> |
|
| 245 | + | <input type="hidden" name="aperture" value={aperture} /> |
|
| 246 | + | <input type="hidden" name="exposure" value={exposure} /> |
|
| 247 | + | <input type="hidden" name="focalLength" value={focalLength} /> |
|
| 248 | + | <input type="hidden" name="iso" value={iso} /> |
|
| 301 | 249 | </div> |
|
| 302 | 250 | </div> |
|
| 303 | - | </div> |
|
| 251 | + | {/if} |
|
| 304 | 252 | ||
| 305 | 253 | {#if form?.error} |
|
| 306 | - | <p class="text-red-500 text-sm">{form.error}</p> |
|
| 254 | + | <p class="text-red-500 text-xs">{form.error}</p> |
|
| 307 | 255 | {/if} |
|
| 308 | 256 | ||
| 309 | 257 | <button |
|
| 310 | 258 | type="submit" |
|
| 311 | 259 | disabled={isLoading || !selectedFile} |
|
| 312 | - | class="w-full py-3 bg-white text-black font-medium rounded hover:bg-zinc-200 transition-colors disabled:opacity-50 disabled:cursor-not-allowed" |
|
| 260 | + | class="w-full py-2 text-sm bg-white text-black font-medium rounded hover:bg-zinc-200 transition-colors disabled:opacity-50 disabled:cursor-not-allowed" |
|
| 313 | 261 | > |
|
| 314 | 262 | {isLoading ? "Uploading..." : "Upload Photo"} |
|
| 315 | 263 | </button> |
|