From 31991ea1f805af79ec2c40b3a42ebb01c4cf97c1 Mon Sep 17 00:00:00 2001 From: mace Date: Sun, 12 Jul 2026 12:28:32 +0200 Subject: [PATCH] Feed filter implementation --- vue/src/components/AppNav.vue | 46 +++++++- vue/src/components/__tests__/AppNav.spec.js | 96 +++++++++++++++- .../composables/__tests__/useFeeds.spec.js | 106 +++++++++++++++++- vue/src/composables/useFeeds.js | 68 ++++++++++- 4 files changed, 306 insertions(+), 10 deletions(-) diff --git a/vue/src/components/AppNav.vue b/vue/src/components/AppNav.vue index 2348f6b..c808476 100644 --- a/vue/src/components/AppNav.vue +++ b/vue/src/components/AppNav.vue @@ -6,7 +6,7 @@ import Modal from './modal/AddUrl.vue' const router = useRouter() const route = useRoute() -const { sync, showModal, viewMode, toggleViewMode, layout, toggleLayout, markAllRead, feeds, lastProgrammaticScroll } = useFeeds() +const { sync, showModal, viewMode, toggleViewMode, layout, toggleLayout, markAllRead, feedFilter, feedTitles, setFeedFilter, unreadCount, lastProgrammaticScroll } = useFeeds() const headerRef = ref(null) @@ -77,15 +77,16 @@ onMounted(() => { lastY = Math.max(0, window.scrollY) window.addEventListener('scroll', onScrollRaf, { passive: true }) + document.addEventListener('click', onDocumentClick) }) onUnmounted(() => { window.removeEventListener('scroll', onScrollRaf) + document.removeEventListener('click', onDocumentClick) }) const onFeedsPage = computed(() => route.path === '/feeds') -const unreadCount = computed(() => feeds.value.filter(f => !f.read).length) const menuOpen = ref(false) @@ -97,6 +98,19 @@ function closeMenu() { menuOpen.value = false } +// The open menu is a thin absolutely-positioned strip under the header, so its +// `@click.self` only catches clicks on that strip — a click anywhere else on +// the page never reaches it. This document-level listener closes the menu on +// any outside click. The hamburger is excluded (it has its own toggle, so an +// opening click mustn't immediately re-close), and clicks inside the menu are +// left to the menu items' own handlers. +function onDocumentClick(event) { + if (!menuOpen.value) return + const target = event.target + if (target.closest?.('.app-nav__hamburger') || target.closest?.('.app-nav__menu')) return + closeMenu() +} + async function logout() { await logoutSession() closeMenu() @@ -133,6 +147,16 @@ function handleToggleLayout() {
RSS Reader ({{ unreadCount }}) +