feat: aide contextuelle dans les paramètres (SettingsHelpBox)
- Nouveau composant SettingsHelpBox (accordéon bleu, étapes numérotées) - Intégrations: aide Google Calendar + aide Readwise (inline, avant les boutons) - MCP: explication de ce qu'est MCP et comment l'utiliser - IA: explication des fournisseurs, BYOK, Ollama, quotas - Données: explication import/export/ré-indexation/suppression compte Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
This commit is contained in:
@@ -1,13 +1,21 @@
|
||||
'use client'
|
||||
|
||||
import { useLanguage } from '@/lib/i18n'
|
||||
import { SettingsHelpBox } from '@/components/settings/settings-help-box'
|
||||
|
||||
export function AISettingsHeader() {
|
||||
const { t } = useLanguage()
|
||||
|
||||
return (
|
||||
<h3 className="text-[10px] font-bold uppercase tracking-[0.4em] text-concrete opacity-60">
|
||||
{t('aiSettings.description')}
|
||||
</h3>
|
||||
<SettingsHelpBox
|
||||
title="Comment configurer votre IA ?"
|
||||
steps={[
|
||||
{ text: 'Choisissez un fournisseur IA parmi 8 disponibles : OpenAI, Anthropic, Google, Mistral, Groq, DeepSeek, Perplexity, ou Ollama (local).' },
|
||||
{ text: 'Sélectionnez le modèle — chaque fournisseur propose plusieurs modèles avec des capacités différentes (rapidité, coût, contexte).' },
|
||||
{ text: 'Mode BYOK (Bring Your Own Key) : entrez votre propre clé API pour utiliser votre quota directement — sans passer par les quotas Momento.' },
|
||||
{ text: 'Les crédits Momento (quota mensuel) sont utilisés quand vous n\'avez pas de clé personnelle. Le plan Free inclut 10 crédits/mois.' },
|
||||
{ icon: '💡', text: 'Conseil : Ollama permet de faire tourner un LLM entièrement en local sur votre machine — 100% privé, zéro coût.' },
|
||||
]}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import { DeleteAccountDialog } from '@/components/legal/delete-account-dialog'
|
||||
import { useRouter } from 'next/navigation'
|
||||
import { motion } from 'motion/react'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { SettingsHelpBox } from '@/components/settings/settings-help-box'
|
||||
|
||||
export default function DataSettingsPage() {
|
||||
const { t } = useLanguage()
|
||||
@@ -225,6 +226,17 @@ export default function DataSettingsPage() {
|
||||
animate={{ opacity: 1, y: 0 }}
|
||||
className="space-y-12"
|
||||
>
|
||||
<SettingsHelpBox
|
||||
title="Import / Export — comment ça fonctionne ?"
|
||||
steps={[
|
||||
{ text: 'Export ZIP : télécharge toutes vos notes en fichiers Markdown + images + métadonnées. Format universel, lisible partout.' },
|
||||
{ text: 'Export JSON : version structurée de vos données — utile pour migrer ou sauvegarder programmatiquement.' },
|
||||
{ text: 'Import Markdown : importez un fichier .md existant directement dans Momento en tant que nouvelle note.' },
|
||||
{ text: 'Ré-indexer : si la recherche sémantique ne trouve pas certaines notes, relancez l\'indexation pour recalculer les embeddings.' },
|
||||
{ icon: '⚠️', text: 'Supprimer le compte efface définitivement toutes vos données. Pensez à exporter d\'abord.' },
|
||||
]}
|
||||
/>
|
||||
|
||||
<h3 className="text-[10px] font-bold uppercase tracking-[0.3em] text-concrete">
|
||||
{t('dataManagement.toolsDescription')}
|
||||
</h3>
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
import { useState, useEffect } from 'react'
|
||||
import { BookOpen, Loader2, Check, X, RefreshCw, Trash2, CalendarDays } from 'lucide-react'
|
||||
import { toast } from 'sonner'
|
||||
import { SettingsHelpBox } from '@/components/settings/settings-help-box'
|
||||
|
||||
export default function IntegrationsPage() {
|
||||
// ── Readwise ───────────────────────────────────────────────────────────
|
||||
@@ -158,13 +159,24 @@ export default function IntegrationsPage() {
|
||||
</div>
|
||||
|
||||
{!calConnected ? (
|
||||
<button
|
||||
onClick={handleCalConnect}
|
||||
className="px-4 py-2 text-sm font-semibold bg-ink text-paper rounded-xl hover:bg-ink/80 transition-all flex items-center gap-2"
|
||||
>
|
||||
<CalendarDays size={14} />
|
||||
Connecter Google Calendar
|
||||
</button>
|
||||
<div className="space-y-3">
|
||||
<SettingsHelpBox
|
||||
title="Comment fonctionne Google Calendar ?"
|
||||
steps={[
|
||||
{ text: 'Cliquez "Connecter Google Calendar" — vous serez redirigé vers Google pour autoriser l\'accès.' },
|
||||
{ text: 'Une fois connecté, revenez ici et cliquez "Événements aujourd\'hui" pour voir votre agenda.' },
|
||||
{ text: 'Sur chaque événement, cliquez "+ Note" pour créer automatiquement une note de réunion avec template (Ordre du jour / Notes / Actions).' },
|
||||
{ text: 'La note s\'ouvre directement dans Momento — ajoutez vos notes en temps réel pendant la réunion.' },
|
||||
]}
|
||||
/>
|
||||
<button
|
||||
onClick={handleCalConnect}
|
||||
className="px-4 py-2 text-sm font-semibold bg-ink text-paper rounded-xl hover:bg-ink/80 transition-all flex items-center gap-2"
|
||||
>
|
||||
<CalendarDays size={14} />
|
||||
Connecter Google Calendar
|
||||
</button>
|
||||
</div>
|
||||
) : (
|
||||
<div className="space-y-3">
|
||||
<div className="flex flex-wrap gap-2">
|
||||
@@ -226,12 +238,16 @@ export default function IntegrationsPage() {
|
||||
|
||||
{!rwConnected && (
|
||||
<div className="space-y-3">
|
||||
<p className="text-[12px] text-concrete">
|
||||
Trouvez votre token sur{' '}
|
||||
<a href="https://readwise.io/access_token" target="_blank" rel="noopener noreferrer" className="text-brand-accent underline">
|
||||
readwise.io/access_token
|
||||
</a>
|
||||
</p>
|
||||
<SettingsHelpBox
|
||||
title="Comment fonctionne Readwise ?"
|
||||
steps={[
|
||||
{ text: 'Copiez votre token d\'accès Readwise.', link: { label: 'readwise.io/access_token', href: 'https://readwise.io/access_token' } },
|
||||
{ text: 'Collez-le dans le champ ci-dessous et cliquez "Connecter". La première synchronisation importe tous vos livres et articles.' },
|
||||
{ text: 'Chaque livre devient une note dans un carnet "Readwise 📚" — avec tous vos surlignages organisés.' },
|
||||
{ text: 'Pour mettre à jour avec de nouveaux surlignages, revenez ici et cliquez "Synchroniser maintenant".' },
|
||||
{ icon: '💡', text: 'Astuce : créez des flashcards IA depuis une note Readwise (bouton 🎓 dans l\'éditeur) pour réviser vos lectures.' },
|
||||
]}
|
||||
/>
|
||||
<div className="flex gap-2">
|
||||
<input
|
||||
type="password"
|
||||
|
||||
@@ -2,7 +2,7 @@ import { auth } from '@/auth'
|
||||
import { redirect } from 'next/navigation'
|
||||
import { McpSettingsPanel } from '@/components/mcp/mcp-settings-panel'
|
||||
import { listMcpKeys, getMcpServerStatus } from '@/app/actions/mcp-keys'
|
||||
import { useLanguage } from '@/lib/i18n'
|
||||
import { SettingsHelpBox } from '@/components/settings/settings-help-box'
|
||||
|
||||
export default async function McpSettingsPage() {
|
||||
const session = await auth()
|
||||
@@ -15,9 +15,17 @@ export default async function McpSettingsPage() {
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<h3 className="text-[10px] font-bold uppercase tracking-[0.3em] text-concrete">
|
||||
Gérez vos clés API et serveurs MCP connectés.
|
||||
</h3>
|
||||
<SettingsHelpBox
|
||||
title="Qu'est-ce que MCP (Model Context Protocol) ?"
|
||||
defaultOpen={true}
|
||||
steps={[
|
||||
{ text: 'MCP est un protocole qui permet aux agents IA de Momento de se connecter à des outils externes (bases de données, APIs, fichiers, etc.).' },
|
||||
{ text: 'Momento expose un serveur MCP avec 22 outils — vos agents peuvent lire/créer des notes, chercher dans votre base, gérer les carnets, etc.' },
|
||||
{ text: 'Créez une clé API ici, puis configurez-la dans votre client MCP (Claude Desktop, Cursor, Continue.dev…) avec l\'URL du serveur.' },
|
||||
{ text: 'Format de configuration : URL du serveur MCP + votre clé dans le header Authorization.', link: { label: 'Documentation MCP', href: 'https://modelcontextprotocol.io/docs' } },
|
||||
{ icon: '⚡', text: 'Cas d\'usage : demandez à Claude Desktop d\'écrire une note dans Momento, de chercher dans vos carnets, ou de créer un agent.' },
|
||||
]}
|
||||
/>
|
||||
<McpSettingsPanel initialKeys={keys} serverStatus={serverStatus} />
|
||||
</div>
|
||||
)
|
||||
|
||||
69
memento-note/components/settings/settings-help-box.tsx
Normal file
69
memento-note/components/settings/settings-help-box.tsx
Normal file
@@ -0,0 +1,69 @@
|
||||
'use client'
|
||||
|
||||
import { useState } from 'react'
|
||||
import { HelpCircle, ChevronDown, ChevronUp, ExternalLink } from 'lucide-react'
|
||||
import { cn } from '@/lib/utils'
|
||||
|
||||
interface HelpStep {
|
||||
icon?: string
|
||||
text: string
|
||||
link?: { label: string; href: string }
|
||||
}
|
||||
|
||||
interface SettingsHelpBoxProps {
|
||||
title: string
|
||||
steps: HelpStep[]
|
||||
defaultOpen?: boolean
|
||||
className?: string
|
||||
}
|
||||
|
||||
export function SettingsHelpBox({ title, steps, defaultOpen = false, className }: SettingsHelpBoxProps) {
|
||||
const [open, setOpen] = useState(defaultOpen)
|
||||
|
||||
return (
|
||||
<div className={cn('rounded-xl border border-blue-200/60 dark:border-blue-800/30 bg-blue-50/50 dark:bg-blue-950/10 overflow-hidden', className)}>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => setOpen((v) => !v)}
|
||||
className="w-full flex items-center gap-2 px-4 py-3 text-left hover:bg-blue-100/40 dark:hover:bg-blue-900/10 transition-colors"
|
||||
>
|
||||
<HelpCircle size={14} className="text-blue-500 dark:text-blue-400 shrink-0" />
|
||||
<span className="text-[12px] font-semibold text-blue-700 dark:text-blue-300 flex-1">{title}</span>
|
||||
{open ? (
|
||||
<ChevronUp size={13} className="text-blue-400 shrink-0" />
|
||||
) : (
|
||||
<ChevronDown size={13} className="text-blue-400 shrink-0" />
|
||||
)}
|
||||
</button>
|
||||
|
||||
{open && (
|
||||
<ol className="px-4 pb-4 space-y-2">
|
||||
{steps.map((step, i) => (
|
||||
<li key={i} className="flex items-start gap-2.5">
|
||||
<span className="w-5 h-5 rounded-full bg-blue-100 dark:bg-blue-900/40 text-blue-600 dark:text-blue-300 text-[10px] font-bold flex items-center justify-center shrink-0 mt-0.5">
|
||||
{step.icon ?? i + 1}
|
||||
</span>
|
||||
<span className="text-[12px] text-blue-800 dark:text-blue-200 leading-relaxed">
|
||||
{step.text}
|
||||
{step.link && (
|
||||
<>
|
||||
{' '}
|
||||
<a
|
||||
href={step.link.href}
|
||||
target="_blank"
|
||||
rel="noopener noreferrer"
|
||||
className="inline-flex items-center gap-0.5 underline underline-offset-2 font-medium hover:text-blue-600"
|
||||
>
|
||||
{step.link.label}
|
||||
<ExternalLink size={10} />
|
||||
</a>
|
||||
</>
|
||||
)}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
)}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
Reference in New Issue
Block a user