Files
llama.cpp/tools/ui/src/lib/components/app/settings/SettingsChatMobileHeader.svelte
T
Aleksander Grygier 539f24529b ui: Move Settings and MCP Servers routes to dialog-based views (#27744)
* ui : open MCP servers in a dialog from the chat form

Replace the MCP servers submenu with a single "MCP Servers" item that opens
a new DialogMcpServers dialog instead of navigating to the /mcp-servers route.

Assisted-by: pi

* ui : browse MCP resources from the server card

Make the Resources capability badge clickable so it opens the MCP resources
browser dialog, and drop the page-only chrome from SettingsMcpServers.

Assisted-by: pi

* ui : remove mcp-servers route and sidebar entry

MCP servers are now managed in a dialog, so drop the dedicated route and the
sidebar icon that navigated to it.

Assisted-by: pi

* ui : remove unused MCP servers submenu component

The submenu was replaced by the MCP servers dialog, so delete the component
and its export.

Assisted-by: pi

* feat(ui): add DialogSettingsChat dialog

* refactor(ui): switch SettingsChat to in-app section navigation

* feat(ui): open settings as dialog from sidebar

* refactor(ui): remove settings route and URL-based settings navigation

* fix(ui): adjust MCP dialogs for new base sizing

* chore: Formatting & linting
2026-08-26 21:07:24 +02:00

62 lines
1.9 KiB
Svelte

<script lang="ts">
import { ScrollCarousel } from '$lib/components/app';
import { ICON_CLASS_DEFAULT, UI_DATA_ATTRS } from '$lib/constants';
import { BooleanString } from '$lib/enums';
import { useScrollCarousel } from '$lib/hooks/use-scroll-carousel.svelte';
import type { SettingsSection, SettingsSectionTitle } from '$lib/types';
import { onMount, tick } from 'svelte';
interface Props {
sections: SettingsSection[];
isActive: (section: SettingsSection) => boolean;
onSectionChange?: (section: SettingsSectionTitle) => void;
}
let { isActive, onSectionChange, sections }: Props = $props();
const carousel = useScrollCarousel();
onMount(async () => {
await tick();
if (carousel.scrollContainer) {
const activeTab = carousel.scrollContainer.querySelector(
`[${UI_DATA_ATTRS.ACTIVE}="${BooleanString.TRUE}"]`
);
if (activeTab instanceof HTMLElement) {
carousel.scrollToCenter(activeTab);
}
}
});
export function updateCarousel() {
setTimeout(carousel.updateScrollButtons, 100);
}
</script>
<div class="flex flex-col bg-background md:hidden sticky top-13 z-50">
<div class="border-b border-border/30">
<ScrollCarousel alwaysShowArrows {carousel} containerClass="py-2" innerClass="gap-2">
{#each sections as section (section.title)}
<button
class="flex cursor-pointer items-center gap-2 rounded-lg px-3 py-2 text-sm whitespace-nowrap transition-colors first:ml-4 last:mr-4 hover:bg-accent {isActive(
section
)
? 'bg-accent text-accent-foreground'
: 'text-muted-foreground'}"
{...{ [UI_DATA_ATTRS.ACTIVE]: isActive(section) }}
onclick={(e: MouseEvent) => {
onSectionChange?.(section.title);
carousel.scrollToCenter(e.currentTarget as HTMLElement);
}}
>
<section.icon class="{ICON_CLASS_DEFAULT} flex-shrink-0" />
<span>{section.title}</span>
</button>
{/each}
</ScrollCarousel>
</div>
</div>