fix some frontend issues
This commit is contained in:
@@ -11,6 +11,7 @@ const showModal = ref(false)
|
||||
const viewMode = ref('list') // 'list' | 'article' — toggled from the hamburger menu
|
||||
const currentIndex = ref(0)
|
||||
const layout = ref(localStorage.getItem('layout') || 'list') // 'list' | 'cards' — list-view display style, toggled from the hamburger menu
|
||||
const navTitleVisible = ref(true) // whether AppNav's "RSS Reader (N)" title is currently in view
|
||||
|
||||
let observer; // Declare observer outside the setup function
|
||||
let initialLoad = false
|
||||
@@ -92,6 +93,11 @@ async function getReadable(feed, index) {
|
||||
doc.head.prepend(base);
|
||||
doc.querySelectorAll('img').forEach(resolveTemplatedImage);
|
||||
doc.querySelectorAll('video, audio').forEach(el => el.remove());
|
||||
// Some feeds (e.g. Stuttgarter Nachrichten) embed a social-sharing widget
|
||||
// (WhatsApp/Email/Facebook/... links plus a "Link kopiert" tooltip) in the
|
||||
// article body. It's not part of the article, so strip it before Readability
|
||||
// pulls it into the parsed content.
|
||||
doc.querySelectorAll('#article-social-bar').forEach(el => el.remove())
|
||||
// Some feeds (e.g. Deutsche Welle) leave behind a heading + play-icon SVG
|
||||
// for an embedded video/audio player whose actual <video>/<audio>/<iframe>
|
||||
// we already stripped — without it, the heading is just a giant orphaned
|
||||
@@ -160,9 +166,14 @@ function setupIntersectionObserver() {
|
||||
observer.disconnect();
|
||||
}
|
||||
|
||||
observer = new IntersectionObserver(handleIntersection, {
|
||||
// The sticky topbar overlays the top of the viewport, so an article fully
|
||||
// hidden behind it should already count as "scrolled past" — shrink the
|
||||
// observer's root by that height so it stops intersecting at that point.
|
||||
const topbarHeight = document.querySelector('.list-topbar')?.getBoundingClientRect().height ?? 0;
|
||||
|
||||
observer = new IntersectionObserver((entries) => handleIntersection(entries, topbarHeight), {
|
||||
root: null, // Use the viewport as the root
|
||||
rootMargin: '0px',
|
||||
rootMargin: `-${topbarHeight}px 0px 0px 0px`,
|
||||
// threshold: 0.5, // Fire the callback when at least 50% of the element is visible
|
||||
});
|
||||
|
||||
@@ -174,14 +185,15 @@ function setupIntersectionObserver() {
|
||||
}
|
||||
}
|
||||
|
||||
async function handleIntersection(entries) {
|
||||
// An article that has scrolled above the viewport (not intersecting,
|
||||
// bounding box above the top edge) has been read. Resolve all affected
|
||||
// feeds up front, before any removal — splicing `feeds` while iterating
|
||||
// would shift the array indices that later entries' `target.id` refer to,
|
||||
// causing the wrong item to be marked read and removed.
|
||||
async function handleIntersection(entries, topbarHeight = 0) {
|
||||
// An article that has scrolled past the (possibly sticky-bar-shrunk) top
|
||||
// edge of the viewport (not intersecting, bounding box above that edge)
|
||||
// has been read. Resolve all affected feeds up front, before any removal —
|
||||
// splicing `feeds` while iterating would shift the array indices that later
|
||||
// entries' `target.id` refer to, causing the wrong item to be marked read
|
||||
// and removed.
|
||||
const readFeeds = entries
|
||||
.filter(entry => initialLoad === true && !entry.isIntersecting && entry.boundingClientRect.y < 0)
|
||||
.filter(entry => initialLoad === true && !entry.isIntersecting && entry.boundingClientRect.y < topbarHeight)
|
||||
.map(entry => feeds.value[entry.target.id])
|
||||
.filter(Boolean)
|
||||
|
||||
@@ -280,6 +292,7 @@ export function useFeeds() {
|
||||
leaveArticleView,
|
||||
layout,
|
||||
toggleLayout,
|
||||
navTitleVisible,
|
||||
nextArticle,
|
||||
prevArticle,
|
||||
fetchData,
|
||||
|
||||
Reference in New Issue
Block a user