From be9ecd0e8edfbe83a6c148cad5c61cce22687ccb Mon Sep 17 00:00:00 2001 From: Ku6epXBOCTuK Date: Sun, 11 Oct 2026 14:06:10 +0500 Subject: [PATCH] feat: add tooltip for errors\warnings --- .../lib/components/schema/PreviewTile.svelte | 24 +++-- .../components/schema/SchemaActions.svelte | 17 ++-- .../components/schema/SchemaResultTile.svelte | 2 +- .../components/schema/SchemaSourceTile.svelte | 2 +- .../components/schema/SchemaToolView.svelte | 19 ++-- web/src/lib/components/ui/DetailBadge.svelte | 98 +++++++++++++++++++ web/src/lib/i18n/en.ts | 5 + web/src/lib/i18n/ru.ts | 5 + web/src/lib/i18n/schema-tool-strings.ts | 42 +++++--- 9 files changed, 175 insertions(+), 39 deletions(-) create mode 100644 web/src/lib/components/ui/DetailBadge.svelte diff --git a/web/src/lib/components/schema/PreviewTile.svelte b/web/src/lib/components/schema/PreviewTile.svelte index 304eb5f..b848528 100644 --- a/web/src/lib/components/schema/PreviewTile.svelte +++ b/web/src/lib/components/schema/PreviewTile.svelte @@ -3,6 +3,7 @@ import { RefreshCw } from "@lucide/svelte"; import { t } from "$lib/i18n/t"; import Badge from "$lib/components/ui/Badge.svelte"; + import DetailBadge from "$lib/components/ui/DetailBadge.svelte"; import type { Snippet } from "svelte"; interface Props { @@ -15,11 +16,11 @@ dims?: string; note?: string; noteTone?: "warning" | "info"; - // Runtime warnings (chain/download events): shown as badges next to the - // derived result note, but from a different source. - warnings?: string[]; - // Runtime errors: danger badges; detail goes to the native tooltip until - // a popover with full text exists. + // Runtime warnings (chain/source/download events): shown as badges next + // to the derived result note, full message in the "?" popover. + warnings?: { label: string; detail?: string }[]; + // Runtime errors: danger badges; the full message lives in the + // DetailBadge popover behind the "?" button. errors?: { label: string; detail?: string }[]; actions?: Snippet; } @@ -61,15 +62,20 @@ {/if} {#each errors as error (error.label + (error.detail ?? ""))} - {/each} - {#each warnings as warning (warning)} - + {#each warnings as warning (warning.label + (warning.detail ?? ""))} + {/each} diff --git a/web/src/lib/components/schema/SchemaActions.svelte b/web/src/lib/components/schema/SchemaActions.svelte index f4efaa7..84b2eb4 100644 --- a/web/src/lib/components/schema/SchemaActions.svelte +++ b/web/src/lib/components/schema/SchemaActions.svelte @@ -1,7 +1,7 @@ + + + + {#if detail} + + (open = e.newState === "open")} + > + {detail} + + {/if} + + + diff --git a/web/src/lib/i18n/en.ts b/web/src/lib/i18n/en.ts index e58bad6..2946365 100644 --- a/web/src/lib/i18n/en.ts +++ b/web/src/lib/i18n/en.ts @@ -70,6 +70,10 @@ export const en: Dict = { warnSizeLimitMiss: "Could not fit into {limit} KB — downloaded file is {actual} KB", stepFailed: "Step {n} failed", + warnPartialShort: "Some files failed", + warnFirstOnlyShort: "First file only", + warnSourceSkipShort: "Files skipped", + warnSizeLimitMissShort: "Over size limit", }, savedChains: { pageTitle: "Saved pipelines — easy-png-tools", @@ -172,6 +176,7 @@ export const en: Dict = { nothingFound: "Nothing found — try another word.", }, ui: { + detailsAria: "Show details", showMask: "Show mask", decrease: "Decrease", increase: "Increase", diff --git a/web/src/lib/i18n/ru.ts b/web/src/lib/i18n/ru.ts index 9b6a9ca..516ed77 100644 --- a/web/src/lib/i18n/ru.ts +++ b/web/src/lib/i18n/ru.ts @@ -72,6 +72,10 @@ export const ru: Dict = { warnSizeLimitMiss: "Не удалось ужаться до {limit} КБ — скачан файл на {actual} КБ", stepFailed: "Шаг {n}: ошибка", + warnPartialShort: "Часть файлов с ошибкой", + warnFirstOnlyShort: "Только первый файл", + warnSourceSkipShort: "Файлы пропущены", + warnSizeLimitMissShort: "Больше лимита", }, savedChains: { pageTitle: "Сохранённые пайплайны — easy-png-tools", @@ -173,6 +177,7 @@ export const ru: Dict = { nothingFound: "Ничего не найдено — попробуйте другое слово.", }, ui: { + detailsAria: "Показать подробности", showMask: "Показать маску", decrease: "Уменьшить", increase: "Увеличить", diff --git a/web/src/lib/i18n/schema-tool-strings.ts b/web/src/lib/i18n/schema-tool-strings.ts index 9bfd35c..29c6c4b 100644 --- a/web/src/lib/i18n/schema-tool-strings.ts +++ b/web/src/lib/i18n/schema-tool-strings.ts @@ -68,23 +68,41 @@ export function verdictTone(key: string): "success" | "danger" | "info" { return "info"; } -/** Human-readable text for a chain run/source warning. */ -export function chainWarningText(w: ChainWarning): string { +/** Short label for a warning badge; detail holds the full message (popover). */ +export interface WarningNotice { + label: string; + detail: string; +} + +/** Human-readable badge + popover text for a chain run/source warning. */ +export function chainWarningNotice(w: ChainWarning): WarningNotice { switch (w.kind) { case "partial": - return t("chain.warnPartial", { n: w.step, ok: w.ok, total: w.total }); + return { + label: t("chain.warnPartialShort"), + detail: t("chain.warnPartial", { n: w.step, ok: w.ok, total: w.total }), + }; case "firstOnly": - return t("chain.warnFirstOnly", { n: w.step, total: w.total }); + return { + label: t("chain.warnFirstOnlyShort"), + detail: t("chain.warnFirstOnly", { n: w.step, total: w.total }), + }; case "sourceSkip": - return t("chain.warnSourceSkip", { - skipped: w.skipped, - total: w.total, - }); + return { + label: t("chain.warnSourceSkipShort"), + detail: t("chain.warnSourceSkip", { + skipped: w.skipped, + total: w.total, + }), + }; case "sizeLimitMiss": - return t("chain.warnSizeLimitMiss", { - limit: w.limitKb, - actual: w.actualKb, - }); + return { + label: t("chain.warnSizeLimitMissShort"), + detail: t("chain.warnSizeLimitMiss", { + limit: w.limitKb, + actual: w.actualKb, + }), + }; } }