Files
ai-florist/src/lib/components/ui/upload/UploadTile.svelte
Chaewon Lee 3e0ff5df70 refine: ui, prompt, and desc card
* ui improved

* prompt:realisic+noHuman

* prompt:editRefinement

* fix: map DescriptionCard truncation and truncateAt typo

Prevent result/map card overflow with character limits and line-clamp; fix buildMapOrderDescription calling undefined truncateAt.

Co-authored-by: Cursor <cursoragent@cursor.com>

---------

Co-authored-by: 이지은 <ijieun@ijieun-ui-MacBookPro.local>
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-06-16 10:27:27 +09:00

82 lines
2.2 KiB
Svelte

<script>
// A single click-to-upload slot: a light bordered placeholder when empty,
// the chosen image (cover) when filled. Layout (size / grid placement) is
// supplied by the parent via `class` and `style` so the same tile works in
// both the moodboard and the SNS feed.
let {
label = null,
/** 빈 타일 중앙에 표시할 안내 문장 */
prompt = null,
showLabel = true,
class: klass = '',
style = '',
file = $bindable(null)
} = $props();
let preview = $state(null);
function pick(event) {
const picked = event.currentTarget.files?.[0];
if (!picked) return;
file = picked;
}
// 부모에서 File을 주입할 때(Dev seed 등) 미리보기 동기화
$effect(() => {
if (!file) {
preview = null;
return;
}
const url = URL.createObjectURL(file);
preview = url;
return () => URL.revokeObjectURL(url);
});
</script>
<label
class={[
'group relative flex cursor-pointer items-center justify-center overflow-hidden bg-track transition-colors',
!preview && 'border border-line hover:border-line-strong',
klass
]}
{style}
>
<input
type="file"
accept="image/*"
class="sr-only"
aria-label={prompt ?? (label ? `Add a ${label} image` : 'Add an image')}
onchange={pick}
/>
{#if preview}
<img src={preview} alt={label ?? ''} class="h-full w-full object-cover" />
<div class="absolute inset-0 bg-linear-to-t from-ink/45 to-transparent"></div>
{#if label && showLabel}
<span class="absolute bottom-3 left-4 text-sm tracking-[0.15em] text-surface uppercase"
>{label}</span
>
{/if}
<span
class="absolute top-3 right-3 rounded-full bg-ink/40 px-2.5 py-1 text-xs text-surface opacity-0 backdrop-blur-sm transition-opacity group-hover:opacity-100"
>
Change
</span>
{:else}
<div
class="flex flex-col items-center gap-3 px-4 text-center text-subtle transition-transform group-hover:scale-105"
>
<span
class="flex size-10 shrink-0 items-center justify-center rounded-full border border-current text-xl leading-none"
aria-hidden="true">+</span
>
{#if prompt}
<span class="max-w-[14rem] text-sm leading-snug text-muted">{prompt}</span>
{:else if label && showLabel}
<span class="text-sm tracking-[0.15em] uppercase">{label}</span>
{/if}
</div>
{/if}
</label>