""" FocusTrack - Shared UI utilities, CSS themes, and helper functions. """ import streamlit as st from datetime import datetime, timedelta, date from typing import Optional import pandas as pd # ─── CSS Theme ─────────────────────────────────────────────────────────────── DARK_CSS = """ """ LIGHT_CSS = """ """ CATEGORY_COLORS = { "coding": "#22d3ee", "browsing": "#f59e0b", "communication": "#10b981", "design": "#a78bfa", "documents": "#fb923c", "media": "#f43f5e", "system": "#64748b", "idle": "#374151", "uncategorized": "#6366f1", } # ─── Helpers ───────────────────────────────────────────────────────────────── def fmt_duration(seconds: Optional[float]) -> str: """Format seconds to human-readable HH:MM or Xh Ym.""" if not seconds: return "0m" seconds = int(seconds) h, m = divmod(seconds // 60, 60) if seconds >= 3600 else (0, seconds // 60) if seconds >= 3600: return f"{h}h {m:02d}m" return f"{m}m {seconds % 60:02d}s" if m == 0 else f"{m}m" def fmt_duration_long(seconds: Optional[float]) -> str: if not seconds: return "0 min" seconds = int(seconds) h = seconds // 3600 m = (seconds % 3600) // 60 parts = [] if h: parts.append(f"{h}h") if m: parts.append(f"{m}m") return " ".join(parts) or "< 1m" def get_focus_score(focus_sec: float, total_sec: float) -> float: if not total_sec: return 0.0 return round((focus_sec / total_sec) * 100, 1) def privacy_badge(): """Render the privacy badge present on every screen.""" st.markdown("""
100% private  •  All data stays on your device
""", unsafe_allow_html=True) def page_header(title: str, subtitle: str = ""): """Render a styled page header.""" st.markdown(f"""

{title}

{"" if not subtitle else f'

{subtitle}

'}
""", unsafe_allow_html=True) def status_dot(status: str) -> str: colors = {"running": "#10b981", "paused": "#f59e0b", "stopped": "#f43f5e"} labels = {"running": "Tracking", "paused": "Paused", "stopped": "Stopped"} c = colors.get(status, "#6366f1") l = labels.get(status, status.title()) return f'● {l}' def category_pill(category: str) -> str: color = CATEGORY_COLORS.get(category, "#6366f1") return ( f'{category}' ) def get_db(): """Get cached database instance via session state.""" from database import Database if "db" not in st.session_state: db = Database() db.initialize() st.session_state.db = db return st.session_state.db def get_date_range(selection: str): today = date.today() if selection == "Today": start = datetime.combine(today, datetime.min.time()) end = datetime.combine(today, datetime.max.time()) elif selection == "Yesterday": y = today - timedelta(days=1) start = datetime.combine(y, datetime.min.time()) end = datetime.combine(y, datetime.max.time()) elif selection == "Last 7 days": start = datetime.combine(today - timedelta(days=6), datetime.min.time()) end = datetime.combine(today, datetime.max.time()) elif selection == "Last 30 days": start = datetime.combine(today - timedelta(days=29), datetime.min.time()) end = datetime.combine(today, datetime.max.time()) else: # Custom return None, None return start, end