From 6e89710ec74dea696c9216635132b4f311ed64d9 Mon Sep 17 00:00:00 2001 From: Stijnus <72551117+Stijnus@users.noreply.github.com> Date: Sat, 15 Feb 2025 17:28:17 +0100 Subject: [PATCH] Several UI fixes --- .../shared/components/TabManagement.tsx | 257 ++++++++++++------ .../@settings/tabs/debug/DebugTab.tsx | 153 ++++++----- .../providers/local/LocalProvidersTab.tsx | 68 ++++- .../providers/local/OllamaModelInstaller.tsx | 13 +- .../@settings/tabs/settings/SettingsTab.tsx | 61 +---- app/lib/stores/settings.ts | 2 +- 6 files changed, 345 insertions(+), 209 deletions(-) diff --git a/app/components/@settings/shared/components/TabManagement.tsx b/app/components/@settings/shared/components/TabManagement.tsx index ec6acece..67311c43 100644 --- a/app/components/@settings/shared/components/TabManagement.tsx +++ b/app/components/@settings/shared/components/TabManagement.tsx @@ -1,7 +1,7 @@ import { useState } from 'react'; import { motion } from 'framer-motion'; import { useStore } from '@nanostores/react'; -import { Switch } from '@radix-ui/react-switch'; +import { Switch } from '~/components/ui/Switch'; import { classNames } from '~/utils/classNames'; import { tabConfigurationStore } from '~/lib/stores/settings'; import { TAB_LABELS } from '~/components/@settings/core/constants'; @@ -177,92 +177,193 @@ export const TabManagement = () => { {/* Tab Grid */}
- {filteredTabs.map((tab, index) => ( - - {/* Status Badges */} -
- {DEFAULT_USER_TABS.includes(tab.id) && ( - + {/* Default Section Header */} + {filteredTabs.some((tab) => DEFAULT_USER_TABS.includes(tab.id)) && ( +
+
+ Default Tabs +
+ )} + + {/* Default Tabs */} + {filteredTabs + .filter((tab) => DEFAULT_USER_TABS.includes(tab.id)) + .map((tab, index) => ( + + {/* Status Badges */} +
+ Default - )} - {OPTIONAL_USER_TABS.includes(tab.id) && ( - - Optional - - )} -
+
-
- -
-
-
- - -
-
-
-
-

- {TAB_LABELS[tab.id]} -

- {BETA_TABS.has(tab.id) && } -
-

- {tab.visible ? 'Visible in user mode' : 'Hidden in user mode'} -

+
+ +
+
- handleTabVisibilityChange(tab.id, checked)} - disabled={!DEFAULT_USER_TABS.includes(tab.id) && !OPTIONAL_USER_TABS.includes(tab.id)} - className={classNames( - 'relative inline-flex h-5 w-9 items-center rounded-full', - 'transition-colors duration-200', - tab.visible ? 'bg-purple-500' : 'bg-bolt-elements-background-depth-4', - { - 'opacity-50 cursor-not-allowed': + + +
+
+
+
+

+ {TAB_LABELS[tab.id]} +

+ {BETA_TABS.has(tab.id) && } +
+

+ {tab.visible ? 'Visible in user mode' : 'Hidden in user mode'} +

+
+ { + const isDisabled = + !DEFAULT_USER_TABS.includes(tab.id) && !OPTIONAL_USER_TABS.includes(tab.id); + + if (!isDisabled) { + handleTabVisibilityChange(tab.id, checked); + } + }} + className={classNames('data-[state=checked]:bg-purple-500 ml-4', { + 'opacity-50 pointer-events-none': !DEFAULT_USER_TABS.includes(tab.id) && !OPTIONAL_USER_TABS.includes(tab.id), - }, - )} - /> + })} + /> +
-
+ + + ))} + + {/* Optional Section Header */} + {filteredTabs.some((tab) => OPTIONAL_USER_TABS.includes(tab.id)) && ( +
+
+ Optional Tabs +
+ )} + + {/* Optional Tabs */} + {filteredTabs + .filter((tab) => OPTIONAL_USER_TABS.includes(tab.id)) + .map((tab, index) => ( - - ))} + key={tab.id} + className={classNames( + 'rounded-lg border bg-bolt-elements-background text-bolt-elements-textPrimary', + 'bg-bolt-elements-background-depth-2', + 'hover:bg-bolt-elements-background-depth-3', + 'transition-all duration-200', + 'relative overflow-hidden group', + )} + initial={{ opacity: 0, y: 20 }} + animate={{ opacity: 1, y: 0 }} + transition={{ delay: index * 0.1 }} + whileHover={{ scale: 1.02 }} + > + {/* Status Badges */} +
+ + Optional + +
+ +
+ +
+
+
+ + +
+
+
+
+

+ {TAB_LABELS[tab.id]} +

+ {BETA_TABS.has(tab.id) && } +
+

+ {tab.visible ? 'Visible in user mode' : 'Hidden in user mode'} +

+
+ { + const isDisabled = + !DEFAULT_USER_TABS.includes(tab.id) && !OPTIONAL_USER_TABS.includes(tab.id); + + if (!isDisabled) { + handleTabVisibilityChange(tab.id, checked); + } + }} + className={classNames('data-[state=checked]:bg-purple-500 ml-4', { + 'opacity-50 pointer-events-none': + !DEFAULT_USER_TABS.includes(tab.id) && !OPTIONAL_USER_TABS.includes(tab.id), + })} + /> +
+
+
+ + + + ))}
diff --git a/app/components/@settings/tabs/debug/DebugTab.tsx b/app/components/@settings/tabs/debug/DebugTab.tsx index ae7a8339..cfaeb966 100644 --- a/app/components/@settings/tabs/debug/DebugTab.tsx +++ b/app/components/@settings/tabs/debug/DebugTab.tsx @@ -1270,60 +1270,32 @@ export default function DebugTab() {
{/* Quick Stats Banner */}
- {/* Ollama Service Status Card */} -
+ {/* Errors Card */} +
-
-
Ollama Service
+
+
Errors
-
- - {status.status === 'Running' &&
} - {status.status === 'Not Running' &&
} - {status.status === 'Disabled' &&
} - {status.status} + 0 ? 'text-red-500' : 'text-green-500')} + > + {errorLogs.length}
0 ? 'i-ph:warning text-red-500' : 'i-ph:check-circle text-green-500', + )} /> - {status.message} -
- {ollamaStatus.models && ollamaStatus.models.length > 0 && ( -
-
-
- Installed Models -
- {ollamaStatus.models.map((model) => ( -
-
- {model.name} - - ({Math.round(parseInt(model.size) / 1024 / 1024)}MB, {model.quantization}) - -
- ))} -
- )} -
-
- Last checked: {ollamaStatus.lastChecked.toLocaleTimeString()} + {errorLogs.length > 0 ? 'Errors detected' : 'No errors detected'}
{/* Memory Usage Card */} -
+
Memory Usage
@@ -1360,7 +1332,7 @@ export default function DebugTab() {
{/* Page Load Time Card */} -
+
Page Load Time
@@ -1386,7 +1358,7 @@ export default function DebugTab() {
{/* Network Speed Card */} -
+
Network Speed
@@ -1411,27 +1383,80 @@ export default function DebugTab() {
- {/* Errors Card */} -
-
-
-
Errors
+ {/* Ollama Service Card - Now spans all 4 columns */} +
+
+
+
+
+
Ollama Service
+
{status.message}
+
+
+
+
+
+ + {status.status} + +
+
+
+ {ollamaStatus.lastChecked.toLocaleTimeString()} +
+
-
- 0 ? 'text-red-500' : 'text-green-500')} - > - {errorLogs.length} - -
-
-
0 ? 'i-ph:warning text-red-500' : 'i-ph:check-circle text-green-500', - )} - /> - {errorLogs.length > 0 ? 'Errors detected' : 'No errors detected'} + +
+ {status.status === 'Running' && ollamaStatus.models && ollamaStatus.models.length > 0 ? ( + <> +
+
+
+ Installed Models + + {ollamaStatus.models.length} + +
+
+
+
+ {ollamaStatus.models.map((model) => ( +
+
+
+ {model.name} +
+ + {Math.round(parseInt(model.size) / 1024 / 1024)}MB + +
+ ))} +
+
+ + ) : ( +
+
+
+ {status.message} +
+
+ )}
diff --git a/app/components/@settings/tabs/providers/local/LocalProvidersTab.tsx b/app/components/@settings/tabs/providers/local/LocalProvidersTab.tsx index df986302..70e8d2f5 100644 --- a/app/components/@settings/tabs/providers/local/LocalProvidersTab.tsx +++ b/app/components/@settings/tabs/providers/local/LocalProvidersTab.tsx @@ -471,6 +471,60 @@ export default function LocalProvidersTab() { />
+ {/* URL Configuration Section */} + + {provider.settings.enabled && ( + +
+ + {editingProvider === provider.name ? ( + { + if (e.key === 'Enter') { + handleUpdateBaseUrl(provider, e.currentTarget.value); + } else if (e.key === 'Escape') { + setEditingProvider(null); + } + }} + onBlur={(e) => handleUpdateBaseUrl(provider, e.target.value)} + autoFocus + /> + ) : ( +
setEditingProvider(provider.name)} + className={classNames( + 'w-full px-3 py-2 rounded-lg text-sm cursor-pointer', + 'bg-bolt-elements-background-depth-3 border border-bolt-elements-borderColor', + 'hover:border-purple-500/30 hover:bg-bolt-elements-background-depth-4', + 'transition-all duration-200', + )} + > +
+
+ {provider.settings.baseUrl || OLLAMA_API_URL} +
+
+ )} +
+ + )} + + {/* Ollama Models Section */} {provider.settings.enabled && ( @@ -505,7 +559,19 @@ export default function LocalProvidersTab() {

No models installed yet

-

Install your first model below

+

+ Browse models at{' '} + + ollama.com/library +

+ {' '} + and copy model names to install +

) : ( ollamaModels.map((model) => ( diff --git a/app/components/@settings/tabs/providers/local/OllamaModelInstaller.tsx b/app/components/@settings/tabs/providers/local/OllamaModelInstaller.tsx index b31bb744..18b8655d 100644 --- a/app/components/@settings/tabs/providers/local/OllamaModelInstaller.tsx +++ b/app/components/@settings/tabs/providers/local/OllamaModelInstaller.tsx @@ -429,16 +429,16 @@ export default function OllamaModelInstaller({ onModelInstalled }: OllamaModelIn }} disabled={isInstalling} /> -

+

Browse models at{' '} ollama.com/library -

+
{' '} and copy model names to install

@@ -448,10 +448,11 @@ export default function OllamaModelInstaller({ onModelInstalled }: OllamaModelIn onClick={() => handleInstallModel(modelString)} disabled={!modelString || isInstalling} className={classNames( - 'rounded-xl px-6 py-3', - 'bg-purple-500 text-white', + 'rounded-lg px-4 py-2', + 'bg-purple-500 text-white text-sm', 'hover:bg-purple-600', 'transition-all duration-200', + 'flex items-center gap-2', { 'opacity-50 cursor-not-allowed': !modelString || isInstalling }, )} whileHover={{ scale: 1.02 }} @@ -459,7 +460,7 @@ export default function OllamaModelInstaller({ onModelInstalled }: OllamaModelIn > {isInstalling ? (
-
+
Installing...
) : ( diff --git a/app/components/@settings/tabs/settings/SettingsTab.tsx b/app/components/@settings/tabs/settings/SettingsTab.tsx index 28a6e1ca..a14937a4 100644 --- a/app/components/@settings/tabs/settings/SettingsTab.tsx +++ b/app/components/@settings/tabs/settings/SettingsTab.tsx @@ -3,7 +3,6 @@ import { motion } from 'framer-motion'; import { toast } from 'react-toastify'; import { classNames } from '~/utils/classNames'; import { Switch } from '~/components/ui/Switch'; -import { themeStore, kTheme } from '~/lib/stores/theme'; import type { UserProfile } from '~/components/@settings/core/types'; import { useStore } from '@nanostores/react'; import { shortcutsStore } from '~/lib/stores/settings'; @@ -41,7 +40,6 @@ export default function SettingsTab() { return saved ? JSON.parse(saved) : { - theme: 'system', notifications: true, language: 'en', timezone: Intl.DateTimeFormat().resolvedOptions().timeZone, @@ -52,22 +50,6 @@ export default function SettingsTab() { setCurrentTimezone(Intl.DateTimeFormat().resolvedOptions().timeZone); }, []); - // Apply theme when settings changes - useEffect(() => { - if (settings.theme === 'system') { - // Remove theme override - localStorage.removeItem(kTheme); - - const prefersDark = window.matchMedia('(prefers-color-scheme: dark)').matches; - document.querySelector('html')?.setAttribute('data-theme', prefersDark ? 'dark' : 'light'); - themeStore.set(prefersDark ? 'dark' : 'light'); - } else { - themeStore.set(settings.theme); - localStorage.setItem(kTheme, settings.theme); - document.querySelector('html')?.setAttribute('data-theme', settings.theme); - } - }, [settings.theme]); - // Save settings automatically when they change useEffect(() => { try { @@ -77,7 +59,6 @@ export default function SettingsTab() { // Merge with new settings const updatedProfile = { ...existingProfile, - theme: settings.theme, notifications: settings.notifications, language: settings.language, timezone: settings.timezone, @@ -93,7 +74,7 @@ export default function SettingsTab() { return (
- {/* Theme & Language */} + {/* Language & Notifications */}
- Appearance -
- -
-
-
- -
-
- {(['light', 'dark', 'system'] as const).map((theme) => ( - - ))} -
+ Preferences
diff --git a/app/lib/stores/settings.ts b/app/lib/stores/settings.ts index f8e36f65..112efdca 100644 --- a/app/lib/stores/settings.ts +++ b/app/lib/stores/settings.ts @@ -179,7 +179,7 @@ const getInitialSettings = () => { contextOptimization: getStoredBoolean(SETTINGS_KEYS.CONTEXT_OPTIMIZATION, true), eventLogs: getStoredBoolean(SETTINGS_KEYS.EVENT_LOGS, true), localModels: getStoredBoolean(SETTINGS_KEYS.LOCAL_MODELS, true), - promptId: isBrowser ? localStorage.getItem(SETTINGS_KEYS.PROMPT_ID) || 'optimized' : 'optimized', + promptId: isBrowser ? localStorage.getItem(SETTINGS_KEYS.PROMPT_ID) || 'default' : 'default', developerMode: getStoredBoolean(SETTINGS_KEYS.DEVELOPER_MODE, false), }; };