Spaces:
Sleeping
Sleeping
| import streamlit as st | |
| import pandas as pd | |
| from datetime import datetime | |
| import time | |
| import os | |
| from io import BytesIO | |
| from fpdf import FPDF | |
| import plotly.express as px | |
| # --- 1. PAGE CONFIGURATION --- | |
| st.set_page_config(page_title="The Task Tracker", page_icon="π‘οΈ", layout="wide") | |
| # --- 2. CSS STYLING --- | |
| st.markdown(""" | |
| <style> | |
| html, body, [class*="css"] { font-family: 'Times New Roman', Times, serif; } | |
| .stApp { background-color: #F5F5DC; color: #001f3f; } | |
| .shield-header { | |
| background: linear-gradient(135deg, #001f3f 0%, #003366 100%); | |
| padding: 30px; border-radius: 12px; color: #F5F5DC; | |
| display: flex; align-items: center; justify-content: center; | |
| border-bottom: 5px solid #C0B283; margin-bottom: 30px; | |
| box-shadow: 0 10px 25px rgba(0,0,0,0.3); | |
| } | |
| .shield-icon { font-size: 5rem; margin-right: 25px; } | |
| .title-block h1 { font-weight: 900; letter-spacing: 4px; margin: 0; font-size: 3rem; text-transform: uppercase; color: #F5F5DC; } | |
| .title-block p { font-size: 1.1rem; font-style: italic; color: #E0D6B9; margin-top: 5px; } | |
| .stButton>button { background-color: #001f3f; color: #F5F5DC; border-radius: 4px; border: 1px solid #C0B283; font-weight: bold; } | |
| .stButton>button:hover { background-color: #003366; color: white; } | |
| </style> | |
| """, unsafe_allow_html=True) | |
| # --- 3. BACKEND FUNCTIONS --- | |
| DATA_FILE = "task_tracker_shield.csv" | |
| def load_data(): | |
| if os.path.exists(DATA_FILE): | |
| return pd.read_csv(DATA_FILE) | |
| return pd.DataFrame(columns=["Date", "Category", "Task", "Status"]) | |
| def save_data(df): | |
| df.to_csv(DATA_FILE, index=False) | |
| def to_excel(df): | |
| output = BytesIO() | |
| with pd.ExcelWriter(output, engine='openpyxl') as writer: | |
| df.to_excel(writer, index=False, sheet_name='Sheet1') | |
| return output.getvalue() | |
| def to_pdf(df, start, end): | |
| pdf = FPDF() | |
| pdf.add_page() | |
| pdf.set_font("Times", 'B', 20) | |
| pdf.set_text_color(0, 31, 63) | |
| pdf.cell(200, 15, txt="OFFICIAL SHIELD REPORT", ln=1, align='C') | |
| pdf.set_font("Times", 'I', 12) | |
| pdf.cell(200, 10, txt=f"Period: {start} to {end}", ln=1, align='C') | |
| pdf.ln(10) | |
| pdf.set_font("Times", size=10) | |
| for col in ["Date", "Category", "Task", "Status"]: | |
| pdf.cell(45, 10, col, 1) | |
| pdf.ln() | |
| for _, row in df.iterrows(): | |
| for val in [row['Date'], row['Category'], str(row['Task'])[:20], row['Status']]: | |
| pdf.cell(45, 10, str(val), 1) | |
| pdf.ln() | |
| return pdf.output(dest='S').encode('latin-1') | |
| # --- 4. UI LOGIC --- | |
| st.markdown(""" | |
| <div class="shield-header"> | |
| <div class="shield-icon">π‘οΈ</div> | |
| <div class="title-block"> | |
| <h1>THE TASK TRACKER</h1> | |
| <p>Planning, Focus, Discipline & Execution β these are the Mantras of the life.</p> | |
| </div> | |
| </div> | |
| """, unsafe_allow_html=True) | |
| df = load_data() | |
| today_str = datetime.now().strftime("%Y-%m-%d") | |
| tab_planner, tab_analytics = st.tabs(["π DAILY OPERATIONS", "π PERFORMANCE METRICS"]) | |
| with tab_planner: | |
| st.markdown("### π New Protocol") | |
| c1, c2, c3 = st.columns([2, 1, 1]) | |
| with c1: new_task = st.text_input("Directive Description", placeholder="Enter mission objective...") | |
| with c2: category = st.selectbox("Category", ["Work πΌ", "Personal π ", "Finance π°", "Health πͺ", "Critical β‘"]) | |
| with c3: | |
| st.write(" ") | |
| if st.button("INITIATE", use_container_width=True): | |
| if new_task: | |
| clean_cat = category.split(" ")[0] | |
| new_entry = pd.DataFrame([{"Date": today_str, "Category": clean_cat, "Task": new_task, "Status": "Pending"}]) | |
| df = pd.concat([df, new_entry], ignore_index=True) | |
| save_data(df) | |
| st.rerun() | |
| st.divider() | |
| today_tasks = df[df['Date'] == today_str] | |
| if not today_tasks.empty: | |
| total = len(today_tasks) | |
| done = len(today_tasks[today_tasks['Status'] == "Completed"]) | |
| st.progress(int((done/total)*100) if total > 0 else 0) | |
| for index, row in today_tasks.iterrows(): | |
| col1, col2 = st.columns([3, 2]) | |
| with col1: st.write(f"β ~~{row['Task']}~~" if row['Status']=="Completed" else f"**{row['Task']}**") | |
| with col2: | |
| new_status = st.radio("Status", ["Pending", "Completed", "Missed"], key=f"r_{index}", index=["Pending", "Completed", "Missed"].index(row['Status']), horizontal=True, label_visibility="collapsed") | |
| if new_status != row['Status']: | |
| df.at[index, 'Status'] = new_status | |
| save_data(df) | |
| if new_status == "Completed": | |
| if len(df[(df['Date'] == today_str) & (df['Status'] == "Completed")]) == total: | |
| st.balloons() | |
| st.snow() | |
| else: | |
| st.toast("π₯ BOOM!", icon="π") | |
| time.sleep(0.5) | |
| st.rerun() | |
| else: | |
| st.info("No active protocols.") | |
| with tab_analytics: | |
| st.header("π Performance Analytics") | |
| d1, d2 = st.columns(2) | |
| start = d1.date_input("Start", value=datetime.now()) | |
| end = d2.date_input("End", value=datetime.now()) | |
| mask = (df['Date'] >= str(start)) & (df['Date'] <= str(end)) | |
| f_df = df.loc[mask] | |
| if not f_df.empty: | |
| c1, c2, c3 = st.columns(3) | |
| c1.metric("Total", len(f_df)) | |
| c2.metric("Executed", len(f_df[f_df['Status']=="Completed"])) | |
| c3.metric("Failed", len(f_df[f_df['Status']=="Missed"])) | |
| fig = px.bar(f_df.groupby(['Date', 'Status']).size().reset_index(name='Count'), x="Date", y="Count", color="Status", barmode="group", color_discrete_map={"Completed": "#001f3f", "Missed": "#8B0000", "Pending": "#C0B283"}) | |
| st.plotly_chart(fig, use_container_width=True) | |
| st.download_button("Export Excel", data=to_excel(f_df), file_name="Data.xlsx") | |
| st.download_button("Export PDF", data=to_pdf(f_df, start, end), file_name="Report.pdf") |