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.
238 lines
5.4 KiB
238 lines
5.4 KiB
<script lang="ts"> |
|
import type { NostrEvent } from '../../types/nostr.js'; |
|
import Icon from '../ui/Icon.svelte'; |
|
|
|
interface Props { |
|
open?: boolean; |
|
event?: NostrEvent | null; |
|
} |
|
|
|
let { open = $bindable(false), event = $bindable(null) }: Props = $props(); |
|
let jsonText = $derived(event ? JSON.stringify(event, null, 2) : ''); |
|
let copied = $state(false); |
|
|
|
function close() { |
|
open = false; |
|
} |
|
|
|
async function copyJson() { |
|
if (!jsonText) return; |
|
try { |
|
await navigator.clipboard.writeText(jsonText); |
|
copied = true; |
|
setTimeout(() => { |
|
copied = false; |
|
}, 2000); |
|
} catch (error) { |
|
console.error('Failed to copy JSON:', error); |
|
} |
|
} |
|
|
|
function selectAll() { |
|
const textarea = document.querySelector('.json-textarea') as HTMLTextAreaElement; |
|
if (textarea) { |
|
textarea.select(); |
|
} |
|
} |
|
</script> |
|
|
|
{#if open && event} |
|
<div |
|
class="modal-overlay" |
|
onclick={(e) => { |
|
// Only close if clicking directly on the overlay, not on modal content |
|
if (e.target === e.currentTarget) { |
|
close(); |
|
} |
|
}} |
|
onkeydown={(e) => { |
|
if (e.key === 'Escape' || e.key === 'Enter' || e.key === ' ') { |
|
e.preventDefault(); |
|
close(); |
|
} |
|
}} |
|
role="dialog" |
|
aria-modal="true" |
|
aria-label="Event JSON modal" |
|
tabindex="-1" |
|
> |
|
<div class="modal-content"> |
|
<div class="modal-header"> |
|
<h2>Event JSON</h2> |
|
<button onclick={close} class="close-button" aria-label="Close"> |
|
<Icon name="x" size={20} /> |
|
</button> |
|
</div> |
|
|
|
<div class="modal-body"> |
|
<textarea |
|
class="json-textarea" |
|
readonly |
|
value={jsonText} |
|
onclick={selectAll} |
|
></textarea> |
|
</div> |
|
|
|
<div class="modal-footer"> |
|
<button onclick={copyJson} class="copy-button flex items-center gap-2"> |
|
<Icon name="copy" size={16} /> |
|
<span>{copied ? 'Copied!' : 'Copy'}</span> |
|
</button> |
|
<button onclick={close} class="flex items-center gap-2"> |
|
<Icon name="x" size={16} /> |
|
<span>Close</span> |
|
</button> |
|
</div> |
|
</div> |
|
</div> |
|
{/if} |
|
|
|
<style> |
|
.modal-overlay { |
|
position: fixed; |
|
top: 0; |
|
left: 0; |
|
right: 0; |
|
bottom: 0; |
|
background: rgba(15, 23, 42, 0.4); |
|
backdrop-filter: blur(4px); |
|
display: flex; |
|
align-items: center; |
|
justify-content: center; |
|
z-index: 1000; |
|
} |
|
|
|
.modal-content { |
|
background: var(--fog-post, #ffffff); |
|
border: 1px solid var(--fog-border, #e5e7eb); |
|
border-radius: 8px; |
|
max-width: 800px; |
|
width: 90%; |
|
max-height: 80vh; |
|
display: flex; |
|
flex-direction: column; |
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.1); |
|
} |
|
|
|
:global(.dark) .modal-content { |
|
background: var(--fog-dark-post, #1f2937); |
|
border-color: var(--fog-dark-border, #374151); |
|
box-shadow: 0 10px 25px rgba(0, 0, 0, 0.3); |
|
} |
|
|
|
.modal-header { |
|
display: flex; |
|
justify-content: space-between; |
|
align-items: center; |
|
padding: 1rem; |
|
border-bottom: 1px solid var(--fog-border, #e5e7eb); |
|
} |
|
|
|
:global(.dark) .modal-header { |
|
border-bottom-color: var(--fog-dark-border, #374151); |
|
} |
|
|
|
.modal-header h2 { |
|
margin: 0; |
|
font-size: 1.25rem; |
|
color: var(--fog-text, #1f2937); |
|
} |
|
|
|
:global(.dark) .modal-header h2 { |
|
color: var(--fog-dark-text, #f1f5f9); |
|
} |
|
|
|
.close-button { |
|
background: none; |
|
border: none; |
|
font-size: 1.5rem; |
|
cursor: pointer; |
|
padding: 0; |
|
width: 2rem; |
|
height: 2rem; |
|
color: var(--fog-text, #1f2937); |
|
display: inline-flex; |
|
align-items: center; |
|
justify-content: center; |
|
} |
|
|
|
:global(.dark) .close-button { |
|
color: var(--fog-dark-text, #f1f5f9); |
|
} |
|
|
|
.modal-body { |
|
padding: 1rem; |
|
flex: 1; |
|
overflow: auto; |
|
} |
|
|
|
.json-textarea { |
|
width: 100%; |
|
min-height: 400px; |
|
font-family: 'Courier New', monospace; |
|
font-size: 0.875rem; |
|
padding: 0.75rem; |
|
border: 1px solid var(--fog-border, #e5e7eb); |
|
border-radius: 4px; |
|
background: var(--fog-bg, #ffffff); |
|
color: var(--fog-text, #1f2937); |
|
resize: vertical; |
|
} |
|
|
|
:global(.dark) .json-textarea { |
|
background: var(--fog-dark-bg, #0f172a); |
|
border-color: var(--fog-dark-border, #374151); |
|
color: var(--fog-dark-text, #f1f5f9); |
|
} |
|
|
|
.modal-footer { |
|
padding: 1rem; |
|
border-top: 1px solid var(--fog-border, #e5e7eb); |
|
display: flex; |
|
justify-content: flex-end; |
|
gap: 0.5rem; |
|
} |
|
|
|
:global(.dark) .modal-footer { |
|
border-top-color: var(--fog-dark-border, #374151); |
|
} |
|
|
|
.modal-footer button { |
|
padding: 0.5rem 1rem; |
|
border: none; |
|
border-radius: 4px; |
|
cursor: pointer; |
|
transition: background-color 0.2s; |
|
font-size: 0.875rem; |
|
display: inline-flex; |
|
align-items: center; |
|
gap: 0.5rem; |
|
} |
|
|
|
.copy-button { |
|
background: var(--fog-accent, #64748b); |
|
color: white; |
|
} |
|
|
|
.copy-button:hover { |
|
background: var(--fog-accent-dark, #475569); |
|
} |
|
|
|
.modal-footer button:not(.copy-button) { |
|
background: var(--fog-border, #e5e7eb); |
|
color: var(--fog-text, #1f2937); |
|
} |
|
|
|
.modal-footer button:not(.copy-button):hover { |
|
background: var(--fog-highlight, #f3f4f6); |
|
} |
|
|
|
:global(.dark) .modal-footer button:not(.copy-button) { |
|
background: var(--fog-dark-border, #374151); |
|
color: var(--fog-dark-text, #f1f5f9); |
|
} |
|
|
|
:global(.dark) .modal-footer button:not(.copy-button):hover { |
|
background: var(--fog-dark-highlight, #374151); |
|
} |
|
</style>
|
|
|