ui: convert Image, Speech, Audio interfaces to shadcn buttons

Replace .btn elements and inline SVG icons with shadcn Button and
@lucide/svelte icons in the image, speech and audio playground tabs.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01UmuGqwNBJNEAMaWsdCDqUC
This commit is contained in:
Claude
2026-06-27 12:05:19 +00:00
parent fc24722258
commit b20be6dcd1
3 changed files with 52 additions and 75 deletions
@@ -4,6 +4,8 @@
import { transcribeAudio } from "../../lib/audioApi"; import { transcribeAudio } from "../../lib/audioApi";
import { playgroundStores } from "../../stores/playgroundActivity"; import { playgroundStores } from "../../stores/playgroundActivity";
import ModelSelector from "./ModelSelector.svelte"; import ModelSelector from "./ModelSelector.svelte";
import { Button } from "$lib/components/ui/button/index.js";
import { Copy, Check } from "@lucide/svelte";
const selectedModelStore = persistentStore<string>("playground-audio-model", ""); const selectedModelStore = persistentStore<string>("playground-audio-model", "");
@@ -169,22 +171,19 @@
{:else if transcriptionResult} {:else if transcriptionResult}
<div class="w-full h-full flex flex-col p-4"> <div class="w-full h-full flex flex-col p-4">
<div class="flex justify-between items-center mb-2"> <div class="flex justify-between items-center mb-2">
<h3 class="font-medium">Transcription Result</h3> <h3 class="pb-0 font-medium">Transcription Result</h3>
<button <Button
class="btn btn-sm" variant="outline"
size="icon-sm"
onclick={copyToClipboard} onclick={copyToClipboard}
title={copied ? 'Copied!' : 'Copy to clipboard'} title={copied ? 'Copied!' : 'Copy to clipboard'}
> >
{#if copied} {#if copied}
<svg class="w-5 h-5 text-green-500" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <Check class="text-success" />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M5 13l4 4L19 7"></path>
</svg>
{:else} {:else}
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"> <Copy />
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 16H6a2 2 0 01-2-2V6a2 2 0 012-2h8a2 2 0 012 2v2m-6 12h8a2 2 0 002-2v-8a2 2 0 00-2-2h-8a2 2 0 00-2 2v8a2 2 0 002 2z"></path>
</svg>
{/if} {/if}
</button> </Button>
</div> </div>
<div class="flex-1 overflow-auto p-3 rounded border border-border bg-background whitespace-pre-wrap"> <div class="flex-1 overflow-auto p-3 rounded border border-border bg-background whitespace-pre-wrap">
{transcriptionResult} {transcriptionResult}
@@ -223,33 +222,21 @@
onchange={handleFileSelect} onchange={handleFileSelect}
bind:this={fileInput} bind:this={fileInput}
/> />
<button <Button variant="outline" onclick={() => fileInput?.click()} disabled={isTranscribing}>
class="btn"
onclick={() => fileInput?.click()}
disabled={isTranscribing}
>
Browse Files Browse Files
</button> </Button>
<div class="flex-1"></div> <div class="flex-1"></div>
{#if isTranscribing} {#if isTranscribing}
<button class="btn bg-red-500 hover:bg-red-600 text-white" onclick={cancelTranscription}> <Button variant="destructive" onclick={cancelTranscription}>Cancel</Button>
Cancel
</button>
{:else} {:else}
<button <Button onclick={transcribe} disabled={!canTranscribe}>Transcribe</Button>
class="btn bg-primary text-primary-foreground hover:opacity-90" <Button
onclick={transcribe} variant="outline"
disabled={!canTranscribe}
>
Transcribe
</button>
<button
class="btn"
onclick={clearAll} onclick={clearAll}
disabled={!selectedFile && !transcriptionResult && !error} disabled={!selectedFile && !transcriptionResult && !error}
> >
Clear Clear
</button> </Button>
{/if} {/if}
</div> </div>
{/if} {/if}
@@ -7,6 +7,7 @@
import ModelSelector from "./ModelSelector.svelte"; import ModelSelector from "./ModelSelector.svelte";
import ExpandableTextarea from "./ExpandableTextarea.svelte"; import ExpandableTextarea from "./ExpandableTextarea.svelte";
import type { ImageApiMode, SdApiLora, SdApiLoraRef } from "../../lib/types"; import type { ImageApiMode, SdApiLora, SdApiLoraRef } from "../../lib/types";
import { Button } from "$lib/components/ui/button/index.js";
const selectedModelStore = persistentStore<string>("playground-image-model", ""); const selectedModelStore = persistentStore<string>("playground-image-model", "");
const selectedSizeStore = persistentStore<string>("playground-image-size", "1024x1024"); const selectedSizeStore = persistentStore<string>("playground-image-size", "1024x1024");
@@ -226,12 +227,9 @@
</select> </select>
{#if isSdapi} {#if isSdapi}
<button <Button variant="outline" onclick={() => showSettings = !showSettings}>
class="px-3 py-2 rounded border border-border bg-background hover:bg-accent transition-colors"
onclick={() => showSettings = !showSettings}
>
{showSettings ? "Hide Settings" : "Settings"} {showSettings ? "Hide Settings" : "Settings"}
</button> </Button>
{/if} {/if}
</div> </div>
@@ -330,13 +328,14 @@
<div> <div>
<span class="text-xs text-muted-foreground block mb-1">LoRAs</span> <span class="text-xs text-muted-foreground block mb-1">LoRAs</span>
<div class="flex items-center gap-2 mb-2"> <div class="flex items-center gap-2 mb-2">
<button <Button
class="px-3 py-1.5 text-sm rounded border border-border bg-background hover:bg-accent transition-colors disabled:opacity-50" variant="outline"
size="sm"
onclick={loadLoras} onclick={loadLoras}
disabled={!$selectedModelStore || isLoadingLoras} disabled={!$selectedModelStore || isLoadingLoras}
> >
{isLoadingLoras ? "Loading..." : lorasLoaded ? "Reload LoRAs" : "Load LoRAs"} {isLoadingLoras ? "Loading..." : lorasLoaded ? "Reload LoRAs" : "Load LoRAs"}
</button> </Button>
{#if lorasLoaded && availableLoras.length > 0} {#if lorasLoaded && availableLoras.length > 0}
<select <select
class="flex-1 px-2 py-1.5 text-sm rounded border border-border bg-background focus:outline-none focus:ring-2 focus:ring-primary" class="flex-1 px-2 py-1.5 text-sm rounded border border-border bg-background focus:outline-none focus:ring-2 focus:ring-primary"
@@ -471,24 +470,25 @@
/> />
<div class="flex flex-row md:flex-col gap-2"> <div class="flex flex-row md:flex-col gap-2">
{#if isGenerating} {#if isGenerating}
<button class="btn bg-red-500 hover:bg-red-600 text-white flex-1 md:flex-none" onclick={cancelGeneration}> <Button variant="destructive" class="flex-1 md:flex-none" onclick={cancelGeneration}>
Cancel Cancel
</button> </Button>
{:else} {:else}
<button <Button
class="btn bg-primary text-primary-foreground hover:opacity-90 flex-1 md:flex-none" class="flex-1 md:flex-none"
onclick={generate} onclick={generate}
disabled={!prompt.trim() || !$selectedModelStore} disabled={!prompt.trim() || !$selectedModelStore}
> >
Generate Generate
</button> </Button>
<button <Button
class="btn flex-1 md:flex-none" variant="outline"
class="flex-1 md:flex-none"
onclick={clearImage} onclick={clearImage}
disabled={generatedImages.length === 0 && !error && !prompt.trim()} disabled={generatedImages.length === 0 && !error && !prompt.trim()}
> >
Clear Clear
</button> </Button>
{/if} {/if}
</div> </div>
</div> </div>
@@ -5,6 +5,8 @@
import { playgroundStores } from "../../stores/playgroundActivity"; import { playgroundStores } from "../../stores/playgroundActivity";
import ModelSelector from "./ModelSelector.svelte"; import ModelSelector from "./ModelSelector.svelte";
import ExpandableTextarea from "./ExpandableTextarea.svelte"; import ExpandableTextarea from "./ExpandableTextarea.svelte";
import { Button } from "$lib/components/ui/button/index.js";
import { RefreshCw, Download } from "@lucide/svelte";
const selectedModelStore = persistentStore<string>("playground-speech-model", ""); const selectedModelStore = persistentStore<string>("playground-speech-model", "");
const selectedVoiceStore = persistentStore<string>("playground-speech-voice", "coral"); const selectedVoiceStore = persistentStore<string>("playground-speech-voice", "coral");
@@ -220,23 +222,16 @@
<option value="(refresh)">(refresh)</option> <option value="(refresh)">(refresh)</option>
</select> </select>
{#if $selectedModelStore && !getVoicesCache()[$selectedModelStore]} {#if $selectedModelStore && !getVoicesCache()[$selectedModelStore]}
<button <Button
class="btn shrink-0" variant="outline"
size="icon"
class="shrink-0"
onclick={refreshVoices} onclick={refreshVoices}
disabled={isLoadingVoices} disabled={isLoadingVoices}
title={isLoadingVoices ? "Loading voices..." : "Load voices for this model"} title={isLoadingVoices ? "Loading voices..." : "Load voices for this model"}
> >
{#if isLoadingVoices} <RefreshCw class={isLoadingVoices ? "animate-spin" : ""} />
<svg class="w-5 h-5 animate-spin" fill="none" viewBox="0 0 24 24"> </Button>
<circle class="opacity-25" cx="12" cy="12" r="10" stroke="currentColor" stroke-width="4"></circle>
<path class="opacity-75" fill="currentColor" d="M4 12a8 8 0 018-8V0C5.373 0 0 5.373 0 12h4zm2 5.291A7.962 7.962 0 014 12H0c0 3.042 1.135 5.824 3 7.938l3-2.647z"></path>
</svg>
{:else}
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 4v5h.582m15.356 2A8.001 8.001 0 004.582 9m0 0H9m11 11v-5h-.581m0 0a8.003 8.003 0 01-15.357-2m15.357 2H15"></path>
</svg>
{/if}
</button>
{/if} {/if}
</div> </div>
</div> </div>
@@ -285,15 +280,9 @@
</span> </span>
{/if} {/if}
</div> </div>
<button <Button variant="outline" size="icon" class="shrink-0" onclick={downloadAudio} title="Download audio file">
class="btn shrink-0" <Download />
onclick={downloadAudio} </Button>
title="Download audio file"
>
<svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4"></path>
</svg>
</button>
</div> </div>
<!-- Audio player with larger controls --> <!-- Audio player with larger controls -->
@@ -327,24 +316,25 @@
/> />
<div class="shrink-0 flex md:flex-col gap-2"> <div class="shrink-0 flex md:flex-col gap-2">
{#if isGenerating} {#if isGenerating}
<button class="btn bg-red-500 hover:bg-red-600 text-white flex-1 md:flex-none" onclick={cancelGeneration}> <Button variant="destructive" class="flex-1 md:flex-none" onclick={cancelGeneration}>
Cancel Cancel
</button> </Button>
{:else} {:else}
<button <Button
class="btn bg-primary text-primary-foreground hover:opacity-90 flex-1 md:flex-none" class="flex-1 md:flex-none"
onclick={generate} onclick={generate}
disabled={!inputText.trim() || !$selectedModelStore} disabled={!inputText.trim() || !$selectedModelStore}
> >
Generate Generate
</button> </Button>
<button <Button
class="btn flex-1 md:flex-none" variant="outline"
class="flex-1 md:flex-none"
onclick={clearInput} onclick={clearInput}
disabled={!inputText.trim()} disabled={!inputText.trim()}
> >
Clear Clear
</button> </Button>
<label class="flex items-center justify-center gap-2 text-sm cursor-pointer"> <label class="flex items-center justify-center gap-2 text-sm cursor-pointer">
<input <input
type="checkbox" type="checkbox"