mirror of
https://github.com/PR0M3TH3AN/bitvid.git
synced 2026-10-27 07:52:24 +00:00
feat: add info icon with filter logic popover to For You feed
Adds a clickable info icon next to the "For You" title that displays a popover explaining the feed's filtering logic ("Most Recent Video - Disinterests Tags - Watch History + Interests Tags"). Implemented as a reusable helper `attachFeedInfoPopover` in `js/ui/components/FeedInfoPopover.js` to support future use on other feed pages. Updated `views/for-you.html` and `js/forYouView.js` to integrate the new component. Verified with Playwright.
This commit is contained in:
1 parent
933841bb0e
commit
bae4020682
5 files changed
+132
-1
No files matched your search
@@ -1,5 +1,6 @@
|
||||
import { getApplication } from "./applicationContext.js";
|
||||
import { devLogger } from "./utils/logger.js";
|
||||
import { attachFeedInfoPopover } from "./ui/components/FeedInfoPopover.js";
|
||||
|
||||
const VIDEO_CARD_SELECTOR = "[data-component=\"video-card\"]";
|
||||
const EMPTY_STATE_SELECTOR = "[data-for-you-empty-state]";
|
||||
@@ -23,6 +24,14 @@ class ForYouView {
|
||||
this.container.addEventListener("click", this.handleContainerClick);
|
||||
this.observeContainer();
|
||||
this.updateEmptyState();
|
||||
|
||||
const infoTrigger = this.document.getElementById("feedInfoTrigger");
|
||||
if (infoTrigger) {
|
||||
attachFeedInfoPopover(
|
||||
infoTrigger,
|
||||
"Most Recent Video - Disinterests Tags - Watch History + Interests Tags"
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
observeContainer() {
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
import createPopover from "../overlay/popoverEngine.js";
|
||||
|
||||
/**
|
||||
* Attaches an informational popover to a trigger element.
|
||||
*
|
||||
* @param {HTMLElement} triggerElement - The element that triggers the popover.
|
||||
* @param {string} text - The text content to display in the popover.
|
||||
* @param {object} [options] - Optional configuration.
|
||||
* @param {string} [options.placement="bottom-start"] - Popover placement.
|
||||
* @returns {object|null} - The popover instance or null if failed.
|
||||
*/
|
||||
export function attachFeedInfoPopover(triggerElement, text, options = {}) {
|
||||
if (!triggerElement || typeof text !== "string") {
|
||||
return null;
|
||||
}
|
||||
|
||||
const render = ({ document: doc, close }) => {
|
||||
const panel = doc.createElement("div");
|
||||
panel.className = "popover-panel p-4 max-w-xs text-sm text-text-strong bg-surface-elevated border border-surface-line rounded-lg shadow-lg z-50";
|
||||
panel.textContent = text;
|
||||
// Ensure the panel can receive focus if needed, but primarily it's informational.
|
||||
// Making it a "tooltip" or "dialog" role might be appropriate depending on interaction.
|
||||
// Since it's a click-toggle info box, standard popover behavior is fine.
|
||||
|
||||
// Add a simple close behavior if clicked outside (handled by popoverEngine),
|
||||
// but maybe we want to close if clicked inside too?
|
||||
// Usually info popovers stay open until clicked away.
|
||||
|
||||
return panel;
|
||||
};
|
||||
|
||||
const popover = createPopover(triggerElement, render, {
|
||||
placement: options.placement || "bottom-start",
|
||||
...options,
|
||||
});
|
||||
|
||||
triggerElement.addEventListener("click", (event) => {
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
popover.toggle();
|
||||
});
|
||||
|
||||
return popover;
|
||||
}
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 43 KiB |
@@ -0,0 +1,54 @@
|
||||
import sys
|
||||
import os
|
||||
import time
|
||||
from playwright.sync_api import sync_playwright
|
||||
|
||||
def verify_feed_info(page):
|
||||
print("Pre-seeding localStorage...")
|
||||
page.goto("http://localhost:8000") # Go to root first to set storage origin
|
||||
page.evaluate("window.localStorage.setItem('hasSeenDisclaimer', 'true')")
|
||||
|
||||
print("Navigating to For You view...")
|
||||
page.goto("http://localhost:8000/#view=for-you")
|
||||
|
||||
print("Waiting for feed info trigger...")
|
||||
trigger = page.locator("#feedInfoTrigger")
|
||||
try:
|
||||
trigger.wait_for(state="visible", timeout=10000)
|
||||
except Exception:
|
||||
page.screenshot(path="verification/debug_not_found.png")
|
||||
raise
|
||||
|
||||
# Ensure no modals are blocking
|
||||
# We can try to force click or wait for potential overlays to disappear
|
||||
# But pre-seeding should handle the main one.
|
||||
|
||||
print("Clicking trigger...")
|
||||
trigger.click()
|
||||
|
||||
print("Waiting for popover...")
|
||||
popover = page.locator(".popover-panel")
|
||||
popover.wait_for(state="visible", timeout=5000)
|
||||
|
||||
text = popover.inner_text()
|
||||
print(f"Popover text: {text}")
|
||||
|
||||
expected = "Most Recent Video - Disinterests Tags - Watch History + Interests Tags"
|
||||
if expected not in text:
|
||||
raise Exception(f"Unexpected text: {text}")
|
||||
|
||||
page.screenshot(path="verification/feed_info.png")
|
||||
print("Screenshot saved to verification/feed_info.png")
|
||||
|
||||
if __name__ == "__main__":
|
||||
with sync_playwright() as p:
|
||||
browser = p.chromium.launch(headless=True)
|
||||
context = browser.new_context()
|
||||
page = context.new_page()
|
||||
try:
|
||||
verify_feed_info(page)
|
||||
except Exception as e:
|
||||
print(f"Error: {e}")
|
||||
sys.exit(1)
|
||||
finally:
|
||||
browser.close()
|
||||
+25
-1
@@ -1,6 +1,30 @@
|
||||
<!-- views/for-you.html -->
|
||||
<section data-ds="new">
|
||||
<h2 class="mb-4 text-xl font-semibold text-text">For You</h2>
|
||||
<div class="flex items-center gap-2 mb-4">
|
||||
<h2 class="text-xl font-semibold text-text">For You</h2>
|
||||
<button
|
||||
type="button"
|
||||
id="feedInfoTrigger"
|
||||
class="text-muted hover:text-text focus:outline-none transition-colors"
|
||||
aria-label="How is this feed sorted?"
|
||||
>
|
||||
<svg
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
viewBox="0 0 24 24"
|
||||
fill="none"
|
||||
stroke="currentColor"
|
||||
stroke-width="2"
|
||||
stroke-linecap="round"
|
||||
stroke-linejoin="round"
|
||||
class="w-5 h-5"
|
||||
aria-hidden="true"
|
||||
>
|
||||
<circle cx="12" cy="12" r="10"></circle>
|
||||
<line x1="12" y1="16" x2="12" y2="12"></line>
|
||||
<line x1="12" y1="8" x2="12.01" y2="8"></line>
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<div id="videoList" class="bv-grid-video">
|
||||
<div class="sidebar-loading-wrapper" role="status" aria-live="polite">
|
||||
|
||||
Reference in new issue
Block a user