diff --git a/client/index.html b/client/index.html index 11223db..c23688c 100644 --- a/client/index.html +++ b/client/index.html @@ -2,7 +2,7 @@ - + go4.video – Top-Inhalte von Folx TV @@ -29,7 +29,23 @@ - + + + + + + + + + + + + + + + + + diff --git a/client/public/manifest.json b/client/public/manifest.json index b44927b..c7b172b 100644 --- a/client/public/manifest.json +++ b/client/public/manifest.json @@ -5,18 +5,78 @@ "theme_color": "#6366f1", "background_color": "#2D1B69", "display": "standalone", + "orientation": "portrait-primary", "start_url": "/", + "scope": "/", + "lang": "en", + "dir": "ltr", + "categories": ["entertainment", "multimedia"], + "prefer_related_applications": false, "icons": [ + { + "src": "/api/favicon?size=57", + "sizes": "57x57", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/api/favicon?size=60", + "sizes": "60x60", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/api/favicon?size=72", + "sizes": "72x72", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/api/favicon?size=76", + "sizes": "76x76", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/api/favicon?size=114", + "sizes": "114x114", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/api/favicon?size=120", + "sizes": "120x120", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/api/favicon?size=144", + "sizes": "144x144", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/api/favicon?size=152", + "sizes": "152x152", + "type": "image/png", + "purpose": "any" + }, + { + "src": "/api/favicon?size=180", + "sizes": "180x180", + "type": "image/png", + "purpose": "any" + }, { "src": "/api/favicon?size=192", "sizes": "192x192", - "type": "image/svg+xml", + "type": "image/png", "purpose": "any maskable" }, { "src": "/api/favicon?size=512", "sizes": "512x512", - "type": "image/svg+xml", + "type": "image/png", "purpose": "any maskable" } ] diff --git a/client/public/sw.js b/client/public/sw.js new file mode 100644 index 0000000..31b8148 --- /dev/null +++ b/client/public/sw.js @@ -0,0 +1,67 @@ +// Service Worker za go4.video PWA +const CACHE_NAME = 'go4-video-v1'; +const urlsToCache = [ + '/', + '/manifest.json', + '/api/favicon', + '/api/favicon?size=192', + '/api/favicon?size=512' +]; + +// Instalacija service worker-ja +self.addEventListener('install', (event) => { + event.waitUntil( + caches.open(CACHE_NAME) + .then((cache) => { + console.log('PWA cache opened'); + return cache.addAll(urlsToCache); + }) + ); +}); + +// Aktivacija service worker-ja +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); + } + }) + ); + }) + ); +}); + +// Prestrezanje omrežnih zahtev +self.addEventListener('fetch', (event) => { + event.respondWith( + caches.match(event.request) + .then((response) => { + // Vrni iz cache-a, če obstaja + if (response) { + return response; + } + + // Sicer povleči iz omrežja + return fetch(event.request).then((response) => { + // Preveri ali je veljaven odgovor + if (!response || response.status !== 200 || response.type !== 'basic') { + return response; + } + + // Kloniraj odgovor + const responseToCache = response.clone(); + + caches.open(CACHE_NAME) + .then((cache) => { + cache.put(event.request, responseToCache); + }); + + return response; + }); + }) + ); +}); \ No newline at end of file diff --git a/client/src/index.css b/client/src/index.css index f0c386a..d5fed7f 100644 --- a/client/src/index.css +++ b/client/src/index.css @@ -65,6 +65,11 @@ background: linear-gradient(135deg, hsl(250, 50%, 15%) 0%, hsl(240, 30%, 25%) 50%, hsl(260, 40%, 20%) 100%); color: hsl(210, 40%, 98%); min-height: 100vh; + /* iOS PWA optimizacije */ + -webkit-touch-callout: none; + -webkit-user-select: none; + -webkit-tap-highlight-color: transparent; + overscroll-behavior: none; } } @@ -365,6 +370,44 @@ input[data-testid*="search"]::placeholder { } } +/* iOS PWA safe area optimizacije */ +@supports (padding: max(0px)) { + .has-fixed-header { + padding-top: max(80px, env(safe-area-inset-top)); + } +} + +/* PWA full screen optimizacije za iOS */ +@media (display-mode: standalone) { + body { + /* Prepreči povlečenje za osvežitev na iOS */ + overscroll-behavior-y: none; + /* Prilagodi safe area */ + padding-top: env(safe-area-inset-top); + padding-bottom: env(safe-area-inset-bottom); + padding-left: env(safe-area-inset-left); + padding-right: env(safe-area-inset-right); + } + + .header-sticky { + top: env(safe-area-inset-top) !important; + } +} + +/* Dodatne mobile optimizacije */ +@media (max-width: 768px) { + /* Prepreči zoom pri fokusiranju input polj */ + input, select, textarea { + font-size: 16px !important; + } + + /* Optimiziraj touch targets za iOS */ + button, a, [role="button"] { + min-height: 44px; + min-width: 44px; + } +} + /* Test grid overlay */ body.show-grid::after { content: ''; diff --git a/client/src/main.tsx b/client/src/main.tsx index 696e0d2..0945fc0 100644 --- a/client/src/main.tsx +++ b/client/src/main.tsx @@ -2,4 +2,17 @@ import { createRoot } from "react-dom/client"; import App from "./App"; import "./index.css"; +// Registracija Service Worker-ja za PWA funkcionalnost +if ('serviceWorker' in navigator) { + window.addEventListener('load', () => { + navigator.serviceWorker.register('/sw.js') + .then((registration) => { + console.log('SW registered: ', registration); + }) + .catch((registrationError) => { + console.log('SW registration failed: ', registrationError); + }); + }); +} + createRoot(document.getElementById("root")!).render();