Pass 3 - add commands, remove run, formatting, mobile view

This commit is contained in:
Owen
2026-08-18 14:59:10 -04:00
parent 8feca67431
commit 03085eb188
4 changed files with 27 additions and 51 deletions
@@ -38,7 +38,6 @@ type AiClientConfigCardProps = {
keyAuth: AiClientAuthInput;
description: string;
icon: LucideIcon;
stackBlocks?: boolean;
};
export function AiClientConfigCard({
@@ -47,8 +46,7 @@ export function AiClientConfigCard({
endpoint,
keyAuth,
description,
icon: Icon,
stackBlocks = true
icon: Icon
}: AiClientConfigCardProps) {
const t = useTranslations();
const [open, setOpen] = useState(false);
@@ -94,7 +92,7 @@ export function AiClientConfigCard({
guide?.presets.find((p) => p.id === presetId) ?? guide?.presets[0];
const manualContent = guide ? (
<div className="space-y-4">
<div className="min-w-0 space-y-4">
{guide.presets.length > 1 ? (
<Select
value={presetId}
@@ -114,14 +112,7 @@ export function AiClientConfigCard({
</SelectContent>
</Select>
) : null}
<div
className={cn(
"grid gap-4",
!stackBlocks &&
(preset?.blocks.length ?? 0) > 1 &&
"@lg:grid-cols-2"
)}
>
<div className="grid min-w-0 gap-4">
{preset?.blocks.map((block) => (
<AiConfigCodeBlock key={block.id} block={block} />
))}
@@ -133,7 +124,7 @@ export function AiClientConfigCard({
<Collapsible
open={open}
onOpenChange={handleOpenChange}
className="rounded-md border bg-card"
className="min-w-0 rounded-md border bg-card"
>
<CollapsibleTrigger className="flex w-full items-center gap-3 px-4 py-3 text-left cursor-pointer">
<Icon className="size-4 shrink-0 text-muted-foreground" />
@@ -150,7 +141,7 @@ export function AiClientConfigCard({
)}
/>
</CollapsibleTrigger>
<CollapsibleContent className="border-t px-4 py-4">
<CollapsibleContent className="min-w-0 border-t px-4 py-4">
{!guide && revealing ? (
<div className="flex items-center justify-center py-6 text-muted-foreground">
<Loader2 className="size-5 animate-spin" />
@@ -179,27 +170,21 @@ export function AiClientConfigCard({
</TabsList>
<TabsContent
value="cli"
className={cn(
"grid gap-4 mt-4",
!stackBlocks && "@lg:grid-cols-2"
)}
className="grid min-w-0 gap-4 mt-4"
>
<AiConfigCodeBlock
block={guide.cli.configure}
/>
<AiConfigCodeBlock block={guide.cli.run} />
{guide.cli.configureWithKey ? (
<AiConfigCodeBlock
block={guide.cli.configureWithKey}
/>
) : null}
{guide.cli.runWithKey ? (
<AiConfigCodeBlock
block={guide.cli.runWithKey}
/>
) : null}
</TabsContent>
<TabsContent value="manual" className="mt-4">
<TabsContent
value="manual"
className="min-w-0 mt-4"
>
{manualContent}
</TabsContent>
</Tabs>
@@ -21,10 +21,10 @@ type AiClientConfigSectionProps = {
endpoint: string;
auth: AiClientAuthInput;
/**
* "wide" lays the client cards out side by side and allows a card's
* code blocks to sit side by side once there's room (e.g. the Keys
* page). "compact" always stacks both, which is what fits the
* Resource Launcher's side panel.
* "wide" lays the client cards out side by side once there's room
* (e.g. the Keys page). "compact" always stacks them, which is what
* fits the Resource Launcher's side panel. A card's own code blocks
* always stack regardless of this setting.
*/
layout?: "wide" | "compact";
className?: string;
@@ -64,10 +64,10 @@ export function AiClientConfigSection({
</SettingsSectionDescription>
</SettingsSectionHeader>
<SettingsSectionBody>
<div className={cn("@container", className)}>
<div className={cn("@container min-w-0", className)}>
<div
className={cn(
"grid gap-3",
"grid min-w-0 gap-3",
isWide && "@3xl:grid-cols-2"
)}
>
@@ -80,7 +80,6 @@ export function AiClientConfigSection({
keyAuth={auth}
description={descriptions[clientId]}
icon={CLIENT_ICONS[clientId]}
stackBlocks={!isWide}
/>
))}
</div>
@@ -2,19 +2,21 @@
import CopyTextBox from "@app/components/CopyTextBox";
import type { AiConfigBlock } from "@app/lib/aiClientConfig";
import { cn } from "@app/lib/cn";
export function AiConfigCodeBlock({ block }: { block: AiConfigBlock }) {
return (
<div className="space-y-1.5">
<div className="min-w-0 space-y-1.5">
<p className="font-mono text-xs text-muted-foreground">
{block.label}
</p>
<div
className={
className={cn(
"min-w-0",
block.kind === "steps"
? "[&_pre]:text-sm"
: "[&_pre]:text-xs [&_code]:font-mono"
}
)}
>
<CopyTextBox
text={block.displayText}
+6 -16
View File
@@ -34,8 +34,6 @@ export type AiConfigPreset = {
export type AiCliCommands = {
configure: AiConfigBlock;
configureWithKey?: AiConfigBlock;
run: AiConfigBlock;
runWithKey?: AiConfigBlock;
};
export type AiClientGuide = {
@@ -59,34 +57,26 @@ function block(
return { id, label, kind, displayText: build(keyValue(auth)) };
}
function buildCli(clientArg: "claude" | "codex", auth: AiClientAuth): AiCliCommands {
function buildCli(
clientArg: "claude" | "codex" | "opencode",
auth: AiClientAuth
): AiCliCommands {
const configure: AiConfigBlock = {
id: `cli-configure-${clientArg}`,
label: "Configure",
displayText: `pangolin configure ${clientArg}`
};
const run: AiConfigBlock = {
id: `cli-run-${clientArg}`,
label: "Run",
displayText: `pangolin run ${clientArg}`
};
if (auth.mode !== "keyed") {
return { configure, run };
return { configure };
}
return {
configure,
run,
configureWithKey: {
id: `cli-configure-key-${clientArg}`,
label: "Configure with an API key",
displayText: `pangolin configure ${clientArg} ${auth.key}`
},
runWithKey: {
id: `cli-run-key-${clientArg}`,
label: "Run with an API key",
displayText: `pangolin run ${clientArg} ${auth.key}`
}
};
}
@@ -278,7 +268,7 @@ function buildOpencodeGuide(endpoint: string, auth: AiClientAuth): AiClientGuide
return {
id: "opencode",
name: AI_CLIENT_NAMES.opencode,
cli: null,
cli: buildCli("opencode", auth),
presets: [
{
id: "default",