feat: multi-image uploads

This commit is contained in:
2025-06-05 17:47:08 +01:00
parent 6e45851892
commit 485063f8d2
3 changed files with 74 additions and 30 deletions

View File

@@ -12,13 +12,20 @@
let carousel = $state<HTMLDivElement>();
let scrollPosition = $state(0);
let scrollWidth = $state(0);
let clientWidth = $state(0);
let clientWidth = $state(1);
function updateScroll() {
scrollPosition = carousel?.scrollLeft || 0;
scrollWidth = carousel?.scrollWidth || 0;
clientWidth = carousel?.clientWidth || 0;
clientWidth = carousel?.clientWidth || 1;
}
onMount(updateScroll);
onMount(() => {
const id = setInterval(() => {
if (carousel) {
updateScroll();
}
}, 1000);
return () => clearInterval(id);
});
</script>
<div class="controls">
@@ -37,7 +44,8 @@
{#if scrollPosition > clientWidth / 2}
<button
class="arrow left"
onclick={() => {
onclick={(e) => {
e.preventDefault();
if (carousel) carousel.scrollLeft -= carousel.clientWidth;
}}
>
@@ -47,7 +55,8 @@
{#if scrollPosition < scrollWidth - clientWidth * 1.5}
<button
class="arrow right"
onclick={() => {
onclick={(e) => {
e.preventDefault();
if (carousel) carousel.scrollLeft += carousel.clientWidth;
}}
>
@@ -95,12 +104,14 @@
background-color: rgba(0, 0, 0, 0.5);
border-radius: 9999px;
}
.arrow {
.arrow,
.delete {
cursor: pointer;
width: 2rem;
aspect-ratio: 1 / 1;
}
.arrow img {
.arrow img,
.delete img {
width: 1.4rem;
}
.arrow:hover {
@@ -120,14 +131,14 @@
transform: translateY(-50%);
}
.delete {
top: 0.1rem;
right: 0.1rem;
top: 0.4rem;
right: 0.2rem;
}
.position {
font-size: 0.8rem;
bottom: 0.7rem;
top: 0.4rem;
border-radius: 1rem;
right: 0.2rem;
left: 0.2rem;
padding: 0.3rem 0.5rem;
background-color: rgba(0, 0, 0, 0.7);
}

View File

@@ -1,5 +1,6 @@
<script lang="ts">
import cameraUrl from "$lib/assets/camera.svg";
import Carousel from "../Carousel.svelte";
interface Props {
name: string;
@@ -18,14 +19,37 @@
class:no-bg={files && files.length > 0}
>
{#if files && files.length > 0}
<img src={URL.createObjectURL(files[0])} alt="uploaded study space" class="preview" />
<Carousel
urls={files
? Array(files.length)
.keys()
.map((i) => URL.createObjectURL(files![i]))
.toArray()
: []}
ondelete={(idx) => {
if (!files) return;
const dt = new DataTransfer();
for (let i = 0; i < files.length; i++) {
if (i !== idx) dt.items.add(files[i]);
}
files = dt.files;
}}
/>
{:else}
<div class="message">
<img src={cameraUrl} class="icon" alt="camera icon" />
<span>Click to upload a photo</span>
</div>
{/if}
<input type="file" id={name} {name} accept=".png, .jpg, .jpeg, .svg" {...rest} bind:files />
<input
type="file"
id={name}
{name}
multiple
accept=".png, .jpg, .jpeg, .svg"
{...rest}
bind:files
/>
</label>
<style>