mirror of
https://github.com/inpharmaticist/inpharmaticist.github.io.git
synced 2026-04-26 16:54:02 +00:00
Compare commits
20 Commits
1099deb3e1
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5108c4c19d | ||
|
|
a8542cad50 | ||
|
|
a023c35de1 | ||
|
|
dbd84dda59 | ||
|
|
5b7e2e4611 | ||
|
|
a25a09d9fe | ||
|
|
5573dfc47d | ||
|
|
834ca47b2f | ||
|
|
05c09ff64d | ||
|
|
0160b74c88 | ||
|
|
ede860141d | ||
|
|
99f49da78d | ||
|
|
1af6e9f083 | ||
|
|
2bf14b4528 | ||
|
|
b97b335c30 | ||
|
|
131b315611 | ||
|
|
af5b4db41a | ||
|
|
0c513f965c | ||
|
|
ce4279e0ec | ||
|
|
e6e6edc645 |
@@ -8,9 +8,7 @@ next: events
|
|||||||
weight: 5
|
weight: 5
|
||||||
breadcrumbs: false
|
breadcrumbs: false
|
||||||
---
|
---
|
||||||
(if the form doesn't show up click [here](https://formstr.app/#/fill/f5ff29ea0fc13932da373f91dc0030998431f3626476acc8ff8a30bd78bf2c2a))
|
|
||||||
|
|
||||||
<center>
|
Send me a message via Nostr:
|
||||||
<iframe src="https://formstr.app/#/embedded/f5ff29ea0fc13932da373f91dc0030998431f3626476acc8ff8a30bd78bf2c2a?hideTitleImage=true&hideDescription=true" height="1200px" width="480px" frameborder="0" style="border-style:none;box-shadow:0px 0px 2px 2px rgba(0,0,0,0.2);" cellspacing="0" >
|
|
||||||
</iframe>
|
{{< nostr-contact npub="npub1youractualkeyhere" >}}
|
||||||
<center>
|
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ markup:
|
|||||||
menu:
|
menu:
|
||||||
main:
|
main:
|
||||||
- name: Contact ↗
|
- name: Contact ↗
|
||||||
url: "https://formstr.app/#/fill/f5ff29ea0fc13932da373f91dc0030998431f3626476acc8ff8a30bd78bf2c2a"
|
url: "https://formstr.app/f/naddr1qvzqqqr4mqpzpafdewsuthj5k8sfre227a6hyn008meuk2jpdg0gl6ltfp809cpfqy2hwumn8ghj7un9d3shjtnyv9kh2uewd9hj7qghwaehxw309aex2mrp0yh8qunfd4skctnwv46z7qgdwaehxw309ahx7uewd3hkcqg7waehxw309aex2mrp0yhxummnw3ezuamfwfjkgmn9wshx5up0qyw8wumn8ghj7mn0wd68ytfsxyh8jcttd95x7mnwv5hxxmmdqyv8wumn8ghj7un9d3shjtnndehhyapwwdhkx6tpdsq3vamnwvaz7tmjv4kxz7fwdehhxarj9e3xzmnyqyghwumn8ghj7mn0wd68yv339e3k7mgqqcc9yapctyuqa0w6ey?viewKey=c709e0eefda9d435fe65e06dbc2a185fb960133bce208301d0772004f822c216"
|
||||||
weight: 1
|
weight: 1
|
||||||
- name: Twitter
|
- name: Twitter
|
||||||
weight: 2
|
weight: 2
|
||||||
|
|||||||
256
layouts/shortcodes/nostr-contact.html
Normal file
256
layouts/shortcodes/nostr-contact.html
Normal file
@@ -0,0 +1,256 @@
|
|||||||
|
<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 .form-group {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
.nostr-contact-wrapper label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
font-size: 0.9rem;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.dark .nostr-contact-wrapper label {
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
.nostr-contact-wrapper input::placeholder,
|
||||||
|
.nostr-contact-wrapper textarea::placeholder {
|
||||||
|
color: #6b7280;
|
||||||
|
}
|
||||||
|
.dark .nostr-contact-wrapper input,
|
||||||
|
.dark .nostr-contact-wrapper textarea {
|
||||||
|
background: #1f2937;
|
||||||
|
border-color: #4b5563;
|
||||||
|
color: #fff;
|
||||||
|
}
|
||||||
|
.nostr-contact-wrapper small {
|
||||||
|
display: block;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
color: #374151;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
.dark .nostr-contact-wrapper small {
|
||||||
|
color: #9ca3af;
|
||||||
|
}
|
||||||
|
.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;
|
||||||
|
}
|
||||||
|
.nostr-contact-wrapper button:hover {
|
||||||
|
background: #374151;
|
||||||
|
}
|
||||||
|
.dark .nostr-contact-wrapper button {
|
||||||
|
background: #fff;
|
||||||
|
color: #000;
|
||||||
|
}
|
||||||
|
.dark .nostr-contact-wrapper button:hover {
|
||||||
|
background: #e5e7eb;
|
||||||
|
}
|
||||||
|
.nostr-contact-wrapper button:disabled {
|
||||||
|
opacity: 0.5;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
#nc-status {
|
||||||
|
margin-top: 1rem;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 0.375rem;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
#nc-status.success {
|
||||||
|
display: block;
|
||||||
|
background: #f0fdf4;
|
||||||
|
border: 1px solid #86efac;
|
||||||
|
color: #166534;
|
||||||
|
}
|
||||||
|
.dark #nc-status.success {
|
||||||
|
background: #064e3b;
|
||||||
|
border-color: #059669;
|
||||||
|
color: #d1fae5;
|
||||||
|
}
|
||||||
|
#nc-status.error {
|
||||||
|
display: block;
|
||||||
|
background: #fef2f2;
|
||||||
|
border: 1px solid #fecaca;
|
||||||
|
color: #991b1b;
|
||||||
|
}
|
||||||
|
.dark #nc-status.error {
|
||||||
|
background: #7f1d1d;
|
||||||
|
border-color: #dc2626;
|
||||||
|
color: #fee2e2;
|
||||||
|
}
|
||||||
|
</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() {
|
||||||
|
// jsonify ensures proper quoting for JavaScript
|
||||||
|
const RECIPIENT_NPUB = "npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkwsyjh6w6";
|
||||||
|
|
||||||
|
const RELAYS = {{ .Get "relays" | default `["wss://relay.damus.io","wss://nos.lol"]` | jsonify }};
|
||||||
|
|
||||||
|
console.log("Debug - npub:", RECIPIENT_NPUB);
|
||||||
|
console.log("Debug - relays:", RELAYS);
|
||||||
|
|
||||||
|
let RECIPIENT_HEX = null;
|
||||||
|
const statusDiv = document.getElementById('nc-status');
|
||||||
|
|
||||||
|
try {
|
||||||
|
if (typeof window.NostrTools === 'undefined') {
|
||||||
|
throw new Error("NostrTools library not loaded");
|
||||||
|
}
|
||||||
|
const decoded = window.NostrTools.nip19.decode(RECIPIENT_NPUB);
|
||||||
|
RECIPIENT_HEX = decoded.data;
|
||||||
|
console.log("Debug - hex pubkey:", RECIPIENT_HEX);
|
||||||
|
} catch (e) {
|
||||||
|
console.error("Failed to decode npub:", e);
|
||||||
|
if (statusDiv) {
|
||||||
|
statusDiv.innerHTML = '<strong>Configuration error:</strong> ' + e.message;
|
||||||
|
statusDiv.className = 'error';
|
||||||
|
statusDiv.style.display = 'block';
|
||||||
|
}
|
||||||
|
return; // Stop here - don't attach event listener if config is bad
|
||||||
|
}
|
||||||
|
|
||||||
|
const form = document.getElementById('nostr-contact-form');
|
||||||
|
const btn = document.getElementById('nc-submit');
|
||||||
|
|
||||||
|
if (!form || !btn) {
|
||||||
|
console.error("Form elements not found");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
form.addEventListener('submit', async function(e) {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
btn.disabled = true;
|
||||||
|
btn.textContent = 'Sending...';
|
||||||
|
statusDiv.className = '';
|
||||||
|
statusDiv.style.display = 'none';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const sk = window.NostrTools.generatePrivateKey();
|
||||||
|
const pk = window.NostrTools.getPublicKey(sk);
|
||||||
|
|
||||||
|
const messageData = {
|
||||||
|
name: document.getElementById('nc-name').value,
|
||||||
|
contact: document.getElementById('nc-contact').value,
|
||||||
|
message: document.getElementById('nc-message').value,
|
||||||
|
timestamp: new Date().toISOString()
|
||||||
|
};
|
||||||
|
|
||||||
|
const encryptedContent = await window.NostrTools.nip04.encrypt(
|
||||||
|
sk,
|
||||||
|
RECIPIENT_HEX,
|
||||||
|
JSON.stringify(messageData)
|
||||||
|
);
|
||||||
|
|
||||||
|
const event = {
|
||||||
|
kind: 4,
|
||||||
|
pubkey: pk,
|
||||||
|
created_at: Math.floor(Date.now() / 1000),
|
||||||
|
tags: [['p', RECIPIENT_HEX]],
|
||||||
|
content: encryptedContent
|
||||||
|
};
|
||||||
|
|
||||||
|
event.id = window.NostrTools.getEventHash(event);
|
||||||
|
event.sig = window.NostrTools.signEvent(event, sk);
|
||||||
|
|
||||||
|
let successCount = 0;
|
||||||
|
const results = await Promise.all(RELAYS.map(url => {
|
||||||
|
return 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) => {
|
||||||
|
try {
|
||||||
|
const data = JSON.parse(msg.data);
|
||||||
|
if (data[0] === 'OK' && data[1] === event.id) {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
ws.close();
|
||||||
|
resolve(true);
|
||||||
|
}
|
||||||
|
} catch(e) {}
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onerror = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
ws.close();
|
||||||
|
resolve(false);
|
||||||
|
};
|
||||||
|
|
||||||
|
ws.onclose = () => {
|
||||||
|
clearTimeout(timeout);
|
||||||
|
resolve(false);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}));
|
||||||
|
|
||||||
|
successCount = results.filter(r => r).length;
|
||||||
|
|
||||||
|
if (successCount > 0) {
|
||||||
|
statusDiv.innerHTML = '<strong>Message sent!</strong><br>Published to ' + successCount + ' relay(s).';
|
||||||
|
statusDiv.className = 'success';
|
||||||
|
form.reset();
|
||||||
|
} else {
|
||||||
|
throw new Error('No relays accepted the message. Check console for details.');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error("Send error:", error);
|
||||||
|
statusDiv.innerHTML = '<strong>Error:</strong> ' + error.message;
|
||||||
|
statusDiv.className = 'error';
|
||||||
|
} finally {
|
||||||
|
btn.disabled = false;
|
||||||
|
btn.textContent = 'Send Message';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
</div>
|
||||||
@@ -6,5 +6,7 @@
|
|||||||
,"bryan":"cb43dde247f361c6d3cdaeb543301377838911757b412eac653e5d8aef277171"
|
,"bryan":"cb43dde247f361c6d3cdaeb543301377838911757b412eac653e5d8aef277171"
|
||||||
,"joe":"69dd82ab809d6d483546949095af1b83614eb5906890796fe8a9d40442a8d58d"
|
,"joe":"69dd82ab809d6d483546949095af1b83614eb5906890796fe8a9d40442a8d58d"
|
||||||
,"kookymonsta":"b3e6ea04acf9e9b769e437ebf2ddf03e2e5bab2a2fe62d3134012dcd3408717d"
|
,"kookymonsta":"b3e6ea04acf9e9b769e437ebf2ddf03e2e5bab2a2fe62d3134012dcd3408717d"
|
||||||
|
,"raymondromero":"aea4efe3c133f721b1739405291256f32c6bbab8644af14a17342c2774472ac4"
|
||||||
|
,"sundiego":"8e7bf451202ec924ceedae3e55e30b5dd6d80d8450dfd6804314b04266841bc8"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user