feat: forecast swipe nav, note swipe-to-delete, night-shift tint
All checks were successful
Deploy / deploy (push) Successful in 2m45s
All checks were successful
Deploy / deploy (push) Successful in 2m45s
- WeatherDayModal now accepts the full forecast array and an onChange callback; supports horizontal drag (framer-motion) plus prev/next chevrons and a dot-indicator. Drag > 60px switches day; style uses semantic tokens (shadow-xl, surface-1). - NotesTab list items wrap each note in a motion.button with drag=x, constrained to -80px. Below it a gradient+trash reveal layer. Drag past 60px opens the existing confirmDelete modal. - HomePageInner adds a night-shift overlay (fixed, mixBlendMode multiply, rgba(255,120,40,0.12)) active 22:00-06:00, auto-checked each minute, fades in/out over 800ms. No user toggle yet — fully automatic.
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
'use client'
|
||||
import { useState, useEffect, useCallback } from 'react'
|
||||
import { motion } from 'framer-motion'
|
||||
import { Plus, X, Trash2, ShoppingCart, FileText, Check, Circle, Calendar as CalendarIcon } from 'lucide-react'
|
||||
|
||||
interface NoteItem {
|
||||
@@ -144,12 +145,37 @@ export default function NotesTab() {
|
||||
const doneCount = note.items?.filter(i => i.done).length || 0
|
||||
const totalCount = note.items?.length || 0
|
||||
return (
|
||||
<button key={note.id} onClick={() => setActiveNote(note)} style={{
|
||||
padding: '14px 16px', borderRadius: 16, textAlign: 'left', width: '100%',
|
||||
background: isActive ? `${note.color}15` : 'rgba(255,255,255,0.025)',
|
||||
border: `1px solid ${isActive ? note.color + '30' : 'rgba(255,255,255,0.05)'}`,
|
||||
transition: 'all 0.2s ease',
|
||||
}}>
|
||||
<motion.div
|
||||
key={note.id}
|
||||
layout
|
||||
style={{ position: 'relative', borderRadius: 16, overflow: 'hidden' }}
|
||||
>
|
||||
{/* Delete reveal layer */}
|
||||
<div style={{
|
||||
position: 'absolute', inset: 0,
|
||||
display: 'flex', alignItems: 'center', justifyContent: 'flex-end',
|
||||
padding: '0 20px', borderRadius: 16,
|
||||
background: 'linear-gradient(90deg, transparent 30%, rgba(239,68,68,0.25))',
|
||||
pointerEvents: 'none',
|
||||
}}>
|
||||
<Trash2 size={18} color="#f87171" />
|
||||
</div>
|
||||
<motion.button
|
||||
drag="x"
|
||||
dragConstraints={{ left: -80, right: 0 }}
|
||||
dragElastic={0.1}
|
||||
onDragEnd={(_, info) => {
|
||||
if (info.offset.x < -60) setConfirmDelete(note)
|
||||
}}
|
||||
onClick={() => setActiveNote(note)}
|
||||
style={{
|
||||
padding: '14px 16px', borderRadius: 16, textAlign: 'left', width: '100%',
|
||||
background: isActive ? `${note.color}15` : 'var(--surface-2)',
|
||||
border: `1px solid ${isActive ? note.color + '30' : 'var(--border-subtle)'}`,
|
||||
transition: 'background 0.2s ease, border-color 0.2s ease',
|
||||
position: 'relative', zIndex: 1,
|
||||
touchAction: 'pan-y',
|
||||
}}>
|
||||
<div style={{ display: 'flex', alignItems: 'center', gap: 8, marginBottom: 6 }}>
|
||||
{note.type === 'shopping'
|
||||
? <ShoppingCart size={14} color={note.color} />
|
||||
@@ -185,7 +211,8 @@ export default function NotesTab() {
|
||||
{note.text}
|
||||
</div>
|
||||
)}
|
||||
</button>
|
||||
</motion.button>
|
||||
</motion.div>
|
||||
)
|
||||
})}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user