|
25 | 25 | import ChevronDownIcon from '~icons/lucide/chevron-down'; |
26 | 26 | import RefreshCwIcon from '~icons/lucide/refresh-cw'; |
27 | 27 | import PencilIcon from '~icons/lucide/pencil'; |
| 28 | + import StarIcon from '~icons/lucide/star'; |
28 | 29 | import * as DropdownMenu from '$lib/components/ui/dropdown-menu'; |
29 | 30 | import { AnnotationSchema, type Annotation } from '$lib/types'; |
30 | 31 | import ExternalLinkIcon from '~icons/lucide/external-link'; |
|
186 | 187 |
|
187 | 188 | let isEditing = $state(false); |
188 | 189 | let editedContent = $state(''); |
| 190 | + let isStarred = $state<boolean>(false); |
| 191 | +
|
| 192 | + $effect(() => { |
| 193 | + isStarred = message.starred ?? false; |
| 194 | + }); |
189 | 195 |
|
190 | 196 | function startEditing() { |
191 | 197 | editedContent = message.content; |
|
274 | 280 | } |
275 | 281 | } |
276 | 282 | } |
| 283 | +
|
| 284 | + async function toggleStarred() { |
| 285 | + if (!session.current?.session.token) return; |
| 286 | + if (message.role !== 'assistant') return; |
| 287 | +
|
| 288 | + const previous = isStarred; |
| 289 | + isStarred = !isStarred; |
| 290 | +
|
| 291 | + try { |
| 292 | + const res = await fetch(api.messages.setStarred.url, { |
| 293 | + method: 'POST', |
| 294 | + headers: { 'Content-Type': 'application/json' }, |
| 295 | + body: JSON.stringify({ |
| 296 | + action: 'setStarred', |
| 297 | + messageId: message.id, |
| 298 | + starred: isStarred, |
| 299 | + }), |
| 300 | + }); |
| 301 | +
|
| 302 | + if (!res.ok) { |
| 303 | + console.error('Failed to update starred state'); |
| 304 | + isStarred = previous; |
| 305 | + return; |
| 306 | + } |
| 307 | +
|
| 308 | + invalidateQueryPattern(api.messages.getAllFromConversation.url); |
| 309 | + } catch (e) { |
| 310 | + console.error('Error updating starred state:', e); |
| 311 | + isStarred = previous; |
| 312 | + } |
| 313 | + } |
277 | 314 | </script> |
278 | 315 |
|
279 | 316 | {#if message.role !== 'system' && !(message.role === 'assistant' && message.content.length === 0 && message.reasoning?.length === 0 && !message.error)} |
|
480 | 517 | {/snippet} |
481 | 518 | {message.role === 'user' ? 'Branch and regenerate message' : 'Branch off this message'} |
482 | 519 | </Tooltip> |
| 520 | + {#if message.role === 'assistant' && message.content.length > 0 && !message.error} |
| 521 | + <Tooltip> |
| 522 | + {#snippet trigger(tooltip)} |
| 523 | + <Button |
| 524 | + size="icon" |
| 525 | + variant="ghost" |
| 526 | + class="order-1 size-7" |
| 527 | + onclick={toggleStarred} |
| 528 | + {...tooltip.trigger} |
| 529 | + > |
| 530 | + <StarIcon |
| 531 | + class={cn('size-4', { |
| 532 | + 'text-yellow-400 fill-yellow-400': isStarred, |
| 533 | + 'text-muted-foreground/60': !isStarred, |
| 534 | + })} |
| 535 | + /> |
| 536 | + </Button> |
| 537 | + {/snippet} |
| 538 | + {isStarred ? 'Unstar message' : 'Star message'} |
| 539 | + </Tooltip> |
| 540 | + {/if} |
483 | 541 | {#if message.content.length > 0} |
484 | 542 | <Tooltip> |
485 | 543 | {#snippet trigger(tooltip)} |
|
0 commit comments