develop #1
@@ -47,7 +47,7 @@ export function KeyboardNavigableNoteList({
|
|||||||
}
|
}
|
||||||
}, [])
|
}, [])
|
||||||
|
|
||||||
const { selectedIndex } = useNoteListKeyboard({
|
const { selectedIndex, prefetchNote } = useNoteListKeyboard({
|
||||||
notes,
|
notes,
|
||||||
onEdit,
|
onEdit,
|
||||||
onFavorite: handleFavorite,
|
onFavorite: handleFavorite,
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
|
import { useRouter } from 'next/navigation'
|
||||||
import { Note } from '@/types/note'
|
import { Note } from '@/types/note'
|
||||||
import { Card, CardContent } from '@/components/ui/card'
|
import { Card, CardContent } from '@/components/ui/card'
|
||||||
import { Badge } from '@/components/ui/badge'
|
import { Badge } from '@/components/ui/badge'
|
||||||
@@ -16,12 +17,21 @@ const typeColors: Record<string, string> = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export function NoteCard({ note }: { note: Note }) {
|
export function NoteCard({ note }: { note: Note }) {
|
||||||
|
const router = useRouter()
|
||||||
const preview = note.content.slice(0, 100) + (note.content.length > 100 ? '...' : '')
|
const preview = note.content.slice(0, 100) + (note.content.length > 100 ? '...' : '')
|
||||||
const typeColor = typeColors[note.type] || typeColors.note
|
const typeColor = typeColors[note.type] || typeColors.note
|
||||||
|
|
||||||
|
const handleMouseEnter = () => {
|
||||||
|
// Prefetch on hover for faster navigation
|
||||||
|
router.prefetch(`/notes/${note.id}`)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link href={`/notes/${note.id}`}>
|
<Link href={`/notes/${note.id}`} prefetch={true}>
|
||||||
<Card className="hover:shadow-md transition-shadow cursor-pointer h-full">
|
<Card
|
||||||
|
className="hover:shadow-md transition-shadow cursor-pointer h-full"
|
||||||
|
onMouseEnter={handleMouseEnter}
|
||||||
|
>
|
||||||
<CardContent className="p-4">
|
<CardContent className="p-4">
|
||||||
<div className="flex items-start justify-between gap-2 mb-2">
|
<div className="flex items-start justify-between gap-2 mb-2">
|
||||||
<h3 className="font-semibold text-lg line-clamp-1">{note.title}</h3>
|
<h3 className="font-semibold text-lg line-clamp-1">{note.title}</h3>
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
import { useEffect, useCallback, useState } from 'react'
|
import { useEffect, useCallback, useState, useRef } from 'react'
|
||||||
import { useRouter } from 'next/navigation'
|
import { useRouter } from 'next/navigation'
|
||||||
import { Note } from '@/types/note'
|
import { Note } from '@/types/note'
|
||||||
|
|
||||||
@@ -17,10 +17,19 @@ export function useNoteListKeyboard({
|
|||||||
}: UseNoteListKeyboardOptions) {
|
}: UseNoteListKeyboardOptions) {
|
||||||
const [selectedIndex, setSelectedIndex] = useState(-1)
|
const [selectedIndex, setSelectedIndex] = useState(-1)
|
||||||
const router = useRouter()
|
const router = useRouter()
|
||||||
|
const prefetchedRef = useRef<Set<string>>(new Set())
|
||||||
|
|
||||||
|
// Prefetch a note's page data for faster navigation
|
||||||
|
const prefetchNote = useCallback((noteId: string) => {
|
||||||
|
if (prefetchedRef.current.has(noteId)) return
|
||||||
|
prefetchedRef.current.add(noteId)
|
||||||
|
router.prefetch(`/notes/${noteId}`)
|
||||||
|
}, [router])
|
||||||
|
|
||||||
// Reset selection when notes change
|
// Reset selection when notes change
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
setSelectedIndex(-1)
|
setSelectedIndex(-1)
|
||||||
|
prefetchedRef.current.clear()
|
||||||
}, [notes.length])
|
}, [notes.length])
|
||||||
|
|
||||||
const handleKeyDown = useCallback(
|
const handleKeyDown = useCallback(
|
||||||
@@ -38,13 +47,19 @@ export function useNoteListKeyboard({
|
|||||||
switch (e.key) {
|
switch (e.key) {
|
||||||
case 'ArrowDown':
|
case 'ArrowDown':
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setSelectedIndex((prev) =>
|
setSelectedIndex((prev) => {
|
||||||
prev < notes.length - 1 ? prev + 1 : notes.length - 1
|
const next = prev < notes.length - 1 ? prev + 1 : notes.length - 1
|
||||||
)
|
if (notes[next]) prefetchNote(notes[next].id)
|
||||||
|
return next
|
||||||
|
})
|
||||||
break
|
break
|
||||||
case 'ArrowUp':
|
case 'ArrowUp':
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
setSelectedIndex((prev) => (prev > 0 ? prev - 1 : -1))
|
setSelectedIndex((prev) => {
|
||||||
|
const next = prev > 0 ? prev - 1 : -1
|
||||||
|
if (next >= 0 && notes[next]) prefetchNote(notes[next].id)
|
||||||
|
return next
|
||||||
|
})
|
||||||
break
|
break
|
||||||
case 'Enter':
|
case 'Enter':
|
||||||
e.preventDefault()
|
e.preventDefault()
|
||||||
@@ -75,7 +90,7 @@ export function useNoteListKeyboard({
|
|||||||
break
|
break
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[notes, selectedIndex, router, onEdit, onFavorite, onPin]
|
[notes, selectedIndex, router, onEdit, onFavorite, onPin, prefetchNote]
|
||||||
)
|
)
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
@@ -83,5 +98,5 @@ export function useNoteListKeyboard({
|
|||||||
return () => window.removeEventListener('keydown', handleKeyDown)
|
return () => window.removeEventListener('keydown', handleKeyDown)
|
||||||
}, [handleKeyDown])
|
}, [handleKeyDown])
|
||||||
|
|
||||||
return { selectedIndex, setSelectedIndex }
|
return { selectedIndex, setSelectedIndex, prefetchNote }
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user