mirror of
https://github.com/voideditor/void
synced 2026-05-24 09:58:23 +00:00
commit
56c2f7a900
1 changed files with 105 additions and 109 deletions
|
|
@ -113,8 +113,8 @@ const providerNamesOfTab: Record<TabName, ProviderName[]> = {
|
||||||
const descriptionOfTab: Record<TabName, string> = {
|
const descriptionOfTab: Record<TabName, string> = {
|
||||||
Free: `Providers with a 100% free tier. Add as many as you'd like!`,
|
Free: `Providers with a 100% free tier. Add as many as you'd like!`,
|
||||||
Paid: `Connect directly with any provider (bring your own key).`,
|
Paid: `Connect directly with any provider (bring your own key).`,
|
||||||
Local: `Add as many local providers as you'd like! Active providers should appear automatically.`,
|
Local: `Active providers should appear automatically. Add as many as you'd like! `,
|
||||||
'Cloud/Other': `Add as many providers as you'd like! Reach out for custom configuration requests.`,
|
'Cloud/Other': `Add as many as you'd like! Reach out for custom configuration requests.`,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -148,127 +148,123 @@ const AddProvidersPage = ({ pageIndex, setPageIndex }: { pageIndex: number, setP
|
||||||
};
|
};
|
||||||
}, [errorMessage]);
|
}, [errorMessage]);
|
||||||
|
|
||||||
return (<div className="flex flex-col w-full h-[80vh] max-w-[900px] mx-auto relative">
|
return (<div className="flex flex-col md:flex-row w-full h-[80vh] gap-6 max-w-[900px] mx-auto relative">
|
||||||
<div className="flex flex-col md:flex-row w-full gap-6"> {/* Left Column - Fixed */}
|
{/* Left Column */}
|
||||||
<div className="md:w-1/4 w-full flex flex-col gap-6 p-6 border-none border-void-border-2 h-full overflow-y-auto">
|
<div className="md:w-1/4 w-full flex flex-col gap-6 p-6 border-none border-void-border-2 h-full overflow-y-auto">
|
||||||
{/* Tab Selector */}
|
{/* Tab Selector */}
|
||||||
<div className="flex md:flex-col gap-2">
|
<div className="flex md:flex-col gap-2">
|
||||||
{[...tabNames, 'Cloud/Other'].map(tab => (
|
{[...tabNames, 'Cloud/Other'].map(tab => (
|
||||||
<button
|
<button
|
||||||
key={tab}
|
key={tab}
|
||||||
className={`py-2 px-4 rounded-md text-left ${currentTab === tab
|
className={`py-2 px-4 rounded-md text-left ${currentTab === tab
|
||||||
? 'bg-[#0e70c0]/80 text-white font-medium shadow-sm'
|
? 'bg-[#0e70c0]/80 text-white font-medium shadow-sm'
|
||||||
: 'bg-void-bg-2 hover:bg-void-bg-2/80 text-void-fg-1'
|
: 'bg-void-bg-2 hover:bg-void-bg-2/80 text-void-fg-1'
|
||||||
} transition-all duration-200`}
|
} transition-all duration-200`}
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
setCurrentTab(tab as TabName);
|
setCurrentTab(tab as TabName);
|
||||||
setErrorMessage(null); // Reset error message when changing tabs
|
setErrorMessage(null); // Reset error message when changing tabs
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{tab}
|
{tab}
|
||||||
</button>
|
</button>
|
||||||
))}
|
))}
|
||||||
</div>
|
|
||||||
|
|
||||||
{/* Feature Checklist */}
|
|
||||||
<div className="flex flex-col gap-1 mt-4 text-sm opacity-80">
|
|
||||||
{featureNameMap.map(({ display, featureName }) => {
|
|
||||||
const hasModel = settingsState.modelSelectionOfFeature[featureName] !== null;
|
|
||||||
return (
|
|
||||||
<div key={featureName} className="flex items-center gap-2">
|
|
||||||
{hasModel ? (
|
|
||||||
<Check className="w-4 h-4 text-emerald-500" />
|
|
||||||
) : (
|
|
||||||
<div className="w-3 h-3 rounded-full flex items-center justify-center">
|
|
||||||
<div className="w-1 h-1 rounded-full bg-white/70"></div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
<span>{display}</span>
|
|
||||||
</div>
|
|
||||||
);
|
|
||||||
})}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Right Column */}
|
{/* Feature Checklist */}
|
||||||
<div className="flex-1 flex flex-col items-center justify-start p-6 h-full overflow-y-auto">
|
<div className="flex flex-col gap-1 mt-4 text-sm opacity-80">
|
||||||
<div className="text-5xl mb-2 text-center w-full">Add a Provider</div>
|
{featureNameMap.map(({ display, featureName }) => {
|
||||||
|
const hasModel = settingsState.modelSelectionOfFeature[featureName] !== null;
|
||||||
<div className="w-full max-w-xl mt-4 mb-10">
|
return (
|
||||||
<div className="text-4xl font-light my-4 w-full">{currentTab}</div>
|
<div key={featureName} className="flex items-center gap-2">
|
||||||
<div className="text-[14px] text-void-fg-3 my-4 w-full">{descriptionOfTab[currentTab]}</div>
|
{hasModel ? (
|
||||||
</div>
|
<Check className="w-4 h-4 text-emerald-500" />
|
||||||
|
) : (
|
||||||
{providerNamesOfTab[currentTab].map((providerName) => (
|
<div className="w-3 h-3 rounded-full flex items-center justify-center">
|
||||||
<div key={providerName} className="w-full max-w-xl mb-10">
|
<div className="w-1 h-1 rounded-full bg-white/70"></div>
|
||||||
<div className="text-xl mb-2">
|
</div>
|
||||||
Add {displayInfoOfProviderName(providerName).title}
|
|
||||||
{providerName === 'gemini' && (
|
|
||||||
<span
|
|
||||||
data-tooltip-id="void-tooltip-provider-info"
|
|
||||||
data-tooltip-content="Gemini 2.5 Pro offers 25 free messages a day, and Gemini 2.5 Flash offers 500. We recommend using models down the line as you run out of free credits."
|
|
||||||
data-tooltip-place="right"
|
|
||||||
className="ml-1 text-xs align-top text-blue-400"
|
|
||||||
>*</span>
|
|
||||||
)}
|
|
||||||
{providerName === 'openRouter' && (
|
|
||||||
<span
|
|
||||||
data-tooltip-id="void-tooltip-provider-info"
|
|
||||||
data-tooltip-content="OpenRouter offers 50 free messages a day, and 1000 if you deposit $10. Only applies to models labeled ':free'."
|
|
||||||
data-tooltip-place="right"
|
|
||||||
className="ml-1 text-xs align-top text-blue-400"
|
|
||||||
>*</span>
|
|
||||||
)}
|
)}
|
||||||
|
<span>{display}</span>
|
||||||
</div>
|
</div>
|
||||||
<div>
|
);
|
||||||
<SettingsForProvider providerName={providerName} showProviderTitle={false} showProviderSuggestions={true} />
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
</div>
|
{/* Right Column */}
|
||||||
{providerName === 'ollama' && <OllamaSetupInstructions />}
|
<div className="flex-1 flex flex-col items-center justify-start p-6 h-full overflow-y-auto">
|
||||||
</div>
|
<div className="text-5xl mb-2 text-center w-full">Add a Provider</div>
|
||||||
))}
|
|
||||||
|
|
||||||
{(currentTab === 'Local' || currentTab === 'Cloud/Other') && (
|
<div className="w-full max-w-xl mt-4 mb-10">
|
||||||
<div className="w-full max-w-xl mt-8 bg-void-bg-2/50 rounded-lg p-6 border border-void-border-2/30">
|
<div className="text-4xl font-light my-4 w-full">{currentTab}</div>
|
||||||
<div className="flex items-center gap-2 mb-4">
|
<div className="text-sm opacity-80 text-void-fg-3 my-4 w-full">{descriptionOfTab[currentTab]}</div>
|
||||||
<div className="text-xl font-medium text-[#0e70c0]">Models</div>
|
</div>
|
||||||
<div className="h-px flex-grow bg-void-border-2/30"></div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{currentTab === 'Local' && (
|
{providerNamesOfTab[currentTab].map((providerName) => (
|
||||||
<div className="text-sm text-void-fg-3 mb-4 bg-void-bg-3/30 p-3 rounded border-l-2 border-[#0e70c0]/70">
|
<div key={providerName} className="w-full max-w-xl mb-10">
|
||||||
Local models should be detected automatically. You can add custom models below.
|
<div className="text-xl mb-2">
|
||||||
</div>
|
Add {displayInfoOfProviderName(providerName).title}
|
||||||
|
{providerName === 'gemini' && (
|
||||||
|
<span
|
||||||
|
data-tooltip-id="void-tooltip-provider-info"
|
||||||
|
data-tooltip-content="Gemini 2.5 Pro offers 25 free messages a day, and Gemini 2.5 Flash offers 500. We recommend using models down the line as you run out of free credits."
|
||||||
|
data-tooltip-place="right"
|
||||||
|
className="ml-1 text-xs align-top text-blue-400"
|
||||||
|
>*</span>
|
||||||
|
)}
|
||||||
|
{providerName === 'openRouter' && (
|
||||||
|
<span
|
||||||
|
data-tooltip-id="void-tooltip-provider-info"
|
||||||
|
data-tooltip-content="OpenRouter offers 50 free messages a day, and 1000 if you deposit $10. Only applies to models labeled ':free'."
|
||||||
|
data-tooltip-place="right"
|
||||||
|
className="ml-1 text-xs align-top text-blue-400"
|
||||||
|
>*</span>
|
||||||
)}
|
)}
|
||||||
|
|
||||||
{currentTab === 'Local' && <ModelDump filteredProviders={localProviderNames} />}
|
|
||||||
{currentTab === 'Cloud/Other' && <ModelDump filteredProviders={cloudProviders} />}
|
|
||||||
</div>
|
</div>
|
||||||
)}
|
<div>
|
||||||
|
<SettingsForProvider providerName={providerName} showProviderTitle={false} showProviderSuggestions={true} />
|
||||||
|
|
||||||
|
</div>
|
||||||
|
{providerName === 'ollama' && <OllamaSetupInstructions />}
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
|
|
||||||
|
{(currentTab === 'Local' || currentTab === 'Cloud/Other') && (
|
||||||
|
<div className="w-full max-w-xl mt-8 bg-void-bg-2/50 rounded-lg p-6 border border-void-border-4">
|
||||||
|
<div className="flex items-center gap-2 mb-4">
|
||||||
|
<div className="text-xl font-medium">Models</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
{/* Navigation buttons in right column */}
|
{currentTab === 'Local' && (
|
||||||
<div className="flex flex-col items-end w-full mt-auto pt-8">
|
<div className="text-sm opacity-80 text-void-fg-3 my-4 w-full">Local models should be detected automatically. You can add custom models below.</div>
|
||||||
{errorMessage && (
|
|
||||||
<div className="text-amber-400 mb-2 text-sm opacity-80 transition-opacity duration-300">{errorMessage}</div>
|
|
||||||
)}
|
)}
|
||||||
<div className="flex items-center gap-2">
|
|
||||||
<PreviousButton onClick={() => setPageIndex(pageIndex - 1)} />
|
|
||||||
<NextButton
|
|
||||||
onClick={() => {
|
|
||||||
const isDisabled = isFeatureNameDisabled('Chat', settingsState)
|
|
||||||
|
|
||||||
if (!isDisabled) {
|
{currentTab === 'Local' && <ModelDump filteredProviders={localProviderNames} />}
|
||||||
setPageIndex(pageIndex + 1);
|
{currentTab === 'Cloud/Other' && <ModelDump filteredProviders={cloudProviders} />}
|
||||||
setErrorMessage(null);
|
</div>
|
||||||
} else {
|
)}
|
||||||
// Show error message
|
|
||||||
setErrorMessage("Please set up at least one Chat model before moving on.");
|
|
||||||
}
|
|
||||||
}}
|
{/* Navigation buttons in right column */}
|
||||||
/>
|
<div className="flex flex-col items-end w-full mt-auto pt-8">
|
||||||
</div>
|
{errorMessage && (
|
||||||
|
<div className="text-amber-400 mb-2 text-sm opacity-80 transition-opacity duration-300">{errorMessage}</div>
|
||||||
|
)}
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<PreviousButton onClick={() => setPageIndex(pageIndex - 1)} />
|
||||||
|
<NextButton
|
||||||
|
onClick={() => {
|
||||||
|
const isDisabled = isFeatureNameDisabled('Chat', settingsState)
|
||||||
|
|
||||||
|
if (!isDisabled) {
|
||||||
|
setPageIndex(pageIndex + 1);
|
||||||
|
setErrorMessage(null);
|
||||||
|
} else {
|
||||||
|
// Show error message
|
||||||
|
setErrorMessage("Please set up at least one Chat model before moving on.");
|
||||||
|
}
|
||||||
|
}}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue