ui : route new-chat entry points through tabs

The sidebar New chat item, Cmd+Shift+O, the search page and the
arrow-key fallback now open a new-chat tab instead of navigating to the
?new_chat URL, which is removed. New chat is no longer a special route
but a tab like any other conversation.
This commit is contained in:
Aleksander Grygier
2026-08-21 15:38:46 +02:00
committed by GitHub
parent d37f8a5c4d
commit 1ae4576fe3
7 changed files with 38 additions and 30 deletions
@@ -12,7 +12,7 @@
SIDEBAR_ACTIONS_ITEMS
} from '$lib/constants';
import { TooltipSide } from '$lib/enums';
import { deviceStore } from '$lib/stores';
import { conversationsStore, deviceStore } from '$lib/stores';
import type { Component } from 'svelte';
import { onMount } from 'svelte';
import { circIn } from 'svelte/easing';
@@ -109,14 +109,20 @@
{@const isActive = isItemActive(item)}
{@const isSearchOnMobile = item.icon === Search && deviceStore.isMobile}
{@const itemHref = isSearchOnMobile ? ROUTES.SEARCH : item.route}
{@const itemOnClick = item.route
? () => {
onNewChat?.();
goto(item.route!);
}
: isSearchOnMobile
? undefined
: onSearchClick}
{@const itemOnClick =
item.action === 'new-chat'
? () => {
onNewChat?.();
conversationsStore.openNewChatTab();
}
: item.route
? () => {
onNewChat?.();
goto(item.route!);
}
: isSearchOnMobile
? undefined
: onSearchClick}
{@const itemTransition = {
delay: !initialized ? i * ICON_STRIP_TRANSITION_DELAY_MULTIPLIER : 0,
duration: ICON_STRIP_TRANSITION_DURATION,
@@ -157,14 +163,20 @@
{#each SIDEBAR_ACTIONS_ITEMS as item, i (item.tooltip)}
{@const isActive = isItemActive(item)}
{@const isSearchOnMobile = item.icon === Search && deviceStore.isMobile}
{@const itemOnClick = item.route
? () => {
onNewChat?.();
goto(item.route!);
}
: isSearchOnMobile
? undefined
: onSearchClick}
{@const itemOnClick =
item.action === 'new-chat'
? () => {
onNewChat?.();
conversationsStore.openNewChatTab();
}
: item.route
? () => {
onNewChat?.();
goto(item.route!);
}
: isSearchOnMobile
? undefined
: onSearchClick}
{@const itemTransition = {
delay: !initialized ? i * ICON_STRIP_TRANSITION_DELAY_MULTIPLIER : 0,
duration: ICON_STRIP_TRANSITION_DURATION,
@@ -4,8 +4,6 @@ export const URL_PARAMS = {
LOAD: 'load',
/** Model to select. */
MODEL: 'model',
/** Start a new chat. */
NEW_CHAT: 'new_chat',
/** Prompt to send on arrival. */
QUERY: 'q'
} as const;
@@ -15,8 +13,6 @@ export const ROUTES = {
CHAT: '#/chat',
/** MCP servers. */
MCP_SERVERS: '#/mcp-servers',
/** New chat — root with new chat query param. */
NEW_CHAT: `?${URL_PARAMS.NEW_CHAT}=true#/`,
/** Search — mobile-only full-page conversation search. */
SEARCH: '#/search',
/** Settings base — for dynamic settings URLs use RouterService. */
+1 -1
View File
@@ -55,7 +55,7 @@ export const ICON_STRIP_TRANSITION_DELAY_MULTIPLIER = 50;
export const MAX_HEIGHT_CODE_BLOCK = '22rem';
export const SIDEBAR_ACTIONS_ITEMS: DesktopIconStripItem[] = [
{ icon: SquarePen, keys: ['shift', 'cmd', 'o'], route: ROUTES.NEW_CHAT, tooltip: 'New chat' },
{ action: 'new-chat', icon: SquarePen, keys: ['shift', 'cmd', 'o'], tooltip: 'New chat' },
{ icon: Search, keys: ['cmd', 'k'], tooltip: 'Search' },
{
activeRouteId: '/mcp-servers',
@@ -1,6 +1,5 @@
import { goto } from '$app/navigation';
import { ROUTES } from '$lib/constants';
import { KeyboardKey } from '$lib/enums';
import { conversationsStore } from '$lib/stores';
interface KeyboardShortcutsCallbacks {
activateSearchMode?: () => void;
@@ -34,7 +33,7 @@ export function useKeyboardShortcuts(callbacks: KeyboardShortcutsCallbacks) {
) {
event.preventDefault();
goto(ROUTES.NEW_CHAT);
conversationsStore.openNewChatTab();
}
if (event.shiftKey && isCmdOrCtrl && event.key === KeyboardKey.E_UPPER) {
+2
View File
@@ -7,6 +7,8 @@ export interface DesktopIconStripItem {
icon: Component;
tooltip: string;
route?: string;
/** Custom action handled by the sidebar, e.g. opening a new-chat tab */
action?: 'new-chat';
activeRouteId?: string;
activeRoutePrefix?: string;
activeUrlIncludes?: string;
+1 -1
View File
@@ -96,7 +96,7 @@
if (targetIdx >= 0 && targetIdx < allConvs.length) {
goto(RouterService.chat(allConvs[targetIdx].id));
} else {
goto(ROUTES.NEW_CHAT);
conversationsStore.openNewChatTab();
}
}
+3 -4
View File
@@ -3,7 +3,6 @@
import { goto } from '$app/navigation';
import { page } from '$app/state';
import { SearchInput, SidebarNavigationSearchResults } from '$lib/components/app';
import { ROUTES } from '$lib/constants';
import { RouterService } from '$lib/services/router.service';
import { chatStore, conversationsStore, deviceStore } from '$lib/stores';
@@ -21,10 +20,10 @@
});
// Search page is intended for mobile; on desktop the sidebar already exposes
// in-place search, so bounce back to a chat.
// in-place search, so bounce back to a new-chat tab.
$effect(() => {
if (browser && !deviceStore.isMobile) {
goto(ROUTES.NEW_CHAT, { replaceState: true });
conversationsStore.openNewChatTab();
}
});
@@ -66,7 +65,7 @@
if (history.length > 1) {
history.back();
} else {
goto(ROUTES.NEW_CHAT);
conversationsStore.openNewChatTab();
}
}
</script>