CoolFace
Apppublic

saiganesh2004/Test-fitplan-2

sourceHugging Faceupdated 7mo agoView on Hugging Face
0likes
ui.py383 linesDownload Raw Back to utils
1"""2ui.py — Expert-level dark design system with fixed calendar + vivid components.3"""4 5BASE_CSS = """6<style>7@import url('https://fonts.googleapis.com/css2?family=Syne:wght@400;600;700;800&family=DM+Sans:opsz,wght@9..40,300;9..40,400;9..40,500;9..40,600;9..40,700&family=JetBrains+Mono:wght@400;500&display=swap');8 9:root {10  --bg:       #07070f;11  --bg2:      #0d0d1a;12  --bg3:      #13132a;13  --bg4:      #1a1a35;14  --border:   rgba(120,119,198,0.18);15  --border2:  rgba(120,119,198,0.35);16  --accent:   #7c7cf7;17  --accent2:  #a78bfa;18  --green:    #10d9a0;19  --amber:    #f59e0b;20  --red:      #f43f5e;21  --text:     #eeeeff;22  --text2:    rgba(238,238,255,0.75);23  --muted:    rgba(238,238,255,0.45);24  --muted2:   rgba(238,238,255,0.25);25  --muted3:   rgba(238,238,255,0.12);26  --radius:   14px;27  --radius-sm:9px;28  --font-head:'Syne', sans-serif;29  --font-body:'DM Sans', sans-serif;30  --font-mono:'JetBrains Mono', monospace;31}32 33#MainMenu,footer,header,34[data-testid="stToolbar"],35[data-testid="stDecoration"],36[data-testid="stSidebarNav"],37section[data-testid="stSidebar"] { display:none!important; }38 39html,body { background:#07070f!important; }40 41.stApp,42[data-testid="stAppViewContainer"],43[data-testid="stAppViewContainer"]>section {44  background:#07070f!important;45  color:#eeeeff!important;46  font-family:'DM Sans',sans-serif!important;47}48 49[data-testid="stAppViewContainer"]>section>div.block-container {50  max-width:1220px!important;51  margin:0 auto!important;52  padding:0 28px 100px!important;53  background:transparent!important;54}55 56h1,h2,h3,h4 { font-family:'Syne',sans-serif!important; color:#eeeeff!important; }57 58[data-testid="stWidgetLabel"] p,59[data-testid="stWidgetLabel"] span,60.stTextInput>label, .stNumberInput>label,61.stSelectbox>label, .stMultiSelect>label,62.stCheckbox>label, .stRadio>label {63  color:rgba(238,238,255,0.55)!important;64  font-size:0.70rem!important; font-weight:600!important;65  letter-spacing:1.8px!important; text-transform:uppercase!important;66}67 68div[data-baseweb="input"]>div,69div[data-baseweb="textarea"]>div {70  background:#0f0f22!important;71  border:1.5px solid rgba(120,119,198,0.22)!important;72  border-radius:9px!important; transition:all 0.2s!important;73}74div[data-baseweb="input"]:focus-within>div,75div[data-baseweb="textarea"]:focus-within>div {76  border-color:#7c7cf7!important;77  box-shadow:0 0 0 3px rgba(124,124,247,0.15)!important;78  background:#13132a!important;79}80div[data-baseweb="input"] input,81div[data-baseweb="textarea"] textarea {82  background:transparent!important; color:#eeeeff!important;83  font-family:'DM Sans',sans-serif!important; font-size:0.92rem!important;84}85div[data-baseweb="input"] input::placeholder { color:rgba(238,238,255,0.22)!important; }86 87div[data-baseweb="select"]>div {88  background:#0f0f22!important;89  border:1.5px solid rgba(120,119,198,0.22)!important;90  border-radius:9px!important; color:#eeeeff!important; transition:all 0.2s!important;91}92div[data-baseweb="select"]>div:focus-within {93  border-color:#7c7cf7!important; box-shadow:0 0 0 3px rgba(124,124,247,0.15)!important;94}95div[data-baseweb="select"] span { color:#eeeeff!important; }96div[data-baseweb="popover"] {97  background:#0d0d1a!important;98  border:1px solid rgba(120,119,198,0.28)!important;99  border-radius:12px!important; box-shadow:0 24px 64px rgba(0,0,0,0.85)!important;100}101li[role="option"] {102  color:rgba(238,238,255,0.45)!important;103  font-family:'DM Sans',sans-serif!important;104  border-radius:6px!important; margin:2px 6px!important;105}106li[role="option"]:hover { background:rgba(124,124,247,0.18)!important; color:#eeeeff!important; }107li[aria-selected="true"] { background:rgba(124,124,247,0.25)!important; color:#eeeeff!important; }108 109div[data-baseweb="multi-select"]>div {110  background:#0f0f22!important;111  border:1.5px solid rgba(120,119,198,0.22)!important;112  border-radius:9px!important; min-height:46px!important;113}114span[data-baseweb="tag"] {115  background:rgba(124,124,247,0.20)!important;116  border:1px solid rgba(124,124,247,0.38)!important; border-radius:5px!important;117}118span[data-baseweb="tag"] span { color:#eeeeff!important; font-size:0.80rem!important; }119 120[data-testid="stCheckbox"] label {121  color:rgba(238,238,255,0.75)!important; font-size:0.88rem!important;122  letter-spacing:0!important; text-transform:none!important; font-weight:400!important;123}124 125.stButton>button {126  background:linear-gradient(135deg,#5b5bd6,#7c3aed)!important;127  border:none!important; color:#fff!important; border-radius:9px!important;128  font-family:'DM Sans',sans-serif!important; font-size:0.87rem!important;129  font-weight:600!important; padding:11px 22px!important;130  letter-spacing:0.3px!important; transition:all 0.2s ease!important;131  box-shadow:0 4px 18px rgba(91,91,214,0.35)!important;132}133.stButton>button:hover {134  transform:translateY(-2px)!important;135  box-shadow:0 10px 34px rgba(91,91,214,0.56)!important;136  filter:brightness(1.10)!important;137}138.stButton>button:active { transform:translateY(0)!important; }139 140.stTabs [data-baseweb="tab-list"] {141  background:#0d0d1a!important; border-radius:9px!important;142  padding:4px!important; gap:3px!important;143  border:1px solid rgba(120,119,198,0.18)!important;144}145.stTabs [data-baseweb="tab"] {146  background:transparent!important; color:rgba(238,238,255,0.45)!important;147  border-radius:6px!important; font-family:'DM Sans',sans-serif!important;148  font-size:0.84rem!important; font-weight:500!important;149  border:none!important; padding:9px 18px!important; transition:all 0.2s!important;150}151.stTabs [aria-selected="true"] {152  background:linear-gradient(135deg,#5b5bd6,#7c3aed)!important;153  color:#fff!important; box-shadow:0 2px 14px rgba(91,91,214,0.45)!important;154}155.stTabs [data-baseweb="tab-highlight"],156.stTabs [data-baseweb="tab-border"] { display:none!important; }157 158.stProgress>div>div {159  background:linear-gradient(90deg,#5b5bd6,#a78bfa)!important; border-radius:100px!important;160}161.stProgress>div { background:rgba(255,255,255,0.06)!important; border-radius:100px!important; }162 163.stAlert { border-radius:9px!important; font-size:0.88rem!important; }164hr { border-color:rgba(120,119,198,0.14)!important; margin:20px 0!important; }165 166::-webkit-scrollbar { width:5px; height:5px; }167::-webkit-scrollbar-track { background:#07070f; }168::-webkit-scrollbar-thumb { background:rgba(124,124,247,0.30); border-radius:100px; }169::-webkit-scrollbar-thumb:hover { background:rgba(124,124,247,0.55); }170 171@keyframes fadeUp {172  from { opacity:0; transform:translateY(10px); }173  to   { opacity:1; transform:translateY(0); }174}175</style>176"""177 178 179def inject_css():180    import streamlit as st181    st.markdown(BASE_CSS, unsafe_allow_html=True)182 183 184# ──────────────────────────────────────────────────────────────────────────────185# COMPONENTS186# ──────────────────────────────────────────────────────────────────────────────187 188def stat_card(icon, label, value, sub="", accent="#7c7cf7", glow=True):189    r, g, b = _hex_to_rgb_tuple(accent)190    glow_css = f"box-shadow:0 0 28px rgba({r},{g},{b},0.22);" if glow else ""191    return f"""192<div style="background:#0f0f22;border:1px solid rgba({r},{g},{b},0.25);193  border-radius:14px;padding:22px 16px;text-align:center;position:relative;194  overflow:hidden;animation:fadeUp 0.4s ease;{glow_css}">195  <div style="position:absolute;top:0;left:15%;right:15%;height:2px;196    background:linear-gradient(90deg,transparent,{accent},transparent);opacity:0.8"></div>197  <div style="font-size:1.55rem;margin-bottom:10px;line-height:1">{icon}</div>198  <div style="font-family:'Syne',sans-serif;font-size:2.1rem;font-weight:800;199    color:{accent};line-height:1;letter-spacing:-1.5px">{value}</div>200  <div style="font-size:0.59rem;font-weight:700;letter-spacing:2.5px;201    text-transform:uppercase;color:rgba(238,238,255,0.38);margin-top:8px">{label}</div>202  {f'<div style="font-size:0.72rem;color:rgba(238,238,255,0.22);margin-top:3px">{sub}</div>' if sub else ''}203</div>"""204 205 206def section_header(title, sub="", icon=""):207    return f"""208<div style="display:flex;align-items:center;gap:13px;margin:30px 0 16px;animation:fadeUp 0.35s ease">209  <div style="width:3px;height:22px;background:linear-gradient(180deg,#5b5bd6,#a78bfa);210    border-radius:2px;flex-shrink:0"></div>211  <div>212    <div style="font-family:'Syne',sans-serif;font-size:1.08rem;font-weight:700;213      color:#eeeeff;line-height:1.15">{icon+' ' if icon else ''}{title}</div>214    {f'<div style="font-size:0.74rem;color:rgba(238,238,255,0.42);margin-top:3px">{sub}</div>' if sub else ''}215  </div>216</div>"""217 218 219def badge(text, color="#7c7cf7"):220    return (f'<span style="display:inline-flex;align-items:center;background:{color}1a;'221            f'border:1px solid {color}44;border-radius:5px;padding:2px 10px;'222            f'font-size:0.70rem;font-weight:700;color:{color}">{text}</span>')223 224 225def exercise_card(icon, name, sets, reps, rest, idx=0, desc=""):226    desc_html = (f'<div style="font-size:0.70rem;color:rgba(238,238,255,0.30);'227                 f'margin-top:3px;line-height:1.5">{desc}</div>') if desc else ""228    sets_reps = (f'<span style="background:rgba(124,124,247,0.14);border:1px solid rgba(124,124,247,0.26);'229                 f'border-radius:6px;padding:3px 10px;font-size:0.70rem;font-weight:700;'230                 f'color:#a78bfa">{sets}x{reps}</span>') if sets else ""231    rest_badge = (f'<span style="background:rgba(245,158,11,0.10);border:1px solid rgba(245,158,11,0.22);'232                  f'border-radius:6px;padding:3px 10px;font-size:0.70rem;font-weight:600;'233                  f'color:#f59e0b">{rest}</span>') if rest and rest != "." else ""234    return f"""235<div style="display:flex;align-items:center;gap:12px;padding:10px;236  border-radius:9px;background:rgba(255,255,255,0.025);237  border:1px solid rgba(120,119,198,0.10);margin-bottom:5px">238  <div style="width:34px;height:34px;border-radius:8px;flex-shrink:0;239    background:rgba(124,124,247,0.12);border:1px solid rgba(124,124,247,0.22);240    display:flex;align-items:center;justify-content:center;font-size:0.85rem">{icon}</div>241  <div style="flex:1;min-width:0">242    <div style="font-size:0.85rem;font-weight:600;color:#eeeeff;243      white-space:nowrap;overflow:hidden;text-overflow:ellipsis">{name}</div>244    {desc_html}245  </div>246  <div style="display:flex;gap:5px;flex-shrink:0">{sets_reps}{rest_badge}</div>247</div>"""248 249 250def progress_ring(pct, size=80, stroke=6, color="#7c7cf7"):251    r = (size - stroke) // 2252    circ = 2 * 3.14159 * r253    offset = circ * (1 - pct / 100)254    return f"""255<svg width="{size}" height="{size}" viewBox="0 0 {size} {size}">256  <circle cx="{size//2}" cy="{size//2}" r="{r}"257    fill="none" stroke="rgba(124,124,247,0.12)" stroke-width="{stroke}"/>258  <circle cx="{size//2}" cy="{size//2}" r="{r}"259    fill="none" stroke="{color}" stroke-width="{stroke}"260    stroke-dasharray="{circ:.1f}" stroke-dashoffset="{offset:.1f}"261    stroke-linecap="round" transform="rotate(-90 {size//2} {size//2})"/>262  <text x="50%" y="50%" text-anchor="middle" dominant-baseline="central"263    font-family="Syne,sans-serif" font-size="{size//5}" font-weight="800"264    fill="{color}">{pct}%</text>265</svg>"""266 267 268def calendar_widget(tracking, num_days, today_str):269    """270    Monthly calendar view showing full current month.271    Each cell displays the date number clearly, colored by workout status.272    """273    from datetime import date, timedelta274    import calendar as cal_mod275 276    today     = date.today()277    year      = today.year278    month     = today.month279    month_name = today.strftime("%B %Y")280    days_in_month  = cal_mod.monthrange(year, month)[1]281    first_weekday  = date(year, month, 1).weekday()   # 0=Mon … 6=Sun282 283    # ── Day-of-week header ────────────────────────────────────────────────────284    day_hdrs = "".join(285        f'<div style="text-align:center;font-size:0.63rem;font-weight:700;'286        f'letter-spacing:1px;text-transform:uppercase;'287        f'color:rgba(238,238,255,0.35);padding-bottom:6px">{d}</div>'288        for d in ["Mon","Tue","Wed","Thu","Fri","Sat","Sun"]289    )290 291    # ── Blank leading cells ───────────────────────────────────────────────────292    cells = "".join('<div></div>' for _ in range(first_weekday))293 294    # ── Day cells ─────────────────────────────────────────────────────────────295    for day_num in range(1, days_in_month + 1):296        d  = date(year, month, day_num)297        ds = d.isoformat()298        s  = tracking.get(ds, {}).get("status", "none")299        is_today  = (d == today)300        is_future = (d > today)301 302        # colors303        if is_future:304            bg      = "rgba(255,255,255,0.03)"305            num_col = "rgba(238,238,255,0.18)"306            bdr     = "rgba(255,255,255,0.05)"307        elif s == "done":308            bg      = "#3d3d9e"309            num_col = "#ffffff"310            bdr     = "#5b5bd6"311        elif s == "skipped":312            bg      = "rgba(245,158,11,0.22)"313            num_col = "#f5c842"314            bdr     = "rgba(245,158,11,0.50)"315        elif d < today:                        # missed316            bg      = "rgba(244,63,94,0.10)"317            num_col = "rgba(244,63,94,0.55)"318            bdr     = "rgba(244,63,94,0.22)"319        else:                                  # today, pending320            bg      = "rgba(124,124,247,0.20)"321            num_col = "#c4b5fd"322            bdr     = "rgba(124,124,247,0.60)"323 324        today_ring = (325            "box-shadow:0 0 0 2px #7c7cf7,0 0 14px rgba(124,124,247,0.40);"326        ) if is_today else ""327 328        # small status dot below number329        dot = ""330        if s == "done":331            dot = '<div style="width:4px;height:4px;border-radius:50%;background:rgba(255,255,255,0.65);margin:2px auto 0"></div>'332        elif s == "skipped":333            dot = '<div style="width:4px;height:4px;border-radius:50%;background:#f59e0b;margin:2px auto 0"></div>'334 335        cells += f"""<div title="{ds}"336  style="background:{bg};border:1px solid {bdr};border-radius:7px;337  min-height:40px;display:flex;flex-direction:column;align-items:center;338  justify-content:center;cursor:pointer;padding:4px 2px;{today_ring}339  transition:transform 0.15s,opacity 0.15s"340  onmouseover="this.style.transform='scale(1.08)'"341  onmouseout="this.style.transform='scale(1)'">342  <span style="font-size:0.84rem;font-weight:700;color:{num_col};line-height:1">{day_num}</span>343  {dot}344</div>"""345 346    # ── Legend + container ────────────────────────────────────────────────────347    return f"""348<div>349  <div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:12px">350    <span style="font-family:'Syne',sans-serif;font-size:0.90rem;font-weight:700;color:#eeeeff">{month_name}</span>351    <div style="display:flex;gap:12px">352      <span style="display:flex;align-items:center;gap:5px;font-size:0.62rem;color:rgba(238,238,255,0.40)">353        <span style="width:9px;height:9px;border-radius:2px;background:#3d3d9e;display:inline-block"></span>Done354      </span>355      <span style="display:flex;align-items:center;gap:5px;font-size:0.62rem;color:rgba(238,238,255,0.40)">356        <span style="width:9px;height:9px;border-radius:2px;background:rgba(245,158,11,0.55);display:inline-block"></span>Skipped357      </span>358      <span style="display:flex;align-items:center;gap:5px;font-size:0.62rem;color:rgba(238,238,255,0.40)">359        <span style="width:9px;height:9px;border-radius:2px;background:rgba(244,63,94,0.40);display:inline-block"></span>Missed360      </span>361    </div>362  </div>363  <div style="display:grid;grid-template-columns:repeat(7,1fr);gap:4px;margin-bottom:4px">364    {day_hdrs}365  </div>366  <div style="display:grid;grid-template-columns:repeat(7,1fr);gap:4px">367    {cells}368  </div>369</div>"""370 371 372# ── internal helpers ──────────────────────────────────────────────────────────373def _hex_to_rgb_tuple(hex_color):374    h = hex_color.lstrip('#')375    try:376        return int(h[0:2], 16), int(h[2:4], 16), int(h[4:6], 16)377    except Exception:378        return 124, 124, 247379 380def _hex_to_rgb(hex_color):381    r, g, b = _hex_to_rgb_tuple(hex_color)382    return f"{r},{g},{b}"383