Reorganize UI controls and improve form interactions (#500)
Reorganizes control placement in the playground interfaces and improves form interactions for better UX, particularly on mobile devices. ## Key Changes - **AudioInterface & ImageInterface**: Moved "Clear" buttons from the top control bar into the action button group below the form inputs for better visual hierarchy and logical grouping - **ImageInterface**: - Added prompt clearing to the `clearImage()` function so the input field is reset when clearing generated images - Updated Clear button disabled state to also check if prompt is empty, allowing users to clear an empty prompt - Added responsive flex styling (`flex-1 md:flex-none`) to the Clear button for better mobile layout - **ExpandableTextarea**: - Imported `untrack` from Svelte to properly handle reactive dependencies - Wrapped `expandedValue.length` in `untrack()` to prevent unnecessary reactivity when setting cursor position - Improved button visibility on mobile by changing opacity from `opacity-0` to `opacity-60` with `md:opacity-0` breakpoint, making the expand button more discoverable on touch devices ## Implementation Details The `untrack()` usage in ExpandableTextarea ensures that reading the text length doesn't create a reactive dependency, preventing potential infinite loops while still allowing the effect to run when `isExpanded` changes.
This commit is contained in:
Generated
-7
@@ -925,7 +925,6 @@
|
|||||||
"integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==",
|
"integrity": "sha512-Y1Cs7hhTc+a5E9Va/xwKlAJoariQyHY+5zBgCZg4PFWNYQ1nMN9sjK1zhw1gK69DuqVP++sht/1GZg1aRwmAXQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@sveltejs/vite-plugin-svelte-inspector": "^4.0.1",
|
"@sveltejs/vite-plugin-svelte-inspector": "^4.0.1",
|
||||||
"debug": "^4.4.1",
|
"debug": "^4.4.1",
|
||||||
@@ -1308,7 +1307,6 @@
|
|||||||
"integrity": "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==",
|
"integrity": "sha512-t7frlewr6+cbx+9Ohpl0NOTKXZNV9xHRmNOvql47BFJKcEG1CxtxlPEEe+gR9uhVWM4DwhnvTF110mIL4yP9RA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"undici-types": "~7.16.0"
|
"undici-types": "~7.16.0"
|
||||||
}
|
}
|
||||||
@@ -1441,7 +1439,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-8.15.0.tgz",
|
||||||
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
"integrity": "sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"acorn": "bin/acorn"
|
"acorn": "bin/acorn"
|
||||||
},
|
},
|
||||||
@@ -3452,7 +3449,6 @@
|
|||||||
"integrity": "sha512-e5lPJi/aui4TO1LpAXIRLySmwXSE8k3b9zoGfd42p67wzxog4WHjiZF3M2uheQih4DGyc25QEV4yRBbpueNiUA==",
|
"integrity": "sha512-e5lPJi/aui4TO1LpAXIRLySmwXSE8k3b9zoGfd42p67wzxog4WHjiZF3M2uheQih4DGyc25QEV4yRBbpueNiUA==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@types/estree": "1.0.8"
|
"@types/estree": "1.0.8"
|
||||||
},
|
},
|
||||||
@@ -3565,7 +3561,6 @@
|
|||||||
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.48.5.tgz",
|
"resolved": "https://registry.npmjs.org/svelte/-/svelte-5.48.5.tgz",
|
||||||
"integrity": "sha512-NB3o70OxfmnE5UPyLr8uH3IV02Q43qJVAuWigYmsSOYsS0s/rHxP0TF81blG0onF/xkhNvZw4G8NfzIX+By5ZQ==",
|
"integrity": "sha512-NB3o70OxfmnE5UPyLr8uH3IV02Q43qJVAuWigYmsSOYsS0s/rHxP0TF81blG0onF/xkhNvZw4G8NfzIX+By5ZQ==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@jridgewell/remapping": "^2.3.4",
|
"@jridgewell/remapping": "^2.3.4",
|
||||||
"@jridgewell/sourcemap-codec": "^1.5.0",
|
"@jridgewell/sourcemap-codec": "^1.5.0",
|
||||||
@@ -3721,7 +3716,6 @@
|
|||||||
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
"integrity": "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "Apache-2.0",
|
"license": "Apache-2.0",
|
||||||
"peer": true,
|
|
||||||
"bin": {
|
"bin": {
|
||||||
"tsc": "bin/tsc",
|
"tsc": "bin/tsc",
|
||||||
"tsserver": "bin/tsserver"
|
"tsserver": "bin/tsserver"
|
||||||
@@ -3900,7 +3894,6 @@
|
|||||||
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
"integrity": "sha512-+Oxm7q9hDoLMyJOYfUYBuHQo+dkAloi33apOPP56pzj+vsdJDzr+j1NISE5pyaAuKL4A3UD34qd0lx5+kfKp2g==",
|
||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"peer": true,
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"esbuild": "^0.25.0",
|
"esbuild": "^0.25.0",
|
||||||
"fdir": "^6.4.4",
|
"fdir": "^6.4.4",
|
||||||
|
|||||||
@@ -141,9 +141,6 @@
|
|||||||
<!-- Model selector -->
|
<!-- Model selector -->
|
||||||
<div class="shrink-0 flex flex-wrap gap-2 mb-4">
|
<div class="shrink-0 flex flex-wrap gap-2 mb-4">
|
||||||
<ModelSelector bind:value={$selectedModelStore} placeholder="Select an audio model..." disabled={isTranscribing} />
|
<ModelSelector bind:value={$selectedModelStore} placeholder="Select an audio model..." disabled={isTranscribing} />
|
||||||
<button class="btn" onclick={clearAll} disabled={!selectedFile && !transcriptionResult && !error}>
|
|
||||||
Clear
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty state for no models configured -->
|
<!-- Empty state for no models configured -->
|
||||||
@@ -241,6 +238,13 @@
|
|||||||
>
|
>
|
||||||
Transcribe
|
Transcribe
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn"
|
||||||
|
onclick={clearAll}
|
||||||
|
disabled={!selectedFile && !transcriptionResult && !error}
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
{/if}
|
{/if}
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
<script lang="ts">
|
<script lang="ts">
|
||||||
|
import { untrack } from "svelte";
|
||||||
import { Maximize2, X } from "lucide-svelte";
|
import { Maximize2, X } from "lucide-svelte";
|
||||||
|
|
||||||
interface Props {
|
interface Props {
|
||||||
@@ -45,7 +46,8 @@
|
|||||||
$effect(() => {
|
$effect(() => {
|
||||||
if (isExpanded && expandedTextarea) {
|
if (isExpanded && expandedTextarea) {
|
||||||
expandedTextarea.focus();
|
expandedTextarea.focus();
|
||||||
expandedTextarea.setSelectionRange(expandedValue.length, expandedValue.length);
|
const len = untrack(() => expandedValue.length);
|
||||||
|
expandedTextarea.setSelectionRange(len, len);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
</script>
|
</script>
|
||||||
@@ -60,7 +62,7 @@
|
|||||||
{disabled}
|
{disabled}
|
||||||
></textarea>
|
></textarea>
|
||||||
<button
|
<button
|
||||||
class="absolute top-2 right-2 p-1.5 rounded-lg opacity-0 group-hover:opacity-100 transition-opacity bg-surface/90 hover:bg-surface border border-gray-200 dark:border-white/10 shadow-sm"
|
class="absolute top-2 right-2 p-1.5 rounded-lg opacity-60 md:opacity-0 group-hover:opacity-100 transition-opacity bg-surface/90 hover:bg-surface border border-gray-200 dark:border-white/10 shadow-sm"
|
||||||
onclick={openExpanded}
|
onclick={openExpanded}
|
||||||
title="Expand to edit"
|
title="Expand to edit"
|
||||||
type="button"
|
type="button"
|
||||||
|
|||||||
@@ -60,6 +60,7 @@
|
|||||||
function clearImage() {
|
function clearImage() {
|
||||||
generatedImage = null;
|
generatedImage = null;
|
||||||
error = null;
|
error = null;
|
||||||
|
prompt = "";
|
||||||
}
|
}
|
||||||
|
|
||||||
function downloadImage() {
|
function downloadImage() {
|
||||||
@@ -117,9 +118,6 @@
|
|||||||
<option value="1024x1792">1024x1792 (SDXL)</option>
|
<option value="1024x1792">1024x1792 (SDXL)</option>
|
||||||
</optgroup>
|
</optgroup>
|
||||||
</select>
|
</select>
|
||||||
<button class="btn" onclick={clearImage} disabled={!generatedImage && !error}>
|
|
||||||
Clear
|
|
||||||
</button>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Empty state for no models configured -->
|
<!-- Empty state for no models configured -->
|
||||||
@@ -192,6 +190,13 @@
|
|||||||
>
|
>
|
||||||
Generate
|
Generate
|
||||||
</button>
|
</button>
|
||||||
|
<button
|
||||||
|
class="btn flex-1 md:flex-none"
|
||||||
|
onclick={clearImage}
|
||||||
|
disabled={!generatedImage && !error && !prompt.trim()}
|
||||||
|
>
|
||||||
|
Clear
|
||||||
|
</button>
|
||||||
{/if}
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
Reference in New Issue
Block a user