Compare commits
8 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| a4202b3aeb | |||
| 7f2448f04a | |||
| 4bf71add87 | |||
| 464d5a532b | |||
| 81460f0cb7 | |||
| cab98834de | |||
| 5746922358 | |||
| fe6dd44a62 |
10
public/manifest.json
Normal file
10
public/manifest.json
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "Rosslyn Inn & Suites", "short_name": "Rosslyn Inn", "description": "Experience timeless comfort and hospitality at Rosslyn Inn and Suites", "start_url": "/", "display": "standalone", "background_color": "#ffffff", "theme_color": "#000000", "orientation": "portrait-primary", "icons": [
|
||||
{
|
||||
"src": "/icon-192.png", "sizes": "192x192", "type": "image/png", "purpose": "any"
|
||||
},
|
||||
{
|
||||
"src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any"
|
||||
}
|
||||
]
|
||||
}
|
||||
96
public/sw.js
Normal file
96
public/sw.js
Normal file
@@ -0,0 +1,96 @@
|
||||
const CACHE_NAME = 'rosslyn-inn-v1';
|
||||
const urlsToCache = [
|
||||
'/',
|
||||
'/index.html',
|
||||
'/manifest.json'
|
||||
];
|
||||
|
||||
self.addEventListener('install', (event) => {
|
||||
event.waitUntil(
|
||||
caches.open(CACHE_NAME)
|
||||
.then((cache) => {
|
||||
console.log('Opened cache');
|
||||
return cache.addAll(urlsToCache);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Cache opening failed:', error);
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('fetch', (event) => {
|
||||
const { request } = event;
|
||||
const url = new URL(request.url);
|
||||
|
||||
if (url.protocol !== 'http:' && url.protocol !== 'https:') {
|
||||
return;
|
||||
}
|
||||
|
||||
if (request.method !== 'GET') {
|
||||
return;
|
||||
}
|
||||
|
||||
event.respondWith(
|
||||
caches.match(request)
|
||||
.then((response) => {
|
||||
if (response) {
|
||||
return response;
|
||||
}
|
||||
|
||||
return fetch(request)
|
||||
.then((response) => {
|
||||
if (!response || response.status !== 200 || response.type === 'error') {
|
||||
return response;
|
||||
}
|
||||
|
||||
const responseToCache = response.clone();
|
||||
const isImage = request.headers.get('accept')?.includes('image');
|
||||
const isFont = request.headers.get('accept')?.includes('font') || request.url.includes('.woff') || request.url.includes('.woff2');
|
||||
const isScript = request.headers.get('accept')?.includes('javascript');
|
||||
const isStylesheet = request.headers.get('accept')?.includes('text/css');
|
||||
|
||||
if (isImage || isFont || isScript || isStylesheet) {
|
||||
caches.open(CACHE_NAME)
|
||||
.then((cache) => {
|
||||
cache.put(request, responseToCache);
|
||||
})
|
||||
.catch((error) => {
|
||||
console.error('Cache update failed:', error);
|
||||
});
|
||||
}
|
||||
|
||||
return response;
|
||||
})
|
||||
.catch(() => {
|
||||
if (request.destination === 'image') {
|
||||
return new Response(
|
||||
'<svg role="img" aria-label="Placeholder" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 100 100"><rect fill="#ddd" width="100" height="100"/></svg>',
|
||||
{ headers: { 'Content-Type': 'image/svg+xml', 'Cache-Control': 'no-store' } }
|
||||
);
|
||||
}
|
||||
return new Response('Network request failed and no cache available', {
|
||||
status: 503,
|
||||
statusText: 'Service Unavailable',
|
||||
headers: new Headers({
|
||||
'Content-Type': 'text/plain'
|
||||
})
|
||||
});
|
||||
});
|
||||
})
|
||||
);
|
||||
});
|
||||
|
||||
self.addEventListener('activate', (event) => {
|
||||
event.waitUntil(
|
||||
caches.keys().then((cacheNames) => {
|
||||
return Promise.all(
|
||||
cacheNames.map((cacheName) => {
|
||||
if (cacheName !== CACHE_NAME) {
|
||||
console.log('Deleting old cache:', cacheName);
|
||||
return caches.delete(cacheName);
|
||||
}
|
||||
})
|
||||
);
|
||||
})
|
||||
);
|
||||
});
|
||||
@@ -16,28 +16,27 @@ const inter = Inter({
|
||||
});
|
||||
|
||||
const sourceSans3 = Source_Sans_3({
|
||||
variable: "--font-source-sans-3", subsets: ["latin"]
|
||||
variable: "--font-source-sans-3", subsets: ["latin"],
|
||||
});
|
||||
|
||||
export const metadata: Metadata = {
|
||||
title: "Rosslyn Inn & Suites | Luxury Hotel Accommodations", description: "Experience timeless comfort at Rosslyn Inn and Suites. Luxury rooms, world-class amenities, and personalized hospitality. Book your perfect stay today.", keywords: "hotel, accommodation, luxury rooms, hospitality, booking, suites", metadataBase: new URL("https://www.rosslyninn.com"),
|
||||
alternates: {
|
||||
canonical: "https://www.rosslyninn.com"
|
||||
},
|
||||
canonical: "https://www.rosslyninn.com"},
|
||||
openGraph: {
|
||||
title: "Rosslyn Inn & Suites | Premium Hotel Experience", description: "Discover luxury accommodations, fine dining, spa services, and exceptional hospitality.", url: "https://www.rosslyninn.com", siteName: "Rosslyn Inn & Suites", type: "website", images: [
|
||||
{
|
||||
url: "http://img.b2bpic.net/free-photo/business-professional-finding-new-ideas-forge-international-partnership-before-attending-conference-hotel-lounge-area-ceo-taking-notes-preparing-important-speech_482257-68049.jpg", alt: "Elegant hotel lobby at Rosslyn Inn and Suites"
|
||||
}
|
||||
]
|
||||
url: "http://img.b2bpic.net/free-photo/business-professional-finding-new-ideas-forge-international-partnership-before-attending-conference-hotel-lounge-area-ceo-taking-notes-preparing-important-speech_482257-68049.jpg", alt: "Elegant hotel lobby at Rosslyn Inn and Suites"},
|
||||
],
|
||||
},
|
||||
twitter: {
|
||||
card: "summary_large_image", title: "Rosslyn Inn & Suites | Luxury Hotel", description: "Book your luxury stay with premium rooms, amenities, and hospitality.", images: ["http://img.b2bpic.net/free-photo/business-professional-finding-new-ideas-forge-international-partnership-before-attending-conference-hotel-lounge-area-ceo-taking-notes-preparing-important-speech_482257-68049.jpg"]
|
||||
card: "summary_large_image", title: "Rosslyn Inn & Suites | Luxury Hotel", description: "Book your luxury stay with premium rooms, amenities, and hospitality.", images: [
|
||||
"http://img.b2bpic.net/free-photo/business-professional-finding-new-ideas-forge-international-partnership-before-attending-conference-hotel-lounge-area-ceo-taking-notes-preparing-important-speech_482257-68049.jpg"],
|
||||
},
|
||||
robots: {
|
||||
index: true,
|
||||
follow: true
|
||||
}
|
||||
follow: true,
|
||||
},
|
||||
};
|
||||
|
||||
export default function RootLayout({
|
||||
@@ -47,6 +46,67 @@ export default function RootLayout({
|
||||
}>) {
|
||||
return (
|
||||
<html lang="en" suppressHydrationWarning>
|
||||
<head>
|
||||
<script
|
||||
async
|
||||
src="https://cdn.jsdelivr.net/npm/workbox-window@7/build/workbox-window.umd.js"
|
||||
></script>
|
||||
<script>
|
||||
{`
|
||||
if ('serviceWorker' in navigator) {
|
||||
window.addEventListener('load', async () => {
|
||||
try {
|
||||
const registration = await navigator.serviceWorker.register('/sw.js');
|
||||
console.log('Service Worker registered:', registration);
|
||||
} catch (error) {
|
||||
console.error('Service Worker registration failed:', error);
|
||||
}
|
||||
});
|
||||
}
|
||||
`}
|
||||
</script>
|
||||
<script>
|
||||
{`
|
||||
if (typeof window !== 'undefined' && 'performance' in window) {
|
||||
window.addEventListener('load', () => {
|
||||
const perfData = window.performance.timing;
|
||||
const pageLoadTime = perfData.loadEventEnd - perfData.navigationStart;
|
||||
const resourcesPerf = window.performance.getEntriesByType('resource');
|
||||
|
||||
const metrics = {
|
||||
pageLoadTime: pageLoadTime,
|
||||
domInteractive: perfData.domInteractive - perfData.navigationStart,
|
||||
domComplete: perfData.domComplete - perfData.navigationStart,
|
||||
resourceCount: resourcesPerf.length,
|
||||
timestamp: new Date().toISOString()
|
||||
};
|
||||
|
||||
if ('sendBeacon' in navigator) {
|
||||
navigator.sendBeacon('/api/metrics', JSON.stringify(metrics));
|
||||
}
|
||||
|
||||
console.log('Performance Metrics:', metrics);
|
||||
});
|
||||
|
||||
if ('PerformanceObserver' in window) {
|
||||
const observer = new PerformanceObserver((list) => {
|
||||
for (const entry of list.getEntries()) {
|
||||
console.log('Web Vital:', {
|
||||
name: entry.name,
|
||||
value: entry.value,
|
||||
rating: entry.rating
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
observer.observe({
|
||||
entryTypes: ['largest-contentful-paint', 'first-input', 'layout-shift']
|
||||
});
|
||||
}
|
||||
}
|
||||
`}
|
||||
</script>
|
||||
</head>
|
||||
<ServiceWrapper>
|
||||
<body
|
||||
className={`${halant.variable} ${inter.variable} ${sourceSans3.variable} antialiased`}
|
||||
|
||||
@@ -206,4 +206,4 @@ export default function LandingPage() {
|
||||
</div>
|
||||
</ThemeProvider>
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user