updated icons and pwa install
This commit is contained in:
parent
2ecf1fc49f
commit
214d94e819
BIN
images/apple-touch-icon.png
Normal file
BIN
images/apple-touch-icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 32 KiB |
BIN
images/favicon-16x16.png
Normal file
BIN
images/favicon-16x16.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 754 B |
BIN
images/favicon-32x32.png
Normal file
BIN
images/favicon-32x32.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.1 KiB |
BIN
images/favicon.ico
Normal file
BIN
images/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
@ -1,16 +1,30 @@
|
|||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
|
|
||||||
<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">
|
||||||
<link rel="manifest" href="/manifest.json">
|
|
||||||
<title>TimeTracker</title>
|
<title>Time Pulse</title>
|
||||||
|
|
||||||
|
<!-- PWA Manifest -->
|
||||||
|
<link rel="manifest" href="manifest.json">
|
||||||
|
|
||||||
|
<!-- Favicons -->
|
||||||
|
<link rel="apple-touch-icon" sizes="180x180" href="../images/apple-touch-icon.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="32x32" href="../images/favicon-32x32.png">
|
||||||
|
<link rel="icon" type="image/png" sizes="16x16" href="../icons/favicon-16x16.png">
|
||||||
|
<link rel="icon" href="../images/favicon.ico" type="image/x-icon">
|
||||||
|
|
||||||
|
<!-- Tailwind CSS -->
|
||||||
<script src="https://cdn.tailwindcss.com"></script>
|
<script src="https://cdn.tailwindcss.com"></script>
|
||||||
|
|
||||||
|
<!-- Fonts -->
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com">
|
<link rel="preconnect" href="https://fonts.googleapis.com">
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
||||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700&display=swap" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="style/style.css">
|
|
||||||
|
<!-- Custom Styles -->
|
||||||
|
<link rel="stylesheet" href="/style/style.css">
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="bg-gray-100">
|
<body class="bg-gray-100">
|
||||||
@ -19,8 +33,8 @@
|
|||||||
<header class="bg-white shadow-md">
|
<header class="bg-white shadow-md">
|
||||||
<nav class="container mx-auto px-6 py-3 flex justify-between items-center">
|
<nav class="container mx-auto px-6 py-3 flex justify-between items-center">
|
||||||
<div class="flex items-center">
|
<div class="flex items-center">
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" width="28" height="28" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="text-blue-600"><path d="M12 22c5.523 0 10-4.477 10-10S17.523 2 12 2 2 6.477 2 12s4.477 10 10 10z"></path><path d="M12 6v6l4 2"></path></svg>
|
<img src="../images/icon-48x48.webp" alt="Time Pulse Logo" width="48" height="48">
|
||||||
<h1 class="text-xl font-bold text-gray-800 ml-2">TimeTracker</h1>
|
<h1 class="text-xl font-bold text-gray-800 ml-2">Time Pulse</h1>
|
||||||
</div>
|
</div>
|
||||||
<div id="nav-user-controls" class="hidden flex items-center">
|
<div id="nav-user-controls" class="hidden flex items-center">
|
||||||
<span id="welcome-message" class="text-gray-600 mr-3 text-sm sm:text-base truncate"></span>
|
<span id="welcome-message" class="text-gray-600 mr-3 text-sm sm:text-base truncate"></span>
|
||||||
@ -42,5 +56,41 @@
|
|||||||
<div id="modal-container"></div>
|
<div id="modal-container"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<script type="module" src="js/main.js"></script></body>
|
<script type="module" src="/public/js/main.js"></script>
|
||||||
</html>
|
<script>
|
||||||
|
let deferredPrompt;
|
||||||
|
|
||||||
|
window.addEventListener('beforeinstallprompt', (e) => {
|
||||||
|
e.preventDefault();
|
||||||
|
deferredPrompt = e;
|
||||||
|
console.log('[PWA] beforeinstallprompt fired');
|
||||||
|
|
||||||
|
// Create the install button
|
||||||
|
const installBtn = document.createElement('button');
|
||||||
|
installBtn.textContent = 'Install Time Pulse';
|
||||||
|
installBtn.className = 'fixed bottom-6 right-6 bg-blue-600 text-white px-4 py-2 rounded-lg shadow-lg hover:bg-blue-700 transition';
|
||||||
|
document.body.appendChild(installBtn);
|
||||||
|
|
||||||
|
// When clicked, trigger the prompt
|
||||||
|
installBtn.addEventListener('click', () => {
|
||||||
|
installBtn.style.display = 'none'; // hide button
|
||||||
|
deferredPrompt.prompt();
|
||||||
|
deferredPrompt.userChoice.then((choiceResult) => {
|
||||||
|
if (choiceResult.outcome === 'accepted') {
|
||||||
|
console.log('[PWA] User accepted install');
|
||||||
|
} else {
|
||||||
|
console.log('[PWA] User dismissed install');
|
||||||
|
}
|
||||||
|
deferredPrompt = null;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
// Optional: show a console message when app is installed
|
||||||
|
window.addEventListener('appinstalled', () => {
|
||||||
|
console.log('[PWA] Installed');
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
|||||||
59
public/sw.js
59
public/sw.js
@ -1,5 +1,8 @@
|
|||||||
const CACHE_NAME = 'timetracker-v1';
|
// --- Time Pulse Service Worker ---
|
||||||
// This list should include all the essential files for your app's shell.
|
|
||||||
|
const CACHE_NAME = 'timepulse-v1';
|
||||||
|
|
||||||
|
// Files to cache (App Shell)
|
||||||
const filesToCache = [
|
const filesToCache = [
|
||||||
'/',
|
'/',
|
||||||
'/index.html',
|
'/index.html',
|
||||||
@ -8,35 +11,63 @@ const filesToCache = [
|
|||||||
'/js/ui.js',
|
'/js/ui.js',
|
||||||
'/js/api.js',
|
'/js/api.js',
|
||||||
'/js/utils.js',
|
'/js/utils.js',
|
||||||
'/images/icon-192x192.png',
|
'/manifest.json',
|
||||||
'/images/icon-512x512.png'
|
'/icons/icon-192x192.webp',
|
||||||
|
'/icons/icon-512x512.webp'
|
||||||
];
|
];
|
||||||
|
|
||||||
// The install event runs when the service worker is first installed.
|
// --- Install Event ---
|
||||||
self.addEventListener('install', event => {
|
self.addEventListener('install', event => {
|
||||||
console.log('Service worker install event!');
|
console.log('[SW] Install event');
|
||||||
event.waitUntil(
|
event.waitUntil(
|
||||||
caches.open(CACHE_NAME)
|
caches.open(CACHE_NAME)
|
||||||
.then(cache => {
|
.then(cache => {
|
||||||
console.log('Caching app shell');
|
console.log('[SW] Caching app shell');
|
||||||
return cache.addAll(filesToCache);
|
return cache.addAll(filesToCache);
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
self.skipWaiting(); // Activate worker immediately
|
||||||
});
|
});
|
||||||
|
|
||||||
// The fetch event runs for every network request the page makes.
|
// --- Activate Event ---
|
||||||
|
self.addEventListener('activate', event => {
|
||||||
|
console.log('[SW] Activate event');
|
||||||
|
event.waitUntil(
|
||||||
|
caches.keys().then(keys =>
|
||||||
|
Promise.all(
|
||||||
|
keys.map(key => {
|
||||||
|
if (key !== CACHE_NAME) {
|
||||||
|
console.log('[SW] Removing old cache:', key);
|
||||||
|
return caches.delete(key);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
)
|
||||||
|
)
|
||||||
|
);
|
||||||
|
self.clients.claim(); // Become available to all pages
|
||||||
|
});
|
||||||
|
|
||||||
|
// --- Fetch Event ---
|
||||||
self.addEventListener('fetch', event => {
|
self.addEventListener('fetch', event => {
|
||||||
// We only want to handle GET requests.
|
// Ignore non-GET requests and API calls
|
||||||
if (event.request.method !== 'GET' || event.request.url.includes('/api/')) {
|
if (event.request.method !== 'GET' || event.request.url.includes('/api/')) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
event.respondWith(
|
event.respondWith(
|
||||||
caches.match(event.request)
|
caches.match(event.request)
|
||||||
.then(response => {
|
.then(response => {
|
||||||
// If we have a cached version, return it.
|
// Return cached file OR fetch from network
|
||||||
// Otherwise, fetch it from the network.
|
return response || fetch(event.request).then(fetchResponse => {
|
||||||
return response || fetch(event.request);
|
// Optionally cache new files on the fly
|
||||||
|
return caches.open(CACHE_NAME).then(cache => {
|
||||||
|
cache.put(event.request, fetchResponse.clone());
|
||||||
|
return fetchResponse;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})
|
||||||
|
.catch(() => {
|
||||||
|
// Optional: return a fallback page or image here
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user