mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2025-09-09 23:48:44 +00:00
update
This commit is contained in:
@@ -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 nostr‑tools v2.10.4 -->
|
||||
@@ -130,38 +130,87 @@
|
||||
<div class="container">
|
||||
<div class="form-container">
|
||||
<p>
|
||||
Have an idea for improving bitvid? We’d 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? We’d 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 & 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? We’d 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? We’d 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 bitvid’s 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>
|
||||
|
Reference in New Issue
Block a user