04/19 Continue fixing the UI issues with Chrome

This commit is contained in:
Nguyen Ngo
2026-04-19 09:40:48 -04:00
parent d2240bc4d7
commit 562cb85de9
6 changed files with 1351 additions and 2808 deletions
+4
View File
@@ -31,6 +31,10 @@ def create_app(config_name: str = 'development') -> Flask:
cors_origins = app.config.get('CORS_ORIGINS', '*') cors_origins = app.config.get('CORS_ORIGINS', '*')
CORS(app, resources={r'/api/*': {'origins': cors_origins}}) CORS(app, resources={r'/api/*': {'origins': cors_origins}})
# Inject static asset version into every template for cache-busting.
# Usage in templates: {{ url_for('static', filename='css/app.css') }}?v={{ sv }}
app.jinja_env.globals['sv'] = app.config.get('STATIC_VERSION', '1')
# Attach security headers to every response # Attach security headers to every response
@app.after_request @app.after_request
def set_security_headers(response): def set_security_headers(response):
+5
View File
@@ -41,6 +41,11 @@ class BaseConfig:
# CORS — restrict to the production origin in production config. # CORS — restrict to the production origin in production config.
CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '*') CORS_ORIGINS = os.environ.get('CORS_ORIGINS', '*')
# Cache-busting version string appended as ?v=... to all static assets.
# Bump this value on every deploy to force browsers to reload CSS/JS.
# Set via .env: STATIC_VERSION=20260418
STATIC_VERSION = os.environ.get('STATIC_VERSION', '1')
class DevelopmentConfig(BaseConfig): class DevelopmentConfig(BaseConfig):
DEBUG = True DEBUG = True
+423 -1129
View File
File diff suppressed because it is too large Load Diff
+26
View File
@@ -0,0 +1,26 @@
/**
* layout-init.js — runs synchronously in <head> before body renders.
*
* Sets html.is-mobile or html.is-desktop immediately so CSS scoped to
* those classes takes effect on the very first paint. No flash, no
* layout shift, works on Chrome and Safari equally.
*
* Also restores the sidebar collapsed state on desktop so the sidebar
* width is correct from the very first frame.
*
* Must be loaded with NO defer/async attribute so it blocks parsing
* until it runs — that's intentional and necessary.
*/
(function () {
var isMobile = window.matchMedia('(max-width: 768px)').matches;
document.documentElement.classList.add(isMobile ? 'is-mobile' : 'is-desktop');
// On desktop, restore collapsed state from localStorage so the sidebar
// renders at the correct width without any visual jump.
if (!isMobile && localStorage.getItem('sidebar_collapsed') === '1') {
// We can't set it on #sidebar yet (body not parsed), so we use a
// temporary html class that CSS can target, then vault.js adds
// .collapsed to the sidebar element on DOMContentLoaded.
document.documentElement.classList.add('sidebar-will-collapse');
}
})();
+798 -1581
View File
File diff suppressed because it is too large Load Diff
+12 -15
View File
@@ -1,23 +1,19 @@
<!doctype html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="UTF-8" /> <meta charset="UTF-8">
<meta <meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
name="viewport" <meta http-equiv="Content-Security-Policy"
content="width=device-width, initial-scale=1.0, viewport-fit=cover" content="default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self';">
/> <meta name="csrf-token" content="{{ csrf_token() }}">
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self'; img-src 'self' data:; font-src 'self';"
/>
<meta name="csrf-token" content="{{ csrf_token() }}" />
<title>{% block title %}PassKeeper{% endblock %}</title> <title>{% block title %}PassKeeper{% endblock %}</title>
<link <!-- layout-init.js MUST be synchronous (no defer/async) so it runs before body renders -->
rel="stylesheet" <script src="{{ url_for('static', filename='js/layout-init.js') }}?v={{ sv }}"></script>
href="{{ url_for('static', filename='css/app.css') }}" <link rel="stylesheet" href="{{ url_for('static', filename='css/app.css') }}?v={{ sv }}">
/>
{% block head_extra %}{% endblock %} {% block head_extra %}{% endblock %}
</head> </head>
<body class="{% block body_class %}{% endblock %}"> <body class="{% block body_class %}{% endblock %}">
{% block body %}{% endblock %} {% block body %}{% endblock %}
@@ -25,4 +21,5 @@
{% block scripts %}{% endblock %} {% block scripts %}{% endblock %}
</body> </body>
</html> </html>