From 788a012aadf5264e239ef3bc583760213588f908 Mon Sep 17 00:00:00 2001 From: kirillk Date: Mon, 23 Mar 2026 17:23:13 -0400 Subject: [PATCH 1/2] feat(vscode): restyle onboarding notifications banner with wizard-style navigation - Replace X dismiss button with Previous/Next/Close navigation flow - Show X/Y progress indicator in header when multiple notifications - Add outlined button style for action buttons using VS Code theme tokens - Raise z-index to 1000 so banner renders above membership panel - Add i18n keys for Previous, Next, Close, and Try model across all 18 locales --- .../src/components/chat/KiloNotifications.tsx | 60 +++++++++--------- .../kilo-vscode/webview-ui/src/i18n/ar.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/br.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/bs.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/da.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/de.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/en.ts | 5 ++ .../kilo-vscode/webview-ui/src/i18n/es.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/fr.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/ja.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/ko.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/nl.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/no.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/pl.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/ru.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/th.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/tr.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/zh.ts | 4 ++ .../kilo-vscode/webview-ui/src/i18n/zht.ts | 4 ++ .../webview-ui/src/styles/chat.css | 61 ++++++++++++++++++- 20 files changed, 163 insertions(+), 31 deletions(-) diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/KiloNotifications.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/KiloNotifications.tsx index 2bacc16c8c5..9b839e73194 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/KiloNotifications.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/KiloNotifications.tsx @@ -1,11 +1,9 @@ import { Component, Show, createMemo, createSignal } from "solid-js" -import { Button } from "@kilocode/kilo-ui/button" -import { IconButton } from "@kilocode/kilo-ui/icon-button" -import { Icon } from "@kilocode/kilo-ui/icon" import { useNotifications } from "../../context/notifications" import { useVSCode } from "../../context/vscode" import { useSession } from "../../context/session" import { useProvider } from "../../context/provider" +import { useLanguage } from "../../context/language" import { KILO_PROVIDER_ID } from "../../../../src/shared/provider-model" import { TelemetryEventName } from "../../../../src/services/telemetry/types" @@ -14,6 +12,7 @@ export const KiloNotifications: Component = () => { const vscode = useVSCode() const session = useSession() const provider = useProvider() + const language = useLanguage() const [index, setIndex] = createSignal(0) const items = filteredNotifications @@ -21,18 +20,18 @@ export const KiloNotifications: Component = () => { const safeIndex = () => Math.min(index(), Math.max(0, total() - 1)) const current = createMemo(() => (total() === 0 ? undefined : items()[safeIndex()])) - const prev = () => setIndex((i) => (i - 1 + total()) % total()) - const next = () => setIndex((i) => (i + 1) % total()) - const handleAction = (url: string) => { vscode.postMessage({ type: "openExternal", url }) } - const handleDismiss = () => { - const n = current() - if (!n) return - dismiss(n.id) - setIndex((i) => Math.min(i, Math.max(0, total() - 2))) + const isLast = () => safeIndex() === total() - 1 + + const handleNext = () => { + if (isLast()) { + for (const n of items()) dismiss(n.id) + } else { + setIndex((i) => i + 1) + } } /** @@ -73,35 +72,36 @@ export const KiloNotifications: Component = () => {
{current()?.title} - + 1}> + + {safeIndex() + 1} / {total()} + +

{current()?.message}

diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts index 9c5f727ae78..f2b84d80c79 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ar.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ar.ts @@ -1188,4 +1188,8 @@ export const dict = { "settings.saveBar.warning.many": "عدة جلسات تعمل وستتوقف", "settings.saveBar.saveAnyway": "حفظ على أي حال", "settings.saveBar.cancel": "إلغاء", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/br.ts b/packages/kilo-vscode/webview-ui/src/i18n/br.ts index 6bb8a8357c9..003bbe2bcbf 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/br.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/br.ts @@ -1211,4 +1211,8 @@ export const dict = { "settings.saveBar.warning.many": "Várias sessões estão em execução e serão interrompidas", "settings.saveBar.saveAnyway": "Salvar mesmo assim", "settings.saveBar.cancel": "Cancelar", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts index 6bffbb3ca30..8d9a97cccd2 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/bs.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/bs.ts @@ -1210,4 +1210,8 @@ export const dict = { "settings.saveBar.warning.many": "Nekoliko sesija je pokrenuto i bit će prekinuto", "settings.saveBar.saveAnyway": "Spremi svejedno", "settings.saveBar.cancel": "Otkaži", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/da.ts b/packages/kilo-vscode/webview-ui/src/i18n/da.ts index 512571f61b6..1e05686dad3 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/da.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/da.ts @@ -1203,4 +1203,8 @@ export const dict = { "settings.saveBar.warning.many": "Flere sessioner kører og vil blive afbrudt", "settings.saveBar.saveAnyway": "Gem alligevel", "settings.saveBar.cancel": "Annuller", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/de.ts b/packages/kilo-vscode/webview-ui/src/i18n/de.ts index 5f6018e047c..c95c970bdf3 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/de.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/de.ts @@ -1225,4 +1225,8 @@ export const dict = { "settings.saveBar.warning.many": "Mehrere Sitzungen laufen und werden unterbrochen", "settings.saveBar.saveAnyway": "Trotzdem speichern", "settings.saveBar.cancel": "Abbrechen", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } satisfies Partial> diff --git a/packages/kilo-vscode/webview-ui/src/i18n/en.ts b/packages/kilo-vscode/webview-ui/src/i18n/en.ts index 7558d52c738..b508de7a234 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/en.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/en.ts @@ -1216,4 +1216,9 @@ export const dict = { "settings.saveBar.warning.many": "Several sessions are running and will be interrupted", "settings.saveBar.saveAnyway": "Save anyway", "settings.saveBar.cancel": "Cancel", + + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/es.ts b/packages/kilo-vscode/webview-ui/src/i18n/es.ts index 4bf2c991a0e..7fbd52c4aac 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/es.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/es.ts @@ -1214,4 +1214,8 @@ export const dict = { "settings.saveBar.warning.many": "Varias sesiones están en ejecución y se interrumpirán", "settings.saveBar.saveAnyway": "Guardar de todas formas", "settings.saveBar.cancel": "Cancelar", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts index 6f3a2067355..56070e8e505 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/fr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/fr.ts @@ -1226,4 +1226,8 @@ export const dict = { "settings.saveBar.warning.many": "Plusieurs sessions sont en cours et seront interrompues", "settings.saveBar.saveAnyway": "Enregistrer quand même", "settings.saveBar.cancel": "Annuler", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts index df4a29e69db..6a4ebbb7dba 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ja.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ja.ts @@ -1200,4 +1200,8 @@ export const dict = { "settings.saveBar.warning.many": "複数のセッションが実行中で中断されます", "settings.saveBar.saveAnyway": "それでも保存", "settings.saveBar.cancel": "キャンセル", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts index 1935ce8b9c4..cb6e9d95115 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ko.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ko.ts @@ -1191,4 +1191,8 @@ export const dict = { "settings.saveBar.warning.many": "여러 세션이 실행 중이며 중단됩니다", "settings.saveBar.saveAnyway": "그래도 저장", "settings.saveBar.cancel": "취소", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts index 0ec1a54c039..456236caf96 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/nl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/nl.ts @@ -1232,4 +1232,8 @@ export const dict = { "settings.saveBar.warning.many": "Meerdere sessies zijn actief en worden onderbroken", "settings.saveBar.saveAnyway": "Toch opslaan", "settings.saveBar.cancel": "Annuleren", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/no.ts b/packages/kilo-vscode/webview-ui/src/i18n/no.ts index 41f5d36b390..f6a325738bd 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/no.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/no.ts @@ -1201,4 +1201,8 @@ export const dict = { "settings.saveBar.warning.many": "Flere økter kjører og vil bli avbrutt", "settings.saveBar.saveAnyway": "Lagre uansett", "settings.saveBar.cancel": "Avbryt", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } satisfies Partial> diff --git a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts index 24e68ab8ba5..c5ded7a8b31 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/pl.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/pl.ts @@ -1208,4 +1208,8 @@ export const dict = { "settings.saveBar.warning.many": "Kilka sesji jest uruchomionych i zostanie przerwanych", "settings.saveBar.saveAnyway": "Zapisz mimo to", "settings.saveBar.cancel": "Anuluj", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts index 16f690a128a..d743b1cd680 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/ru.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/ru.ts @@ -1207,4 +1207,8 @@ export const dict = { "settings.saveBar.warning.many": "Несколько сеансов выполняются и будут прерваны", "settings.saveBar.saveAnyway": "Сохранить в любом случае", "settings.saveBar.cancel": "Отмена", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/th.ts b/packages/kilo-vscode/webview-ui/src/i18n/th.ts index d41aa865244..f6b9a97d219 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/th.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/th.ts @@ -1187,4 +1187,8 @@ export const dict = { "settings.saveBar.warning.many": "มีหลายเซสชันกำลังทำงานและจะถูกขัดจังหวะ", "settings.saveBar.saveAnyway": "บันทึกต่อไป", "settings.saveBar.cancel": "ยกเลิก", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts index 0da999bcab6..7139c4364e1 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/tr.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/tr.ts @@ -1226,4 +1226,8 @@ export const dict = { "settings.saveBar.warning.many": "Birden fazla oturum çalışıyor ve kesintiye uğrayacak", "settings.saveBar.saveAnyway": "Yine de kaydet", "settings.saveBar.cancel": "İptal", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts index 57039a79909..d4424a61bfa 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zh.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zh.ts @@ -1171,4 +1171,8 @@ export const dict = { "settings.saveBar.warning.many": "多个会话正在运行,将被中断", "settings.saveBar.saveAnyway": "仍然保存", "settings.saveBar.cancel": "取消", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } satisfies Partial> diff --git a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts index 461c0f25cf7..e200222b813 100644 --- a/packages/kilo-vscode/webview-ui/src/i18n/zht.ts +++ b/packages/kilo-vscode/webview-ui/src/i18n/zht.ts @@ -1172,4 +1172,8 @@ export const dict = { "settings.saveBar.warning.many": "多個工作階段正在執行,將被中斷", "settings.saveBar.saveAnyway": "仍然儲存", "settings.saveBar.cancel": "取消", + "notifications.action.previous": "Previous", + "notifications.action.next": "Next", + "notifications.action.close": "Close", + "notifications.action.tryModel": "Try model", } satisfies Partial> diff --git a/packages/kilo-vscode/webview-ui/src/styles/chat.css b/packages/kilo-vscode/webview-ui/src/styles/chat.css index cc6fc06855f..ee7b045df24 100644 --- a/packages/kilo-vscode/webview-ui/src/styles/chat.css +++ b/packages/kilo-vscode/webview-ui/src/styles/chat.css @@ -2124,7 +2124,7 @@ top: 0; left: 0; right: 0; - z-index: 10; + z-index: 1000; display: flex; flex-direction: column; border-bottom: 1px solid var(--vscode-panel-border); @@ -2185,6 +2185,65 @@ gap: 2px; } +.kilo-notifications-next-group { + display: flex; + align-items: center; + gap: 6px; +} + +.kilo-notifications-action-btn { + display: inline-flex; + align-items: center; + justify-content: center; + height: 24px; + padding: 0 8px; + background: none; + border: 1px solid var(--vscode-focusBorder); + border-radius: 3px; + color: var(--vscode-focusBorder); + font-size: 12px; + font-family: var(--vscode-font-family); + cursor: pointer; + white-space: nowrap; +} + +.kilo-notifications-action-btn:hover { + background-color: var(--vscode-toolbar-hoverBackground); +} + +.kilo-notifications-primary-btn { + display: inline-flex; + align-items: center; + justify-content: center; + height: 24px; + padding: 0 8px; + background-color: var(--vscode-button-background); + border: 1px solid transparent; + border-radius: 3px; + color: var(--vscode-button-foreground); + font-size: 12px; + font-family: var(--vscode-font-family); + cursor: pointer; + white-space: nowrap; +} + +.kilo-notifications-primary-btn:hover { + background-color: var(--vscode-button-hoverBackground); +} + +.kilo-notifications-back-link { + background: none; + border: none; + padding: 0; + cursor: pointer; + color: var(--vscode-descriptionForeground); + font-size: 12px; +} + +.kilo-notifications-back-link:hover { + color: var(--vscode-foreground); +} + .kilo-notifications-nav-btn { background: none; border: none; From 3f4598266c0a2a06d089e091a53014fa94aa2993 Mon Sep 17 00:00:00 2001 From: kirillk Date: Mon, 23 Mar 2026 17:33:34 -0400 Subject: [PATCH 2/2] fix(vscode): clamp notification index when list shrinks and derive navigation from safeIndex --- .../src/components/chat/KiloNotifications.tsx | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/packages/kilo-vscode/webview-ui/src/components/chat/KiloNotifications.tsx b/packages/kilo-vscode/webview-ui/src/components/chat/KiloNotifications.tsx index 9b839e73194..7beffc2fc00 100644 --- a/packages/kilo-vscode/webview-ui/src/components/chat/KiloNotifications.tsx +++ b/packages/kilo-vscode/webview-ui/src/components/chat/KiloNotifications.tsx @@ -1,4 +1,4 @@ -import { Component, Show, createMemo, createSignal } from "solid-js" +import { Component, Show, createEffect, createMemo, createSignal } from "solid-js" import { useNotifications } from "../../context/notifications" import { useVSCode } from "../../context/vscode" import { useSession } from "../../context/session" @@ -20,6 +20,12 @@ export const KiloNotifications: Component = () => { const safeIndex = () => Math.min(index(), Math.max(0, total() - 1)) const current = createMemo(() => (total() === 0 ? undefined : items()[safeIndex()])) + // Clamp index whenever the list shrinks so navigation always reflects reality + createEffect(() => { + const max = Math.max(0, total() - 1) + if (index() > max) setIndex(max) + }) + const handleAction = (url: string) => { vscode.postMessage({ type: "openExternal", url }) } @@ -30,7 +36,7 @@ export const KiloNotifications: Component = () => { if (isLast()) { for (const n of items()) dismiss(n.id) } else { - setIndex((i) => i + 1) + setIndex(safeIndex() + 1) } } @@ -94,7 +100,7 @@ export const KiloNotifications: Component = () => {
0}> -