From d82277fc4a1a2fd98450ad7c889b7f471cc0112f Mon Sep 17 00:00:00 2001 From: Silberengel Date: Wed, 11 Feb 2026 11:22:52 +0100 Subject: [PATCH] deletion, reporting --- package-lock.json | 4 +- package.json | 2 +- public/healthz.json | 6 +- src/lib/components/EventMenu.svelte | 226 ++----- .../modals/DeleteAllEventsModal.svelte | 549 ++++++++++++++++++ .../components/modals/DeleteEventModal.svelte | 371 ++++++++++++ .../components/modals/ReportEventModal.svelte | 355 +++++++++++ .../components/modals/ReportUserModal.svelte | 353 +++++++++++ .../modals/VersionHistoryModal.svelte | 449 ++++++++++++++ .../profile/EditProfileEventsPanel.svelte | 379 ++++++++++++ src/lib/components/profile/ProfileMenu.svelte | 69 +++ src/lib/services/cache/event-archive.ts | 38 ++ src/lib/services/cache/event-cache.ts | 47 ++ src/lib/services/cache/indexeddb-store.ts | 10 +- src/lib/services/cache/profile-cache.ts | 12 + src/lib/services/cache/version-history.ts | 151 +++++ src/lib/types/kind-lookup.ts | 2 + src/routes/about/+page.svelte | 10 +- 18 files changed, 2844 insertions(+), 189 deletions(-) create mode 100644 src/lib/components/modals/DeleteAllEventsModal.svelte create mode 100644 src/lib/components/modals/DeleteEventModal.svelte create mode 100644 src/lib/components/modals/ReportEventModal.svelte create mode 100644 src/lib/components/modals/ReportUserModal.svelte create mode 100644 src/lib/components/modals/VersionHistoryModal.svelte create mode 100644 src/lib/components/profile/EditProfileEventsPanel.svelte create mode 100644 src/lib/services/cache/version-history.ts diff --git a/package-lock.json b/package-lock.json index e29d2e6..e9de78b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "aitherboard", - "version": "0.2.1", + "version": "0.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "aitherboard", - "version": "0.2.1", + "version": "0.3.0", "license": "MIT", "dependencies": { "@codemirror/autocomplete": "^6.20.0", diff --git a/package.json b/package.json index 8cba962..749894b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "aitherboard", - "version": "0.2.1", + "version": "0.3.0", "type": "module", "author": "silberengel@gitcitadel.com", "description": "A decentralized messageboard built on the Nostr protocol.", diff --git a/public/healthz.json b/public/healthz.json index 011f953..2d8e345 100644 --- a/public/healthz.json +++ b/public/healthz.json @@ -1,8 +1,8 @@ { "status": "ok", "service": "aitherboard", - "version": "0.2.1", - "buildTime": "2026-02-11T09:48:17.166Z", + "version": "0.3.0", + "buildTime": "2026-02-11T10:22:29.390Z", "gitCommit": "unknown", - "timestamp": 1770803297166 + "timestamp": 1770805349390 } \ No newline at end of file diff --git a/src/lib/components/EventMenu.svelte b/src/lib/components/EventMenu.svelte index 983804f..2c1d5db 100644 --- a/src/lib/components/EventMenu.svelte +++ b/src/lib/components/EventMenu.svelte @@ -5,6 +5,9 @@ import { relayManager } from '../services/nostr/relay-manager.js'; import EventJsonModal from './modals/EventJsonModal.svelte'; import PublicationStatusModal from './modals/PublicationStatusModal.svelte'; + import ReportEventModal from './modals/ReportEventModal.svelte'; + import DeleteEventModal from './modals/DeleteEventModal.svelte'; + import VersionHistoryModal from './modals/VersionHistoryModal.svelte'; import { isPinned, isBookmarked, @@ -17,7 +20,7 @@ import { sessionManager } from '../services/auth/session-manager.js'; import { signAndPublish } from '../services/nostr/auth-handler.js'; import RelatedEventsModal from './modals/RelatedEventsModal.svelte'; - import { KIND } from '../types/kind-lookup.js'; + import { KIND, isReplaceableKind, isParameterizedReplaceableKind } from '../types/kind-lookup.js'; import { goto } from '$app/navigation'; import Icon from './ui/Icon.svelte'; import { getEventLink } from '../services/event-links.js'; @@ -38,7 +41,13 @@ let broadcasting = $state(false); let deleting = $state(false); let deleteConfirmOpen = $state(false); + let reportModalOpen = $state(false); + let deleteEventModalOpen = $state(false); + let versionHistoryModalOpen = $state(false); let copied = $state(null); + + // Check if this is a replaceable event + let isReplaceable = $derived(isReplaceableKind(event.kind) || isParameterizedReplaceableKind(event.kind)); let menuButtonElement: HTMLButtonElement | null = $state(null); let menuDropdownElement: HTMLDivElement | null = $state(null); let menuPosition = $state({ top: 0, right: 0 }); @@ -365,47 +374,19 @@ closeMenu(); } - function confirmDelete() { - deleteConfirmOpen = true; + function openReportModal() { + reportModalOpen = true; closeMenu(); } - async function deleteEvent() { - if (!isLoggedIn) return; - - deleting = true; - deleteConfirmOpen = false; - - try { - // Create kind 5 deletion event - const deletionEvent: Omit = { - kind: KIND.EVENT_DELETION, - pubkey: currentUserPubkey!, // Use the current user's pubkey (the person deleting) - created_at: Math.floor(Date.now() / 1000), - tags: [['e', event.id]], // Reference the deleted event - content: '' - }; - - // Get all available relays for publishing - const relays = relayManager.getPublishRelays( - [...relayManager.getThreadReadRelays(), ...relayManager.getFeedReadRelays()], - true - ); - - // Sign and publish - const results = await signAndPublish(deletionEvent, relays); - publicationResults = results; - publicationModalOpen = true; - } catch (error) { - console.error('Error deleting event:', error); - publicationResults = { - success: [], - failed: [{ relay: 'Unknown', error: error instanceof Error ? error.message : 'Unknown error' }] - }; - publicationModalOpen = true; - } finally { - deleting = false; - } + function openDeleteModal() { + deleteEventModalOpen = true; + closeMenu(); + } + + function openVersionHistory() { + versionHistoryModalOpen = true; + closeMenu(); } @@ -435,6 +416,12 @@ View JSON + {#if isReplaceable} + + {/if} @@ -517,12 +504,21 @@ {/if} + + {#if isLoggedIn && !isOwnEvent} + + + {/if} + {#if isLoggedIn && isOwnEvent} - {/if} @@ -532,41 +528,9 @@ - -{#if deleteConfirmOpen} - -{/if} + reportModalOpen = false} /> + deleteEventModalOpen = false} /> + versionHistoryModalOpen = false} /> diff --git a/src/lib/components/modals/DeleteAllEventsModal.svelte b/src/lib/components/modals/DeleteAllEventsModal.svelte new file mode 100644 index 0000000..f5d303c --- /dev/null +++ b/src/lib/components/modals/DeleteAllEventsModal.svelte @@ -0,0 +1,549 @@ + + +{#if open} + +{/if} + + + + diff --git a/src/lib/components/modals/DeleteEventModal.svelte b/src/lib/components/modals/DeleteEventModal.svelte new file mode 100644 index 0000000..81426ec --- /dev/null +++ b/src/lib/components/modals/DeleteEventModal.svelte @@ -0,0 +1,371 @@ + + +{#if open} + +{/if} + + + + diff --git a/src/lib/components/modals/ReportEventModal.svelte b/src/lib/components/modals/ReportEventModal.svelte new file mode 100644 index 0000000..2bbe392 --- /dev/null +++ b/src/lib/components/modals/ReportEventModal.svelte @@ -0,0 +1,355 @@ + + +{#if open} + +{/if} + + + + diff --git a/src/lib/components/modals/ReportUserModal.svelte b/src/lib/components/modals/ReportUserModal.svelte new file mode 100644 index 0000000..46ce27c --- /dev/null +++ b/src/lib/components/modals/ReportUserModal.svelte @@ -0,0 +1,353 @@ + + +{#if open} + +{/if} + + + + diff --git a/src/lib/components/modals/VersionHistoryModal.svelte b/src/lib/components/modals/VersionHistoryModal.svelte new file mode 100644 index 0000000..420e4a1 --- /dev/null +++ b/src/lib/components/modals/VersionHistoryModal.svelte @@ -0,0 +1,449 @@ + + +{#if open} + +{/if} + + diff --git a/src/lib/components/profile/EditProfileEventsPanel.svelte b/src/lib/components/profile/EditProfileEventsPanel.svelte new file mode 100644 index 0000000..509efc2 --- /dev/null +++ b/src/lib/components/profile/EditProfileEventsPanel.svelte @@ -0,0 +1,379 @@ + + +{#if isOpen} +
{ + if (e.key === 'Enter' || e.key === ' ') { + e.preventDefault(); + onClose(); + } + }} + role="button" + tabindex="0" + aria-label="Close panel" + >
+
+
+

