fix(03-04): replace CameraCapture with file input capture="environment"

- Remove CameraCapture modal which required getUserMedia (HTTPS only)
- Use native file input with capture="environment" attribute
- Opens camera directly via OS file picker on mobile
- Works over HTTP during development
- Simpler implementation with better browser compatibility
This commit is contained in:
Thomas Richter
2026-01-31 12:19:16 +01:00
parent b239862854
commit a2f9183011

View File

@@ -5,8 +5,7 @@
import { slide } from 'svelte/transition';
import ImageGallery from './ImageGallery.svelte';
import ImageUpload from './ImageUpload.svelte';
import CameraCapture from './CameraCapture.svelte';
interface EntryWithImages extends Entry {
images: Image[];
}
@@ -21,8 +20,8 @@
let expanded = $state(false);
// Image management state
let showCamera = $state(false);
let editImagesMode = $state(false);
let cameraInput: HTMLInputElement;
// Edit state - use $derived to stay in sync with entry prop
let editTitle = $state(entry.title || '');
@@ -49,6 +48,11 @@
let isSwiping = $state(false);
function handleTouchStart(e: TouchEvent) {
// Ignore if touch started on a button or interactive element
const target = e.target as HTMLElement;
if (target.closest('button, input, textarea, select, a, [role="button"]')) {
return;
}
touchStartX = e.touches[0].clientX;
isSwiping = true;
}
@@ -151,9 +155,22 @@
// invalidateAll is called by ImageUpload, so nothing extra needed here
}
function handleCameraCapture() {
showCamera = false;
// invalidateAll is called by CameraCapture
async function handleCameraInput(e: Event) {
const input = e.target as HTMLInputElement;
const file = input.files?.[0];
if (!file || !file.type.startsWith('image/')) return;
const formData = new FormData();
formData.append('image', file);
formData.append('entryId', entry.id);
await fetch('?/uploadImage', {
method: 'POST',
body: formData
});
await invalidateAll();
input.value = '';
}
</script>
@@ -357,7 +374,7 @@
</div>
<button
type="button"
onclick={() => (showCamera = true)}
onclick={() => cameraInput?.click()}
class="px-4 py-2 border border-gray-300 rounded-lg flex items-center gap-2 hover:bg-gray-50 transition-colors"
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
@@ -376,6 +393,14 @@
</svg>
Camera
</button>
<input
bind:this={cameraInput}
type="file"
accept="image/*"
capture="environment"
onchange={handleCameraInput}
class="hidden"
/>
</div>
</div>
@@ -436,10 +461,3 @@
{/if}
</div>
{#if showCamera}
<CameraCapture
entryId={entry.id}
onClose={() => (showCamera = false)}
onCapture={handleCameraCapture}
/>
{/if}