From 334e1430575caaf3d587d75c4e012c07594dec4a Mon Sep 17 00:00:00 2001 From: qer Date: Thu, 11 Jun 2026 18:25:17 +0800 Subject: [PATCH] feat(web): add Kimi design-language theme, drop Terminal from pickers MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a third UI theme "kimi" implementing the official Kimi design language (Quiet Utility) with token-exact values from kimi-design-skill tokens.json v0.2.0: - Interaction accent = kimiDark (black in light / white in dark); kimiBlue stays reserved for brand/data-viz (::selection only) - Gray user bubbles (bubbleGrayPc), flat tool cards and dialogs; shadows only on the composer (shadow.inputDefault) and floating menus (shadow.small); dark elevated surfaces use background.tertiary - PingFang SC for UI, Geist Mono for code (bundled JetBrains fallback) - Modern's de-terminalization rules are shared via :is(html[data-theme="modern"], html[data-theme="kimi"]) — identical specificity, so Modern renders exactly as before; kimi token blocks sit after the data-accent rules and pin the accent (the accent picker is hidden while kimi is active) Theme pickers (sidebar popover, mobile sheet) and onboarding now offer Modern/Kimi only. Terminal remains the CSS baseline and a persisted 'terminal' choice still loads; it's just no longer offered in the UI. Also: file-preview pane default width now follows half the window. --- apps/kimi-web/index.html | 2 +- apps/kimi-web/src/App.vue | 12 +- .../src/components/ConversationPane.vue | 5 +- .../src/components/MobileSettingsSheet.vue | 12 +- apps/kimi-web/src/components/Onboarding.vue | 27 +- apps/kimi-web/src/components/Sidebar.vue | 24 +- .../src/composables/useKimiWebClient.ts | 10 +- .../src/i18n/locales/en/onboarding.ts | 2 +- apps/kimi-web/src/i18n/locales/en/theme.ts | 2 +- .../src/i18n/locales/zh/onboarding.ts | 2 +- apps/kimi-web/src/i18n/locales/zh/theme.ts | 2 +- apps/kimi-web/src/style.css | 618 ++++++++++++------ 12 files changed, 488 insertions(+), 230 deletions(-) diff --git a/apps/kimi-web/index.html b/apps/kimi-web/index.html index 1c024e8e1..255b88737 100644 --- a/apps/kimi-web/index.html +++ b/apps/kimi-web/index.html @@ -15,7 +15,7 @@ (function () { try { var theme = localStorage.getItem('kimi-web.theme'); - document.documentElement.dataset.theme = theme === 'terminal' || theme === 'modern' ? theme : 'modern'; + document.documentElement.dataset.theme = theme === 'terminal' || theme === 'modern' || theme === 'kimi' ? theme : 'modern'; var v = localStorage.getItem('kimi-web.color-scheme'); if (v === 'light' || v === 'dark' || v === 'system') { document.documentElement.dataset.colorScheme = v; diff --git a/apps/kimi-web/src/App.vue b/apps/kimi-web/src/App.vue index 3027f5661..04aa72216 100644 --- a/apps/kimi-web/src/App.vue +++ b/apps/kimi-web/src/App.vue @@ -86,9 +86,11 @@ const sideWidth = computed(() => sessionColWidth.value); // tab keeps its local split-pane preview. // --------------------------------------------------------------------------- const PREVIEW_WIDTH_KEY = 'kimi-web.file-preview-width'; -const PREVIEW_DEFAULT = 460; const PREVIEW_MIN = 320; const PREVIEW_MAX = 760; +const PREVIEW_DEFAULT = typeof window !== 'undefined' + ? Math.max(PREVIEW_MIN, Math.min(PREVIEW_MAX, Math.round(window.innerWidth / 2))) + : 460; const previewWidth = ref(PREVIEW_DEFAULT); const previewTarget = ref(null); @@ -536,7 +538,7 @@ function handleCreateSessionInWorkspace(workspaceId: string): void { v-if="!hasMultiSelect" ref="conversationPaneRef" :mobile="isMobile" - :modern="client.theme.value === 'modern'" + :modern="client.theme.value === 'modern' || client.theme.value === 'kimi'" :turns="client.turns.value" :approvals="client.pendingApprovals.value" :changes="client.changes.value" @@ -908,8 +910,10 @@ function handleCreateSessionInWorkspace(workspaceId: string): void { diff --git a/apps/kimi-web/src/components/ConversationPane.vue b/apps/kimi-web/src/components/ConversationPane.vue index 5507cee88..06e1b898b 100644 --- a/apps/kimi-web/src/components/ConversationPane.vue +++ b/apps/kimi-web/src/components/ConversationPane.vue @@ -50,7 +50,7 @@ const props = defineProps<{ fileReloadKey?: string | number; /** Mobile shell: compact chrome + give the TabBar bigger taps. */ mobile?: boolean; - /** Modern theme: render chat bubbles at all widths (desktop included). */ + /** Bubble themes (Modern/Kimi): render chat bubbles at all widths (desktop included). */ modern?: boolean; /** True while switching sessions and the turns array is not yet loaded. */ sessionLoading?: boolean; @@ -127,7 +127,7 @@ watch( }, ); -// Bubble chat layout: always on mobile, and on desktop under the Modern theme. +// Bubble chat layout: always on mobile, and on desktop under Modern/Kimi. const bubble = computed(() => props.mobile === true || props.modern === true); const runningTasks = computed(() => props.tasks.filter((t) => t.state === 'run').length); @@ -841,6 +841,7 @@ onUnmounted(() => { @media (max-width: 1199px) { .float-stack { display: none; } } + .panes { flex: 1; min-height: 0; diff --git a/apps/kimi-web/src/components/MobileSettingsSheet.vue b/apps/kimi-web/src/components/MobileSettingsSheet.vue index 0727caf66..2085311f7 100644 --- a/apps/kimi-web/src/components/MobileSettingsSheet.vue +++ b/apps/kimi-web/src/components/MobileSettingsSheet.vue @@ -168,10 +168,10 @@ function onLogout(): void { + :class="{ on: theme === 'kimi' }" + :aria-pressed="theme === 'kimi'" + @click="emit('setTheme', 'kimi')" + >{{ t('theme.kimi') }} @@ -204,7 +204,9 @@ function onLogout(): void { -
+ +
{{ t('theme.accentLabel') }} diff --git a/apps/kimi-web/src/components/Onboarding.vue b/apps/kimi-web/src/components/Onboarding.vue index a660a53b3..ccc8870b5 100644 --- a/apps/kimi-web/src/components/Onboarding.vue +++ b/apps/kimi-web/src/components/Onboarding.vue @@ -101,21 +101,21 @@ function finish(): void {
- -
+ +
{{ t('theme.accentLabel') }}
+ :class="{ on: theme === 'kimi' }" + :aria-pressed="theme === 'kimi'" + @click="emit('setTheme', 'kimi')" + >{{ t('theme.kimi') }}
@@ -656,7 +656,9 @@ function blinkOnce(): void { >{{ t('theme.system') }}
-
+ +
{{ t('theme.accentLabel') }}
+ :class="{ on: theme === 'kimi' }" + :aria-pressed="theme === 'kimi'" + @click="emit('setTheme', 'kimi')" + >{{ t('theme.kimi') }}
@@ -733,7 +735,9 @@ function blinkOnce(): void { >{{ t('theme.system') }}
-
+ +
{{ t('theme.accentLabel') }}