Normalize screen layouts: extract control groups, unify sidebar widths, and refactor PromptsScreen

- Extract ToolControls group from ToolsScreen (search, list, list-changed indicator)
- Extract PromptControls and PromptListItem groups for PromptsScreen sidebar
- Refactor PromptsScreen to sidebar + detail layout (matching ResourcesScreen pattern)
- Refactor PromptArgumentsForm to accept a single prompt instead of a dropdown
- Normalize all screen sidebar widths to 340px (Tools, Resources, Prompts, Logs, Tasks, History)
- Convert ToolsScreen from Grid-only to sidebar + Grid layout
- Replace LogControls checkboxes with full-width toggle buttons
- Move Clear/Export buttons from LogControls to LogStreamPanel toolbar
- Make PromptArgumentsForm "Get Prompt" button right-aligned and compact
- Update all affected stories and ConnectedView

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
cliffhall 2026-03-31 17:54:20 -04:00
commit a6724626b7
2 changed files with 627 additions and 233 deletions

View file

@ -6,7 +6,6 @@ const meta: Meta<typeof PromptArgumentsForm> = {
title: "Groups/PromptArgumentsForm",
component: PromptArgumentsForm,
args: {
onSelectPrompt: fn(),
onArgumentChange: fn(),
onGetPrompt: fn(),
},
@ -15,31 +14,19 @@ const meta: Meta<typeof PromptArgumentsForm> = {
export default meta;
type Story = StoryObj<typeof PromptArgumentsForm>;
const samplePrompts = [
{
export const NoArguments: Story = {
args: {
name: "summarize",
description: "Summarize the given text into key points",
},
{
name: "translate",
description: "Translate text from one language to another",
},
{ name: "analyze", description: "Analyze sentiment and tone of the text" },
];
export const NoSelection: Story = {
args: {
prompts: samplePrompts,
selectedPrompt: undefined,
arguments: [],
argumentValues: {},
},
};
export const Selected: Story = {
export const WithArguments: Story = {
args: {
prompts: samplePrompts,
selectedPrompt: "translate",
name: "translate",
description: "Translate text from one language to another",
arguments: [
{ name: "text", required: true, description: "The text to translate" },
{
@ -52,10 +39,10 @@ export const Selected: Story = {
},
};
export const WithRequiredArgs: Story = {
export const WithRequiredAndOptional: Story = {
args: {
prompts: samplePrompts,
selectedPrompt: "summarize",
name: "summarize",
description: "Summarize the given text into key points",
arguments: [
{ name: "text", required: true, description: "The text to summarize" },
{
@ -75,8 +62,8 @@ export const WithRequiredArgs: Story = {
export const AllFilled: Story = {
args: {
prompts: samplePrompts,
selectedPrompt: "translate",
name: "translate",
description: "Translate text from one language to another",
arguments: [
{ name: "text", required: true, description: "The text to translate" },
{
@ -91,3 +78,13 @@ export const AllFilled: Story = {
},
},
};
export const NoDescription: Story = {
args: {
name: "code-review",
arguments: [
{ name: "code", required: true, description: "The code to review" },
],
argumentValues: {},
},
};

View file

@ -1,4 +1,4 @@
import { Button, Select, Stack, Text, TextInput, Title } from "@mantine/core";
import { Button, Group, Stack, Text, TextInput, Title } from "@mantine/core";
export interface PromptArgument {
name: string;
@ -6,17 +6,11 @@ export interface PromptArgument {
description?: string;
}
export interface PromptInfo {
export interface PromptArgumentsFormProps {
name: string;
description?: string;
}
export interface PromptArgumentsFormProps {
prompts: PromptInfo[];
selectedPrompt?: string;
arguments: PromptArgument[];
argumentValues: Record<string, string>;
onSelectPrompt: (name: string) => void;
onArgumentChange: (name: string, value: string) => void;
onGetPrompt: () => void;
}
@ -31,34 +25,19 @@ function formatPlaceholder(name: string): string {
}
export function PromptArgumentsForm({
prompts,
selectedPrompt,
name,
description,
arguments: promptArguments,
argumentValues,
onSelectPrompt,
onArgumentChange,
onGetPrompt,
}: PromptArgumentsFormProps) {
const selectedPromptInfo = prompts.find((p) => p.name === selectedPrompt);
return (
<Stack gap="md">
<Title order={4}>Prompts</Title>
<Select
data={prompts.map((p) => ({ value: p.name, label: p.name }))}
value={selectedPrompt ?? null}
onChange={(value) => {
if (value) {
onSelectPrompt(value);
}
}}
placeholder="Choose a prompt..."
/>
{selectedPrompt && selectedPromptInfo?.description && (
<DescriptionText>{selectedPromptInfo.description}</DescriptionText>
)}
<Title order={4}>{name}</Title>
{description && <DescriptionText>{description}</DescriptionText>}
{promptArguments.length > 0 && (
<>
<Stack gap="sm">
{promptArguments.map((arg) => (
<TextInput
key={arg.name}
@ -72,11 +51,13 @@ export function PromptArgumentsForm({
}
/>
))}
</>
</Stack>
)}
<Button fullWidth onClick={onGetPrompt} disabled={!selectedPrompt}>
Get Prompt
</Button>
<Group justify="flex-end">
<Button size="sm" onClick={onGetPrompt}>
Get Prompt
</Button>
</Group>
</Stack>
);
}