# Hydro Flux Dashboard - Complete Replication Guide

## Overview
A mobile-first health tracking dashboard called "Hydro Flux" that tracks water intake, steps, sleep, Strava integration, goals, and notes. Built with React, TypeScript, Tailwind CSS, and Motion (Framer Motion).

## Design Specifications

### Color Palette
- Primary Blue: #60A5FA (blue-400)
- Secondary Blue: #3B82F6 (blue-500)
- Light Blue: #DBEAFE (blue-50)
- Orange (Strava): #EA580C (orange-600)
- Gray Background: Linear gradient from gray-100 to gray-200
- White: #FFFFFF
- Text Primary: #1F2937 (gray-800)
- Text Secondary: #6B7280 (gray-500)

### Layout
- Mobile-first design (max-width: 28rem / 448px)
- Rounded container with 3rem border radius
- White background with shadow-2xl
- Padding: 1.5rem (6 units)
- Component spacing: 1rem gap (4 units)

### Typography
- Headers: font-bold
- Body: font-medium
- Small text: text-sm, text-xs

## Dependencies Required

```json
{
  "recharts": "2.15.2",
  "motion": "12.23.24",
  "lucide-react": "0.487.0"
}
```

Import Motion using: `import { motion } from 'motion/react'`

## File Structure

```
/src/app/
  ├── App.tsx
  └── components/
      ├── Header.tsx
      ├── WaterTracker.tsx
      ├── StepsTracker.tsx
      ├── StravaIntegration.tsx
      ├── SleepTracker.tsx
      ├── Goals.tsx
      └── Notes.tsx
```

## Complete Component Code

### 1. /src/app/App.tsx

```tsx
import { useState, useEffect } from 'react';
import { Header } from './components/Header';
import { WaterTracker } from './components/WaterTracker';
import { StepsTracker } from './components/StepsTracker';
import { StravaIntegration } from './components/StravaIntegration';
import { SleepTracker } from './components/SleepTracker';
import { Goals } from './components/Goals';
import { Notes } from './components/Notes';

function App() {
  const [waterAmount, setWaterAmount] = useState(1.2);
  const [currentDate, setCurrentDate] = useState('');
  const [currentTime, setCurrentTime] = useState('');
  const [note, setNote] = useState('Feeling hydrated today. Remember to add those gym sessions!');
  const [goals, setGoals] = useState([
    { id: '1', text: 'Drink 3L of water', completed: true },
    { id: '2', text: 'Walk 10K steps', completed: false },
    { id: '3', text: 'Sleep 8 hours', completed: false },
  ]);

  // Sleep data for the chart
  const sleepData = [
    { value: 30 }, { value: 35 }, { value: 25 }, { value: 40 }, 
    { value: 55 }, { value: 45 }, { value: 60 }, { value: 75 },
    { value: 70 }, { value: 80 }, { value: 65 }, { value: 55 },
    { value: 50 }, { value: 45 }, { value: 40 },
  ];

  useEffect(() => {
    const updateDateTime = () => {
      const now = new Date();
      const dateStr = now.toLocaleDateString('en-US', { 
        weekday: 'long', 
        year: 'numeric', 
        month: 'long', 
        day: 'numeric' 
      });
      const timeStr = now.toLocaleTimeString('en-US', { 
        hour: 'numeric', 
        minute: '2-digit',
        hour12: true 
      }) + ' AEDT';
      setCurrentDate(dateStr);
      setCurrentTime(timeStr);
    };

    updateDateTime();
    const interval = setInterval(updateDateTime, 1000);
    return () => clearInterval(interval);
  }, []);

  const handleAddWater = () => {
    setWaterAmount((prev) => Math.min(prev + 0.25, 3.0));
  };

  const handleToggleGoal = (id: string) => {
    setGoals((prev) =>
      prev.map((goal) =>
        goal.id === id ? { ...goal, completed: !goal.completed } : goal
      )
    );
  };

  return (
    <div className="min-h-screen bg-gradient-to-br from-gray-100 to-gray-200 flex items-center justify-center p-4">
      <div className="w-full max-w-md bg-white rounded-[3rem] shadow-2xl p-6 relative overflow-hidden">
        {/* Subtle background decoration */}
        <div className="absolute top-0 right-0 w-64 h-64 bg-blue-200/20 rounded-full blur-3xl -z-10" />
        <div className="absolute bottom-0 left-0 w-64 h-64 bg-purple-200/20 rounded-full blur-3xl -z-10" />

        <Header
          level={14}
          streakDays={14}
          currentDate={currentDate}
          currentTime={currentTime}
        />

        <WaterTracker
          currentAmount={waterAmount}
          targetAmount={3.0}
          onAddWater={handleAddWater}
        />

        <div className="grid grid-cols-2 gap-4 mb-4">
          <StepsTracker steps={8432} goal={10000} />
          <StravaIntegration distance={5.2} lastSync="2h ago" />
        </div>

        <div className="mb-4">
          <SleepTracker
            hours={7}
            minutes={20}
            sleepType="Light Sleep"
            data={sleepData}
          />
        </div>

        <div className="grid grid-cols-2 gap-4">
          <Goals goals={goals} onToggleGoal={handleToggleGoal} />
          <Notes note={note} onNoteChange={setNote} />
        </div>
      </div>
    </div>
  );
}

export default App;
```

