Add UI polish: animations, mobile responsiveness, and visual enhancements

- Update daily quotes to 36 curated motivational quotes from notable figures
- Add entrance animations (fade-in, slide-in, scale-in) with staggered delays
- Add hover effects on cards and buttons with smooth transitions
- Improve mobile responsiveness: stacking layouts, responsive text, touch targets
- Enhance glassmorphism with stronger blur and gradient orbs on cards
- Add gradient logo for QuitTraq branding
- Improve quote section with decorative elements and inner glow
- Refine streak celebrations and weekly target indicators
- Update background with multiple color gradient spots

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Avery Felts 2026-01-24 11:18:38 -07:00
parent fac443c281
commit 45bcad9788
8 changed files with 424 additions and 136 deletions

View File

@ -174,10 +174,11 @@
font-family: var(--font-sans);
letter-spacing: var(--tracking-normal);
background: linear-gradient(135deg,
#1a1a2e 0%,
#16213e 25%,
#1a1a2e 50%,
#0f0f1a 75%,
#0f0f1a 0%,
#1a1a2e 20%,
#16213e 40%,
#1a1a2e 60%,
#0f0f1a 80%,
#1a1a2e 100%);
background-attachment: fixed;
min-height: 100vh;
@ -191,9 +192,11 @@
right: 0;
bottom: 0;
background:
radial-gradient(ellipse at 20% 20%, rgba(120, 119, 198, 0.15) 0%, transparent 50%),
radial-gradient(ellipse at 80% 80%, rgba(74, 85, 104, 0.2) 0%, transparent 50%),
radial-gradient(ellipse at 40% 60%, rgba(45, 55, 72, 0.15) 0%, transparent 40%);
radial-gradient(ellipse at 15% 10%, rgba(99, 102, 241, 0.15) 0%, transparent 40%),
radial-gradient(ellipse at 85% 20%, rgba(168, 85, 247, 0.12) 0%, transparent 35%),
radial-gradient(ellipse at 50% 50%, rgba(45, 55, 72, 0.1) 0%, transparent 50%),
radial-gradient(ellipse at 20% 80%, rgba(34, 197, 94, 0.08) 0%, transparent 40%),
radial-gradient(ellipse at 80% 85%, rgba(239, 68, 68, 0.08) 0%, transparent 35%);
pointer-events: none;
z-index: -1;
}
@ -202,4 +205,257 @@
.rdp {
--rdp-cell-size: 36px;
}
/* Mobile calendar adjustments */
@media (max-width: 640px) {
.rdp {
--rdp-cell-size: 32px;
font-size: 0.875rem;
}
}
}
/* Animation keyframes */
@keyframes fade-in {
from { opacity: 0; }
to { opacity: 1; }
}
@keyframes fade-in-up {
from {
opacity: 0;
transform: translateY(20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes fade-in-down {
from {
opacity: 0;
transform: translateY(-20px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
@keyframes scale-in {
from {
opacity: 0;
transform: scale(0.95);
}
to {
opacity: 1;
transform: scale(1);
}
}
@keyframes slide-in-right {
from {
opacity: 0;
transform: translateX(20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes slide-in-left {
from {
opacity: 0;
transform: translateX(-20px);
}
to {
opacity: 1;
transform: translateX(0);
}
}
@keyframes pulse-subtle {
0%, 100% { opacity: 1; }
50% { opacity: 0.7; }
}
@keyframes float {
0%, 100% { transform: translateY(0); }
50% { transform: translateY(-5px); }
}
@keyframes shimmer {
0% { background-position: -200% 0; }
100% { background-position: 200% 0; }
}
@keyframes glow {
0%, 100% { box-shadow: 0 0 5px rgba(99, 102, 241, 0.5); }
50% { box-shadow: 0 0 20px rgba(99, 102, 241, 0.8); }
}
/* Animation utility classes */
.animate-fade-in {
animation: fade-in 0.5s ease-out forwards;
}
.animate-fade-in-up {
animation: fade-in-up 0.5s ease-out forwards;
}
.animate-fade-in-down {
animation: fade-in-down 0.5s ease-out forwards;
}
.animate-scale-in {
animation: scale-in 0.4s ease-out forwards;
}
.animate-slide-in-right {
animation: slide-in-right 0.5s ease-out forwards;
}
.animate-slide-in-left {
animation: slide-in-left 0.5s ease-out forwards;
}
.animate-pulse-subtle {
animation: pulse-subtle 2s ease-in-out infinite;
}
.animate-float {
animation: float 3s ease-in-out infinite;
}
.animate-glow {
animation: glow 2s ease-in-out infinite;
}
/* Stagger delay utilities */
.delay-100 { animation-delay: 100ms; }
.delay-200 { animation-delay: 200ms; }
.delay-300 { animation-delay: 300ms; }
.delay-400 { animation-delay: 400ms; }
.delay-500 { animation-delay: 500ms; }
/* Start hidden for animations */
.opacity-0 { opacity: 0; }
/* Smooth transitions */
.transition-smooth {
transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
}
/* Interactive hover effects */
.hover-lift {
transition: transform 0.2s ease, box-shadow 0.2s ease;
}
.hover-lift:hover {
transform: translateY(-2px);
box-shadow: 0 10px 25px -5px rgba(0, 0, 0, 0.3);
}
.hover-scale {
transition: transform 0.2s ease;
}
.hover-scale:hover {
transform: scale(1.02);
}
.hover-glow {
transition: box-shadow 0.3s ease;
}
.hover-glow:hover {
box-shadow: 0 0 20px rgba(99, 102, 241, 0.4);
}
/* Glassmorphism effect */
.glass {
background: rgba(255, 255, 255, 0.05);
backdrop-filter: blur(10px);
border: 1px solid rgba(255, 255, 255, 0.1);
}
.glass-strong {
background: rgba(255, 255, 255, 0.1);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.15);
}
/* Premium card effect */
.card-premium {
background: linear-gradient(135deg, rgba(255, 255, 255, 0.1) 0%, rgba(255, 255, 255, 0.05) 100%);
backdrop-filter: blur(20px);
border: 1px solid rgba(255, 255, 255, 0.18);
box-shadow:
0 8px 32px rgba(0, 0, 0, 0.1),
inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
/* Gradient text */
.gradient-text {
background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.gradient-text-warm {
background: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
/* Subtle inner glow for cards */
.inner-glow {
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.1);
}
/* Text shadow for better readability */
.text-shadow {
text-shadow: 0 2px 4px rgba(0, 0, 0, 0.3);
}
.text-shadow-sm {
text-shadow: 0 1px 2px rgba(0, 0, 0, 0.2);
}
/* Gradient borders */
.gradient-border {
position: relative;
}
.gradient-border::before {
content: '';
position: absolute;
inset: 0;
border-radius: inherit;
padding: 1px;
background: linear-gradient(135deg, rgba(99, 102, 241, 0.5), rgba(168, 85, 247, 0.5));
-webkit-mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
mask: linear-gradient(#fff 0 0) content-box, linear-gradient(#fff 0 0);
-webkit-mask-composite: xor;
mask-composite: exclude;
pointer-events: none;
}
/* Noise texture overlay for depth */
.noise-overlay {
position: relative;
}
.noise-overlay::after {
content: '';
position: absolute;
inset: 0;
background-image: url("data:image/svg+xml,%3Csvg viewBox='0 0 256 256' xmlns='http://www.w3.org/2000/svg'%3E%3Cfilter id='noiseFilter'%3E%3CfeTurbulence type='fractalNoise' baseFrequency='0.9' numOctaves='4' stitchTiles='stitch'/%3E%3C/filter%3E%3Crect width='100%25' height='100%25' filter='url(%23noiseFilter)'/%3E%3C/svg%3E");
opacity: 0.03;
pointer-events: none;
border-radius: inherit;
}

View File

@ -137,35 +137,43 @@ export function Dashboard({ user }: DashboardProps) {
{preferences && (
<>
{/* Floating Log Button */}
<div className="fixed bottom-6 right-6 z-50">
<div className="fixed bottom-4 right-4 sm:bottom-6 sm:right-6 z-50 opacity-0 animate-scale-in delay-500">
<Button
size="lg"
onClick={() => setShowUsagePrompt(true)}
className="h-16 px-8 text-lg rounded-full shadow-xl bg-gradient-to-r from-primary to-primary/80 hover:from-primary/90 hover:to-primary/70 drop-shadow-lg"
className="h-14 px-6 sm:h-16 sm:px-8 text-base sm:text-lg rounded-full shadow-xl bg-gradient-to-r from-primary to-primary/80 hover:from-primary/90 hover:to-primary/70 drop-shadow-lg hover-lift transition-all duration-300 hover:scale-105 active:scale-95"
>
<PlusCircle className="mr-2 h-6 w-6" />
<PlusCircle className="mr-2 h-5 w-5 sm:h-6 sm:w-6" />
Log Usage
</Button>
</div>
<div className="grid gap-6 md:grid-cols-2">
<div className="space-y-6">
<UsageCalendar
key={refreshKey}
usageData={usageData}
onDataUpdate={loadData}
userId={user.id}
/>
<QuitPlanCard
key={`quit-plan-${refreshKey}`}
plan={preferences.quitPlan}
onGeneratePlan={handleGeneratePlan}
usageData={usageData}
/>
<div className="opacity-0 animate-fade-in-up">
<UsageCalendar
key={refreshKey}
usageData={usageData}
onDataUpdate={loadData}
userId={user.id}
/>
</div>
<div className="opacity-0 animate-fade-in-up delay-200">
<QuitPlanCard
key={`quit-plan-${refreshKey}`}
plan={preferences.quitPlan}
onGeneratePlan={handleGeneratePlan}
usageData={usageData}
/>
</div>
</div>
<div className="space-y-6">
<StatsCard key={`stats-nicotine-${refreshKey}`} usageData={usageData} substance="nicotine" />
<StatsCard key={`stats-weed-${refreshKey}`} usageData={usageData} substance="weed" />
<div className="opacity-0 animate-slide-in-right delay-100">
<StatsCard key={`stats-nicotine-${refreshKey}`} usageData={usageData} substance="nicotine" />
</div>
<div className="opacity-0 animate-slide-in-right delay-300">
<StatsCard key={`stats-weed-${refreshKey}`} usageData={usageData} substance="weed" />
</div>
</div>
</div>
</>

View File

@ -40,11 +40,12 @@ export function QuitPlanCard({
if (!plan) {
return (
<Card className="backdrop-blur-sm shadow-lg drop-shadow-md border-yellow-500/30" style={{
<Card className="backdrop-blur-xl shadow-xl drop-shadow-lg border-yellow-500/40 hover-lift transition-all duration-300 overflow-hidden relative" style={{
background: yellowBackground
}}>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-white">
<div className="absolute top-0 right-0 w-40 h-40 bg-gradient-to-br from-yellow-500/10 to-transparent rounded-full -translate-y-1/2 translate-x-1/2 pointer-events-none" />
<CardHeader className="relative z-10">
<CardTitle className="flex items-center gap-2 text-white text-shadow-sm">
<Target className="h-5 w-5 text-yellow-400" />
Your Personalized Plan
</CardTitle>
@ -52,17 +53,17 @@ export function QuitPlanCard({
We&apos;re tracking your usage to build your custom quit plan
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="bg-yellow-500/20 border border-yellow-500/30 p-4 rounded-lg">
<CardContent className="space-y-4 relative z-10">
<div className="bg-yellow-500/20 border border-yellow-500/30 p-4 rounded-xl backdrop-blur-sm">
<div className="flex justify-between items-center mb-3">
<span className="text-sm font-medium text-white">Tracking Progress</span>
<span className="text-sm text-yellow-300 font-bold">
{daysRemaining > 0 ? `${daysRemaining} days left` : 'Ready!'}
</span>
</div>
<div className="w-full bg-white/10 rounded-full h-3">
<div className="w-full bg-white/10 rounded-full h-3 overflow-hidden">
<div
className="bg-gradient-to-r from-yellow-400 to-yellow-500 h-3 rounded-full transition-all"
className="bg-gradient-to-r from-yellow-400 to-yellow-500 h-3 rounded-full transition-all duration-700 ease-out"
style={{ width: `${Math.min(100, (uniqueDaysWithData / 7) * 100)}%` }}
/>
</div>
@ -77,7 +78,7 @@ export function QuitPlanCard({
Great work! Your average daily usage is{' '}
<strong className="text-yellow-300">{currentAverage}</strong> per day.
</p>
<Button onClick={onGeneratePlan} className="w-full bg-yellow-500 hover:bg-yellow-600 text-black font-semibold">
<Button onClick={onGeneratePlan} className="w-full bg-yellow-500 hover:bg-yellow-600 text-black font-semibold transition-all duration-300 hover:scale-[1.02] active:scale-[0.98]">
<TrendingDown className="mr-2 h-4 w-4" />
Generate My Quit Plan
</Button>
@ -106,11 +107,12 @@ export function QuitPlanCard({
const currentTarget = weekNumber <= totalWeeks ? plan.weeklyTargets[weekNumber - 1] : 0;
return (
<Card className="backdrop-blur-sm shadow-lg drop-shadow-md border-pink-500/30" style={{
<Card className="backdrop-blur-xl shadow-xl drop-shadow-lg border-pink-500/40 hover-lift transition-all duration-300 overflow-hidden relative" style={{
background: pinkBackground
}}>
<CardHeader>
<CardTitle className="flex items-center gap-2 text-white">
<div className="absolute top-0 right-0 w-40 h-40 bg-gradient-to-br from-pink-500/10 to-transparent rounded-full -translate-y-1/2 translate-x-1/2 pointer-events-none" />
<CardHeader className="relative z-10">
<CardTitle className="flex items-center gap-2 text-white text-shadow-sm">
<TrendingDown className="h-5 w-5 text-pink-400" />
Your Quit Plan
</CardTitle>
@ -118,24 +120,24 @@ export function QuitPlanCard({
Week {Math.min(weekNumber, totalWeeks)} of {totalWeeks} - 25% weekly reduction
</CardDescription>
</CardHeader>
<CardContent className="space-y-4">
<div className="bg-pink-500/20 border border-pink-500/30 p-4 rounded-lg text-center">
<CardContent className="space-y-4 relative z-10">
<div className="bg-gradient-to-br from-pink-500/25 to-pink-600/20 border border-pink-500/40 p-5 rounded-xl text-center backdrop-blur-sm">
<p className="text-sm text-white/70 mb-1">This week&apos;s daily target</p>
<p className="text-4xl font-bold text-pink-300">
<p className="text-5xl font-bold text-pink-300 text-shadow">
{currentTarget !== null && currentTarget > 0 ? currentTarget : '0'}
</p>
<p className="text-sm text-white/60">per day</p>
</div>
<div className="space-y-2">
<div className="space-y-2 relative z-10">
<p className="text-sm font-medium text-white">Weekly targets:</p>
<div className="grid grid-cols-4 gap-2">
{plan.weeklyTargets.map((target, index) => (
<div
key={index}
className={`text-center p-2 rounded-lg ${
className={`text-center p-2 rounded-lg transition-all duration-200 hover:scale-105 ${
index + 1 === weekNumber
? 'bg-pink-500 text-white'
? 'bg-gradient-to-br from-pink-500 to-pink-600 text-white shadow-lg shadow-pink-500/30'
: index + 1 < weekNumber
? 'bg-pink-900/50 text-pink-200'
: 'bg-white/10 text-white/60'

View File

@ -68,39 +68,40 @@ export function StatsCard({ usageData, substance }: StatsCardProps) {
return (
<Card
className={`backdrop-blur-sm border ${borderColor} shadow-lg drop-shadow-md`}
className={`backdrop-blur-xl border ${borderColor} shadow-xl drop-shadow-lg hover-lift transition-all duration-300 overflow-hidden relative`}
style={{ background: cardBackground }}
>
<CardHeader className="pb-2">
<CardTitle className="flex items-center gap-2 text-white">
<div className="absolute top-0 right-0 w-40 h-40 bg-gradient-to-br from-white/5 to-transparent rounded-full -translate-y-1/2 translate-x-1/2 pointer-events-none" />
<CardHeader className="pb-2 relative z-10">
<CardTitle className="flex items-center gap-2 text-white text-shadow-sm">
<SubstanceIcon className={`h-5 w-5 ${iconColor}`} />
<span>{substanceLabel} Stats</span>
</CardTitle>
</CardHeader>
<CardContent>
<div className="grid grid-cols-2 gap-4">
<div className="bg-white/10 p-4 rounded-lg text-center">
<p className="text-2xl font-bold text-white">{todayUsage}</p>
<p className="text-sm text-white/70">Today</p>
<div className="grid grid-cols-2 gap-2 sm:gap-4">
<div className="bg-white/10 p-3 sm:p-4 rounded-lg text-center hover:bg-white/15 transition-all duration-200 hover:scale-[1.02]">
<p className="text-xl sm:text-2xl font-bold text-white">{todayUsage}</p>
<p className="text-xs sm:text-sm text-white/70">Today</p>
</div>
<div className="bg-white/10 p-4 rounded-lg text-center">
<p className="text-2xl font-bold text-white">{weekAverage}</p>
<p className="text-sm text-white/70">Daily Avg (7d)</p>
<div className="bg-white/10 p-3 sm:p-4 rounded-lg text-center hover:bg-white/15 transition-all duration-200 hover:scale-[1.02]">
<p className="text-xl sm:text-2xl font-bold text-white">{weekAverage}</p>
<p className="text-xs sm:text-sm text-white/70">Daily Avg (7d)</p>
</div>
<div className="bg-white/10 p-4 rounded-lg text-center">
<p className="text-2xl font-bold text-white">{streak}</p>
<p className="text-sm text-white/70">Free days</p>
<div className="bg-white/10 p-3 sm:p-4 rounded-lg text-center hover:bg-white/15 transition-all duration-200 hover:scale-[1.02]">
<p className="text-xl sm:text-2xl font-bold text-white">{streak}</p>
<p className="text-xs sm:text-sm text-white/70">Free days</p>
</div>
<div className="bg-white/10 p-4 rounded-lg text-center">
<p className="text-2xl font-bold text-white">{totalDays}</p>
<p className="text-sm text-white/70">Days tracked</p>
<div className="bg-white/10 p-3 sm:p-4 rounded-lg text-center hover:bg-white/15 transition-all duration-200 hover:scale-[1.02]">
<p className="text-xl sm:text-2xl font-bold text-white">{totalDays}</p>
<p className="text-xs sm:text-sm text-white/70">Days tracked</p>
</div>
</div>
{streak > 0 && (
<div className={`mt-4 ${substance === 'nicotine' ? 'bg-red-100 dark:bg-red-900/30' : 'bg-green-100 dark:bg-green-900/30'} p-4 rounded-lg text-center`}>
<p className="text-lg">🎉 {streak} day{streak > 1 ? 's' : ''} {substanceLabel.toLowerCase()}-free!</p>
<p className="text-sm text-muted-foreground">Keep up the great work!</p>
<div className={`mt-4 ${substance === 'nicotine' ? 'bg-gradient-to-r from-red-500/20 to-orange-500/20 border-red-500/30' : 'bg-gradient-to-r from-green-500/20 to-emerald-500/20 border-green-500/30'} p-4 rounded-xl text-center border backdrop-blur-sm`}>
<p className="text-lg font-semibold text-white">{streak} day{streak > 1 ? 's' : ''} {substanceLabel.toLowerCase()}-free!</p>
<p className="text-sm text-white/70">Keep up the great work!</p>
</div>
)}
</CardContent>

View File

@ -62,42 +62,46 @@ export function SubstanceTrackingPage({ user, substance }: SubstanceTrackingPage
<main className="container mx-auto px-4 py-8">
{/* Substance Header */}
<div className={`mb-8 p-6 rounded-xl bg-gradient-to-r ${gradientColors} border ${borderColor} backdrop-blur-sm shadow-lg`}>
<div className="flex items-center gap-4">
<div className={`p-3 rounded-full bg-background/50 ${iconColor}`}>
<SubstanceIcon className="h-8 w-8" />
<div className={`mb-6 sm:mb-8 p-4 sm:p-6 rounded-xl bg-gradient-to-r ${gradientColors} border ${borderColor} backdrop-blur-sm shadow-lg opacity-0 animate-fade-in-down`}>
<div className="flex items-center gap-3 sm:gap-4">
<div className={`p-2 sm:p-3 rounded-full bg-background/50 ${iconColor} transition-transform duration-300 hover:scale-110`}>
<SubstanceIcon className="h-6 w-6 sm:h-8 sm:w-8" />
</div>
<div>
<h1 className={`text-3xl font-bold ${theme === 'light' ? 'text-gray-900' : 'text-white'}`}>{substanceLabel} Tracking</h1>
<p className={`mt-1 ${theme === 'light' ? 'text-gray-700' : 'text-white/70'}`}>Monitor your {substanceLabel.toLowerCase()} usage and progress</p>
<h1 className={`text-2xl sm:text-3xl font-bold ${theme === 'light' ? 'text-gray-900' : 'text-white'}`}>{substanceLabel} Tracking</h1>
<p className={`mt-1 text-sm sm:text-base ${theme === 'light' ? 'text-gray-700' : 'text-white/70'}`}>Monitor your {substanceLabel.toLowerCase()} usage and progress</p>
</div>
</div>
</div>
{/* Today's Status Message */}
<div className="mb-8 text-center">
<div className="mb-6 sm:mb-8 text-center opacity-0 animate-fade-in delay-100">
{todayCount === 0 ? (
<p className={`text-2xl font-medium ${theme === 'light' ? 'text-green-600' : 'text-green-400'}`}>
<p className={`text-xl sm:text-2xl font-medium ${theme === 'light' ? 'text-green-600' : 'text-green-400'}`}>
Great job, nothing yet!
</p>
) : (
<p className={`text-2xl font-medium ${theme === 'light' ? 'text-gray-900' : 'text-white'}`}>
<p className={`text-xl sm:text-2xl font-medium ${theme === 'light' ? 'text-gray-900' : 'text-white'}`}>
{todayCount} {todayCount === 1 ? (substance === 'nicotine' ? 'puff' : 'hit') : unitLabel} recorded, you got this!
</p>
)}
</div>
{/* Inspirational Message */}
<div className="mb-8 text-center">
<p className={`text-xl font-light italic ${theme === 'light' ? 'text-gray-500' : 'text-white/60'}`}>
<div className="mb-6 sm:mb-8 text-center opacity-0 animate-fade-in delay-200">
<p className={`text-lg sm:text-xl font-light italic ${theme === 'light' ? 'text-gray-500' : 'text-white/60'}`}>
&quot;One day at a time...&quot;
</p>
</div>
{/* Stats and Graph */}
<div className="grid gap-6 md:grid-cols-2">
<StatsCard usageData={usageData} substance={substance} />
<UsageTrendGraph usageData={usageData} substance={substance} />
<div className="opacity-0 animate-fade-in-up delay-200">
<StatsCard usageData={usageData} substance={substance} />
</div>
<div className="opacity-0 animate-slide-in-right delay-300">
<UsageTrendGraph usageData={usageData} substance={substance} />
</div>
</div>
</main>
</div>

View File

@ -17,37 +17,42 @@ import { ChevronLeftIcon, ChevronRightIcon, Cigarette, Leaf, Sparkles } from 'lu
import { useTheme } from '@/lib/theme-context';
const quotes = [
{ text: "The secret of getting ahead is getting started.", author: "Mark Twain" },
{ text: "It does not matter how slowly you go as long as you do not stop.", author: "Confucius" },
{ text: "Your future self will thank you for the choices you make today.", author: "Unknown" },
{ text: "Every moment is a fresh beginning.", author: "T.S. Eliot" },
{ text: "Believe you can and you're halfway there.", author: "Theodore Roosevelt" },
{ text: "Small steps every day lead to big changes over time.", author: "Unknown" },
{ text: "You are stronger than your cravings.", author: "Unknown" },
{ text: "The best time to plant a tree was 20 years ago. The second best time is now.", author: "Chinese Proverb" },
{ text: "Progress, not perfection, is what we should be asking of ourselves.", author: "Julia Cameron" },
{ text: "The greatest glory in living lies not in never falling, but in rising every time we fall.", author: "Nelson Mandela" },
{ text: "Your life does not get better by chance, it gets better by change.", author: "Jim Rohn" },
{ text: "You don't have to be great to start, but you have to start to be great.", author: "Zig Ziglar" },
{ text: "The pain of discipline is far less than the pain of regret.", author: "Sarah Bombell" },
{ text: "One day or day one. You decide.", author: "Unknown" },
{ text: "Your health is an investment, not an expense.", author: "Unknown" },
{ text: "The comeback is always stronger than the setback.", author: "Unknown" },
{ text: "Difficult roads often lead to beautiful destinations.", author: "Zig Ziglar" },
{ text: "Success is the sum of small efforts repeated day in and day out.", author: "Robert Collier" },
{ text: "Fall seven times, stand up eight.", author: "Japanese Proverb" },
{ text: "Great things never come from comfort zones.", author: "Unknown" },
{ text: "Every champion was once a contender that refused to give up.", author: "Rocky Balboa" },
{ text: "Don't stop when you're tired. Stop when you're done.", author: "Unknown" },
{ text: "Break free from the chains of habit and unlock your true potential.", author: "Unknown" },
{ text: "Dream it. Wish it. Do it.", author: "Unknown" },
{ text: "Your limitation—it's only your imagination.", author: "Unknown" },
{ text: "You are not defined by your past. You are prepared by it.", author: "Unknown" },
{ text: "Don't let yesterday take up too much of today.", author: "Will Rogers" },
{ text: "What lies behind us and what lies before us are tiny matters compared to what lies within us.", author: "Ralph Waldo Emerson" },
{ text: "The only person you are destined to become is the person you decide to be.", author: "Ralph Waldo Emerson" },
{ text: "The only way to do great work is to love what you do.", author: "Steve Jobs" },
{ text: "The harder you work for something, the greater you'll feel when you achieve it.", author: "Unknown" },
{ text: "It is during our darkest moments that we must focus to see the light.", author: "Aristotle" },
{ text: "The greatest glory in living lies not in never falling, but in rising every time we fall.", author: "Nelson Mandela" },
{ text: "In the middle of difficulty lies opportunity.", author: "Albert Einstein" },
{ text: "What you get by achieving your goals is not as important as what you become by achieving your goals.", author: "Zig Ziglar" },
{ text: "The future belongs to those who believe in the beauty of their dreams.", author: "Eleanor Roosevelt" },
{ text: "It does not matter how slowly you go as long as you do not stop.", author: "Confucius" },
{ text: "Everything you've ever wanted is on the other side of fear.", author: "George Addair" },
{ text: "The best time to plant a tree was 20 years ago. The second best time is now.", author: "Chinese Proverb" },
{ text: "You are never too old to set another goal or to dream a new dream.", author: "C.S. Lewis" },
{ text: "The only impossible journey is the one you never begin.", author: "Tony Robbins" },
{ text: "Success is not final, failure is not fatal: it is the courage to continue that counts.", author: "Winston Churchill" },
{ text: "Believe you can and you're halfway there.", author: "Theodore Roosevelt" },
{ text: "The pain you feel today will be the strength you feel tomorrow.", author: "Arnold Schwarzenegger" },
{ text: "Your life does not get better by chance, it gets better by change.", author: "Jim Rohn" },
{ text: "The secret of change is to focus all of your energy not on fighting the old, but on building the new.", author: "Socrates" },
{ text: "What lies behind us and what lies before us are tiny matters compared to what lies within us.", author: "Ralph Waldo Emerson" },
{ text: "The man who moves a mountain begins by carrying away small stones.", author: "Confucius" },
{ text: "Our greatest weakness lies in giving up. The most certain way to succeed is always to try just one more time.", author: "Thomas Edison" },
{ text: "Fall seven times, stand up eight.", author: "Japanese Proverb" },
{ text: "You don't have to be great to start, but you have to start to be great.", author: "Zig Ziglar" },
{ text: "The only person you are destined to become is the person you decide to be.", author: "Ralph Waldo Emerson" },
{ text: "When you reach the end of your rope, tie a knot in it and hang on.", author: "Franklin D. Roosevelt" },
{ text: "Do not wait to strike till the iron is hot; but make it hot by striking.", author: "William Butler Yeats" },
{ text: "Whether you think you can or you think you can't, you're right.", author: "Henry Ford" },
{ text: "The mind is everything. What you think you become.", author: "Buddha" },
{ text: "Strength does not come from physical capacity. It comes from an indomitable will.", author: "Mahatma Gandhi" },
{ text: "A journey of a thousand miles begins with a single step.", author: "Lao Tzu" },
{ text: "He who conquers himself is the mightiest warrior.", author: "Confucius" },
{ text: "The wound is the place where the light enters you.", author: "Rumi" },
{ text: "Rock bottom became the solid foundation on which I rebuilt my life.", author: "J.K. Rowling" },
{ text: "You have power over your mind, not outside events. Realize this, and you will find strength.", author: "Marcus Aurelius" },
{ text: "Out of suffering have emerged the strongest souls.", author: "Kahlil Gibran" },
{ text: "The only limit to our realization of tomorrow will be our doubts of today.", author: "Franklin D. Roosevelt" },
{ text: "Courage is not the absence of fear, but rather the judgment that something else is more important than fear.", author: "Ambrose Redmoon" },
{ text: "Every morning brings new potential, but if you dwell on the misfortunes of the day before, you tend to overlook tremendous opportunities.", author: "Harvey Mackay" },
];
interface UsageCalendarProps {
@ -231,14 +236,14 @@ export function UsageCalendar({ usageData, onDataUpdate }: UsageCalendarProps) {
return (
<>
<Card className="bg-card/80 backdrop-blur-sm shadow-lg drop-shadow-md">
<Card className="bg-card/80 backdrop-blur-xl shadow-xl drop-shadow-lg hover-lift transition-all duration-300 border-white/10">
<CardHeader>
<CardTitle>Usage Calendar</CardTitle>
</CardHeader>
<CardContent>
<div className="flex gap-4">
<div className="flex flex-col lg:flex-row gap-4">
{/* Calendar */}
<div className="shrink-0">
<div className="shrink-0 overflow-x-auto">
<DayPicker
mode="single"
selected={selectedDate}
@ -258,41 +263,47 @@ export function UsageCalendar({ usageData, onDataUpdate }: UsageCalendarProps) {
{/* Daily Quote */}
<div
className="flex-1 flex flex-col justify-center p-4 rounded-lg border border-indigo-500/30"
style={{ background: 'linear-gradient(135deg, rgba(67, 56, 202, 0.4) 0%, rgba(109, 40, 217, 0.35) 50%, rgba(76, 29, 149, 0.45) 100%)' }}
className="flex-1 flex flex-col justify-center p-5 rounded-xl border border-indigo-500/40 min-h-[120px] relative overflow-hidden"
style={{
background: 'linear-gradient(135deg, rgba(67, 56, 202, 0.35) 0%, rgba(109, 40, 217, 0.3) 50%, rgba(76, 29, 149, 0.4) 100%)',
boxShadow: 'inset 0 1px 0 rgba(255, 255, 255, 0.1), 0 4px 20px rgba(99, 102, 241, 0.15)'
}}
>
<div className="flex items-center gap-2 mb-3">
<Sparkles className="h-4 w-4 text-yellow-300" />
<span className="text-xs font-medium text-white/70 uppercase tracking-wide">Daily Inspiration</span>
<div className="absolute top-0 right-0 w-32 h-32 bg-gradient-to-br from-purple-500/20 to-transparent rounded-full -translate-y-1/2 translate-x-1/2" />
<div className="relative z-10">
<div className="flex items-center gap-2 mb-3">
<Sparkles className="h-4 w-4 text-yellow-300 animate-pulse-subtle" />
<span className="text-xs font-semibold text-white/80 uppercase tracking-wider">Daily Inspiration</span>
</div>
<p className="text-sm font-medium text-white leading-relaxed mb-3 text-shadow-sm">
&ldquo;{dailyQuote.text}&rdquo;
</p>
<p className="text-xs text-white/70 font-medium">
{dailyQuote.author}
</p>
</div>
<p className="text-sm font-medium text-white leading-relaxed mb-3">
&ldquo;{dailyQuote.text}&rdquo;
</p>
<p className="text-xs text-white/60">
{dailyQuote.author}
</p>
</div>
</div>
<div className="mt-4 flex flex-wrap gap-4 text-sm">
<div className="mt-4 grid grid-cols-2 sm:grid-cols-3 md:flex md:flex-wrap gap-3 text-sm">
<div className="flex items-center gap-2">
<div className="w-4 h-4 rounded" style={{ background: 'linear-gradient(135deg, rgba(96,165,250,0.5), rgba(59,130,246,0.6))' }} />
<div className="w-4 h-4 rounded shrink-0" style={{ background: 'linear-gradient(135deg, rgba(96,165,250,0.5), rgba(59,130,246,0.6))' }} />
<span>No usage</span>
</div>
<div className="flex items-center gap-2">
<div className="w-4 h-4 rounded" style={{ background: 'linear-gradient(135deg, rgba(251,191,36,0.6), rgba(245,158,11,0.7))' }} />
<div className="w-4 h-4 rounded shrink-0" style={{ background: 'linear-gradient(135deg, rgba(251,191,36,0.6), rgba(245,158,11,0.7))' }} />
<span>Today</span>
</div>
<div className="flex items-center gap-2">
<div className="w-4 h-4 rounded" style={{ background: 'linear-gradient(135deg, rgba(239,68,68,0.7), rgba(185,28,28,0.8))' }} />
<div className="w-4 h-4 rounded shrink-0" style={{ background: 'linear-gradient(135deg, rgba(239,68,68,0.7), rgba(185,28,28,0.8))' }} />
<span>Nicotine</span>
</div>
<div className="flex items-center gap-2">
<div className="w-4 h-4 rounded" style={{ background: 'linear-gradient(135deg, rgba(34,197,94,0.7), rgba(22,163,74,0.8))' }} />
<div className="w-4 h-4 rounded shrink-0" style={{ background: 'linear-gradient(135deg, rgba(34,197,94,0.7), rgba(22,163,74,0.8))' }} />
<span>Marijuana</span>
</div>
<div className="flex items-center gap-2">
<div className="w-4 h-4 rounded" style={{ background: 'linear-gradient(135deg, rgba(239,68,68,0.8) 50%, rgba(34,197,94,0.8) 50%)' }} />
<div className="w-4 h-4 rounded shrink-0" style={{ background: 'linear-gradient(135deg, rgba(239,68,68,0.8) 50%, rgba(34,197,94,0.8) 50%)' }} />
<span>Both</span>
</div>
</div>

View File

@ -62,7 +62,7 @@ export function UsageTrendGraph({ usageData, substance }: UsageTrendGraphProps)
}, [chartData]);
return (
<Card className="bg-card/80 backdrop-blur-sm shadow-lg drop-shadow-md">
<Card className="bg-card/80 backdrop-blur-xl shadow-xl drop-shadow-lg hover-lift transition-all duration-300 border-white/10">
<CardHeader>
<CardTitle className="flex items-center justify-between">
<span>{substanceLabel} Usage Trend</span>
@ -117,14 +117,14 @@ export function UsageTrendGraph({ usageData, substance }: UsageTrendGraphProps)
</div>
<div className="mt-4 grid grid-cols-2 gap-4">
<div className="bg-muted/50 p-3 rounded-lg text-center">
<div className="bg-muted/50 p-3 rounded-lg text-center hover:bg-muted/70 transition-all duration-200 hover:scale-[1.02]">
<p className="text-2xl font-bold">{average}</p>
<p className="text-sm text-muted-foreground">Daily Average</p>
</div>
<div className="bg-muted/50 p-3 rounded-lg text-center">
<div className="bg-muted/50 p-3 rounded-lg text-center hover:bg-muted/70 transition-all duration-200 hover:scale-[1.02]">
<p className="text-2xl font-bold capitalize">{trend}</p>
<p className="text-sm text-muted-foreground">
{trend === 'decreasing' ? '📉 Great progress!' : trend === 'increasing' ? '📈 Stay strong!' : '➡️ Holding steady'}
{trend === 'decreasing' ? 'Great progress!' : trend === 'increasing' ? 'Stay strong!' : 'Holding steady'}
</p>
</div>
</div>

View File

@ -50,11 +50,17 @@ export function UserHeader({ user }: UserHeaderProps) {
background: 'linear-gradient(135deg, rgba(10, 10, 20, 0.98) 0%, rgba(20, 30, 60, 0.95) 50%, rgba(15, 25, 50, 0.98) 100%)',
backdropFilter: 'blur(10px)',
}}>
<div className="container mx-auto px-4 py-4 flex items-center justify-between">
<div className="flex items-center gap-8">
<div className="container mx-auto px-4 py-3 sm:py-4 flex items-center justify-between">
<div className="flex items-center gap-4 sm:gap-8">
<h1
className="text-2xl font-bold text-white cursor-pointer hover:opacity-80 transition-opacity"
className="text-xl sm:text-2xl font-bold cursor-pointer hover:opacity-90 transition-all duration-300 hover:scale-105"
onClick={() => handleNavigate('/')}
style={{
background: 'linear-gradient(135deg, #a78bfa 0%, #818cf8 50%, #6366f1 100%)',
WebkitBackgroundClip: 'text',
WebkitTextFillColor: 'transparent',
backgroundClip: 'text',
}}
>
QuitTraq
</h1>
@ -65,16 +71,16 @@ export function UserHeader({ user }: UserHeaderProps) {
)}
</div>
<div className="flex items-center gap-3">
<div className="flex items-center gap-2 sm:gap-3">
<button
onClick={toggleTheme}
className="p-2 rounded-full bg-white/10 hover:bg-white/20 transition-all focus:outline-none focus:ring-2 focus:ring-white/30"
className="p-2.5 sm:p-2 rounded-full bg-white/10 hover:bg-white/20 transition-all duration-300 focus:outline-none focus:ring-2 focus:ring-white/30 hover:scale-110 active:scale-95"
aria-label="Toggle theme"
>
{theme === 'dark' ? (
<Moon className="h-5 w-5 text-blue-300" />
<Moon className="h-5 w-5 text-blue-300 transition-transform duration-300" />
) : (
<Sun className="h-5 w-5 text-yellow-400" />
<Sun className="h-5 w-5 text-yellow-400 transition-transform duration-300" />
)}
</button>
<DropdownMenu>
@ -111,8 +117,8 @@ export function UserHeader({ user }: UserHeaderProps) {
</div>
</div>
{userName && (
<div className="sm:hidden container mx-auto px-4 pb-3">
<p className="text-white/90 text-base">
<div className="sm:hidden container mx-auto px-4 pb-2">
<p className="text-white/90 text-sm">
Welcome {userName}, you got this!
</p>
</div>