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("""
🔐
Private Access
Enter your secret code
""", 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)