Surn commited on
Commit
8c564f0
·
1 Parent(s): 1ef2bdb

Fade out update

Browse files
Files changed (2) hide show
  1. battlewords/ui.py +25 -7
  2. battlewords/ui_helpers.py +18 -14
battlewords/ui.py CHANGED
@@ -161,6 +161,9 @@ def _init_session() -> None:
161
  if "enable_sound_effects" not in st.session_state:
162
  st.session_state.enable_sound_effects = False
163
 
 
 
 
164
  def _new_game() -> None:
165
  spinner_placeholder = st.empty()
166
  with CustomSpinner(spinner_placeholder, "Initializing New Game..."):
@@ -771,7 +774,14 @@ def _render_guess_form(state: GameState):
771
  <style>
772
  .st-key-guess_input .stTextInput label .st-emotion-cache-lyi571, .st-key-guess_input .stTextInput label .st-emotion-cache-on6lu2 {
773
  font-size: 1.2em;
 
 
774
  }
 
 
 
 
 
775
  .st-key-guess_input .stTextInput input {
776
  font-size: 1.1em;
777
  }
@@ -863,7 +873,8 @@ def _render_guess_form(state: GameState):
863
  color: #ff9999;
864
  }
865
 
866
- .stForm { padding-bottom: 30px; }
 
867
 
868
  .stColumn .st-emotion-cache-6023h2 {margin-top:0px;}
869
  /*.stColumn .st-emotion-cache-1w9nhvb { display:none;} hide OK BUTTON col spacing under form */
@@ -1468,7 +1479,7 @@ def _on_game_option_change() -> None:
1468
  _new_game()
1469
 
1470
  def run_app():
1471
- start_root_fade_in(0.3)
1472
  # Render PWA service worker registration (meta tags in <head> via Docker)
1473
  # Streamlit reruns the script frequently; inject this only once per session.
1474
  if not st.session_state.get("pwa_injected", False):
@@ -1486,6 +1497,10 @@ def run_app():
1486
  except Exception:
1487
  params = {}
1488
 
 
 
 
 
1489
  # Handle overlay dismissal
1490
  if params.get("overlay") == "0":
1491
  # Clear param and remember to hide overlay this session
@@ -1528,7 +1543,8 @@ def run_app():
1528
  #inject_ocean_layers()
1529
  inject_styles()
1530
  render_settings_page(_on_game_option_change)
1531
- render_footer(current_page="settings")
 
1532
  return
1533
 
1534
  if page == "leaderboard":
@@ -1539,7 +1555,8 @@ def run_app():
1539
  inject_styles()
1540
  st.header("Leaderboard")
1541
  st.caption("Leaderboard UI will be added as part of the upgrade checklist.")
1542
- render_footer(current_page="leaderboard")
 
1543
  return
1544
 
1545
  # Handle game_id for loading shared games
@@ -1592,14 +1609,15 @@ def run_app():
1592
  state = _to_state()
1593
  if is_game_over(state) and not st.session_state.get("hide_gameover_overlay", False):
1594
  _render_game_over(state)
1595
- render_footer(current_page="play")
1596
- finish_root_fade_in(0.3)
 
1597
 
1598
  def _render_game_tab():
1599
  """
1600
  Render the main game tab layout.
1601
  """
1602
- # start_root_fade_in(0.3)
1603
  _init_session()
1604
  st.markdown(ocean_background_css, unsafe_allow_html=True)
1605
  #inject_ocean_layers() # <-- add the animated layers
 
161
  if "enable_sound_effects" not in st.session_state:
162
  st.session_state.enable_sound_effects = False
163
 
164
+ if "hide_footer" not in st.session_state:
165
+ st.session_state["hide_footer"] = False
166
+
167
  def _new_game() -> None:
168
  spinner_placeholder = st.empty()
169
  with CustomSpinner(spinner_placeholder, "Initializing New Game..."):
 
774
  <style>
775
  .st-key-guess_input .stTextInput label .st-emotion-cache-lyi571, .st-key-guess_input .stTextInput label .st-emotion-cache-on6lu2 {
776
  font-size: 1.2em;
777
+ transition: opacity 1.5s ease-in, visibility 1.5s ease-in, display 1.5s allow-discrete;
778
+ transition-behavior: allow-discrete;
779
  }
