Compare commits

..

No commits in common. "9a5acf16fb1f75763222159764957bae247752b4" and "c60d434a4358aad7a9beb55170f5e2dca694a2db" have entirely different histories.

5 changed files with 237 additions and 924 deletions

View File

@ -26,46 +26,6 @@
<link rel="stylesheet" href="{{ '/embed-preview-style.css' | relative_url }}">
<link rel="icon" type="image/x-icon" href="{{ '/favicon.ico' | relative_url }}">
<meta name="description" content="AI prompt viewer">
<style>
@keyframes flash {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
.flash-animation {
animation: flash 1.5s ease-in-out infinite;
}
@keyframes slideUp {
from {
transform: translateY(100%);
opacity: 0;
}
to {
transform: translateY(0);
opacity: 1;
}
}
@keyframes slideDown {
from {
transform: translateY(0);
opacity: 1;
}
to {
transform: translateY(100%);
opacity: 0;
}
}
.diff-enter {
animation: slideUp 0.3s ease-out;
}
.diff-exit {
animation: slideDown 0.3s ease-out;
}
</style>
</head>
<body class="bg-dynamic-background text-dynamic-foreground overflow-hidden">
<!-- Viewer Mode -->
@ -79,9 +39,9 @@
</div>
<!-- Main Content -->
<div class="flex-1 flex flex-col p-2 sm:p-4 h-full overflow-hidden">
<div class="flex-1 flex flex-col p-2 sm:p-4 min-h-0">
<!-- Top Bar with Context Pills and Edit Button -->
<div class="flex justify-between items-start gap-2 mb-1 sm:mb-2 flex-shrink-0">
<div class="flex justify-between items-start gap-2 mb-1 sm:mb-2 max-w-full flex-shrink-0">
<!-- Context Pills -->
<div id="context-pills" class="flex flex-wrap gap-1.5 empty:hidden flex-1 min-w-0 pr-2"></div>
@ -94,98 +54,22 @@
</button>
</div>
<!-- Main Prompt Interface with Floating Diff - Flex-1 to take remaining space -->
<div class="flex-1 relative min-h-0 overflow-hidden">
<!-- Floating Diff View (when enabled and viewport is compact) -->
<div id="diff-view" class="hidden absolute top-2 left-2 right-2 z-10 diff-floating">
<div class="bg-dynamic-background/95 backdrop-blur-sm border border-dynamic-border shadow-lg rounded-lg p-3">
<div class="flex items-center justify-between">
<div class="flex items-center gap-1.5">
<svg class="w-3 h-3 text-dynamic-primary flex-shrink-0" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4 2a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V7.414A2 2 0 0017.414 6L14 2.586A2 2 0 0012.586 2H4zm2 4a1 1 0 011-1h4a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7zm-1 5a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1z" clip-rule="evenodd"/>
</svg>
<span id="diff-filename" class="text-xs font-medium text-dynamic-foreground truncate"></span>
</div>
<div class="flex gap-1 items-center">
<div class="flex rounded-md overflow-hidden">
<button id="diff-accept-diff" class="px-2 py-0.5 bg-green-500 hover:bg-green-600 text-white text-[10px] font-medium transition-colors flex items-center gap-0.5">
<svg class="w-2.5 h-2.5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
</svg>
<span class="hidden sm:inline">Accept</span>
</button>
<button id="diff-reject-diff" class="px-2 py-0.5 bg-red-500 hover:bg-red-600 text-white text-[10px] font-medium transition-colors flex items-center gap-0.5">
<svg class="w-2.5 h-2.5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
</svg>
<span class="hidden sm:inline">Reject</span>
</button>
</div>
<!-- Collapse/Expand button -->
<button id="toggle-diff" class="p-0.5 text-dynamic-muted-foreground hover:text-dynamic-foreground transition-colors" title="Toggle diff view">
<svg class="w-3 h-3 transform transition-transform" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M5.293 7.293a1 1 0 011.414 0L10 10.586l3.293-3.293a1 1 0 111.414 1.414l-4 4a1 1 0 01-1.414 0l-4-4a1 1 0 010-1.414z" clip-rule="evenodd"/>
</svg>
</button>
</div>
</div>
<div id="diff-content" class="space-y-1 transition-all duration-300 overflow-hidden">
<div id="diff-old-content" class="bg-red-50/70 dark:bg-red-950/20 p-2 rounded text-[10px] font-mono whitespace-pre-wrap text-red-700 dark:text-red-400 overflow-x-auto border border-red-200/50 dark:border-red-900/30 max-h-20 overflow-y-auto custom-scrollbar"></div>
<div id="diff-new-content" class="bg-green-50/70 dark:bg-green-950/20 p-2 rounded text-[10px] font-mono whitespace-pre-wrap text-green-700 dark:text-green-400 overflow-x-auto border border-green-200/50 dark:border-green-900/30 max-h-20 overflow-y-auto custom-scrollbar"></div>
</div>
</div>
</div>
<!-- Container for inline diff and prompt -->
<div class="h-full flex flex-col">
<!-- Inline Diff View (when enabled and viewport has space) -->
<div id="diff-view-inline" class="hidden mb-2 flex-shrink-0">
<div class="bg-dynamic-muted border border-dynamic-border rounded-lg p-2">
<div class="flex items-center justify-between mb-1.5">
<div class="flex items-center gap-1.5">
<svg class="w-3 h-3 text-dynamic-primary flex-shrink-0" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4 2a2 2 0 00-2 2v12a2 2 0 002 2h12a2 2 0 002-2V7.414A2 2 0 0017.414 6L14 2.586A2 2 0 0012.586 2H4zm2 4a1 1 0 011-1h4a1 1 0 110 2H7a1 1 0 01-1-1zm1 3a1 1 0 100 2h6a1 1 0 100-2H7zm-1 5a1 1 0 011-1h6a1 1 0 110 2H7a1 1 0 01-1-1z" clip-rule="evenodd"/>
</svg>
<span id="inline-diff-filename" class="text-xs font-medium text-dynamic-foreground truncate"></span>
</div>
<div class="flex rounded-md overflow-hidden">
<button id="inline-accept-diff" class="px-2 py-0.5 bg-green-500 hover:bg-green-600 text-white text-[10px] font-medium transition-colors flex items-center gap-0.5">
<svg class="w-2.5 h-2.5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M16.707 5.293a1 1 0 010 1.414l-8 8a1 1 0 01-1.414 0l-4-4a1 1 0 011.414-1.414L8 12.586l7.293-7.293a1 1 0 011.414 0z" clip-rule="evenodd"/>
</svg>
<span class="hidden sm:inline">Accept</span>
</button>
<button id="inline-reject-diff" class="px-2 py-0.5 bg-red-500 hover:bg-red-600 text-white text-[10px] font-medium transition-colors flex items-center gap-0.5">
<svg class="w-2.5 h-2.5" viewBox="0 0 20 20" fill="currentColor">
<path fill-rule="evenodd" d="M4.293 4.293a1 1 0 011.414 0L10 8.586l4.293-4.293a1 1 0 111.414 1.414L11.414 10l4.293 4.293a1 1 0 01-1.414 1.414L10 11.414l-4.293 4.293a1 1 0 01-1.414-1.414L8.586 10 4.293 5.707a1 1 0 010-1.414z" clip-rule="evenodd"/>
</svg>
<span class="hidden sm:inline">Reject</span>
</button>
</div>
</div>
<div class="space-y-0.5">
<div id="inline-old-content" class="bg-red-50/70 dark:bg-red-950/20 p-1 rounded text-[10px] font-mono whitespace-pre-wrap text-red-700 dark:text-red-400 overflow-x-auto border border-red-200/50 dark:border-red-900/30 max-h-20 overflow-y-auto custom-scrollbar"></div>
<div id="inline-new-content" class="bg-green-50/70 dark:bg-green-950/20 p-1 rounded text-[10px] font-mono whitespace-pre-wrap text-green-700 dark:text-green-400 overflow-x-auto border border-green-200/50 dark:border-green-900/30 max-h-20 overflow-y-auto custom-scrollbar"></div>
</div>
</div>
</div>
<!-- Prompt Container - Full height of parent -->
<div id="prompt-container" class="flex-1 bg-dynamic-muted border border-dynamic-border rounded-xl p-3 relative focus-within:border-dynamic-primary transition-colors flex flex-col min-h-0">
<div id="prompt-text" class="flex-1 text-dynamic-foreground leading-relaxed whitespace-pre-wrap overflow-y-auto custom-scrollbar text-sm sm:text-base duration-300"></div>
<div id="prompt-placeholder" class="text-dynamic-muted-foreground italic absolute top-3 left-3 pointer-events-none text-sm sm:text-base">← Enter your prompt on designer...</div>
</div>
<!-- Main Prompt Interface - Full Height -->
<div class="flex-1 flex flex-col min-h-0">
<div id="prompt-container" class="flex-1 bg-dynamic-muted border border-dynamic-border rounded-xl p-3 relative focus-within:border-dynamic-primary transition-colors flex flex-col min-h-0">
<div id="prompt-text" class="flex-1 text-dynamic-foreground leading-relaxed whitespace-pre-wrap overflow-y-auto custom-scrollbar text-sm sm:text-base"></div>
<div id="prompt-placeholder" class="text-dynamic-muted-foreground italic absolute top-3 left-3 pointer-events-none text-sm sm:text-base">← Enter your prompt on designer...</div>
</div>
</div>
<!-- Bottom Bar - Always visible with reduced height -->
<div class="flex justify-between items-center gap-2 mt-1 pt-1 flex-shrink-0">
<!-- Settings Pills - Smaller -->
<div id="settings-pills" class="flex gap-1 flex-wrap flex-1 min-w-0"></div>
<!-- Bottom Bar -->
<div class="flex justify-between items-center gap-2 mt-1 sm:mt-2 flex-shrink-0">
<!-- Settings Pills -->
<div id="settings-pills" class="flex gap-1 sm:gap-2 flex-wrap flex-1 min-w-0"></div>
<!-- Send Button - Smaller -->
<button id="copy-button" class="w-7 h-7 sm:w-8 sm:h-8 bg-dynamic-primary text-white rounded-full flex items-center justify-center hover:opacity-90 transition-opacity flex-shrink-0 shadow-md" title="Send prompt">
<svg width="14" height="14" class="sm:w-4 sm:h-4" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<!-- Send Button (circular with arrow up) -->
<button id="copy-button" class="w-8 h-8 sm:w-10 sm:h-10 bg-dynamic-primary text-white rounded-full flex items-center justify-center hover:opacity-90 transition-opacity focus-ring flex-shrink-0 shadow-lg touch-target" title="Send prompt">
<svg width="16" height="16" class="sm:w-5 sm:h-5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
<path d="M12 19V5M5 12l7-7 7 7"/>
</svg>
</button>

View File

@ -27,30 +27,8 @@
<link rel="stylesheet" href="{{ '/embed-style.css' | relative_url }}">
<link rel="icon" type="image/x-icon" href="{{ '/favicon.ico' | relative_url }}">
<meta name="description" content="Design and customize embeddable AI prompts">
<style>
.checkerboard-bg {
background-image:
linear-gradient(45deg, rgba(0,0,0,0.06) 25%, transparent 25%),
linear-gradient(-45deg, rgba(0,0,0,0.06) 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, rgba(0,0,0,0.06) 75%),
linear-gradient(-45deg, transparent 75%, rgba(0,0,0,0.06) 75%);
background-size: 20px 20px;
background-position: 0 0, 0 10px, 10px -10px, -10px 0px;
}
.dark .checkerboard-bg {
background-color: #1e1e1e;
background-image:
linear-gradient(45deg, #353535 25%, transparent 25%),
linear-gradient(-45deg, #353535 25%, transparent 25%),
linear-gradient(45deg, transparent 75%, #353535 75%),
linear-gradient(-45deg, transparent 75%, #353535 75%);
background-size: 16px 16px;
background-position: 0 0, 0 8px, 8px -8px, -8px 0px;
}
</style>
</head>
<body class="bg-dynamic-background text-dynamic-foreground overflow-hidden checkerboard-bg">
<body class="bg-dynamic-background text-dynamic-foreground overflow-hidden">
<!-- Site Header -->
<header class="site-header">
<div class="header-left">
@ -59,13 +37,6 @@
<p class="site-slogan sm:hidden">Design and share AI prompts</p>
</div>
<div class="header-right">
<a href="https://blog.fka.dev/blog/2025-06-18-building-a-react-hook-with-ai-a-step-by-step-guide-using-vibe-an-example-post-that-uses-prompts-chat-embed/"
target="_blank"
rel="noopener noreferrer"
class="flex items-center text-xs text-dynamic-muted-foreground hover:text-dynamic-foreground transition-colors mr-3 touch-target hidden sm:inline-flex"
title="View example blog post using prompts.chat embed">
View example blog post
</a>
<button class="dark-mode-toggle touch-target" onclick="toggleDarkMode()" title="Toggle dark mode">
<svg class="mode-icon sun-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="5"></circle><line x1="12" y1="1" x2="12" y2="3"></line><line x1="12" y1="21" x2="12" y2="23"></line><line x1="4.22" y1="4.22" x2="5.64" y2="5.64"></line><line x1="18.36" y1="18.36" x2="19.78" y2="19.78"></line><line x1="1" y1="12" x2="3" y2="12"></line><line x1="21" y1="12" x2="23" y2="12"></line><line x1="4.22" y1="19.78" x2="5.64" y2="18.36"></line><line x1="18.36" y1="5.64" x2="19.78" y2="4.22"></line></svg>
<svg class="mode-icon moon-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" style="display: none;"><path d="M21 12.79A9 9 0 1 1 11.21 3 7 7 0 0 0 21 12.79z"></path></svg>
@ -78,144 +49,127 @@
<!-- Left Panel - Customization -->
<div class="designer-panel w-full lg:w-80 flex flex-col h-auto lg:h-full overflow-hidden order-2 lg:order-1 flex-shrink-0">
<div class="flex-1 overflow-y-auto custom-scrollbar">
<div class="p-3 lg:p-4 space-y-3">
<!-- CONTENT SECTION -->
<div class="p-4 lg:p-6 lg:pt-0 space-y-4">
<!-- Context -->
<div class="space-y-2">
<h3 class="text-xs font-semibold text-dynamic-foreground uppercase tracking-wider border-b border-dynamic-border pb-1">Prompt</h3>
<!-- Example Selector -->
<div class="space-y-1">
<label class="text-xs font-medium text-dynamic-muted-foreground">Load Example</label>
<select id="example-select" class="w-full p-2 bg-dynamic-muted border border-dynamic-border rounded text-xs focus-ring touch-target">
<option value="">Choose an example...</option>
<option value="vibe-coding">Vibe coding (no diff)</option>
<option value="vibe-coding-diff">Vibe coding with diff</option>
<option value="chatgpt">ChatGPT example</option>
<option value="claude">Claude example</option>
<option value="image-analysis">Image analysis</option>
<option value="api-design">API design</option>
<label class="text-sm font-medium text-dynamic-muted-foreground">Context</label>
<input type="text" id="designer-context"
class="w-full p-3 lg:p-2 bg-dynamic-background border border-dynamic-border rounded-lg text-sm focus-ring touch-target"
placeholder="file.py, @web, @codebase, #image">
</div>
<!-- Prompt Text -->
<div class="space-y-2">
<label class="text-sm font-medium text-dynamic-muted-foreground">Prompt Text</label>
<textarea id="designer-prompt"
class="w-full p-3 bg-dynamic-background border border-dynamic-border rounded-lg text-sm resize-none focus-ring custom-scrollbar touch-target"
rows="8"
placeholder="Enter your prompt..."></textarea>
<div class="flex gap-3">
<button type="button" id="vibe-example" class="text-xs text-dynamic-primary hover:text-opacity-80 transition-opacity touch-target py-1">
Vibe coding example →
</button>
<button type="button" id="chat-example" class="text-xs text-dynamic-primary hover:text-opacity-80 transition-opacity touch-target py-1">
Chat example →
</button>
</div>
</div>
<!-- Model & Mode -->
<div class="grid grid-cols-1 sm:grid-cols-2 gap-3">
<div class="space-y-2">
<label class="text-sm font-medium text-dynamic-muted-foreground">Model</label>
<select id="designer-model" class="w-full p-3 lg:p-2 bg-dynamic-background border border-dynamic-border rounded-lg text-sm focus-ring touch-target">
<option value="o3">o3</option>
<option value="GPT 4.1">GPT 4.1</option>
<option value="GPT 4o" selected>GPT 4o</option>
<option value="Claude 3.7 Sonnet">Claude 3.7 Sonnet</option>
<option value="Claude 4 Sonnet">Claude 4 Sonnet</option>
<option value="Claude 4 Opus">Claude 4 Opus</option>
<option value="Gemini 2.5 Pro">Gemini 2.5 Pro</option>
<option value="DeepSeek R1">DeepSeek R1</option>
<option value="custom">[Custom]</option>
</select>
<input type="text" id="designer-custom-model"
class="w-full p-3 lg:p-2 bg-dynamic-background border border-dynamic-border rounded-lg text-sm focus-ring hidden touch-target"
placeholder="Enter custom model name">
</div>
<div class="space-y-2">
<label class="text-sm font-medium text-dynamic-muted-foreground">Mode</label>
<select id="designer-mode-select" class="w-full p-3 lg:p-2 bg-dynamic-background border border-dynamic-border rounded-lg text-sm focus-ring touch-target">
<option value="chat">Chat</option>
<option value="agent">Agent</option>
<option value="manual">Manual</option>
<option value="cloud">Cloud</option>
</select>
</div>
<!-- Context -->
<div class="space-y-1">
<label class="text-xs font-medium text-dynamic-muted-foreground">Context</label>
<input type="text" id="designer-context"
class="w-full p-2 bg-dynamic-background border border-dynamic-border rounded text-xs focus-ring touch-target"
placeholder="file.py, @web, @codebase, #image">
</div>
<!-- Prompt Text -->
<div class="space-y-1">
<label class="text-xs font-medium text-dynamic-muted-foreground">Prompt Text</label>
<textarea id="designer-prompt"
class="w-full p-2 bg-dynamic-background border border-dynamic-border rounded text-xs resize-none focus-ring custom-scrollbar touch-target"
rows="6"
placeholder="Enter your prompt..."></textarea>
</div>
<!-- Options -->
<div class="grid grid-cols-1 sm:grid-cols-2 gap-2 justify-items-start">
<label class="flex items-center space-x-2 touch-target">
<input type="checkbox" id="designer-thinking" class="rounded border-dynamic-border w-4 h-4">
<span class="text-sm text-dynamic-muted-foreground">Thinking</span>
</label>
<label class="flex items-center space-x-2 touch-target">
<input type="checkbox" id="designer-max" class="rounded border-dynamic-border w-4 h-4">
<span class="text-sm text-dynamic-muted-foreground">MAX mode</span>
</label>
</div>
<!-- Theme Mode Selector -->
<div class="space-y-2">
<label class="text-sm font-medium text-dynamic-muted-foreground">Theme Mode</label>
<div class="grid grid-cols-3 gap-2">
<button type="button" id="theme-light" class="theme-mode-btn px-3 py-3 lg:py-2 text-xs font-medium rounded-lg border border-dynamic-border bg-dynamic-background hover:bg-dynamic-muted transition-colors text-center touch-target">
Light
</button>
<button type="button" id="theme-dark" class="theme-mode-btn px-3 py-3 lg:py-2 text-xs font-medium rounded-lg border border-dynamic-border bg-dynamic-background hover:bg-dynamic-muted transition-colors text-center touch-target">
Dark
</button>
<button type="button" id="theme-auto" class="theme-mode-btn px-3 py-3 lg:py-2 text-xs font-medium rounded-lg border border-dynamic-border bg-dynamic-primary text-white transition-colors text-center touch-target">
Auto
</button>
</div>
</div>
<!-- AI SETTINGS SECTION -->
<div class="space-y-2">
<h3 class="text-xs font-semibold text-dynamic-foreground uppercase tracking-wider border-b border-dynamic-border pb-1">AI Settings</h3>
<!-- Model & Mode Grid -->
<div class="grid grid-cols-2 gap-2">
<div class="space-y-1">
<label class="text-xs font-medium text-dynamic-muted-foreground">Model</label>
<select id="designer-model" class="w-full p-2 bg-dynamic-background border border-dynamic-border rounded text-xs focus-ring touch-target">
<option value="o3">o3</option>
<option value="GPT 4.1">GPT 4.1</option>
<option value="GPT 4o" selected>GPT 4o</option>
<option value="Claude 3.7 Sonnet">Claude 3.7 Sonnet</option>
<option value="Claude 4 Sonnet">Claude 4 Sonnet</option>
<option value="Claude 4 Opus">Claude 4 Opus</option>
<option value="Gemini 2.5 Pro">Gemini 2.5 Pro</option>
<option value="DeepSeek R1">DeepSeek R1</option>
<option value="custom">[Custom]</option>
</select>
<input type="text" id="designer-custom-model"
class="w-full p-2 bg-dynamic-background border border-dynamic-border rounded text-xs focus-ring hidden touch-target"
placeholder="Custom model">
</div>
<div class="space-y-1">
<label class="text-xs font-medium text-dynamic-muted-foreground">Mode</label>
<select id="designer-mode-select" class="w-full p-2 bg-dynamic-background border border-dynamic-border rounded text-xs focus-ring touch-target">
<option value="chat">Chat</option>
<option value="agent">Agent</option>
<option value="manual">Manual</option>
<option value="cloud">Cloud</option>
</select>
</div>
</div>
<!-- Options -->
<div class="flex gap-4">
<label class="flex items-center space-x-1.5 touch-target">
<input type="checkbox" id="designer-thinking" class="rounded border-dynamic-border w-3.5 h-3.5">
<span class="text-xs text-dynamic-muted-foreground">Thinking</span>
</label>
<label class="flex items-center space-x-1.5 touch-target">
<input type="checkbox" id="designer-max" class="rounded border-dynamic-border w-3.5 h-3.5">
<span class="text-xs text-dynamic-muted-foreground">MAX mode</span>
</label>
</div>
</div>
<!-- APPEARANCE SECTION -->
<div class="space-y-2">
<h3 class="text-xs font-semibold text-dynamic-foreground uppercase tracking-wider border-b border-dynamic-border pb-1">Appearance</h3>
<!-- Theme Mode -->
<div class="space-y-1">
<label class="text-xs font-medium text-dynamic-muted-foreground">Theme</label>
<div class="grid grid-cols-3 gap-1">
<button type="button" id="theme-light" class="theme-mode-btn px-2 py-1.5 text-xs font-medium rounded border border-dynamic-border bg-dynamic-background hover:bg-dynamic-muted transition-colors text-center touch-target">
Light
</button>
<button type="button" id="theme-dark" class="theme-mode-btn px-2 py-1.5 text-xs font-medium rounded border border-dynamic-border bg-dynamic-background hover:bg-dynamic-muted transition-colors text-center touch-target">
Dark
</button>
<button type="button" id="theme-auto" class="theme-mode-btn px-2 py-1.5 text-xs font-medium rounded border border-dynamic-border bg-dynamic-primary text-white transition-colors text-center touch-target">
Auto
</button>
</div>
</div>
<!-- Color Scheme -->
<div class="space-y-3">
<label class="text-sm font-medium text-dynamic-muted-foreground">Color Scheme</label>
<!-- Color Presets -->
<div class="space-y-1">
<label class="text-xs font-medium text-dynamic-muted-foreground">Colors</label>
<div class="grid grid-cols-8 gap-1">
<button type="button" class="color-preset w-full h-6 rounded border border-dynamic-border hover:border-dynamic-primary transition-colors touch-target"
<div class="space-y-2">
<label class="text-xs text-dynamic-muted-foreground uppercase tracking-wider">Presets</label>
<div class="grid grid-cols-4 gap-2">
<button type="button" class="color-preset w-full h-10 lg:h-8 rounded-lg border-2 border-transparent hover:border-dynamic-primary transition-colors touch-target"
data-light="#6b7280" data-dark="#e5e7eb"
style="background: linear-gradient(135deg, #6b7280 50%, #e5e7eb 50%)"
title="Minimal"></button>
<button type="button" class="color-preset w-full h-6 rounded border border-dynamic-border hover:border-dynamic-primary transition-colors touch-target"
<button type="button" class="color-preset w-full h-10 lg:h-8 rounded-lg border-2 border-transparent hover:border-dynamic-primary transition-colors touch-target"
data-light="#1f2937" data-dark="#9ca3af"
style="background: linear-gradient(135deg, #1f2937 50%, #9ca3af 50%)"
title="Dark Gray"></button>
<button type="button" class="color-preset w-full h-6 rounded border border-dynamic-border hover:border-dynamic-primary transition-colors touch-target"
<button type="button" class="color-preset w-full h-10 lg:h-8 rounded-lg border-2 border-transparent hover:border-dynamic-primary transition-colors touch-target"
data-light="#64748b" data-dark="#94a3b8"
style="background: linear-gradient(135deg, #64748b 50%, #94a3b8 50%)"
title="Dimmed"></button>
<button type="button" class="color-preset w-full h-6 rounded border border-dynamic-border hover:border-dynamic-primary transition-colors touch-target"
<button type="button" class="color-preset w-full h-10 lg:h-8 rounded-lg border-2 border-transparent hover:border-dynamic-primary transition-colors touch-target"
data-light="#3b82f6" data-dark="#60a5fa"
style="background: linear-gradient(135deg, #3b82f6 50%, #60a5fa 50%)"
title="Blue"></button>
<button type="button" class="color-preset w-full h-6 rounded border border-dynamic-border hover:border-dynamic-primary transition-colors touch-target"
<button type="button" class="color-preset w-full h-10 lg:h-8 rounded-lg border-2 border-transparent hover:border-dynamic-primary transition-colors touch-target"
data-light="#10b981" data-dark="#34d399"
style="background: linear-gradient(135deg, #10b981 50%, #34d399 50%)"
title="Green"></button>
<button type="button" class="color-preset w-full h-6 rounded border border-dynamic-border hover:border-dynamic-primary transition-colors touch-target"
<button type="button" class="color-preset w-full h-10 lg:h-8 rounded-lg border-2 border-transparent hover:border-dynamic-primary transition-colors touch-target"
data-light="#8b5cf6" data-dark="#a78bfa"
style="background: linear-gradient(135deg, #8b5cf6 50%, #a78bfa 50%)"
title="Purple"></button>
<button type="button" class="color-preset w-full h-6 rounded border border-dynamic-border hover:border-dynamic-primary transition-colors touch-target"
<button type="button" class="color-preset w-full h-10 lg:h-8 rounded-lg border-2 border-transparent hover:border-dynamic-primary transition-colors touch-target"
data-light="#f97316" data-dark="#fb923c"
style="background: linear-gradient(135deg, #f97316 50%, #fb923c 50%)"
title="Orange"></button>
<button type="button" class="color-preset w-full h-6 rounded border border-dynamic-border hover:border-dynamic-primary transition-colors touch-target"
<button type="button" class="color-preset w-full h-10 lg:h-8 rounded-lg border-2 border-transparent hover:border-dynamic-primary transition-colors touch-target"
data-light="#ec4899" data-dark="#f472b6"
style="background: linear-gradient(135deg, #ec4899 50%, #f472b6 50%)"
title="Pink"></button>
@ -223,115 +177,88 @@
</div>
<!-- Custom Colors -->
<div class="grid grid-cols-2 gap-2">
<div class="space-y-1">
<label class="text-[10px] text-dynamic-muted-foreground">Light</label>
<div class="flex gap-1">
<input type="color" id="designer-light-color" value="#3b82f6" class="w-6 h-6 rounded border border-dynamic-border cursor-pointer touch-target">
<input type="text" id="designer-light-color-text" value="#3b82f6" class="flex-1 px-1 py-1 bg-dynamic-background border border-dynamic-border rounded text-[10px] focus-ring font-mono touch-target" pattern="^#[0-9A-Fa-f]{6}$">
<div class="space-y-2">
<label class="text-xs text-dynamic-muted-foreground uppercase tracking-wider">Custom Colors</label>
<div class="space-y-3">
<div class="flex items-center gap-3">
<div class="flex items-center gap-2 flex-1">
<div class="relative">
<input type="color" id="designer-light-color"
value="#3b82f6"
class="w-12 h-12 lg:w-10 lg:h-10 rounded-lg border-2 border-dynamic-border cursor-pointer hover:border-dynamic-primary transition-colors touch-target">
<div class="absolute inset-0 rounded-lg pointer-events-none" style="background: linear-gradient(135deg, transparent 50%, rgba(0,0,0,0.1) 50%)"></div>
</div>
<div class="flex-1">
<label class="text-xs text-dynamic-muted-foreground block mb-1">Light Mode</label>
<input type="text" id="designer-light-color-text"
value="#3b82f6"
class="w-full px-3 py-2 lg:px-2 lg:py-1 bg-dynamic-background border border-dynamic-border rounded text-xs focus-ring font-mono touch-target"
pattern="^#[0-9A-Fa-f]{6}$">
</div>
</div>
</div>
</div>
<div class="space-y-1">
<label class="text-[10px] text-dynamic-muted-foreground">Dark</label>
<div class="flex gap-1">
<input type="color" id="designer-dark-color" value="#60a5fa" class="w-6 h-6 rounded border border-dynamic-border cursor-pointer touch-target">
<input type="text" id="designer-dark-color-text" value="#60a5fa" class="flex-1 px-1 py-1 bg-dynamic-background border border-dynamic-border rounded text-[10px] focus-ring font-mono touch-target" pattern="^#[0-9A-Fa-f]{6}$">
<div class="flex items-center gap-3">
<div class="flex items-center gap-2 flex-1">
<div class="relative">
<input type="color" id="designer-dark-color"
value="#60a5fa"
class="w-12 h-12 lg:w-10 lg:h-10 rounded-lg border-2 border-dynamic-border cursor-pointer hover:border-dynamic-primary transition-colors touch-target">
<div class="absolute inset-0 rounded-lg pointer-events-none" style="background: linear-gradient(135deg, transparent 50%, rgba(255,255,255,0.1) 50%)"></div>
</div>
<div class="flex-1">
<label class="text-xs text-dynamic-muted-foreground block mb-1">Dark Mode</label>
<input type="text" id="designer-dark-color-text"
value="#60a5fa"
class="w-full px-3 py-2 lg:px-2 lg:py-1 bg-dynamic-background border border-dynamic-border rounded text-xs focus-ring font-mono touch-target"
pattern="^#[0-9A-Fa-f]{6}$">
</div>
</div>
</div>
</div>
</div>
<!-- Height -->
<div class="space-y-1">
<label class="text-xs font-medium text-dynamic-muted-foreground">
Height: <span id="height-value" class="text-dynamic-foreground">400</span>px
</label>
<input type="range" id="designer-height"
class="w-full h-1.5 bg-dynamic-muted rounded-lg appearance-none cursor-pointer slider"
min="200" max="800" value="400" step="50">
<div class="flex justify-between text-[10px] text-dynamic-muted-foreground opacity-60">
<span>200px</span>
<span>800px</span>
</div>
</div>
</div>
<!-- FEATURES SECTION -->
<!-- Height -->
<div class="space-y-2">
<h3 class="text-xs font-semibold text-dynamic-foreground uppercase tracking-wider border-b border-dynamic-border pb-1">Features</h3>
<!-- File Tree -->
<div class="space-y-1">
<div class="flex items-center justify-between">
<label class="text-xs font-medium text-dynamic-muted-foreground">File Tree</label>
<label class="flex items-center space-x-1 text-[10px]">
<input type="checkbox" id="designer-show-filetree" class="rounded border-dynamic-border w-3 h-3" checked>
<span class="text-dynamic-muted-foreground">Show</span>
</label>
</div>
<textarea id="designer-filetree"
class="w-full p-2 bg-dynamic-background border border-dynamic-border rounded text-[10px] resize-none focus-ring custom-scrollbar touch-target font-mono"
rows="4"
placeholder="index.html&#10;styles/main.css&#10;scripts/app.js&#10;components/header.vue"></textarea>
<p class="text-[9px] text-dynamic-muted-foreground opacity-60">
One per line. Use / for folders. Add * to highlight.
</p>
<label class="text-sm font-medium text-dynamic-muted-foreground">
Height: <span id="height-value" class="text-dynamic-foreground">400</span>px
</label>
<input type="range" id="designer-height"
class="w-full h-2 bg-dynamic-muted rounded-lg appearance-none cursor-pointer slider"
min="200" max="800" value="400" step="50">
<div class="flex justify-between text-xs text-dynamic-muted-foreground">
<span>200px</span>
<span>800px</span>
</div>
<!-- Diff View -->
<div class="space-y-1">
<div class="flex items-center justify-between">
<label class="text-xs font-medium text-dynamic-muted-foreground">Diff View</label>
<label class="flex items-center space-x-1 text-[10px]">
<input type="checkbox" id="designer-show-diff" class="rounded border-dynamic-border w-3 h-3">
<span class="text-dynamic-muted-foreground">Show</span>
</label>
</div>
<div id="diff-fields" class="space-y-2 hidden">
<div class="grid grid-cols-2 gap-2">
<div>
<label class="text-[10px] text-dynamic-muted-foreground">Filename</label>
<input type="text" id="designer-diff-filename"
class="w-full p-1.5 bg-dynamic-background border border-dynamic-border rounded text-[10px] focus-ring touch-target font-mono"
placeholder="file.tsx">
</div>
<div>
<label class="text-[10px] text-dynamic-muted-foreground">Flash</label>
<select id="designer-flash-button" class="w-full p-1.5 bg-dynamic-background border border-dynamic-border rounded text-[10px] focus-ring touch-target">
<option value="none">None</option>
<option value="accept">Accept</option>
<option value="reject">Reject</option>
</select>
</div>
</div>
<div>
<label class="text-[10px] text-dynamic-muted-foreground">Old Text</label>
<textarea id="designer-diff-old"
class="w-full p-2 bg-dynamic-background border border-dynamic-border rounded text-[10px] resize-none focus-ring custom-scrollbar touch-target font-mono"
rows="3"
placeholder="// Original code..."></textarea>
</div>
<div>
<label class="text-[10px] text-dynamic-muted-foreground">New Text</label>
<textarea id="designer-diff-new"
class="w-full p-2 bg-dynamic-background border border-dynamic-border rounded text-[10px] resize-none focus-ring custom-scrollbar touch-target font-mono"
rows="3"
placeholder="// Updated code..."></textarea>
</div>
<p class="text-[9px] text-dynamic-muted-foreground opacity-50">
Keep short for URL sharing.
</p>
</div>
</div>
<!-- File Tree -->
<div class="space-y-2">
<div class="flex items-center justify-between">
<label class="text-sm font-medium text-dynamic-muted-foreground">File Tree</label>
<label class="flex items-center space-x-1.5 text-xs">
<input type="checkbox" id="designer-show-filetree" class="rounded border-dynamic-border w-3.5 h-3.5" checked>
<span class="text-dynamic-muted-foreground">Show in preview</span>
</label>
</div>
<textarea id="designer-filetree"
class="w-full p-3 bg-dynamic-background border border-dynamic-border rounded-lg text-sm resize-none focus-ring custom-scrollbar touch-target font-mono"
rows="6"
placeholder="Enter files (one per line):&#10;index.html&#10;styles/main.css&#10;scripts/app.js&#10;components/header.vue"></textarea>
<p class="text-xs text-dynamic-muted-foreground">
Enter filenames one per line. Use forward slashes for folders (e.g., folder/file.js).
Add * at the end of a filename to highlight it (e.g., main.js*)
</p>
</div>
</div>
</div>
<!-- Generate Buttons - Fixed at bottom -->
<div class="p-3 lg:p-4 space-y-2 border-t border-dynamic-border bg-dynamic-muted">
<button id="generate-embed" class="w-full bg-dynamic-primary text-white p-2.5 rounded text-xs font-medium hover:opacity-90 transition-opacity touch-target">
<div class="p-4 lg:p-6 space-y-3 border-t border-dynamic-border bg-dynamic-muted lg:pb-0">
<button id="generate-embed" class="w-full bg-dynamic-primary text-white p-3 lg:p-2 rounded-lg text-sm font-medium hover:opacity-90 transition-opacity touch-target">
Generate Embed Code
</button>
<button id="reset-settings" class="text-[10px] text-dynamic-muted-foreground hover:text-dynamic-foreground transition-colors opacity-50 hover:opacity-100 touch-target">
<button id="reset-settings" class="text-[11px] text-dynamic-muted-foreground hover:text-dynamic-foreground transition-colors opacity-60 hover:opacity-100 touch-target">
Reset settings
</button>
</div>

View File

@ -26,12 +26,7 @@ class EmbedPreview {
lightColor: this.params.lightColor || '#3b82f6',
darkColor: this.params.darkColor || '#60a5fa',
themeMode: this.params.themeMode || 'auto',
filetree: this.params.filetree ? decodeURIComponent(this.params.filetree).split('\n').filter(f => f.trim()) : [],
showDiff: this.params.showDiff === 'true',
diffFilename: this.params.diffFilename || '',
diffOldText: this.params.diffOldText ? decodeURIComponent(this.params.diffOldText) : '',
diffNewText: this.params.diffNewText ? decodeURIComponent(this.params.diffNewText) : '',
flashButton: this.params.flashButton || 'none'
filetree: this.params.filetree ? decodeURIComponent(this.params.filetree).split('\n').filter(f => f.trim()) : []
};
}
@ -39,7 +34,6 @@ class EmbedPreview {
this.setupColors();
this.setupElements();
this.render();
this.setupResizeListener();
}
setupColors() {
@ -193,7 +187,6 @@ class EmbedPreview {
}
render() {
this.renderDiffView();
this.renderContextPills();
this.renderPromptText();
this.renderSettingsPills();
@ -322,21 +315,21 @@ class EmbedPreview {
createSettingPill(text, type) {
const pill = document.createElement('div');
pill.className = 'rounded-full text-[10px] font-medium flex items-center gap-1';
pill.className = 'rounded-full text-xs font-medium flex items-center gap-1.5';
let icon = '';
// Use different styling based on pill type
if (type === 'mode') {
// Mode pill keeps the background with reduced padding
// Mode pill keeps the background
if (this.isDarkMode) {
pill.className += ' px-2 py-1 bg-dynamic-primary/20 text-dynamic-foreground border border-dynamic-primary/30';
pill.className += ' px-3 py-2 bg-dynamic-primary/20 text-dynamic-foreground border border-dynamic-primary/30';
} else {
pill.className += ' px-2 py-1 bg-dynamic-primary/10 text-dynamic-foreground border border-dynamic-primary/20';
pill.className += ' px-3 py-2 bg-dynamic-primary/10 text-dynamic-foreground border border-dynamic-primary/20';
}
} else {
// Model, thinking, and max pills only have text color
pill.className += ' pl-0.5 text-dynamic-primary';
pill.className += ' pl-1 text-dynamic-primary';
}
switch (type) {
@ -348,16 +341,16 @@ class EmbedPreview {
const modeType = text.toLowerCase();
switch (modeType) {
case 'agent':
icon = '<svg class="w-2.5 h-2.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M18.18 8.04c-.78-.84-1.92-1.54-3.18-1.54-1.44 0-2.7.93-3.48 2.25-.78-1.32-2.04-2.25-3.48-2.25-1.26 0-2.4.7-3.18 1.54-.87.94-1.36 2.11-1.36 3.46 0 1.35.49 2.52 1.36 3.46.78.84 1.92 1.54 3.18 1.54 1.44 0 2.7-.93 3.48-2.25.78 1.32 2.04 2.25 3.48 2.25 1.26 0 2.4-.7 3.18-1.54.87-.94 1.36-2.11 1.36-3.46 0-1.35-.49-2.52-1.36-3.46z"/></svg>';
icon = '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5"><path d="M18.18 8.04c-.78-.84-1.92-1.54-3.18-1.54-1.44 0-2.7.93-3.48 2.25-.78-1.32-2.04-2.25-3.48-2.25-1.26 0-2.4.7-3.18 1.54-.87.94-1.36 2.11-1.36 3.46 0 1.35.49 2.52 1.36 3.46.78.84 1.92 1.54 3.18 1.54 1.44 0 2.7-.93 3.48-2.25.78 1.32 2.04 2.25 3.48 2.25 1.26 0 2.4-.7 3.18-1.54.87-.94 1.36-2.11 1.36-3.46 0-1.35-.49-2.52-1.36-3.46z"/></svg>';
break;
case 'chat':
icon = '<svg class="w-2.5 h-2.5" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M18 10c0 3.866-3.582 7-8 7a8.841 8.841 0 01-4.083-.98L2 17l1.338-3.123C2.493 12.767 2 11.434 2 10c0-3.866 3.582-7 8-7s8 3.134 8 7zM7 9H5v2h2V9zm8 0h-2v2h2V9zM9 9h2v2H9V9z" clip-rule="evenodd"/></svg>';
icon = '<svg class="w-3 h-3" viewBox="0 0 20 20" fill="currentColor"><path fill-rule="evenodd" d="M18 10c0 3.866-3.582 7-8 7a8.841 8.841 0 01-4.083-.98L2 17l1.338-3.123C2.493 12.767 2 11.434 2 10c0-3.866 3.582-7 8-7s8 3.134 8 7zM7 9H5v2h2V9zm8 0h-2v2h2V9zM9 9h2v2H9V9z" clip-rule="evenodd"/></svg>';
break;
case 'manual':
icon = '<svg class="w-2.5 h-2.5" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 2v20M2 12h20"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>';
icon = '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 2v20M2 12h20"/><circle cx="12" cy="12" r="3" fill="currentColor"/></svg>';
break;
case 'cloud':
icon = '<svg class="w-2.5 h-2.5" viewBox="0 0 20 20" fill="currentColor"><path d="M5.5 16a3.5 3.5 0 01-.369-6.98 4 4 0 117.753-1.977A4.5 4.5 0 1113.5 16h-8z"/></svg>';
icon = '<svg class="w-3 h-3" viewBox="0 0 20 20" fill="currentColor"><path d="M5.5 16a3.5 3.5 0 01-.369-6.98 4 4 0 117.753-1.977A4.5 4.5 0 1113.5 16h-8z"/></svg>';
break;
default:
icon = '';
@ -367,12 +360,12 @@ class EmbedPreview {
break;
case 'thinking':
// Brain icon for thinking mode
icon = '<svg class="w-2.5 h-2.5" viewBox="0 0 24 24" fill="currentColor"><path d="M19.864 8.465a3.505 3.505 0 0 0-3.03-4.449A3.005 3.005 0 0 0 14 2a2.98 2.98 0 0 0-2 .78A2.98 2.98 0 0 0 10 2c-1.301 0-2.41.831-2.825 2.015a3.505 3.505 0 0 0-3.039 4.45A4.028 4.028 0 0 0 2 12c0 1.075.428 2.086 1.172 2.832A4.067 4.067 0 0 0 3 16c0 1.957 1.412 3.59 3.306 3.934A3.515 3.515 0 0 0 9.5 22c.979 0 1.864-.407 2.5-1.059A3.484 3.484 0 0 0 14.5 22a3.51 3.51 0 0 0 3.19-2.06 4.006 4.006 0 0 0 3.138-5.108A4.003 4.003 0 0 0 22 12a4.028 4.028 0 0 0-2.136-3.535zM9.5 20c-.711 0-1.33-.504-1.47-1.198L7.818 18H7c-1.103 0-2-.897-2-2 0-.352.085-.682.253-.981l.456-.816-.784-.51A2.019 2.019 0 0 1 4 12c0-.977.723-1.824 1.682-1.972l1.693-.26-1.059-1.346a1.502 1.502 0 0 1 1.498-2.39L9 6.207V5a1 1 0 0 1 2 0v13.5c0 .827-.673 1.5-1.5 1.5zm9.575-6.308-.784.51.456.816c.168.3.253.63.253.982 0 1.103-.897 2-2.05 2h-.818l-.162.802A1.502 1.502 0 0 1 14.5 20c-.827 0-1.5-.673-1.5-1.5V5c0-.552.448-1 1-1s1 .448 1 1.05v1.207l1.186-.225a1.502 1.502 0 0 1 1.498 2.39l-1.059 1.347 1.693.26A2.002 2.002 0 0 1 20 12c0 .683-.346 1.315-.925 1.692z"></path></svg>';
icon = '<svg class="w-3 h-3" viewBox="0 0 24 24" fill="currentColor"><path d="M19.864 8.465a3.505 3.505 0 0 0-3.03-4.449A3.005 3.005 0 0 0 14 2a2.98 2.98 0 0 0-2 .78A2.98 2.98 0 0 0 10 2c-1.301 0-2.41.831-2.825 2.015a3.505 3.505 0 0 0-3.039 4.45A4.028 4.028 0 0 0 2 12c0 1.075.428 2.086 1.172 2.832A4.067 4.067 0 0 0 3 16c0 1.957 1.412 3.59 3.306 3.934A3.515 3.515 0 0 0 9.5 22c.979 0 1.864-.407 2.5-1.059A3.484 3.484 0 0 0 14.5 22a3.51 3.51 0 0 0 3.19-2.06 4.006 4.006 0 0 0 3.138-5.108A4.003 4.003 0 0 0 22 12a4.028 4.028 0 0 0-2.136-3.535zM9.5 20c-.711 0-1.33-.504-1.47-1.198L7.818 18H7c-1.103 0-2-.897-2-2 0-.352.085-.682.253-.981l.456-.816-.784-.51A2.019 2.019 0 0 1 4 12c0-.977.723-1.824 1.682-1.972l1.693-.26-1.059-1.346a1.502 1.502 0 0 1 1.498-2.39L9 6.207V5a1 1 0 0 1 2 0v13.5c0 .827-.673 1.5-1.5 1.5zm9.575-6.308-.784.51.456.816c.168.3.253.63.253.982 0 1.103-.897 2-2.05 2h-.818l-.162.802A1.502 1.502 0 0 1 14.5 20c-.827 0-1.5-.673-1.5-1.5V5c0-.552.448-1 1-1s1 .448 1 1.05v1.207l1.186-.225a1.502 1.502 0 0 1 1.498 2.39l-1.059 1.347 1.693.26A2.002 2.002 0 0 1 20 12c0 .683-.346 1.315-.925 1.692z"></path></svg>';
pill.innerHTML = icon + '<span>' + text + '</span>';
break;
case 'max':
// Lightning bolt icon for MAX mode
icon = '<svg class="w-2.5 h-2.5" viewBox="0 0 20 20" fill="currentColor"><path d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z"/></svg>';
icon = '<svg class="w-3 h-3" viewBox="0 0 20 20" fill="currentColor"><path d="M11.3 1.046A1 1 0 0112 2v5h4a1 1 0 01.82 1.573l-7 10A1 1 0 018 18v-5H4a1 1 0 01-.82-1.573l7-10a1 1 0 011.12-.38z"/></svg>';
pill.innerHTML = icon + '<span>' + text + '</span>';
break;
}
@ -380,171 +373,8 @@ class EmbedPreview {
return pill;
}
setupResizeListener() {
let resizeTimeout;
window.addEventListener('resize', () => {
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(() => {
this.renderDiffView();
}, 100);
});
}
renderDiffView() {
const diffView = document.getElementById('diff-view');
const diffViewInline = document.getElementById('diff-view-inline');
const promptText = document.getElementById('prompt-text');
if (!diffView || !diffViewInline) return;
const viewportHeight = window.innerHeight;
const isCompact = viewportHeight < 400;
if (this.config.showDiff && (this.config.diffOldText || this.config.diffNewText)) {
// Determine which view to show based on viewport height
if (isCompact) {
// Show floating diff view
diffView.classList.remove('hidden');
diffView.classList.add('diff-enter');
diffViewInline.classList.add('hidden');
this.setupDiffContent('diff-view');
} else {
// Show inline diff view
diffViewInline.classList.remove('hidden');
diffView.classList.add('hidden');
this.setupDiffContent('diff-view-inline');
// Reset margin when switching to inline view
if (promptText) {
promptText.style.marginTop = '0';
}
}
} else {
diffView.classList.add('hidden');
diffViewInline.classList.add('hidden');
// Reset margin when diff is hidden
if (promptText) {
promptText.style.marginTop = '0';
}
}
}
setupDiffContent(containerId) {
const container = document.getElementById(containerId);
if (!container) return;
// Count lines in old and new content
const oldLines = this.config.diffOldText ? this.config.diffOldText.split('\n').length : 0;
const newLines = this.config.diffNewText ? this.config.diffNewText.split('\n').length : 0;
// Set filename with line counts
const filenameElement = container.querySelector('[id$="-filename"]');
if (filenameElement) {
const filename = this.config.diffFilename || 'untitled';
filenameElement.innerHTML = `
<span>${filename}</span>
<span class="ml-2 text-[10px] font-mono">
<span class="text-green-600 dark:text-green-400">+${newLines}</span>
<span class="text-red-600 dark:text-red-400">-${oldLines}</span>
</span>
`;
}
// Set diff content
const oldContent = container.querySelector('[id$="-old-content"]');
const newContent = container.querySelector('[id$="-new-content"]');
if (oldContent) {
oldContent.textContent = this.config.diffOldText || '(empty)';
// Update colors based on dark mode
if (this.isDarkMode) {
oldContent.style.backgroundColor = 'rgba(127, 29, 29, 0.15)';
oldContent.style.color = '#fca5a5';
oldContent.style.borderColor = 'rgba(127, 29, 29, 0.3)';
} else {
oldContent.style.backgroundColor = 'rgba(254, 226, 226, 0.7)';
oldContent.style.color = '#b91c1c';
oldContent.style.borderColor = 'rgba(252, 165, 165, 0.5)';
}
}
if (newContent) {
newContent.textContent = this.config.diffNewText || '(empty)';
// Update colors based on dark mode
if (this.isDarkMode) {
newContent.style.backgroundColor = 'rgba(20, 83, 45, 0.15)';
newContent.style.color = '#86efac';
newContent.style.borderColor = 'rgba(20, 83, 45, 0.3)';
} else {
newContent.style.backgroundColor = 'rgba(220, 252, 231, 0.7)';
newContent.style.color = '#15803d';
newContent.style.borderColor = 'rgba(134, 239, 172, 0.5)';
}
}
// Apply flash animation to buttons if configured
const acceptButton = container.querySelector('[id$="-accept-diff"]');
const rejectButton = container.querySelector('[id$="-reject-diff"]');
if (this.config.flashButton === 'accept' && acceptButton) {
acceptButton.classList.add('flash-animation');
// Remove from reject button if it exists
if (rejectButton) rejectButton.classList.remove('flash-animation');
} else if (this.config.flashButton === 'reject' && rejectButton) {
rejectButton.classList.add('flash-animation');
// Remove from accept button if it exists
if (acceptButton) acceptButton.classList.remove('flash-animation');
} else {
// Remove animation from both if 'none'
if (acceptButton) acceptButton.classList.remove('flash-animation');
if (rejectButton) rejectButton.classList.remove('flash-animation');
}
// Setup toggle button for floating view only
if (containerId === 'diff-view') {
const toggleButton = container.querySelector('#toggle-diff');
const diffContent = container.querySelector('#diff-content');
const promptText = document.getElementById('prompt-text');
if (toggleButton && diffContent && promptText) {
// Remove existing listeners
const newToggleButton = toggleButton.cloneNode(true);
toggleButton.parentNode.replaceChild(newToggleButton, toggleButton);
// Set initial state - collapsed when compact
let isExpanded = false;
diffContent.style.maxHeight = '0';
diffContent.style.overflow = 'hidden';
newToggleButton.querySelector('svg').style.transform = 'rotate(-90deg)';
// Function to update prompt margin based on diff view height
const updatePromptMargin = () => {
const diffHeight = container.offsetHeight;
promptText.parentElement.style.paddingTop = `${diffHeight + 16}px`; // 16px for some breathing room
};
// Set initial margin
setTimeout(updatePromptMargin, 0);
newToggleButton.addEventListener('click', () => {
isExpanded = !isExpanded;
if (isExpanded) {
diffContent.style.maxHeight = diffContent.scrollHeight + 'px';
newToggleButton.querySelector('svg').style.transform = 'rotate(0deg)';
// Update margin after animation
setTimeout(updatePromptMargin, 300);
} else {
diffContent.style.maxHeight = '0';
diffContent.style.overflow = 'hidden';
newToggleButton.querySelector('svg').style.transform = 'rotate(-90deg)';
// Update margin after animation
setTimeout(updatePromptMargin, 300);
}
});
}
}
}
highlightMentions(text) {
return text.replaceAll(/@(https?:\/\/[^\s]+.*?|\w+\.\w+|\w+)/g, '<span class="mention">@$1</span>');
return text.replace(/@(\w+)/g, '<span class="mention">@$1</span>');
}
capitalizeFirst(str) {

View File

@ -34,12 +34,7 @@ class EmbedDesigner {
height: this.params.height || savedConfig.height || '400',
themeMode: this.params.themeMode || savedConfig.themeMode || 'auto',
filetree: this.params.filetree ? decodeURIComponent(this.params.filetree).split('\n').filter(f => f.trim()) : (savedConfig.filetree || []),
showFiletree: savedConfig.showFiletree !== undefined ? savedConfig.showFiletree : true,
showDiff: this.params.showDiff === 'true' || savedConfig.showDiff || false,
diffFilename: this.params.diffFilename || savedConfig.diffFilename || '',
diffOldText: this.params.diffOldText ? decodeURIComponent(this.params.diffOldText) : (savedConfig.diffOldText || ''),
diffNewText: this.params.diffNewText ? decodeURIComponent(this.params.diffNewText) : (savedConfig.diffNewText || ''),
flashButton: this.params.flashButton || savedConfig.flashButton || 'none'
showFiletree: savedConfig.showFiletree !== undefined ? savedConfig.showFiletree : true
};
}
@ -62,12 +57,7 @@ class EmbedDesigner {
height: '400',
themeMode: 'auto',
filetree: [],
showFiletree: true,
showDiff: false,
diffFilename: '',
diffOldText: '',
diffNewText: '',
flashButton: 'none'
showFiletree: true
};
}
@ -91,12 +81,7 @@ class EmbedDesigner {
height: config.height || '400',
themeMode: config.themeMode || 'auto',
filetree: config.filetree || [],
showFiletree: config.showFiletree !== undefined ? config.showFiletree : true,
showDiff: config.showDiff || false,
diffFilename: config.diffFilename || '',
diffOldText: config.diffOldText || '',
diffNewText: config.diffNewText || '',
flashButton: config.flashButton || 'none'
showFiletree: config.showFiletree !== undefined ? config.showFiletree : true
};
}
}
@ -192,27 +177,6 @@ class EmbedDesigner {
darkColorPicker.value = this.config.darkColor;
darkColorText.value = this.config.darkColor;
}
// Set up diff view
const showDiffCheckbox = document.getElementById('designer-show-diff');
const diffFields = document.getElementById('diff-fields');
if (showDiffCheckbox) {
showDiffCheckbox.checked = this.config.showDiff || false;
if (diffFields) {
diffFields.classList.toggle('hidden', !this.config.showDiff);
}
}
// Set diff field values
const diffFilename = document.getElementById('designer-diff-filename');
const diffOldText = document.getElementById('designer-diff-old');
const diffNewText = document.getElementById('designer-diff-new');
const flashButton = document.getElementById('designer-flash-button');
if (diffFilename) diffFilename.value = this.config.diffFilename || '';
if (diffOldText) diffOldText.value = this.config.diffOldText || '';
if (diffNewText) diffNewText.value = this.config.diffNewText || '';
if (flashButton) flashButton.value = this.config.flashButton || 'none';
}
updateThemeModeButtons() {
@ -231,7 +195,7 @@ class EmbedDesigner {
setupDesignerEvents() {
// Form changes update preview
['designer-prompt', 'designer-context', 'designer-mode-select', 'designer-thinking', 'designer-max', 'designer-filetree', 'designer-show-filetree', 'designer-diff-filename', 'designer-diff-old', 'designer-diff-new', 'designer-flash-button'].forEach(id => {
['designer-prompt', 'designer-context', 'designer-mode-select', 'designer-thinking', 'designer-max', 'designer-filetree', 'designer-show-filetree'].forEach(id => {
const element = document.getElementById(id);
if (element) {
element.addEventListener('input', () => this.updateConfigFromForm());
@ -239,18 +203,6 @@ class EmbedDesigner {
}
});
// Diff view toggle
const showDiffCheckbox = document.getElementById('designer-show-diff');
const diffFields = document.getElementById('diff-fields');
if (showDiffCheckbox) {
showDiffCheckbox.addEventListener('change', (e) => {
if (diffFields) {
diffFields.classList.toggle('hidden', !e.target.checked);
}
this.updateConfigFromForm();
});
}
// Theme mode buttons
document.querySelectorAll('.theme-mode-btn').forEach(btn => {
btn.addEventListener('click', (e) => {
@ -377,11 +329,7 @@ class EmbedDesigner {
height: '400',
themeMode: 'auto',
filetree: [],
showFiletree: true,
showDiff: false,
diffFilename: '',
diffOldText: '',
diffNewText: ''
showFiletree: true
};
// Update UI to reflect defaults
this.setupDesignerElements();
@ -390,37 +338,14 @@ class EmbedDesigner {
}
});
// Example select
const exampleSelect = document.getElementById('example-select');
if (exampleSelect) {
exampleSelect.addEventListener('change', (e) => {
const example = e.target.value;
if (example) {
switch (example) {
case 'vibe-coding':
this.loadVibeCodingExample();
break;
case 'vibe-coding-diff':
this.loadVibeCodingDiffExample();
break;
case 'chatgpt':
this.loadChatGPTExample();
break;
case 'claude':
this.loadClaudeExample();
break;
case 'image-analysis':
this.loadImageAnalysisExample();
break;
case 'api-design':
this.loadAPIDesignExample();
break;
}
// Reset select to placeholder after loading
exampleSelect.value = '';
}
});
}
// Example buttons
document.getElementById('vibe-example').addEventListener('click', () => {
this.loadVibeExample();
});
document.getElementById('chat-example').addEventListener('click', () => {
this.loadChatExample();
});
// Modal events
document.getElementById('close-modal').addEventListener('click', () => this.hideEmbedModal());
@ -458,12 +383,7 @@ class EmbedDesigner {
height: heightSlider ? heightSlider.value : '400',
themeMode: this.config.themeMode || 'auto',
filetree: document.getElementById('designer-filetree').value.split('\n').map(f => f.trim()).filter(f => f),
showFiletree: document.getElementById('designer-show-filetree').checked,
showDiff: document.getElementById('designer-show-diff').checked,
diffFilename: document.getElementById('designer-diff-filename').value,
diffOldText: document.getElementById('designer-diff-old').value,
diffNewText: document.getElementById('designer-diff-new').value,
flashButton: document.getElementById('designer-flash-button').value
showFiletree: document.getElementById('designer-show-filetree').checked
};
this.updatePreview();
@ -537,20 +457,6 @@ class EmbedDesigner {
if (this.config.darkColor !== '#60a5fa') params.set('darkColor', this.config.darkColor);
if (this.config.themeMode !== 'auto') params.set('themeMode', this.config.themeMode);
if (this.config.showFiletree && this.config.filetree && this.config.filetree.length > 0) params.set('filetree', encodeURIComponent(this.config.filetree.join('\n')));
if (this.config.showDiff) {
params.set('showDiff', 'true');
if (this.config.diffFilename) params.set('diffFilename', this.config.diffFilename);
if (this.config.flashButton && this.config.flashButton !== 'none') params.set('flashButton', this.config.flashButton);
// Truncate diff text if too long to prevent URL length issues
if (this.config.diffOldText) {
const truncated = this.config.diffOldText.substring(0, 100);
params.set('diffOldText', encodeURIComponent(truncated)+'...');
}
if (this.config.diffNewText) {
const truncated = this.config.diffNewText.substring(0, 100);
params.set('diffNewText', encodeURIComponent(truncated)+'...');
}
}
params.set('preview', 'true');
return `/embed-preview/?${params.toString()}`;
@ -568,20 +474,6 @@ class EmbedDesigner {
if (this.config.darkColor !== '#60a5fa') params.set('darkColor', this.config.darkColor);
if (this.config.themeMode !== 'auto') params.set('themeMode', this.config.themeMode);
if (this.config.showFiletree && this.config.filetree && this.config.filetree.length > 0) params.set('filetree', encodeURIComponent(this.config.filetree.join('\n')));
if (this.config.showDiff) {
params.set('showDiff', 'true');
if (this.config.diffFilename) params.set('diffFilename', this.config.diffFilename);
if (this.config.flashButton && this.config.flashButton !== 'none') params.set('flashButton', this.config.flashButton);
// Truncate diff text if too long to prevent URL length issues
if (this.config.diffOldText) {
const truncated = this.config.diffOldText.substring(0, 150);
params.set('diffOldText', encodeURIComponent(truncated));
}
if (this.config.diffNewText) {
const truncated = this.config.diffNewText.substring(0, 150);
params.set('diffNewText', encodeURIComponent(truncated));
}
}
return `${window.location.origin}/embed-preview/?${params.toString()}`;
}
@ -662,26 +554,42 @@ class EmbedDesigner {
}, duration);
}
loadVibeCodingExample() {
// Vibe coding example WITHOUT diff
loadVibeExample() {
// Set vibe coding example values
document.getElementById('designer-prompt').value =
`Refactor my React ProductList component:
- Extract filtering logic to custom hook
- Split into smaller components
- Add TypeScript types
- Implement virtualization
`I'm working on a React e-commerce app. The current ProductList component is getting messy with too much logic.
Currently handles display, filtering, sorting, and pagination in one file.
Can you help me refactor it to:
1. Extract the filtering logic into a custom hook
2. Split the large component into smaller, reusable pieces
3. Add proper TypeScript types
4. Implement virtualization for better performance with large product lists
@web Check React Query docs for data fetching patterns.`;
The component currently handles products display, filtering by category/price, sorting, and pagination all in one file. I want a cleaner architecture.`;
document.getElementById('designer-context').value = '@codebase, ProductList.tsx';
document.getElementById('designer-context').value = '@codebase, ProductList.tsx, components/, hooks/';
document.getElementById('designer-filetree').value =
`src/components/ProductList.tsx*
`src/
src/components/
src/components/ProductList.tsx*
src/components/ProductCard.tsx
src/components/ProductGrid.tsx
src/components/Filters/
src/components/Filters/CategoryFilter.tsx
src/components/Filters/PriceRangeFilter.tsx
src/components/Filters/index.tsx
src/hooks/
src/hooks/useProducts.ts
src/types/product.ts`;
src/hooks/useFilters.ts
src/hooks/useInfiniteScroll.ts
src/types/
src/types/product.ts
src/api/
src/api/products.ts
src/utils/
src/utils/formatters.ts
package.json
tsconfig.json`;
// Set vibe coding settings
document.getElementById('designer-model').value = 'Claude 4 Opus';
@ -710,98 +618,30 @@ src/types/product.ts`;
this.config.themeMode = 'dark';
this.updateThemeModeButtons();
// No diff for this example
document.getElementById('designer-show-diff').checked = false;
document.getElementById('diff-fields').classList.add('hidden');
document.getElementById('designer-flash-button').value = 'none';
// Update config from form
this.updateConfigFromForm();
this.showNotification('Vibe coding example loaded!');
}
loadVibeCodingDiffExample() {
// Vibe coding WITH diff - user giving feedback on suggested changes
document.getElementById('designer-prompt').value =
`Actually, don't use Error | null for the error state. Instead:
- Create a custom ApiError type with code, message, and retry()
- Add an AbortController for request cancellation
- Include error boundary integration
- Show me how to handle network vs API errors differently
Also add a refetch function that the UI can call.`;
document.getElementById('designer-context').value = '@codebase, useProducts.ts';
document.getElementById('designer-filetree').value =
`src/hooks/useProducts.ts*
src/types/errors.ts
src/utils/api.ts`;
// Set same settings as regular vibe coding
document.getElementById('designer-model').value = 'Claude 4 Opus';
document.getElementById('designer-mode-select').value = 'agent';
document.getElementById('designer-thinking').checked = true;
document.getElementById('designer-max').checked = true;
document.getElementById('designer-show-filetree').checked = true;
// Set height and colors
const heightSlider = document.getElementById('designer-height');
const heightValue = document.getElementById('height-value');
if (heightSlider) {
heightSlider.value = '500';
if (heightValue) {
heightValue.textContent = '500';
}
}
document.getElementById('designer-light-color').value = '#8b5cf6';
document.getElementById('designer-light-color-text').value = '#8b5cf6';
document.getElementById('designer-dark-color').value = '#a78bfa';
document.getElementById('designer-dark-color-text').value = '#a78bfa';
this.config.themeMode = 'dark';
this.updateThemeModeButtons();
// Add diff view showing the previous suggestion
document.getElementById('designer-show-diff').checked = true;
document.getElementById('diff-fields').classList.remove('hidden');
document.getElementById('designer-diff-filename').value = 'useProducts.ts';
document.getElementById('designer-diff-old').value =
`const [products, setProducts] = useState([]);
const [loading, setLoading] = useState(true);`;
document.getElementById('designer-diff-new').value =
`const [products, setProducts] = useState<Product[]>([]);
const [loading, setLoading] = useState(true);
const [error, setError] = useState<Error | null>(null);`;
// Flash accept button for this example with diff
document.getElementById('designer-flash-button').value = 'accept';
// Update config from form
this.updateConfigFromForm();
this.showNotification('Vibe coding with diff loaded!');
}
loadChatGPTExample() {
// ChatGPT example with green colors
loadChatExample() {
// Set chat example values
document.getElementById('designer-prompt').value =
`I'm planning a dinner party for 8 people this weekend. One person is vegetarian, another is gluten-free, and I want to make something impressive but not too complicated.
Can you suggest a menu with appetizers, main course, and dessert that would work for everyone? I have about 4 hours to prepare everything and a moderate cooking skill level.`;
document.getElementById('designer-context').value = '#Kitchen Layout.png, #Pantry Inventory.jpg';
document.getElementById('designer-context').value = '#Screenshot Kitchen Layout.png, Recipes Collection.pdf';
document.getElementById('designer-filetree').value = '';
// ChatGPT settings
// Set chat settings
document.getElementById('designer-model').value = 'GPT 4o';
document.getElementById('designer-mode-select').value = 'chat';
document.getElementById('designer-thinking').checked = false;
document.getElementById('designer-max').checked = false;
document.getElementById('designer-show-filetree').checked = false;
// Set height and colors for ChatGPT
// Set height and colors for chat example
const heightSlider = document.getElementById('designer-height');
const heightValue = document.getElementById('height-value');
if (heightSlider) {
@ -811,188 +651,20 @@ Can you suggest a menu with appetizers, main course, and dessert that would work
}
}
// ChatGPT green color scheme
// Set friendly color scheme (green)
document.getElementById('designer-light-color').value = '#10b981';
document.getElementById('designer-light-color-text').value = '#10b981';
document.getElementById('designer-dark-color').value = '#34d399';
document.getElementById('designer-dark-color-text').value = '#34d399';
// Light theme for ChatGPT
// Set light theme mode for chat
this.config.themeMode = 'light';
this.updateThemeModeButtons();
// Clear diff view
document.getElementById('designer-show-diff').checked = false;
document.getElementById('diff-fields').classList.add('hidden');
document.getElementById('designer-flash-button').value = 'none';
// Update config from form
this.updateConfigFromForm();
this.showNotification('ChatGPT example loaded!');
}
loadClaudeExample() {
// Claude example with orange colors - daily usage
document.getElementById('designer-prompt').value =
`Help me write a professional email to decline a job offer while keeping the door open for future opportunities.
Context:
- Received offer from TechCorp as Senior Engineer
- Great team and compensation, but role doesn't align with my career goals
- Want to maintain good relationship with the hiring manager Sarah
- Interested in their upcoming ML team expansion next year
Keep it warm but professional, around 150-200 words.`;
document.getElementById('designer-context').value = '';
document.getElementById('designer-filetree').value = '';
// Claude settings
document.getElementById('designer-model').value = 'Claude 3.7 Sonnet';
document.getElementById('designer-mode-select').value = 'chat';
document.getElementById('designer-thinking').checked = false;
document.getElementById('designer-max').checked = false;
document.getElementById('designer-show-filetree').checked = false;
// Set height and colors for Claude
const heightSlider = document.getElementById('designer-height');
const heightValue = document.getElementById('height-value');
if (heightSlider) {
heightSlider.value = '350';
if (heightValue) {
heightValue.textContent = '350';
}
}
// Claude orange color scheme
document.getElementById('designer-light-color').value = '#f97316';
document.getElementById('designer-light-color-text').value = '#f97316';
document.getElementById('designer-dark-color').value = '#fb923c';
document.getElementById('designer-dark-color-text').value = '#fb923c';
// Auto theme for Claude
this.config.themeMode = 'auto';
this.updateThemeModeButtons();
// Clear diff view
document.getElementById('designer-show-diff').checked = false;
document.getElementById('diff-fields').classList.add('hidden');
document.getElementById('designer-flash-button').value = 'none';
// Update config from form
this.updateConfigFromForm();
this.showNotification('Claude example loaded!');
}
loadImageAnalysisExample() {
// Image analysis example
document.getElementById('designer-prompt').value =
`Analyze these UI screenshots and provide detailed feedback on:
- Visual hierarchy and layout
- Color scheme and contrast
- Typography choices
- Accessibility concerns
- Mobile responsiveness issues`;
document.getElementById('designer-context').value = '#Homepage Desktop.png, #Homepage Mobile.png, #Dashboard View.jpg';
document.getElementById('designer-filetree').value = '';
// Image analysis settings
document.getElementById('designer-model').value = 'GPT 4.1';
document.getElementById('designer-mode-select').value = 'chat';
document.getElementById('designer-thinking').checked = false;
document.getElementById('designer-max').checked = false;
document.getElementById('designer-show-filetree').checked = false;
// Set height and colors
const heightSlider = document.getElementById('designer-height');
const heightValue = document.getElementById('height-value');
if (heightSlider) {
heightSlider.value = '400';
if (heightValue) {
heightValue.textContent = '400';
}
}
// Pink/purple color scheme for design
document.getElementById('designer-light-color').value = '#ec4899';
document.getElementById('designer-light-color-text').value = '#ec4899';
document.getElementById('designer-dark-color').value = '#f472b6';
document.getElementById('designer-dark-color-text').value = '#f472b6';
// Light theme
this.config.themeMode = 'light';
this.updateThemeModeButtons();
// Clear diff view
document.getElementById('designer-show-diff').checked = false;
document.getElementById('diff-fields').classList.add('hidden');
document.getElementById('designer-flash-button').value = 'none';
// Update config from form
this.updateConfigFromForm();
this.showNotification('Image analysis example loaded!');
}
loadAPIDesignExample() {
// API design example
document.getElementById('designer-prompt').value =
`Design a RESTful API for a task management system with:
- User authentication
- Project and task CRUD operations
- Team collaboration features
- Real-time notifications
Include endpoint definitions, request/response schemas, and error handling patterns.`;
document.getElementById('designer-context').value = '@Web, openapi.yaml';
document.getElementById('designer-filetree').value =
`api/
api/v1/
api/v1/users/
api/v1/projects/
api/v1/tasks/
docs/openapi.yaml*`;
// API design settings
document.getElementById('designer-model').value = 'Claude 4 Opus';
document.getElementById('designer-mode-select').value = 'manual';
document.getElementById('designer-thinking').checked = true;
document.getElementById('designer-max').checked = false;
document.getElementById('designer-show-filetree').checked = true;
// Set height and colors
const heightSlider = document.getElementById('designer-height');
const heightValue = document.getElementById('height-value');
if (heightSlider) {
heightSlider.value = '500';
if (heightValue) {
heightValue.textContent = '500';
}
}
// Blue color scheme for API
document.getElementById('designer-light-color').value = '#3b82f6';
document.getElementById('designer-light-color-text').value = '#3b82f6';
document.getElementById('designer-dark-color').value = '#60a5fa';
document.getElementById('designer-dark-color-text').value = '#60a5fa';
// Dark theme for technical
this.config.themeMode = 'dark';
this.updateThemeModeButtons();
// Clear diff view
document.getElementById('designer-show-diff').checked = false;
document.getElementById('diff-fields').classList.add('hidden');
document.getElementById('designer-flash-button').value = 'none';
// Update config from form
this.updateConfigFromForm();
this.showNotification('API design example loaded!');
this.showNotification('Chat example loaded!');
}
}

View File

@ -249,7 +249,7 @@ body.dark-mode .designer-panel {
/* Adjust the scrollable content area */
.designer-panel > .flex-1 {
padding-top: calc(var(--header-height));
padding-top: calc(var(--header-height) + 1rem);
height: 100%;
box-sizing: border-box;
display: flex;