aboutsummaryrefslogtreecommitdiffstats
path: root/src/routes
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-03-07 08:54:47 -0800
committerAdam Soltys <[email protected]>2026-03-07 08:54:47 -0800
commitad0b4009b2b2ae9173fffb41f0cfa7b35edcb303 (patch)
tree49c2eceb273b73ce5b9c0aba74dafbf6fddce442 /src/routes
parent13b2a17e6f6ed1697c51a6650874313a6da4aa8f (diff)
downloadcoinos-ui-ad0b4009b2b2ae9173fffb41f0cfa7b35edcb303.tar.gz
coinos-ui-ad0b4009b2b2ae9173fffb41f0cfa7b35edcb303.zip
image upload
Diffstat (limited to 'src/routes')
-rw-r--r--src/routes/(app)/messages/[id]/+page.svelte80
1 files changed, 80 insertions, 0 deletions
diff --git a/src/routes/(app)/messages/[id]/+page.svelte b/src/routes/(app)/messages/[id]/+page.svelte
index f9aea4da..a5768df7 100644
--- a/src/routes/(app)/messages/[id]/+page.svelte
+++ b/src/routes/(app)/messages/[id]/+page.svelte
@@ -1,11 +1,13 @@
<script lang="ts">
import PhPaperPlaneRightFill from "virtual:icons/ph/paper-plane-right-fill";
+ import PhPlusBold from "virtual:icons/ph/plus-bold";
import { tick, onMount, onDestroy } from "svelte";
import { page } from "$app/state";
import { goto } from "$app/navigation";
import {
getGroups, getGroupRumours, sendGroupMessage,
+ sendGroupMediaMessage,
subscribeToMessages, fetchGroupHistory,
findOrCreateDmGroup,
resolveUser, displayName,
@@ -45,6 +47,7 @@
let messageRumours: Map<number, any[]> = $state(new Map());
let dates: number[] = $state([]);
let sendError = $state("");
+ let uploading = $state(false);
let senderInfos = $state(new Map<string, any>());
const groupDisplayName = (g: GroupInfo | undefined): string => {
@@ -223,6 +226,22 @@
}
};
+ const sendMedia = async (file: File) => {
+ sendError = "";
+ uploading = true;
+ try {
+ await sendGroupMediaMessage(user, groupId, file);
+ updateMessages();
+ await tick();
+ scrollChat();
+ } catch (e: any) {
+ console.error("Failed to send media:", e);
+ sendError = e.message || "Failed to send media";
+ } finally {
+ uploading = false;
+ }
+ };
+
let closeSub: (() => void) | undefined;
onMount(() => {
@@ -297,8 +316,32 @@
<div id="messages-end"></div>
</div>
+ <input
+ type="file"
+ accept="image/*,video/*,audio/*"
+ id="media-upload"
+ hidden
+ onchange={(e) => {
+ const file = (e.currentTarget as HTMLInputElement).files?.[0];
+ if (file) sendMedia(file);
+ (e.currentTarget as HTMLInputElement).value = "";
+ }}
+ />
+
<div class="input-bar">
<div class="input-row">
+ <button
+ class="attach-btn"
+ disabled={uploading || !groupId}
+ onclick={() => document.getElementById("media-upload")?.click()}
+ aria-label="Attach media"
+ >
+ {#if uploading}
+ <span class="spinner"></span>
+ {:else}
+ <PhPlusBold width="20" />
+ {/if}
+ </button>
<textarea
id="message-contents"
bind:value={text}
@@ -521,4 +564,41 @@
opacity: 0.35;
cursor: default;
}
+
+ .attach-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 2.5rem;
+ height: 2.5rem;
+ border-radius: 9999px;
+ background: transparent;
+ color: inherit;
+ border: 1px solid rgba(128, 128, 128, 0.3);
+ cursor: pointer;
+ flex-shrink: 0;
+ opacity: 0.7;
+ }
+
+ .attach-btn:hover {
+ opacity: 1;
+ }
+
+ .attach-btn:disabled {
+ opacity: 0.35;
+ cursor: default;
+ }
+
+ .spinner {
+ width: 18px;
+ height: 18px;
+ border: 2px solid rgba(128, 128, 128, 0.3);
+ border-top-color: currentColor;
+ border-radius: 50%;
+ animation: spin 0.6s linear infinite;
+ }
+
+ @keyframes spin {
+ to { transform: rotate(360deg); }
+ }
</style>