mirror of
https://github.com/MarekWo/mc-webui.git
synced 2026-08-09 10:12:54 +02:00
feat: Add full offline support with local Bootstrap libraries
Implement complete offline functionality by hosting Bootstrap CSS/JS and icons locally, eliminating dependency on external CDNs. This ensures the application works reliably in internet-free environments, perfect for mesh networks in remote or emergency scenarios. Changes: - Download and host Bootstrap 5.3.2 CSS/JS locally (~307 KB total) - Download and host Bootstrap Icons 1.11.2 CSS and fonts (~300 KB) - Update base.html to use local library paths instead of CDN URLs - Enhance Service Worker with hybrid caching strategy: - Cache-first for vendor libraries (static, unchanging) - Network-first for app code (dynamic, needs updates) - Bump Service Worker cache version to v2 - Add vendor libraries to pre-cache list for instant offline availability - Update README.md with offline support documentation - Update project structure documentation Benefits: - Works without internet connection (no CDN dependency) - Faster initial page load (no external requests) - Reliable operation during internet outages - Perfect for air-gapped and remote mesh network deployments File sizes: - Bootstrap CSS: ~227 KB - Bootstrap JS: ~80 KB - Bootstrap Icons CSS: ~98 KB - Bootstrap Icons Fonts: ~300 KB (woff2 + woff) 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -40,6 +40,11 @@ A lightweight web interface for meshcore-cli, providing browser-based access to
|
||||
- App badge counter on home screen icon (Android/Desktop)
|
||||
- Service Worker for PWA installability and offline support
|
||||
- Tested on Windows desktop (Firefox), requires further testing on Android mobile
|
||||
- 📴 **Full offline support** - Works without internet connection
|
||||
- Bootstrap CSS/JS and icons hosted locally (no CDN dependency)
|
||||
- Service Worker caches all UI assets automatically
|
||||
- Hybrid caching strategy: cache-first for libraries, network-first for app updates
|
||||
- Perfect for mesh networks operating in remote/emergency scenarios
|
||||
|
||||
## Tech Stack
|
||||
|
||||
@@ -236,6 +241,7 @@ mc-webui/
|
||||
- [x] Advanced Contact Management - Multi-page interface with sorting, filtering, and activity tracking
|
||||
- [x] Message Content Enhancements - Mention badges, clickable URLs, and image previews
|
||||
- [x] PWA Notifications (Experimental) - Browser notifications and app badge counters (tested on Windows/Firefox, requires testing on Android)
|
||||
- [x] Full Offline Support - Local Bootstrap libraries and Service Worker caching for internet-free operation
|
||||
|
||||
### Next Steps
|
||||
|
||||
|
||||
+36
-7
@@ -1,4 +1,4 @@
|
||||
const CACHE_NAME = 'mc-webui-v1';
|
||||
const CACHE_NAME = 'mc-webui-v2';
|
||||
const ASSETS_TO_CACHE = [
|
||||
'/',
|
||||
'/static/css/style.css',
|
||||
@@ -7,7 +7,14 @@ const ASSETS_TO_CACHE = [
|
||||
'/static/js/contacts.js',
|
||||
'/static/js/message-utils.js',
|
||||
'/static/images/android-chrome-192x192.png',
|
||||
'/static/images/android-chrome-512x512.png'
|
||||
'/static/images/android-chrome-512x512.png',
|
||||
// Bootstrap 5.3.2 (local)
|
||||
'/static/vendor/bootstrap/css/bootstrap.min.css',
|
||||
'/static/vendor/bootstrap/js/bootstrap.bundle.min.js',
|
||||
// Bootstrap Icons 1.11.2 (local)
|
||||
'/static/vendor/bootstrap-icons/bootstrap-icons.css',
|
||||
'/static/vendor/bootstrap-icons/fonts/bootstrap-icons.woff2',
|
||||
'/static/vendor/bootstrap-icons/fonts/bootstrap-icons.woff'
|
||||
];
|
||||
|
||||
// Install event - cache core assets
|
||||
@@ -32,10 +39,32 @@ self.addEventListener('activate', (event) => {
|
||||
);
|
||||
});
|
||||
|
||||
// Fetch event - network first, fallback to cache (for dynamic content like messages)
|
||||
// Fetch event - hybrid strategy:
|
||||
// - Cache-first for vendor libraries (static, unchanging)
|
||||
// - Network-first for app content (dynamic, needs updates)
|
||||
self.addEventListener('fetch', (event) => {
|
||||
event.respondWith(
|
||||
fetch(event.request)
|
||||
.catch(() => caches.match(event.request))
|
||||
);
|
||||
const url = new URL(event.request.url);
|
||||
|
||||
// Cache-first for vendor libraries (Bootstrap, Icons)
|
||||
if (url.pathname.includes('/static/vendor/')) {
|
||||
event.respondWith(
|
||||
caches.match(event.request)
|
||||
.then((cachedResponse) => {
|
||||
return cachedResponse || fetch(event.request)
|
||||
.then((response) => {
|
||||
// Cache the fetched vendor file for future use
|
||||
return caches.open(CACHE_NAME).then((cache) => {
|
||||
cache.put(event.request, response.clone());
|
||||
return response;
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
} else {
|
||||
// Network-first for everything else (app code, API calls, dynamic content)
|
||||
event.respondWith(
|
||||
fetch(event.request)
|
||||
.catch(() => caches.match(event.request))
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
+2078
File diff suppressed because it is too large
Load Diff
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -12,10 +12,10 @@
|
||||
<link rel="manifest" href="{{ url_for('static', filename='manifest.json') }}">
|
||||
<link rel="shortcut icon" href="{{ url_for('static', filename='favicon.ico') }}">
|
||||
|
||||
<!-- Bootstrap 5 CSS -->
|
||||
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/css/bootstrap.min.css" rel="stylesheet">
|
||||
<!-- Bootstrap Icons -->
|
||||
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.11.2/font/bootstrap-icons.css">
|
||||
<!-- Bootstrap 5 CSS (local) -->
|
||||
<link href="{{ url_for('static', filename='vendor/bootstrap/css/bootstrap.min.css') }}" rel="stylesheet">
|
||||
<!-- Bootstrap Icons (local) -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='vendor/bootstrap-icons/bootstrap-icons.css') }}">
|
||||
|
||||
<!-- Custom CSS -->
|
||||
<link rel="stylesheet" href="{{ url_for('static', filename='css/style.css') }}">
|
||||
@@ -266,8 +266,8 @@
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Bootstrap 5 JS Bundle -->
|
||||
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.2/dist/js/bootstrap.bundle.min.js"></script>
|
||||
<!-- Bootstrap 5 JS Bundle (local) -->
|
||||
<script src="{{ url_for('static', filename='vendor/bootstrap/js/bootstrap.bundle.min.js') }}"></script>
|
||||
|
||||
<!-- Message Content Processing Utilities (must load before app.js and dm.js) -->
|
||||
<script src="{{ url_for('static', filename='js/message-utils.js') }}"></script>
|
||||
|
||||
Reference in New Issue
Block a user