feat(playground): wire F7 components into Studio shell

This commit is contained in:
diegosouzapw
2026-05-28 11:20:27 -03:00
parent d516cf0506
commit e7e16b416d
3 changed files with 29 additions and 25 deletions

View File

@@ -13,6 +13,8 @@ import type { StreamMetrics } from "@/shared/schemas/playground";
// Lazy-load tabs to reduce initial bundle size
const ChatTab = dynamic(() => import("./components/tabs/ChatTab"), { ssr: false });
const ApiTab = dynamic(() => import("./components/tabs/ApiTab"), { ssr: false });
const CompareTab = dynamic(() => import("./components/tabs/CompareTab"), { ssr: false });
const BuildTab = dynamic(() => import("./components/tabs/BuildTab"), { ssr: false });
const INITIAL_METRICS: StreamMetrics = {
ttftMs: null,
@@ -74,6 +76,13 @@ export function PlaygroundStudio() {
activeTab={effectiveTab}
onTabChange={handleTabChange}
metrics={metrics}
exportState={{
endpoint: configState.endpoint,
baseUrl: configState.baseUrl,
model: configState.model,
systemPrompt: configState.systemPrompt,
params: configState.params,
}}
/>
{/* Main content area: tab content + config pane */}
@@ -84,27 +93,13 @@ export function PlaygroundStudio() {
<ChatTab configState={configState} onMetricsUpdate={handleMetricsUpdate} />
)}
{effectiveTab === "compare" && (
<div className="flex items-center justify-center h-full text-text-muted">
<div className="text-center space-y-2">
<span className="material-symbols-outlined text-[48px] text-text-muted/30">
compare
</span>
<p className="text-sm">Compare tab F7 implementation pending</p>
</div>
</div>
<CompareTab configState={configState} />
)}
{effectiveTab === "api" && (
<ApiTab configState={configState} />
)}
{effectiveTab === "build" && (
<div className="flex items-center justify-center h-full text-text-muted">
<div className="text-center space-y-2">
<span className="material-symbols-outlined text-[48px] text-text-muted/30">
build
</span>
<p className="text-sm">Build tab F7 implementation pending</p>
</div>
</div>
<BuildTab configState={configState} />
)}
</div>

View File

@@ -6,6 +6,8 @@ import { useState } from "react";
import ParamSliders, { type PlaygroundParams } from "./ParamSliders";
import type { PlaygroundEndpoint } from "@/lib/playground/codeExport";
import { endpointToPath } from "@/lib/playground/codeExport";
import PresetPicker from "./PresetPicker";
import ImprovePromptButton from "./ImprovePromptButton";
export interface ConfigState {
endpoint: PlaygroundEndpoint;
@@ -82,8 +84,8 @@ export default function StudioConfigPane({ configState, setConfigState }: Studio
</div>
<div className="flex flex-col gap-5 p-4">
{/* SLOT_PRESETS: F7 substituirá com PresetPicker */}
{/* SLOT_PRESETS */}
{/* PresetPicker — injected by F7 */}
<PresetPicker configState={configState} setConfigState={setConfigState} />
{/* Endpoint */}
<div className="flex flex-col gap-1.5">
@@ -129,8 +131,8 @@ export default function StudioConfigPane({ configState, setConfigState }: Studio
rows={4}
className="w-full text-xs bg-surface border border-border rounded px-2 py-1.5 focus:outline-none focus:ring-1 focus:ring-primary text-text-main resize-y"
/>
{/* SLOT_IMPROVE: F7 substituirá com ImprovePromptButton */}
{/* SLOT_IMPROVE */}
{/* ImprovePromptButton — injected by F7 */}
<ImprovePromptButton configState={configState} setConfigState={setConfigState} />
</div>
{/* Param sliders */}

View File

@@ -4,7 +4,9 @@
import { useState } from "react";
import TokenCostCounter from "./TokenCostCounter";
import ExportCodeModal from "./ExportCodeModal";
import type { StreamMetrics } from "@/shared/schemas/playground";
import type { PlaygroundState } from "@/lib/playground/codeExport";
export type StudioTab = "chat" | "compare" | "api" | "build";
@@ -12,6 +14,8 @@ interface StudioTopBarProps {
activeTab: StudioTab;
onTabChange: (tab: StudioTab) => void;
metrics: StreamMetrics;
/** Optional playground state for the Export code modal. If omitted, a minimal state is used. */
exportState?: PlaygroundState;
}
interface TabConfig {
@@ -29,9 +33,9 @@ const TABS: TabConfig[] = [
/**
* Top bar with tab switcher, token/cost counter, and export code button.
* Export code modal is a placeholder in F6; F7 replaces it with ExportCodeModal.
* Export code modal uses ExportCodeModal (F7) when exportState is provided.
*/
export default function StudioTopBar({ activeTab, onTabChange, metrics }: StudioTopBarProps) {
export default function StudioTopBar({ activeTab, onTabChange, metrics, exportState }: StudioTopBarProps) {
const [exportOpen, setExportOpen] = useState(false);
return (
@@ -77,8 +81,11 @@ export default function StudioTopBar({ activeTab, onTabChange, metrics }: Studio
</div>
</div>
{/* Export code placeholder modal — F7 replaces with ExportCodeModal */}
{exportOpen && (
{/* Export code modal — uses ExportCodeModal (F7) */}
{exportOpen && exportState != null && (
<ExportCodeModal state={exportState} onClose={() => setExportOpen(false)} />
)}
{exportOpen && exportState == null && (
<div
className="fixed inset-0 z-50 flex items-center justify-center bg-black/40"
onClick={() => setExportOpen(false)}
@@ -98,7 +105,7 @@ export default function StudioTopBar({ activeTab, onTabChange, metrics }: Studio
</button>
</div>
<p className="text-sm text-text-muted">
Export code modal F7 implementation pending.
No playground state available to export.
</p>
</div>
</div>