780
+ .st-emotion-cache-on6lu2, .st-emotion-cache-6c7yup , .st-emotion-cache-1pcf7lv {
781
+ visibility: inherit !important;
782
+ transition: opacity 1.5s ease-in, visibility 1.5s ease-in, display 1.5s allow-discrete;
783
+ transition-behavior: allow-discrete;
784
+ }
785
  .st-key-guess_input .stTextInput input {
786
  font-size: 1.1em;
787
  }
 
873
  color: #ff9999;
874
  }
875
 
876
+ .stForm { padding-bottom: 30px; transition: opacity 1.5s ease-in, visibility 1.5s ease; display 1.5s allow-discrete;
877
+ transition-behavior: allow-discrete;}
878
 
879
  .stColumn .st-emotion-cache-6023h2 {margin-top:0px;}
880
  /*.stColumn .st-emotion-cache-1w9nhvb { display:none;} hide OK BUTTON col spacing under form */
 
1479
  _new_game()
1480
 
1481
  def run_app():
1482
+ start_root_fade_in(0.2)
1483
  # Render PWA service worker registration (meta tags in <head> via Docker)
1484
  # Streamlit reruns the script frequently; inject this only once per session.
1485
  if not st.session_state.get("pwa_injected", False):
 
1497
  except Exception:
1498
  params = {}
1499
 
1500
+ # handle no footer query string param (for embedding use cases)
1501
+ if "nofooter" in params:
1502
+ st.session_state["hide_footer"] = True
1503
+
1504
  # Handle overlay dismissal
1505
  if params.get("overlay") == "0":
1506
  # Clear param and remember to hide overlay this session
 
1543
  #inject_ocean_layers()
1544
  inject_styles()
1545
  render_settings_page(_on_game_option_change)
1546
+ if st.session_state["hide_footer"] is not True:
1547
+ render_footer(current_page="settings", params=params)
1548
  return
1549
 
1550
  if page == "leaderboard":
 
1555
  inject_styles()
1556
  st.header("Leaderboard")
1557
  st.caption("Leaderboard UI will be added as part of the upgrade checklist.")
1558
+ if st.session_state["hide_footer"] is not True:
1559
+ render_footer(current_page="leaderboard", params=params)
1560
  return
1561
 
1562
  # Handle game_id for loading shared games
 
1609
  state = _to_state()
1610
  if is_game_over(state) and not st.session_state.get("hide_gameover_overlay", False):
1611
  _render_game_over(state)
1612
+ if st.session_state["hide_footer"] is not True:
1613
+ render_footer(current_page="play", params=params)
1614
+ finish_root_fade_in(2.0)
1615
 
1616
  def _render_game_tab():
1617
  """
1618
  Render the main game tab layout.
1619
  """
1620
+ # start_root_fade_in(0.0)
1621
  _init_session()
1622
  st.markdown(ocean_background_css, unsafe_allow_html=True)
1623
  #inject_ocean_layers() # <-- add the animated layers
battlewords/ui_helpers.py CHANGED
@@ -329,7 +329,7 @@ def start_root_fade_in(duration_s: float = 0.35) -> None:
329
  root.style.setProperty('visibility', 'hidden', 'important');
330
  // Force style/layout flush so opacity=0 commits before re-enabling transition.
331
  void root.offsetHeight;
332
- root.style.setProperty('transition', 'opacity {duration_s:.3f}s ease', 'important');
333
  }} catch (e) {{ /* no-op */ }}
334
  }})();
335
  </script>
@@ -350,7 +350,7 @@ def finish_root_fade_in(duration_s: float = 0.35) -> None:
350
  if (!root) return;
351
  root.style.opacity = '0';
352
  root.style.visibility = 'visible';
353
- root.style.transition = 'opacity {duration_s:.3f}s ease';
354
  root.style.opacity = '1';
355
  root.classList.remove('bw-fadein-prep');
356
  }} catch (e) {{ /* no-op */ }}
@@ -435,7 +435,8 @@ def inject_styles() -> None:
435
  font-size: 1.8rem;
436
  min-height: 2.5rem;
437
  min-width: 0.5em;
438
- transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease;
 
439
  background: #1d64c8; /* Base cell color */
440
  color: #FFFFFF; /* Base text color for contrast */
441
  }
@@ -471,11 +472,12 @@ def inject_styles() -> None:
471
  .bw-fadein-prep {visibility: hidden !important;}
