feat(ui): panneau repliable, carnets plus lisibles et accueil plus clair
Harmonise la liste des notes et l’éditeur (titres, dates, retour), rend la saisie rapide et les raccourcis de l’accueil utilisables sur téléphone, et conserve le panneau latéral repliable.
This commit is contained in:
@@ -1,7 +1,8 @@
|
||||
'use client'
|
||||
|
||||
import { useState, useRef, useCallback, useEffect } from 'react'
|
||||
import { useSearchParams } from 'next/navigation'
|
||||
import { usePathname, useSearchParams } from 'next/navigation'
|
||||
import { editorBackLabelKey, resolveEditorBackKind } from '@/lib/editor/editor-back-context'
|
||||
import { useNoteEditorContext } from './note-editor-context'
|
||||
import { LabelManager } from '@/components/label-manager'
|
||||
import { LabelBadge } from '@/components/label-badge'
|
||||
@@ -34,7 +35,6 @@ import { NOTE_COLORS, NoteColor, Note } from '@/lib/types'
|
||||
import { cn } from '@/lib/utils'
|
||||
import { useVoiceTranscription } from '@/hooks/use-voice-transcription'
|
||||
import { toast } from 'sonner'
|
||||
import { format } from 'date-fns'
|
||||
import { tiptapHTMLToMarkdown, markdownToHTML, extractMarkdownTitle } from '@/lib/editor/markdown-export'
|
||||
import { getCalloutColors } from '@/lib/editor/callout-colors'
|
||||
import { copyTextToClipboard } from '@/lib/editor/copy-text-to-clipboard'
|
||||
@@ -52,7 +52,9 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
const { state, actions, note, readOnly, fullPage, notebooks, fileInputRef, richTextEditorRef } = useNoteEditorContext()
|
||||
const { t, language } = useLanguage()
|
||||
const searchParams = useSearchParams()
|
||||
const fromDashboard = searchParams.get('from') === 'dashboard' || Boolean(searchParams.get('peekNote'))
|
||||
const pathname = usePathname()
|
||||
const backKind = resolveEditorBackKind(pathname, searchParams)
|
||||
const backLabel = t(editorBackLabelKey(backKind))
|
||||
const { requestAiConsent } = useAiConsent()
|
||||
const [isConverting, setIsConverting] = useState(false)
|
||||
const [shareOpen, setShareOpen] = useState(false)
|
||||
@@ -562,32 +564,40 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
|
||||
if (mode === 'fullPage') {
|
||||
const handleCloseWithSave = async () => {
|
||||
if (state.isDirty && !state.isSaving) {
|
||||
await actions.handleSaveInPlace()
|
||||
if (state.isSaving) return
|
||||
if (state.isDirty) {
|
||||
const saved = await actions.handleSaveInPlace()
|
||||
if (!saved) return
|
||||
}
|
||||
onClose()
|
||||
}
|
||||
|
||||
return (
|
||||
<div className="max-w-5xl mx-auto w-full px-4 sm:px-8 md:px-12 py-4 sm:py-6 md:py-8 flex items-center justify-between sticky top-0 bg-white/95 dark:bg-background/95 backdrop-blur-sm z-40 border-b border-border dark:border-white/10">
|
||||
<div className="max-w-5xl mx-auto w-full px-3 sm:px-8 md:px-12 py-3 sm:py-6 md:py-8 flex items-center justify-between gap-2 sticky top-0 bg-white/95 dark:bg-background/95 backdrop-blur-sm z-40 border-b border-border dark:border-white/10">
|
||||
<button
|
||||
type="button"
|
||||
onClick={handleCloseWithSave}
|
||||
className="flex items-center gap-2 text-foreground hover:opacity-60 transition-opacity"
|
||||
title={backLabel}
|
||||
aria-label={backLabel}
|
||||
className="flex h-11 min-w-11 shrink-0 items-center gap-2 px-1.5 md:px-0 text-foreground hover:opacity-60 transition-opacity rounded-md focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-brand-accent"
|
||||
>
|
||||
<ArrowLeft size={18} />
|
||||
<span className="text-sm font-medium">
|
||||
{fromDashboard ? t('notes.backToDashboard') : t('notes.backToCollection')}
|
||||
</span>
|
||||
<ArrowLeft size={18} className="rtl:rotate-180 shrink-0" />
|
||||
<span className="hidden md:inline text-sm font-medium whitespace-nowrap">{backLabel}</span>
|
||||
<span className="md:hidden text-sm font-medium whitespace-nowrap">{t('general.back')}</span>
|
||||
</button>
|
||||
|
||||
<div className="flex items-center gap-1.5 sm:gap-2">
|
||||
<div className="flex items-center gap-1 sm:gap-1.5 md:gap-2 min-w-0">
|
||||
{/* 1. Status */}
|
||||
<span className="hidden sm:flex items-center gap-1.5 text-[11px] text-foreground/40 select-none me-1">
|
||||
<span
|
||||
className="flex items-center gap-1.5 text-[11px] text-foreground/40 select-none me-1 min-h-11 md:min-h-0"
|
||||
title={state.isSaving ? t('notes.saving') : state.isDirty ? t('notes.dirtyStatus') : t('notes.savedStatus')}
|
||||
aria-label={state.isSaving ? t('notes.saving') : state.isDirty ? t('notes.dirtyStatus') : t('notes.savedStatus')}
|
||||
>
|
||||
{state.isSaving
|
||||
? <><Loader2 className="h-3 w-3 animate-spin" /><span>{t('notes.saving')}</span></>
|
||||
? <><Loader2 className="h-3 w-3 animate-spin" /><span className="hidden sm:inline">{t('notes.saving')}</span></>
|
||||
: state.isDirty
|
||||
? <><span className="h-1.5 w-1.5 rounded-full bg-amber-400 inline-block" /><span>{t('notes.dirtyStatus')}</span></>
|
||||
: <><Check className="h-3 w-3 text-emerald-500" /><span>{t('notes.savedStatus')}</span></>}
|
||||
? <><span className="h-1.5 w-1.5 rounded-full bg-amber-400 inline-block" /><span className="hidden sm:inline">{t('notes.dirtyStatus')}</span></>
|
||||
: <><Check className="h-3 w-3 text-emerald-500" /><span className="hidden sm:inline">{t('notes.savedStatus')}</span></>}
|
||||
</span>
|
||||
|
||||
{note.historyEnabled && (
|
||||
@@ -607,7 +617,7 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
onClick={() => actions.handleSaveInPlace()}
|
||||
disabled={state.isSaving || !state.isDirty}
|
||||
className={cn(
|
||||
'p-1.5 rounded-full border transition-all duration-300',
|
||||
'flex h-11 w-11 shrink-0 items-center justify-center rounded-full border transition-all duration-300 md:h-auto md:w-auto md:p-1.5',
|
||||
state.isDirty
|
||||
? 'bg-foreground text-background border-foreground hover:opacity-80'
|
||||
: 'border-black/20 dark:border-white/20 text-foreground/40 cursor-not-allowed'
|
||||
@@ -626,7 +636,7 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
title={t('richTextEditor.publishTitle')}
|
||||
aria-label={t('richTextEditor.publishTitle')}
|
||||
className={cn(
|
||||
'p-1.5 rounded-full border transition-all',
|
||||
'flex h-11 w-11 shrink-0 items-center justify-center rounded-full border transition-all md:h-auto md:w-auto md:p-1.5',
|
||||
publishMeta.isPublic
|
||||
? 'border-green-400/40 text-green-600 dark:text-green-400 bg-green-50 dark:bg-green-950/20'
|
||||
: 'border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5',
|
||||
@@ -834,7 +844,7 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
title={t('notes.shareNoteTitle')}
|
||||
aria-label={t('notes.shareNoteAria')}
|
||||
onClick={() => setShareOpen(true)}
|
||||
className="p-1.5 rounded-full border border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5 transition-all"
|
||||
className="hidden min-[360px]:flex h-11 w-11 shrink-0 items-center justify-center rounded-full border border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5 transition-all md:h-auto md:w-auto md:p-1.5"
|
||||
>
|
||||
<Share2 size={16} />
|
||||
</button>
|
||||
@@ -846,7 +856,7 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
aria-label={t('ai.openAssistant')}
|
||||
onClick={() => { actions.setAiOpen(!state.aiOpen); actions.setInfoOpen(false) }}
|
||||
className={cn(
|
||||
'p-1.5 rounded-full border transition-all duration-300',
|
||||
'flex h-11 w-11 shrink-0 items-center justify-center rounded-full border transition-all duration-300 md:h-auto md:w-auto md:p-1.5',
|
||||
state.aiOpen
|
||||
? 'bg-foreground text-background border-foreground'
|
||||
: 'border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5'
|
||||
@@ -866,19 +876,19 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
if (!seed.trim()) return
|
||||
window.open(`/brainstorm?seed=${encodeURIComponent(seed.slice(0, 300))}&sourceNoteId=${note.id}`, '_self')
|
||||
}}
|
||||
className="p-1.5 rounded-full border border-brand-accent/30 dark:border-brand-accent/50 text-brand-accent hover:bg-brand-accent/10 dark:hover:bg-brand-accent/20 transition-all"
|
||||
className="hidden md:flex h-11 w-11 shrink-0 items-center justify-center rounded-full border border-brand-accent/30 dark:border-brand-accent/50 text-brand-accent hover:bg-brand-accent/10 dark:hover:bg-brand-accent/20 transition-all md:h-auto md:w-auto md:p-1.5"
|
||||
>
|
||||
<Wind size={16} />
|
||||
</button>
|
||||
|
||||
{/* 7. Education (flashcards / exercises) */}
|
||||
{!readOnly && (
|
||||
<div className="relative">
|
||||
<div className="relative hidden md:block">
|
||||
<button
|
||||
title={t('flashcards.toolbarGenerate')}
|
||||
aria-label={t('flashcards.toolbarGenerate')}
|
||||
onClick={() => setShowEduMenu(v => !v)}
|
||||
className="p-1.5 rounded-full border border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5 transition-all"
|
||||
className="flex h-11 w-11 shrink-0 items-center justify-center rounded-full border border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5 transition-all md:h-auto md:w-auto md:p-1.5"
|
||||
>
|
||||
<GraduationCap size={16} />
|
||||
</button>
|
||||
@@ -926,7 +936,7 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
aria-label={voiceState === 'listening' ? (t('richTextEditor.stopVoice') || 'Stop voice') : (t('richTextEditor.startVoice') || 'Start voice')}
|
||||
onClick={toggleVoice}
|
||||
className={cn(
|
||||
'p-1.5 rounded-full border transition-all',
|
||||
'hidden md:flex h-11 w-11 shrink-0 items-center justify-center rounded-full border transition-all md:h-auto md:w-auto md:p-1.5',
|
||||
voiceState === 'listening'
|
||||
? 'border-red-400 bg-red-50 dark:bg-red-950/30 text-red-500 animate-pulse'
|
||||
: 'border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5',
|
||||
@@ -941,7 +951,7 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
title={t('notes.attachments') || 'Attachments'}
|
||||
aria-label={t('notes.attachments') || 'Attachments'}
|
||||
onClick={onToggleAttachments}
|
||||
className="relative p-1.5 rounded-full border border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5 transition-all"
|
||||
className="relative hidden md:flex h-11 w-11 shrink-0 items-center justify-center rounded-full border border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5 transition-all md:h-auto md:w-auto md:p-1.5"
|
||||
>
|
||||
<Paperclip size={16} />
|
||||
{(attachmentsCount ?? 0) > 0 && (
|
||||
@@ -958,7 +968,7 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
aria-label={state.showMarkdownPreview ? t('notes.markdownEditingTitle') : t('notes.markdownPreviewTitle')}
|
||||
onClick={() => actions.setShowMarkdownPreview(!state.showMarkdownPreview)}
|
||||
className={cn(
|
||||
'p-1.5 rounded-full border transition-all duration-300',
|
||||
'hidden md:flex h-11 w-11 shrink-0 items-center justify-center rounded-full border transition-all duration-300 md:h-auto md:w-auto md:p-1.5',
|
||||
state.showMarkdownPreview
|
||||
? 'bg-foreground text-background border-foreground'
|
||||
: 'border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5'
|
||||
@@ -975,7 +985,7 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
onClick={handleConvertToRichtext}
|
||||
disabled={isConverting}
|
||||
className={cn(
|
||||
'p-1.5 rounded-full border transition-all duration-300',
|
||||
'hidden md:flex h-11 w-11 shrink-0 items-center justify-center rounded-full border transition-all duration-300 md:h-auto md:w-auto md:p-1.5',
|
||||
'border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5',
|
||||
isConverting && 'opacity-50 cursor-not-allowed'
|
||||
)}
|
||||
@@ -984,53 +994,123 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
</button>
|
||||
)}
|
||||
|
||||
{/* 9. Overflow menu */}
|
||||
{!readOnly && (
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button aria-label={t('notes.optionsMenuAria')} className="p-1.5 rounded-full border border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5 transition-all">
|
||||
<MoreHorizontal size={16} />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-52">
|
||||
<DropdownMenuItem onClick={handleExportMarkdown}>
|
||||
<FileDown className="h-4 w-4 me-2" />
|
||||
{t('richTextEditor.exportMarkdown')}
|
||||
{/* 9. Overflow menu — always on mobile (secondary actions), desktop when editable */}
|
||||
<DropdownMenu>
|
||||
<DropdownMenuTrigger asChild>
|
||||
<button
|
||||
type="button"
|
||||
aria-label={t('notes.optionsMenuAria')}
|
||||
className={cn(
|
||||
'flex h-11 w-11 shrink-0 items-center justify-center rounded-full border border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5 transition-all md:h-auto md:w-auto md:p-1.5',
|
||||
readOnly && 'md:hidden',
|
||||
)}
|
||||
>
|
||||
<MoreHorizontal size={16} />
|
||||
</button>
|
||||
</DropdownMenuTrigger>
|
||||
<DropdownMenuContent align="end" className="w-56">
|
||||
{!readOnly && (
|
||||
<DropdownMenuItem className="min-[360px]:hidden" onClick={() => setShareOpen(true)}>
|
||||
<Share2 className="h-4 w-4 me-2" />
|
||||
{t('notes.shareNoteTitle')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={handleExportPdf}>
|
||||
<Printer className="h-4 w-4 me-2" />
|
||||
{t('richTextEditor.exportPdf') || 'Exporter en PDF'}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={openMarkdownImport}>
|
||||
<FileUp className="h-4 w-4 me-2" />
|
||||
{t('richTextEditor.importMarkdown')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={actions.toggleAutoSave} className="flex items-center justify-between cursor-pointer">
|
||||
<span className="flex items-center">
|
||||
<Save className="h-4 w-4 me-2 text-muted-foreground" />
|
||||
{t('settings.autoSave') || 'Auto-enregistrement'}
|
||||
</span>
|
||||
<span className={cn(
|
||||
'text-[10px] px-1.5 py-0.5 rounded font-bold uppercase tracking-wider',
|
||||
state.autoSaveEnabled
|
||||
? 'bg-emerald-100 text-emerald-800 dark:bg-emerald-950/40 dark:text-emerald-400'
|
||||
: 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400'
|
||||
)}>
|
||||
{state.autoSaveEnabled ? (t('common.on') || 'Actif') : (t('common.off') || 'Désactivé')}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
onClick={() => setConfirmDeleteOpen(true)}
|
||||
className="text-red-600 dark:text-red-400 focus:text-red-600"
|
||||
>
|
||||
<Trash2 className="h-4 w-4 me-2" />
|
||||
{t('notes.deleteNoteConfirmItem')}
|
||||
</DropdownMenuItem>
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
)}
|
||||
)}
|
||||
<DropdownMenuItem
|
||||
className="md:hidden"
|
||||
onClick={() => { actions.setInfoOpen(!state.infoOpen); actions.setAiOpen(false) }}
|
||||
>
|
||||
<PanelRight className="h-4 w-4 me-2" />
|
||||
{t('notes.documentInfoAria')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem
|
||||
className="md:hidden"
|
||||
onClick={() => {
|
||||
const title = note.title || ''
|
||||
const summary = state.content?.replace(/<[^>]*>/g, '').slice(0, 200) || ''
|
||||
const seed = title ? `${title}. ${summary}` : summary
|
||||
if (!seed.trim()) return
|
||||
window.open(`/brainstorm?seed=${encodeURIComponent(seed.slice(0, 300))}&sourceNoteId=${note.id}`, '_self')
|
||||
}}
|
||||
>
|
||||
<Wind className="h-4 w-4 me-2" />
|
||||
{t('notes.brainstormThisIdea')}
|
||||
</DropdownMenuItem>
|
||||
{!readOnly && (
|
||||
<>
|
||||
<DropdownMenuItem className="md:hidden" onClick={() => setFlashcardsOpen(true)}>
|
||||
<GraduationCap className="h-4 w-4 me-2" />
|
||||
{t('flashcards.toolbarGenerate')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="md:hidden" onClick={() => void handleGenerateExercises()}>
|
||||
<PenTool className="h-4 w-4 me-2" />
|
||||
{t('richTextEditor.generateExercises') || 'Générer des exercices'}
|
||||
</DropdownMenuItem>
|
||||
{voiceSupported && (
|
||||
<DropdownMenuItem className="md:hidden" onClick={toggleVoice}>
|
||||
{voiceState === 'listening' ? <MicOff className="h-4 w-4 me-2" /> : <Mic className="h-4 w-4 me-2" />}
|
||||
{voiceState === 'listening'
|
||||
? (t('editor.voiceStop') || 'Arrêter la dictée')
|
||||
: (t('editor.voiceStart') || 'Dicter du texte')}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{onToggleAttachments && (
|
||||
<DropdownMenuItem className="md:hidden" onClick={onToggleAttachments}>
|
||||
<Paperclip className="h-4 w-4 me-2" />
|
||||
{t('notes.attachments') || 'Attachments'}
|
||||
</DropdownMenuItem>
|
||||
)}
|
||||
{state.isMarkdown && (
|
||||
<>
|
||||
<DropdownMenuItem className="md:hidden" onClick={() => actions.setShowMarkdownPreview(!state.showMarkdownPreview)}>
|
||||
<Eye className="h-4 w-4 me-2" />
|
||||
{state.showMarkdownPreview ? t('notes.markdownEditingTitle') : t('notes.markdownPreviewTitle')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem className="md:hidden" onClick={() => void handleConvertToRichtext()}>
|
||||
<Wand2 className="h-4 w-4 me-2" />
|
||||
{t('ai.convertToRichtext') || 'Convert to Rich Text'}
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
)}
|
||||
<DropdownMenuSeparator className="md:hidden" />
|
||||
<DropdownMenuItem onClick={handleExportMarkdown}>
|
||||
<FileDown className="h-4 w-4 me-2" />
|
||||
{t('richTextEditor.exportMarkdown')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={handleExportPdf}>
|
||||
<Printer className="h-4 w-4 me-2" />
|
||||
{t('richTextEditor.exportPdf') || 'Exporter en PDF'}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={openMarkdownImport}>
|
||||
<FileUp className="h-4 w-4 me-2" />
|
||||
{t('richTextEditor.importMarkdown')}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem onClick={actions.toggleAutoSave} className="flex items-center justify-between cursor-pointer">
|
||||
<span className="flex items-center">
|
||||
<Save className="h-4 w-4 me-2 text-muted-foreground" />
|
||||
{t('settings.autoSave') || 'Auto-enregistrement'}
|
||||
</span>
|
||||
<span className={cn(
|
||||
'text-[10px] px-1.5 py-0.5 rounded font-bold uppercase tracking-wider',
|
||||
state.autoSaveEnabled
|
||||
? 'bg-emerald-100 text-emerald-800 dark:bg-emerald-950/40 dark:text-emerald-400'
|
||||
: 'bg-zinc-100 text-zinc-600 dark:bg-zinc-800 dark:text-zinc-400'
|
||||
)}>
|
||||
{state.autoSaveEnabled ? (t('common.on') || 'Actif') : (t('common.off') || 'Désactivé')}
|
||||
</span>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuSeparator />
|
||||
<DropdownMenuItem
|
||||
onClick={() => setConfirmDeleteOpen(true)}
|
||||
className="text-red-600 dark:text-red-400 focus:text-red-600"
|
||||
>
|
||||
<Trash2 className="h-4 w-4 me-2" />
|
||||
{t('notes.deleteNoteConfirmItem')}
|
||||
</DropdownMenuItem>
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuContent>
|
||||
</DropdownMenu>
|
||||
|
||||
<ConfirmDeleteNoteDialog
|
||||
open={confirmDeleteOpen}
|
||||
@@ -1091,7 +1171,7 @@ export function NoteEditorToolbar({ mode, onClose, onToggleAttachments, attachme
|
||||
aria-label={t('notes.documentInfoAria')}
|
||||
onClick={() => { actions.setInfoOpen(!state.infoOpen); actions.setAiOpen(false) }}
|
||||
className={cn(
|
||||
'p-1.5 rounded-full border transition-all duration-300',
|
||||
'hidden md:flex h-11 w-11 shrink-0 items-center justify-center rounded-full border transition-all duration-300 md:h-auto md:w-auto md:p-1.5',
|
||||
state.infoOpen
|
||||
? 'bg-foreground text-background border-foreground'
|
||||
: 'border-black/20 dark:border-white/20 text-foreground hover:bg-black/5 dark:hover:bg-white/5'
|
||||
|
||||
Reference in New Issue
Block a user