Edit Profile Events

+ +
+ +
+
+ {#each PROFILE_EVENT_KINDS as { kind, name }} + {@const event = eventMap.get(kind)} + {@const isLoading = loadingKinds.has(kind)} + {@const isLoaded = loadedKinds.has(kind)} +
+
+ {name} + Kind {kind} +
+
+ {#if isLoading} + Loading... + {:else if event} + + {:else if isLoaded} + + {:else} + + {/if} +
+
+ {/each} +
+
+
+{/if} + + diff --git a/src/lib/components/profile/ProfileMenu.svelte b/src/lib/components/profile/ProfileMenu.svelte index f4bf5c1..15b8ae6 100644 --- a/src/lib/components/profile/ProfileMenu.svelte +++ b/src/lib/components/profile/ProfileMenu.svelte @@ -9,6 +9,9 @@ import type { NostrEvent } from '../../types/nostr.js'; import { toggleMute, toggleFollow, isMuted, isFollowed } from '../../services/user-actions.js'; import Icon from '../ui/Icon.svelte'; + import EditProfileEventsPanel from './EditProfileEventsPanel.svelte'; + import ReportUserModal from '../modals/ReportUserModal.svelte'; + import DeleteAllEventsModal from '../modals/DeleteAllEventsModal.svelte'; // @ts-ignore - highlight.js default export works at runtime import hljs from 'highlight.js'; import 'highlight.js/styles/vs2015.css'; @@ -30,6 +33,9 @@ let following = $state(false); let showJsonModal = $state(false); let jsonPreviewRef: HTMLElement | null = $state(null); + let showEditProfileEventsPanel = $state(false); + let showReportModal = $state(false); + let showDeleteAllEventsModal = $state(false); // Highlight JSON when profileEvent or showJsonModal changes $effect(() => { @@ -343,6 +349,33 @@ closeMenu(); } } + + function openEditProfileEventsPanel() { + showEditProfileEventsPanel = true; + closeMenu(); + } + + function closeEditProfileEventsPanel() { + showEditProfileEventsPanel = false; + } + + function openReportModal() { + showReportModal = true; + closeMenu(); + } + + function closeReportModal() { + showReportModal = false; + } + + function openDeleteAllEventsModal() { + showDeleteAllEventsModal = true; + closeMenu(); + } + + function closeDeleteAllEventsModal() { + showDeleteAllEventsModal = false; + }
@@ -392,6 +425,24 @@ {/if} + {#if isOwnProfile} + + + {/if} + + {#if isLoggedIn && !isOwnProfile} + + {/if} +
{/if} + + + + + +