472
  .bw-fadein-prep #bw-spinner-overlay {
473
  visibility: visible !important;
474
- opacity: 1 !important;
475
  }
476
 
477
  div[data-testid="column"], .st-emotion-cache-zh2fnc, .st-emotion-cache-1tj828o, .st-emotion-cache-1anq8dj { width: auto !important; flex: 1 1 auto !important; min-width: 100% !important; max-width: 100% !important; border-radius:0; background-color: #1e69d2; border: 1px solid transparent;}
478
- .st-emotion-cache-1permvm, .st-emotion-cache-1n6tfoc { gap:0.15rem !important; min-height: 2.5rem; min-width: 2.5rem;}
 
479
 
480
  .bw-grid-row-anchor + div[data-testid="stHorizontalBlock"] { flex-wrap: nowrap !important; overflow-x: auto !important; margin: 2px 0 !important; }
481
  .bw-grid-row-anchor + div[data-testid="stHorizontalBlock"] > div[data-testid="column"] { flex: 0 0 auto !important; }
@@ -517,7 +519,7 @@ def inject_styles() -> None:
517
  .shiny-border:hover::before { left: 100%; }
518
 
519
  .st-emotion-cache-1n1mx2j p {font-size: 1rem;}
520
- .bw-radio-group { display:flex; align-items:flex-start; gap: 5px; flex-flow: row; min-height: 92px;}
521
  .bw-radio-item { display:flex; flex-direction:column; align-items:center; gap:6px; text-align:center;}
522
  .bw-radio-circle { width: 45px; height: 45px; border-radius: 50%; border: 4px solid; background: rgba(255,255,255,0.06); display: grid; place-items: center; color:#fff; font-weight:700; }
523
  .bw-radio-circle .dot { width: 14px; height: 14px; border-radius: 50%; background:#777; box-shadow: inset 0 0 0 2px rgba(255,255,255,0.25); }
@@ -581,22 +583,21 @@ def inject_styles() -> None:
581
  )
582
 
583
  # --- Footer Navigation ---
584
- def render_footer(current_page: str = "play") -> None:
585
  """Render footer navigation.
586
 
587
  Args:
588
  current_page: Active page key ("play", "leaderboard", "settings").
589
  """
 
 
 
 
 
590
  play_active = "active" if current_page == "play" else ""
591
  leaderboard_active = "active" if current_page == "leaderboard" else ""
592
  settings_active = "active" if current_page == "settings" else ""
593
 
594
- params = {}
595
- try:
596
- params = st.query_params
597
- except Exception:
598
- params = {}
599
-
600
  game_id: Optional[str] = None
601
  if isinstance(params, dict):
602
  game_id = params.get("game_id")
@@ -689,13 +690,16 @@ def show_spinner(message: str = "Loading..."):
689
  .bw-spinner-overlay {{
690
  position: fixed; z-index: 99999; top: 0; left: 0; width: 100vw; height: 100vh;
691
  opacity: 1;
692
- transition: opacity 1.5s ease;
 
693
  background: rgb(29, 100, 200); display: flex; align-items: center; justify-content: center;
694
  visibility: visible;
695
  }}
696
  .bw-spinner-overlay.bw-spinner-fadeout {{
697
  opacity: 0;
698
  pointer-events: none;
 
 
699
  }}
700
  .bw-spinner-img {{
701
  width: 150px; height: 150px; border-radius: 16px; box-shadow: 0 0 8px #1d64c8;
 
329
  root.style.setProperty('visibility', 'hidden', 'important');
330
  // Force style/layout flush so opacity=0 commits before re-enabling transition.
331
  void root.offsetHeight;
332
+ // root.style.setProperty('transition', 'opacity {duration_s:.3f}s ease, visibility {duration_s:.3f}s ease', 'important');
333
  }} catch (e) {{ /* no-op */ }}
334
  }})();
335
  </script>
 
350
  if (!root) return;
351
  root.style.opacity = '0';
352
  root.style.visibility = 'visible';
353
+ root.style.transition = 'opacity {duration_s:.3f}s ease-in, visibility {duration_s:.3f}s ease-in !important';
354
  root.style.opacity = '1';
355
  root.classList.remove('bw-fadein-prep');
356
  }} catch (e) {{ /* no-op */ }}
 
435
  font-size: 1.8rem;
