"test/config/vscode:/vscode.git/clone" did not exist on "9c1f534450bb253f01de5d8a2c9e39e234af4e5b"
PromptCommands.svelte 3.32 KB
Newer Older
Timothy J. Baek's avatar
Timothy J. Baek committed
1
<script lang="ts">
Timothy J. Baek's avatar
Timothy J. Baek committed
2
	import { prompts } from '$lib/stores';
Timothy J. Baek's avatar
Timothy J. Baek committed
3
4
	import { findWordIndices } from '$lib/utils';
	import { tick } from 'svelte';
Jannik Streidl's avatar
Jannik Streidl committed
5
	import { toast } from 'svelte-sonner';
Timothy J. Baek's avatar
Timothy J. Baek committed
6
7
8
9
10

	export let prompt = '';
	let selectedCommandIdx = 0;
	let filteredPromptCommands = [];

Timothy J. Baek's avatar
Timothy J. Baek committed
11
	$: filteredPromptCommands = $prompts
12
13
		.filter((p) => p.command.includes(prompt))
		.sort((a, b) => a.title.localeCompare(b.title));
Timothy J. Baek's avatar
Timothy J. Baek committed
14
15
16
17
18
19
20
21
22
23
24
25
26
27

	$: if (prompt) {
		selectedCommandIdx = 0;
	}

	export const selectUp = () => {
		selectedCommandIdx = Math.max(0, selectedCommandIdx - 1);
	};

	export const selectDown = () => {
		selectedCommandIdx = Math.min(selectedCommandIdx + 1, filteredPromptCommands.length - 1);
	};

	const confirmCommand = async (command) => {
28
29
30
31
32
33
34
35
36
37
38
39
		let text = command.content;

		if (command.content.includes('{{CLIPBOARD}}')) {
			const clipboardText = await navigator.clipboard.readText().catch((err) => {
				toast.error('Failed to read clipboard contents');
				return '{{CLIPBOARD}}';
			});

			text = command.content.replaceAll('{{CLIPBOARD}}', clipboardText);
		}

		prompt = text;
Timothy J. Baek's avatar
Timothy J. Baek committed
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61

		const chatInputElement = document.getElementById('chat-textarea');

		await tick();

		chatInputElement.style.height = '';
		chatInputElement.style.height = Math.min(chatInputElement.scrollHeight, 200) + 'px';

		chatInputElement?.focus();

		await tick();

		const words = findWordIndices(prompt);

		if (words.length > 0) {
			const word = words.at(0);
			chatInputElement.setSelectionRange(word?.startIndex, word.endIndex + 1);
		}
	};
</script>

{#if filteredPromptCommands.length > 0}
Timothy J. Baek's avatar
Timothy J. Baek committed
62
	<div class="md:px-2 mb-3 text-left w-full absolute bottom-0 left-0 right-0">
Timothy J. Baek's avatar
Timothy J. Baek committed
63
64
		<div class="flex w-full px-2">
			<div class=" bg-gray-100 dark:bg-gray-700 w-10 rounded-l-xl text-center">
Timothy J. Baek's avatar
Timothy J. Baek committed
65
				<div class=" text-lg font-semibold mt-2">/</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
66
			</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
67

Timothy J. Baek's avatar
Timothy J. Baek committed
68
69
			<div class="max-h-60 flex flex-col w-full rounded-r-xl bg-white">
				<div class="m-1 overflow-y-auto p-1 rounded-r-xl space-y-0.5">
Timothy J. Baek's avatar
Timothy J. Baek committed
70
71
					{#each filteredPromptCommands as command, commandIdx}
						<button
Timothy J. Baek's avatar
Timothy J. Baek committed
72
							class=" px-3 py-1.5 rounded-xl w-full text-left {commandIdx === selectedCommandIdx
Timothy J. Baek's avatar
Timothy J. Baek committed
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
								? ' bg-gray-100 selected-command-option-button'
								: ''}"
							type="button"
							on:click={() => {
								confirmCommand(command);
							}}
							on:mousemove={() => {
								selectedCommandIdx = commandIdx;
							}}
							on:focus={() => {}}
						>
							<div class=" font-medium text-black">
								{command.command}
							</div>

							<div class=" text-xs text-gray-600">
								{command.title}
							</div>
						</button>
					{/each}
				</div>

Timothy J. Baek's avatar
Timothy J. Baek committed
95
				<div
Timothy J. Baek's avatar
Timothy J. Baek committed
96
					class=" px-2 pb-1 text-xs text-gray-600 bg-white rounded-br-xl flex items-center space-x-1"
Timothy J. Baek's avatar
Timothy J. Baek committed
97
				>
Timothy J. Baek's avatar
Timothy J. Baek committed
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
					<div>
						<svg
							xmlns="http://www.w3.org/2000/svg"
							fill="none"
							viewBox="0 0 24 24"
							stroke-width="1.5"
							stroke="currentColor"
							class="w-3 h-3"
						>
							<path
								stroke-linecap="round"
								stroke-linejoin="round"
								d="m11.25 11.25.041-.02a.75.75 0 0 1 1.063.852l-.708 2.836a.75.75 0 0 0 1.063.853l.041-.021M21 12a9 9 0 1 1-18 0 9 9 0 0 1 18 0Zm-9-3.75h.008v.008H12V8.25Z"
							/>
						</svg>
					</div>

					<div class="line-clamp-1">
Timothy J. Baek's avatar
Timothy J. Baek committed
116
117
						Tip: Update multiple variable slots consecutively by pressing the tab key in the chat
						input after each replacement.
Timothy J. Baek's avatar
Timothy J. Baek committed
118
119
					</div>
				</div>
Timothy J. Baek's avatar
Timothy J. Baek committed
120
121
122
123
			</div>
		</div>
	</div>
{/if}