mirror of
https://github.com/inpharmaticist/links.git
synced 2026-04-26 17:04:03 +00:00
Compare commits
4 Commits
1a3b80cddb
...
main
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
faa68c9be3 | ||
|
|
8bb2d3ff10 | ||
|
|
6a93d3f731 | ||
|
|
53dd5c6077 |
261
contact.html
Normal file
261
contact.html
Normal file
@@ -0,0 +1,261 @@
|
|||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>Contact Form</title>
|
||||||
|
<style>
|
||||||
|
* {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
box-sizing: border-box;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
|
||||||
|
line-height: 1.6;
|
||||||
|
color: #000;
|
||||||
|
background-color: #fff;
|
||||||
|
padding: 2rem 1rem;
|
||||||
|
max-width: 600px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1 {
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-size: 1.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
p {
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
.form-group {
|
||||||
|
margin-bottom: 1.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
display: block;
|
||||||
|
margin-bottom: 0.5rem;
|
||||||
|
font-weight: 600;
|
||||||
|
}
|
||||||
|
|
||||||
|
input, textarea {
|
||||||
|
width: 100%;
|
||||||
|
padding: 0.75rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
border: 1px solid #ccc;
|
||||||
|
border-radius: 4px;
|
||||||
|
font-family: inherit;
|
||||||
|
}
|
||||||
|
|
||||||
|
input:focus, textarea:focus {
|
||||||
|
outline: none;
|
||||||
|
border-color: #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
small {
|
||||||
|
display: block;
|
||||||
|
margin-top: 0.25rem;
|
||||||
|
color: #666;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
button {
|
||||||
|
background-color: #000;
|
||||||
|
color: #fff;
|
||||||
|
padding: 1rem 2rem;
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
border: none;
|
||||||
|
border-radius: 4px;
|
||||||
|
cursor: pointer;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:hover {
|
||||||
|
background-color: #333;
|
||||||
|
}
|
||||||
|
|
||||||
|
button:disabled {
|
||||||
|
background-color: #999;
|
||||||
|
cursor: not-allowed;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status {
|
||||||
|
margin-top: 1.5rem;
|
||||||
|
padding: 1rem;
|
||||||
|
border-radius: 4px;
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status.success {
|
||||||
|
display: block;
|
||||||
|
background-color: #f0f0f0;
|
||||||
|
border-left: 4px solid #000;
|
||||||
|
}
|
||||||
|
|
||||||
|
#status.error {
|
||||||
|
display: block;
|
||||||
|
background-color: #fee;
|
||||||
|
border-left: 4px solid #c00;
|
||||||
|
color: #c00;
|
||||||
|
}
|
||||||
|
|
||||||
|
a {
|
||||||
|
color: #000;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<h1>Contact</h1>
|
||||||
|
<p>Send a message.</p>
|
||||||
|
|
||||||
|
<form id="contact-form" onsubmit="return false;">
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="name">Name</label>
|
||||||
|
<input type="text" id="name" name="name" required>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="contact-info">Contact Info</label>
|
||||||
|
<input type="text" id="contact-info" name="contact-info"
|
||||||
|
placeholder="email@example.com" required>
|
||||||
|
<small>How you want to be contacted back.</small>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="form-group">
|
||||||
|
<label for="message">Comments</label>
|
||||||
|
<textarea id="message" name="message" rows="5" placeholder="Your message..." required></textarea>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<button type="submit" id="submit-btn">Send Message</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div id="status"></div>
|
||||||
|
|
||||||
|
<script src="https://unpkg.com/nostr-tools@1.17.0/lib/nostr.bundle.js"></script>
|
||||||
|
<script>
|
||||||
|
// CONFIGURATION: Replace these with your own values
|
||||||
|
const RECIPIENT_NPUB = 'npub1c0r3ytrr4afgrlhrhyec6y9wvkckdllx7ul3cfevtsgjqcrhx8tsdzqs7w';
|
||||||
|
const RELAYS = [
|
||||||
|
'wss://bits.sdbitcoiners.com/nostrrelay/Leug2TNY',
|
||||||
|
'wss://relay.damus.io',
|
||||||
|
'wss://nos.lol',
|
||||||
|
'wss://relay.nostr.band'
|
||||||
|
// Add more relays if desired
|
||||||
|
];
|
||||||
|
|
||||||
|
// Decode npub to hex pubkey
|
||||||
|
let RECIPIENT_HEX;
|
||||||
|
try {
|
||||||
|
const decoded = window.NostrTools.nip19.decode(RECIPIENT_NPUB);
|
||||||
|
RECIPIENT_HEX = decoded.data;
|
||||||
|
} catch (e) {
|
||||||
|
console.error('Invalid npub in configuration');
|
||||||
|
}
|
||||||
|
|
||||||
|
document.getElementById('contact-form').addEventListener('submit', async (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
|
||||||
|
const submitBtn = document.getElementById('submit-btn');
|
||||||
|
const status = document.getElementById('status');
|
||||||
|
|
||||||
|
if (!RECIPIENT_HEX) {
|
||||||
|
status.innerHTML = '<strong>Configuration error:</strong> Invalid npub.';
|
||||||
|
status.className = 'error';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
submitBtn.disabled = true;
|
||||||
|
submitBtn.textContent = 'Sending...';
|
||||||
|
status.className = '';
|
||||||
|
status.style.display = 'none';
|
||||||
|
|
||||||
|
try {
|
||||||
|
const sk = window.NostrTools.generatePrivateKey();
|
||||||
|
const pk = window.NostrTools.getPublicKey(sk);
|
||||||
|
|
||||||
|
const formData = {
|
||||||
|
name: document.getElementById('name').value,
|
||||||
|
contact: document.getElementById('contact-info').value,
|
||||||
|
message: document.getElementById('message').value,
|
||||||
|
timestamp: new Date().toISOString(),
|
||||||
|
source: 'littlelink'
|
||||||
|
};
|
||||||
|
|
||||||
|
const encryptedContent = await window.NostrTools.nip04.encrypt(
|
||||||
|
sk,
|
||||||
|
RECIPIENT_HEX,
|
||||||
|
JSON.stringify(formData)
|
||||||
|
);
|
||||||
|
|
||||||
|
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 publishedCount = 0;
|
||||||
|
const publishPromises = RELAYS.map(relayUrl => {
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
const ws = new WebSocket(relayUrl);
|
||||||
|
let timeout;
|
||||||
|
|
||||||
|
ws.onopen = () => {
|
||||||
|
ws.send(JSON.stringify(['EVENT', event]));
|
||||||
|
timeout = setTimeout(() => {
|
||||||
|
ws.close();
|
||||||
|
resolve(false);
|
||||||
|
}, 5000);
|
||||||
|
};
|
||||||
|
|
||||||
|
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 results = await Promise.all(publishPromises);
|
||||||
|
publishedCount = results.filter(r => r).length;
|
||||||
|
|
||||||
|
if (publishedCount > 0) {
|
||||||
|
status.innerHTML = '<strong>Message sent!</strong><br>Published to ' + publishedCount + ' relay(s).';
|
||||||
|
status.className = 'success';
|
||||||
|
document.getElementById('contact-form').reset();
|
||||||
|
} else {
|
||||||
|
throw new Error('No relays accepted the message');
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (error) {
|
||||||
|
console.error(error);
|
||||||
|
status.innerHTML = '<strong>Network error.</strong><br>Please try again later.';
|
||||||
|
status.className = 'error';
|
||||||
|
} finally {
|
||||||
|
submitBtn.disabled = false;
|
||||||
|
submitBtn.textContent = 'Send Message';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
@@ -87,10 +87,10 @@
|
|||||||
<a class="button button-github" href="https://raw.githubusercontent.com/inpharmaticist/links/refs/heads/main/gpg.asc" target="_blank" rel="noopener" role="button"><img class="icon" aria-hidden="true" src="images/icons/gpg.png" alt="Email Icon">PGP Key</a>
|
<a class="button button-github" href="https://raw.githubusercontent.com/inpharmaticist/links/refs/heads/main/gpg.asc" target="_blank" rel="noopener" role="button"><img class="icon" aria-hidden="true" src="images/icons/gpg.png" alt="Email Icon">PGP Key</a>
|
||||||
|
|
||||||
<!-- Generic Email -->
|
<!-- Generic Email -->
|
||||||
<a class="button button-default" href="mailto:upstairs_evaluate832@slmail.me" target="_blank" rel="noopener" role="button"><img class="icon" aria-hidden="true" src="images/icons/generic-email-alt.svg" alt="Email Icon">Email</a>
|
<a class="button button-default" href="mailto:couch_banjo048@slmail.me" target="_blank" rel="noopener" role="button"><img class="icon" aria-hidden="true" src="images/icons/generic-email-alt.svg" alt="Email Icon">Email</a>
|
||||||
|
|
||||||
<!-- Contact Form -->
|
<!-- Contact Form -->
|
||||||
<a class="button button-default" href="https://formstr.app/f/naddr1qvzqqqr4mqpzpafdewsuthj5k8sfre227a6hyn008meuk2jpdg0gl6ltfp809cpfqy2hwumn8ghj7un9d3shjtnyv9kh2uewd9hj7qghwaehxw309aex2mrp0yh8qunfd4skctnwv46z7qgdwaehxw309ahx7uewd3hkcqg7waehxw309aex2mrp0yhxummnw3ezuamfwfjkgmn9wshx5up0qyw8wumn8ghj7mn0wd68ytfsxyh8jcttd95x7mnwv5hxxmmdqyv8wumn8ghj7un9d3shjtnndehhyapwwdhkx6tpdsq3vamnwvaz7tmjv4kxz7fwdehhxarj9e3xzmnyqyghwumn8ghj7mn0wd68yv339e3k7mgqqcc9yapctyuqa0w6ey?viewKey=c709e0eefda9d435fe65e06dbc2a185fb960133bce208301d0772004f822c216" target="_blank" rel="noopener" role="button"><img class="icon" aria-hidden="true" src="images/icons/generic-email.svg" alt="Email Icon">Contact Form</a>
|
<a class="button button-default" href="contact.html" target="_blank" rel="noopener" role="button"><img class="icon" aria-hidden="true" src="images/icons/generic-email.svg" alt="Email Icon">Contact Form</a>
|
||||||
|
|
||||||
<!-- Generic Shopping Bag -->
|
<!-- Generic Shopping Bag -->
|
||||||
<a class="button button-sd-bitcoiners" href="https://pay.sdbitcoiners.com" target="_blank" rel="noopener" role="button"><img class="icon" aria-hidden="true" src="images/icons/generic-shopping-bag.svg" alt="Shopping Bag Icon">Store</a>
|
<a class="button button-sd-bitcoiners" href="https://pay.sdbitcoiners.com" target="_blank" rel="noopener" role="button"><img class="icon" aria-hidden="true" src="images/icons/generic-shopping-bag.svg" alt="Shopping Bag Icon">Store</a>
|
||||||
|
|||||||
Reference in New Issue
Block a user