fix(nav,footer): drop orphan _hidden section header, show footer on Activate
Two follow-ups to the prior sidebar/footer cleanup: - The "_hidden" section header was still visible in the sidebar because Streamlit renders ``stNavSectionHeader`` as a sibling of ``stNavSection``, not a child — so the ``:has()`` rule on the section was hiding the items list but leaving the header (and its collapse/drilldown marker) behind. Move Activate + Close into the unlabeled section (key ``""``) alongside Home so there is no header to leak in the first place, then hide just the two links via ``stSidebarNavLinkContainer:has(...)`` (with a defensive ``a[href$=...]`` fallback for browsers without ``:has()`` support). - The sticky footer was missing on ``pages/_Activate.py`` because the page never called ``render_sticky_footer`` — added the call so the Help / Close bar persists when the user follows the popover's Activate / Manage link. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -109,13 +109,16 @@ def _build_navigation() -> dict[str, list]:
|
|||||||
url_path="close",
|
url_path="close",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# Activate + Close are placed in the unlabeled section alongside
|
||||||
|
# Home (key ``""`` — Streamlit renders no header for it). The CSS
|
||||||
|
# in ``hide_streamlit_chrome`` then hides just their two links by
|
||||||
|
# ``href``, leaving Home visible and no orphan section header /
|
||||||
|
# drilldown marker in the sidebar.
|
||||||
return {
|
return {
|
||||||
"": [home],
|
"": [home, activate, close],
|
||||||
section_label("cleaners"): by_section["cleaners"],
|
section_label("cleaners"): by_section["cleaners"],
|
||||||
section_label("transformations"): by_section["transformations"],
|
section_label("transformations"): by_section["transformations"],
|
||||||
section_label("automations"): by_section["automations"],
|
section_label("automations"): by_section["automations"],
|
||||||
# Hidden section — see comment above + CSS in hide_streamlit_chrome.
|
|
||||||
"_hidden": [activate, close],
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -60,29 +60,29 @@ header[data-testid="stHeader"] {
|
|||||||
footer {
|
footer {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
/* Hide the Activate + Close entries from the sidebar nav — both
|
/* Hide the Activate + Close entries from the sidebar nav. Both
|
||||||
pages stay registered (so /activate and /close remain
|
pages stay registered (so /activate and /close remain
|
||||||
URL-routable) but are reached from the sticky-footer Help
|
URL-routable) but are reached from the sticky-footer Help
|
||||||
popover instead of the sidebar. */
|
popover instead of the sidebar. They are grouped under the
|
||||||
|
unlabeled section alongside Home in ``app.py`` so hiding the
|
||||||
|
two links here leaves no orphan section header behind. We
|
||||||
|
target the LinkContainer (Streamlit's per-entry wrapper) so the
|
||||||
|
list item collapses, not just the inner anchor — otherwise the
|
||||||
|
container's spacing would still occupy a row. */
|
||||||
|
[data-testid="stSidebarNav"] [data-testid="stSidebarNavLinkContainer"]:has(a[href$="/activate"]),
|
||||||
|
[data-testid="stSidebarNav"] [data-testid="stSidebarNavLinkContainer"]:has(a[href$="/activate/"]),
|
||||||
|
[data-testid="stSidebarNav"] [data-testid="stSidebarNavLinkContainer"]:has(a[href$="/close"]),
|
||||||
|
[data-testid="stSidebarNav"] [data-testid="stSidebarNavLinkContainer"]:has(a[href$="/close/"]) {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
/* Defensive fallback for browsers without :has() support — at
|
||||||
|
least hide the anchor itself so the entry isn't clickable. */
|
||||||
[data-testid="stSidebarNav"] a[href$="/activate"],
|
[data-testid="stSidebarNav"] a[href$="/activate"],
|
||||||
[data-testid="stSidebarNav"] a[href$="/activate/"],
|
[data-testid="stSidebarNav"] a[href$="/activate/"],
|
||||||
[data-testid="stSidebarNav"] a[href$="/close"],
|
[data-testid="stSidebarNav"] a[href$="/close"],
|
||||||
[data-testid="stSidebarNav"] a[href$="/close/"] {
|
[data-testid="stSidebarNav"] a[href$="/close/"] {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
/* Hide the section header that wraps those entries so no orphan
|
|
||||||
label is left above the hidden links. Streamlit tags each nav
|
|
||||||
section with ``data-testid="stNavSection"``; the :has() selector
|
|
||||||
picks only the one(s) containing those links. Modern browsers
|
|
||||||
(Chrome 105+, Safari 15.4+, Firefox 121+) all support :has();
|
|
||||||
older browsers fall back to showing the section header, which
|
|
||||||
is visually harmless. */
|
|
||||||
[data-testid="stSidebarNav"] [data-testid="stNavSection"]:has(a[href$="/activate"]),
|
|
||||||
[data-testid="stSidebarNav"] [data-testid="stNavSection"]:has(a[href$="/activate/"]),
|
|
||||||
[data-testid="stSidebarNav"] [data-testid="stNavSection"]:has(a[href$="/close"]),
|
|
||||||
[data-testid="stSidebarNav"] [data-testid="stNavSection"]:has(a[href$="/close/"]) {
|
|
||||||
display: none !important;
|
|
||||||
}
|
|
||||||
/* Reclaim top padding lost from hidden header. Slim the bottom too —
|
/* Reclaim top padding lost from hidden header. Slim the bottom too —
|
||||||
Streamlit's default leaves several rems below the last widget. */
|
Streamlit's default leaves several rems below the last widget. */
|
||||||
.stAppViewBlockContainer,
|
.stAppViewBlockContainer,
|
||||||
|
|||||||
@@ -19,7 +19,11 @@ _project_root = Path(__file__).resolve().parent.parent.parent.parent
|
|||||||
if str(_project_root) not in sys.path:
|
if str(_project_root) not in sys.path:
|
||||||
sys.path.insert(0, str(_project_root))
|
sys.path.insert(0, str(_project_root))
|
||||||
|
|
||||||
from src.gui.components import hide_streamlit_chrome, render_activation_form
|
from src.gui.components import (
|
||||||
|
hide_streamlit_chrome,
|
||||||
|
render_activation_form,
|
||||||
|
render_sticky_footer,
|
||||||
|
)
|
||||||
from src.i18n import t
|
from src.i18n import t
|
||||||
|
|
||||||
st.set_page_config(
|
st.set_page_config(
|
||||||
@@ -31,4 +35,5 @@ st.set_page_config(
|
|||||||
# ``gate_license=False`` keeps the chrome from re-rendering the
|
# ``gate_license=False`` keeps the chrome from re-rendering the
|
||||||
# activation form on top of the form we're about to render below.
|
# activation form on top of the form we're about to render below.
|
||||||
hide_streamlit_chrome(gate_license=False)
|
hide_streamlit_chrome(gate_license=False)
|
||||||
|
render_sticky_footer()
|
||||||
render_activation_form(key_prefix="page")
|
render_activation_form(key_prefix="page")
|
||||||
|
|||||||
Reference in New Issue
Block a user