You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
209 lines
5.5 KiB
209 lines
5.5 KiB
<script lang="ts"> |
|
import { getBookmarkedEvents } from '../../services/user-actions.js'; |
|
import { nostrClient } from '../../services/nostr/nostr-client.js'; |
|
import { relayManager } from '../../services/nostr/relay-manager.js'; |
|
import { sessionManager } from '../../services/auth/session-manager.js'; |
|
import FeedPost from '../../modules/feed/FeedPost.svelte'; |
|
import { onMount } from 'svelte'; |
|
import type { NostrEvent } from '../../types/nostr.js'; |
|
import { KIND } from '../../types/kind-lookup.js'; |
|
import { goto } from '$app/navigation'; |
|
|
|
interface Props { |
|
isOpen: boolean; |
|
onClose: () => void; |
|
} |
|
|
|
let { isOpen, onClose }: Props = $props(); |
|
|
|
let bookmarkedEvents = $state<NostrEvent[]>([]); |
|
let loading = $state(true); |
|
|
|
function navigateToEvent(event: NostrEvent) { |
|
goto(`/event/${event.id}`); |
|
} |
|
|
|
$effect(() => { |
|
if (isOpen) { |
|
loadBookmarks(); |
|
} |
|
}); |
|
|
|
async function loadBookmarks() { |
|
loading = true; |
|
try { |
|
// Get bookmarks from published kind 10003 event (from cache/relays) |
|
const allBookmarkedIds = await getBookmarkedEvents(); |
|
|
|
console.log('[BookmarksPanel] Total bookmarked IDs to fetch:', allBookmarkedIds.size, Array.from(allBookmarkedIds)); |
|
|
|
if (allBookmarkedIds.size === 0) { |
|
bookmarkedEvents = []; |
|
loading = false; |
|
return; |
|
} |
|
|
|
const profileRelays = relayManager.getProfileReadRelays(); |
|
const events = await nostrClient.fetchEvents( |
|
[{ ids: Array.from(allBookmarkedIds), limit: 100 }], |
|
profileRelays, |
|
{ useCache: true, cacheResults: true, timeout: 10000 } |
|
); |
|
|
|
console.log('[BookmarksPanel] Fetched', events.length, 'events out of', allBookmarkedIds.size, 'bookmarked IDs'); |
|
|
|
// Log which IDs were not found |
|
const foundIds = new Set(events.map(e => e.id)); |
|
const missingIds = Array.from(allBookmarkedIds).filter(id => !foundIds.has(id)); |
|
if (missingIds.length > 0) { |
|
console.warn('[BookmarksPanel] Could not find events for these bookmarked IDs:', missingIds); |
|
} |
|
|
|
// Sort by created_at descending |
|
bookmarkedEvents = events.sort((a, b) => b.created_at - a.created_at); |
|
} catch (error) { |
|
console.error('Error loading bookmarks:', error); |
|
bookmarkedEvents = []; |
|
} finally { |
|
loading = false; |
|
} |
|
} |
|
</script> |
|
|
|
{#if isOpen} |
|
<div |
|
class="bookmarks-panel-overlay" |
|
onclick={(e) => { |
|
// Only close if clicking directly on the overlay, not on the panel |
|
if (e.target === e.currentTarget) { |
|
onClose(); |
|
} |
|
}} |
|
onkeydown={(e) => { |
|
if (e.key === 'Escape') { |
|
onClose(); |
|
} |
|
}} |
|
role="dialog" |
|
aria-modal="true" |
|
aria-label="Bookmarks panel" |
|
tabindex="-1" |
|
> |
|
<div |
|
class="bookmarks-panel" |
|
> |
|
<div class="bookmarks-panel-header"> |
|
<h2 class="bookmarks-panel-title">Bookmarks</h2> |
|
<button class="bookmarks-panel-close" onclick={onClose} aria-label="Close bookmarks"> |
|
✕ |
|
</button> |
|
</div> |
|
|
|
<div class="bookmarks-panel-content"> |
|
{#if loading} |
|
<p class="text-fog-text-light dark:text-fog-dark-text-light">Loading bookmarks...</p> |
|
{:else if bookmarkedEvents.length === 0} |
|
<p class="text-fog-text-light dark:text-fog-dark-text-light">No bookmarks yet.</p> |
|
{:else} |
|
<div class="bookmarks-list"> |
|
{#each bookmarkedEvents as event (event.id)} |
|
<FeedPost post={event} onOpenEvent={navigateToEvent} /> |
|
{/each} |
|
</div> |
|
{/if} |
|
</div> |
|
</div> |
|
</div> |
|
{/if} |
|
|
|
<style> |
|
.bookmarks-panel-overlay { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
bottom: 0; |
|
background: rgba(0, 0, 0, 0.5); |
|
z-index: 1000; |
|
display: flex; |
|
align-items: stretch; |
|
} |
|
|
|
.bookmarks-panel { |
|
width: 400px; |
|
max-width: 90vw; |
|
background: var(--fog-post, #ffffff); |
|
border-right: 1px solid var(--fog-border, #e5e7eb); |
|
display: flex; |
|
flex-direction: column; |
|
overflow: hidden; |
|
} |
|
|
|
:global(.dark) .bookmarks-panel { |
|
background: var(--fog-dark-post, #1f2937); |
|
border-right-color: var(--fog-dark-border, #374151); |
|
} |
|
|
|
.bookmarks-panel-header { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
padding: 1rem; |
|
border-bottom: 1px solid var(--fog-border, #e5e7eb); |
|
} |
|
|
|
:global(.dark) .bookmarks-panel-header { |
|
border-bottom-color: var(--fog-dark-border, #374151); |
|
} |
|
|
|
.bookmarks-panel-title { |
|
margin: 0; |
|
font-size: 1.25rem; |
|
font-weight: 600; |
|
color: var(--fog-text, #1f2937); |
|
} |
|
|
|
:global(.dark) .bookmarks-panel-title { |
|
color: var(--fog-dark-text, #f9fafb); |
|
} |
|
|
|
.bookmarks-panel-close { |
|
background: none; |
|
border: none; |
|
font-size: 1.5rem; |
|
cursor: pointer; |
|
color: var(--fog-text-light, #6b7280); |
|
padding: 0; |
|
width: 2rem; |
|
height: 2rem; |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
border-radius: 0.25rem; |
|
transition: background 0.2s; |
|
} |
|
|
|
:global(.dark) .bookmarks-panel-close { |
|
color: var(--fog-dark-text-light, #9ca3af); |
|
} |
|
|
|
.bookmarks-panel-close:hover { |
|
background: var(--fog-highlight, #f3f4f6); |
|
} |
|
|
|
:global(.dark) .bookmarks-panel-close:hover { |
|
background: var(--fog-dark-highlight, #374151); |
|
} |
|
|
|
.bookmarks-panel-content { |
|
flex: 1; |
|
overflow-y: auto; |
|
padding: 1rem; |
|
} |
|
|
|
.bookmarks-list { |
|
display: flex; |
|
flex-direction: column; |
|
gap: 1rem; |
|
} |
|
</style>
|
|
|