Add PWA support: installable standalone app with safe area handling

- Service worker, manifest, and SVG icon for PWA installability
- Root /sw.js route for full-scope service worker registration
- Meta tags: theme-color, apple-mobile-web-app, viewport-fit=cover
- Safe area insets for notched phones (container, mini-player, footer, banner)
- Dynamic theme-color sync on light/dark toggle
- Overscroll prevention and touch-action optimization
- Hide mini-player prev/next buttons on small screens
- Updated README with PWA and new feature documentation

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-01 13:17:56 +03:00
parent 652f10fc4c
commit a20812ec29
9 changed files with 182 additions and 6 deletions

View File

@@ -3067,6 +3067,10 @@ footer .separator {
padding-top: calc(0.5rem + 2px);
}
.mini-nav-btn {
display: none;
}
.mini-player-info {
min-width: 120px;
}
@@ -3164,3 +3168,72 @@ footer .separator {
justify-content: flex-start;
}
}
/* ========================================
PWA Standalone & Mobile Polish
======================================== */
html {
overscroll-behavior: none;
}
/* Safe area insets for notched phones (viewport-fit=cover) */
.container {
padding-left: max(0.75rem, env(safe-area-inset-left));
padding-right: max(0.75rem, env(safe-area-inset-right));
}
.mini-player {
padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
padding-left: max(1rem, env(safe-area-inset-left));
padding-right: max(1rem, env(safe-area-inset-right));
}
footer {
padding-bottom: max(0.75rem, env(safe-area-inset-bottom));
}
body.mini-player-visible footer {
padding-bottom: calc(70px + env(safe-area-inset-bottom, 0px));
}
.connection-banner {
padding-top: max(10px, env(safe-area-inset-top));
}
/* Touch optimization: eliminate 300ms tap delay */
.controls button,
.mini-controls button,
.mini-control-btn,
.tab-btn,
.header-btn,
.header-link,
.mute-btn,
.vinyl-toggle-btn,
.view-toggle-btn,
.browser-item,
.browser-list-item,
.script-btn,
.action-btn {
touch-action: manipulation;
}
@media (max-width: 600px) {
.container {
padding-left: max(0.5rem, env(safe-area-inset-left));
padding-right: max(0.5rem, env(safe-area-inset-right));
}
.mini-player {
padding-bottom: max(0.5rem, env(safe-area-inset-bottom));
padding-left: max(0.75rem, env(safe-area-inset-left));
padding-right: max(0.75rem, env(safe-area-inset-right));
}
}
@media (display-mode: standalone) {
body {
overscroll-behavior-y: none;
-webkit-overflow-scrolling: touch;
}
}