develop #1
@@ -2,6 +2,7 @@ import { prisma } from '@/lib/prisma'
|
||||
import { notFound } from 'next/navigation'
|
||||
import { getRelatedNotes } from '@/lib/related'
|
||||
import { getBacklinksForNote, getOutgoingLinksForNote } from '@/lib/backlinks'
|
||||
import { getCoUsedNotes } from '@/lib/usage'
|
||||
import { NoteConnections } from '@/components/note-connections'
|
||||
import { MarkdownContent } from '@/components/markdown-content'
|
||||
import { DeleteNoteButton } from '@/components/delete-note-button'
|
||||
@@ -36,6 +37,7 @@ export default async function NoteDetailPage({ params }: { params: Promise<{ id:
|
||||
const related = await getRelatedNotes(id, 5)
|
||||
const backlinks = await getBacklinksForNote(id)
|
||||
const outgoingLinks = await getOutgoingLinksForNote(id)
|
||||
const coUsedNotes = await getCoUsedNotes(id, 5)
|
||||
const noteType = note.type as NoteType
|
||||
|
||||
return (
|
||||
@@ -100,6 +102,7 @@ export default async function NoteDetailPage({ params }: { params: Promise<{ id:
|
||||
backlinks={backlinks}
|
||||
outgoingLinks={outgoingLinks}
|
||||
relatedNotes={related}
|
||||
coUsedNotes={coUsedNotes}
|
||||
/>
|
||||
</main>
|
||||
</>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
import Link from 'next/link'
|
||||
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
|
||||
import { Badge } from '@/components/ui/badge'
|
||||
import { ArrowRight, Link2, RefreshCw, ExternalLink } from 'lucide-react'
|
||||
import { ArrowRight, Link2, RefreshCw, ExternalLink, Users } from 'lucide-react'
|
||||
|
||||
interface BacklinkInfo {
|
||||
id: string
|
||||
@@ -30,6 +30,7 @@ interface NoteConnectionsProps {
|
||||
backlinks: BacklinkInfo[]
|
||||
outgoingLinks: BacklinkInfo[]
|
||||
relatedNotes: RelatedNote[]
|
||||
coUsedNotes: { noteId: string; title: string; type: string; weight: number }[]
|
||||
}
|
||||
|
||||
function ConnectionGroup({
|
||||
@@ -84,9 +85,10 @@ export function NoteConnections({
|
||||
backlinks,
|
||||
outgoingLinks,
|
||||
relatedNotes,
|
||||
coUsedNotes,
|
||||
}: NoteConnectionsProps) {
|
||||
const hasAnyConnections =
|
||||
backlinks.length > 0 || outgoingLinks.length > 0 || relatedNotes.length > 0
|
||||
backlinks.length > 0 || outgoingLinks.length > 0 || relatedNotes.length > 0 || coUsedNotes.length > 0
|
||||
|
||||
if (!hasAnyConnections) {
|
||||
return null
|
||||
@@ -136,6 +138,18 @@ export function NoteConnections({
|
||||
}))}
|
||||
emptyMessage="No hay notas relacionadas"
|
||||
/>
|
||||
|
||||
{/* Co-used notes - often viewed together */}
|
||||
<ConnectionGroup
|
||||
title="Co-usadas"
|
||||
icon={Users}
|
||||
notes={coUsedNotes.map((cu) => ({
|
||||
id: cu.noteId,
|
||||
title: cu.title,
|
||||
type: cu.type,
|
||||
}))}
|
||||
emptyMessage="No hay notas co-usadas"
|
||||
/>
|
||||
</CardContent>
|
||||
</Card>
|
||||
)
|
||||
|
||||
@@ -7,6 +7,10 @@ import { Button } from '@/components/ui/button'
|
||||
import { Search, Loader2 } from 'lucide-react'
|
||||
import { ScoredNote } from '@/lib/search'
|
||||
|
||||
// Simple in-memory cache for search results
|
||||
const searchCache = new Map<string, ScoredNote[]>()
|
||||
const MAX_CACHE_SIZE = 50
|
||||
|
||||
export function SearchBar() {
|
||||
const [query, setQuery] = useState('')
|
||||
const [results, setResults] = useState<ScoredNote[]>([])
|
||||
@@ -31,14 +35,31 @@ export function SearchBar() {
|
||||
}
|
||||
|
||||
debounceRef.current = setTimeout(async () => {
|
||||
// Check cache first
|
||||
if (searchCache.has(query)) {
|
||||
setResults(searchCache.get(query)!)
|
||||
setIsOpen(true)
|
||||
setSelectedIndex(-1)
|
||||
return
|
||||
}
|
||||
|
||||
setIsLoading(true)
|
||||
try {
|
||||
const res = await fetch(`/api/search?q=${encodeURIComponent(query)}`)
|
||||
const json = await res.json()
|
||||
if (json.success) {
|
||||
setResults(json.data.slice(0, 8))
|
||||
const results = json.data.slice(0, 8)
|
||||
setResults(results)
|
||||
setIsOpen(true)
|
||||
setSelectedIndex(-1)
|
||||
|
||||
// Cache the results
|
||||
if (searchCache.size >= MAX_CACHE_SIZE) {
|
||||
// Remove oldest entry (first in Map)
|
||||
const firstKey = searchCache.keys().next().value
|
||||
if (firstKey) searchCache.delete(firstKey)
|
||||
}
|
||||
searchCache.set(query, results)
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Search failed:', error)
|
||||
|
||||
Reference in New Issue
Block a user