Enhanced onboarding page visual design (#4156)

Co-authored-by: Zane Staggs <zane@squareup.com>
This commit is contained in:
Spence
2025-08-20 16:29:10 -04:00
committed by GitHub
parent 1dbbd9155e
commit 134ae8b9c5
10 changed files with 351 additions and 154 deletions
+122 -43
View File
@@ -8,6 +8,8 @@ import { initializeSystem } from '../utils/providerUtils';
import { toastService } from '../toasts';
import { OllamaSetup } from './OllamaSetup';
import { checkOllamaStatus } from '../utils/ollamaDetection';
import { Goose } from './icons/Goose';
import { OpenRouter, Ollama } from './icons';
interface ProviderGuardProps {
children: React.ReactNode;
@@ -73,6 +75,9 @@ export default function ProviderGuard({ children }: ProviderGuardProps) {
setOpenRouterSetupState(null);
setShowFirstTimeSetup(false);
setHasProvider(true);
// Navigate to chat after successful setup
navigate('/', { replace: true });
} else {
throw new Error('Provider or model not found after OpenRouter setup');
}
@@ -106,8 +111,6 @@ export default function ProviderGuard({ children }: ProviderGuardProps) {
const model = (await read('GOOSE_MODEL', false)) ?? config.GOOSE_DEFAULT_MODEL;
// Always check for Ollama regardless of provider status
const ollamaStatus = await checkOllamaStatus();
setOllamaDetected(ollamaStatus.isRunning);
if (provider && model) {
console.log('ProviderGuard - Provider and model found, continuing normally');
@@ -116,6 +119,9 @@ export default function ProviderGuard({ children }: ProviderGuardProps) {
console.log('ProviderGuard - No provider/model configured');
setShowFirstTimeSetup(true);
}
const ollamaStatus = await checkOllamaStatus();
setOllamaDetected(ollamaStatus.isRunning);
} catch (error) {
// On error, assume no provider and redirect to welcome
console.error('Error checking provider configuration:', error);
@@ -170,7 +176,7 @@ export default function ProviderGuard({ children }: ProviderGuardProps) {
if (showOllamaSetup) {
return (
<div className="h-screen w-full flex flex-col items-center justify-center bg-background-default">
<div className="min-h-screen w-full flex flex-col items-center justify-center p-4 bg-background-default">
<div className="max-w-md w-full mx-auto p-8">
<div className="mb-8 text-center">
<WelcomeGooseLogo />
@@ -179,6 +185,8 @@ export default function ProviderGuard({ children }: ProviderGuardProps) {
onSuccess={() => {
setShowOllamaSetup(false);
setHasProvider(true);
// Navigate to chat after successful setup
navigate('/', { replace: true });
}}
onCancel={() => {
setShowOllamaSetup(false);
@@ -192,53 +200,124 @@ export default function ProviderGuard({ children }: ProviderGuardProps) {
if (showFirstTimeSetup) {
return (
<div className="h-screen w-full flex flex-col items-center justify-center bg-background-default">
<div className="max-w-md w-full mx-auto p-8 text-center">
<WelcomeGooseLogo />
<h1 className="text-2xl font-bold text-text-standard mt-8 mb-4">Welcome to Goose!</h1>
<p className="text-text-muted mb-8">
Let's get you set up with an AI provider to start using Goose.
</p>
<div className="h-screen w-full bg-background-default overflow-hidden">
<div className="h-full overflow-y-auto">
<div className="min-h-full flex flex-col items-center justify-center p-4 py-8">
<div className="max-w-lg w-full mx-auto p-8">
{/* Header section - same width as buttons, left aligned */}
<div className="text-left mb-8 sm:mb-12">
<div className="space-y-3 sm:space-y-4">
<div className="origin-bottom-left goose-icon-animation">
<Goose className="size-6 sm:size-8" />
</div>
<h1 className="text-2xl sm:text-4xl font-light text-left">
Welcome to Goose
</h1>
</div>
<p className="text-text-muted text-base sm:text-lg mt-4 sm:mt-6">
Since it's your first time here, let's get your set you with a provider so we can make incredible work together.
</p>
</div>
<div className="space-y-4">
<button
onClick={handleOpenRouterSetup}
className="w-full px-6 py-3 bg-background-muted text-text-standard rounded-lg hover:bg-background-hover transition-colors font-medium flex items-center justify-center gap-2"
>
Automatic setup with OpenRouter (recommended)
</button>
{/* Setup options - same width container */}
<div className="space-y-3 sm:space-y-4">
{/* Primary OpenRouter Card with subtle shimmer - wrapped for badge positioning */}
<div className="relative">
{/* Recommended badge - positioned relative to wrapper */}
<div className="absolute -top-2 -right-2 sm:-top-3 sm:-right-3 z-20">
<span className="inline-block px-2 py-1 text-xs font-medium bg-blue-600 text-white rounded-full">
Recommended
</span>
</div>
<div
onClick={handleOpenRouterSetup}
className="relative w-full p-4 sm:p-6 bg-background-muted border border-background-hover rounded-xl hover:border-text-muted transition-all duration-200 cursor-pointer group overflow-hidden"
>
{/* Subtle shimmer effect */}
<div className="absolute inset-0 -translate-x-full animate-shimmer bg-gradient-to-r from-transparent via-white/8 to-transparent"></div>
<div className="relative flex items-start justify-between mb-3">
<div className="flex-1">
<OpenRouter className="w-5 h-5 sm:w-6 sm:h-6 mb-12 text-text-standard" />
<h3 className="font-medium text-text-standard text-sm sm:text-base">
Automatic setup with OpenRouter
</h3>
</div>
<div className="text-text-muted group-hover:text-text-standard transition-colors">
<svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</div>
</div>
<p className="relative text-text-muted text-sm sm:text-base">
Get instant access to multiple AI models including GPT-4, Claude, and more. Quick setup with just a few clicks.
</p>
</div>
</div>
<button
onClick={() => {
setShowFirstTimeSetup(false);
setShowOllamaSetup(true);
}}
className="w-full px-6 py-3 bg-background-muted text-text-standard rounded-lg hover:bg-background-hover transition-colors font-medium flex items-center justify-center gap-2"
>
{ollamaDetected ? (
<>
<span className="text-text-success">●</span>
Use Ollama (auto detected)
</>
) : (
'Set up Ollama (run AI locally and free)'
{/* Ollama Card - outline style */}
<div className="relative">
{/* Detected badge - similar to recommended but green */}
{ollamaDetected && (
<div className="absolute -top-2 -right-2 sm:-top-3 sm:-right-3 z-20">
<span className="inline-block px-2 py-1 text-xs font-medium bg-green-600 text-white rounded-full">
Detected
</span>
</div>
)}
</button>
<div
onClick={() => {
setShowFirstTimeSetup(false);
setShowOllamaSetup(true);
}}
className="w-full p-4 sm:p-6 bg-transparent border border-background-hover rounded-xl hover:border-text-muted transition-all duration-200 cursor-pointer group"
>
<div className="flex items-start justify-between mb-3">
<div className="flex-1">
<Ollama className="w-5 h-5 sm:w-6 sm:h-6 mb-12 text-text-standard" />
<h3 className="font-medium text-text-standard text-sm sm:text-base">
Ollama
</h3>
</div>
<div className="text-text-muted group-hover:text-text-standard transition-colors flex-shrink-0">
<svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</div>
</div>
<p className="text-text-muted text-sm sm:text-base">
Run AI models locally on your computer. Completely free and private with no internet required.
</p>
</div>
</div>
<button
{/* Other providers Card - outline style */}
<div
onClick={() => navigate('/welcome', { replace: true })}
className="w-full px-6 py-3 bg-background-muted text-text-standard rounded-lg hover:bg-background-hover transition-colors font-medium"
className="w-full p-4 sm:p-6 bg-transparent border border-background-hover rounded-xl hover:border-text-muted transition-all duration-200 cursor-pointer group"
>
Configure Other Providers (advanced)
</button>
</div>
<div className="flex items-start justify-between mb-3">
<div className="flex-1">
<h3 className="font-medium text-text-standard text-sm sm:text-base">
Other providers
</h3>
</div>
<div className="text-text-muted group-hover:text-text-standard transition-colors">
<svg className="w-4 h-4 sm:w-5 sm:h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M9 5l7 7-7 7" />
</svg>
</div>
</div>
<p className="text-text-muted text-sm sm:text-base">
If you've already signed up for providers like Anthropic, OpenAI etc, you can enter your own keys.
</p>
</div>
<p className="text-sm text-text-muted mt-6">
OpenRouter provides instant access to multiple AI models with a simple setup.
{ollamaDetected
? ' Ollama is also detected on your system for running models locally.'
: ' You can also install Ollama to run free AI models locally on your computer.'}
</p>
</div>
</div>
</div>
</div>
</div>
);