import streamlit as st import base64 import os import time st.set_page_config(page_title="A Special Invitation 🌸", page_icon="🌸", layout="centered") # ── session state ────────────────────────────────────────────────────────────── PASSWORD = "0207" for k, v in { "authenticated": False, "show_yes": False, "showing_no": False, "no_index": 0, }.items(): if k not in st.session_state: st.session_state[k] = v # ── image helper ─────────────────────────────────────────────────────────────── SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) def img_to_b64(stem): for ext in (".jpeg", ".jpg", ".png"): for base in (SCRIPT_DIR, os.getcwd()): p = os.path.join(base, stem + ext) if os.path.exists(p): mime = "image/png" if ext == ".png" else "image/jpeg" with open(p, "rb") as f: return base64.b64encode(f.read()).decode(), mime return None, None # ── CSS ──────────────────────────────────────────────────────────────────────── st.markdown(""" """, unsafe_allow_html=True) # ── floating hearts ──────────────────────────────────────────────────────────── show_confetti = "true" if st.session_state.show_yes else "false" st.markdown(f""" """, unsafe_allow_html=True) # ══════════════════════════════════════════════════════════════════════════════ # LOGIN # ══════════════════════════════════════════════════════════════════════════════ if not st.session_state.authenticated: st.markdown("""
""", unsafe_allow_html=True) _, mid, _ = st.columns([1, 4, 1]) with mid: pwd = st.text_input("code", type="password", placeholder="✦ Access Code ✦", label_visibility="collapsed") if st.button("✦ Unlock ✦", use_container_width=True): if pwd == PASSWORD: st.session_state.authenticated = True st.rerun() else: st.error("Incorrect code 💔") st.stop() # ══════════════════════════════════════════════════════════════════════════════ # YES OVERLAY # ══════════════════════════════════════════════════════════════════════════════ if st.session_state.show_yes: b64, mime = img_to_b64("yes_image") img_tag = f'' if b64 \ else '
🌸
' st.markdown(f"""
{img_tag}

She said YES! 🎉🌹🤓

YAYYYYYY!!!!
You've made this Valentine's Day absolutely perfect. 🤓

""", unsafe_allow_html=True) st.stop() # ══════════════════════════════════════════════════════════════════════════════ # NO OVERLAY (Strictly Paired Logic) # ══════════════════════════════════════════════════════════════════════════════ if st.session_state.showing_no: # 1. Define strict pairs so they never desync # Format: (Image_Name, Text_Message) pairs = [ ("no1", "Why though... 🥺"), # 1st Click (Index 0) ("no2", "Really? 💔"), # 2nd Click (Index 1) ("no3", "My poor heart... 😭"), # 3rd Click (Index 2) ] # 2. Calculate Index # If index is 3, modulo 3 = 0 (Back to start). # If index is 50, modulo 3 = 2 (Correctly shows 3rd pair). idx = st.session_state.no_index % len(pairs) stem, t = pairs[idx] # 3. Load Image b64, mime = img_to_b64(stem) img_tag = f'' if b64 \ else '
😢
' # 4. Show Overlay st.markdown(f"""
{img_tag}

{t}

I'm not letting you leave until you say Yes. 😤
(Tap the X to try again)

""", unsafe_allow_html=True) if st.button("✕", key="close_overlay_btn"): st.session_state.showing_no = False st.session_state.no_index += 1 # Increment Counter st.rerun() st.stop() # ══════════════════════════════════════════════════════════════════════════════ # MAIN PAGE # ══════════════════════════════════════════════════════════════════════════════ st.markdown("""
🌹

A Special Request

Chondi, will you give me the honor of being your
platonic Valentine
this year?

♡   ♡   ♡

No pressure... but also, just a little. 🌸

""", unsafe_allow_html=True) # ── Dynamic Shrinking Logic ── click_count = st.session_state.no_index # Start at 100%, shrink by 15% each time, don't go below 20% scale_factor = max(0.2, 1.0 - (click_count * 0.15)) # CSS: Target NO button (2nd col) and YES button (1st col) st.markdown(f""" """, unsafe_allow_html=True) # ── Buttons ── c1, c2 = st.columns(2) with c1: if st.button("✦ Yes! ✦", key="yes_btn", use_container_width=True): st.session_state.show_yes = True st.rerun() with c2: if st.button("No", key="no_btn", use_container_width=True): st.session_state.showing_no = True st.rerun() # Guilt Trip Text (Synced Logic) # Define same messages for bottom text (can be different or same, but cycled safely) no_messages = [ "Are you sure? 🥺", "Please reconsider... 💔", "My heart is shattering...", "I'll wait forever 🌸", "Pretty please? 🙏", "This wasn't supposed to happen 😢", ] if st.session_state.no_index > 0: # Use modulo length of messages to ensure it never breaks idx = (st.session_state.no_index - 1) % len(no_messages) st.markdown(f"

{no_messages[idx]}

", unsafe_allow_html=True)