import streamlit as st import json import os from datetime import datetime, timedelta import pandas as pd import plotly.express as px from plotly.subplots import make_subplots import plotly.graph_objects as go # Page config st.set_page_config( page_title="Atomic Habits Tracker", page_icon="🎯", layout="wide", initial_sidebar_state="expanded" ) # Custom CSS for Atomic Habits styling st.markdown(""" """, unsafe_allow_html=True) # Data persistence HABITS_FILE = "habits_data.json" LOGS_FILE = "habits_log.json" def load_data(): """Load habits and logs from JSON""" habits = {} logs = {} if os.path.exists(HABITS_FILE): with open(HABITS_FILE, 'r') as f: habits = json.load(f) if os.path.exists(LOGS_FILE): with open(LOGS_FILE, 'r') as f: logs = json.load(f) return habits, logs def save_data(habits, logs): """Save to JSON files""" with open(HABITS_FILE, 'w') as f: json.dump(habits, f, indent=2) with open(LOGS_FILE, 'w') as f: json.dump(logs, f, indent=2) # Initialize data if 'habits' not in st.session_state: st.session_state.habits, st.session_state.logs = load_data() habits = st.session_state.habits logs = st.session_state.logs # Helper functions def get_today(): return datetime.now().strftime("%Y-%m-%d") def get_yesterday(): return (datetime.now() - timedelta(days=1)).strftime("%Y-%m-%d") def calculate_streak(habit_id): """Calculate current streak for a habit""" if habit_id not in logs: return 0 dates = sorted(logs[habit_id].keys(), reverse=True) if not dates: return 0 today = get_today() yesterday = get_yesterday() # If nothing logged today, check if we can continue from yesterday if today not in logs[habit_id]: if yesterday not in logs[habit_id]: return 0 streak = 0 check_date = datetime.now() # If missed today, start counting from yesterday if today not in logs[habit_id]: check_date = datetime.now() - timedelta(days=1) while True: date_str = check_date.strftime("%Y-%m-%d") if date_str in logs[habit_id]: status = logs[habit_id][date_str].get('status') if status in ['completed', 'two_minute']: streak += 1 check_date -= timedelta(days=1) else: break else: break return streak def missed_yesterday(habit_id): """Check if habit was missed yesterday""" yesterday = get_yesterday() if habit_id not in logs or yesterday not in logs[habit_id]: return True return logs[habit_id][yesterday].get('status') == 'missed' # Sidebar - Add New Habit (Identity Design) with st.sidebar: st.header("🆕 Design New Habit") st.markdown("**Remember:** Focus on *identity*, not outcomes.") with st.form("new_habit"): habit_name = st.text_input("Habit Name", placeholder="e.g., Read 30 pages") identity = st.text_input("Identity Label", placeholder="e.g., Reader") st.markdown("**Habit Stack** (Implementation Intention)") anchor = st.text_input("After I...", placeholder="pour my morning coffee") behavior = st.text_input("I will...", placeholder="read one page") st.markdown("**Environment Design**") environment = st.text_input("Environment Cue", placeholder="Book on pillow") st.markdown("**The 2-Minute Rule**") two_min = st.text_input("2-Minute Version", placeholder="Open the book") submitted = st.form_submit_button("Create Habit", use_container_width=True) if submitted and habit_name and identity: habit_id = f"habit_{datetime.now().timestamp()}" habits[habit_id] = { "name": habit_name, "identity": identity, "anchor": anchor, "behavior": behavior, "environment": environment, "two_minute": two_min, "created": get_today() } save_data(habits, logs) st.success(f"Created identity: I am a {identity}") st.rerun() # Main Layout st.title("🎯 Atomic Habits Tracker") st.markdown("*Every action you take is a vote for the type of person you wish to become.*") # Today's Check-in Section st.header("📅 Today's Vote") today = get_today() cols = st.columns(2) if not habits: st.info("👈 Create your first identity-based habit in the sidebar") else: for idx, (habit_id, habit) in enumerate(habits.items()): with cols[idx % 2]: # Identity Card streak = calculate_streak(habit_id) st.markdown(f"""
"After I {habit['anchor']}, I will {habit['behavior']}"
🔥 {streak} day streak