| 
7 | 7 | 		ChatMessageThinkingBlock,  | 
8 | 8 | 		MarkdownContent  | 
9 | 9 | 	} from '$lib/components/app';  | 
10 |  | -	import { inputClasses } from '$lib/constants/input-classes';  | 
11 |  | -	import type { MessageSiblingInfo } from '$lib/utils/branching';  | 
12 | 10 | 	import * as AlertDialog from '$lib/components/ui/alert-dialog';  | 
13 | 11 | 	import * as Tooltip from '$lib/components/ui/tooltip';  | 
 | 12 | +	import { inputClasses } from '$lib/constants/input-classes';  | 
 | 13 | +	import { useProcessingState } from '$lib/hooks/use-processing-state.svelte';  | 
 | 14 | +	import { getDeletionInfo, isLoading } from '$lib/stores/chat.svelte';  | 
 | 15 | +	import type { MessageSiblingInfo } from '$lib/utils/branching';  | 
14 | 16 | 	import { copyToClipboard } from '$lib/utils/copy';  | 
15 | 17 | 	import { parseThinkingContent } from '$lib/utils/thinking';  | 
16 |  | -	import { getDeletionInfo } from '$lib/stores/chat.svelte';  | 
17 |  | -	import { isLoading } from '$lib/stores/chat.svelte';  | 
18 |  | -	import { useProcessingState } from '$lib/hooks/use-processing-state.svelte';  | 
19 | 18 | 	import type { Component } from 'svelte';  | 
20 | 19 | 	import { fade } from 'svelte/transition';  | 
21 | 20 | 	import MessageBranchingControls from './MessageBranchingControls.svelte';  | 
22 | 21 | 
  | 
23 | 22 | 	interface Props {  | 
24 | 23 | 		class?: string;  | 
25 | 24 | 		message: DatabaseMessage;  | 
26 |  | -		siblingInfo?: MessageSiblingInfo | null;  | 
27 | 25 | 		onCopy?: (message: DatabaseMessage) => void;  | 
28 | 26 | 		onDelete?: (message: DatabaseMessage) => void;  | 
29 |  | -		onNavigateToSibling?: (siblingId: string) => void;  | 
30 | 27 | 		onEditWithBranching?: (message: DatabaseMessage, newContent: string) => void;  | 
 | 28 | +		onNavigateToSibling?: (siblingId: string) => void;  | 
31 | 29 | 		onRegenerateWithBranching?: (message: DatabaseMessage) => void;  | 
 | 30 | +		siblingInfo?: MessageSiblingInfo | null;  | 
32 | 31 | 	}  | 
33 | 32 | 
  | 
34 | 33 | 	let {  | 
35 | 34 | 		class: className = '',  | 
36 | 35 | 		message,  | 
37 |  | -		siblingInfo = null,  | 
38 | 36 | 		onCopy,  | 
39 | 37 | 		onDelete,  | 
40 |  | -		onNavigateToSibling,  | 
41 | 38 | 		onEditWithBranching,  | 
42 |  | -		onRegenerateWithBranching  | 
 | 39 | +		onNavigateToSibling,  | 
 | 40 | +		onRegenerateWithBranching,  | 
 | 41 | +		siblingInfo = null  | 
43 | 42 | 	}: Props = $props();  | 
44 | 43 | 
  | 
45 | 44 | 	let showDeleteDialog = $state(false);  | 
 | 
77 | 76 | 		return message.content?.replace('<|channel|>analysis', '');  | 
78 | 77 | 	});  | 
79 | 78 | 
  | 
 | 79 | +	function handleCancelEdit() {  | 
 | 80 | +		isEditing = false;  | 
 | 81 | +		editedContent = message.content;  | 
 | 82 | +	}  | 
 | 83 | +
  | 
 | 84 | +	function handleConfirmDelete() {  | 
 | 85 | +		onDelete?.(message);  | 
 | 86 | +		showDeleteDialog = false;  | 
 | 87 | +	}  | 
 | 88 | +
  | 
80 | 89 | 	async function handleCopy() {  | 
81 | 90 | 		await copyToClipboard(message.content, 'Message copied to clipboard');  | 
82 | 91 | 		onCopy?.(message);  | 
83 | 92 | 	}  | 
84 | 93 | 
  | 
85 |  | -	function handleCancelEdit() {  | 
86 |  | -		isEditing = false;  | 
87 |  | -		editedContent = message.content;  | 
 | 94 | +	async function handleDelete() {  | 
 | 95 | +		deletionInfo = await getDeletionInfo(message.id);  | 
 | 96 | +		showDeleteDialog = true;  | 
88 | 97 | 	}  | 
89 | 98 | 
  | 
90 | 99 | 	function handleEdit() {  | 
 | 
121 | 130 | 		}  | 
122 | 131 | 		isEditing = false;  | 
123 | 132 | 	}  | 
124 |  | -
  | 
125 |  | -	async function handleDelete() {  | 
126 |  | -		deletionInfo = await getDeletionInfo(message.id);  | 
127 |  | -		showDeleteDialog = true;  | 
128 |  | -	}  | 
129 |  | -
  | 
130 |  | -	function handleConfirmDelete() {  | 
131 |  | -		onDelete?.(message);  | 
132 |  | -		showDeleteDialog = false;  | 
133 |  | -	}  | 
134 | 133 | </script>  | 
135 | 134 | 
 
  | 
136 | 135 | {#if message.role === 'user'}  | 
137 | 136 | 	<div  | 
 | 137 | +		aria-label="User message with actions"  | 
138 | 138 | 		class="group flex flex-col items-end gap-2 {className}"  | 
139 | 139 | 		role="group"  | 
140 |  | -		aria-label="User message with actions"  | 
141 | 140 | 	>  | 
142 | 141 | 		{#if isEditing}  | 
143 | 142 | 			<div class="w-full max-w-[80%]">  | 
144 | 143 | 				<textarea  | 
145 | 144 | 					bind:this={textareaElement}  | 
146 | 145 | 					bind:value={editedContent}  | 
147 |  | -					onkeydown={handleEditKeydown}  | 
148 | 146 | 					class="min-h-[60px] w-full resize-none rounded-2xl px-3 py-2 text-sm {inputClasses}"  | 
 | 147 | +					onkeydown={handleEditKeydown}  | 
149 | 148 | 					placeholder="Edit your message..."  | 
150 | 149 | 				></textarea>  | 
151 | 150 | 
 
  | 
152 | 151 | 				<div class="mt-2 flex justify-end gap-2">  | 
153 |  | -					<Button variant="outline" size="sm" class="h-8 px-3" onclick={handleCancelEdit}>  | 
 | 152 | +					<Button class="h-8 px-3" onclick={handleCancelEdit} size="sm" variant="outline" >  | 
154 | 153 | 						<X class="mr-1 h-3 w-3" />  | 
 | 154 | + | 
155 | 155 | 						Cancel  | 
156 | 156 | 					</Button>  | 
157 | 157 | 
 
  | 
158 | 158 | 					<Button  | 
159 |  | -						size="sm"  | 
160 | 159 | 						class="h-8 px-3"  | 
161 | 160 | 						onclick={handleSaveEdit}  | 
162 | 161 | 						disabled={!editedContent.trim() || editedContent === message.content}  | 
 | 162 | +						size="sm"  | 
163 | 163 | 					>  | 
164 | 164 | 						<Check class="mr-1 h-3 w-3" />  | 
 | 165 | + | 
165 | 166 | 						Send  | 
166 | 167 | 					</Button>  | 
167 | 168 | 				</div>  | 
 | 
0 commit comments