feat(nav,i18n): sticky footer with Back-to-Home + localized tool headers
Two unrelated UX issues addressed in one sweep across all nine tool
pages because they share the same edit surface.
(1) Sticky footer replaces the top + bottom back-link buttons.
Reported: a big white empty footer space at the bottom of every page;
the Back to Home button at the top scrolled out of view on long pages.
New ``render_sticky_footer()`` helper in ``components/_legacy.py``
injects a fixed-position bar at ``bottom: 0`` of the viewport with:
- A border-top so it visually reads as a non-movable bar.
- A semi-transparent background (rgba 0.96 + ``backdrop-filter: blur``)
so content underneath shows through faintly when the user scrolls.
- A styled ``<a href="home">`` anchor (not an ``st.button``) because
Streamlit widgets can't be CSS-positioned reliably — Streamlit owns
the widget's DOM container and re-mounts it on every rerun. A real
anchor sits exactly where the CSS puts it and triggers Streamlit's
URL routing to the home page.
- ``padding-bottom: 3.5rem`` on the main container so the last widget
isn't hidden behind the bar.
Called once per tool page, immediately after ``hide_streamlit_chrome()``
so it renders even on pages that ``st.stop()`` early before any other
content runs. The old top-and-bottom ``back_to_home_link()`` calls are
removed from every tool page; their entry/exit points were dropping
the button when the script short-circuited.
(2) Tool-page headers now localize.
Reported: switching the sidebar language picker to Spanish left the
tool page's title + caption in English. Root cause: every page had
hard-coded ``st.title("✂️ Clean Text")`` / ``st.caption("Trim
whitespace...")`` strings.
Added per-tool ``tools.<id>.page_title`` and
``tools.<id>.page_caption`` keys to ``en.json`` and ``es.json`` for
all nine tools. Routed each page's title/caption call through ``t()``.
Verified: with ``ui_lang=es`` set, the Clean Text page now renders
"✂️ Limpiar texto" + the Spanish caption.
Updated ``tests/gui/test_smoke.py::EXPECTED_SUBSTRINGS`` so the
``es`` column for each tool page asserts the actual Spanish string
(was a duplicate of the English string back when the page bodies
were English-only).
2220 tests pass.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -491,6 +491,88 @@ def local_download_button(
|
||||
html_download_button = local_download_button
|
||||
|
||||
|
||||
def render_sticky_footer() -> None:
|
||||
"""Render a slim fixed-position footer at the bottom of the viewport.
|
||||
|
||||
Contains a "Back to Home" link that's always visible regardless of
|
||||
scroll position. Replaces the previous top + bottom-of-page
|
||||
``back_to_home_link`` buttons: a single sticky bar is more
|
||||
discoverable, doesn't scroll out of view, and visually reads as a
|
||||
"non-movable footer" (border-top + slim padding) rather than
|
||||
just-another-button-at-the-bottom.
|
||||
|
||||
Implementation notes:
|
||||
|
||||
- Uses a styled ``<a href="home">`` anchor rather than an
|
||||
``st.button`` because Streamlit widgets can't be CSS-positioned
|
||||
reliably (their DOM container is owned by Streamlit's renderer
|
||||
and gets re-mounted on every rerun). A real anchor sits anywhere
|
||||
we want and triggers Streamlit's URL routing to the home page.
|
||||
- ``href="home"`` is a relative path so it works behind a reverse
|
||||
proxy / non-root mount.
|
||||
- We bump ``padding-bottom`` on the main container so the last
|
||||
widget isn't hidden behind the fixed bar.
|
||||
- Theme: ``rgba(255,255,255,0.96)`` background with a thin
|
||||
semi-transparent border-top. The blur backdrop keeps content
|
||||
slightly visible underneath. Works against both light and dark
|
||||
Streamlit themes — explicit colours, not theme variables,
|
||||
because Streamlit's CSS variable surface is unstable across
|
||||
minor versions.
|
||||
"""
|
||||
import html as _html
|
||||
label = _html.escape(_t("nav.back_to_home"))
|
||||
st.markdown(
|
||||
f"""
|
||||
<style>
|
||||
[data-testid="stAppViewBlockContainer"] {{
|
||||
padding-bottom: 3.5rem !important;
|
||||
}}
|
||||
.datatools-sticky-footer {{
|
||||
position: fixed;
|
||||
bottom: 0;
|
||||
left: 0;
|
||||
right: 0;
|
||||
background: rgba(255, 255, 255, 0.96);
|
||||
backdrop-filter: blur(8px);
|
||||
-webkit-backdrop-filter: blur(8px);
|
||||
border-top: 1px solid rgba(49, 51, 63, 0.22);
|
||||
padding: 0.45rem 1.25rem;
|
||||
z-index: 9999;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: flex-start;
|
||||
font-family: inherit;
|
||||
}}
|
||||
.datatools-sticky-footer a {{
|
||||
display: inline-block;
|
||||
color: rgb(38, 39, 48);
|
||||
text-decoration: none;
|
||||
padding: 0.3rem 0.85rem;
|
||||
border-radius: 0.5rem;
|
||||
border: 1px solid rgba(49, 51, 63, 0.22);
|
||||
background: rgb(240, 242, 246);
|
||||
font-size: 14px;
|
||||
font-weight: 500;
|
||||
line-height: 1.4;
|
||||
cursor: pointer;
|
||||
transition: background 0.12s ease, border-color 0.12s ease;
|
||||
}}
|
||||
.datatools-sticky-footer a:hover {{
|
||||
background: rgb(225, 228, 235);
|
||||
border-color: rgba(49, 51, 63, 0.35);
|
||||
}}
|
||||
.datatools-sticky-footer a:active {{
|
||||
background: rgb(210, 214, 222);
|
||||
}}
|
||||
</style>
|
||||
<div class="datatools-sticky-footer">
|
||||
<a href="home" target="_self">{label}</a>
|
||||
</div>
|
||||
""",
|
||||
unsafe_allow_html=True,
|
||||
)
|
||||
|
||||
|
||||
def back_to_home_link(*, key: str = "_back_to_home_link") -> None:
|
||||
"""Render a "← Back to Home" affordance on a tool page.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user