develop #1
@@ -9,7 +9,8 @@
|
|||||||
"Bash(node:*)",
|
"Bash(node:*)",
|
||||||
"Bash(curl:*)",
|
"Bash(curl:*)",
|
||||||
"Bash(npx tsc:*)",
|
"Bash(npx tsc:*)",
|
||||||
"Bash(npm list:*)"
|
"Bash(npm list:*)",
|
||||||
|
"Bash(npx jest:*)"
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
BIN
prisma/dev.db
BIN
prisma/dev.db
Binary file not shown.
@@ -148,6 +148,11 @@ model Backlink {
|
|||||||
- Registro de origen de creación (form/quick/import)
|
- Registro de origen de creación (form/quick/import)
|
||||||
- Feature flags configurables
|
- Feature flags configurables
|
||||||
|
|
||||||
|
### Mejoras UI Recientes
|
||||||
|
- Header responsive con menú hamburguesa en móvil
|
||||||
|
- Desktop: una fila con logo, nav links, QuickAdd y botón Nueva nota
|
||||||
|
- Mobile: logo + QuickAdd + hamburguesa → dropdown con nav links y botón Nueva nota
|
||||||
|
|
||||||
## Algoritmo de Scoring
|
## Algoritmo de Scoring
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
'use client'
|
'use client'
|
||||||
|
|
||||||
|
import { useState } from 'react'
|
||||||
import Link from 'next/link'
|
import Link from 'next/link'
|
||||||
import { usePathname } from 'next/navigation'
|
import { usePathname } from 'next/navigation'
|
||||||
import { Button } from '@/components/ui/button'
|
import { Button } from '@/components/ui/button'
|
||||||
import { Plus, FileText, Settings } from 'lucide-react'
|
import { Plus, FileText, Settings, Menu, X } from 'lucide-react'
|
||||||
import { QuickAdd } from '@/components/quick-add'
|
import { QuickAdd } from '@/components/quick-add'
|
||||||
|
|
||||||
export function Header() {
|
export function Header() {
|
||||||
const pathname = usePathname()
|
const pathname = usePathname()
|
||||||
|
const [mobileMenuOpen, setMobileMenuOpen] = useState(false)
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className="sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
<header className="sticky top-0 z-40 w-full border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
|
||||||
<div className="container mx-auto px-4 flex h-14 items-center justify-between">
|
<div className="container mx-auto px-2 sm:px-4">
|
||||||
<div className="flex items-center gap-4">
|
{/* Desktop: single row */}
|
||||||
|
<div className="hidden sm:flex h-14 items-center justify-between gap-2">
|
||||||
<Link href="/" className="flex items-center gap-2">
|
<Link href="/" className="flex items-center gap-2">
|
||||||
<span className="text-xl font-bold">Recall</span>
|
<span className="text-xl font-bold">Recall</span>
|
||||||
</Link>
|
</Link>
|
||||||
@@ -38,16 +41,74 @@ export function Header() {
|
|||||||
</Button>
|
</Button>
|
||||||
</Link>
|
</Link>
|
||||||
</nav>
|
</nav>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<QuickAdd />
|
||||||
|
<Link href="/new">
|
||||||
|
<Button size="sm" className="gap-1.5">
|
||||||
|
<Plus className="h-4 w-4" />
|
||||||
|
Nueva nota
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="flex items-center gap-3">
|
|
||||||
<QuickAdd />
|
{/* Mobile: hamburger + logo */}
|
||||||
<Link href="/new">
|
<div className="flex sm:hidden h-14 items-center justify-between gap-2">
|
||||||
<Button size="sm" className="gap-1.5">
|
<Link href="/" className="flex items-center gap-2">
|
||||||
<Plus className="h-4 w-4" />
|
<span className="text-lg font-bold">Recall</span>
|
||||||
Nueva nota
|
|
||||||
</Button>
|
|
||||||
</Link>
|
</Link>
|
||||||
|
<div className="flex items-center gap-2">
|
||||||
|
<QuickAdd />
|
||||||
|
<Button
|
||||||
|
variant="ghost"
|
||||||
|
size="sm"
|
||||||
|
onClick={() => setMobileMenuOpen(!mobileMenuOpen)}
|
||||||
|
className="p-2"
|
||||||
|
>
|
||||||
|
{mobileMenuOpen ? (
|
||||||
|
<X className="h-5 w-5" />
|
||||||
|
) : (
|
||||||
|
<Menu className="h-5 w-5" />
|
||||||
|
)}
|
||||||
|
</Button>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Mobile dropdown menu */}
|
||||||
|
{mobileMenuOpen && (
|
||||||
|
<div className="sm:hidden py-3 border-t flex flex-col gap-2">
|
||||||
|
<nav className="flex flex-col gap-1">
|
||||||
|
<Link href="/notes" onClick={() => setMobileMenuOpen(false)}>
|
||||||
|
<Button
|
||||||
|
variant={pathname === '/notes' ? 'secondary' : 'ghost'}
|
||||||
|
size="sm"
|
||||||
|
className="w-full justify-start gap-2"
|
||||||
|
>
|
||||||
|
<FileText className="h-4 w-4" />
|
||||||
|
Notas
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
<Link href="/settings" onClick={() => setMobileMenuOpen(false)}>
|
||||||
|
<Button
|
||||||
|
variant={pathname === '/settings' ? 'secondary' : 'ghost'}
|
||||||
|
size="sm"
|
||||||
|
className="w-full justify-start gap-2"
|
||||||
|
>
|
||||||
|
<Settings className="h-4 w-4" />
|
||||||
|
Configuración
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</nav>
|
||||||
|
<div className="border-t pt-2">
|
||||||
|
<Link href="/new" onClick={() => setMobileMenuOpen(false)}>
|
||||||
|
<Button size="sm" className="w-full justify-start gap-2">
|
||||||
|
<Plus className="h-4 w-4" />
|
||||||
|
Nueva nota
|
||||||
|
</Button>
|
||||||
|
</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -188,8 +188,8 @@ export function QuickAdd() {
|
|||||||
onFocus={() => setIsExpanded(true)}
|
onFocus={() => setIsExpanded(true)}
|
||||||
onPaste={handlePaste}
|
onPaste={handlePaste}
|
||||||
className={cn(
|
className={cn(
|
||||||
'w-48 transition-all duration-200',
|
'w-24 xs:w-32 sm:w-48 transition-all duration-200',
|
||||||
isExpanded && 'w-72'
|
isExpanded && 'w-40 xs:w-48 sm:w-72'
|
||||||
)}
|
)}
|
||||||
disabled={isLoading}
|
disabled={isLoading}
|
||||||
/>
|
/>
|
||||||
@@ -202,29 +202,29 @@ export function QuickAdd() {
|
|||||||
type="button"
|
type="button"
|
||||||
onClick={toggleMultiline}
|
onClick={toggleMultiline}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center justify-center rounded-lg border bg-background p-2',
|
'inline-flex items-center justify-center rounded-lg border bg-background p-1.5 sm:p-2',
|
||||||
'hover:bg-accent hover:text-accent-foreground',
|
'hover:bg-accent hover:text-accent-foreground',
|
||||||
'transition-colors',
|
'transition-colors',
|
||||||
isMultiline && 'bg-accent text-accent-foreground'
|
isMultiline && 'bg-accent text-accent-foreground'
|
||||||
)}
|
)}
|
||||||
title={isMultiline ? 'Modo línea' : 'Modo multilínea'}
|
title={isMultiline ? 'Modo línea' : 'Modo multilínea'}
|
||||||
>
|
>
|
||||||
<Text className="h-4 w-4" />
|
<Text className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||||
</button>
|
</button>
|
||||||
<button
|
<button
|
||||||
type="submit"
|
type="submit"
|
||||||
disabled={!value.trim() || isLoading}
|
disabled={!value.trim() || isLoading}
|
||||||
className={cn(
|
className={cn(
|
||||||
'inline-flex items-center justify-center rounded-lg border bg-background p-2',
|
'inline-flex items-center justify-center rounded-lg border bg-background p-1.5 sm:p-2',
|
||||||
'hover:bg-accent hover:text-accent-foreground',
|
'hover:bg-accent hover:text-accent-foreground',
|
||||||
'disabled:pointer-events-none disabled:opacity-50',
|
'disabled:pointer-events-none disabled:opacity-50',
|
||||||
'transition-colors'
|
'transition-colors'
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
{isLoading ? (
|
{isLoading ? (
|
||||||
<Loader2 className="h-4 w-4 animate-spin" />
|
<Loader2 className="h-3 w-3 sm:h-4 sm:w-4 animate-spin" />
|
||||||
) : (
|
) : (
|
||||||
<Plus className="h-4 w-4" />
|
<Plus className="h-3 w-3 sm:h-4 sm:w-4" />
|
||||||
)}
|
)}
|
||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
|
|||||||
Reference in New Issue
Block a user