diff --git a/app/Http/Controllers/PwaManifestController.php b/app/Http/Controllers/PwaManifestController.php index c2f1f72..40b9e30 100644 --- a/app/Http/Controllers/PwaManifestController.php +++ b/app/Http/Controllers/PwaManifestController.php @@ -11,16 +11,15 @@ public function show(SystemService $systemService): JsonResponse { $systemData = $systemService->systemData(); $appName = $systemData['app_name'] ?? config('app.name', 'DST Collection'); - $logoUrl = $systemData['logo_url'] ?? asset('assets/logo.png'); + $iconUrl = $systemData['favicon_url'] ?? $systemData['logo_url'] ?? asset('assets/logo.png'); - // Determine mime type from logoUrl extension $mimeType = 'image/png'; - $lowerLogoUrl = strtolower($logoUrl); - if (str_contains($lowerLogoUrl, '.svg')) { + $lowerIconUrl = strtolower($iconUrl); + if (str_contains($lowerIconUrl, '.svg')) { $mimeType = 'image/svg+xml'; - } elseif (str_contains($lowerLogoUrl, '.jpg') || str_contains($lowerLogoUrl, '.jpeg')) { + } elseif (str_contains($lowerIconUrl, '.jpg') || str_contains($lowerIconUrl, '.jpeg')) { $mimeType = 'image/jpeg'; - } elseif (str_contains($lowerLogoUrl, '.webp')) { + } elseif (str_contains($lowerIconUrl, '.webp')) { $mimeType = 'image/webp'; } @@ -37,23 +36,23 @@ public function show(SystemService $systemService): JsonResponse 'id' => '/', 'icons' => [ [ - 'src' => $logoUrl, + 'src' => $iconUrl, 'sizes' => '64x64', 'type' => $mimeType, ], [ - 'src' => $logoUrl, + 'src' => $iconUrl, 'sizes' => '192x192', 'type' => $mimeType, ], [ - 'src' => $logoUrl, + 'src' => $iconUrl, 'sizes' => '512x512', 'type' => $mimeType, 'purpose' => 'any', ], [ - 'src' => $logoUrl, + 'src' => $iconUrl, 'sizes' => '512x512', 'type' => $mimeType, 'purpose' => 'maskable', diff --git a/package.json b/package.json index 126bfb3..a466978 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,6 @@ "tw-animate-css": "^1.4.0", "typescript-eslint": "^8.23.0", "vite": "^7.3.6", - "vite-plugin-pwa": "^1.3.0", "vue-tsc": "^2.2.4" }, "dependencies": { diff --git a/public/manifest.webmanifest b/public/manifest.webmanifest deleted file mode 100644 index e29eabb..0000000 --- a/public/manifest.webmanifest +++ /dev/null @@ -1,36 +0,0 @@ -{ - "name": "DST Collection", - "short_name": "DST Collection", - "description": "DST Collection - Progressive Web App", - "theme_color": "#171717", - "background_color": "#ffffff", - "display": "standalone", - "orientation": "portrait", - "scope": "/", - "start_url": "/", - "id": "/", - "icons": [ - { - "src": "/assets/pwa-64x64.png", - "sizes": "64x64", - "type": "image/png" - }, - { - "src": "/assets/pwa-192x192.png", - "sizes": "192x192", - "type": "image/png" - }, - { - "src": "/assets/pwa-512x512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "any" - }, - { - "src": "/assets/maskable-icon-512x512.png", - "sizes": "512x512", - "type": "image/png", - "purpose": "maskable" - } - ] -} diff --git a/resources/js/app.ts b/resources/js/app.ts index ac7e8be..1a0bbfd 100644 --- a/resources/js/app.ts +++ b/resources/js/app.ts @@ -16,6 +16,11 @@ if ('serviceWorker' in navigator) { }); } +window.addEventListener('beforeinstallprompt', (e) => { + e.preventDefault(); + (window as any).deferredPwaPrompt = e; +}); + void restoreConnection(); const appName = import.meta.env.VITE_APP_NAME || 'Laravel'; diff --git a/resources/js/types/global.d.ts b/resources/js/types/global.d.ts index 9b78589..b64e663 100644 --- a/resources/js/types/global.d.ts +++ b/resources/js/types/global.d.ts @@ -1,5 +1,17 @@ import type { Auth } from '@/types/auth'; +interface BeforeInstallPromptEvent extends Event { + readonly platforms: string[]; + readonly userChoice: Promise<{ outcome: 'accepted' | 'dismissed'; platform: string }>; + prompt(): Promise; +} + +declare global { + interface Window { + deferredPwaPrompt?: BeforeInstallPromptEvent; + } +} + // Extend ImportMeta interface for Vite... declare module 'vite/client' { interface ImportMetaEnv { diff --git a/vite.config.ts b/vite.config.ts index 5194707..3068914 100644 --- a/vite.config.ts +++ b/vite.config.ts @@ -3,90 +3,26 @@ import { wayfinder } from '@laravel/vite-plugin-wayfinder'; import tailwindcss from '@tailwindcss/vite'; import vue from '@vitejs/plugin-vue'; import laravel from 'laravel-vite-plugin'; -import { defineConfig, loadEnv } from 'vite'; -import { VitePWA } from 'vite-plugin-pwa'; +import { defineConfig } from 'vite'; -const manifestIcons = [ - { - src: '/assets/pwa-64x64.png', - sizes: '64x64', - type: 'image/png', - }, - { - src: '/assets/pwa-192x192.png', - sizes: '192x192', - type: 'image/png', - }, - { - src: '/assets/pwa-512x512.png', - sizes: '512x512', - type: 'image/png', - purpose: 'any', - }, - { - src: '/assets/maskable-icon-512x512.png', - sizes: '512x512', - type: 'image/png', - purpose: 'maskable', - }, -] as const; - -export default defineConfig(({ mode }) => { - const env = loadEnv(mode, process.cwd(), ''); - const appName = env.VITE_APP_NAME || 'DST Collection'; - - return { - plugins: [ - laravel({ - input: ['resources/css/app.css', 'resources/js/app.ts'], - refresh: false, - }), - inertia(), - tailwindcss(), - vue({ - template: { - transformAssetUrls: { - base: null, - includeAbsolute: false, - }, +export default defineConfig({ + plugins: [ + laravel({ + input: ['resources/css/app.css', 'resources/js/app.ts'], + refresh: false, + }), + inertia(), + tailwindcss(), + vue({ + template: { + transformAssetUrls: { + base: null, + includeAbsolute: false, }, - }), - wayfinder({ - formVariants: true, - }), - VitePWA({ - buildBase: '/build/', - scope: '/', - base: '/', - registerType: 'autoUpdate', - // Kita daftarkan SW manual di app.ts (public/sw.js yang support push) - // VitePWA hanya generate manifest di sini - injectRegister: null, - devOptions: { - enabled: false, - }, - workbox: { - globPatterns: [ - '**/*.{js,css,html,ico,jpg,png,svg,woff,woff2,ttf,eot}', - ], - navigateFallback: '/', - navigateFallbackDenylist: [/^\/telescope/], - maximumFileSizeToCacheInBytes: 3_000_000, - }, - manifest: { - name: appName, - short_name: appName, - description: `${appName} - Progressive Web App`, - theme_color: '#171717', - background_color: '#ffffff', - display: 'standalone', - orientation: 'portrait', - scope: '/', - start_url: '/', - id: '/', - icons: [...manifestIcons], - }, - }), - ], - }; + }, + }), + wayfinder({ + formVariants: true, + }), + ], });