This commit is contained in:
Keep Creating Online
2025-02-03 17:33:16 -05:00
parent 2f90f845a2
commit f5e3484cbc
12 changed files with 1425 additions and 810 deletions

View File

@@ -4,7 +4,7 @@
<meta charset="utf-8" />
<title>bitvid Feature Request Form</title>
<!-- Link to your main stylesheet -->
<link rel="stylesheet" href="style.css" />
<link rel="stylesheet" href="../../css/style.css" />
<style>
/* Override for form page to match modal field styling */
@@ -42,7 +42,7 @@
display: block;
margin-top: 1em;
font-weight: bold;
color: #E5E7EB;
color: #e5e7eb;
}
/* Input, textarea, and select styling */
@@ -51,8 +51,8 @@
select {
width: 100%;
margin-bottom: 0.75em;
background-color: #1F2937;
color: #F3F4F6;
background-color: #1f2937;
color: #f3f4f6;
border: 1px solid #374151;
padding: 0.5em;
border-radius: 0.375rem;
@@ -62,9 +62,9 @@
input:focus,
textarea:focus,
select:focus {
border-color: #3B82F6;
border-color: #3b82f6;
outline: none;
box-shadow: 0 0 0 1px #3B82F6;
box-shadow: 0 0 0 1px #3b82f6;
}
/* Checkbox group styling */
@@ -77,7 +77,7 @@
/* Button styling */
button {
padding: 0.5em 1em;
background: #3B82F6;
background: #3b82f6;
color: #fff;
border: none;
border-radius: 0.375rem;
@@ -97,13 +97,13 @@
margin: 0.25em 0;
}
.error {
color: #F87171;
color: #f87171;
}
.success {
color: #3B82F6;
color: #3b82f6;
}
.warn {
color: #FACC15;
color: #facc15;
}
/* Custom Scrollbar styling */
@@ -115,12 +115,12 @@
background: transparent;
}
::-webkit-scrollbar-thumb {
background-color: #3B82F6;
background-color: #3b82f6;
border-radius: 4px;
}
* {
scrollbar-width: thin;
scrollbar-color: #3B82F6 transparent;
scrollbar-color: #3b82f6 transparent;
}
</style>
<!-- Load nostrtools v2.10.4 -->
@@ -130,38 +130,87 @@
<div class="container">
<div class="form-container">
<p>
Have an idea for improving bitvid? Wed love to hear it! Please use this form to request new features or enhancements. Your feedback helps shape the future of bitvid.
Have an idea for improving bitvid? Wed love to hear it! Please use
this form to request new features or enhancements. Your feedback helps
shape the future of bitvid.
</p>
<form id="feature-form">
<!-- Section 1: User Information -->
<h2>1. User Information</h2>
<label for="userNpub">Nostr Public Key (npub) (optional):</label>
<input type="text" id="userNpub" placeholder="Enter your npub (optional)" />
<input
type="text"
id="userNpub"
placeholder="Enter your npub (optional)"
/>
<p>Are you a (check all that apply):</p>
<div class="checkbox-group">
<label><input type="checkbox" name="userRole" value="Viewer" /> Viewer</label>
<label><input type="checkbox" name="userRole" value="Content Creator" /> Content Creator</label>
<label><input type="checkbox" name="userRole" value="Developer/Contributor" /> Developer / Contributor</label>
<label
><input type="checkbox" name="userRole" value="Viewer" />
Viewer</label
>
<label
><input type="checkbox" name="userRole" value="Content Creator" />
Content Creator</label
>
<label
><input
type="checkbox"
name="userRole"
value="Developer/Contributor"
/>
Developer / Contributor</label
>
</div>
<!-- Section 2: Feature Request Details -->
<h2>2. Feature Request Details</h2>
<label for="featureName">Feature Name:</label>
<input type="text" id="featureName" placeholder="Short, descriptive title" required />
<input
type="text"
id="featureName"
placeholder="Short, descriptive title"
required
/>
<label for="featureDescription">Describe the feature:</label>
<textarea id="featureDescription" rows="3" placeholder="Explain in detail what the feature does and how it works"></textarea>
<textarea
id="featureDescription"
rows="3"
placeholder="Explain in detail what the feature does and how it works"
></textarea>
<label for="featureImportance">Why is this feature important?</label>
<textarea id="featureImportance" rows="2" placeholder="Describe how this will improve the platform and benefit users"></textarea>
<textarea
id="featureImportance"
rows="2"
placeholder="Describe how this will improve the platform and benefit users"
></textarea>
<label for="beneficiary">Who would benefit from this feature?</label>
<input type="text" id="beneficiary" placeholder="e.g., Content Creators, Viewers, Both" />
<input
type="text"
id="beneficiary"
placeholder="e.g., Content Creators, Viewers, Both"
/>
<!-- Section 3: Additional Information -->
<h2>3. Additional Information</h2>
<label for="existingPlatforms">Are there existing platforms that have this feature?</label>
<textarea id="existingPlatforms" rows="2" placeholder="Provide examples if applicable"></textarea>
<label for="existingPlatforms"
>Are there existing platforms that have this feature?</label
>
<textarea
id="existingPlatforms"
rows="2"
placeholder="Provide examples if applicable"
></textarea>
<label for="mockups">Do you have any mockups or examples?</label>
<textarea id="mockups" rows="2" placeholder="Links, screenshots, or diagrams"></textarea>
<label for="willingToTest">Would you be willing to help test this feature if implemented?</label>
<textarea
id="mockups"
rows="2"
placeholder="Links, screenshots, or diagrams"
></textarea>
<label for="willingToTest"
>Would you be willing to help test this feature if
implemented?</label
>
<select id="willingToTest">
<option value="">Select an option</option>
<option value="Yes">Yes</option>
@@ -172,12 +221,27 @@
<h2>4. Priority &amp; Impact</h2>
<p>How urgent is this feature?</p>
<div class="checkbox-group">
<label><input type="checkbox" name="featurePriority" value="High" /> High (Essential for platform success)</label>
<label><input type="checkbox" name="featurePriority" value="Medium" /> Medium (Would improve experience significantly)</label>
<label><input type="checkbox" name="featurePriority" value="Low" /> Low (Nice to have, but not urgent)</label>
<label
><input type="checkbox" name="featurePriority" value="High" />
High (Essential for platform success)</label
>
<label
><input type="checkbox" name="featurePriority" value="Medium" />
Medium (Would improve experience significantly)</label
>
<label
><input type="checkbox" name="featurePriority" value="Low" /> Low
(Nice to have, but not urgent)</label
>
</div>
<label for="techChallenges">Does this feature require technical expertise to implement?</label>
<textarea id="techChallenges" rows="2" placeholder="Describe any dependencies or challenges"></textarea>
<label for="techChallenges"
>Does this feature require technical expertise to implement?</label
>
<textarea
id="techChallenges"
rows="2"
placeholder="Describe any dependencies or challenges"
></textarea>
<button type="submit">Submit Feature Request</button>
</form>
@@ -204,50 +268,79 @@
log("NostrTools not loaded. Check console or ad-blockers.", "error");
return;
}
const { generateSecretKey, getPublicKey, finalizeEvent, nip04, nip19, SimplePool, Relay } = window.NostrTools;
const {
generateSecretKey,
getPublicKey,
finalizeEvent,
nip04,
nip19,
SimplePool,
Relay,
} = window.NostrTools;
// Set the recipient's NPUB (your personal NPUB)
const recipientNpub = "npub13yarr7j6vjqjjkahd63dmr27curypehx45ucue286ac7sft27y0srnpmpe";
const recipientNpub =
"npub13yarr7j6vjqjjkahd63dmr27curypehx45ucue286ac7sft27y0srnpmpe";
const RELAYS = [
"wss://relay.snort.social",
"wss://relay.damus.io",
"wss://relay.primal.net"
"wss://relay.primal.net",
];
const pool = new SimplePool();
document.getElementById("feature-form").addEventListener("submit", async (ev) => {
ev.preventDefault();
clear();
try {
// Section 1: User Information
const userNpub = document.getElementById("userNpub").value.trim();
const roleNodes = document.querySelectorAll('input[name="userRole"]:checked');
let userRoles = [];
roleNodes.forEach(node => {
userRoles.push(node.value);
});
// Section 2: Feature Request Details
const featureName = document.getElementById("featureName").value.trim();
const featureDescription = document.getElementById("featureDescription").value.trim();
const featureImportance = document.getElementById("featureImportance").value.trim();
const beneficiary = document.getElementById("beneficiary").value.trim();
document
.getElementById("feature-form")
.addEventListener("submit", async (ev) => {
ev.preventDefault();
clear();
try {
// Section 1: User Information
const userNpub = document.getElementById("userNpub").value.trim();
const roleNodes = document.querySelectorAll(
'input[name="userRole"]:checked'
);
let userRoles = [];
roleNodes.forEach((node) => {
userRoles.push(node.value);
});
// Section 3: Additional Information
const existingPlatforms = document.getElementById("existingPlatforms").value.trim();
const mockups = document.getElementById("mockups").value.trim();
const willingToTest = document.getElementById("willingToTest").value.trim();
// Section 2: Feature Request Details
const featureName = document
.getElementById("featureName")
.value.trim();
const featureDescription = document
.getElementById("featureDescription")
.value.trim();
const featureImportance = document
.getElementById("featureImportance")
.value.trim();
const beneficiary = document
.getElementById("beneficiary")
.value.trim();
// Section 4: Priority & Impact
const priorityNodes = document.querySelectorAll('input[name="featurePriority"]:checked');
let featurePriorities = [];
priorityNodes.forEach(node => {
featurePriorities.push(node.value);
});
const techChallenges = document.getElementById("techChallenges").value.trim();
// Section 3: Additional Information
const existingPlatforms = document
.getElementById("existingPlatforms")
.value.trim();
const mockups = document.getElementById("mockups").value.trim();
const willingToTest = document
.getElementById("willingToTest")
.value.trim();
// Construct Markdown feature request
const featureRequestContent = `
// Section 4: Priority & Impact
const priorityNodes = document.querySelectorAll(
'input[name="featurePriority"]:checked'
);
let featurePriorities = [];
priorityNodes.forEach((node) => {
featurePriorities.push(node.value);
});
const techChallenges = document
.getElementById("techChallenges")
.value.trim();
// Construct Markdown feature request
const featureRequestContent = `
# **bitvid Feature Request Form**
Have an idea for improving bitvid? Wed love to hear it! Please use this form to request new features or enhancements. Your feedback helps shape the future of bitvid.
@@ -270,7 +363,9 @@ Have an idea for improving bitvid? Wed love to hear it! Please use this form
${existingPlatforms || "N/A"}
- **Do you have any mockups or examples?**
${mockups || "N/A"}
- **Would you be willing to help test this feature if implemented?** ${willingToTest || "N/A"}
- **Would you be willing to help test this feature if implemented?** ${
willingToTest || "N/A"
}
## **4. Priority & Impact**
- **How urgent is this feature?**
@@ -286,71 +381,90 @@ All feature requests are reviewed, but not all may be implemented. We prioritize
For further discussions, reach out through bitvids Nostr support channels.
`.trim();
log("[DEBUG] Constructed feature request content:\n" + featureRequestContent);
log(
"[DEBUG] Constructed feature request content:\n" +
featureRequestContent
);
// Decode the recipient NPUB
log("Decoding recipient npub...");
const decoded = nip19.decode(recipientNpub);
log("[DEBUG] Decoded npub: " + JSON.stringify(decoded));
if (decoded.type !== "npub") {
throw new Error("Decoded type is not npub.");
// Decode the recipient NPUB
log("Decoding recipient npub...");
const decoded = nip19.decode(recipientNpub);
log("[DEBUG] Decoded npub: " + JSON.stringify(decoded));
if (decoded.type !== "npub") {
throw new Error("Decoded type is not npub.");
}
const targetPubHex = decoded.data;
log("Recipient pubkey: " + targetPubHex.slice(0, 16) + "...");
// Generate an ephemeral key pair
log("Generating ephemeral key...");
const ephemeralPriv = generateSecretKey();
const ephemeralPubHex = getPublicKey(ephemeralPriv);
log("Ephemeral pubkey: " + ephemeralPubHex.slice(0, 16) + "...");
// Encrypt the feature request content
log("Encrypting feature request content (nip04)...");
const ciphertext = await nip04.encrypt(
ephemeralPriv,
targetPubHex,
featureRequestContent
);
log("[DEBUG] Ciphertext: " + ciphertext);
log("Encryption done.");
// Build the event template
const now = Math.floor(Date.now() / 1000);
const eventTemplate = {
kind: 4,
created_at: now,
tags: [["p", targetPubHex]],
content: ciphertext,
};
log(
"[DEBUG] Event template before finalizing: " +
JSON.stringify(eventTemplate)
);
// Finalize the event
const event = finalizeEvent(eventTemplate, ephemeralPriv);
log("[DEBUG] Final event: " + JSON.stringify(event));
// Publish to relays
log("Publishing the feature request to relays...");
await Promise.any(pool.publish(RELAYS, event));
log("At least one relay accepted the event.", "success");
// Subscribe to verify event storage
for (const url of RELAYS) {
log("Connecting to " + url + " for subscription...");
const relay = await Relay.connect(url);
relay.subscribe([{ authors: [ephemeralPubHex], kinds: [4] }], {
onEvent(foundEvent) {
if (foundEvent.id === event.id) {
log(
"[" +
url +
"] => Found our feature request in storage! ID: " +
foundEvent.id.slice(0, 8) +
"...",
"success"
);
}
},
onEose() {
relay.close();
},
});
}
log(
"Done. If the logs show that at least one relay accepted the event and the feature request was stored, it will be reviewed accordingly."
);
} catch (err) {
log("Error: " + err.message, "error");
console.error(err);
}
const targetPubHex = decoded.data;
log("Recipient pubkey: " + targetPubHex.slice(0, 16) + "...");
// Generate an ephemeral key pair
log("Generating ephemeral key...");
const ephemeralPriv = generateSecretKey();
const ephemeralPubHex = getPublicKey(ephemeralPriv);
log("Ephemeral pubkey: " + ephemeralPubHex.slice(0, 16) + "...");
// Encrypt the feature request content
log("Encrypting feature request content (nip04)...");
const ciphertext = await nip04.encrypt(ephemeralPriv, targetPubHex, featureRequestContent);
log("[DEBUG] Ciphertext: " + ciphertext);
log("Encryption done.");
// Build the event template
const now = Math.floor(Date.now() / 1000);
const eventTemplate = {
kind: 4,
created_at: now,
tags: [["p", targetPubHex]],
content: ciphertext,
};
log("[DEBUG] Event template before finalizing: " + JSON.stringify(eventTemplate));
// Finalize the event
const event = finalizeEvent(eventTemplate, ephemeralPriv);
log("[DEBUG] Final event: " + JSON.stringify(event));
// Publish to relays
log("Publishing the feature request to relays...");
await Promise.any(pool.publish(RELAYS, event));
log("At least one relay accepted the event.", "success");
// Subscribe to verify event storage
for (const url of RELAYS) {
log("Connecting to " + url + " for subscription...");
const relay = await Relay.connect(url);
relay.subscribe([{ authors: [ephemeralPubHex], kinds: [4] }], {
onEvent(foundEvent) {
if (foundEvent.id === event.id) {
log("[" + url + "] => Found our feature request in storage! ID: " + foundEvent.id.slice(0, 8) + "...", "success");
}
},
onEose() {
relay.close();
},
});
}
log("Done. If the logs show that at least one relay accepted the event and the feature request was stored, it will be reviewed accordingly.");
} catch (err) {
log("Error: " + err.message, "error");
console.error(err);
}
});
});
});
</script>
</body>