From 8ab1b3af36bf3179625c2b974824cf67c6a46dcb Mon Sep 17 00:00:00 2001 From: Felix <24791380+vcfgv@users.noreply.github.com> Date: Thu, 12 Feb 2026 11:11:28 +0800 Subject: [PATCH] misc: provider icons, tooltip in chat toolbar, conditionally display the "Open Skills Folder" button and update "Documentation" to "Website" in settings (#60) --- src/App.tsx | 41 ++++----- src/assets/providers/anthropic.svg | 1 + src/assets/providers/custom.svg | 1 + src/assets/providers/google.svg | 1 + src/assets/providers/index.ts | 19 +++++ src/assets/providers/moonshot.svg | 1 + src/assets/providers/ollama.svg | 1 + src/assets/providers/openai.svg | 1 + src/assets/providers/openrouter.svg | 1 + src/assets/providers/siliconflow.svg | 1 + src/components/settings/ProvidersSettings.tsx | 20 ++++- src/components/ui/tooltip.tsx | 28 +++++++ src/i18n/locales/en/chat.json | 8 +- src/i18n/locales/en/settings.json | 2 +- src/i18n/locales/en/skills.json | 3 +- src/i18n/locales/ja/chat.json | 8 +- src/i18n/locales/ja/settings.json | 2 +- src/i18n/locales/ja/skills.json | 3 +- src/i18n/locales/zh/chat.json | 8 +- src/i18n/locales/zh/settings.json | 2 +- src/i18n/locales/zh/skills.json | 3 +- src/lib/providers.ts | 12 +++ src/pages/Chat/ChatInput.tsx | 15 +--- src/pages/Chat/ChatToolbar.tsx | 83 ++++++++++++------- src/pages/Setup/index.tsx | 4 +- src/pages/Skills/index.tsx | 19 +++-- 26 files changed, 206 insertions(+), 82 deletions(-) create mode 100644 src/assets/providers/anthropic.svg create mode 100644 src/assets/providers/custom.svg create mode 100644 src/assets/providers/google.svg create mode 100644 src/assets/providers/index.ts create mode 100644 src/assets/providers/moonshot.svg create mode 100644 src/assets/providers/ollama.svg create mode 100644 src/assets/providers/openai.svg create mode 100644 src/assets/providers/openrouter.svg create mode 100644 src/assets/providers/siliconflow.svg create mode 100644 src/components/ui/tooltip.tsx diff --git a/src/App.tsx b/src/App.tsx index 299e774c0..cb6a426fb 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -8,6 +8,7 @@ import type { ErrorInfo, ReactNode } from 'react'; import { Toaster } from 'sonner'; import i18n from './i18n'; import { MainLayout } from './components/layout/MainLayout'; +import { TooltipProvider } from '@/components/ui/tooltip'; import { Dashboard } from './pages/Dashboard'; import { Chat } from './pages/Chat'; import { Channels } from './pages/Channels'; @@ -145,27 +146,29 @@ function App() { return ( - - {/* Setup wizard (shown on first launch) */} - } /> + + + {/* Setup wizard (shown on first launch) */} + } /> - {/* Main application routes */} - }> - } /> - } /> - } /> - } /> - } /> - } /> - - + {/* Main application routes */} + }> + } /> + } /> + } /> + } /> + } /> + } /> + + - {/* Global toast notifications */} - + {/* Global toast notifications */} + + ); } diff --git a/src/assets/providers/anthropic.svg b/src/assets/providers/anthropic.svg new file mode 100644 index 000000000..88dc7450b --- /dev/null +++ b/src/assets/providers/anthropic.svg @@ -0,0 +1 @@ +Anthropic \ No newline at end of file diff --git a/src/assets/providers/custom.svg b/src/assets/providers/custom.svg new file mode 100644 index 000000000..f39acfc35 --- /dev/null +++ b/src/assets/providers/custom.svg @@ -0,0 +1 @@ +Custom diff --git a/src/assets/providers/google.svg b/src/assets/providers/google.svg new file mode 100644 index 000000000..80cd65a6b --- /dev/null +++ b/src/assets/providers/google.svg @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/src/assets/providers/index.ts b/src/assets/providers/index.ts new file mode 100644 index 000000000..416be1ba0 --- /dev/null +++ b/src/assets/providers/index.ts @@ -0,0 +1,19 @@ +import anthropic from './anthropic.svg'; +import openai from './openai.svg'; +import google from './google.svg'; +import openrouter from './openrouter.svg'; +import moonshot from './moonshot.svg'; +import siliconflow from './siliconflow.svg'; +import ollama from './ollama.svg'; +import custom from './custom.svg'; + +export const providerIcons: Record = { + anthropic, + openai, + google, + openrouter, + moonshot, + siliconflow, + ollama, + custom, +}; diff --git a/src/assets/providers/moonshot.svg b/src/assets/providers/moonshot.svg new file mode 100644 index 000000000..8e682fcff --- /dev/null +++ b/src/assets/providers/moonshot.svg @@ -0,0 +1 @@ +MoonshotAI \ No newline at end of file diff --git a/src/assets/providers/ollama.svg b/src/assets/providers/ollama.svg new file mode 100644 index 000000000..432f73e73 --- /dev/null +++ b/src/assets/providers/ollama.svg @@ -0,0 +1 @@ +Ollama \ No newline at end of file diff --git a/src/assets/providers/openai.svg b/src/assets/providers/openai.svg new file mode 100644 index 000000000..04bf59dec --- /dev/null +++ b/src/assets/providers/openai.svg @@ -0,0 +1 @@ +OpenAI diff --git a/src/assets/providers/openrouter.svg b/src/assets/providers/openrouter.svg new file mode 100644 index 000000000..18274737f --- /dev/null +++ b/src/assets/providers/openrouter.svg @@ -0,0 +1 @@ +OpenRouter \ No newline at end of file diff --git a/src/assets/providers/siliconflow.svg b/src/assets/providers/siliconflow.svg new file mode 100644 index 000000000..044f43017 --- /dev/null +++ b/src/assets/providers/siliconflow.svg @@ -0,0 +1 @@ +SiliconCloud \ No newline at end of file diff --git a/src/components/settings/ProvidersSettings.tsx b/src/components/settings/ProvidersSettings.tsx index 4de81f056..60a80c9a3 100644 --- a/src/components/settings/ProvidersSettings.tsx +++ b/src/components/settings/ProvidersSettings.tsx @@ -26,6 +26,8 @@ import { useProviderStore, type ProviderConfig, type ProviderWithKeyInfo } from import { PROVIDER_TYPE_INFO, type ProviderType, + getProviderIconUrl, + shouldInvertInDark, } from '@/lib/providers'; import { cn } from '@/lib/utils'; import { toast } from 'sonner'; @@ -292,7 +294,11 @@ function ProviderCard({ {/* Top row: icon + name + toggle */}
- {typeInfo?.icon || '⚙️'} + {getProviderIconUrl(provider.type) ? ( + {typeInfo?.name + ) : ( + {typeInfo?.icon || '⚙️'} + )}
{provider.name} @@ -521,7 +527,11 @@ function AddProviderDialog({ existingTypes, onClose, onAdd, onValidateKey }: Add }} className="p-4 rounded-lg border hover:bg-accent transition-colors text-center" > - {type.icon} + {getProviderIconUrl(type.id) ? ( + {type.name} + ) : ( + {type.icon} + )}

{type.name}

))} @@ -529,7 +539,11 @@ function AddProviderDialog({ existingTypes, onClose, onAdd, onValidateKey }: Add ) : (
- {typeInfo?.icon} + {getProviderIconUrl(selectedType!) ? ( + {typeInfo?.name} + ) : ( + {typeInfo?.icon} + )}

{typeInfo?.name}

+ s.sessions); @@ -17,6 +19,7 @@ export function ChatToolbar() { const loading = useChatStore((s) => s.loading); const showThinking = useChatStore((s) => s.showThinking); const toggleThinking = useChatStore((s) => s.toggleThinking); + const { t } = useTranslation('chat'); const handleSessionChange = (e: React.ChangeEvent) => { switchSession(e.target.value); @@ -51,41 +54,59 @@ export function ChatToolbar() {
{/* New Session */} - + + + + + +

{t('toolbar.newSession')}

+
+
{/* Refresh */} - + + + + + +

{t('toolbar.refresh')}

+
+
{/* Thinking Toggle */} - + + + + + +

{showThinking ? t('toolbar.hideThinking') : t('toolbar.showThinking')}

+
+
); } diff --git a/src/pages/Setup/index.tsx b/src/pages/Setup/index.tsx index 594665e4c..5cb44b427 100644 --- a/src/pages/Setup/index.tsx +++ b/src/pages/Setup/index.tsx @@ -101,7 +101,7 @@ const defaultSkills: DefaultSkill[] = [ { id: 'terminal', name: 'Terminal', description: 'Shell command execution' }, ]; -import { SETUP_PROVIDERS, type ProviderTypeInfo } from '@/lib/providers'; +import { SETUP_PROVIDERS, type ProviderTypeInfo, getProviderIconUrl, shouldInvertInDark } from '@/lib/providers'; // Use the shared provider registry for setup providers const providers = SETUP_PROVIDERS; @@ -1454,7 +1454,7 @@ function CompleteContent({ selectedProvider, installedSkills }: CompleteContentP
{t('complete.provider')} - {providerData ? `${providerData.icon} ${providerData.name}` : '—'} + {providerData ? {getProviderIconUrl(providerData.id) ? {providerData.name} : providerData.icon} {providerData.name} : '—'}
diff --git a/src/pages/Skills/index.tsx b/src/pages/Skills/index.tsx index 5c861933b..eada6b69e 100644 --- a/src/pages/Skills/index.tsx +++ b/src/pages/Skills/index.tsx @@ -615,6 +615,8 @@ export function Skills() { } }, [enableSkill, disableSkill, t]); + const hasInstalledSkills = skills.some(s => !s.isBundled); + const handleOpenSkillsFolder = useCallback(async () => { try { const skillsDir = await window.electron.ipcRenderer.invoke('openclaw:getSkillsDir') as string; @@ -623,7 +625,12 @@ export function Skills() { } const result = await window.electron.ipcRenderer.invoke('shell:openPath', skillsDir) as string; if (result) { - throw new Error(result); + // shell.openPath returns an error string if the path doesn't exist + if (result.toLowerCase().includes('no such file') || result.toLowerCase().includes('not found') || result.toLowerCase().includes('failed to open')) { + toast.error(t('toast.failedFolderNotFound')); + } else { + throw new Error(result); + } } } catch (err) { toast.error(t('toast.failedOpenFolder') + ': ' + String(err)); @@ -702,10 +709,12 @@ export function Skills() { {t('refresh')} - + {hasInstalledSkills && ( + + )}