When offline, hide Files and Admin from the bottom nav and display "Offline Mode" next to the status dot. The SW offline fallback page also only shows Capture and Queue nav items. Online-only pages (browser, admin, reviewer) are never cached and go straight to the offline fallback when the network is unavailable. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
111 lines
4.6 KiB
HTML
111 lines
4.6 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
|
|
|
<!-- PWA Meta Tags -->
|
|
<meta name="theme-color" content="#16213e">
|
|
<link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
|
|
|
|
<!-- iOS PWA Support -->
|
|
<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-title" content="NextSnap">
|
|
<link rel="apple-touch-icon" href="{{ url_for('static', filename='icons/icon-192.png') }}">
|
|
|
|
<title>{% block title %}NextSnap{% endblock %}</title>
|
|
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
|
{% block extra_css %}{% endblock %}
|
|
</head>
|
|
<body>
|
|
<!-- Top Bar -->
|
|
<header class="top-bar">
|
|
<div class="top-bar-content">
|
|
<h1 class="app-title">NextSnap</h1>
|
|
<div class="top-bar-indicators">
|
|
<div class="connectivity-indicator online" title="Online"></div>
|
|
<span class="offline-label" id="offlineLabel" style="display:none">Offline Mode</span>
|
|
<div class="pending-count" id="pendingCount" style="display: none;">
|
|
<span id="pendingCountValue">0</span>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</header>
|
|
|
|
<!-- Main App Content -->
|
|
<main id="app">
|
|
{% block content %}{% endblock %}
|
|
</main>
|
|
|
|
<!-- Bottom Navigation (for authenticated pages) -->
|
|
{% if show_nav %}
|
|
<nav class="bottom-nav">
|
|
<a href="/capture" class="nav-item {% if request.path == '/capture' %}active{% endif %}">
|
|
<span class="nav-icon">📷</span>
|
|
<span class="nav-label">Capture</span>
|
|
</a>
|
|
<a href="/queue" class="nav-item {% if request.path == '/queue' %}active{% endif %}">
|
|
<span class="nav-icon">📤</span>
|
|
<span class="nav-label">Queue</span>
|
|
</a>
|
|
<a href="/browser" class="nav-item {% if request.path == '/browser' %}active{% endif %}" data-online-only>
|
|
<span class="nav-icon">📁</span>
|
|
<span class="nav-label">Files</span>
|
|
</a>
|
|
{% if is_admin %}
|
|
<a href="/admin" class="nav-item {% if request.path == '/admin' %}active{% endif %}" data-online-only>
|
|
<span class="nav-icon">⚙️</span>
|
|
<span class="nav-label">Admin</span>
|
|
</a>
|
|
{% endif %}
|
|
</nav>
|
|
{% endif %}
|
|
|
|
<!-- Service Worker Registration -->
|
|
<script>
|
|
if ('serviceWorker' in navigator) {
|
|
window.addEventListener('load', () => {
|
|
navigator.serviceWorker.register('/sw.js', { scope: '/' })
|
|
.then((registration) => {
|
|
console.log('Service Worker registered:', registration.scope);
|
|
|
|
// Check for updates periodically
|
|
setInterval(() => {
|
|
registration.update();
|
|
}, 60000); // Check every minute
|
|
|
|
// Handle updates
|
|
registration.addEventListener('updatefound', () => {
|
|
const newWorker = registration.installing;
|
|
newWorker.addEventListener('statechange', () => {
|
|
if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
|
|
// New service worker available
|
|
console.log('New service worker available');
|
|
// Could show update notification here
|
|
}
|
|
});
|
|
});
|
|
})
|
|
.catch((error) => {
|
|
console.error('Service Worker registration failed:', error);
|
|
});
|
|
|
|
// Pre-cache key pages for offline support once SW is active
|
|
navigator.serviceWorker.ready.then(() => {
|
|
['/capture', '/queue'].forEach(url => {
|
|
fetch(url).catch(() => {});
|
|
});
|
|
});
|
|
});
|
|
} else {
|
|
console.warn('Service Workers not supported in this browser');
|
|
}
|
|
</script>
|
|
|
|
<script src="{{ url_for('static', filename='js/app.js') }}"></script>
|
|
<script src="{{ url_for('static', filename='js/polish.js') }}"></script>
|
|
{% block extra_js %}{% endblock %}
|
|
</body>
|
|
</html>
|