Add mobile responsiveness + PWA support

Mobile (768px):
- Tab bar: horizontal scroll with momentum, hidden scrollbar
- Header: compact layout, smaller fonts
- Tables: horizontal scroll, hide-mobile class for less important cols
- Modals: bottom-sheet style, full width
- Touch targets: min-height 36px for buttons/selects
- Toolbar: stacks vertically
- Stat cards: compact

Small phone (480px):
- Even more compact header and tabs
- Smaller table cells
- iOS zoom prevention (16px font on inputs)

PWA:
- manifest.json for Add to Home Screen
- apple-mobile-web-app-capable meta tags
- theme-color for status bar
- overscroll-behavior: none (prevent pull-to-refresh)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-03-13 18:33:48 +02:00
parent 45de863d07
commit 77dc790b0f
4 changed files with 237 additions and 23 deletions

View File

@@ -2,9 +2,13 @@
<html lang="fi"> <html lang="fi">
<head> <head>
<meta charset="UTF-8"> <meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="theme-color" content="#0f3460">
<link rel="manifest" href="manifest.json">
<title>Noxus HUB</title> <title>Noxus HUB</title>
<link rel="stylesheet" href="style.css?v=20260313w"> <link rel="stylesheet" href="style.css?v=20260313x">
</head> </head>
<body> <body>
<!-- Login --> <!-- Login -->
@@ -1480,9 +1484,9 @@
<tr> <tr>
<th>Käyttäjätunnus</th> <th>Käyttäjätunnus</th>
<th>Nimi</th> <th>Nimi</th>
<th>Sähköposti</th> <th class="hide-mobile">Sähköposti</th>
<th>Rooli</th> <th>Rooli</th>
<th>Luotu</th> <th class="hide-mobile">Luotu</th>
<th>Toiminnot</th> <th>Toiminnot</th>
</tr> </tr>
</thead> </thead>

22
manifest.json Normal file
View File

@@ -0,0 +1,22 @@
{
"name": "Noxus HUB",
"short_name": "HUB",
"description": "Noxus HUB - Hallintapaneeli",
"start_url": "/",
"display": "standalone",
"orientation": "any",
"background_color": "#0f3460",
"theme_color": "#0f3460",
"icons": [
{
"src": "icon-192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "icon-512.png",
"sizes": "512x512",
"type": "image/png"
}
]
}

View File

