aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-03-01 21:36:02 -0800
committerAdam Soltys <[email protected]>2026-03-01 21:36:02 -0800
commitc4a5498968b531b3965b347ed6b2b744a6cea7a3 (patch)
tree5bd24783a9b90811d62bf1031c2820b4ff0dfdc0 /src
parent77f407e06d21152546ccee3d8f4b21766d598c6f (diff)
downloadcoinos-ui-c4a5498968b531b3965b347ed6b2b744a6cea7a3.tar.gz
coinos-ui-c4a5498968b531b3965b347ed6b2b744a6cea7a3.zip
scrollbar
Diffstat (limited to 'src')
-rw-r--r--src/lib/nip17.ts1
-rw-r--r--src/routes/(app)/messages/+layout.svelte42
-rw-r--r--src/routes/(app)/messages/[pubkey]/+page.svelte148
3 files changed, 149 insertions, 42 deletions
diff --git a/src/lib/nip17.ts b/src/lib/nip17.ts
index 69f69464..ecdee29c 100644
--- a/src/lib/nip17.ts
+++ b/src/lib/nip17.ts
@@ -307,6 +307,7 @@ const publishToPreferred = async (
if (expiryEnabled) {
preferredRelays = await relaysSupporting(preferredRelays, [40]);
}
+ console.log("[nip17] publishing to relays for", pubkey, ":", preferredRelays);
if (preferredRelays.length === 0) {
throw new Error("No relays available to publish to");
}
diff --git a/src/routes/(app)/messages/+layout.svelte b/src/routes/(app)/messages/+layout.svelte
index 7e7e3cd0..230f8baf 100644
--- a/src/routes/(app)/messages/+layout.svelte
+++ b/src/routes/(app)/messages/+layout.svelte
@@ -28,28 +28,38 @@
<svelte:window bind:innerWidth={w} />
-<nav class="flex items-center p-4 gap-4">
- {#if isDetail}
- <a href="/messages" class="btn-menu" aria-label="Back">
- <iconify-icon noobserver icon="ph:arrow-left-bold" width={(w ?? 0) > 640 ? 32 : 24}></iconify-icon>
- </a>
- {/if}
+<div class="messages-layout">
+ <nav class="flex items-center p-4 gap-4 shrink-0">
+ {#if isDetail}
+ <a href="/messages" class="btn-menu" aria-label="Back">
+ <iconify-icon noobserver icon="ph:arrow-left-bold" width={(w ?? 0) > 640 ? 32 : 24}></iconify-icon>
+ </a>
+ {/if}
- <div class="ml-auto flex items-center gap-4">
- <a href="/{user?.username}" data-sveltekit-preload-code="eager" aria-label="Home">
- <button class="btn-menu" aria-label="Home">
- <iconify-icon noobserver icon="ph:house-bold" width={(w ?? 0) > 640 ? 32 : 24}></iconify-icon>
- </button>
- </a>
- <Menu {opacity} {user} t={$t} {w} />
- </div>
-</nav>
+ <div class="ml-auto flex items-center gap-4">
+ <a href="/{user?.username}" data-sveltekit-preload-code="eager" aria-label="Home">
+ <button class="btn-menu" aria-label="Home">
+ <iconify-icon noobserver icon="ph:house-bold" width={(w ?? 0) > 640 ? 32 : 24}></iconify-icon>
+ </button>
+ </a>
+ <Menu {opacity} {user} t={$t} {w} />
+ </div>
+ </nav>
-{@render children?.()}
+ <div class="flex-1 min-h-0">
+ {@render children?.()}
+ </div>
+</div>
<style>
@reference "../../../app.css";
+ .messages-layout {
+ display: flex;
+ flex-direction: column;
+ height: 100dvh;
+ }
+
.btn-menu {
@apply flex justify-center items-center bg-base-100 p-2 rounded-full w-12 h-12 sm:w-16 sm:h-16 drop-shadow-xl;
}
diff --git a/src/routes/(app)/messages/[pubkey]/+page.svelte b/src/routes/(app)/messages/[pubkey]/+page.svelte
index 0efa6206..5bd77203 100644
--- a/src/routes/(app)/messages/[pubkey]/+page.svelte
+++ b/src/routes/(app)/messages/[pubkey]/+page.svelte
@@ -143,9 +143,11 @@
try {
await libnip17.send(message, user, selectedChat);
text = "";
+ const ta = document.getElementById("message-contents") as HTMLTextAreaElement;
+ if (ta) ta.style.height = "auto";
updateEvents();
await tick();
- document.getElementById("message-contents")?.focus();
+ ta?.focus();
} catch (e: any) {
console.error("Failed to send message:", e);
sendError = $t("dm.sendFailed");
@@ -171,6 +173,20 @@
let closeSub: (() => void) | undefined;
+ // Keep input visible when mobile keyboard opens
+ onMount(() => {
+ const vv = window.visualViewport;
+ if (!vv) return;
+ const onResize = () => {
+ const active = document.activeElement;
+ if (active?.id === "message-contents") {
+ active.scrollIntoView({ block: "nearest" });
+ }
+ };
+ vv.addEventListener("resize", onResize);
+ return () => vv.removeEventListener("resize", onResize);
+ });
+
onMount(() => {
libnip17.subscribeToMessages(user, async (rumour) => {
if (!allRumours.find((r) => r.id === rumour.id)) {
@@ -204,10 +220,10 @@
onDestroy(() => closeSub?.());
</script>
-<div class="container mx-auto max-w-xl px-4 space-y-2">
+<div class="chat-container">
{#if selectedChat}
{@const chatProfile = selectedChat.coinosUsername ? `/${selectedChat.coinosUsername}` : null}
- <a href={chatProfile} class="flex items-center gap-3 mb-2 hover:opacity-80">
+ <a href={chatProfile} class="chat-header">
{#if selectedChat.picture}
<img src={selectedChat.picture} alt={name(selectedChat)} class="w-10 h-10 rounded-full object-cover" />
{/if}
@@ -262,27 +278,35 @@
</div>
<div class="input-bar">
- <textarea
- id="message-contents"
- bind:value={text}
- use:focus
- onkeydown={(e) => {
- if (e.key === "Enter" && !e.shiftKey) {
- e.preventDefault();
- if (canSend && text.trim()) sendMessage(text);
- }
- }}
- ></textarea>
- <input
- id="send-message"
- type="button"
- class="btn btn-accent"
- disabled={!canSend}
- value={canSend
- ? $t("dm.sendMessage")
- : $t("dm.relaysNotFound").replace("[R]", selectedChat ? name(selectedChat) : "")}
- onclick={async () => sendMessage(text)}
- />
+ <div class="input-row">
+ <textarea
+ id="message-contents"
+ bind:value={text}
+ use:focus
+ rows="1"
+ placeholder={canSend ? "" : $t("dm.relaysNotFound").replace("[R]", selectedChat ? name(selectedChat) : "")}
+ disabled={!canSend}
+ oninput={(e) => {
+ const el = e.currentTarget;
+ el.style.height = "auto";
+ el.style.height = Math.min(el.scrollHeight, 120) + "px";
+ }}
+ onkeydown={(e) => {
+ if (e.key === "Enter" && !e.shiftKey) {
+ e.preventDefault();
+ if (canSend && text.trim()) sendMessage(text);
+ }
+ }}
+ ></textarea>
+ <button
+ class="send-btn"
+ disabled={!canSend || !text.trim()}
+ onclick={() => sendMessage(text)}
+ aria-label="Send"
+ >
+ <iconify-icon noobserver icon="ph:paper-plane-right-fill" width="22"></iconify-icon>
+ </button>
+ </div>
{#if sendError}
<p class="warning"><em>{sendError}</em></p>
{/if}
@@ -300,6 +324,27 @@
</div>
<style>
+ .chat-container {
+ display: flex;
+ flex-direction: column;
+ height: 100%;
+ max-width: 36rem;
+ margin: 0 auto;
+ padding: 0 1rem;
+ }
+
+ .chat-header {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ padding: 0.5rem 0;
+ flex-shrink: 0;
+ }
+
+ .chat-header:hover {
+ opacity: 0.8;
+ }
+
.warning {
color: #ff7f00;
}
@@ -352,9 +397,18 @@
}
#messages {
+ flex: 1;
overflow-y: auto;
- max-height: 50vh;
scrollbar-width: thin;
+ margin-right: -1rem;
+ padding-right: 1.5rem;
+ }
+
+ @media (min-width: 36rem) {
+ #messages {
+ margin-right: 0;
+ padding-right: 0.5rem;
+ }
}
#messages::-webkit-scrollbar {
@@ -386,9 +440,51 @@
}
.input-bar {
+ flex-shrink: 0;
padding: 0.5rem 0;
+ }
+
+ .input-row {
display: flex;
- flex-direction: column;
+ align-items: flex-end;
gap: 0.5rem;
}
+
+ .input-row textarea {
+ flex: 1;
+ resize: none;
+ overflow-y: auto;
+ line-height: 1.4;
+ padding: 0.5rem 0.75rem;
+ border-radius: 1.25rem;
+ border: 1px solid rgba(128, 128, 128, 0.3);
+ background: transparent;
+ color: inherit;
+ font: inherit;
+ min-height: unset;
+ }
+
+ .input-row textarea:focus {
+ outline: none;
+ border-color: rgba(128, 128, 128, 0.6);
+ }
+
+ .send-btn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 2.5rem;
+ height: 2.5rem;
+ border-radius: 9999px;
+ background: var(--accent, #6366f1);
+ color: white;
+ border: none;
+ cursor: pointer;
+ flex-shrink: 0;
+ }
+
+ .send-btn:disabled {
+ opacity: 0.35;
+ cursor: default;
+ }
</style>