diff --git a/index.html b/index.html new file mode 100644 index 0000000..a79f024 --- /dev/null +++ b/index.html @@ -0,0 +1,134 @@ + + + + + + + + Stacey Williams - Digital Business Card + + + + + + + +
+
+
+ +
+
+

Stacey Williams

+

Certified Service Technician

+

Mercedes Benz Of Collierville

+ +
+ + +
+
+ + + +
+ +1 (234) 567-8890 +
+ +
+
+ + + + +
+ Collierville, TN +
+
+ +
+

Scan to Save Contact

+
+ + + + + + + + + + + + + + + + + + + + +
+
+ + +
+
+
+ + + + diff --git a/manifest.json b/manifest.json index fa4791b..dad45d8 100644 --- a/manifest.json +++ b/manifest.json @@ -2,7 +2,7 @@ "name": "Stacey Williams - Digital Business Card", "short_name": "Stacey Card", "description": "Professional business card for Stacey Williams, Certified Service Technician at Mercedes Benz Of Collierville", - "start_url": "/rag7/", + "start_url": "/", "display": "standalone", "background_color": "#1a1a1a", "theme_color": "#C0C0C0", diff --git a/style.css b/style.css index 181b0e8..90441ce 100644 --- a/style.css +++ b/style.css @@ -28,6 +28,8 @@ body { 0 0 0 1px rgba(192, 192, 192, 0.1); overflow: hidden; transition: transform 0.3s ease, box-shadow 0.3s ease; + will-change: transform; /* Optimize hover animation */ + contain: layout style paint; /* Optimize rendering performance */ } .business-card:hover { @@ -47,6 +49,7 @@ body { .logo svg { filter: drop-shadow(0 4px 8px rgba(192, 192, 192, 0.3)); animation: pulse 2s ease-in-out infinite; + will-change: opacity; /* Optimize animation performance */ } @keyframes pulse { @@ -151,6 +154,7 @@ body { cursor: pointer; transition: all 0.3s ease; box-shadow: 0 4px 15px rgba(192, 192, 192, 0.3); + will-change: transform; /* Optimize hover animation */ } .install-btn:hover { diff --git a/sw.js b/sw.js index 31aa6d7..ddc8986 100644 --- a/sw.js +++ b/sw.js @@ -1,21 +1,87 @@ const CACHE_NAME = 'stacey-card-v1'; +const FETCH_TIMEOUT = 5000; // 5 seconds timeout for network requests const urlsToCache = [ - '/rag7/', - '/rag7/index.html', - '/rag7/style.css', - '/rag7/manifest.json' + '/', + '/index.html', + '/style.css', + '/manifest.json' ]; +// Helper function to validate response for caching +function isValidResponse(response) { + return response && + response.status === 200 && + (response.type === 'basic' || response.type === 'cors'); +} + +// Install event - cache resources and activate immediately self.addEventListener('install', event => { event.waitUntil( caches.open(CACHE_NAME) .then(cache => cache.addAll(urlsToCache)) + .then(() => self.skipWaiting()) // Activate immediately + .catch(error => console.error('Cache installation failed:', error)) + ); +}); + +// Activate event - clean up old caches +self.addEventListener('activate', event => { + event.waitUntil( + caches.keys() + .then(cacheNames => { + return Promise.all( + cacheNames + .filter(cacheName => cacheName !== CACHE_NAME) + .map(cacheName => caches.delete(cacheName)) + ); + }) + .then(() => self.clients.claim()) // Take control immediately + .catch(error => console.error('Cache cleanup failed:', error)) ); }); +// Fetch event - cache-first with network fallback and timeout self.addEventListener('fetch', event => { event.respondWith( caches.match(event.request) - .then(response => response || fetch(event.request)) + .then(response => { + if (response) { + return response; + } + + // Clone the request for fetch + const fetchRequest = event.request.clone(); + + // Create AbortController for timeout cleanup + const controller = new AbortController(); + const timeoutId = setTimeout(() => controller.abort(), FETCH_TIMEOUT); + + return fetch(fetchRequest, { signal: controller.signal }) + .then(response => { + clearTimeout(timeoutId); // Clean up timeout + + // Check if valid response (allow both basic and cors types) + // Return invalid responses without caching to preserve server behavior + if (!isValidResponse(response)) { + return response; + } + + // Clone response for cache and update cache asynchronously + const responseToCache = response.clone(); + event.waitUntil( + caches.open(CACHE_NAME) + .then(cache => cache.put(event.request, responseToCache)) + .catch(error => console.error('Failed to update cache:', error)) + ); + + return response; + }) + .catch(error => { + clearTimeout(timeoutId); // Clean up timeout on error + console.error('Fetch failed:', error); + // Could return a custom offline page here + throw error; + }); + }) ); }); \ No newline at end of file