Show a sync-in-progress spinner in the header next to the feed filter
activeSyncCount/isSyncing() in useFeeds.js already refcounted both boot reload (fetchData) and manual sync() but wasn't reactive. Make it a ref + computed and expose it so AppNav can render a small spinner next to the feed filter whenever a sync is in flight. The spinner sits outside the filter's own v-if so it also shows during a manual sync from pages other than /feeds, and its box is always reserved (visibility toggle, not v-if) so the one-time --app-nav-height measurement stays correct.
This commit is contained in:
@@ -5,7 +5,7 @@ import { useFeeds, logout as logoutSession } from '@/composables/useFeeds'
|
||||
|
||||
const router = useRouter()
|
||||
const route = useRoute()
|
||||
const { sync, viewMode, toggleViewMode, layout, toggleLayout, markAllRead, feedFilter, feedTitles, setFeedFilter, unreadCount, displayedFeedUnreadCounts, refreshUnreadDisplay, lastProgrammaticScroll } = useFeeds()
|
||||
const { sync, viewMode, toggleViewMode, layout, toggleLayout, markAllRead, feedFilter, feedTitles, setFeedFilter, unreadCount, displayedFeedUnreadCounts, refreshUnreadDisplay, lastProgrammaticScroll, isSyncing } = useFeeds()
|
||||
|
||||
const headerRef = ref(null)
|
||||
|
||||
@@ -161,6 +161,11 @@ function handleToggleLayout() {
|
||||
<header ref="headerRef" class="app-nav" :class="{ 'app-nav--hidden': hidden }">
|
||||
<div class="app-nav__wrapper">
|
||||
<span class="app-nav__title">RSS Reader<span v-if="unreadCount" class="app-nav__unread"> ({{ unreadCount }})</span></span>
|
||||
<span
|
||||
class="app-nav__sync-spinner"
|
||||
:class="{ 'app-nav__sync-spinner--active': isSyncing }"
|
||||
aria-hidden="true"
|
||||
></span>
|
||||
<select
|
||||
v-if="onFeedsPage && feedTitles.length"
|
||||
class="app-nav__filter"
|
||||
@@ -251,6 +256,34 @@ function handleToggleLayout() {
|
||||
opacity: 0.6;
|
||||
}
|
||||
|
||||
.app-nav__sync-spinner {
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
border: 2px solid var(--color-border);
|
||||
border-top-color: var(--color-text);
|
||||
border-radius: 50%;
|
||||
opacity: 0.6;
|
||||
flex-shrink: 0;
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.app-nav__sync-spinner--active {
|
||||
visibility: visible;
|
||||
animation: app-nav-spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
@keyframes app-nav-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@media (prefers-reduced-motion: reduce) {
|
||||
.app-nav__sync-spinner--active {
|
||||
animation: none;
|
||||
}
|
||||
}
|
||||
|
||||
.app-nav__filter {
|
||||
min-height: 44px;
|
||||
max-width: clamp(120px, 40vw, 220px);
|
||||
|
||||
Reference in New Issue
Block a user