Browse Source

feat(47-01): add inline parameters infrastructure - types, hook, and panel component

- Add parametersExpanded field to 5 generation node data types (NanoBanana, GenerateVideo, Generate3D, GenerateAudio, LLMGenerate)
- Create useInlineParameters hook for localStorage-backed global setting (default: false)
- Create InlineParameterPanel component with collapsible UI and chevron toggle
- All TypeScript compiles without new errors
handoff-20260429-1057
shrimbly 4 months ago
parent
commit
e405e46bf9
  1. 62
      src/components/nodes/InlineParameterPanel.tsx
  2. 24
      src/hooks/useInlineParameters.ts
  3. 5
      src/types/nodes.ts

62
src/components/nodes/InlineParameterPanel.tsx

@ -0,0 +1,62 @@
"use client";
import { ReactNode } from "react";
interface InlineParameterPanelProps {
expanded: boolean;
onToggle: () => void;
children: ReactNode;
nodeId: string;
}
/**
* Collapsible parameter container for inline display within generation nodes.
* Provides a chevron toggle button and smooth expand/collapse transitions.
*/
export function InlineParameterPanel({
expanded,
onToggle,
children,
nodeId,
}: InlineParameterPanelProps) {
return (
<div className="w-full">
{/* Chevron toggle button - acts as visual boundary */}
<button
type="button"
onClick={onToggle}
className="nodrag nopan w-full flex items-center justify-center py-1 text-neutral-500 hover:text-neutral-300 transition-colors"
aria-label={expanded ? "Collapse parameters" : "Expand parameters"}
aria-expanded={expanded}
aria-controls={`params-${nodeId}`}
>
<svg
className="w-4 h-4 transition-transform duration-200"
style={{ transform: expanded ? "rotate(180deg)" : "rotate(0deg)" }}
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
strokeWidth="2"
strokeLinecap="round"
strokeLinejoin="round"
>
<polyline points="6 9 12 15 18 9" />
</svg>
</button>
{/* Collapsible content area */}
<div
id={`params-${nodeId}`}
className="overflow-hidden transition-all duration-200"
style={{
maxHeight: expanded ? "2000px" : "0",
opacity: expanded ? 1 : 0,
}}
>
<div className="nodrag nopan nowheel bg-neutral-900/60 px-3 pb-3">
<div className="space-y-2">{children}</div>
</div>
</div>
</div>
);
}

24
src/hooks/useInlineParameters.ts

@ -0,0 +1,24 @@
import { useState, useCallback } from "react";
const INLINE_PARAMS_KEY = "node-banana-inline-parameters";
export function useInlineParameters() {
const [enabled, setEnabled] = useState(() => {
try {
return localStorage.getItem(INLINE_PARAMS_KEY) === "true";
} catch {
return false;
}
});
const setInlineParameters = useCallback((value: boolean) => {
try {
localStorage.setItem(INLINE_PARAMS_KEY, String(value));
} catch {
// localStorage not available
}
setEnabled(value);
}, []);
return { inlineParametersEnabled: enabled, setInlineParameters };
}

5
src/types/nodes.ts

@ -177,6 +177,7 @@ export interface NanoBananaNodeData extends BaseNodeData {
useImageSearch: boolean; // Only available for Nano Banana 2
parameters?: Record<string, unknown>; // Model-specific parameters for external providers
inputSchema?: ModelInputDef[]; // Model's input schema for dynamic handles
parametersExpanded?: boolean; // Collapse state for inline parameter display
status: NodeStatus;
error: string | null;
imageHistory: CarouselImageItem[]; // Carousel history (IDs only)
@ -195,6 +196,7 @@ export interface GenerateVideoNodeData extends BaseNodeData {
selectedModel?: SelectedModel; // Required for video generation (no legacy fallback)
parameters?: Record<string, unknown>; // Model-specific parameters
inputSchema?: ModelInputDef[]; // Model's input schema for dynamic handles
parametersExpanded?: boolean; // Collapse state for inline parameter display
status: NodeStatus;
error: string | null;
videoHistory: CarouselVideoItem[]; // Carousel history (IDs only)
@ -214,6 +216,7 @@ export interface Generate3DNodeData extends BaseNodeData {
selectedModel?: SelectedModel;
parameters?: Record<string, unknown>;
inputSchema?: ModelInputDef[];
parametersExpanded?: boolean; // Collapse state for inline parameter display
status: NodeStatus;
error: string | null;
}
@ -238,6 +241,7 @@ export interface GenerateAudioNodeData extends BaseNodeData {
selectedModel?: SelectedModel; // Required for audio generation
parameters?: Record<string, unknown>; // Model-specific parameters (voice, speed, etc.)
inputSchema?: ModelInputDef[]; // Model's input schema for dynamic handles
parametersExpanded?: boolean; // Collapse state for inline parameter display
status: NodeStatus;
error: string | null;
audioHistory: CarouselAudioItem[]; // Carousel history (IDs only)
@ -258,6 +262,7 @@ export interface LLMGenerateNodeData extends BaseNodeData {
model: LLMModelType;
temperature: number;
maxTokens: number;
parametersExpanded?: boolean; // Collapse state for inline parameter display
status: NodeStatus;
error: string | null;
}

Loading…
Cancel
Save