mirror of
https://github.com/inpharmaticist/inpharmaticist.github.io.git
synced 2026-04-26 16:54:02 +00:00
178 lines
5.7 KiB
HTML
178 lines
5.7 KiB
HTML
<div class="nostr-contact-wrapper not-prose">
|
|
<style>
|
|
.nostr-contact-wrapper {
|
|
max-width: 600px;
|
|
margin: 2rem 0;
|
|
font-family: inherit;
|
|
color: #000;
|
|
}
|
|
.nostr-contact-wrapper label {
|
|
display: block;
|
|
margin-bottom: 0.5rem;
|
|
font-weight: 600;
|
|
font-size: 0.9rem;
|
|
color: #000; /* Light mode: black */
|
|
}
|
|
/* Dark mode override */
|
|
.dark .nostr-contact-wrapper label {
|
|
color: #fff; /* Dark mode: white */
|
|
}
|
|
|
|
.nostr-contact-wrapper input,
|
|
.nostr-contact-wrapper textarea {
|
|
width: 100%;
|
|
padding: 0.75rem;
|
|
border: 1px solid #e5e7eb;
|
|
border-radius: 0.375rem;
|
|
background: white;
|
|
font-size: 1rem;
|
|
color: #000;
|
|
}
|
|
/* Optional: Dark mode input styling */
|
|
.dark .nostr-contact-wrapper input,
|
|
.dark .nostr-contact-wrapper textarea {
|
|
background: #1f2937;
|
|
border-color: #374151;
|
|
color: #fff;
|
|
}
|
|
|
|
.nostr-contact-wrapper small {
|
|
display: block;
|
|
margin-top: 0.25rem;
|
|
color: #374151; /* Light mode */
|
|
font-size: 0.875rem;
|
|
}
|
|
.dark .nostr-contact-wrapper small {
|
|
color: #9ca3af; /* Dark mode: lighter grey */
|
|
}
|
|
.nostr-contact-wrapper button {
|
|
background: #111827;
|
|
color: white;
|
|
padding: 0.75rem 1.5rem;
|
|
border-radius: 0.375rem;
|
|
font-weight: 600;
|
|
width: 100%;
|
|
cursor: pointer;
|
|
border: none; /* Ensure no default borders */
|
|
}
|
|
.nostr-contact-wrapper button:hover {
|
|
background: #374151;
|
|
}
|
|
|
|
/* Dark mode: Invert button to light */
|
|
.dark .nostr-contact-wrapper button {
|
|
background: #fff;
|
|
color: #000;
|
|
}
|
|
.dark .nostr-contact-wrapper button:hover {
|
|
background: #e5e7eb;
|
|
}
|
|
|
|
</style>
|
|
|
|
<form id="nostr-contact-form" onsubmit="return false;">
|
|
<div class="form-group">
|
|
<label for="nc-name">Name</label>
|
|
<input type="text" id="nc-name" required>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="nc-contact">Contact Info</label>
|
|
<input type="text" id="nc-contact" placeholder="email@example.com" required>
|
|
<small>How you want to be contacted back</small>
|
|
</div>
|
|
<div class="form-group">
|
|
<label for="nc-message">Message</label>
|
|
<textarea id="nc-message" rows="5" required></textarea>
|
|
</div>
|
|
<button type="submit" id="nc-submit">Send Message</button>
|
|
</form>
|
|
<div id="nc-status"></div>
|
|
|
|
<script src="https://unpkg.com/nostr-tools@1.17.0/lib/nostr.bundle.js"></script>
|
|
<script>
|
|
(function() {
|
|
const RECIPIENT_NPUB = {{ .Get "npub" | default "npub1c0r3ytrr4afgrlhrhyec6y9wvkckdllx7ul3cfevtsgjqcrhx8tsdzqs7w" }};
|
|
const RELAYS = {{ .Get "relays" | default `["wss://relay.damus.io","wss://nos.lol"]` | safeJS }};
|
|
|
|
let RECIPIENT_HEX;
|
|
try {
|
|
RECIPIENT_HEX = window.NostrTools.nip19.decode(RECIPIENT_NPUB).data;
|
|
} catch(e) {
|
|
console.error("Invalid npub");
|
|
}
|
|
|
|
document.getElementById('nostr-contact-form').addEventListener('submit', async (e) => {
|
|
e.preventDefault();
|
|
const btn = document.getElementById('nc-submit');
|
|
const status = document.getElementById('nc-status');
|
|
|
|
if (!RECIPIENT_HEX) {
|
|
status.innerHTML = '<strong>Config error:</strong> Invalid npub';
|
|
status.className = 'error';
|
|
return;
|
|
}
|
|
|
|
btn.disabled = true;
|
|
btn.textContent = 'Sending...';
|
|
status.className = '';
|
|
status.style.display = 'none';
|
|
|
|
try {
|
|
const sk = window.NostrTools.generatePrivateKey();
|
|
const pk = window.NostrTools.getPublicKey(sk);
|
|
|
|
const content = await window.NostrTools.nip04.encrypt(sk, RECIPIENT_HEX, JSON.stringify({
|
|
name: document.getElementById('nc-name').value,
|
|
contact: document.getElementById('nc-contact').value,
|
|
message: document.getElementById('nc-message').value,
|
|
timestamp: new Date().toISOString(),
|
|
source: 'sdbitcoiners.com'
|
|
}));
|
|
|
|
const event = {
|
|
kind: 4,
|
|
pubkey: pk,
|
|
created_at: Math.floor(Date.now() / 1000),
|
|
tags: [['p', RECIPIENT_HEX]],
|
|
content: content
|
|
};
|
|
event.id = window.NostrTools.getEventHash(event);
|
|
event.sig = window.NostrTools.signEvent(event, sk);
|
|
|
|
const results = await Promise.all(RELAYS.map(url =>
|
|
new Promise(resolve => {
|
|
const ws = new WebSocket(url);
|
|
const timeout = setTimeout(() => { ws.close(); resolve(false); }, 5000);
|
|
ws.onopen = () => ws.send(JSON.stringify(['EVENT', event]));
|
|
ws.onmessage = (msg) => {
|
|
const data = JSON.parse(msg.data);
|
|
if (data[0] === 'OK' && data[1] === event.id) {
|
|
clearTimeout(timeout);
|
|
ws.close();
|
|
resolve(true);
|
|
}
|
|
};
|
|
ws.onerror = () => { clearTimeout(timeout); ws.close(); resolve(false); };
|
|
})
|
|
));
|
|
|
|
const count = results.filter(r => r).length;
|
|
if (count > 0) {
|
|
status.innerHTML = `<strong>Message sent!</strong><br>Published to ${count} relay(s)`;
|
|
status.className = 'success';
|
|
document.getElementById('nostr-contact-form').reset();
|
|
} else {
|
|
throw new Error('No relays accepted');
|
|
}
|
|
} catch(err) {
|
|
status.innerHTML = '<strong>Error:</strong> Failed to send. Try again later.';
|
|
status.className = 'error';
|
|
} finally {
|
|
btn.disabled = false;
|
|
btn.textContent = 'Send Message';
|
|
}
|
|
});
|
|
})();
|
|
</script>
|
|
</div>
|