|
1 | 1 | <script lang="ts">
|
2 | 2 | import { onMount } from 'svelte';
|
3 | 3 | import { ChatMessage, MessageInput } from '$lib/fragments';
|
4 |
| - import { Avatar, Button } from '$lib/ui'; |
| 4 | + import { Avatar, Button, Input, Label } from '$lib/ui'; |
| 5 | + import { InputFile } from '$lib/fragments'; |
| 6 | + import { HugeiconsFreeIcons, Edit01FreeIcons } from '@hugeicons/core-free-icons'; |
5 | 7 | import { goto } from '$app/navigation';
|
6 | 8 | import { page } from '$app/state';
|
| 9 | + import Settings from '$lib/icons/Settings.svelte'; |
| 10 | + import { clickOutside } from '$lib/utils'; |
7 | 11 |
|
8 | 12 | let messagesContainer: HTMLDivElement;
|
9 | 13 | let messageValue = $state('');
|
| 14 | + let openMenuId = $state<string | null>(null); |
10 | 15 |
|
11 | 16 | let userId = 'user-1';
|
12 | 17 | let id = page.params.id;
|
|
40 | 45 | }
|
41 | 46 | ]);
|
42 | 47 |
|
43 |
| - let openMenuId = $state<string | null>(null); |
44 |
| -
|
45 | 48 | function scrollToBottom() {
|
46 | 49 | if (messagesContainer) {
|
47 | 50 | messagesContainer.scrollTop = messagesContainer.scrollHeight;
|
|
67 | 70 | messageValue = '';
|
68 | 71 | setTimeout(scrollToBottom, 0);
|
69 | 72 | }
|
| 73 | +
|
| 74 | + // Edit Dialog state and logic |
| 75 | + let openEditDialog = $state(false); |
| 76 | + let groupName = $state(group.name); |
| 77 | + let groupDescription = $state(group.description); |
| 78 | + let groupImageDataUrl = $state(group.avatar); |
| 79 | + let groupImageFiles = $state<FileList | undefined>(); |
| 80 | +
|
| 81 | + function handleGroupImageChange() { |
| 82 | + if (groupImageFiles && groupImageFiles[0]) { |
| 83 | + const reader = new FileReader(); |
| 84 | + reader.onload = (e) => { |
| 85 | + if (e.target?.result) { |
| 86 | + groupImageDataUrl = e.target.result as string; |
| 87 | + } |
| 88 | + }; |
| 89 | + reader.readAsDataURL(groupImageFiles[0]); |
| 90 | + } |
| 91 | + } |
| 92 | +
|
| 93 | + $effect(() => { |
| 94 | + if (groupImageFiles) handleGroupImageChange(); |
| 95 | + }); |
| 96 | +
|
| 97 | + function saveGroupInfo() { |
| 98 | + group.name = groupName; |
| 99 | + group.description = groupDescription; |
| 100 | + group.avatar = groupImageDataUrl; |
| 101 | + openEditDialog = false; |
| 102 | + } |
70 | 103 | </script>
|
71 | 104 |
|
| 105 | +<!-- Group Header --> |
72 | 106 | <section class="flex items-center justify-between gap-4 px-4 py-3 border-b border-gray-200">
|
73 | 107 | <div class="flex items-center gap-4">
|
74 | 108 | <Avatar src={group.avatar} />
|
|
77 | 111 | <p class="text-sm text-gray-600">{group.description}</p>
|
78 | 112 | </div>
|
79 | 113 | </div>
|
80 |
| - <Button |
81 |
| - variant="secondary" |
82 |
| - size="sm" |
83 |
| - class="w-[max-content]" |
84 |
| - callback={() => { |
85 |
| - goto(`/group/${id}/members`) |
86 |
| - }} |
87 |
| - > |
88 |
| - View Members |
89 |
| - </Button> |
| 114 | + <div class="flex items-center gap-2"> |
| 115 | + <Button |
| 116 | + variant="secondary" |
| 117 | + size="sm" |
| 118 | + class="w-[max-content]" |
| 119 | + callback={() => { |
| 120 | + goto(`/group/${id}/members`); |
| 121 | + }} |
| 122 | + > |
| 123 | + View Members |
| 124 | + </Button> |
| 125 | + <button |
| 126 | + onclick={() => (openEditDialog = true)} |
| 127 | + > |
| 128 | + <Settings size="24px" color="var(--color-brand-burnt-orange)" /> |
| 129 | + </button> |
| 130 | + </div> |
90 | 131 | </section>
|
91 | 132 |
|
| 133 | +<!-- Chat Area --> |
92 | 134 | <section class="chat relative px-0">
|
93 | 135 | <div class="h-[calc(100vh-300px)] mt-4 overflow-auto" bind:this={messagesContainer}>
|
94 | 136 | {#each messages as msg (msg.id)}
|
|
109 | 151 | {handleSend}
|
110 | 152 | />
|
111 | 153 | </section>
|
| 154 | + |
| 155 | +<dialog open={openEditDialog} use:clickOutside={() => openEditDialog = false} onclose={() => (openEditDialog = false)} class="absolute start-[50%] top-[50%] translate-x-[-50%] translate-y-[-50%] p-4" > |
| 156 | + <div class="flex flex-col gap-6"> |
| 157 | + <div> |
| 158 | + <InputFile |
| 159 | + bind:files={groupImageFiles} |
| 160 | + accept="image/*" |
| 161 | + label="Upload Group Avatar" |
| 162 | + cancelLabel="Remove" |
| 163 | + oncancel={() => { |
| 164 | + groupImageDataUrl = ''; |
| 165 | + groupImageFiles = undefined; |
| 166 | + }} |
| 167 | + /> |
| 168 | + {#if groupImageDataUrl} |
| 169 | + <img |
| 170 | + src={groupImageDataUrl} |
| 171 | + alt="Group preview" |
| 172 | + class="mt-2 h-24 w-24 rounded-full object-cover" |
| 173 | + /> |
| 174 | + {/if} |
| 175 | + </div> |
| 176 | + |
| 177 | + <div> |
| 178 | + <Label>Group Name</Label> |
| 179 | + <Input type="text" placeholder="Edit group name" bind:value={groupName} /> |
| 180 | + </div> |
| 181 | + |
| 182 | + <div> |
| 183 | + <Label>Description</Label> |
| 184 | + <Input type="text" placeholder="Edit group description" bind:value={groupDescription} /> |
| 185 | + </div> |
| 186 | + |
| 187 | + <hr class="text-grey" /> |
| 188 | + <Button size="sm" variant="secondary" callback={saveGroupInfo}>Save Changes</Button> |
| 189 | + </div> |
| 190 | +</dialog> |
0 commit comments