### 2. /src/app/components/Header.tsx

```tsx
import { Droplet } from 'lucide-react';

interface HeaderProps {
  level: number;
  streakDays: number;
  currentDate: string;
  currentTime: string;
}

export function Header({ level, streakDays, currentDate, currentTime }: HeaderProps) {
  return (
    <div className="flex flex-col items-center gap-2 mb-6">
      <div className="flex items-center justify-between w-full px-4">
        <div className="flex flex-col items-center">
          <div className="w-14 h-14 rounded-full bg-gradient-to-br from-blue-400 to-blue-600 flex items-center justify-center mb-1 shadow-lg">
            <div className="w-12 h-12 rounded-full bg-white/90 flex items-center justify-center text-sm font-semibold text-gray-700">
              JD
            </div>
          </div>
          <span className="text-xs text-blue-600 font-medium">Level {level}</span>
        </div>

        <div className="flex flex-col items-center flex-1">
          <h1 className="text-2xl font-bold text-gray-800 mb-1">Hydro Flux</h1>
          <div className="text-sm text-gray-600">{currentDate}</div>
          <div className="text-sm text-gray-500">{currentTime}</div>
        </div>

        <div className="flex items-center gap-1">
          <Droplet className="w-5 h-5 fill-blue-500 text-blue-500" />
          <Droplet className="w-5 h-5 fill-blue-400 text-blue-400" />
          <span className="text-sm font-semibold text-gray-700 ml-1">{streakDays} Days</span>
        </div>
      </div>
    </div>
  );
}
```

### 3. /src/app/components/WaterTracker.tsx

```tsx
import { Plus } from 'lucide-react';
import { motion } from 'motion/react';

interface WaterTrackerProps {
  currentAmount: number;
  targetAmount: number;
  onAddWater: () => void;
}

export function WaterTracker({ currentAmount, targetAmount, onAddWater }: WaterTrackerProps) {
  const percentage = (currentAmount / targetAmount) * 100;

  return (
    <div className="relative h-64 bg-gradient-to-b from-blue-50 to-blue-100 rounded-3xl overflow-hidden shadow-lg mb-6">
      {/* Water wave */}
      <motion.div
        className="absolute bottom-0 left-0 right-0"
        style={{
          height: `${percentage}%`,
          background: 'linear-gradient(180deg, rgba(96, 165, 250, 0.8) 0%, rgba(59, 130, 246, 0.9) 100%)',
        }}
        animate={{
          y: [0, -10, 0],
        }}
        transition={{
          duration: 3,
          repeat: Infinity,
          ease: "easeInOut",
        }}
      >
        {/* Wave effect */}
        <svg
          className="absolute top-0 left-0 w-full"
          viewBox="0 0 1200 120"
          preserveAspectRatio="none"
          style={{ height: '60px', transform: 'translateY(-50%)' }}
        >
          <motion.path
            d="M0,50 Q300,10 600,50 T1200,50 L1200,120 L0,120 Z"
            fill="rgba(96, 165, 250, 0.5)"
            animate={{
              d: [
                "M0,50 Q300,10 600,50 T1200,50 L1200,120 L0,120 Z",
                "M0,50 Q300,90 600,50 T1200,50 L1200,120 L0,120 Z",
                "M0,50 Q300,10 600,50 T1200,50 L1200,120 L0,120 Z",
              ],
            }}
            transition={{
              duration: 4,
              repeat: Infinity,
              ease: "easeInOut",
            }}
          />
        </svg>
      </motion.div>

      {/* Add button */}
      <button
        onClick={onAddWater}
        className="absolute top-1/2 left-1/2 transform -translate-x-1/2 -translate-y-1/2 w-16 h-16 bg-blue-400/50 hover:bg-blue-400/70 backdrop-blur-sm rounded-full flex items-center justify-center shadow-xl transition-all hover:scale-110 z-10"
      >
        <Plus className="w-8 h-8 text-white" />
      </button>

      {/* Amount display */}
      <div className="absolute bottom-6 left-0 right-0 text-center z-10">
        <span className="text-2xl font-bold text-gray-700">
          {currentAmount.toFixed(1)}L / {targetAmount.toFixed(1)}L
        </span>
      </div>
    </div>
  );
}
```

