A beautiful, modern life planner PWA built for real people. Think Notion × Daylio × Sunsama, wrapped in a soft kawaii aesthetic. Designed for Samsung Tab S9 FE, iPhone, and laptop.
Bloom is a full-featured personal planning app that combines everything you need to live intentionally. Think Notion × Sunsama × Daylio, wrapped in a soft kawaii aesthetic.
| Feature | Description |
|---|---|
| ⚡ Quick Capture | Global Ctrl/Cmd+K shortcut — add a task, event, or note from any page in 2 seconds |
| ✅ Tasks | Priority levels, time estimates, kanban board, categories, today's time budget |
| 📅 Calendar | Month/week/day views, recurring events, .ics export, WhatsApp/email sharing |
| 🌱 Habits | Forgiveness-based score (0–100%), not punishing streak resets; 28-day heatmap |
| 🎯 Goals | Milestones, progress slider, deadline tracking — fully persisted across sessions |
| 📖 Notes | Markdown editor, sections, tags, GIF embeds, Markdown/JSON export, XSS-safe |
| 🌙 Journal | Mood + weather picker, 30-day mood calendar grid, mood-habit correlation insights |
| ⏱ Focus | Pomodoro timer with session tracking, sound picker, in-session task list |
| 🏡 Dashboard | Daily intention, today's schedule timeline, weekly stats, smart insight strips |
- Forgiveness algorithm — Habits show a consistency percentage, not a binary streak. Missing one day drops you from 100% to 90%, not to zero. Research shows this prevents the "what-the-hell effect" that causes 52% of habit app abandonment.
- Global Quick Capture —
Ctrl+Kanywhere opens a modal to capture tasks, events, or notes instantly. No navigation required. - Mood-Habit Correlation — Like Daylio, Bloom analyzes which habits correlate with your better mood days and surfaces the insight automatically.
- Daily Intention — Set a focus word or mantra for the day (Sunsama-inspired). Persisted per day, shown beautifully on the dashboard.
- Today's Timeline — A vertical chronological view of today's calendar events (Structured/Cron-inspired), always visible on the dashboard.
- Weekly Stats — A 7-day productivity snapshot: habit consistency bar chart, tasks completed, mood average, focus sessions.
- Task time estimates — Add estimated minutes to any task. Dashboard shows "Today: 1h 20m planned / 45m done".
All data is persisted locally (works offline) and optionally synced to the cloud via Supabase. Installs as a PWA on any device.
| Layer | Technology |
|---|---|
| Framework | React 18 |
| Language | TypeScript (strict, zero errors) |
| Build Tool | Vite |
| Styling | Tailwind CSS v4 + CSS Variables (themes) |
| Animations | Framer Motion |
| State | Zustand v4 with persist middleware (localStorage, version 4) |
| Cloud Backend | Supabase (Auth + PostgreSQL + Realtime) |
| Security | DOMPurify (XSS sanitization on all HTML renders), Supabase RLS |
| PWA | vite-plugin-pwa + Workbox (offline support, installable) |
| Icons | Lucide React |
| Date Handling | date-fns |
| Notifications | react-hot-toast |
| Confetti | canvas-confetti |
| GIFs | GIPHY API |
| Markdown | Custom renderer + DOMPurify allowlist sanitizer |
| Calendar Export | Manual .ics string generation (no library needed) |
| Image Export | html2canvas (month view snapshot) |
bloom/
├── public/ # Static assets + PWA icons
├── supabase/
│ └── schema.sql # Full database schema + RLS policies
├── src/
│ ├── components/
│ │ ├── animations/ # Sakura petals, floating elements
│ │ ├── layout/ # Sidebar, MobileNav
│ │ ├── notes/ # GifPicker component
│ │ ├── widgets/
│ │ │ ├── MoodWidget.tsx
│ │ │ ├── WaterWidget.tsx
│ │ │ ├── TasksWidget.tsx
│ │ │ ├── HabitsWidget.tsx
│ │ │ ├── QuoteWidget.tsx
│ │ │ ├── CountdownWidget.tsx
│ │ │ ├── WeatherWidget.tsx
│ │ │ ├── TimelineWidget.tsx # ← NEW: Today's schedule (Cron/Structured style)
│ │ │ ├── WeeklyStatsWidget.tsx # ← NEW: 7-day productivity overview (Sunsama style)
│ │ │ └── IntentionWidget.tsx # ← NEW: Daily intention setter (Sunsama ritual)
│ │ ├── ErrorBoundary.tsx # Global crash handler with retry
│ │ ├── QuickAdd.tsx # ← NEW: Global Ctrl+K capture (Akiflow/Todoist style)
│ │ └── StatusBar.tsx # Online/offline banner + sync dot
│ ├── hooks/
│ │ └── useEasterEggs.ts # Fun hidden interactions
│ ├── lib/
│ │ ├── supabase.ts # Supabase client (env-gated)
│ │ └── sync.ts # Pull/push layer between Zustand ↔ Supabase
│ ├── pages/
│ │ ├── Auth.tsx # Sign in / Register / Email verification
│ │ ├── Calendar.tsx # Full calendar (month/week/day, recurring, sharing)
│ │ ├── Dashboard.tsx # Home with smart insights + all widgets
│ │ ├── Focus.tsx # Pomodoro timer (sessions tracked in store)
│ │ ├── Goals.tsx # Goal + milestone tracking (fully persisted)
│ │ ├── Habits.tsx # Habit tracker with forgiveness score + analytics
│ │ ├── Journal.tsx # Daily journal + mood grid + habit correlation
│ │ ├── Notes.tsx # Markdown notes editor (DOMPurify sanitized)
│ │ ├── Settings.tsx # Theme, name, preferences
│ │ └── Tasks.tsx # Task manager + time estimates (list + kanban)
│ ├── stores/
│ │ ├── useAppStore.ts # All app state (Zustand + localStorage v4)
│ │ └── useAuthStore.ts # Auth state (Supabase session)
│ ├── types/
│ │ └── index.ts # Shared TypeScript interfaces
│ ├── utils/
│ │ └── cn.ts # Class utilities + nanoid
│ ├── App.tsx # Root layout, routing, auth gate, QuickAdd
│ └── main.tsx # React entry point
├── .env.local # 🔒 Never commit — Supabase keys here
├── README.md # This file
├── ROADMAP.md # Stage tracker + future plans
├── package.json
├── tailwind.config.ts
├── tsconfig.app.json
└── vite.config.ts
┌─────────────────────────────────────────────────────┐
│ USER (Browser / PWA) │
│ │
│ ┌─────────────┐ ┌───────────────────────────┐ │
│ │ React UI │◄──│ Zustand Store (persist) │ │
│ │ (pages + │ │ localStorage (offline) │ │
│ │ widgets) │──►│ version 3, migrated │ │
│ └──────┬──────┘ └────────────┬──────────────┘ │
│ │ │ │
│ │ user actions │ pull / push │
│ │ ▼ │
│ │ ┌────────────────────────────┐ │
│ │ │ sync.ts layer │ │
│ │ │ pullAll() / pushAll() │ │
│ │ │ subscribeRealtime() │ │
│ │ └────────────┬───────────────┘ │
│ │ │ │
└──────────┼───────────────────────┼───────────────────┘
│ │ Supabase JS SDK
▼ ▼
┌──────────────────────────────────────────────────────┐
│ SUPABASE │
│ │
│ ┌──────────┐ ┌──────────────┐ ┌───────────────┐ │
│ │ Auth │ │ PostgreSQL │ │ Realtime │ │
│ │ (email │ │ (10 tables) │ │ (live sync │ │
│ │ + OAuth)│ │ + RLS │ │ across tabs) │ │
│ └──────────┘ └──────────────┘ └───────────────┘ │
└──────────────────────────────────────────────────────┘
- Offline-first: All reads/writes hit Zustand → persisted to
localStorage - On login:
pullAll()fetches from Supabase and merges into store - On changes: debounced
pushAll()syncs to Supabase in the background - Realtime:
subscribeRealtime()listens for changes from other devices - Auth gate: If Supabase is configured and no session exists, the Auth page is shown
- All Supabase tables have Row Level Security (RLS) — users can only read/write their own data
- Markdown preview is sanitized with DOMPurify to prevent XSS attacks
- Auth tokens are managed by Supabase JS SDK (HttpOnly cookies in production)
- No user data is ever sent to third-party services (GIFs are fetched client-side via GIPHY)
- Node.js 18+
- npm 9+
# 1. Clone the repo
git clone <your-repo-url>
cd bloom
# 2. Install dependencies
npm install --legacy-peer-deps
# 3. Set up environment variables
cp .env.example .env.local
# Fill in your Supabase URL + anon key (optional — app works without it)
# 4. Run the dev server
npm run devThe app runs at http://localhost:5173.
Without Supabase: The app works fully offline — data is stored in
localStorage. You can skip the.env.localstep entirely and use the app as a local tool.
npm run build
# Output: dist/# .env.local
VITE_SUPABASE_URL=https://your-project.supabase.co
VITE_SUPABASE_ANON_KEY=your-anon-key-here
VITE_GIPHY_KEY=your-giphy-api-key-here # optional, for GIF picker in notes- Create a new project at supabase.com
- Go to SQL Editor → New Query
- Paste and run the full contents of
supabase/schema.sql - Go to Database → Replication and enable Realtime for all tables
- (Optional) Enable storage bucket for avatar uploads (instructions in schema.sql comments)
Bloom supports three built-in themes, switchable from Settings:
| Theme | Description |
|---|---|
pink |
Soft rose & sakura (default) |
dark |
Deep plum night mode |
light |
Clean white minimal |
Themes are applied via CSS custom properties on [data-theme] attribute.
Bloom is a full Progressive Web App:
- Android / Samsung Tab: Open in Chrome → "Add to Home Screen"
- iPhone / iPad: Open in Safari → Share → "Add to Home Screen"
- Desktop (Mac/Windows): Chrome/Edge address bar → Install icon
Once installed, the app works completely offline.
Made By Cengiz 💕