fix(ui,auth): fix login overlay styles, PWA service worker scope, favicon, and update user config to kopri
This commit is contained in:
1 parent
d82bb9e8e9
commit
c51c505b61
5 files changed
+72
-19
No files matched your search
+12
@@ -147,6 +147,18 @@ async def manifest_endpoint():
|
|||||||
raise HTTPException(status_code=404, detail="Manifest not found")
|
raise HTTPException(status_code=404, detail="Manifest not found")
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/favicon.ico", include_in_schema=False)
|
||||||
|
async def favicon_endpoint():
|
||||||
|
icon_path = config.BASE_DIR / "app" / "static" / "icons" / "icon-192.png"
|
||||||
|
if icon_path.exists():
|
||||||
|
return Response(
|
||||||
|
content=icon_path.read_bytes(),
|
||||||
|
media_type="image/png",
|
||||||
|
headers={"Cache-Control": "public, max-age=86400"},
|
||||||
|
)
|
||||||
|
raise HTTPException(status_code=404, detail="Favicon not found")
|
||||||
|
|
||||||
|
|
||||||
@app.get("/sw.js", include_in_schema=False)
|
@app.get("/sw.js", include_in_schema=False)
|
||||||
async def service_worker_endpoint():
|
async def service_worker_endpoint():
|
||||||
sw_path = config.BASE_DIR / "app" / "static" / "sw.js"
|
sw_path = config.BASE_DIR / "app" / "static" / "sw.js"
|
||||||
|
|||||||
@@ -88,17 +88,23 @@ body {
|
|||||||
display: none !important;
|
display: none !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Auth Screen */
|
/* Auth Screen / Login Overlay */
|
||||||
.auth-screen {
|
.auth-screen,
|
||||||
|
.login-overlay {
|
||||||
|
position: fixed;
|
||||||
|
inset: 0;
|
||||||
|
z-index: 10000;
|
||||||
min-height: 100vh;
|
min-height: 100vh;
|
||||||
display: flex;
|
display: flex;
|
||||||
align-items: center;
|
align-items: center;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
padding: 20px;
|
padding: 20px;
|
||||||
background: radial-gradient(circle at top, rgba(56, 189, 248, 0.12), transparent 70%);
|
background-color: var(--bg-main);
|
||||||
|
background-image: radial-gradient(circle at top, rgba(56, 189, 248, 0.15), transparent 70%);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-card {
|
.auth-card,
|
||||||
|
.login-card {
|
||||||
background-color: var(--bg-surface);
|
background-color: var(--bg-surface);
|
||||||
border: 1px solid var(--border-color);
|
border: 1px solid var(--border-color);
|
||||||
border-radius: var(--radius-lg);
|
border-radius: var(--radius-lg);
|
||||||
@@ -106,31 +112,65 @@ body {
|
|||||||
width: 100%;
|
width: 100%;
|
||||||
max-width: 420px;
|
max-width: 420px;
|
||||||
box-shadow: var(--shadow-lg);
|
box-shadow: var(--shadow-lg);
|
||||||
|
animation: fadeInScale 0.2s ease-out;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-header {
|
@keyframes fadeInScale {
|
||||||
|
from {
|
||||||
|
opacity: 0;
|
||||||
|
transform: scale(0.96);
|
||||||
|
}
|
||||||
|
to {
|
||||||
|
opacity: 1;
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-header,
|
||||||
|
.login-header {
|
||||||
text-align: center;
|
text-align: center;
|
||||||
margin-bottom: 28px;
|
margin-bottom: 28px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-header .app-logo {
|
.auth-header .app-logo,
|
||||||
|
.login-header .login-logo {
|
||||||
font-size: 48px;
|
font-size: 48px;
|
||||||
margin-bottom: 8px;
|
margin-bottom: 8px;
|
||||||
|
display: block;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-header h2 {
|
.auth-header h2,
|
||||||
|
.login-header h1 {
|
||||||
font-size: 24px;
|
font-size: 24px;
|
||||||
font-weight: 700;
|
font-weight: 700;
|
||||||
color: var(--text-main);
|
color: var(--text-main);
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-header p {
|
.auth-header p,
|
||||||
|
.login-header p {
|
||||||
color: var(--text-muted);
|
color: var(--text-muted);
|
||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
margin-top: 4px;
|
margin-top: 4px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.auth-footer {
|
.login-form {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
}
|
||||||
|
|
||||||
|
.login-error {
|
||||||
|
background-color: var(--danger-dim);
|
||||||
|
color: var(--danger);
|
||||||
|
border: 1px solid var(--danger);
|
||||||
|
padding: 10px 14px;
|
||||||
|
border-radius: var(--radius-sm);
|
||||||
|
font-size: 13px;
|
||||||
|
margin-bottom: 16px;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.auth-footer,
|
||||||
|
.login-footer {
|
||||||
margin-top: 24px;
|
margin-top: 24px;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
font-size: 12px;
|
font-size: 12px;
|
||||||
|
|||||||
@@ -13,6 +13,7 @@
|
|||||||
<meta name="apple-mobile-web-app-capable" content="yes">
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
|
||||||
<meta name="apple-mobile-web-app-title" content="Notes English">
|
<meta name="apple-mobile-web-app-title" content="Notes English">
|
||||||
|
<link rel="icon" type="image/png" href="/static/icons/icon-192.png">
|
||||||
<link rel="apple-touch-icon" href="/static/icons/icon-192.png">
|
<link rel="apple-touch-icon" href="/static/icons/icon-192.png">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
@@ -28,7 +29,7 @@
|
|||||||
<form id="login-form" class="login-form">
|
<form id="login-form" class="login-form">
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label for="login-username">Имя пользователя</label>
|
<label for="login-username">Имя пользователя</label>
|
||||||
<input type="text" id="login-username" class="input-styled" autocomplete="username" required autofocus placeholder="admin">
|
<input type="text" id="login-username" class="input-styled" autocomplete="username" required autofocus placeholder="kopri">
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
@@ -43,13 +44,13 @@
|
|||||||
</button>
|
</button>
|
||||||
</form>
|
</form>
|
||||||
<div class="login-footer">
|
<div class="login-footer">
|
||||||
<small>Безопасное хранилище словаря • notes.qpid.pro</small>
|
<small>Безопасное хранилище словаря • study.qpid.pro</small>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Main Application Shell -->
|
<!-- Main Application Shell -->
|
||||||
<div id="app-shell" class="app-shell">
|
<div id="app-shell" class="app-shell hidden">
|
||||||
<!-- Top Navigation Bar -->
|
<!-- Top Navigation Bar -->
|
||||||
<header class="navbar">
|
<header class="navbar">
|
||||||
<div class="nav-brand" id="nav-brand-home" title="На главную">
|
<div class="nav-brand" id="nav-brand-home" title="На главную">
|
||||||
|
|||||||
@@ -2,11 +2,9 @@
|
|||||||
document.addEventListener('DOMContentLoaded', () => {
|
document.addEventListener('DOMContentLoaded', () => {
|
||||||
// Register PWA Service Worker
|
// Register PWA Service Worker
|
||||||
if ('serviceWorker' in navigator) {
|
if ('serviceWorker' in navigator) {
|
||||||
window.addEventListener('load', () => {
|
navigator.serviceWorker.register('/sw.js', { scope: '/' })
|
||||||
navigator.serviceWorker.register('/static/sw.js')
|
.then(reg => console.log('Notes PWA ServiceWorker active:', reg.scope))
|
||||||
.then(reg => console.log('Notes PWA ServiceWorker active:', reg.scope))
|
.catch(err => console.log('Notes ServiceWorker failed:', err));
|
||||||
.catch(err => console.log('Notes ServiceWorker failed:', err));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// App State
|
// App State
|
||||||
@@ -316,11 +314,13 @@ document.addEventListener('DOMContentLoaded', () => {
|
|||||||
|
|
||||||
function showLogin() {
|
function showLogin() {
|
||||||
loginOverlay.classList.remove('hidden');
|
loginOverlay.classList.remove('hidden');
|
||||||
|
if (appShell) appShell.classList.add('hidden');
|
||||||
loginUsername.focus();
|
loginUsername.focus();
|
||||||
}
|
}
|
||||||
|
|
||||||
function showApp() {
|
function showApp() {
|
||||||
loginOverlay.classList.add('hidden');
|
loginOverlay.classList.add('hidden');
|
||||||
|
if (appShell) appShell.classList.remove('hidden');
|
||||||
userDisplayName.textContent = currentUser ? currentUser.username : 'user';
|
userDisplayName.textContent = currentUser ? currentUser.username : 'user';
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+2
-2
@@ -12,6 +12,6 @@ services:
|
|||||||
- PORT=8002
|
- PORT=8002
|
||||||
- DEBUG=False
|
- DEBUG=False
|
||||||
- SECRET_KEY=study-qpid-pro-secret-key-change-in-prod
|
- SECRET_KEY=study-qpid-pro-secret-key-change-in-prod
|
||||||
- ADMIN_USERNAME=admin
|
- ADMIN_USERNAME=kopri
|
||||||
- ADMIN_PASSWORD=adminpass
|
- ADMIN_PASSWORD=kopri2026pass
|
||||||
- DB_PATH=/app/data/notes.db
|
- DB_PATH=/app/data/notes.db
|
||||||
Reference in new issue
Block a user