updated gear icon on profile page and removed "make private" option until i can get it working correctly

This commit is contained in:
Keep Creating Online
2025-02-10 08:01:01 -05:00
parent 56b6bb988e
commit e5ce98db07
4 changed files with 82 additions and 48 deletions

View File

@@ -105,7 +105,7 @@
class="mt-1 block w-full rounded-md border-gray-700 bg-gray-800 text-gray-100 focus:border-blue-500 focus:ring-blue-500" class="mt-1 block w-full rounded-md border-gray-700 bg-gray-800 text-gray-100 focus:border-blue-500 focus:ring-blue-500"
></textarea> ></textarea>
</div> </div>
<!--
<div class="flex items-center space-x-2"> <div class="flex items-center space-x-2">
<input <input
type="checkbox" type="checkbox"
@@ -116,7 +116,7 @@
>Private Listing (Encrypt Magnet)</span >Private Listing (Encrypt Magnet)</span
> >
</div> </div>
-->
<button <button
type="submit" type="submit"
class="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2" class="bg-blue-500 text-white px-4 py-2 rounded-md hover:bg-blue-600 focus:outline-none focus:ring-2 focus:ring-blue-500 focus:ring-offset-2"

View File

@@ -2,8 +2,31 @@
> ⚠️ **Note:** If you find a new bug thats not listed here. Please submit a [Bug Report](https://bitvid.network/?modal=bug). > ⚠️ **Note:** If you find a new bug thats not listed here. Please submit a [Bug Report](https://bitvid.network/?modal=bug).
- Speed up loading in subscriptions. Save to local cache?
- Fix "Dev Mode" publishing "Live Mode" notes—add a flag for dev mode posts. - Fix "Dev Mode" publishing "Live Mode" notes—add a flag for dev mode posts.
- Fix issue with video post set to private. - Fix issue with video post set to private.
- Disable "private video" until I can make it work better.
- Make "private video" work better using nip-04 encryption for magnet field.
- Fix slow back button issues on Firefox.
- Add Amber login support for mobile.
- Add settings (three dots) button for all videos, not the same as gear menu. Only show delete and edit gear for logged-in users videos.
- Add support for "Playlist" lists and other custom lists (named whatever) and also "Watch Later" list and "Watch History".
- Add an "add to playlist" button to the edit button.
- Add "add to watch later" option to edit button.
- Add block button to settings button.
- Add report button to settings button.
- Fix autoplay broken on iPhone chrome.
- Fix playback broken on Safari on iPhone.
- Update note spec v3 transition to include new fields that have been added like "has previous" or "videoRootID" or enentID if null.
- Change "explore" view to "kids" view and add flag to all notes to see if they are for kids.
- Add "seed" lists.
- Make "edit" video a form modal rather than a browser pop-up.
- Add "upload thumbnail" as option to add/edit video form. (use https://apidocs.imgur.com/)
- Fix issue where page refreshes when pulling up a video in the video modal.
- Fix sidebar media query settings on medium-sized screens. (tablet/laptops)
- Fix various "text wrap" issues causing scroll left and right on profile and modal pages.
- Add zaps to profile and video modal pages.
- Add comments to video modal pages.
## Feature Additions ## Feature Additions

View File

@@ -349,7 +349,7 @@ class bitvidApp {
this.showError("Could not generate link."); this.showError("Could not generate link.");
} }
}); });
} }
// Add click handlers for avatar and name => channel profile // Add click handlers for avatar and name => channel profile
if (this.creatorAvatar) { if (this.creatorAvatar) {
@@ -708,31 +708,33 @@ class bitvidApp {
async batchFetchProfiles(authorSet) { async batchFetchProfiles(authorSet) {
const pubkeys = Array.from(authorSet); const pubkeys = Array.from(authorSet);
if (!pubkeys.length) return; if (!pubkeys.length) return;
const filter = { const filter = {
kinds: [0], kinds: [0],
authors: pubkeys, authors: pubkeys,
limit: pubkeys.length, limit: pubkeys.length,
}; };
try { try {
// Query each relay // Query each relay
const results = await Promise.all( const results = await Promise.all(
nostrClient.relays.map(relayUrl => nostrClient.relays.map((relayUrl) =>
nostrClient.pool.list([relayUrl], [filter]) nostrClient.pool.list([relayUrl], [filter])
) )
); );
const allProfileEvents = results.flat(); const allProfileEvents = results.flat();
// Keep only the newest per author // Keep only the newest per author
const newestEvents = new Map(); const newestEvents = new Map();
for (const evt of allProfileEvents) { for (const evt of allProfileEvents) {
if (!newestEvents.has(evt.pubkey) || if (
evt.created_at > newestEvents.get(evt.pubkey).created_at) { !newestEvents.has(evt.pubkey) ||
evt.created_at > newestEvents.get(evt.pubkey).created_at
) {
newestEvents.set(evt.pubkey, evt); newestEvents.set(evt.pubkey, evt);
} }
} }
// Update the cache & DOM // Update the cache & DOM
for (const [pubkey, evt] of newestEvents.entries()) { for (const [pubkey, evt] of newestEvents.entries()) {
try { try {
@@ -751,7 +753,7 @@ class bitvidApp {
console.error("Batch profile fetch error:", err); console.error("Batch profile fetch error:", err);
} }
} }
updateProfileInDOM(pubkey, profile) { updateProfileInDOM(pubkey, profile) {
// For any .author-pic[data-pubkey=...] // For any .author-pic[data-pubkey=...]
const picEls = document.querySelectorAll( const picEls = document.querySelectorAll(
@@ -791,7 +793,7 @@ class bitvidApp {
thumbnail: thumbEl?.value.trim() || "", thumbnail: thumbEl?.value.trim() || "",
description: descEl?.value.trim() || "", description: descEl?.value.trim() || "",
mode: isDevMode ? "dev" : "live", mode: isDevMode ? "dev" : "live",
isPrivate: privEl?.checked || false, // isPrivate: privEl?.checked || false,
}; };
if (!formData.title || !formData.magnet) { if (!formData.title || !formData.magnet) {
@@ -1023,10 +1025,10 @@ class bitvidApp {
}); });
if (this.videoSubscription) { if (this.videoSubscription) {
console.log(
console.log("[loadVideos] subscription remains open to get live updates."); "[loadVideos] subscription remains open to get live updates."
);
} }
} else { } else {
// Already subscribed: just show what's cached // Already subscribed: just show what's cached
const allCached = nostrClient.getActiveVideos(); const allCached = nostrClient.getActiveVideos();
@@ -1055,12 +1057,12 @@ class bitvidApp {
async loadOlderVideos(lastTimestamp) { async loadOlderVideos(lastTimestamp) {
// 1) Use nostrClient to fetch older slices // 1) Use nostrClient to fetch older slices
const olderVideos = await nostrClient.fetchOlderVideos(lastTimestamp); const olderVideos = await nostrClient.fetchOlderVideos(lastTimestamp);
if (!olderVideos || olderVideos.length === 0) { if (!olderVideos || olderVideos.length === 0) {
this.showSuccess("No more older videos found."); this.showSuccess("No more older videos found.");
return; return;
} }
// 2) Merge them into the clients allEvents / activeMap // 2) Merge them into the clients allEvents / activeMap
for (const v of olderVideos) { for (const v of olderVideos) {
nostrClient.allEvents.set(v.id, v); nostrClient.allEvents.set(v.id, v);
@@ -1069,11 +1071,11 @@ class bitvidApp {
// You can call getActiveKey(v) if you want to match your codes approach. // You can call getActiveKey(v) if you want to match your codes approach.
// Then re-check if this one is newer than whats stored, etc. // Then re-check if this one is newer than whats stored, etc.
} }
// 3) Re-render // 3) Re-render
const all = nostrClient.getActiveVideos(); const all = nostrClient.getActiveVideos();
this.renderVideoList(all); this.renderVideoList(all);
} }
/** /**
* Returns true if there's at least one strictly older version * Returns true if there's at least one strictly older version
@@ -1094,7 +1096,7 @@ class bitvidApp {
async renderVideoList(videos) { async renderVideoList(videos) {
if (!this.videoList) return; if (!this.videoList) return;
// 1) If no videos // 1) If no videos
if (!videos || videos.length === 0) { if (!videos || videos.length === 0) {
this.videoList.innerHTML = ` this.videoList.innerHTML = `
@@ -1103,38 +1105,40 @@ class bitvidApp {
</p>`; </p>`;
return; return;
} }
// 2) Sort newest first // 2) Sort newest first
videos.sort((a, b) => b.created_at - a.created_at); videos.sort((a, b) => b.created_at - a.created_at);
const fullAllEventsArray = Array.from(nostrClient.allEvents.values()); const fullAllEventsArray = Array.from(nostrClient.allEvents.values());
const fragment = document.createDocumentFragment(); const fragment = document.createDocumentFragment();
const authorSet = new Set(); const authorSet = new Set();
// 3) Build each card // 3) Build each card
videos.forEach((video, index) => { videos.forEach((video, index) => {
if (!video.id || !video.title) { if (!video.id || !video.title) {
console.error("Video missing ID/title:", video); console.error("Video missing ID/title:", video);
return; return;
} }
authorSet.add(video.pubkey); authorSet.add(video.pubkey);
const nevent = window.NostrTools.nip19.neventEncode({ id: video.id }); const nevent = window.NostrTools.nip19.neventEncode({ id: video.id });
const shareUrl = `${window.location.pathname}?v=${encodeURIComponent(nevent)}`; const shareUrl = `${window.location.pathname}?v=${encodeURIComponent(
nevent
)}`;
const canEdit = video.pubkey === this.pubkey; const canEdit = video.pubkey === this.pubkey;
const highlightClass = const highlightClass =
video.isPrivate && canEdit video.isPrivate && canEdit
? "border-2 border-yellow-500" ? "border-2 border-yellow-500"
: "border-none"; : "border-none";
const timeAgo = this.formatTimeAgo(video.created_at); const timeAgo = this.formatTimeAgo(video.created_at);
// Check if there's an older version // Check if there's an older version
let hasOlder = false; let hasOlder = false;
if (canEdit && video.videoRootId) { if (canEdit && video.videoRootId) {
hasOlder = this.hasOlderVersion(video, fullAllEventsArray); hasOlder = this.hasOlderVersion(video, fullAllEventsArray);
} }
const revertButton = hasOlder const revertButton = hasOlder
? ` ? `
<button <button
@@ -1145,7 +1149,7 @@ class bitvidApp {
</button> </button>
` `
: ""; : "";
const gearMenu = canEdit const gearMenu = canEdit
? ` ? `
<div class="relative inline-block ml-3 overflow-visible"> <div class="relative inline-block ml-3 overflow-visible">
@@ -1183,7 +1187,7 @@ class bitvidApp {
</div> </div>
` `
: ""; : "";
const cardHtml = ` const cardHtml = `
<div class="video-card bg-gray-900 rounded-lg overflow-hidden shadow-lg hover:shadow-2xl transition-all duration-300 ${highlightClass}"> <div class="video-card bg-gray-900 rounded-lg overflow-hidden shadow-lg hover:shadow-2xl transition-all duration-300 ${highlightClass}">
<!-- The clickable link to play video --> <!-- The clickable link to play video -->
@@ -1236,23 +1240,25 @@ class bitvidApp {
</div> </div>
</div> </div>
`; `;
const template = document.createElement("template"); const template = document.createElement("template");
template.innerHTML = cardHtml.trim(); template.innerHTML = cardHtml.trim();
const cardEl = template.content.firstElementChild; const cardEl = template.content.firstElementChild;
fragment.appendChild(cardEl); fragment.appendChild(cardEl);
}); });
// Clear old content, add new // Clear old content, add new
this.videoList.innerHTML = ""; this.videoList.innerHTML = "";
this.videoList.appendChild(fragment); this.videoList.appendChild(fragment);
// Lazy-load images // Lazy-load images
const lazyEls = this.videoList.querySelectorAll("[data-lazy]"); const lazyEls = this.videoList.querySelectorAll("[data-lazy]");
lazyEls.forEach((el) => this.mediaLoader.observe(el)); lazyEls.forEach((el) => this.mediaLoader.observe(el));
// GEAR MENU / button event listeners... // GEAR MENU / button event listeners...
const gearButtons = this.videoList.querySelectorAll("[data-settings-dropdown]"); const gearButtons = this.videoList.querySelectorAll(
"[data-settings-dropdown]"
);
gearButtons.forEach((button) => { gearButtons.forEach((button) => {
button.addEventListener("click", () => { button.addEventListener("click", () => {
const index = button.getAttribute("data-settings-dropdown"); const index = button.getAttribute("data-settings-dropdown");
@@ -1262,7 +1268,7 @@ class bitvidApp {
} }
}); });
}); });
// Edit button // Edit button
const editButtons = this.videoList.querySelectorAll("[data-edit-index]"); const editButtons = this.videoList.querySelectorAll("[data-edit-index]");
editButtons.forEach((button) => { editButtons.forEach((button) => {
@@ -1275,7 +1281,9 @@ class bitvidApp {
}); });
// Revert button // Revert button
const revertButtons = this.videoList.querySelectorAll("[data-revert-index]"); const revertButtons = this.videoList.querySelectorAll(
"[data-revert-index]"
);
revertButtons.forEach((button) => { revertButtons.forEach((button) => {
button.addEventListener("click", () => { button.addEventListener("click", () => {
const index = button.getAttribute("data-revert-index"); const index = button.getAttribute("data-revert-index");
@@ -1286,7 +1294,9 @@ class bitvidApp {
}); });
// Delete All button // Delete All button
const deleteAllButtons = this.videoList.querySelectorAll("[data-delete-all-index]"); const deleteAllButtons = this.videoList.querySelectorAll(
"[data-delete-all-index]"
);
deleteAllButtons.forEach((button) => { deleteAllButtons.forEach((button) => {
button.addEventListener("click", () => { button.addEventListener("click", () => {
const index = button.getAttribute("data-delete-all-index"); const index = button.getAttribute("data-delete-all-index");
@@ -1295,10 +1305,10 @@ class bitvidApp {
this.handleFullDeleteVideo(index); this.handleFullDeleteVideo(index);
}); });
}); });
// 2) After building cards, do one batch profile fetch // 2) After building cards, do one batch profile fetch
this.batchFetchProfiles(authorSet); this.batchFetchProfiles(authorSet);
// === NEW: attach click listeners to .author-pic and .author-name // === NEW: attach click listeners to .author-pic and .author-name
const authorPics = this.videoList.querySelectorAll(".author-pic"); const authorPics = this.videoList.querySelectorAll(".author-pic");
authorPics.forEach((pic) => { authorPics.forEach((pic) => {
@@ -1310,7 +1320,7 @@ class bitvidApp {
this.goToProfile(pubkey); this.goToProfile(pubkey);
}); });
}); });
const authorNames = this.videoList.querySelectorAll(".author-name"); const authorNames = this.videoList.querySelectorAll(".author-name");
authorNames.forEach((nameEl) => { authorNames.forEach((nameEl) => {
nameEl.style.cursor = "pointer"; nameEl.style.cursor = "pointer";
@@ -1322,7 +1332,7 @@ class bitvidApp {
}); });
}); });
} }
/** /**
* Updates the modal to reflect current torrent stats. * Updates the modal to reflect current torrent stats.
* We remove the unused torrent.status references, * We remove the unused torrent.status references,
@@ -1416,7 +1426,7 @@ class bitvidApp {
"New Description? (blank=keep existing)", "New Description? (blank=keep existing)",
video.description video.description
); );
const wantPrivate = confirm("Make this video private? OK=Yes, Cancel=No"); // const wantPrivate = confirm("Make this video private? OK=Yes, Cancel=No");
// 4) Build final updated fields (or fallback to existing) // 4) Build final updated fields (or fallback to existing)
const title = const title =
@@ -1431,7 +1441,7 @@ class bitvidApp {
// 5) Create an object with the new data // 5) Create an object with the new data
const updatedData = { const updatedData = {
version: video.version || 2, version: video.version || 2,
isPrivate: wantPrivate, // isPrivate: wantPrivate,
title, title,
magnet, magnet,
thumbnail, thumbnail,

View File

@@ -276,15 +276,16 @@ async function loadUserVideos(pubkey) {
<div class="relative inline-block ml-3 overflow-visible"> <div class="relative inline-block ml-3 overflow-visible">
<button <button
type="button" type="button"
class="inline-flex items-center p-2 rounded-full text-gray-400 class="inline-flex items-center justify-center
hover:text-gray-200 hover:bg-gray-800 focus:outline-none focus:ring-2 w-10 h-10 p-2
focus:ring-blue-500" rounded-full text-gray-400 hover:text-gray-200 hover:bg-gray-800
focus:outline-none focus:ring-2 focus:ring-blue-500"
data-settings-dropdown="${index}" data-settings-dropdown="${index}"
> >
<img <img
src="assets/svg/video-settings-gear.svg" src="assets/svg/video-settings-gear.svg"
alt="Settings" alt="Settings"
class="w-5 h-5" class="w-5 h-5 object-contain"
/> />
</button> </button>
<div <div