All checks were successful
Deploy to Production / Build and Deploy (push) Successful in 2m12s
Replace JSON-string embeddings with native pgvector(1536) storage and add PostgreSQL full-text search (tsvector/GIN) with Reciprocal Rank Fusion for hybrid keyword + semantic ranking. Changes: - NoteEmbedding.embedding: String → vector(1536) via pgvector - NoteEmbedding: added updatedAt for reindex tracking - Note: added tsv (tsvector) with auto-update trigger for FTS - semantic-search.service: hybrid FTS + vector search with RRF fusion - embedding.service: toVectorString() for pgvector SQL literals - Removed JS-side cosine similarity loops (now DB-side via <=>) - Added HNSW index on NoteEmbedding.embedding (cosine distance) - Added GIN index on Note.tsv for FTS queries Schema migration in: prisma/migrations/20260512120000_pgvector_and_fts_search/ Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
52 lines
2.2 KiB
TypeScript
52 lines
2.2 KiB
TypeScript
import React from 'react';
|
|
import { Settings, Sparkles, Palette, User, Database, Code, Info } from 'lucide-react';
|
|
import { motion } from 'motion/react';
|
|
import { SettingsTab } from '../../types';
|
|
|
|
interface SettingsHeaderProps {
|
|
activeTab: SettingsTab;
|
|
setActiveTab: (tab: SettingsTab) => void;
|
|
}
|
|
|
|
export const SettingsHeader: React.FC<SettingsHeaderProps> = ({ activeTab, setActiveTab }) => {
|
|
const tabs = [
|
|
{ id: 'general', label: 'Paramètres généraux', icon: <Settings size={14} /> },
|
|
{ id: 'ai', label: 'Paramètres IA', icon: <Sparkles size={14} /> },
|
|
{ id: 'appearance', label: 'Apparence', icon: <Palette size={14} /> },
|
|
{ id: 'profile', label: 'Profil', icon: <User size={14} /> },
|
|
{ id: 'data', label: 'Gestion des données', icon: <Database size={14} /> },
|
|
{ id: 'mcp', label: 'Paramètres MCP', icon: <Code size={14} /> },
|
|
{ id: 'about', label: 'À propos', icon: <Info size={14} /> },
|
|
];
|
|
|
|
return (
|
|
<header className="px-12 pt-20 pb-16 space-y-12">
|
|
<div className="space-y-4">
|
|
<h1 className="text-[64px] font-serif text-ink tracking-tight leading-none italic font-medium">Paramètres</h1>
|
|
<p className="text-[10px] font-bold uppercase tracking-[0.4em] text-concrete opacity-60">Configuration & Préférences</p>
|
|
</div>
|
|
|
|
<nav className="flex items-center gap-1 border-b border-border/40 pb-px">
|
|
{tabs.map((tab) => (
|
|
<button
|
|
key={tab.id}
|
|
onClick={() => setActiveTab(tab.id as SettingsTab)}
|
|
className={`flex items-center gap-2.5 px-6 py-5 text-[10px] font-bold uppercase tracking-[0.18em] transition-all relative whitespace-nowrap
|
|
${activeTab === tab.id ? 'text-ink' : 'text-concrete hover:text-ink/60'}`}
|
|
>
|
|
<span className={activeTab === tab.id ? 'text-ink' : 'text-concrete'}>{tab.icon}</span>
|
|
{tab.label}
|
|
{activeTab === tab.id && (
|
|
<motion.div
|
|
layoutId="activeSettingsTabLine"
|
|
className="absolute bottom-0 left-0 right-0 h-0.5 bg-ink"
|
|
transition={{ type: 'spring', bounce: 0.1, duration: 0.8 }}
|
|
/>
|
|
)}
|
|
</button>
|
|
))}
|
|
</nav>
|
|
</header>
|
|
);
|
|
};
|