fix: stabilize mini app mobile navigation

This commit is contained in:
3252a8
2026-06-08 10:32:53 +03:00
parent 63192659e4
commit d2149357c6
3 changed files with 90 additions and 3 deletions
+14 -2
View File
@@ -1474,7 +1474,7 @@ def _resolve_hashed_js_asset_name(*, kind: str, base_name: str) -> str:
if minified_assets:
minified_assets.sort(reverse=True)
return _set_cached_asset_name(kind, minified_assets[0][1])
return _set_cached_asset_name(kind, f"{base_name}.js")
return _set_cached_asset_name(kind, _stable_asset_name_with_version(f"{base_name}.js"))
def _resolve_webapp_css_asset_name() -> str:
@@ -1506,7 +1506,19 @@ def _resolve_hashed_css_asset_name(*, kind: str, base_name: str) -> str:
if hashed_assets:
hashed_assets.sort(reverse=True)
return _set_cached_asset_name(kind, hashed_assets[0][1])
return _set_cached_asset_name(kind, f"{base_name}.css")
return _set_cached_asset_name(kind, _stable_asset_name_with_version(f"{base_name}.css"))
def _stable_asset_name_with_version(filename: str) -> str:
path = ASSET_DIR / filename
try:
stat = path.stat()
except OSError:
return filename
raw_version = f"{filename}:{int(stat.st_mtime_ns)}:{int(stat.st_size)}"
version = hashlib.sha256(raw_version.encode("utf-8")).hexdigest()[:8]
return f"{filename}?v={version}"
def _get_cached_asset_name(kind: str) -> Optional[str]:
+48 -1
View File
@@ -2154,8 +2154,11 @@ a {
display: grid;
grid-template-columns: repeat(var(--bottom-nav-visible-items, 3), minmax(0, 1fr));
grid-auto-flow: column;
grid-auto-columns: minmax(0, 1fr);
grid-auto-rows: 1fr;
height: var(--bottom-nav-height);
gap: 2px;
min-height: 64px;
min-height: var(--bottom-nav-height);
overflow: hidden;
border: 1px solid var(--border);
border-radius: var(--radius);
@@ -2174,7 +2177,11 @@ a {
.bottom-nav button {
display: grid;
grid-template-rows: 22px minmax(0, 12px);
width: 100%;
height: 100%;
min-width: 0;
min-height: 0;
place-items: center;
align-content: center;
gap: 4px;
@@ -2185,6 +2192,13 @@ a {
font-weight: 800;
overflow: hidden;
padding: 6px 2px;
line-height: 1;
}
.bottom-nav button > svg {
width: 21px;
height: 21px;
min-width: 0;
}
.bottom-nav button.active {
@@ -2193,10 +2207,12 @@ a {
.bottom-nav .bottom-nav-label {
display: block;
width: 100%;
max-width: 100%;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
font-size: 10px;
line-height: 1.1;
}
@@ -2204,12 +2220,40 @@ a {
display: none !important;
}
@media (max-width: 460px) {
.bottom-nav.bottom-nav-many {
height: 58px;
min-height: 58px;
}
.bottom-nav.bottom-nav-many button {
grid-template-rows: 1fr;
gap: 0;
padding: 0 2px;
}
.bottom-nav.bottom-nav-many .bottom-nav-label {
display: none;
}
.bottom-nav.bottom-nav-many .nav-attention-dot {
top: 8px;
right: calc(50% - 18px);
}
.bottom-nav.bottom-nav-many .nav-badge-floating {
top: 6px;
right: calc(50% - 24px);
}
}
@media (max-width: 380px) {
.bottom-nav.bottom-nav-many {
min-height: 58px;
}
.bottom-nav.bottom-nav-many button {
grid-template-rows: 1fr;
gap: 0;
padding: 0 2px;
}
@@ -2231,10 +2275,12 @@ a {
@media (max-width: 360px) {
.bottom-nav {
height: 56px;
min-height: 56px;
}
.bottom-nav button {
grid-template-rows: 1fr;
gap: 0;
padding: 0 2px;
}
@@ -3149,6 +3195,7 @@ a {
display: grid !important;
grid-template-columns: 22px 1fr !important;
grid-template-rows: auto !important;
height: auto !important;
align-items: center !important;
justify-items: start !important;
gap: 12px !important;
+28
View File
@@ -335,6 +335,15 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
self.assertIn("<title>Subscription</title>", html)
self.assertLess(html.index("/subscription_webapp.css"), html.index("WEBAPP_JS_SCRIPT"))
def test_mobile_bottom_nav_many_items_uses_compact_phone_layout(self):
css_path = Path(__file__).resolve().parents[1] / "frontend/src/styles/webapp.css"
css = css_path.read_text(encoding="utf-8")
self.assertIn("@media (max-width: 460px)", css)
self.assertIn(".bottom-nav.bottom-nav-many", css)
self.assertIn(".bottom-nav.bottom-nav-many .bottom-nav-label", css)
self.assertIn("display: none;", css)
def test_https_webapp_logo_uses_same_origin_proxy(self):
settings = SimpleNamespace(WEBAPP_LOGO_URL="https://cdn.example.com/logo.png")
@@ -981,6 +990,25 @@ class WebAppAssetTests(unittest.IsolatedAsyncioTestCase):
"subscription_webapp.min.22222222.js",
)
def test_resolve_webapp_asset_names_version_stable_fallbacks(self):
with tempfile.TemporaryDirectory() as tmpdir:
asset_dir = Path(tmpdir)
(asset_dir / "subscription_webapp.js").write_text(
"console.log('fallback');", encoding="utf-8"
)
(asset_dir / "subscription_webapp.css").write_text(".app{color:red}", encoding="utf-8")
with patch.object(webapp_assets, "ASSET_DIR", asset_dir):
webapp_assets._ASSET_NAME_CACHE.clear()
self.assertRegex(
subscription_webapp._resolve_webapp_js_asset_name(),
r"^subscription_webapp\.js\?v=[0-9a-f]{8}$",
)
self.assertRegex(
subscription_webapp._resolve_webapp_css_asset_name(),
r"^subscription_webapp\.css\?v=[0-9a-f]{8}$",
)
def test_resolve_webapp_admin_asset_names_use_stable_runtime_builds(self):
with tempfile.TemporaryDirectory() as tmpdir:
asset_dir = Path(tmpdir)