diff --git a/frontend/src/client/agenda.ts b/frontend/src/client/agenda.ts index c733302..f835f18 100644 --- a/frontend/src/client/agenda.ts +++ b/frontend/src/client/agenda.ts @@ -2,6 +2,13 @@ import { initI18n, onLangChange, t, tDyn, getLang } from "./i18n"; import { initSidebar } from "./sidebar"; import { attachEventTypeMultiSelectFilter, type FilterHandle } from "./event-types"; +// Eye-icon SVG used inside .approval-pill--icon (mirrors events.ts). +const APPROVAL_PILL_EYE_SVG = + ''; + let eventTypeFilter: FilterHandle | null = null; type Urgency = "overdue" | "today" | "tomorrow" | "this_week" | "later"; @@ -279,8 +286,11 @@ function renderItem(it: AgendaItem, bucketUrgency: Urgency): string { const project = it.project_id ? `${esc(formatProjectLabel(it))}` : ""; + // Icon-only pill — eye glyph + tooltip with the lifecycle label. + // m's 2026-05-08 cosmetic ask. + const pendingLabel = it.approval_status === "pending" ? tDyn("approvals.pending_update.label") : ""; const pendingPill = it.approval_status === "pending" - ? `${esc(tDyn("approvals.pending_update.label"))}` + ? `${APPROVAL_PILL_EYE_SVG}` : ""; const timePart = it.type === "appointment" diff --git a/frontend/src/client/events.ts b/frontend/src/client/events.ts index 5df58c5..8435e5c 100644 --- a/frontend/src/client/events.ts +++ b/frontend/src/client/events.ts @@ -9,6 +9,16 @@ import { } from "./event-types"; import { projectIndent } from "./project-indent"; +// Eye-icon SVG used inside .approval-pill--icon. Kept as a string +// constant rather than a separate module since only events.ts and +// agenda.ts render it; the duplication is two lines, easier to read +// than yet another import. +const APPROVAL_PILL_EYE_SVG = + ''; + // EventsPage shared client (t-paliad-110). Drives /deadlines and // /appointments off the same shell — the route handler injects // `window.__PALIAD_EVENTS__ = { defaultType: "deadline" | "appointment" }` @@ -507,12 +517,13 @@ function renderRow(item: EventListItem, showReopen: boolean): string { ? `${esc(tDyn(`appointments.type.${item.appointment_type}`) || item.appointment_type)}` : "—"; - // Approval pending pill (t-paliad-138). Soft-tint the row + insert a - // ⚠ chip next to the title. Generic "pending approval" — the inbox - // shows the lifecycle detail. + // Approval pending pill (t-paliad-138 / m's 2026-05-08 cosmetic ask). + // Soft-tint the row + drop an eye-icon pill next to the title; hover + // reveals the lifecycle label. Inbox surface shows the full detail. const pendingClass = item.approval_status === "pending" ? " entity-row--pending-update" : ""; + const pendingLabel = item.approval_status === "pending" ? t("approvals.pending_update.label") : ""; const pendingPill = item.approval_status === "pending" - ? `${esc(t("approvals.pending_update.label"))}` + ? `${APPROVAL_PILL_EYE_SVG}` : ""; return ` diff --git a/frontend/src/styles/global.css b/frontend/src/styles/global.css index 0d18730..24d2b73 100644 --- a/frontend/src/styles/global.css +++ b/frontend/src/styles/global.css @@ -10612,6 +10612,27 @@ dialog.quick-add-sheet::backdrop { } .approval-pill::before { content: "⚠"; } +/* Icon-only variant — eye glyph signals "preliminary, awaiting approval" + * without consuming row width. Hover (title attr) reveals the full + * lifecycle label. m's 2026-05-08 ask: smaller pill, eye icon, tooltip. */ +.approval-pill--icon { + width: 22px; + height: 22px; + padding: 0; + justify-content: center; + cursor: help; +} +.approval-pill--icon::before { content: ""; } +.approval-pill--icon svg { + width: 14px; + height: 14px; + stroke: currentColor; + fill: none; + stroke-width: 1.8; + stroke-linecap: round; + stroke-linejoin: round; +} + .approval-pill--historic { background: var(--bg-soft); color: var(--fg-muted);