@@ -1208,9 +1208,9 @@ function renderUserRow(u, companyId) {
return `<tr> return `<tr>
<td><strong>${esc(u.username)}</strong></td> <td><strong>${esc(u.username)}</strong></td>
<td>${esc(u.nimi)}</td> <td>${esc(u.nimi)}</td>
<td>${esc(u.email || '')}</td> <td class="hide-mobile">${esc(u.email || '')}</td>
<td>${role}</td> <td>${role}</td>
<td>${esc(u.luotu)}</td> <td class="hide-mobile">${esc(u.luotu)}</td>
<td class="actions-cell"> <td class="actions-cell">
<button onclick="editUser('${u.id}')" title="Muokkaa">&#9998;</button> <button onclick="editUser('${u.id}')" title="Muokkaa">&#9998;</button>
${u.id !== currentUser?.id ? `<button onclick="deleteUser('${u.id}','${esc(u.username)}')" title="Poista">&#128465;</button>` : ''} ${u.id !== currentUser?.id ? `<button onclick="deleteUser('${u.id}','${esc(u.username)}')" title="Poista">&#128465;</button>` : ''}

222
style.css
View File

@@ -970,7 +970,9 @@ span.empty {
background: #fef2f2; background: #fef2f2;
} }
/* Responsive */ /* ==================== RESPONSIVE ==================== */
/* Tablet */
@media (max-width: 1024px) { @media (max-width: 1024px) {
.content-layout { .content-layout {
grid-template-columns: 1fr; grid-template-columns: 1fr;
@@ -989,51 +991,237 @@ span.empty {
} }
} }
/* Mobile */
@media (max-width: 768px) { @media (max-width: 768px) {
/* Header: kompakti mobiilissa */
header { header {
flex-direction: column; padding: 0.6rem 1rem;
gap: 0.75rem; gap: 0.4rem;
padding: 1rem;
text-align: center;
} }
.header-brand { .header-left h1 {
justify-content: center; font-size: 1rem;
} }
.header-brand img {
height: 28px;
}
.header-right {
gap: 0.3rem;
font-size: 0.8rem;
}
.header-right .btn-primary,
.header-right .btn-secondary {
padding: 5px 8px;
font-size: 0.75rem;
}
.user-info {
font-size: 0.78rem;
}
/* Tab bar: horisontaalinen scroll */
.tab-bar {
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: none; /* Firefox */
padding: 0 0.5rem;
top: 44px; /* pienempi header */
}
.tab-bar::-webkit-scrollbar {
display: none;
}
.tab {
padding: 0.6rem 0.9rem;
font-size: 0.78rem;
white-space: nowrap;
flex-shrink: 0;
}
/* Sub-tab bar: sama horisontaalinen scroll */
.sub-tab-bar {
overflow-x: auto;
overflow-y: hidden;
-webkit-overflow-scrolling: touch;
scrollbar-width: none;
padding: 0 0.5rem;
}
.sub-tab-bar::-webkit-scrollbar {
display: none;
}
.sub-tab {
padding: 0.5rem 0.8rem;
font-size: 0.78rem;
white-space: nowrap;
flex-shrink: 0;
}
/* Main container */
.main-container { .main-container {
padding: 1rem; padding: 0.75rem;
} }
/* Lomakkeet */
.form-grid, .form-grid,
.form-grid-liittyma, .form-grid-liittyma,
.detail-grid { .detail-grid {
grid-template-columns: 1fr; grid-template-columns: 1fr;
} }
/* Yhteenvetopalkki */
.summary-bar { .summary-bar {
flex-direction: column; flex-direction: column;
gap: 0.25rem; gap: 0.25rem;
text-align: center; text-align: center;
} }
/* Taulukot: horisontaalinen scroll */
.table-card {
overflow-x: auto;
-webkit-overflow-scrolling: touch;
}
thead th, thead th,
tbody td { tbody td {
padding: 9px 10px; padding: 8px 8px;
font-size: 0.83rem; font-size: 0.8rem;
}
/* Toolbar: pinoa mobiilissa */
.toolbar {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.toolbar .search-bar {
width: 100%;
}
.toolbar .search-bar input {
width: 100%;
}
/* Modaalit: täysi leveys */
.modal-content {
max-width: 100%;
max-height: 95vh;
border-radius: 12px 12px 0 0;
margin-top: auto;
}
.modal {
align-items: flex-end;
padding: 0;
}
.modal-header {
padding: 1rem;
}
.modal-header h2 {
font-size: 1.1rem;
}
/* Modaalin sisältöpadding */
.modal-content form,
.modal-content .modal-body {
padding: 0.75rem;
}
/* Stat-kortit mobiilissa */
.stat-card {
padding: 0.75rem;
}
.stat-card h3 {
font-size: 0.75rem;
}
.stat-card .stat-number {
font-size: 1.3rem;
}
/* Sidebar: kompaktimpi */
.sidebar-stats .stat-card {
min-width: 100px;
}
/* Tikettinäkymä: kompaktimpi */
#ticket-detail-header select {
padding: 5px 6px !important;
font-size: 0.78rem !important;
}
/* Touch-ystävälliset napit — isommat klikattavat alueet */
button, .btn-primary, .btn-secondary, select {
min-height: 36px;
}
/* Piilota vähemmän tärkeät kolumnit */
.hide-mobile {
display: none !important;
} }
} }
/* Pieni puhelin */
@media (max-width: 480px) { @media (max-width: 480px) {
.header-right { header {
flex-direction: column; padding: 0.5rem 0.75rem;
width: 100%;
} }
.header-right .btn-primary, .header-left h1 {
.header-right .btn-secondary { font-size: 0.9rem;
width: 100%; }
text-align: center;
/* Piilota "Vaihda yritys" teksti, näytä vain ikoni/select */
.header-right {
flex-wrap: wrap;
gap: 0.25rem;
justify-content: center;
}
.tab {
padding: 0.5rem 0.7rem;
font-size: 0.72rem;
}
.tab-bar {
top: 38px;
}
/* Taulukot: pienempi fontti */
thead th,
tbody td {
padding: 6px 6px;
font-size: 0.75rem;
}
/* Actions-sarake: pienemmät napit */
.actions-cell button {
padding: 3px 5px;
font-size: 0.75rem;
}
/* Modaalin lomakekentät */
.modal-content input,
.modal-content select,
.modal-content textarea {
font-size: 16px; /* Estää iOS zoom-in focuksessa */
}
}
/* PWA-tyylinen kokemus: estä pull-to-refresh ja bounce */
@media (max-width: 768px) {
html {
overscroll-behavior: none;
} }
} }