aboutsummaryrefslogtreecommitdiffstats
path: root/frontend/src/components/FeedItems.tsx
diff options
context:
space:
mode:
authorAdam Mathes <adam@adammathes.com>2026-02-16 10:53:59 -0800
committerAdam Mathes <adam@trenchant.org>2026-02-16 10:57:38 -0800
commit5cf8275540d7162cd4936a7c0e76dbfe7f66b62c (patch)
treefdb3c47560f1b1556f7c203f72d50d13f171c95a /frontend/src/components/FeedItems.tsx
parent96e78c5fdfada73d37644083c7580a1d444ed748 (diff)
downloadneko-5cf8275540d7162cd4936a7c0e76dbfe7f66b62c.tar.gz
neko-5cf8275540d7162cd4936a7c0e76dbfe7f66b62c.tar.bz2
neko-5cf8275540d7162cd4936a7c0e76dbfe7f66b62c.zip
V3 UI Polish: Improved keyboard navigation, fixed logo position, and updated branding
- Fix V3 keyboard navigation delay (resolved NK-wjats7) - Update V3 document title to 'neko' (resolved NK-4p3s91) - Fix V3 neko logo/button position to be top-left fixed (resolved NK-89za3s) - Improve FeedItems (React) stability with ref-based index tracking and robust tests - Sync V3 styling and selection feedback with V2 patterns - Rebuild production assets
Diffstat (limited to 'frontend/src/components/FeedItems.tsx')
-rw-r--r--frontend/src/components/FeedItems.tsx21
1 files changed, 14 insertions, 7 deletions
diff --git a/frontend/src/components/FeedItems.tsx b/frontend/src/components/FeedItems.tsx
index 2c3253b..ea5d8fd 100644
--- a/frontend/src/components/FeedItems.tsx
+++ b/frontend/src/components/FeedItems.tsx
@@ -19,6 +19,7 @@ export default function FeedItems() {
const hasMoreRef = useRef(hasMore);
const [error, setError] = useState('');
const [selectedIndex, setSelectedIndex] = useState(-1);
+ const selectedIndexRef = useRef(selectedIndex);
// Sync refs
useEffect(() => {
@@ -33,6 +34,10 @@ export default function FeedItems() {
hasMoreRef.current = hasMore;
}, [hasMore]);
+ useEffect(() => {
+ selectedIndexRef.current = selectedIndex;
+ }, [selectedIndex]);
+
const fetchItems = useCallback((maxId?: string) => {
if (maxId) {
setLoadingMore(true);
@@ -156,8 +161,9 @@ export default function FeedItems() {
if (currentItems.length === 0) return;
if (e.key === 'j') {
- const nextIndex = Math.min(selectedIndex + 1, currentItems.length - 1);
- if (nextIndex !== selectedIndex) {
+ const nextIndex = Math.min(selectedIndexRef.current + 1, currentItems.length - 1);
+ if (nextIndex !== selectedIndexRef.current) {
+ selectedIndexRef.current = nextIndex;
setSelectedIndex(nextIndex);
const item = currentItems[nextIndex];
if (!item.read) {
@@ -174,21 +180,22 @@ export default function FeedItems() {
fetchItems(String(currentItems[currentItems.length - 1]._id));
}
} else if (e.key === 'k') {
- const nextIndex = Math.max(selectedIndex - 1, 0);
- if (nextIndex !== selectedIndex) {
+ const nextIndex = Math.max(selectedIndexRef.current - 1, 0);
+ if (nextIndex !== selectedIndexRef.current) {
+ selectedIndexRef.current = nextIndex;
setSelectedIndex(nextIndex);
scrollToItem(nextIndex);
}
} else if (e.key === 's') {
- if (selectedIndex >= 0 && selectedIndex < currentItems.length) {
- toggleStar(currentItems[selectedIndex]);
+ if (selectedIndexRef.current >= 0 && selectedIndexRef.current < currentItems.length) {
+ toggleStar(currentItems[selectedIndexRef.current]);
}
}
};
window.addEventListener('keydown', handleKeyDown);
return () => window.removeEventListener('keydown', handleKeyDown);
- }, [markAsRead, scrollToItem, toggleStar, fetchItems, selectedIndex]);
+ }, [markAsRead, scrollToItem, toggleStar, fetchItems]);
// Stable Observer