From a94c964267f41b1177149219ce1760cd10bb876f Mon Sep 17 00:00:00 2001 From: qer Date: Sun, 28 Jun 2026 00:34:08 +0800 Subject: [PATCH] feat(web): focus composer on /new and /clear, keep viewport scalable --- .changeset/focus-new-session-input.md | 5 ++++ apps/kimi-web/src/App.vue | 12 +++++++++- .../kimi-web/src/components/chat/ChatDock.vue | 8 +++++-- .../kimi-web/src/components/chat/Composer.vue | 7 +++++- .../src/components/chat/ConversationPane.vue | 23 ++++++++++++++----- .../components/dialogs/NewSessionDialog.vue | 23 ++++++++++++++----- 6 files changed, 62 insertions(+), 16 deletions(-) create mode 100644 .changeset/focus-new-session-input.md diff --git a/.changeset/focus-new-session-input.md b/.changeset/focus-new-session-input.md new file mode 100644 index 0000000000..33114e6b7a --- /dev/null +++ b/.changeset/focus-new-session-input.md @@ -0,0 +1,5 @@ +--- +"@moonshot-ai/kimi-code": patch +--- + +In the bundled web UI, `/new` and `/clear` are now aliases that open the session onboarding composer and focus the input. iOS auto-zoom is prevented by keeping text inputs at 16px instead of disabling viewport scaling. diff --git a/apps/kimi-web/src/App.vue b/apps/kimi-web/src/App.vue index 51d2f4eb2b..51a75ba5de 100644 --- a/apps/kimi-web/src/App.vue +++ b/apps/kimi-web/src/App.vue @@ -394,9 +394,11 @@ function handleCommand(cmd: string): void { return; } switch (cmd) { + // `/new` and `/clear` are aliases: both open the onboarding composer (or + // the new-session dialog when no workspace is active). case '/new': case '/clear': - showNewSession.value = true; + handleCreateSession(); break; case '/sessions': showSessions.value = true; @@ -496,6 +498,12 @@ function handleCloseAddWorkspace(): void { showAddWorkspace.value = false; } +function focusComposerAfterDraft(): void { + void nextTick(() => { + conversationPaneRef.value?.focusComposer(); + }); +} + // Primary "+ New": enter the draft state in the current workspace so the // right pane shows the onboarding composer. The session is only created when // the user sends the first message. @@ -503,6 +511,7 @@ function handleCreateSession(): void { const wsId = client.activeWorkspaceId.value; if (wsId) { client.openWorkspaceDraft(wsId); + focusComposerAfterDraft(); } else { showNewSession.value = true; } @@ -513,6 +522,7 @@ function handleCreateSession(): void { // actually sends a message. function handleCreateSessionInWorkspace(workspaceId: string): void { client.openWorkspaceDraft(workspaceId); + focusComposerAfterDraft(); } // Chat header: open a GitHub PR in a new tab. diff --git a/apps/kimi-web/src/components/chat/ChatDock.vue b/apps/kimi-web/src/components/chat/ChatDock.vue index 6da44466a1..94b6fe46e3 100644 --- a/apps/kimi-web/src/components/chat/ChatDock.vue +++ b/apps/kimi-web/src/components/chat/ChatDock.vue @@ -75,7 +75,7 @@ const emit = defineEmits<{ }>(); const { t } = useI18n(); -const composerRef = ref<{ loadForEdit: (value: string) => void } | null>(null); +const composerRef = ref<{ loadForEdit: (value: string) => void; focus: () => void } | null>(null); const workPanelRef = ref(null); const workbarRef = ref(null); @@ -83,6 +83,10 @@ function loadForEdit(value: string): void { composerRef.value?.loadForEdit(value); } +function focus(): void { + composerRef.value?.focus(); +} + function handleEditQueued(index: number): void { const text = props.queued?.[index]?.text ?? ''; if (text) loadForEdit(text); @@ -114,7 +118,7 @@ onUnmounted(() => { } }); -defineExpose({ loadForEdit }); +defineExpose({ loadForEdit, focus });