Prechádzať zdrojové kódy

refac: prompt editor

Timothy Jaeryang Baek 5 mesiacov pred
rodič
commit
0cc6e20d65

+ 186 - 0
src/lib/components/workspace/Prompts/PromptEditor.svelte

@@ -0,0 +1,186 @@
+<script lang="ts">
+	import { onMount, tick, getContext } from 'svelte';
+
+	import Textarea from '$lib/components/common/Textarea.svelte';
+	import { toast } from 'svelte-sonner';
+
+	export let onSubmit: Function;
+	export let edit = false;
+	export let prompt = null;
+
+	const i18n = getContext('i18n');
+
+	let loading = false;
+
+	let title = '';
+	let command = '';
+	let content = '';
+
+	$: if (!edit) {
+		command = title !== '' ? `${title.replace(/\s+/g, '-').toLowerCase()}` : '';
+	}
+
+	const submitHandler = async () => {
+		loading = true;
+
+		if (validateCommandString(command)) {
+			await onSubmit({
+				title,
+				command,
+				content
+			});
+		} else {
+			toast.error(
+				$i18n.t('Only alphanumeric characters and hyphens are allowed in the command string.')
+			);
+		}
+
+		loading = false;
+	};
+
+	const validateCommandString = (inputString) => {
+		// Regular expression to match only alphanumeric characters and hyphen
+		const regex = /^[a-zA-Z0-9-]+$/;
+
+		// Test the input string against the regular expression
+		return regex.test(inputString);
+	};
+
+	onMount(async () => {
+		if (prompt) {
+			title = prompt.title;
+			await tick();
+
+			command = prompt.command.at(0) === '/' ? prompt.command.slice(1) : prompt.command;
+			content = prompt.content;
+		}
+	});
+</script>
+
+<form
+	class="flex flex-col max-w-2xl mx-auto mt-4 mb-10 pb-10"
+	on:submit|preventDefault={() => {
+		submitHandler();
+	}}
+>
+	<div class="my-2">
+		<div class=" text-sm font-semibold mb-2">{$i18n.t('Title')}*</div>
+
+		<div>
+			<input
+				class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
+				placeholder={$i18n.t('Add a short title for this prompt')}
+				bind:value={title}
+				required
+			/>
+		</div>
+	</div>
+
+	<div class="my-2">
+		<div class=" text-sm font-semibold mb-2">{$i18n.t('Command')}*</div>
+
+		<div class="flex items-center mb-1">
+			<div
+				class="bg-gray-200 dark:bg-gray-600 font-semibold px-3 py-1 border border-r-0 dark:border-gray-600 rounded-l-lg"
+			>
+				/
+			</div>
+			<input
+				class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-r-lg"
+				placeholder={$i18n.t('short-summary')}
+				bind:value={command}
+				required
+				disabled={edit}
+			/>
+		</div>
+
+		<div class="text-xs text-gray-400 dark:text-gray-500">
+			{$i18n.t('Only')}
+			<span class=" text-gray-600 dark:text-gray-300 font-medium"
+				>{$i18n.t('alphanumeric characters and hyphens')}</span
+			>
+			{$i18n.t('are allowed - Activate this command by typing')}&nbsp;"<span
+				class=" text-gray-600 dark:text-gray-300 font-medium"
+			>
+				/{command}
+			</span>" &nbsp;
+			{$i18n.t('to chat input.')}
+		</div>
+	</div>
+
+	<div class="my-2">
+		<div class="flex w-full justify-between">
+			<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt Content')}*</div>
+		</div>
+
+		<div class="mt-2">
+			<div>
+				<Textarea
+					className="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none overflow-y-hidden rounded-lg resize-none"
+					placeholder={$i18n.t('Write a summary in 50 words that summarizes [topic or keyword].')}
+					bind:value={content}
+					rows={6}
+					required
+				/>
+			</div>
+
+			<div class="text-xs text-gray-400 dark:text-gray-500">
+				ⓘ {$i18n.t('Format your variables using brackets like this:')}&nbsp;<span
+					class=" text-gray-600 dark:text-gray-300 font-medium"
+					>{'{{'}{$i18n.t('variable')}{'}}'}</span
+				>.
+				{$i18n.t('Make sure to enclose them with')}
+				<span class=" text-gray-600 dark:text-gray-300 font-medium">{'{{'}</span>
+				{$i18n.t('and')}
+				<span class=" text-gray-600 dark:text-gray-300 font-medium">{'}}'}</span>.
+			</div>
+
+			<div class="text-xs text-gray-400 dark:text-gray-500">
+				{$i18n.t('Utilize')}<span class=" text-gray-600 dark:text-gray-300 font-medium">
+					{` {{CLIPBOARD}}`}</span
+				>
+				{$i18n.t('variable to have them replaced with clipboard content.')}
+			</div>
+		</div>
+	</div>
+
+	<div class="my-2 flex justify-end">
+		<button
+			class=" text-sm px-3 py-2 transition rounded-xl {loading
+				? ' cursor-not-allowed bg-gray-100 dark:bg-gray-800'
+				: ' bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-800'} flex"
+			type="submit"
+			disabled={loading}
+		>
+			<div class=" self-center font-medium">{$i18n.t('Save & Create')}</div>
+
+			{#if loading}
+				<div class="ml-1.5 self-center">
+					<svg
+						class=" w-4 h-4"
+						viewBox="0 0 24 24"
+						fill="currentColor"
+						xmlns="http://www.w3.org/2000/svg"
+						><style>
+							.spinner_ajPY {
+								transform-origin: center;
+								animation: spinner_AtaB 0.75s infinite linear;
+							}
+							@keyframes spinner_AtaB {
+								100% {
+									transform: rotate(360deg);
+								}
+							}
+						</style><path
+							d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
+							opacity=".25"
+						/><path
+							d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
+							class="spinner_ajPY"
+						/></svg
+					>
+				</div>
+			{/if}
+		</button>
+	</div>
+</form>

+ 27 - 207
src/routes/(app)/workspace/prompts/create/+page.svelte

@@ -1,58 +1,26 @@
 <script>
 <script>
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
-
 	import { goto } from '$app/navigation';
 	import { goto } from '$app/navigation';
 	import { prompts } from '$lib/stores';
 	import { prompts } from '$lib/stores';
 	import { onMount, tick, getContext } from 'svelte';
 	import { onMount, tick, getContext } from 'svelte';
 
 
 	import { createNewPrompt, getPrompts } from '$lib/apis/prompts';
 	import { createNewPrompt, getPrompts } from '$lib/apis/prompts';
-	import Textarea from '$lib/components/common/Textarea.svelte';
-
-	const i18n = getContext('i18n');
-
-	let loading = false;
-
-	// ///////////
-	// Prompt
-	// ///////////
-
-	let title = '';
-	let command = '';
-	let content = '';
-
-	$: command = title !== '' ? `${title.replace(/\s+/g, '-').toLowerCase()}` : '';
-
-	const submitHandler = async () => {
-		loading = true;
+	import PromptEditor from '$lib/components/workspace/Prompts/PromptEditor.svelte';
 
 
-		if (validateCommandString(command)) {
-			const prompt = await createNewPrompt(localStorage.token, command, title, content).catch(
-				(error) => {
-					toast.error(error);
+	let prompt = null;
+	const onSubmit = async ({ title, command, content }) => {
+		const prompt = await createNewPrompt(localStorage.token, command, title, content).catch(
+			(error) => {
+				toast.error(error);
 
 
-					return null;
-				}
-			);
-
-			if (prompt) {
-				await prompts.set(await getPrompts(localStorage.token));
-				await goto('/workspace/prompts');
+				return null;
 			}
 			}
-		} else {
-			toast.error(
-				$i18n.t('Only alphanumeric characters and hyphens are allowed in the command string.')
-			);
-		}
-
-		loading = false;
-	};
-
-	const validateCommandString = (inputString) => {
-		// Regular expression to match only alphanumeric characters and hyphen
-		const regex = /^[a-zA-Z0-9-]+$/;
+		);
 
 
-		// Test the input string against the regular expression
-		return regex.test(inputString);
+		if (prompt) {
+			await prompts.set(await getPrompts(localStorage.token));
+			await goto('/workspace/prompts');
+		}
 	};
 	};
 
 
 	onMount(async () => {
 	onMount(async () => {
@@ -63,13 +31,14 @@
 				)
 				)
 			)
 			)
 				return;
 				return;
-			const prompt = JSON.parse(event.data);
-			console.log(prompt);
-
-			title = prompt.title;
-			await tick();
-			content = prompt.content;
-			command = prompt.command;
+			const _prompt = JSON.parse(event.data);
+			console.log(_prompt);
+
+			prompt = {
+				title: _prompt.title,
+				command: _prompt.command,
+				content: _prompt.content
+			};
 		});
 		});
 
 
 		if (window.opener ?? false) {
 		if (window.opener ?? false) {
@@ -77,167 +46,18 @@
 		}
 		}
 
 
 		if (sessionStorage.prompt) {
 		if (sessionStorage.prompt) {
-			const prompt = JSON.parse(sessionStorage.prompt);
-
-			console.log(prompt);
-			title = prompt.title;
-			await tick();
-			content = prompt.content;
-			command = prompt.command.at(0) === '/' ? prompt.command.slice(1) : prompt.command;
+			const _prompt = JSON.parse(sessionStorage.prompt);
 
 
+			prompt = {
+				title: _prompt.title,
+				command: _prompt.command,
+				content: _prompt.content
+			};
 			sessionStorage.removeItem('prompt');
 			sessionStorage.removeItem('prompt');
 		}
 		}
 	});
 	});
 </script>
 </script>
 
 
 <div class="w-full max-h-full">
 <div class="w-full max-h-full">
