]> git.djapps.eu Git - pkg/ggml/sources/llama.cpp/commitdiff
feat: Improve mobile UI for Settings Dialog (#16084)
authorAleksander Grygier <redacted>
Fri, 19 Sep 2025 07:52:27 +0000 (09:52 +0200)
committerGitHub <redacted>
Fri, 19 Sep 2025 07:52:27 +0000 (09:52 +0200)
* feat: Improve mobile UI for Settings Dialog

* chore: update webui build output

* fix: Linting errors

* chore: update webui build output

tools/server/public/index.html.gz
tools/server/webui/scripts/install-git-hooks.sh
tools/server/webui/src/app.css
tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettingsDialog.svelte
tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettingsFields.svelte [new file with mode: 0644]
tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettingsFooter.svelte
tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettingsSection.svelte [deleted file]
tools/server/webui/src/lib/components/app/index.ts

index 909fa1cceb81d4030c5a11b475304ba206a8d95b..c6d8258d7f81499c0317e6a32c3f89227ac875c4 100644 (file)
Binary files a/tools/server/public/index.html.gz and b/tools/server/public/index.html.gz differ
index 740075e2819b40a8302ac208862489e3ecd7b855..a2a3ca76f53e1cb1f59a50224c956a669313a59c 100755 (executable)
@@ -1,7 +1,7 @@
 #!/bin/bash
 
 # Script to install pre-commit and post-commit hooks for webui
-# Pre-commit: formats code and builds, stashes unstaged changes
+# Pre-commit: formats, lints, checks, and builds code, stashes unstaged changes
 # Post-commit: automatically unstashes changes
 
 REPO_ROOT=$(git rev-parse --show-toplevel)
@@ -44,6 +44,18 @@ if git diff --cached --name-only | grep -q "^tools/server/webui/"; then
         exit 1
     fi
 
+    # Run the lint command
+    npm run lint
+    
+    # Check if lint command succeeded
+    if [ $? -ne 0 ]; then
+        echo "Error: npm run lint failed"
+        if [ $STASH_CREATED -eq 0 ]; then
+            echo "You can restore your unstaged changes with: git stash pop"
+        fi
+        exit 1
+    fi
+
     # Run the check command
     npm run check
     
@@ -112,7 +124,7 @@ if [ $? -eq 0 ]; then
     echo "   Post-commit: $POST_COMMIT_HOOK"
     echo ""
     echo "The hooks will automatically:"
-    echo "  • Format and build webui code before commits"
+    echo "  • Format, lint, check, and build webui code before commits"
     echo "  • Stash unstaged changes during the process"
     echo "  • Restore your unstaged changes after the commit"
     echo ""
index d05a422f026e4e10b068d0b09b8be5a730a3c93f..a9ac80ab9cf002166942dfe014d33eb2aa315824 100644 (file)
                @apply bg-background text-foreground;
        }
 }
+
+@layer utilities {
+       .scrollbar-hide {
+               /* Hide scrollbar for Chrome, Safari and Opera */
+               &::-webkit-scrollbar {
+                       display: none;
+               }
+               /* Hide scrollbar for IE, Edge and Firefox */
+               -ms-overflow-style: none;
+               scrollbar-width: none;
+       }
+}
index 6752f066368da67aa63055768cff8fb4be55ea64..0d9cca0589e7faf190487d6effafff439e693c69 100644 (file)
@@ -1,15 +1,20 @@
 <script lang="ts">
-       import { Settings, Funnel, AlertTriangle, Brain, Cog, Monitor, Sun, Moon } from '@lucide/svelte';
-       import { ChatSettingsFooter, ChatSettingsSection } from '$lib/components/app';
-       import { Checkbox } from '$lib/components/ui/checkbox';
+       import {
+               Settings,
+               Funnel,
+               AlertTriangle,
+               Brain,
+               Cog,
+               Monitor,
+               Sun,
+               Moon,
+               ChevronLeft,
+               ChevronRight
+       } from '@lucide/svelte';
+       import { ChatSettingsFooter, ChatSettingsFields } from '$lib/components/app';
        import * as Dialog from '$lib/components/ui/dialog';
-       import { Input } from '$lib/components/ui/input';
-       import Label from '$lib/components/ui/label/label.svelte';
        import { ScrollArea } from '$lib/components/ui/scroll-area';
