Les boutons suivent la couleur d’apparence, les libellés trop petits ou trop techniques sont clarifiés, et le catalogue des fournisseurs se met à jour tout seul. Co-authored-by: Cursor <cursoragent@cursor.com>
39 lines
1.1 KiB
TypeScript
39 lines
1.1 KiB
TypeScript
const PLACEHOLDER_TITLES = new Set([
|
|
'untitled',
|
|
'sans titre',
|
|
'(sans titre)',
|
|
'(untitled)',
|
|
])
|
|
|
|
function usableTitle(title: string | null | undefined): string | null {
|
|
const trimmed = title?.trim()
|
|
if (!trimmed) return null
|
|
if (PLACEHOLDER_TITLES.has(trimmed.toLowerCase())) return null
|
|
return trimmed
|
|
}
|
|
|
|
/** Titre affichable : vrai titre, sinon premier extrait du contenu. */
|
|
export function pathNoteTitle(
|
|
title: string | null | undefined,
|
|
content?: string | null,
|
|
): string | null {
|
|
const named = usableTitle(title)
|
|
if (named) return named
|
|
if (!content?.trim()) return null
|
|
const plain = content
|
|
.replace(/<[^>]+>/g, ' ')
|
|
.replace(/ /gi, ' ')
|
|
.replace(/\s+/g, ' ')
|
|
.trim()
|
|
if (!plain) return null
|
|
return plain.length > 80 ? `${plain.slice(0, 80).trim()}…` : plain
|
|
}
|
|
|
|
/** Première note récente qui a un titre ou un extrait — évite un héros « Sans titre ». */
|
|
export function pickFocusNote<T extends { title: string | null; content: string }>(
|
|
notes: T[],
|
|
): T | undefined {
|
|
if (notes.length === 0) return undefined
|
|
return notes.find(n => pathNoteTitle(n.title, n.content)) ?? notes[0]
|
|
}
|