Spaces:
Running
Running
Commit
Β·
b08ff4e
1
Parent(s):
70dfac7
Fix mobile layout - shift input up, ensure send button and model selector visible
Browse files- app.py +86 -39
- memory-bank/activeContext.md +25 -8
- memory-bank/progress.md +21 -7
- memory-bank/systemPatterns.md +28 -7
app.py
CHANGED
|
@@ -623,11 +623,12 @@ label {
|
|
| 623 |
cursor: text !important;
|
| 624 |
}
|
| 625 |
|
| 626 |
-
/*
|
| 627 |
-
.
|
| 628 |
display: flex !important;
|
| 629 |
align-items: center !important;
|
| 630 |
justify-content: flex-start !important;
|
|
|
|
| 631 |
gap: 4px !important;
|
| 632 |
padding: 0 !important;
|
| 633 |
margin: 0 !important;
|
|
@@ -635,6 +636,23 @@ label {
|
|
| 635 |
border: none !important;
|
| 636 |
}
|
| 637 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 638 |
.input-actions-row > * {
|
| 639 |
background: transparent !important;
|
| 640 |
}
|
|
@@ -1586,35 +1604,51 @@ textarea::placeholder {
|
|
| 1586 |
display: inline !important;
|
| 1587 |
}
|
| 1588 |
|
| 1589 |
-
/* Gemini input - mobile */
|
| 1590 |
.input-container-gemini {
|
| 1591 |
-
padding:
|
|
|
|
| 1592 |
position: sticky !important;
|
| 1593 |
bottom: 0 !important;
|
| 1594 |
z-index: 100 !important;
|
|
|
|
| 1595 |
}
|
| 1596 |
|
| 1597 |
.input-box-gemini {
|
| 1598 |
-
padding: 10px
|
| 1599 |
-
border-radius:
|
| 1600 |
max-width: 100% !important;
|
|
|
|
|
|
|
| 1601 |
}
|
| 1602 |
|
| 1603 |
.input-textarea-gemini textarea {
|
| 1604 |
font-size: 16px !important;
|
| 1605 |
-webkit-appearance: none !important;
|
|
|
|
|
|
|
| 1606 |
}
|
| 1607 |
|
| 1608 |
-
|
|
|
|
| 1609 |
gap: 2px !important;
|
| 1610 |
flex-wrap: wrap !important;
|
| 1611 |
-
justify-content:
|
| 1612 |
}
|
| 1613 |
|
| 1614 |
/* Preprompt icons - mobile */
|
| 1615 |
.preprompt-icon {
|
| 1616 |
padding: 3px 6px !important;
|
| 1617 |
font-size: 14px !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1618 |
}
|
| 1619 |
|
| 1620 |
.action-spacer {
|
|
@@ -1624,24 +1658,30 @@ textarea::placeholder {
|
|
| 1624 |
/* Model selector on mobile - ensure visible */
|
| 1625 |
.model-selector-simple {
|
| 1626 |
flex-shrink: 0 !important;
|
| 1627 |
-
min-width:
|
| 1628 |
-
max-width:
|
| 1629 |
}
|
| 1630 |
|
| 1631 |
.model-selector-simple [data-testid="dropdown"] {
|
| 1632 |
padding: 6px 10px !important;
|
| 1633 |
-
font-size:
|
| 1634 |
-
min-width:
|
| 1635 |
}
|
| 1636 |
|
| 1637 |
#send-button,
|
| 1638 |
.send-button-inline {
|
| 1639 |
-
width:
|
| 1640 |
-
height:
|
| 1641 |
-
min-width:
|
| 1642 |
-
border-radius:
|
| 1643 |
-
font-size:
|
| 1644 |
flex-shrink: 0 !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1645 |
}
|
| 1646 |
|
| 1647 |
/* Code blocks - mobile scroll */
|
|
@@ -1752,23 +1792,32 @@ textarea::placeholder {
|
|
| 1752 |
display: inline !important;
|
| 1753 |
}
|
| 1754 |
|
| 1755 |
-
/* Gemini input - small phones */
|
| 1756 |
.input-container-gemini {
|
| 1757 |
-
padding:
|
|
|
|
| 1758 |
}
|
| 1759 |
|
| 1760 |
.input-box-gemini {
|
| 1761 |
-
padding: 8px
|
| 1762 |
-
border-radius:
|
|
|
|
| 1763 |
}
|
| 1764 |
|
| 1765 |
.input-textarea-gemini textarea {
|
| 1766 |
font-size: 15px !important;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1767 |
}
|
| 1768 |
|
| 1769 |
.preprompt-icon {
|
| 1770 |
-
padding: 2px
|
| 1771 |
-
font-size:
|
|
|
|
| 1772 |
}
|
| 1773 |
|
| 1774 |
.send-button-inline {
|
|
@@ -2319,19 +2368,20 @@ with gr.Blocks(
|
|
| 2319 |
</script>
|
| 2320 |
""")
|
| 2321 |
|
| 2322 |
-
#
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2323 |
with gr.Row(elem_classes=["input-actions-row"]):
|
| 2324 |
-
#
|
| 2325 |
-
news_btn = gr.Button("π°", elem_classes=["preprompt-icon"], elem_id="news-btn", scale=0, min_width=36)
|
| 2326 |
-
finance_btn = gr.Button("π°", elem_classes=["preprompt-icon"], elem_id="finance-btn", scale=0, min_width=36)
|
| 2327 |
-
health_btn = gr.Button("π₯", elem_classes=["preprompt-icon"], elem_id="health-btn", scale=0, min_width=36)
|
| 2328 |
-
math_btn = gr.Button("π’", elem_classes=["preprompt-icon"], elem_id="math-btn", scale=0, min_width=36)
|
| 2329 |
-
science_btn = gr.Button("π¬", elem_classes=["preprompt-icon"], elem_id="science-btn", scale=0, min_width=36)
|
| 2330 |
-
tech_btn = gr.Button("π»", elem_classes=["preprompt-icon"], elem_id="tech-btn", scale=0, min_width=36)
|
| 2331 |
-
creative_btn = gr.Button("π¨", elem_classes=["preprompt-icon"], elem_id="creative-btn", scale=0, min_width=36)
|
| 2332 |
-
food_btn = gr.Button("π³", elem_classes=["preprompt-icon"], elem_id="food-btn", scale=0, min_width=36)
|
| 2333 |
-
|
| 2334 |
-
# Spacer
|
| 2335 |
gr.HTML("<div style='flex: 1'></div>")
|
| 2336 |
|
| 2337 |
# Model selector (simple dropdown)
|
|
@@ -2345,13 +2395,10 @@ with gr.Blocks(
|
|
| 2345 |
elem_classes=["model-selector-simple"],
|
| 2346 |
elem_id="model-selector",
|
| 2347 |
scale=0,
|
| 2348 |
-
min_width=
|
| 2349 |
interactive=True
|
| 2350 |
)
|
| 2351 |
|
| 2352 |
-
# Spacer between model and send
|
| 2353 |
-
gr.HTML("<div style='min-width: 12px'></div>")
|
| 2354 |
-
|
| 2355 |
# Send button (right)
|
| 2356 |
send_btn = gr.Button(
|
| 2357 |
"β€",
|
|
|
|
| 623 |
cursor: text !important;
|
| 624 |
}
|
| 625 |
|
| 626 |
+
/* Preprompt icons row */
|
| 627 |
+
.preprompt-icons-row {
|
| 628 |
display: flex !important;
|
| 629 |
align-items: center !important;
|
| 630 |
justify-content: flex-start !important;
|
| 631 |
+
flex-wrap: wrap !important;
|
| 632 |
gap: 4px !important;
|
| 633 |
padding: 0 !important;
|
| 634 |
margin: 0 !important;
|
|
|
|
| 636 |
border: none !important;
|
| 637 |
}
|
| 638 |
|
| 639 |
+
.preprompt-icons-row > * {
|
| 640 |
+
background: transparent !important;
|
| 641 |
+
}
|
| 642 |
+
|
| 643 |
+
/* Bottom row with model selector and send */
|
| 644 |
+
.input-actions-row {
|
| 645 |
+
display: flex !important;
|
| 646 |
+
align-items: center !important;
|
| 647 |
+
justify-content: flex-end !important;
|
| 648 |
+
gap: 8px !important;
|
| 649 |
+
padding: 0 !important;
|
| 650 |
+
margin: 0 !important;
|
| 651 |
+
background: transparent !important;
|
| 652 |
+
border: none !important;
|
| 653 |
+
flex-wrap: nowrap !important;
|
| 654 |
+
}
|
| 655 |
+
|
| 656 |
.input-actions-row > * {
|
| 657 |
background: transparent !important;
|
| 658 |
}
|
|
|
|
| 1604 |
display: inline !important;
|
| 1605 |
}
|
| 1606 |
|
| 1607 |
+
/* Gemini input - mobile - shifted UP to ensure send button visible */
|
| 1608 |
.input-container-gemini {
|
| 1609 |
+
padding: 10px 12px 20px 12px !important;
|
| 1610 |
+
padding-bottom: calc(20px + env(safe-area-inset-bottom, 0px)) !important;
|
| 1611 |
position: sticky !important;
|
| 1612 |
bottom: 0 !important;
|
| 1613 |
z-index: 100 !important;
|
| 1614 |
+
margin-bottom: 0 !important;
|
| 1615 |
}
|
| 1616 |
|
| 1617 |
.input-box-gemini {
|
| 1618 |
+
padding: 8px 10px !important;
|
| 1619 |
+
border-radius: 18px !important;
|
| 1620 |
max-width: 100% !important;
|
| 1621 |
+
width: calc(100% - 8px) !important;
|
| 1622 |
+
margin: 0 auto !important;
|
| 1623 |
}
|
| 1624 |
|
| 1625 |
.input-textarea-gemini textarea {
|
| 1626 |
font-size: 16px !important;
|
| 1627 |
-webkit-appearance: none !important;
|
| 1628 |
+
min-height: 24px !important;
|
| 1629 |
+
max-height: 80px !important;
|
| 1630 |
}
|
| 1631 |
|
| 1632 |
+
/* Preprompt icons row - mobile */
|
| 1633 |
+
.preprompt-icons-row {
|
| 1634 |
gap: 2px !important;
|
| 1635 |
flex-wrap: wrap !important;
|
| 1636 |
+
justify-content: center !important;
|
| 1637 |
}
|
| 1638 |
|
| 1639 |
/* Preprompt icons - mobile */
|
| 1640 |
.preprompt-icon {
|
| 1641 |
padding: 3px 6px !important;
|
| 1642 |
font-size: 14px !important;
|
| 1643 |
+
min-width: 28px !important;
|
| 1644 |
+
}
|
| 1645 |
+
|
| 1646 |
+
/* Model selector + send button row - ALWAYS visible */
|
| 1647 |
+
.input-actions-row {
|
| 1648 |
+
gap: 8px !important;
|
| 1649 |
+
flex-wrap: nowrap !important;
|
| 1650 |
+
justify-content: flex-end !important;
|
| 1651 |
+
margin-top: 4px !important;
|
| 1652 |
}
|
| 1653 |
|
| 1654 |
.action-spacer {
|
|
|
|
| 1658 |
/* Model selector on mobile - ensure visible */
|
| 1659 |
.model-selector-simple {
|
| 1660 |
flex-shrink: 0 !important;
|
| 1661 |
+
min-width: 90px !important;
|
| 1662 |
+
max-width: 120px !important;
|
| 1663 |
}
|
| 1664 |
|
| 1665 |
.model-selector-simple [data-testid="dropdown"] {
|
| 1666 |
padding: 6px 10px !important;
|
| 1667 |
+
font-size: 11px !important;
|
| 1668 |
+
min-width: 90px !important;
|
| 1669 |
}
|
| 1670 |
|
| 1671 |
#send-button,
|
| 1672 |
.send-button-inline {
|
| 1673 |
+
width: 34px !important;
|
| 1674 |
+
height: 34px !important;
|
| 1675 |
+
min-width: 34px !important;
|
| 1676 |
+
border-radius: 50% !important;
|
| 1677 |
+
font-size: 16px !important;
|
| 1678 |
flex-shrink: 0 !important;
|
| 1679 |
+
margin-left: 4px !important;
|
| 1680 |
+
}
|
| 1681 |
+
|
| 1682 |
+
/* Hide spacer on mobile */
|
| 1683 |
+
.input-actions-row > div[style*="flex: 1"] {
|
| 1684 |
+
display: none !important;
|
| 1685 |
}
|
| 1686 |
|
| 1687 |
/* Code blocks - mobile scroll */
|
|
|
|
| 1792 |
display: inline !important;
|
| 1793 |
}
|
| 1794 |
|
| 1795 |
+
/* Gemini input - small phones - more compact */
|
| 1796 |
.input-container-gemini {
|
| 1797 |
+
padding: 8px 8px 16px 8px !important;
|
| 1798 |
+
padding-bottom: calc(16px + env(safe-area-inset-bottom, 0px)) !important;
|
| 1799 |
}
|
| 1800 |
|
| 1801 |
.input-box-gemini {
|
| 1802 |
+
padding: 6px 8px !important;
|
| 1803 |
+
border-radius: 16px !important;
|
| 1804 |
+
gap: 4px !important;
|
| 1805 |
}
|
| 1806 |
|
| 1807 |
.input-textarea-gemini textarea {
|
| 1808 |
font-size: 15px !important;
|
| 1809 |
+
min-height: 22px !important;
|
| 1810 |
+
}
|
| 1811 |
+
|
| 1812 |
+
/* Smaller preprompt icons on small phones */
|
| 1813 |
+
.preprompt-icons-row {
|
| 1814 |
+
gap: 1px !important;
|
| 1815 |
}
|
| 1816 |
|
| 1817 |
.preprompt-icon {
|
| 1818 |
+
padding: 2px 4px !important;
|
| 1819 |
+
font-size: 12px !important;
|
| 1820 |
+
min-width: 24px !important;
|
| 1821 |
}
|
| 1822 |
|
| 1823 |
.send-button-inline {
|
|
|
|
| 2368 |
</script>
|
| 2369 |
""")
|
| 2370 |
|
| 2371 |
+
# Row 1: Preprompt icons
|
| 2372 |
+
with gr.Row(elem_classes=["preprompt-icons-row"]):
|
| 2373 |
+
news_btn = gr.Button("π°", elem_classes=["preprompt-icon"], elem_id="news-btn", scale=0, min_width=32)
|
| 2374 |
+
finance_btn = gr.Button("π°", elem_classes=["preprompt-icon"], elem_id="finance-btn", scale=0, min_width=32)
|
| 2375 |
+
health_btn = gr.Button("π₯", elem_classes=["preprompt-icon"], elem_id="health-btn", scale=0, min_width=32)
|
| 2376 |
+
math_btn = gr.Button("π’", elem_classes=["preprompt-icon"], elem_id="math-btn", scale=0, min_width=32)
|
| 2377 |
+
science_btn = gr.Button("π¬", elem_classes=["preprompt-icon"], elem_id="science-btn", scale=0, min_width=32)
|
| 2378 |
+
tech_btn = gr.Button("π»", elem_classes=["preprompt-icon"], elem_id="tech-btn", scale=0, min_width=32)
|
| 2379 |
+
creative_btn = gr.Button("π¨", elem_classes=["preprompt-icon"], elem_id="creative-btn", scale=0, min_width=32)
|
| 2380 |
+
food_btn = gr.Button("π³", elem_classes=["preprompt-icon"], elem_id="food-btn", scale=0, min_width=32)
|
| 2381 |
+
|
| 2382 |
+
# Row 2: Model selector + Send button (always visible)
|
| 2383 |
with gr.Row(elem_classes=["input-actions-row"]):
|
| 2384 |
+
# Spacer (pushes model selector and send to right)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 2385 |
gr.HTML("<div style='flex: 1'></div>")
|
| 2386 |
|
| 2387 |
# Model selector (simple dropdown)
|
|
|
|
| 2395 |
elem_classes=["model-selector-simple"],
|
| 2396 |
elem_id="model-selector",
|
| 2397 |
scale=0,
|
| 2398 |
+
min_width=120,
|
| 2399 |
interactive=True
|
| 2400 |
)
|
| 2401 |
|
|
|
|
|
|
|
|
|
|
| 2402 |
# Send button (right)
|
| 2403 |
send_btn = gr.Button(
|
| 2404 |
"β€",
|
memory-bank/activeContext.md
CHANGED
|
@@ -1,14 +1,31 @@
|
|
| 1 |
# Active Context
|
| 2 |
|
| 3 |
## Current Focus
|
| 4 |
-
-
|
| 5 |
-
-
|
| 6 |
-
- Improve scrollbar styling for desktop and mobile.
|
| 7 |
|
| 8 |
-
## Recent Changes
|
| 9 |
-
-
|
| 10 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 11 |
|
| 12 |
## Next Steps
|
| 13 |
-
-
|
| 14 |
-
-
|
|
|
|
| 1 |
# Active Context
|
| 2 |
|
| 3 |
## Current Focus
|
| 4 |
+
- Preprompt popup feature is now fully working
|
| 5 |
+
- UI refinements complete
|
|
|
|
| 6 |
|
| 7 |
+
## Recent Changes (Jan 2026)
|
| 8 |
+
- **Commit 70dfac7** - Fixed preprompt popup functionality:
|
| 9 |
+
- Popup now appears when clicking category icons (π°, π°, π₯, π’, π¬, π», π¨, π³)
|
| 10 |
+
- Shows multiple prompt options to choose from
|
| 11 |
+
- Closes properly after selecting a prompt
|
| 12 |
+
- No more gray empty boxes appearing
|
| 13 |
+
|
| 14 |
+
- **Key fixes applied:**
|
| 15 |
+
1. Changed popup from `position: absolute` to `position: fixed` (avoids chatbot blocking clicks)
|
| 16 |
+
2. Correct indentation level - popup outside `input-box-gemini` Group
|
| 17 |
+
3. Clear choices on selection (`choices=[]`) to force Gradio to hide popup
|
| 18 |
+
4. JavaScript `hideEmptyPopups()` function to hide popups with no content
|
| 19 |
+
5. JavaScript auto-close on radio label click with multiple timed attempts
|
| 20 |
+
|
| 21 |
+
- **Working commit reference:** `0321f68` was the original working version that was used as reference
|
| 22 |
+
|
| 23 |
+
## Previous Fixes
|
| 24 |
+
- Python 3.12 pinned in README.md for spacy wheel compatibility
|
| 25 |
+
- Input box layout fixed (centered, proper width)
|
| 26 |
+
- Mobile responsiveness for send button and model selector
|
| 27 |
+
- Chatbot label hidden via JavaScript
|
| 28 |
|
| 29 |
## Next Steps
|
| 30 |
+
- Monitor for any additional UI issues
|
| 31 |
+
- Consider adding more preprompt categories if needed
|
memory-bank/progress.md
CHANGED
|
@@ -1,13 +1,27 @@
|
|
| 1 |
# Progress
|
| 2 |
|
| 3 |
## What Works
|
| 4 |
-
- Core chat flow and agent routing
|
| 5 |
-
- Sidebar branding and Gemini-style input row
|
| 6 |
-
- Custom CSS pipeline in `app.py
|
|
|
|
|
|
|
|
|
|
|
|
|
| 7 |
|
| 8 |
-
##
|
| 9 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 10 |
|
| 11 |
## Remaining
|
| 12 |
-
- Validate scroll behavior and remove any lingering default UI elements
|
| 13 |
-
- Gather user feedback on spacing and bubble styling
|
|
|
|
|
|
| 1 |
# Progress
|
| 2 |
|
| 3 |
## What Works
|
| 4 |
+
- Core chat flow and agent routing
|
| 5 |
+
- Sidebar branding and Gemini-style input row
|
| 6 |
+
- Custom CSS pipeline in `app.py`
|
| 7 |
+
- **Preprompt popup feature** - Click category icons to see prompt suggestions, select to fill input
|
| 8 |
+
- Mobile responsive layout (send button, model selector visible)
|
| 9 |
+
- Python 3.12 deployment on HF Spaces (spacy wheel compatibility)
|
| 10 |
+
- Chatbot label hidden
|
| 11 |
|
| 12 |
+
## Completed (Jan 2026)
|
| 13 |
+
- Fixed preprompt popup not appearing (position: fixed, correct DOM placement)
|
| 14 |
+
- Fixed popup not closing after selection (clear choices + JavaScript hide)
|
| 15 |
+
- Fixed gray empty popup boxes appearing
|
| 16 |
+
- Fixed input box layout (centered, proper width)
|
| 17 |
+
- Fixed mobile responsiveness
|
| 18 |
+
- Pinned Python 3.12 in README.md metadata
|
| 19 |
+
|
| 20 |
+
## Key Commits
|
| 21 |
+
- **70dfac7** - Fix popup close - clear choices on selection to force hide
|
| 22 |
+
- **0321f68** - Original working version (used as reference for popup logic)
|
| 23 |
|
| 24 |
## Remaining
|
| 25 |
+
- Validate scroll behavior and remove any lingering default UI elements
|
| 26 |
+
- Gather user feedback on spacing and bubble styling
|
| 27 |
+
- Consider additional preprompt categories
|
memory-bank/systemPatterns.md
CHANGED
|
@@ -1,12 +1,33 @@
|
|
| 1 |
# System Patterns
|
| 2 |
|
| 3 |
## Architecture
|
| 4 |
-
- `app.py` is the entry point and owns UI assembly
|
| 5 |
-
- UI is built with Gradio `Blocks` and extensive CSS overrides
|
| 6 |
-
- Model/agent logic lives under `core
|
| 7 |
-
- Configurations are JSON-based under `config
|
| 8 |
|
| 9 |
## UI Composition
|
| 10 |
-
- Two-column layout: sidebar branding + main chat area
|
| 11 |
-
- Chat history rendered via `gr.Chatbot
|
| 12 |
-
- Gemini-style input row (icons, model select, send)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 1 |
# System Patterns
|
| 2 |
|
| 3 |
## Architecture
|
| 4 |
+
- `app.py` is the entry point and owns UI assembly
|
| 5 |
+
- UI is built with Gradio `Blocks` and extensive CSS overrides
|
| 6 |
+
- Model/agent logic lives under `core/`
|
| 7 |
+
- Configurations are JSON-based under `config/`
|
| 8 |
|
| 9 |
## UI Composition
|
| 10 |
+
- Two-column layout: sidebar branding + main chat area
|
| 11 |
+
- Chat history rendered via `gr.Chatbot`
|
| 12 |
+
- Gemini-style input row (icons, model select, send)
|
| 13 |
+
|
| 14 |
+
## Preprompt Popup Pattern
|
| 15 |
+
The preprompt popup required specific implementation patterns:
|
| 16 |
+
|
| 17 |
+
1. **DOM Placement**: `prompt_row` must be a sibling of `input-container-gemini`, NOT nested inside `input-box-gemini` Group
|
| 18 |
+
2. **CSS Positioning**: Use `position: fixed` (not absolute) with high z-index (999999) to avoid chatbot blocking clicks
|
| 19 |
+
3. **Closing Logic**:
|
| 20 |
+
- Python: Clear choices on selection (`gr.update(choices=[], value=None)`) to force Gradio hide
|
| 21 |
+
- JavaScript: `hideEmptyPopups()` function monitors and hides empty popup containers
|
| 22 |
+
- Multiple timed hide attempts (0ms, 50ms, 100ms, 200ms, 500ms, 1000ms) to counter Gradio re-renders
|
| 23 |
+
|
| 24 |
+
## Gradio-Specific Patterns
|
| 25 |
+
- `visible=False` removes elements from DOM entirely (can't style hidden elements)
|
| 26 |
+
- Use `gr.State` for tracking popup state (e.g., `current_popup`)
|
| 27 |
+
- JavaScript in `gr.HTML` for DOM manipulation that Gradio doesn't support natively
|
| 28 |
+
- MutationObserver pattern for handling dynamic Gradio re-renders
|
| 29 |
+
|
| 30 |
+
## Deployment Patterns
|
| 31 |
+
- Python version pinned in README.md YAML front matter (`python_version: "3.12"`)
|
| 32 |
+
- spacy requires specific Python version for wheel compatibility
|
| 33 |
+
- HF Spaces uses README.md metadata for configuration
|