Tweak setup banner (#1567)
<!-- CURSOR_SUMMARY -->
> [!NOTE]
> Refines the setup banner UI (copy, layout, and badges), updates
SetupProviderCard to support a chip and typed subtitle, and adjusts e2e
to new OpenRouter button label.
>
> - **UI/Setup Banner (`src/components/SetupBanner.tsx`)**:
> - Rename step title to `2. Setup AI Access` and update helper copy.
> - Layout: show `google` and `openrouter` cards side-by-side; increase
title font sizes.
> - Add badges: `chip={Free}` on Google/OpenRouter; `chip={Recommended}`
on Dyad Pro.
> - Simplify Dyad Pro `subtitle` to a string; remove `GlobeIcon` usage.
> - "Other providers" card: tweak heading size and copy (remove
`OpenRouter`).
> - `OpenRouterSetupBanner`: use `chip` for "Free models available"
instead of `subtitle`.
> - **Component API (`src/components/SetupProviderCard.tsx`)**:
> - Add optional `chip` prop and render top-right badge.
> - Change `subtitle` type to `string`; adjust styles (relative
container, font sizes).
> - **E2E (`e2e-tests/setup.spec.ts`)**:
> - Update button selector to `Setup OpenRouter API Key` (remove
`Free`).
>
> <sup>Written by [Cursor
Bugbot](https://cursor.com/dashboard?tab=bugbot) for commit
991807b2edd4baa7a8ec7f4d47f867ba058ebf36. This will update automatically
on new commits. Configure
[here](https://cursor.com/dashboard?tab=bugbot).</sup>
<!-- /CURSOR_SUMMARY -->
This commit is contained in:
@@ -15,7 +15,7 @@ testSetup("setup ai provider", async ({ po }) => {
|
|||||||
|
|
||||||
await po.page.getByRole("button", { name: "Go Back" }).click();
|
await po.page.getByRole("button", { name: "Go Back" }).click();
|
||||||
await po.page
|
await po.page
|
||||||
.getByRole("button", { name: "Setup OpenRouter API Key Free" })
|
.getByRole("button", { name: "Setup OpenRouter API Key" })
|
||||||
.click();
|
.click();
|
||||||
await expect(
|
await expect(
|
||||||
po.page.getByRole("heading", { name: "Configure OpenRouter" }),
|
po.page.getByRole("heading", { name: "Configure OpenRouter" }),
|
||||||
|
|||||||
@@ -8,7 +8,6 @@ import {
|
|||||||
XCircle,
|
XCircle,
|
||||||
Loader2,
|
Loader2,
|
||||||
Settings,
|
Settings,
|
||||||
GlobeIcon,
|
|
||||||
} from "lucide-react";
|
} from "lucide-react";
|
||||||
import { providerSettingsRoute } from "@/routes/settings/providers/$provider";
|
import { providerSettingsRoute } from "@/routes/settings/providers/$provider";
|
||||||
|
|
||||||
@@ -246,16 +245,18 @@ export function SetupBanner() {
|
|||||||
<div className="flex items-center gap-3">
|
<div className="flex items-center gap-3">
|
||||||
{getStatusIcon(isAnyProviderSetup())}
|
{getStatusIcon(isAnyProviderSetup())}
|
||||||
<span className="font-medium text-sm">
|
<span className="font-medium text-sm">
|
||||||
2. Setup AI Model Access
|
2. Setup AI Access
|
||||||
</span>
|
</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</AccordionTrigger>
|
</AccordionTrigger>
|
||||||
<AccordionContent className="px-4 pt-2 pb-4 bg-white dark:bg-zinc-900 border-t border-inherit">
|
<AccordionContent className="px-4 pt-2 pb-4 bg-white dark:bg-zinc-900 border-t border-inherit">
|
||||||
<p className="text-sm mb-3">
|
<p className="text-[15px] mb-3">
|
||||||
Connect your preferred AI provider to start generating code.
|
Not sure what to do? Watch the Get Started video above ☝️
|
||||||
</p>
|
</p>
|
||||||
|
<div className="flex gap-2">
|
||||||
<SetupProviderCard
|
<SetupProviderCard
|
||||||
|
className="flex-1"
|
||||||
variant="google"
|
variant="google"
|
||||||
onClick={handleGoogleSetupClick}
|
onClick={handleGoogleSetupClick}
|
||||||
tabIndex={isNodeSetupComplete ? 0 : -1}
|
tabIndex={isNodeSetupComplete ? 0 : -1}
|
||||||
@@ -263,16 +264,11 @@ export function SetupBanner() {
|
|||||||
<Sparkles className="w-4 h-4 text-blue-600 dark:text-blue-400" />
|
<Sparkles className="w-4 h-4 text-blue-600 dark:text-blue-400" />
|
||||||
}
|
}
|
||||||
title="Setup Google Gemini API Key"
|
title="Setup Google Gemini API Key"
|
||||||
subtitle={
|
chip={<>Free</>}
|
||||||
<>
|
|
||||||
<GiftIcon className="w-3 h-3" />
|
|
||||||
Use Google Gemini for free
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<SetupProviderCard
|
<SetupProviderCard
|
||||||
className="mt-2"
|
className="flex-1"
|
||||||
variant="openrouter"
|
variant="openrouter"
|
||||||
onClick={handleOpenRouterSetupClick}
|
onClick={handleOpenRouterSetupClick}
|
||||||
tabIndex={isNodeSetupComplete ? 0 : -1}
|
tabIndex={isNodeSetupComplete ? 0 : -1}
|
||||||
@@ -280,13 +276,9 @@ export function SetupBanner() {
|
|||||||
<Sparkles className="w-4 h-4 text-teal-600 dark:text-teal-400" />
|
<Sparkles className="w-4 h-4 text-teal-600 dark:text-teal-400" />
|
||||||
}
|
}
|
||||||
title="Setup OpenRouter API Key"
|
title="Setup OpenRouter API Key"
|
||||||
subtitle={
|
chip={<>Free</>}
|
||||||
<>
|
|
||||||
<GiftIcon className="w-3 h-3" />
|
|
||||||
Free models available
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
|
</div>
|
||||||
|
|
||||||
<SetupProviderCard
|
<SetupProviderCard
|
||||||
className="mt-2"
|
className="mt-2"
|
||||||
@@ -297,12 +289,8 @@ export function SetupBanner() {
|
|||||||
<img src={logo} alt="Dyad Logo" className="w-6 h-6 mr-0.5" />
|
<img src={logo} alt="Dyad Logo" className="w-6 h-6 mr-0.5" />
|
||||||
}
|
}
|
||||||
title="Setup Dyad Pro"
|
title="Setup Dyad Pro"
|
||||||
subtitle={
|
subtitle="Access all AI models with one plan"
|
||||||
<>
|
chip={<>Recommended</>}
|
||||||
<GlobeIcon className="w-3 h-3" />
|
|
||||||
Access all AI models with one plan
|
|
||||||
</>
|
|
||||||
}
|
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
@@ -317,11 +305,11 @@ export function SetupBanner() {
|
|||||||
<Settings className="w-4 h-4 text-gray-600 dark:text-gray-400" />
|
<Settings className="w-4 h-4 text-gray-600 dark:text-gray-400" />
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className="font-medium text-sm text-gray-800 dark:text-gray-300">
|
<h4 className="font-medium text-[15px] text-gray-800 dark:text-gray-300">
|
||||||
Setup other AI providers
|
Setup other AI providers
|
||||||
</h4>
|
</h4>
|
||||||
<p className="text-xs text-gray-600 dark:text-gray-400">
|
<p className="text-xs text-gray-600 dark:text-gray-400">
|
||||||
OpenAI, Anthropic, OpenRouter and more
|
OpenAI, Anthropic and more
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@@ -428,7 +416,7 @@ export const OpenRouterSetupBanner = ({
|
|||||||
<Sparkles className="w-4 h-4 text-purple-600 dark:text-purple-400" />
|
<Sparkles className="w-4 h-4 text-purple-600 dark:text-purple-400" />
|
||||||
}
|
}
|
||||||
title="Setup OpenRouter API Key"
|
title="Setup OpenRouter API Key"
|
||||||
subtitle={
|
chip={
|
||||||
<>
|
<>
|
||||||
<GiftIcon className="w-3 h-3" />
|
<GiftIcon className="w-3 h-3" />
|
||||||
Free models available
|
Free models available
|
||||||
|
|||||||
@@ -8,6 +8,7 @@ export function SetupProviderCard({
|
|||||||
variant,
|
variant,
|
||||||
title,
|
title,
|
||||||
subtitle,
|
subtitle,
|
||||||
|
chip,
|
||||||
leadingIcon,
|
leadingIcon,
|
||||||
onClick,
|
onClick,
|
||||||
tabIndex = 0,
|
tabIndex = 0,
|
||||||
@@ -15,7 +16,8 @@ export function SetupProviderCard({
|
|||||||
}: {
|
}: {
|
||||||
variant: SetupProviderVariant;
|
variant: SetupProviderVariant;
|
||||||
title: string;
|
title: string;
|
||||||
subtitle?: ReactNode;
|
subtitle?: string;
|
||||||
|
chip?: ReactNode;
|
||||||
leadingIcon: ReactNode;
|
leadingIcon: ReactNode;
|
||||||
onClick: () => void;
|
onClick: () => void;
|
||||||
tabIndex?: number;
|
tabIndex?: number;
|
||||||
@@ -26,7 +28,7 @@ export function SetupProviderCard({
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"p-3 border rounded-lg cursor-pointer transition-colors",
|
"p-3 border rounded-lg cursor-pointer transition-colors relative",
|
||||||
styles.container,
|
styles.container,
|
||||||
className,
|
className,
|
||||||
)}
|
)}
|
||||||
@@ -34,19 +36,30 @@ export function SetupProviderCard({
|
|||||||
role="button"
|
role="button"
|
||||||
tabIndex={tabIndex}
|
tabIndex={tabIndex}
|
||||||
>
|
>
|
||||||
|
{chip && (
|
||||||
|
<div
|
||||||
|
className={cn(
|
||||||
|
"absolute top-2 right-2 px-2 py-1 rounded-full text-xs font-semibold",
|
||||||
|
styles.subtitleColor,
|
||||||
|
"bg-white/80 dark:bg-black/20 backdrop-blur-sm",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{chip}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
<div className="flex items-center justify-between gap-3">
|
<div className="flex items-center justify-between gap-3">
|
||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<div className={cn("p-1.5 rounded-full", styles.iconWrapper)}>
|
<div className={cn("p-1.5 rounded-full", styles.iconWrapper)}>
|
||||||
{leadingIcon}
|
{leadingIcon}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
<h4 className={cn("font-medium text-sm", styles.titleColor)}>
|
<h4 className={cn("font-medium text-[15px]", styles.titleColor)}>
|
||||||
{title}
|
{title}
|
||||||
</h4>
|
</h4>
|
||||||
{subtitle ? (
|
{subtitle ? (
|
||||||
<div
|
<div
|
||||||
className={cn(
|
className={cn(
|
||||||
"text-xs flex items-center gap-1",
|
"text-sm flex items-center gap-1",
|
||||||
styles.subtitleColor,
|
styles.subtitleColor,
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
|
|||||||
Reference in New Issue
Block a user