04/19 Continue fixing the UI issues with Chrome
This commit is contained in:
@@ -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):
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
+440
-1146
File diff suppressed because it is too large
Load Diff
@@ -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');
|
||||||
|
}
|
||||||
|
})();
|
||||||
+851
-1634
File diff suppressed because it is too large
Load Diff
+21
-24
@@ -1,28 +1,25 @@
|
|||||||
<!doctype html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
|
||||||
<meta charset="UTF-8" />
|
|
||||||
<meta
|
|
||||||
name="viewport"
|
|
||||||
content="width=device-width, initial-scale=1.0, viewport-fit=cover"
|
|
||||||
/>
|
|
||||||
<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>
|
|
||||||
<link
|
|
||||||
rel="stylesheet"
|
|
||||||
href="{{ url_for('static', filename='css/app.css') }}"
|
|
||||||
/>
|
|
||||||
{% block head_extra %}{% endblock %}
|
|
||||||
</head>
|
|
||||||
<body class="{% block body_class %}{% endblock %}">
|
|
||||||
{% block body %}{% endblock %}
|
|
||||||
|
|
||||||
<div id="toast" class="toast" aria-live="polite"></div>
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, viewport-fit=cover">
|
||||||
|
<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>
|
||||||
|
<!-- layout-init.js MUST be synchronous (no defer/async) so it runs before body renders -->
|
||||||
|
<script src="{{ url_for('static', filename='js/layout-init.js') }}?v={{ sv }}"></script>
|
||||||
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/app.css') }}?v={{ sv }}">
|
||||||
|
{% block head_extra %}{% endblock %}
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body class="{% block body_class %}{% endblock %}">
|
||||||
|
{% block body %}{% endblock %}
|
||||||
|
|
||||||
|
<div id="toast" class="toast" aria-live="polite"></div>
|
||||||
|
|
||||||
|
{% block scripts %}{% endblock %}
|
||||||
|
</body>
|
||||||
|
|
||||||
{% block scripts %}{% endblock %}
|
|
||||||
</body>
|
|
||||||
</html>
|
</html>
|
||||||
Reference in New Issue
Block a user