-       import * as Select from '$lib/components/ui/select';
-       import { Textarea } from '$lib/components/ui/textarea';
-       import { SETTING_CONFIG_DEFAULT, SETTING_CONFIG_INFO } from '$lib/constants/settings-config';
-       import { supportsVision } from '$lib/stores/server.svelte';
+       import { SETTING_CONFIG_DEFAULT } from '$lib/constants/settings-config';
        import { config, updateMultipleConfig, resetConfig } from '$lib/stores/settings.svelte';
        import { setMode } from 'mode-watcher';
        import type { Component } from 'svelte';
        let localConfig: SettingsConfigType = $state({ ...config() });
        let originalTheme: string = $state('');
 
+       let canScrollLeft = $state(false);
+       let canScrollRight = $state(false);
+       let scrollContainer: HTMLDivElement | undefined = $state();
+
        function handleThemeChange(newTheme: string) {
                localConfig.theme = newTheme;
 
                setMode(newTheme as 'light' | 'dark' | 'system');
        }
 
+       function handleConfigChange(key: string, value: string | boolean) {
+               localConfig[key] = value;
+       }
+
        function handleClose() {
                if (localConfig.theme !== originalTheme) {
                        setMode(originalTheme as 'light' | 'dark' | 'system');
                onOpenChange?.(false);
        }
 
+       function scrollToCenter(element: HTMLElement) {
+               if (!scrollContainer) return;
+
+               const containerRect = scrollContainer.getBoundingClientRect();
+               const elementRect = element.getBoundingClientRect();
+
+               const elementCenter = elementRect.left + elementRect.width / 2;
+               const containerCenter = containerRect.left + containerRect.width / 2;
+               const scrollOffset = elementCenter - containerCenter;
+
+               scrollContainer.scrollBy({ left: scrollOffset, behavior: 'smooth' });
+       }
+
+       function scrollLeft() {
+               if (!scrollContainer) return;
+
+               scrollContainer.scrollBy({ left: -250, behavior: 'smooth' });
+       }
+
+       function scrollRight() {
+               if (!scrollContainer) return;
+
+               scrollContainer.scrollBy({ left: 250, behavior: 'smooth' });
+       }
+
+       function updateScrollButtons() {
+               if (!scrollContainer) return;
+
+               const { scrollLeft, scrollWidth, clientWidth } = scrollContainer;
+               canScrollLeft = scrollLeft > 0;
+               canScrollRight = scrollLeft < scrollWidth - clientWidth - 1; // -1 for rounding
+       }
+
        $effect(() => {
                if (open) {
                        localConfig = { ...config() };
                        originalTheme = config().theme as string;
+
+                       setTimeout(updateScrollButtons, 100);
+               }
+       });
+
+       $effect(() => {
+               if (scrollContainer) {
+                       updateScrollButtons();
                }
        });
 </script>
 
 <Dialog.Root {open} onOpenChange={handleClose}>
-       <Dialog.Content class="flex h-[64vh] flex-col gap-0 p-0" style="max-width: 48rem;">
-               <div class="flex flex-1 overflow-hidden">
-                       <div class="w-64 border-r border-border/30 p-6">
+       <Dialog.Content
+               class="z-999999 flex h-[100vh] flex-col gap-0 rounded-none p-0 md:h-[64vh] md:rounded-lg"
+               style="max-width: 48rem;"
+       >
+               <div class="flex flex-1 flex-col overflow-hidden md:flex-row">
+                       <!-- Desktop Sidebar -->
+                       <div class="hidden w-64 border-r border-border/30 p-6 md:block">
                                <nav class="space-y-1 py-2">
                                        <Dialog.Title class="mb-6 flex items-center gap-2">Settings</Dialog.Title>
 
                                </nav>
                        </div>
 
-                       <ScrollArea class="flex-1">
-                               <div class="space-y-6 p-6">
-                                       <ChatSettingsSection title={currentSection.title} Icon={currentSection.icon}>
-                                               {#each currentSection.fields as field (field.key)}
-                                                       <div class="space-y-2">
-                                                               {#if field.type === 'input'}
-                                                                       <Label for={field.key} class="block text-sm font-medium">
-                                                                               {field.label}
-                                                                       </Label>
-
-                                                                       <Input
-                                                                               id={field.key}
-                                                                               value={String(localConfig[field.key] || '')}
-                                                                               onchange={(e) => (localConfig[field.key] = e.currentTarget.value)}
-                                                                               placeholder={`Default: ${SETTING_CONFIG_DEFAULT[field.key] || 'none'}`}
-                                                                               class="max-w-md"
-                                                                       />
-                                                                       {#if field.help || SETTING_CONFIG_INFO[field.key]}
-                                                                               <p class="mt-1 text-xs text-muted-foreground">
-                                                                                       {field.help || SETTING_CONFIG_INFO[field.key]}
-                                                                               </p>
-                                                                       {/if}
-                                                               {:else if field.type === 'textarea'}
-                                                                       <Label for={field.key} class="block text-sm font-medium">
-                                                                               {field.label}
-                                                                       </Label>
-
-                                                                       <Textarea
-                                                                               id={field.key}
-                                                                               value={String(localConfig[field.key] || '')}
-                                                                               onchange={(e) => (localConfig[field.key] = e.currentTarget.value)}
-                                                                               placeholder={`Default: ${SETTING_CONFIG_DEFAULT[field.key] || 'none'}`}
-                                                                               class="min-h-[100px] max-w-2xl"
-                                                                       />
-                                                                       {#if field.help || SETTING_CONFIG_INFO[field.key]}
-                                                                               <p class="mt-1 text-xs text-muted-foreground">
-                                                                                       {field.help || SETTING_CONFIG_INFO[field.key]}
-                                                                               </p>
-                                                                       {/if}
-                                                               {:else if field.type === 'select'}
-                                                                       {@const selectedOption = field.options?.find(
-                                                                               (opt: { value: string; label: string; icon?: Component }) =>
-                                                                                       opt.value === localConfig[field.key]
-                                                                       )}
-
-                                                                       <Label for={field.key} class="block text-sm font-medium">
-                                                                               {field.label}
-                                                                       </Label>
-
-                                                                       <Select.Root
-                                                                               type="single"
-                                                                               value={localConfig[field.key]}
-                                                                               onValueChange={(value) => {
-                                                                                       if (field.key === 'theme' && value) {
-                                                                                               handleThemeChange(value);
-                                                                                       } else {
-                                                                                               localConfig[field.key] = value;
-                                                                                       }
+                       <!-- Mobile Header with Horizontal Scrollable Menu -->
+                       <div class="flex flex-col md:hidden">
+                               <div class="border-b border-border/30 py-4">
+                                       <Dialog.Title class="mb-6 flex items-center gap-2 px-4">Settings</Dialog.Title>
+
+                                       <!-- Horizontal Scrollable Category Menu with Navigation -->
+                                       <div class="relative flex items-center" style="scroll-padding: 1rem;">
+                                               <button
+                                                       class="absolute left-2 z-10 flex h-6 w-6 items-center justify-center rounded-full bg-muted shadow-md backdrop-blur-sm transition-opacity hover:bg-accent {canScrollLeft
+                                                               ? 'opacity-100'
+                                                               : 'pointer-events-none opacity-0'}"
+                                                       onclick={scrollLeft}
+                                                       aria-label="Scroll left"
+                                               >
+                                                       <ChevronLeft class="h-4 w-4" />
+                                               </button>
+
+                                               <div
+                                                       class="scrollbar-hide overflow-x-auto py-2"
+                                                       bind:this={scrollContainer}
+                                                       onscroll={updateScrollButtons}
+                                               >
+                                                       <div class="flex min-w-max gap-2">
+                                                               {#each settingSections 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 {activeSection ===
+                                                                               section.title
+                                                                                       ? 'bg-accent text-accent-foreground'
+                                                                                       : 'text-muted-foreground'}"
+                                                                               onclick={(e: MouseEvent) => {
+                                                                                       activeSection = section.title;
+                                                                                       scrollToCenter(e.currentTarget as HTMLElement);
                                                                                }}
                                                                        >
-                                                                               <Select.Trigger class="max-w-md">
-                                                                                       <div class="flex items-center gap-2">
-                                                                                               {#if selectedOption?.icon}
-                                                                                                       {@const IconComponent = selectedOption.icon}
-                                                                                                       <IconComponent class="h-4 w-4" />
-                                                                                               {/if}
-
-                                                                                               {selectedOption?.label || `Select ${field.label.toLowerCase()}`}
-                                                                                       </div>
-                                                                               </Select.Trigger>
-                                                                               <Select.Content>
-                                                                                       {#if field.options}
-                                                                                               {#each field.options as option (option.value)}
-                                                                                                       <Select.Item value={option.value} label={option.label}>
-                                                                                                               <div class="flex items-center gap-2">
-                                                                                                                       {#if option.icon}
-                                                                                                                               {@const IconComponent = option.icon}
-                                                                                                                               <IconComponent class="h-4 w-4" />
-                                                                                                                       {/if}
-                                                                                                                       {option.label}
-                                                                                                               </div>
-                                                                                                       </Select.Item>
-                                                                                               {/each}
-                                                                                       {/if}
-                                                                               </Select.Content>
-                                                                       </Select.Root>
-                                                                       {#if field.help || SETTING_CONFIG_INFO[field.key]}
-                                                                               <p class="mt-1 text-xs text-muted-foreground">
-                                                                                       {field.help || SETTING_CONFIG_INFO[field.key]}
-                                                                               </p>
-                                                                       {/if}
-                                                               {:else if field.type === 'checkbox'}
-                                                                       {@const isDisabled = field.key === 'pdfAsImage' && !supportsVision()}
-                                                                       <div class="flex items-start space-x-3">
-                                                                               <Checkbox
-                                                                                       id={field.key}
-                                                                                       checked={Boolean(localConfig[field.key])}
-                                                                                       disabled={isDisabled}
-                                                                                       onCheckedChange={(checked) => (localConfig[field.key] = checked)}
-                                                                                       class="mt-1"
-                                                                               />
-
-                                                                               <div class="space-y-1">
-                                                                                       <label
-                                                                                               for={field.key}
-                                                                                               class="cursor-pointer text-sm leading-none font-medium {isDisabled
-                                                                                                       ? 'text-muted-foreground'
-                                                                                                       : ''}"
-                                                                                       >
-                                                                                               {field.label}
-                                                                                       </label>
-
-                                                                                       {#if field.help || SETTING_CONFIG_INFO[field.key]}
-                                                                                               <p class="text-xs text-muted-foreground">
-                                                                                                       {field.help || SETTING_CONFIG_INFO[field.key]}
-                                                                                               </p>
-                                                                                       {:else if field.key === 'pdfAsImage' && !supportsVision()}
-                                                                                               <p class="text-xs text-muted-foreground">
-                                                                                                       PDF-to-image processing requires a vision-capable model. PDFs will be
-                                                                                                       processed as text.
-                                                                                               </p>
-                                                                                       {/if}
-                                                                               </div>
-                                                                       </div>
-                                                               {/if}
+                                                                               <section.icon class="h-4 w-4 flex-shrink-0" />
+                                                                               <span>{section.title}</span>
+                                                                       </button>
+                                                               {/each}
                                                        </div>
-                                               {/each}
-                                       </ChatSettingsSection>
+                                               </div>
+
+                                               <button
+                                                       class="absolute right-2 z-10 flex h-6 w-6 items-center justify-center rounded-full bg-muted shadow-md backdrop-blur-sm transition-opacity hover:bg-accent {canScrollRight
+                                                               ? 'opacity-100'
+                                                               : 'pointer-events-none opacity-0'}"
+                                                       onclick={scrollRight}
+                                                       aria-label="Scroll right"
+                                               >
+                                                       <ChevronRight class="h-4 w-4" />
+                                               </button>
+                                       </div>
+                               </div>
+                       </div>
+
+                       <ScrollArea class="max-h-[calc(100vh-13.5rem)] flex-1">
+                               <div class="space-y-6 p-4 md:p-6">
+                                       <div>
+                                               <div class="mb-6 flex hidden items-center gap-2 border-b border-border/30 pb-6 md:flex">
+                                                       <currentSection.icon class="h-5 w-5" />
+
+                                                       <h3 class="text-lg font-semibold">{currentSection.title}</h3>
+                                               </div>
+
+                                               <div class="space-y-6">
+                                                       <ChatSettingsFields
+                                                               fields={currentSection.fields}
+                                                               {localConfig}
+                                                               onConfigChange={handleConfigChange}
+                                                               onThemeChange={handleThemeChange}
+                                                               isMobile={false}
+                                                       />
+                                               </div>
+                                       </div>
 
                                        <div class="mt-8 border-t pt-6">
                                                <p class="text-xs text-muted-foreground">
                        </ScrollArea>
                </div>
 
-               <ChatSettingsFooter onClose={handleClose} onReset={handleReset} onSave={handleSave} />
+               <ChatSettingsFooter onReset={handleReset} onSave={handleSave} />
        </Dialog.Content>
 </Dialog.Root>
diff --git a/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettingsFields.svelte b/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettingsFields.svelte
new file mode 100644 (file)
index 0000000..c1eeed3
--- /dev/null
@@ -0,0 +1,145 @@
+<script lang="ts">
+       import { Checkbox } from '$lib/components/ui/checkbox';
+       import { Input } from '$lib/components/ui/input';
+       import Label from '$lib/components/ui/label/label.svelte';
+       import * as Select from '$lib/components/ui/select';
+       import { Textarea } from '$lib/components/ui/textarea';
+       import { SETTING_CONFIG_DEFAULT, SETTING_CONFIG_INFO } from '$lib/constants/settings-config';
+       import { supportsVision } from '$lib/stores/server.svelte';
+       import type { Component } from 'svelte';
+
+       interface Props {
+               fields: SettingsFieldConfig[];
+               localConfig: SettingsConfigType;
+               onConfigChange: (key: string, value: string | boolean) => void;
+               onThemeChange?: (theme: string) => void;
+               isMobile?: boolean;
+       }
+
+       let { fields, localConfig, onConfigChange, onThemeChange, isMobile = false }: Props = $props();
+</script>
+
+{#each fields as field (field.key)}
+       <div class="space-y-2">
+               {#if field.type === 'input'}
+                       <Label for={field.key} class="block text-sm font-medium">
+                               {field.label}
+                       </Label>
+
+                       <Input
+                               id={field.key}
+                               value={String(localConfig[field.key] || '')}
+                               onchange={(e) => onConfigChange(field.key, e.currentTarget.value)}
+                               placeholder={`Default: ${SETTING_CONFIG_DEFAULT[field.key] || 'none'}`}
+                               class={isMobile ? 'w-full' : 'max-w-md'}
+                       />
+                       {#if field.help || SETTING_CONFIG_INFO[field.key]}
+                               <p class="mt-1 text-xs text-muted-foreground">
+                                       {field.help || SETTING_CONFIG_INFO[field.key]}
+                               </p>
+                       {/if}
+               {:else if field.type === 'textarea'}
+                       <Label for={field.key} class="block text-sm font-medium">
+                               {field.label}
+                       </Label>
+
+                       <Textarea
+                               id={field.key}
+                               value={String(localConfig[field.key] || '')}
+                               onchange={(e) => onConfigChange(field.key, e.currentTarget.value)}
+                               placeholder={`Default: ${SETTING_CONFIG_DEFAULT[field.key] || 'none'}`}
+                               class={isMobile ? 'min-h-[100px] w-full' : 'min-h-[100px] max-w-2xl'}
+                       />
+                       {#if field.help || SETTING_CONFIG_INFO[field.key]}
+                               <p class="mt-1 text-xs text-muted-foreground">
+                                       {field.help || SETTING_CONFIG_INFO[field.key]}
+                               </p>
+                       {/if}
+               {:else if field.type === 'select'}
+                       {@const selectedOption = field.options?.find(
+                               (opt: { value: string; label: string; icon?: Component }) =>
+                                       opt.value === localConfig[field.key]
+                       )}
+
+                       <Label for={field.key} class="block text-sm font-medium">
+                               {field.label}
+                       </Label>
+
+                       <Select.Root
+                               type="single"
+                               value={localConfig[field.key]}
+                               onValueChange={(value) => {
+                                       if (field.key === 'theme' && value && onThemeChange) {
+                                               onThemeChange(value);
+                                       } else {
+                                               onConfigChange(field.key, value);
+                                       }
+                               }}
+                       >
+                               <Select.Trigger class={isMobile ? 'w-full' : 'max-w-md'}>
+                                       <div class="flex items-center gap-2">
+                                               {#if selectedOption?.icon}
+                                                       {@const IconComponent = selectedOption.icon}
+                                                       <IconComponent class="h-4 w-4" />
+                                               {/if}
+
+                                               {selectedOption?.label || `Select ${field.label.toLowerCase()}`}
+                                       </div>
+                               </Select.Trigger>
+                               <Select.Content>
+                                       {#if field.options}
+                                               {#each field.options as option (option.value)}
+                                                       <Select.Item value={option.value} label={option.label}>
+                                                               <div class="flex items-center gap-2">
+                                                                       {#if option.icon}
+                                                                               {@const IconComponent = option.icon}
+                                                                               <IconComponent class="h-4 w-4" />
+                                                                       {/if}
+                                                                       {option.label}
+                                                               </div>
+                                                       </Select.Item>
+                                               {/each}
+                                       {/if}
+                               </Select.Content>
+                       </Select.Root>
+                       {#if field.help || SETTING_CONFIG_INFO[field.key]}
+                               <p class="mt-1 text-xs text-muted-foreground">
+                                       {field.help || SETTING_CONFIG_INFO[field.key]}
+                               </p>
+                       {/if}
+               {:else if field.type === 'checkbox'}
+                       {@const isDisabled = field.key === 'pdfAsImage' && !supportsVision()}
+                       <div class="flex items-start space-x-3">
+                               <Checkbox
+                                       id={field.key}
+                                       checked={Boolean(localConfig[field.key])}
+                                       disabled={isDisabled}
+                                       onCheckedChange={(checked) => onConfigChange(field.key, checked)}
+                                       class="mt-1"
+                               />
+
+                               <div class="space-y-1">
+                                       <label
+                                               for={field.key}
+                                               class="cursor-pointer text-sm leading-none font-medium {isDisabled
+                                                       ? 'text-muted-foreground'
+                                                       : ''}"
+                                       >
+                                               {field.label}
+                                       </label>
+
+                                       {#if field.help || SETTING_CONFIG_INFO[field.key]}
+                                               <p class="text-xs text-muted-foreground">
+                                                       {field.help || SETTING_CONFIG_INFO[field.key]}
+                                               </p>
+                                       {:else if field.key === 'pdfAsImage' && !supportsVision()}
+                                               <p class="text-xs text-muted-foreground">
+                                                       PDF-to-image processing requires a vision-capable model. PDFs will be processed as
+                                                       text.
+                                               </p>
+                                       {/if}
+                               </div>
+                       </div>
+               {/if}
+       </div>
+{/each}
index 980d2df7f4b31a9d2f0086ce979bba76b895e8db..e862cdb2bc68a051087ba0a1f30d097b23ac02bd 100644 (file)
@@ -2,16 +2,11 @@
        import { Button } from '$lib/components/ui/button';
 
        interface Props {
-               onClose?: () => void;
                onReset?: () => void;
                onSave?: () => void;
        }
 
-       let { onClose, onReset, onSave }: Props = $props();
-
-       function handleClose() {
-               onClose?.();
-       }
+       let { onReset, onSave }: Props = $props();
 
        function handleReset() {
                onReset?.();
@@ -25,9 +20,5 @@
 <div class="flex justify-between border-t border-border/30 p-6">
        <Button variant="outline" onclick={handleReset}>Reset to default</Button>
 
-       <div class="flex gap-2">
-               <Button variant="outline" onclick={handleClose}>Close</Button>
-
-               <Button onclick={handleSave}>Save</Button>
-       </div>
+       <Button onclick={handleSave}>Save settings</Button>
 </div>
diff --git a/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettingsSection.svelte b/tools/server/webui/src/lib/components/app/chat/ChatSettings/ChatSettingsSection.svelte
deleted file mode 100644 (file)
index c4abb02..0000000
+++ /dev/null
@@ -1,23 +0,0 @@
-<script lang="ts">
-       import type { Component, Snippet } from 'svelte';
-
-       interface Props {
-               children: Snippet;
-               title: string;
-               Icon: Component;
-       }
-
-       let { children, title, Icon }: Props = $props();
-</script>
-
-<div>
-       <div class="mb-6 flex items-center gap-2 border-b border-border/30 pb-6">
-               <Icon class="h-5 w-5" />
-
-               <h3 class="text-lg font-semibold">{title}</h3>
-       </div>
-
-       <div class="space-y-6">
-               {@render children()}
-       </div>
-</div>
index b9d7eb7cfacdae58c5c9a27b3789ce3d97afc0c2..2f559bd623a519801a0f488cd60fa38ccbd405f5 100644 (file)
@@ -22,8 +22,8 @@ export { default as ChatScreenHeader } from './chat/ChatScreen/ChatScreenHeader.
 export { default as ChatScreen } from './chat/ChatScreen/ChatScreen.svelte';
 
 export { default as ChatSettingsDialog } from './chat/ChatSettings/ChatSettingsDialog.svelte';
-export { default as ChatSettingsSection } from './chat/ChatSettings/ChatSettingsSection.svelte';
 export { default as ChatSettingsFooter } from './chat/ChatSettings/ChatSettingsFooter.svelte';
+export { default as ChatSettingsFields } from './chat/ChatSettings/ChatSettingsFields.svelte';
 
 export { default as ChatSidebar } from './chat/ChatSidebar/ChatSidebar.svelte';
 export { default as ChatSidebarConversationItem } from './chat/ChatSidebar/ChatSidebarConversationItem.svelte';