|
| 1 | +<svelte:options |
| 2 | + customElement={{ |
| 3 | + tag: "sui-chat-window", |
| 4 | + shadow: "none", |
| 5 | + props: { |
| 6 | + messages: { type: "Array", reflect: true }, |
| 7 | + users: { type: "Array" }, |
| 8 | + meId: { type: "String" }, |
| 9 | + threads: { type: "Array" } |
| 10 | + } |
| 11 | + }} |
| 12 | +/> |
| 13 | + |
| 14 | +<script lang="ts"> |
| 15 | + import { createEventDispatcher, onMount } from "svelte"; |
| 16 | + import type { ChatThread } from "./chat-message"; |
| 17 | + import MessageThread from "./MessageThread.svelte"; |
| 18 | +
|
| 19 | + const messageEventDispatcher = createEventDispatcher(); |
| 20 | +
|
| 21 | + let { |
| 22 | + threads = [], |
| 23 | + meId, |
| 24 | + showAvatars = "always", |
| 25 | + currentThreadId, |
| 26 | + sendMessage |
| 27 | + }: { |
| 28 | + threads?: ChatThread[]; |
| 29 | + meId: string; |
| 30 | + showAvatars?: "never" | "always" | "change"; |
| 31 | + currentThreadId?: string; |
| 32 | + sendMessage: (threadId: string, message: string) => void; |
| 33 | + } = $props(); |
| 34 | + let newChatMessage = $state(""); |
| 35 | + let sidePanelOpen = $state(false); |
| 36 | +
|
| 37 | + onMount(() => { |
| 38 | + if (!currentThreadId && threads.length > 0) currentThreadId = threads[0].id; |
| 39 | + }); |
| 40 | + let currentThread = $derived(threads?.find((thread) => thread.id === currentThreadId)); |
| 41 | +
|
| 42 | + function executeSendMessage() { |
| 43 | + if (sendMessage) sendMessage(currentThreadId, newChatMessage); |
| 44 | + else messageEventDispatcher("message", newChatMessage); |
| 45 | + newChatMessage = ""; |
| 46 | + } |
| 47 | +</script> |
| 48 | + |
| 49 | +<div class="flex flex-row gap-2 text-primary-content min-h-64"> |
| 50 | + {#if threads && threads.length > 0} |
| 51 | + <div |
| 52 | + class="flex flex-col bg-primary bg-opacity-90 rounded p-2 text-primary-content items-start {sidePanelOpen |
| 53 | + ? 'w-64' |
| 54 | + : 'w-14'}" |
| 55 | + > |
| 56 | + <div class="grow flex flex-col gap-2 items-start"> |
| 57 | + {#each threads as thread} |
| 58 | + <button |
| 59 | + class="flex flex-row gap-2" |
| 60 | + onclick={() => { |
| 61 | + currentThreadId = thread.id; |
| 62 | + sidePanelOpen = false; |
| 63 | + }} |
| 64 | + > |
| 65 | + <img |
| 66 | + src={thread.avatarUrl} |
| 67 | + alt={thread.name} |
| 68 | + class="avatar rounded-full w-10 h-10 {thread.id === currentThreadId |
| 69 | + ? 'bg-secondary' |
| 70 | + : 'bg-primary'}" |
| 71 | + /> |
| 72 | + {#if sidePanelOpen} |
| 73 | + <div class="flex flex-col gap-0 justify-center items-start h-full"> |
| 74 | + <span class="font-bold truncate">{thread.name}</span> |
| 75 | + <span class="text-xs truncate text-gray-500" |
| 76 | + >{thread.messages[thread.messages.length - 1].text}</span |
| 77 | + > |
| 78 | + </div> |
| 79 | + {/if} |
| 80 | + </button> |
| 81 | + {/each} |
| 82 | + </div> |
| 83 | + <button onclick={() => (sidePanelOpen = !sidePanelOpen)} class="btn btn-circle btn-ghost btn-sm m-1"> |
| 84 | + <svg |
| 85 | + xmlns="http://www.w3.org/2000/svg" |
| 86 | + x="0px" |
| 87 | + y="0px" |
| 88 | + width="16" |
| 89 | + height="16" |
| 90 | + viewBox="0 0 50 50" |
| 91 | + > |
| 92 | + <path |
| 93 | + fill="currentColor" |
| 94 | + d="M 0 7.5 L 0 12.5 L 50 12.5 L 50 7.5 Z M 0 22.5 L 0 27.5 L 50 27.5 L 50 22.5 Z M 0 37.5 L 0 42.5 L 50 42.5 L 50 37.5 Z" |
| 95 | + ></path> |
| 96 | + </svg> |
| 97 | + </button> |
| 98 | + </div> |
| 99 | + {/if} |
| 100 | + <div class="flex flex-col gap-2 grow"> |
| 101 | + {#if currentThread} |
| 102 | + <div class="grow"> |
| 103 | + <MessageThread |
| 104 | + messages={currentThread.messages} |
| 105 | + users={currentThread.users} |
| 106 | + {meId} |
| 107 | + {showAvatars} |
| 108 | + /> |
| 109 | + </div> |
| 110 | + <div class="join"> |
| 111 | + <input |
| 112 | + type="string" |
| 113 | + class="join-item input input-bordered grow" |
| 114 | + bind:value={newChatMessage} |
| 115 | + onkeydown={(e) => e.key === "Enter" && executeSendMessage()} |
| 116 | + /> |
| 117 | + <button class="join-item btn" disabled={newChatMessage === ""} onclick={executeSendMessage}> |
| 118 | + Send |
| 119 | + </button> |
| 120 | + </div> |
| 121 | + {/if} |
| 122 | + </div> |
| 123 | +</div> |
0 commit comments