### 4. /src/app/components/StepsTracker.tsx

```tsx
interface StepsTrackerProps {
  steps: number;
  goal: number;
}

export function StepsTracker({ steps, goal }: StepsTrackerProps) {
  const percentage = Math.min((steps / goal) * 100, 100);
  const circumference = 2 * Math.PI * 45;
  const strokeDashoffset = circumference - (percentage / 100) * circumference;

  return (
    <div className="bg-gradient-to-br from-blue-50 to-white rounded-2xl p-6 shadow-md">
      <h3 className="text-sm font-semibold text-gray-700 mb-4">Steps Tracker</h3>
      <div className="flex items-center justify-center">
        <div className="relative w-32 h-32">
          <svg className="transform -rotate-90 w-32 h-32">
            <circle
              cx="64"
              cy="64"
              r="45"
              stroke="#E5E7EB"
              strokeWidth="8"
              fill="none"
            />
            <circle
              cx="64"
              cy="64"
              r="45"
              stroke="#60A5FA"
              strokeWidth="8"
              fill="none"
              strokeDasharray={circumference}
              strokeDashoffset={strokeDashoffset}
              strokeLinecap="round"
              className="transition-all duration-500"
            />
          </svg>
          <div className="absolute inset-0 flex flex-col items-center justify-center">
            <span className="text-2xl font-bold text-gray-800">{steps.toLocaleString()}</span>
            <span className="text-xs text-gray-500">steps</span>
          </div>
        </div>
      </div>
    </div>
  );
}
```

### 5. /src/app/components/StravaIntegration.tsx

```tsx
interface StravaIntegrationProps {
  distance: number;
  lastSync: string;
}

export function StravaIntegration({ distance, lastSync }: StravaIntegrationProps) {
  return (
    <div className="bg-gradient-to-br from-orange-50 to-white rounded-2xl p-6 shadow-md">
      <h3 className="text-sm font-semibold text-gray-700 mb-4">Strava Integration</h3>
      <div className="flex flex-col items-center justify-center py-4">
        <div className="w-16 h-16 bg-gradient-to-br from-orange-500 to-orange-600 rounded-2xl flex items-center justify-center mb-3 shadow-lg transform rotate-12">
          <span className="text-3xl font-bold text-white transform -rotate-12">S</span>
        </div>
        <span className="text-lg font-bold text-gray-800">{distance}km Run</span>
        <span className="text-xs text-gray-500 mt-1">Last Sync: {lastSync}</span>
      </div>
    </div>
  );
}
```

### 6. /src/app/components/SleepTracker.tsx

```tsx
import { LineChart, Line, ResponsiveContainer, YAxis } from 'recharts';

interface SleepTrackerProps {
  hours: number;
  minutes: number;
  sleepType: string;
  data: { value: number }[];
}

export function SleepTracker({ hours, minutes, sleepType, data }: SleepTrackerProps) {
  return (
    <div className="bg-gradient-to-br from-blue-50 to-white rounded-2xl p-6 shadow-md">
      <h3 className="text-sm font-semibold text-gray-700 mb-4">Sleep Tracker</h3>
      <div className="h-24 mb-3">
        <ResponsiveContainer width="100%" height="100%">
          <LineChart data={data}>
            <YAxis hide domain={[0, 100]} />
            <Line
              type="monotone"
              dataKey="value"
              stroke="#60A5FA"
              strokeWidth={2}
              dot={false}
            />
          </LineChart>
        </ResponsiveContainer>
      </div>
      <div className="flex items-center justify-between">
        <span className="text-xl font-bold text-gray-800">
          {hours}h {minutes}m
        </span>
        <span className="text-sm text-blue-600 font-medium">{sleepType}</span>
      </div>
    </div>
  );
}
```