-	<button
-		class="flex space-x-1"
-		on:click={() => {
-			history.back();
-		}}
-	>
-		<div class=" self-center">
-			<svg
-				xmlns="http://www.w3.org/2000/svg"
-				viewBox="0 0 20 20"
-				fill="currentColor"
-				class="w-4 h-4"
-			>
-				<path
-					fill-rule="evenodd"
-					d="M17 10a.75.75 0 01-.75.75H5.612l4.158 3.96a.75.75 0 11-1.04 1.08l-5.5-5.25a.75.75 0 010-1.08l5.5-5.25a.75.75 0 111.04 1.08L5.612 9.25H16.25A.75.75 0 0117 10z"
-					clip-rule="evenodd"
-				/>
-			</svg>
-		</div>
-		<div class=" self-center font-medium text-sm">{$i18n.t('Back')}</div>
-	</button>
-
-	<form
-		class="flex flex-col max-w-2xl mx-auto mt-4 mb-10 pb-10"
-		on:submit|preventDefault={() => {
-			submitHandler();
-		}}
-	>
-		<div class="my-2">
-			<div class=" text-sm font-semibold mb-2">{$i18n.t('Title')}*</div>
-
-			<div>
-				<input
-					class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
-					placeholder={$i18n.t('Add a short title for this prompt')}
-					bind:value={title}
-					required
-				/>
-			</div>
-		</div>
-
-		<div class="my-2">
-			<div class=" text-sm font-semibold mb-2">{$i18n.t('Command')}*</div>
-
-			<div class="flex items-center mb-1">
-				<div
-					class="bg-gray-200 dark:bg-gray-600 font-semibold px-3 py-1 border border-r-0 dark:border-gray-600 rounded-l-lg"
-				>
-					/
-				</div>
-				<input
-					class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-r-lg"
-					placeholder={$i18n.t('short-summary')}
-					bind:value={command}
-					required
-				/>
-			</div>
-
-			<div class="text-xs text-gray-400 dark:text-gray-500">
-				{$i18n.t('Only')}
-				<span class=" text-gray-600 dark:text-gray-300 font-medium"
-					>{$i18n.t('alphanumeric characters and hyphens')}</span
-				>
-				{$i18n.t('are allowed - Activate this command by typing')}&nbsp;"<span
-					class=" text-gray-600 dark:text-gray-300 font-medium"
-				>
-					/{command}
-				</span>" &nbsp;
-				{$i18n.t('to chat input.')}
-			</div>
-		</div>
-
-		<div class="my-2">
-			<div class="flex w-full justify-between">
-				<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt Content')}*</div>
-			</div>
-
-			<div class="mt-2">
-				<div>
-					<Textarea
-						className="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none overflow-y-hidden rounded-lg resize-none"
-						placeholder={$i18n.t('Write a summary in 50 words that summarizes [topic or keyword].')}
-						bind:value={content}
-						rows={6}
-						required
-					/>
-				</div>
-
-				<div class="text-xs text-gray-400 dark:text-gray-500">
-					ⓘ {$i18n.t('Format your variables using brackets like this:')}&nbsp;<span
-						class=" text-gray-600 dark:text-gray-300 font-medium"
-						>{'{{'}{$i18n.t('variable')}{'}}'}</span
-					>.
-					{$i18n.t('Make sure to enclose them with')}
-					<span class=" text-gray-600 dark:text-gray-300 font-medium">{'{{'}</span>
-					{$i18n.t('and')}
-					<span class=" text-gray-600 dark:text-gray-300 font-medium">{'}}'}</span>.
-				</div>
-
-				<div class="text-xs text-gray-400 dark:text-gray-500">
-					{$i18n.t('Utilize')}<span class=" text-gray-600 dark:text-gray-300 font-medium">
-						{` {{CLIPBOARD}}`}</span
-					>
-					{$i18n.t('variable to have them replaced with clipboard content.')}
-				</div>
-			</div>
-		</div>
-
-		<div class="my-2 flex justify-end">
-			<button
-				class=" text-sm px-3 py-2 transition rounded-xl {loading
-					? ' cursor-not-allowed bg-gray-100 dark:bg-gray-800'
-					: ' bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-800'} flex"
-				type="submit"
-				disabled={loading}
-			>
-				<div class=" self-center font-medium">{$i18n.t('Save & Create')}</div>
-
-				{#if loading}
-					<div class="ml-1.5 self-center">
-						<svg
-							class=" w-4 h-4"
-							viewBox="0 0 24 24"
-							fill="currentColor"
-							xmlns="http://www.w3.org/2000/svg"
-							><style>
-								.spinner_ajPY {
-									transform-origin: center;
-									animation: spinner_AtaB 0.75s infinite linear;
-								}
-								@keyframes spinner_AtaB {
-									100% {
-										transform: rotate(360deg);
-									}
-								}
-							</style><path
-								d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
-								opacity=".25"
-							/><path
-								d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
-								class="spinner_ajPY"
-							/></svg
-						>
-					</div>
-				{/if}
-			</button>
-		</div>
-	</form>
+	<PromptEditor {prompt} {onSubmit} />
 </div>
 </div>

+ 24 - 203
src/routes/(app)/workspace/prompts/edit/+page.svelte

@@ -1,72 +1,40 @@
 <script>
 <script>
 	import { toast } from 'svelte-sonner';
 	import { toast } from 'svelte-sonner';
-
 	import { goto } from '$app/navigation';
 	import { goto } from '$app/navigation';
 	import { prompts } from '$lib/stores';
 	import { prompts } from '$lib/stores';
 	import { onMount, tick, getContext } from 'svelte';
 	import { onMount, tick, getContext } from 'svelte';
 
 
-	const i18n = getContext('i18n');
-
 	import { getPrompts, updatePromptByCommand } from '$lib/apis/prompts';
 	import { getPrompts, updatePromptByCommand } from '$lib/apis/prompts';
 	import { page } from '$app/stores';
 	import { page } from '$app/stores';
-	import Textarea from '$lib/components/common/Textarea.svelte';
-
-	let loading = false;
-
-	// ///////////
-	// Prompt
-	// ///////////
 
 
-	let title = '';
-	let command = '';
-	let content = '';
+	import PromptEditor from '$lib/components/workspace/Prompts/PromptEditor.svelte';
 
 
-	const updateHandler = async () => {
-		loading = true;
-
-		if (validateCommandString(command)) {
-			const prompt = await updatePromptByCommand(localStorage.token, command, title, content).catch(
-				(error) => {
-					toast.error(error);
-					return null;
-				}
-			);
-
-			if (prompt) {
-				await prompts.set(await getPrompts(localStorage.token));
-				await goto('/workspace/prompts');
+	let prompt = null;
+	const onSubmit = async ({ title, command, content }) => {
+		const prompt = await updatePromptByCommand(localStorage.token, command, title, content).catch(
+			(error) => {
+				toast.error(error);
+				return null;
 			}
 			}
-		} else {
-			toast.error(
-				$i18n.t('Only alphanumeric characters and hyphens are allowed in the command string.')
-			);
-		}
-
-		loading = false;
-	};
+		);
 
 
-	const validateCommandString = (inputString) => {
-		// Regular expression to match only alphanumeric characters and hyphen
-		const regex = /^[a-zA-Z0-9-]+$/;
-
-		// Test the input string against the regular expression
-		return regex.test(inputString);
+		if (prompt) {
+			await prompts.set(await getPrompts(localStorage.token));
+			await goto('/workspace/prompts');
+		}
 	};
 	};
 
 
 	onMount(async () => {
 	onMount(async () => {
-		command = $page.url.searchParams.get('command');
+		const command = $page.url.searchParams.get('command');
 		if (command) {
 		if (command) {
-			const prompt = $prompts.filter((prompt) => prompt.command === command).at(0);
-
-			if (prompt) {
-				console.log(prompt);
-
-				console.log(prompt.command);
-
-				title = prompt.title;
-				await tick();
-				command = prompt.command.slice(1);
-				content = prompt.content;
+			const _prompt = $prompts.filter((prompt) => prompt.command === command).at(0);
+
+			if (_prompt) {
+				prompt = {
+					title: _prompt.title,
+					command: _prompt.command,
+					content: _prompt.content
+				};
 			} else {
 			} else {
 				goto('/workspace/prompts');
 				goto('/workspace/prompts');
 			}
 			}
@@ -77,154 +45,7 @@
 </script>
 </script>
 
 
 <div class="w-full max-h-full">
 <div class="w-full max-h-full">
-	<button
-		class="flex space-x-1"
-		on:click={() => {
-			history.back();
-		}}
-	>
-		<div class=" self-center">
-			<svg
-				xmlns="http://www.w3.org/2000/svg"
-				viewBox="0 0 20 20"
-				fill="currentColor"
-				class="w-4 h-4"
-			>
-				<path
-					fill-rule="evenodd"
-					d="M17 10a.75.75 0 01-.75.75H5.612l4.158 3.96a.75.75 0 11-1.04 1.08l-5.5-5.25a.75.75 0 010-1.08l5.5-5.25a.75.75 0 111.04 1.08L5.612 9.25H16.25A.75.75 0 0117 10z"
-					clip-rule="evenodd"
-				/>
-			</svg>
-		</div>
-		<div class=" self-center font-medium text-sm">{$i18n.t('Back')}</div>
-	</button>
-
-	<form
-		class="flex flex-col max-w-2xl mx-auto mt-4 mb-10 pb-10"
-		on:submit|preventDefault={() => {
-			updateHandler();
-		}}
-	>
-		<div class="my-2">
-			<div class=" text-sm font-semibold mb-2">{$i18n.t('Title')}*</div>
-
-			<div>
-				<input
-					class="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none rounded-lg"
-					placeholder={$i18n.t('Add a short title for this prompt')}
-					bind:value={title}
-					required
-				/>
-			</div>
-		</div>
-
-		<div class="my-2">
-			<div class=" text-sm font-semibold mb-2">{$i18n.t('Command')}*</div>
-
-			<div class="flex items-center mb-1">
-				<div
-					class="bg-gray-200 dark:bg-gray-600 font-semibold px-3 py-1 border border-r-0 dark:border-gray-600 rounded-l-lg"
-				>
-					/
-				</div>
-				<input
-					class="px-3 py-1.5 text-sm w-full bg-transparent border disabled:text-gray-500 dark:border-gray-600 outline-none rounded-r-lg"
-					placeholder="short-summary"
-					bind:value={command}
-					disabled
-					required
-				/>
-			</div>
-
-			<div class="text-xs text-gray-400 dark:text-gray-500">
-				{$i18n.t('Only')}
-				<span class=" text-gray-600 dark:text-gray-300 font-medium"
-					>{$i18n.t('alphanumeric characters and hyphens')}</span
-				>
-				{$i18n.t('are allowed - Activate this command by typing')}&nbsp;"<span
-					class=" text-gray-600 dark:text-gray-300 font-medium"
-				>
-					/{command}
-				</span>" &nbsp;
-				{$i18n.t('to chat input.')}
-			</div>
-		</div>
-
-		<div class="my-2">
-			<div class="flex w-full justify-between">
-				<div class=" self-center text-sm font-semibold">{$i18n.t('Prompt Content')}*</div>
-			</div>
-
-			<div class="mt-2">
-				<div>
-					<Textarea
-						className="px-3 py-1.5 text-sm w-full bg-transparent border dark:border-gray-600 outline-none overflow-y-hidden rounded-lg resize-none"
-						placeholder={$i18n.t(`Write a summary in 50 words that summarizes [topic or keyword].`)}
-						rows={6}
-						bind:value={content}
-						required
-					/>
-				</div>
-
-				<div class="text-xs text-gray-400 dark:text-gray-500">
-					ⓘ {$i18n.t('Format your variables using brackets like this:')}&nbsp;<span
-						class=" text-gray-600 dark:text-gray-300 font-medium"
-						>{'{{'}{$i18n.t('variable')}{'}}'}</span
-					>.
-					{$i18n.t('Make sure to enclose them with')}
-					<span class=" text-gray-600 dark:text-gray-300 font-medium">{'{{'}</span>
-					{$i18n.t('and')}
-					<span class=" text-gray-600 dark:text-gray-300 font-medium">{'}}'}</span>.
-				</div>
-
-				<div class="text-xs text-gray-400 dark:text-gray-500">
-					{$i18n.t('Utilize')}<span class=" text-gray-600 dark:text-gray-300 font-medium">
-						{` {{CLIPBOARD}}`}</span
-					>
-					{$i18n.t('variable to have them replaced with clipboard content.')}
-				</div>
-			</div>
-		</div>
-
-		<div class="my-2 flex justify-end">
-			<button
-				class=" text-sm px-3 py-2 transition rounded-xl {loading
-					? ' cursor-not-allowed bg-gray-100 dark:bg-gray-800'
-					: ' bg-gray-50 hover:bg-gray-100 dark:bg-gray-700 dark:hover:bg-gray-800'} flex"
-				type="submit"
-				disabled={loading}
-			>
-				<div class=" self-center font-medium">{$i18n.t('Save & Update')}</div>
-
-				{#if loading}
-					<div class="ml-1.5 self-center">
-						<svg
-							class=" w-4 h-4"
-							viewBox="0 0 24 24"
-							fill="currentColor"
-							xmlns="http://www.w3.org/2000/svg"
-							><style>
-								.spinner_ajPY {
-									transform-origin: center;
-									animation: spinner_AtaB 0.75s infinite linear;
-								}
-								@keyframes spinner_AtaB {
-									100% {
-										transform: rotate(360deg);
-									}
-								}
-							</style><path
-								d="M12,1A11,11,0,1,0,23,12,11,11,0,0,0,12,1Zm0,19a8,8,0,1,1,8-8A8,8,0,0,1,12,20Z"
-								opacity=".25"
-							/><path
-								d="M10.14,1.16a11,11,0,0,0-9,8.92A1.59,1.59,0,0,0,2.46,12,1.52,1.52,0,0,0,4.11,10.7a8,8,0,0,1,6.66-6.61A1.42,1.42,0,0,0,12,2.69h0A1.57,1.57,0,0,0,10.14,1.16Z"
-								class="spinner_ajPY"
-							/></svg
-						>
-					</div>
-				{/if}
-			</button>
-		</div>
-	</form>
+	{#if prompt}
+		<PromptEditor {prompt} {onSubmit} edit />
+	{/if}
 </div>
 </div>