Commit 7efc4c6d41ab
tarball2 files changed+67-20
@@ -449,11 +449,12 @@
449449
selectedSpaceId = null;450450
spaceChildIds = null;451451
spaceChildrenError = null;452
+ if (window.innerWidth > 640) navFolded.set(false);452453
sidebarOpen = true;453454
}454455
455456
function toggleChannelsPane(): void {456
- if (window.innerWidth <= 1100) sidebarOpen = !sidebarOpen;457
+ if (window.innerWidth <= 640) sidebarOpen = !sidebarOpen;457458
else navFolded.update((v) => !v);458459
}459460
@@ -469,6 +470,7 @@
469470
if (resume) {470471
void selectRoom(resume);471472
} else {473
+ if (window.innerWidth > 640) navFolded.set(false);472474
sidebarOpen = true;473475
// A space is navigation, not a message timeline.474476
selectedRoomId.set(null);@@ -478,6 +480,7 @@
478480
if (selectedSpaceId === spaceId) {479481
spaceChildIds = res.room_ids ?? [];480482
if (resume && !spaceChildIds.includes(resume) && $selectedRoomId === resume) {483
+ if (window.innerWidth > 640) navFolded.set(false);481484
sidebarOpen = true;482485
selectedRoomId.set(null);483486
}@@ -924,6 +927,8 @@
924927
925928
let pinnedOpenFor: string | null = null;926929
let pinsExpanded = false;930
+ let pinPreview: TimelineEvent | null = null;931
+ let pinJumpBusy = false;927932
$: syncPinned(selectedRoom?.room_id ?? null, (selectedRoom?.pinned_events.length ?? 0) > 0);928933
function syncPinned(roomId: string | null, hasPins: boolean): void {929934
const want = hasPins ? roomId : null;@@ -951,9 +956,29 @@
951956
);952957
}953958
954
- function jumpToPin(eventId: string): void {959
+ async function jumpToPin(eventId: string): Promise<void> {960
+ const roomId = $selectedRoomId;961
+ if (!roomId || !eventId || pinJumpBusy) return;955962
pinsExpanded = false;956
- jumpTo(eventId);963
+ pinPreview = pins.find((event) => event.event_id === eventId) ?? null;964
+ pinJumpBusy = true;965
+ try {966
+ for (let attempt = 0; attempt < 24; attempt += 1) {967
+ if (($timelines[roomId] ?? []).some((item) => item.kind === 'event' && item.event.event_id === eventId)) {968
+ pinPreview = null;969
+ await tick();970
+ jumpTo(eventId);971
+ return;972
+ }973
+ await paginateRoom(roomId);974
+ await new Promise((resolve) => window.setTimeout(resolve, 180));975
+ }976
+ pushBanner('Could not load that pinned message');977
+ } catch (e) {978
+ pushBanner(e instanceof Error ? e.message : 'Could not load that pinned message');979
+ } finally {980
+ pinJumpBusy = false;981
+ }957982
}958983
959984
function jumpTo(eventId: string): void {@@ -1716,7 +1741,7 @@
17161741
{:else}17171742
<div17181743
class="app"1719
- class:nav-folded={$navFolded && (selectedRoom || sidebarOpen)}1744
+ class:nav-folded={$navFolded}17201745
class:rail-folded={$railFolded && selectedRoom}17211746
class:members-open={selectedRoom && membersOpen}17221747
class:sidebar-open={sidebarOpen}@@ -2257,6 +2282,19 @@
22572282
<p class="conn-banner error" role="alert">{openFailed[$selectedRoomId]}</p>22582283
{/if}22592284
2285
+ {#if pinPreview}2286
+ <div class="pin-preview" role="dialog" aria-label="Pinned message preview">2287
+ <div class="pin-preview-head">2288
+ <strong>{people[pinPreview.sender.user_id]?.name ?? senderLabel(pinPreview.sender)}</strong>2289
+ <button type="button" class="icon-btn" aria-label="Close pinned message preview" on:click={() => (pinPreview = null)}>✕</button>2290
+ </div>2291
+ <p>{contentPreview(pinPreview.content)}</p>2292
+ <button type="button" class="primary-btn" disabled={pinJumpBusy} on:click={() => void jumpToPin(pinPreview?.event_id ?? '')}>2293
+ {pinJumpBusy ? 'Loading message…' : 'Jump to message'}2294
+ </button>2295
+ </div>2296
+ {/if}2297
+22602298
<!-- svelte-ignore a11y_no_static_element_interactions -->22612299
<div22622300
class="timeline"@@ -282,10 +282,11 @@ input, textarea { font: inherit; }
282282
min-height: 0;283283
}284284
.side-search {285
+ order: 2;285286
display: flex;286287
gap: 4px;287288
padding: 8px;288
- border-bottom: 1px solid var(--border);289
+ border-top: 1px solid var(--border);289290
}290291
.side-search input {291292
flex: 1;@@ -298,7 +299,7 @@ input, textarea { font: inherit; }
298299
padding: 0 10px;299300
}300301
.side-search input:focus { outline: none; border-color: var(--accent); }301
-.side-scroll { flex: 1; overflow-y: auto; padding: 6px; min-height: 0; }302
+.side-scroll { order: 1; flex: 1; overflow-y: auto; padding: 6px; min-height: 0; }302303
.side-h {303304
font-size: 10.5px;304305
font-weight: 650;@@ -463,7 +464,7 @@ input, textarea { font: inherit; }
463464
.scrim { display: none; }464465
465466
/* ——— Chat ——— */466
-.chat { display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--bg); }467
+.chat { position: relative; display: flex; flex-direction: column; min-width: 0; min-height: 0; background: var(--bg); }467468
.empty {468469
margin: auto;469470
text-align: center;@@ -583,7 +584,7 @@ input, textarea { font: inherit; }
583584
.ghost-btn.danger { color: var(--danger); }584585
.ghost-btn.danger:hover:not(:disabled) { border-color: var(--danger); }585586
586
-.banners { display: flex; flex-direction: column; gap: 6px; padding: 8px 12px 0; }587
+.banners { position: absolute; top: 8px; left: 12px; right: 12px; z-index: 12; display: flex; flex-direction: column; gap: 6px; pointer-events: none; }587588
.banner {588589
display: flex;589590
align-items: center;@@ -595,6 +596,7 @@ input, textarea { font: inherit; }
595596
padding: 6px 10px;596597
font-size: 13px;597598
animation: pop-in var(--pop);599
+ pointer-events: auto;598600
}599601
.banner span { flex: 1; }600602
.banner button {@@ -613,6 +615,10 @@ input, textarea { font: inherit; }
613615
color: var(--warn-text);614616
font-size: 12.5px;615617
}618
+.pin-preview { position: absolute; top: 56px; right: 16px; z-index: 11; width: min(360px, calc(100% - 32px)); padding: 12px; border: 1px solid var(--border); border-radius: var(--r-lg); background: var(--panel); box-shadow: 0 12px 36px rgb(0 0 0 / 0.35); animation: pop-in var(--pop); }619
+.pin-preview-head { display: flex; align-items: center; gap: 8px; }620
+.pin-preview-head strong { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }621
+.pin-preview p { margin: 8px 0 12px; color: var(--muted); overflow-wrap: anywhere; }616622
617623
.timeline {618624
flex: 1;@@ -946,19 +952,22 @@ input, textarea { font: inherit; }
946952
.only-mobile { display: none; }947953
.only-desktop { display: inline-block; }948954
.app { transition: grid-template-columns var(--pane-ease); }949
- .app > .sidebar { left: var(--rail-w); transform: translateX(calc(-100% - var(--rail-w))); }950
- .app > .sidebar.open { transform: none; }951
- .scrim { left: var(--rail-w); }952
- .app > .account {953
- position: fixed;954
- left: var(--rail-w);955
- bottom: 0;956
- z-index: 41;957
- width: var(--side-open, 260px);958
- transform: translateX(calc(-100% - var(--rail-w)));959
- transition: transform var(--pane-ease);955
+ .app { --side-w: var(--side-open, 260px); }956
+ .app.rail-folded { --rail-w: 0px; }957
+ .app.rail-folded > .rail { visibility: hidden !important; }958
+ .app > .sidebar {959
+ position: relative;960
+ left: auto;961
+ top: auto;962
+ bottom: auto;963
+ width: auto;964
+ transform: none;965
+ box-shadow: none;966
+ transition: visibility 0s linear 0s;960967
}961
- .app.sidebar-open > .account { transform: none; }968
+ .app > .sidebar > * { min-width: var(--side-open, 260px); }969
+ .app.nav-folded > .sidebar { visibility: hidden !important; transition: visibility 0s linear 0.22s; }970
+ .scrim { display: none; }962971
.app > .members {963972
position: relative;964973
top: auto;