### 7. /src/app/components/Goals.tsx

```tsx
import { Check } from 'lucide-react';

interface Goal {
  id: string;
  text: string;
  completed: boolean;
}

interface GoalsProps {
  goals: Goal[];
  onToggleGoal: (id: string) => void;
}

export function Goals({ goals, onToggleGoal }: GoalsProps) {
  return (
    <div className="bg-gradient-to-br from-blue-50 to-white rounded-2xl p-6 shadow-md">
      <h3 className="text-sm font-semibold text-gray-700 mb-4">Goals</h3>
      <div className="space-y-3">
        {goals.map((goal) => (
          <button
            key={goal.id}
            onClick={() => onToggleGoal(goal.id)}
            className={`w-full flex items-center gap-3 px-4 py-3 rounded-xl transition-all ${
              goal.completed
                ? 'bg-blue-500 text-white shadow-lg'
                : 'bg-blue-100 text-gray-700 hover:bg-blue-200'
            }`}
          >
            <div
              className={`w-5 h-5 rounded-full flex items-center justify-center ${
                goal.completed ? 'bg-white/30' : 'bg-white'
              }`}
            >
              {goal.completed && <Check className="w-4 h-4 text-blue-500" />}
            </div>
            <span className="text-sm font-medium">{goal.text}</span>
          </button>
        ))}
      </div>
    </div>
  );
}
```

### 8. /src/app/components/Notes.tsx

```tsx
interface NotesProps {
  note: string;
  onNoteChange: (note: string) => void;
}

export function Notes({ note, onNoteChange }: NotesProps) {
  return (
    <div className="bg-gradient-to-br from-blue-50 to-white rounded-2xl p-6 shadow-md">
      <h3 className="text-sm font-semibold text-gray-700 mb-4">Notes</h3>
      <textarea
        value={note}
        onChange={(e) => onNoteChange(e.target.value)}
        placeholder="Add your notes here..."
        className="w-full h-24 bg-white/50 rounded-lg px-4 py-3 text-sm text-gray-700 placeholder-gray-400 border-none outline-none resize-none"
      />
    </div>
  );
}
```

## Key Features & Interactions

1. **Water Tracker**
   - Animated wave visualization using SVG and Motion
   - Click + button to add 0.25L (max 3.0L)
   - Displays current/target amount

2. **Steps Tracker**
   - Circular progress indicator using SVG circles
   - Shows 8,432 / 10,000 steps
   - Animated stroke-dashoffset for progress

3. **Strava Integration**
   - Orange gradient background
   - Rotated "S" logo
   - Displays distance and last sync time

4. **Sleep Tracker**
   - Recharts line chart visualization
   - Shows hours and minutes
   - Sleep type label (Light Sleep)

5. **Goals**
   - Three clickable goal items
   - Toggle completed state
   - Visual feedback with color change

6. **Notes**
   - Textarea for user input
   - Placeholder text
   - Auto-updating state

7. **Header**
   - User avatar with initials "JD"
   - Level indicator
   - Streak counter with droplet icons
   - Live date/time that updates every second

## Important Implementation Notes

- Use Tailwind CSS v4 (no config file needed)
- Motion package is imported as `import { motion } from 'motion/react'`
- All components are TypeScript with proper interfaces
- State management uses React useState hooks
- DateTime updates every 1000ms using setInterval
- Responsive design with max-width container
- All interactive elements have hover states
- Glassmorphism effects using backdrop-blur and opacity

## Testing Checklist

- [ ] Water tracker + button increases amount
- [ ] Water amount doesn't exceed 3.0L
- [ ] Goals toggle between completed/incomplete
- [ ] Notes textarea updates on input
- [ ] Date and time update in real-time
- [ ] All animations are smooth
- [ ] Mobile responsive (320px - 448px width)
- [ ] All icons from lucide-react render correctly
- [ ] Sleep chart displays properly with recharts
