From a0bc72ef5d06b65507d6fe2ee3150872dbc146ae Mon Sep 17 00:00:00 2001 From: Ku6epXBOCTuK Date: Mon, 5 Oct 2026 14:54:39 +0500 Subject: [PATCH] feat: upload image on click, tooltip --- docs/backlog.md | 2 - web/src/app.css | 1 + .../components/schema/SchemaSourceTile.svelte | 88 ++++++++++++++++++- web/src/lib/i18n/en.ts | 1 + web/src/lib/i18n/ru.ts | 1 + 5 files changed, 89 insertions(+), 4 deletions(-) diff --git a/docs/backlog.md b/docs/backlog.md index d90d474..24a269b 100644 --- a/docs/backlog.md +++ b/docs/backlog.md @@ -155,8 +155,6 @@ - [ ] просмотр картинки в оригинальном размере, и возможно с зумом отдельных областей, чтобы просмотреть мелкие артефакты, выбор разных подложек - черная\белая\цветные\серая для проверки прозрачных картинок -- [ ] при клике на картинку-исходник предложить загрузитрь другой файл (возможно - сделать кнопку, которая появляется при ховере на картинке) - [ ] обдумать объединение пар `inputMode + source` и `resultKind + result` в единую структуру, позволит упростить некоторые вещи - например `sourceValue` \ `resultValue` в `SchemaPreview.svelte` diff --git a/web/src/app.css b/web/src/app.css index bbab20b..96a3827 100644 --- a/web/src/app.css +++ b/web/src/app.css @@ -122,6 +122,7 @@ --color-main-tint: hct(from var(--brand-main) h 65 55); --color-main-soft: color-mix(in srgb, var(--color-main) 12%, transparent); + --color-scrim: color-mix(in srgb, var(--color-background) 65%, transparent); --color-accent-tint: hct(from var(--brand-alt) h 65 55); --color-success-tint: hct(160 65 55); --color-warning-tint: hct(80 65 55); diff --git a/web/src/lib/components/schema/SchemaSourceTile.svelte b/web/src/lib/components/schema/SchemaSourceTile.svelte index ccac845..efa094f 100644 --- a/web/src/lib/components/schema/SchemaSourceTile.svelte +++ b/web/src/lib/components/schema/SchemaSourceTile.svelte @@ -29,6 +29,27 @@ const sourceUrl = $derived(source ? toDataUrl(source) : null); let dragging = $state(false); + let input = $state(null); + // Подсказка замены: показываем на ховер и гасим через 10с до нового захода. + let hintVisible = $state(false); + let hintTimer: ReturnType | null = null; + + function showHint() { + hintVisible = true; + if (hintTimer) clearTimeout(hintTimer); + hintTimer = setTimeout(() => { + hintVisible = false; + hintTimer = null; + }, 3_000); + } + + function hideHint() { + hintVisible = false; + if (hintTimer) { + clearTimeout(hintTimer); + hintTimer = null; + } + } function onDrop(e: DragEvent) { e.preventDefault(); @@ -36,6 +57,10 @@ const file = e.dataTransfer?.files?.[0]; if (file) onupload?.(file); } + + function open() { + input?.click(); + } @@ -52,15 +77,38 @@
{ + if (e.key === "Enter" || e.key === " ") { + e.preventDefault(); + open(); + } + }} ondragover={(e) => { e.preventDefault(); dragging = true; }} ondragleave={() => (dragging = false)} ondrop={onDrop} + onmouseenter={showHint} + onmouseleave={hideHint} + onfocus={showHint} + onblur={hideHint} > + { + const file = (e.target as HTMLInputElement).files?.[0]; + if (file) onupload?.(file); + }} + /> {#if dragging} {t("dropZone.overlayDefault")} + {:else} + {t("sourceCard.replaceHint")} {/if}
{:else if mode === "image"} @@ -114,4 +164,38 @@ text-align: center; pointer-events: none; } + .tile-drop { + cursor: pointer; + } + .tile-drop::before { + content: ""; + position: absolute; + inset: 0; + background: var(--color-scrim); + opacity: 0; + transition: opacity var(--duration-s) ease; + pointer-events: none; + } + .tile-drop.hint::before { + opacity: 1; + } + .tile-drop .hover-hint { + position: absolute; + inset: 25%; + display: grid; + place-items: center; + padding: var(--space-l); + border: var(--size-border-thick) dashed var(--color-main); + border-radius: var(--radius-m); + background: var(--color-panel); + color: var(--color-main); + font: 600 var(--font-size-l) var(--font-mono); + text-align: center; + opacity: 0; + transition: opacity var(--duration-s) ease; + pointer-events: none; + } + .tile-drop.hint .hover-hint { + opacity: 1; + } diff --git a/web/src/lib/i18n/en.ts b/web/src/lib/i18n/en.ts index 1865535..3008cd7 100644 --- a/web/src/lib/i18n/en.ts +++ b/web/src/lib/i18n/en.ts @@ -59,6 +59,7 @@ export const en: Dict = { sourceCard: { source: "Source", replaceImage: "Replace image", + replaceHint: "Click to upload an image", chooseImage: "choose an image", noSource: "no source — configure the parameters", alt: "Source image", diff --git a/web/src/lib/i18n/ru.ts b/web/src/lib/i18n/ru.ts index e84743f..c1b11c4 100644 --- a/web/src/lib/i18n/ru.ts +++ b/web/src/lib/i18n/ru.ts @@ -60,6 +60,7 @@ export const ru: Dict = { sourceCard: { source: "Источник", replaceImage: "Заменить изображение", + replaceHint: "Кликните, чтобы загрузить изображение", chooseImage: "выберите изображение", noSource: "нет источника — настройте параметры", alt: "Исходное изображение",