Spaces:
Sleeping
Sleeping
| import gradio as gr | |
| from PIL import Image | |
| from datetime import datetime | |
| from dateutil import relativedelta | |
| import os | |
| # Hardcoded wedding date | |
| WEDDING_DATE = "2025-11-25" | |
| # Create placeholder images for the gallery | |
| def create_placeholder_images(): | |
| """Create placeholder images for the gallery when local images aren't available""" | |
| placeholder_images = [] | |
| for i in range(4): # Create 4 placeholder images | |
| # Create a simple colored image with text | |
| img = Image.new('RGB', (300, 300), color=(255, 182, 193)) # Light pink background | |
| placeholder_images.append(img) | |
| return placeholder_images | |
| # Try to load local images, fallback to placeholders | |
| try: | |
| # Local image paths (replace these with your own) | |
| # image_paths = ["/Users/shubhamsetia/Downloads/WhatsApp Image 2025-03-31 at 21.57.39.jpeg", "/Users/shubhamsetia/Downloads/WhatsApp Image 2025-03-31 at 21.52.21.jpeg"] | |
| # images = [Image.open(img) for img in image_paths if os.path.exists(img)] | |
| # if not images: # If no local images found, use placeholders | |
| images = create_placeholder_images() | |
| except Exception as e: | |
| print(f"Error loading images: {e}") | |
| images = create_placeholder_images() | |
| def calculate_time_remaining(): | |
| """ | |
| Calculates time until WEDDING_DATE (YYYY-MM-DD). | |
| Returns a formatted "X years, Y months, Z days..." | |
| or "The Wedding Day Has Arrived!" if the date is in the past. | |
| """ | |
| try: | |
| wedding_date = datetime.strptime(WEDDING_DATE, "%Y-%m-%d") | |
| now = datetime.now() | |
| if now > wedding_date: | |
| return "The Wedding Day Has Arrived! π" | |
| diff = relativedelta.relativedelta(wedding_date, now) | |
| return ( | |
| f"{diff.years} years, {diff.months} months, {diff.days} days, " | |
| f"{diff.hours} hours, {diff.minutes} minutes, {diff.seconds} seconds" | |
| ) | |
| except Exception as e: | |
| return f"Error calculating time remaining: {e}" | |
| # ------------------------------------------------------------------------------ | |
| # THEME: Pale Pink Background -> White Card Container -> Pink Title Headers | |
| # ------------------------------------------------------------------------------ | |
| custom_css = """ | |
| /* Entire Gradio background: pale pink */ | |
| .gradio-container { | |
| background-color: #FFE6EE !important; | |
| font-family: 'Trebuchet MS', sans-serif; | |
| color: #000000 !important; /* Default text black for strong contrast */ | |
| } | |
| /* Main "card" container: white background, black text */ | |
| .wedding-container { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| padding: 30px; | |
| background-color: #FFFFFF; | |
| border-radius: 20px; | |
| box-shadow: 0 10px 30px rgba(0,0,0,0.1); | |
| margin: 20px auto; | |
| max-width: 900px; | |
| } | |
| /* HEADERS with a darker pink background + white text */ | |
| .wedding-title { | |
| display: inline-block; /* Let us style the background behind the text */ | |
| background-color: #d13078; /* Bold pink */ | |
| color: #FFFFFF !important; /* White text */ | |
| padding: 10px 20px; | |
| border-radius: 10px; | |
| font-size: 36px; | |
| font-weight: bold; | |
| margin-bottom: 20px; | |
| text-align: center; | |
| text-shadow: none; | |
| } | |
| .gallery-header { | |
| display: inline-block; | |
| background-color: #d13078; | |
| color: #FFFFFF !important; | |
| padding: 8px 16px; | |
| border-radius: 8px; | |
| font-size: 24px; | |
| font-weight: bold; | |
| margin: 20px 0; | |
| text-align: center; | |
| text-shadow: none; | |
| } | |
| /* Countdown container: bold pink (#E91E63) with white text inside */ | |
| .countdown-container { | |
| background-color: #E91E63; | |
| border-radius: 15px; | |
| padding: 20px; | |
| margin-bottom: 30px; | |
| width: 100%; | |
| text-align: center; | |
| box-shadow: 0 5px 15px rgba(0,0,0,0.15); | |
| color: #FFFFFF !important; | |
| } | |
| /* Title inside countdown box */ | |
| .countdown-title { | |
| font-size: 28px; | |
| margin-bottom: 10px; | |
| font-weight: bold; | |
| color: #FFFFFF !important; | |
| } | |
| /* Subtitle includes the countdown text */ | |
| .countdown-subtitle { | |
| font-size: 20px; | |
| margin-bottom: 20px; | |
| color: #FFFFFF !important; | |
| } | |
| /* Wedding date text inside countdown box */ | |
| .countdown-date { | |
| font-size: 20px; | |
| color: #FFFFFF !important; | |
| margin-top: 10px; | |
| } | |
| /* Refresh button: darker pink with white text */ | |
| .refresh-button { | |
| background-color: #C2185B !important; | |
| color: #FFFFFF !important; | |
| border: none !important; | |
| padding: 10px 20px !important; | |
| border-radius: 8px !important; | |
| font-size: 16px !important; | |
| cursor: pointer !important; | |
| transition: background-color 0.3s ease !important; | |
| box-shadow: 0 3px 10px rgba(0,0,0,0.1) !important; | |
| margin-top: 10px !important; | |
| } | |
| .refresh-button:hover { | |
| background-color: #A0134D !important; | |
| } | |
| /* Floating hearts animation */ | |
| .floating-hearts { | |
| position: relative; | |
| height: 50px; | |
| margin: 10px 0; | |
| } | |
| @keyframes float { | |
| 0% { transform: translateY(0) rotate(0deg); opacity: 1; } | |
| 100% { transform: translateY(-60px) rotate(20deg); opacity: 0; } | |
| } | |
| .heart { | |
| position: absolute; | |
| font-size: 24px; | |
| animation: float 4s infinite; | |
| } | |
| /* Heartbeat effect on the celebration icon */ | |
| @keyframes heartbeat { | |
| 0%, 100% { transform: scale(1); } | |
| 50% { transform: scale(1.1); } | |
| } | |
| .heartbeat { | |
| animation: heartbeat 1.5s infinite ease-in-out; | |
| display: inline-block; | |
| } | |
| /* Gallery container: white background + subtle shadow */ | |
| .gr-gallery { | |
| background-color: #ffffff; | |
| border-radius: 10px; | |
| padding: 10px; | |
| box-shadow: 0 3px 10px rgba(0,0,0,0.1); | |
| } | |
| """ | |
| with gr.Blocks(css=custom_css) as app: | |
| with gr.Column(elem_classes=["wedding-container"]): | |
| # Title with darker pink background + white text | |
| gr.Markdown("# Wedding Countdown Gallery", elem_classes=["wedding-title"]) | |
| # Floating hearts | |
| gr.HTML(""" | |
| <div class="floating-hearts"> | |
| <span class="heart" style="left: 10%; animation-delay: 0s;">β€οΈ</span> | |
| <span class="heart" style="left: 30%; animation-delay: 1s;">π</span> | |
| <span class="heart" style="left: 50%; animation-delay: 2s;">π</span> | |
| <span class="heart" style="left: 70%; animation-delay: 1.5s;">π</span> | |
| <span class="heart" style="left: 90%; animation-delay: 0.5s;">π</span> | |
| </div> | |
| """) | |
| # Countdown Section | |
| with gr.Column(elem_classes=["countdown-container"]): | |
| gr.Markdown( | |
| "## Congratulations on Your Wedding! <span class='heartbeat'>π</span> <br> Harshita and Prasuk", | |
| elem_classes=["countdown-title"] | |
| ) | |
| gr.Markdown(f"Wedding Date: **{WEDDING_DATE}**", elem_classes=["countdown-date"]) | |
| countdown_display = gr.Markdown( | |
| f"### {calculate_time_remaining()}", | |
| elem_classes=["countdown-subtitle"] | |
| ) | |
| # Refresh button | |
| timer = gr.Timer(value=1.0) | |
| timer.tick(fn=calculate_time_remaining, inputs=None, outputs=countdown_display) | |
| gr.Markdown( | |
| f"""### Message to Prasuk: <br> | |
| some message. <br> | |
| ### Message to Harshita: <br> | |
| some message. | |
| ### Message to Prasuk and Harshita: <br> | |
| some message.""", | |
| elem_classes=["countdown-subtitle"] | |
| ) | |
| # refresh_button = gr.Button("Update Countdown β€οΈ", elem_classes=["refresh-button"]) | |
| # refresh_button.click(fn=calculate_time_remaining, inputs=None, outputs=countdown_display) | |
| # Photo Gallery with pink background + white text for the heading | |
| gr.Markdown("## Wedding Photos πΈ", elem_classes=["gallery-header"]) | |
| gr.Gallery( | |
| value=images, | |
| columns=2, | |
| rows=2, | |
| object_fit="contain", | |
| height="500px" | |
| ) | |
| gr.HTML(""" | |
| <div class="floating-hearts"> | |
| <span class="heart" style="left: 10%; animation-delay: 0s;">β€οΈ</span> | |
| <span class="heart" style="left: 30%; animation-delay: 1s;">π</span> | |
| <span class="heart" style="left: 50%; animation-delay: 2s;">π</span> | |
| <span class="heart" style="left: 70%; animation-delay: 1.5s;">π</span> | |
| <span class="heart" style="left: 90%; animation-delay: 0.5s;">π</span> | |
| </div> | |
| """) | |
| # Update the countdown on page load | |
| app.load(fn=calculate_time_remaining, outputs=countdown_display) | |
| if __name__ == "__main__": | |
| app.launch(auth=("prasuk", "prasuk"), ssr_mode=False) | |
| # app.launch() | |