fix(ui): bottom padding + close-screen button removed + sidebar collapse + quiet loguru
Four issues batched together since they all touch the GUI shell:
- ``stMainBlockContainer``'s ``padding-bottom`` bumped from 0.75rem
→ 4rem (~one button-height of free space above the fixed Help/Close
footer). The last line of content on a page that fills the viewport
was previously sitting flush against the footer's top border.
- Farewell overlay's "Close this window" button removed per UX
request. The auto-dismiss path is now the only flow: try
programmatic close (works in Chrome/Edge ``--app`` windows);
failing that, surface the hint and redirect the parent window to
``about:blank`` after a short timeout. Previously the user had to
click the button to get the same fallback. The
``quit.close_window_button`` i18n key is retained as a no-op for
now in case the button comes back; nothing references it.
- Sidebar collapse → expand was broken: clicking « collapsed the
sidebar but the » expand-back affordance was invisible. Two causes
pulled apart:
1. ``.dt-brand { flex: 1 }`` was eating the entire
``stSidebarHeader`` width, squeezing Streamlit's
``stSidebarCollapseButton`` off the right edge. Changed to
``margin: 0 auto 0 0`` so the brand keeps its natural width
and the chevron has room to live next to it.
2. The "hide Streamlit chrome" toolbar block was listing
``stToolbar`` and ``stToolbarActions`` for ``display: none``
— but the post-collapse re-open button
(``stExpandSidebarButton``) lives inside ``stToolbar``, so
hiding the container killed the button too. Dropped both
container testids from the hide list and kept the per-icon
rules for ``stMainMenu`` / ``stAppDeployButton`` /
``stStatusWidget`` / ``stDecoration``.
- Loguru's stderr sink quieted in GUI mode. ``src/gui/app.py`` now
runs ``logger.remove()`` + ``logger.add(sys.stderr, level="ERROR",
…)`` at the top so internal ``logger.debug`` / ``logger.warning``
breadcrumbs (e.g.
``standardize_dataframe: 7/31 cells were unparseable``) no longer
print to the terminal when the user runs ``python -m src.gui``.
CLI entry points already do the same configuration per-script.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -25,6 +25,20 @@ if str(_project_root) not in sys.path:
|
|||||||
sys.path.insert(0, str(_project_root))
|
sys.path.insert(0, str(_project_root))
|
||||||
|
|
||||||
|
|
||||||
|
# Quiet the loguru stderr sink. The CLIs (``src/cli*.py``) reconfigure
|
||||||
|
# it per-script to ``WARNING``; the GUI's ``python -m src.gui``
|
||||||
|
# entrypoint never did, so internal ``logger.debug`` /
|
||||||
|
# ``logger.warning`` breadcrumbs bled into the terminal where users
|
||||||
|
# launched the app from. Drop the default ``DEBUG``-level stderr sink
|
||||||
|
# and add a clean ``ERROR``-only one so only genuinely actionable
|
||||||
|
# problems surface — diagnostic warnings still land in the audit log
|
||||||
|
# via its own sink. Runs once, before any module-level ``logger`` use
|
||||||
|
# in the GUI tree.
|
||||||
|
from loguru import logger as _logger # noqa: E402
|
||||||
|
_logger.remove()
|
||||||
|
_logger.add(sys.stderr, level="ERROR", format="{level: <8} | {message}")
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# Home page (rendered when the user selects the default nav entry)
|
# Home page (rendered when the user selects the default nav entry)
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
@@ -43,17 +43,17 @@ header[data-testid="stHeader"] {
|
|||||||
background: transparent !important;
|
background: transparent !important;
|
||||||
height: 0 !important;
|
height: 0 !important;
|
||||||
}
|
}
|
||||||
/* Hide every Streamlit-shipped icon button in the header band:
|
/* Hide the noisy Streamlit-shipped icon buttons in the header band
|
||||||
hamburger menu, deploy button, status / running indicator,
|
(hamburger menu, deploy button, status / running indicator). We
|
||||||
toolbar action stacks. ``toolbarMode = "viewer"`` already suppresses
|
deliberately do NOT hide ``stToolbar`` or ``stToolbarActions`` as
|
||||||
most of these but newer Streamlit releases keep emitting them with
|
containers — those wrap ``stExpandSidebarButton`` which is the
|
||||||
tiny inline styles, so we belt-and-suspenders the visibility from
|
ONLY path back to an expanded sidebar after the user collapses it.
|
||||||
CSS too. */
|
``toolbarMode = "viewer"`` already suppresses most of these icons;
|
||||||
|
the CSS belt-and-suspenders the visibility for newer Streamlit
|
||||||
|
releases that keep emitting them with inline styles. */
|
||||||
#MainMenu,
|
#MainMenu,
|
||||||
[data-testid="stMainMenu"],
|
[data-testid="stMainMenu"],
|
||||||
[data-testid="stAppDeployButton"],
|
[data-testid="stAppDeployButton"],
|
||||||
[data-testid="stToolbar"],
|
|
||||||
[data-testid="stToolbarActions"],
|
|
||||||
[data-testid="stStatusWidget"],
|
[data-testid="stStatusWidget"],
|
||||||
[data-testid="stDecoration"] {
|
[data-testid="stDecoration"] {
|
||||||
display: none !important;
|
display: none !important;
|
||||||
@@ -104,7 +104,11 @@ footer {
|
|||||||
.stMainBlockContainer,
|
.stMainBlockContainer,
|
||||||
[data-testid="stMainBlockContainer"] {
|
[data-testid="stMainBlockContainer"] {
|
||||||
padding-top: 0.5rem !important;
|
padding-top: 0.5rem !important;
|
||||||
padding-bottom: 0.75rem !important;
|
/* +4rem buys a comfortable read of the last line of content on a
|
||||||
|
page that fills the viewport: the fixed Help/Close footer is
|
||||||
|
~36px (≈2.25rem) tall and we want at least a button-height of
|
||||||
|
free space between the last widget and the footer's top edge. */
|
||||||
|
padding-bottom: 4rem !important;
|
||||||
}
|
}
|
||||||
/* Scale content to fit app window */
|
/* Scale content to fit app window */
|
||||||
.stApp {
|
.stApp {
|
||||||
@@ -192,14 +196,32 @@ body, .stApp {
|
|||||||
text. Injected into ``[data-testid="stSidebarHeader"]`` by the JS
|
text. Injected into ``[data-testid="stSidebarHeader"]`` by the JS
|
||||||
below; ``stLogoSpacer`` is hidden so the brand block takes its
|
below; ``stLogoSpacer`` is hidden so the brand block takes its
|
||||||
place flush against the left edge of the sidebar header. */
|
place flush against the left edge of the sidebar header. */
|
||||||
|
/* The brand sits next to Streamlit's sidebar collapse button inside
|
||||||
|
``stSidebarHeader``. ``flex: 1`` would steal all the horizontal
|
||||||
|
space and squash the collapse chevron out of view — once collapsed
|
||||||
|
the user would have no way to reopen the sidebar. Keep the brand
|
||||||
|
at its natural width and let the header's flex layout leave room
|
||||||
|
for the chevron on the right. */
|
||||||
.dt-brand {
|
.dt-brand {
|
||||||
display: flex !important;
|
display: flex !important;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
gap: 10px;
|
gap: 10px;
|
||||||
padding: 0 0 0 4px;
|
padding: 0 0 0 4px;
|
||||||
margin: 0;
|
margin: 0 auto 0 0;
|
||||||
height: 100%;
|
}
|
||||||
flex: 1;
|
/* Belt-and-suspenders: keep the in-sidebar collapse button + the
|
||||||
|
out-of-sidebar collapsed control reachable. The latter is what
|
||||||
|
appears on the page edge once the sidebar slides shut. */
|
||||||
|
[data-testid="stSidebarCollapseButton"],
|
||||||
|
[data-testid="stSidebarCollapseButton"] button {
|
||||||
|
display: inline-flex !important;
|
||||||
|
visibility: visible !important;
|
||||||
|
opacity: 1 !important;
|
||||||
|
}
|
||||||
|
[data-testid="stSidebarCollapsedControl"] {
|
||||||
|
display: flex !important;
|
||||||
|
visibility: visible !important;
|
||||||
|
z-index: 9999 !important;
|
||||||
}
|
}
|
||||||
/* "Letter D (sans)" wordmark per Business/DataTools/app_icons.html
|
/* "Letter D (sans)" wordmark per Business/DataTools/app_icons.html
|
||||||
§03: 28px ink-filled rounded square, cream "D" in Geist 700 with
|
§03: 28px ink-filled rounded square, cream "D" in Geist 700 with
|
||||||
@@ -1274,12 +1296,7 @@ _FAREWELL_SCRIPT_TEMPLATE = """
|
|||||||
'border-radius:12px;background:#161922;max-width:480px;">' +
|
'border-radius:12px;background:#161922;max-width:480px;">' +
|
||||||
'<h1 style="margin:0 0 8px 0;font-weight:600;letter-spacing:-0.01em;">' +
|
'<h1 style="margin:0 0 8px 0;font-weight:600;letter-spacing:-0.01em;">' +
|
||||||
'__TITLE__</h1>' +
|
'__TITLE__</h1>' +
|
||||||
'<p style="opacity:0.7;margin:0 0 20px 0;">__SUBTITLE__</p>' +
|
'<p style="opacity:0.7;margin:0;">__SUBTITLE__</p>' +
|
||||||
'<button id="datatools-close-btn" style="' +
|
|
||||||
'background:#6ee7b7;color:#052e1a;font-weight:600;' +
|
|
||||||
'padding:10px 20px;border-radius:8px;border:none;' +
|
|
||||||
'font-size:15px;cursor:pointer;font-family:inherit;">' +
|
|
||||||
'__CLOSE_BTN__</button>' +
|
|
||||||
'<p id="datatools-close-hint" style="' +
|
'<p id="datatools-close-hint" style="' +
|
||||||
'display:none;font-size:13px;opacity:0.6;margin:14px 0 0 0;">' +
|
'display:none;font-size:13px;opacity:0.6;margin:14px 0 0 0;">' +
|
||||||
'__CLOSE_HINT__</p>' +
|
'__CLOSE_HINT__</p>' +
|
||||||
@@ -1310,21 +1327,21 @@ _FAREWELL_SCRIPT_TEMPLATE = """
|
|||||||
// push to history.
|
// push to history.
|
||||||
try { win.location.replace('about:blank'); } catch (e) {}
|
try { win.location.replace('about:blank'); } catch (e) {}
|
||||||
}
|
}
|
||||||
function wireClose(doc, win) {
|
function autoDismiss(doc, win) {
|
||||||
var btn = doc.getElementById('datatools-close-btn');
|
// Try the programmatic close first — succeeds in Chrome/Edge
|
||||||
if (!btn) return;
|
// --app windows. If it fails (regular browser tab), surface the
|
||||||
btn.onclick = function () {
|
// hint and auto-redirect to about:blank so the user lands on a
|
||||||
var standalone = isStandalone(win);
|
// clean page instead of the frozen farewell overlay. The "Close
|
||||||
if (tryClose(win)) return;
|
// this window" button used to drive the same flow on click; we
|
||||||
// Close failed (or definitely will fail in a regular tab).
|
// dropped that affordance per UX request, so this auto-timer is
|
||||||
// Surface the hint immediately, then redirect to about:blank
|
// the only path on regular tabs.
|
||||||
// after a short delay so the user has a moment to read why.
|
var standalone = isStandalone(win);
|
||||||
var hint = doc.getElementById('datatools-close-hint');
|
if (tryClose(win)) return;
|
||||||
if (hint) hint.style.display = 'block';
|
var hint = doc.getElementById('datatools-close-hint');
|
||||||
setTimeout(function () {
|
if (hint) hint.style.display = 'block';
|
||||||
if (!win.closed) fallbackToBlank(win);
|
setTimeout(function () {
|
||||||
}, standalone ? 250 : 1500);
|
if (!win.closed) fallbackToBlank(win);
|
||||||
};
|
}, standalone ? 400 : 2500);
|
||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
var doc = window.top.document;
|
var doc = window.top.document;
|
||||||
@@ -1332,17 +1349,12 @@ _FAREWELL_SCRIPT_TEMPLATE = """
|
|||||||
if (!doc.getElementById('datatools-farewell-overlay')) {
|
if (!doc.getElementById('datatools-farewell-overlay')) {
|
||||||
doc.body.appendChild(buildOverlay(doc));
|
doc.body.appendChild(buildOverlay(doc));
|
||||||
}
|
}
|
||||||
wireClose(doc, win);
|
autoDismiss(doc, win);
|
||||||
// Auto-close attempt on first paint — succeeds in Chrome --app
|
|
||||||
// windows, fails silently on regular tabs (and we don't redirect
|
|
||||||
// automatically here; the manual button drives that path so the
|
|
||||||
// user is in control).
|
|
||||||
tryClose(win);
|
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
// Cross-origin access denied (shouldn't happen given Streamlit's
|
// Cross-origin access denied (shouldn't happen given Streamlit's
|
||||||
// sandbox flags, but fall back gracefully): cover this iframe.
|
// sandbox flags, but fall back gracefully): cover this iframe.
|
||||||
document.body.appendChild(buildOverlay(document));
|
document.body.appendChild(buildOverlay(document));
|
||||||
wireClose(document, window);
|
autoDismiss(document, window);
|
||||||
}
|
}
|
||||||
})();
|
})();
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
Reference in New Issue
Block a user