436
  min-height: 2.5rem;
437
  min-width: 0.5em;
438
+ transition: background 0.15s ease, color 0.15s ease, border-color 0.15s ease display 0.15s allow-discrete;
439
+ transition-behavior: allow-discrete;
440
  background: #1d64c8; /* Base cell color */
441
  color: #FFFFFF; /* Base text color for contrast */
442
  }
 
472
  .bw-fadein-prep {visibility: hidden !important;}
473
  .bw-fadein-prep #bw-spinner-overlay {
474
  visibility: visible !important;
475
+ opacity: 1 !important;
476
  }
477
 
478
  div[data-testid="column"], .st-emotion-cache-zh2fnc, .st-emotion-cache-1tj828o, .st-emotion-cache-1anq8dj { width: auto !important; flex: 1 1 auto !important; min-width: 100% !important; max-width: 100% !important; border-radius:0; background-color: #1e69d2; border: 1px solid transparent;}
479
+ .st-emotion-cache-1permvm, .st-emotion-cache-1n6tfoc { gap:0.15rem !important; min-height: 2.5rem; min-width: 2.5rem;}
480
+ .stColumn.st-emotion-cache-1ruy632, .stColumn.st-emotion-cache-t2z0eb {margin-top:0;}
481
 
482
  .bw-grid-row-anchor + div[data-testid="stHorizontalBlock"] { flex-wrap: nowrap !important; overflow-x: auto !important; margin: 2px 0 !important; }
483
  .bw-grid-row-anchor + div[data-testid="stHorizontalBlock"] > div[data-testid="column"] { flex: 0 0 auto !important; }
 
519
  .shiny-border:hover::before { left: 100%; }
520
 
521
  .st-emotion-cache-1n1mx2j p {font-size: 1rem;}
522
+ .bw-radio-group { display:flex; align-items:flex-start; gap: 5px; flex-flow: row; min-height: 92px; transition: opacity 1.5s ease-in, visibility 1.5s ease-in, display 1.5s allow-discrete; transition-behavior: allow-discrete; visibility: inherit;}
523
  .bw-radio-item { display:flex; flex-direction:column; align-items:center; gap:6px; text-align:center;}
524
  .bw-radio-circle { width: 45px; height: 45px; border-radius: 50%; border: 4px solid; background: rgba(255,255,255,0.06); display: grid; place-items: center; color:#fff; font-weight:700; }
525
  .bw-radio-circle .dot { width: 14px; height: 14px; border-radius: 50%; background:#777; box-shadow: inset 0 0 0 2px rgba(255,255,255,0.25); }
 
583
  )
584
 
585
  # --- Footer Navigation ---
586
+ def render_footer(current_page: str = "play", params: dict = {}) -> None:
587
  """Render footer navigation.
588
 
589
  Args:
590
  current_page: Active page key ("play", "leaderboard", "settings").
591
  """
592
+
593
+ # If nofooter=1 is present, do not render the footer
594
+ if isinstance(params, dict) and params.get("nofooter") == "1":
595
+ return
596
+
597
  play_active = "active" if current_page == "play" else ""
598
  leaderboard_active = "active" if current_page == "leaderboard" else ""
599
  settings_active = "active" if current_page == "settings" else ""
600
 
 
 
 
 
 
 
601
  game_id: Optional[str] = None
602
  if isinstance(params, dict):
603
  game_id = params.get("game_id")
 
690
  .bw-spinner-overlay {{
691
  position: fixed; z-index: 99999; top: 0; left: 0; width: 100vw; height: 100vh;
692
  opacity: 1;
693
+ transition: opacity 1.5s ease-out, visibility 1.5s ease-out, display 1.5s allow-discrete;
694
+ transition-behavior: allow-discrete;
695
  background: rgb(29, 100, 200); display: flex; align-items: center; justify-content: center;
696
  visibility: visible;
697
  }}
698
  .bw-spinner-overlay.bw-spinner-fadeout {{
699
  opacity: 0;
700
  pointer-events: none;
701
+ transition: opacity 1.5s ease, visibility 1.5s ease, display 1.5s allow-discrete;
702
+ transition-behavior: allow-discrete;
703
  }}
704
  .bw-spinner-img {{
705
  width: 150px; height: 150px; border-radius: 16px; box-shadow: 0 0 8px #1d64c8;