From 87e07be40f31cc54a921f3449337e643a70b1b5a Mon Sep 17 00:00:00 2001 From: sebastjanartic <45803536-sebastjanartic@users.noreply.replit.com> Date: Sun, 31 Aug 2025 20:25:15 +0000 Subject: [PATCH] Add support for iOS app icons and PWA favicons Updates `client/index.html` and `client/public/manifest.json` to include proper iOS icon links and specifies PNG format for favicons. Enhances the `/api/favicon` endpoint to generate PNG favicons using `sharp` for various sizes and includes the "go4" text for larger icons. Also adds `@types/compression` to `package.json` and `package-lock.json`. Replit-Commit-Author: Agent Replit-Commit-Session-Id: ab9cd02a-d0b2-4288-9ceb-1964d0059648 Replit-Commit-Checkpoint-Type: full_checkpoint Replit-Commit-Screenshot-Url: https://storage.googleapis.com/screenshot-production-us-central1/8cc42625-c1f5-4e43-99bd-77f2c4dedee2/ab9cd02a-d0b2-4288-9ceb-1964d0059648/mbX83Mu --- client/index.html | 20 +++++------ client/public/manifest.json | 22 ++++++------ package-lock.json | 11 ++++++ package.json | 1 + server/routes.ts | 71 +++++++++++++++++++++++++++---------- 5 files changed, 85 insertions(+), 40 deletions(-) diff --git a/client/index.html b/client/index.html index c23688c..3fea956 100644 --- a/client/index.html +++ b/client/index.html @@ -37,19 +37,19 @@ - - - - - - - - - + + + + + + + + + - + diff --git a/client/public/manifest.json b/client/public/manifest.json index c7b172b..4f70c51 100644 --- a/client/public/manifest.json +++ b/client/public/manifest.json @@ -14,67 +14,67 @@ "prefer_related_applications": false, "icons": [ { - "src": "/api/favicon?size=57", + "src": "/api/favicon?size=57&format=png", "sizes": "57x57", "type": "image/png", "purpose": "any" }, { - "src": "/api/favicon?size=60", + "src": "/api/favicon?size=60&format=png", "sizes": "60x60", "type": "image/png", "purpose": "any" }, { - "src": "/api/favicon?size=72", + "src": "/api/favicon?size=72&format=png", "sizes": "72x72", "type": "image/png", "purpose": "any" }, { - "src": "/api/favicon?size=76", + "src": "/api/favicon?size=76&format=png", "sizes": "76x76", "type": "image/png", "purpose": "any" }, { - "src": "/api/favicon?size=114", + "src": "/api/favicon?size=114&format=png", "sizes": "114x114", "type": "image/png", "purpose": "any" }, { - "src": "/api/favicon?size=120", + "src": "/api/favicon?size=120&format=png", "sizes": "120x120", "type": "image/png", "purpose": "any" }, { - "src": "/api/favicon?size=144", + "src": "/api/favicon?size=144&format=png", "sizes": "144x144", "type": "image/png", "purpose": "any" }, { - "src": "/api/favicon?size=152", + "src": "/api/favicon?size=152&format=png", "sizes": "152x152", "type": "image/png", "purpose": "any" }, { - "src": "/api/favicon?size=180", + "src": "/api/favicon?size=180&format=png", "sizes": "180x180", "type": "image/png", "purpose": "any" }, { - "src": "/api/favicon?size=192", + "src": "/api/favicon?size=192&format=png", "sizes": "192x192", "type": "image/png", "purpose": "any maskable" }, { - "src": "/api/favicon?size=512", + "src": "/api/favicon?size=512&format=png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" diff --git a/package-lock.json b/package-lock.json index 90eaa6c..8ad22d5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,6 +43,7 @@ "@radix-ui/react-tooltip": "^1.2.0", "@tanstack/react-query": "^5.60.5", "@types/bcryptjs": "^2.4.6", + "@types/compression": "^1.8.1", "@types/memoizee": "^0.4.12", "@types/multer": "^2.0.0", "@types/node-fetch": "^2.6.13", @@ -4326,6 +4327,16 @@ "integrity": "sha512-hWtVTC2q7hc7xZ/RLbxapMvDMgUnDvKvMOpKal4DrMyfGBUfB1oKaZlIRr6mJL+If3bAP6sV/QneGzF6tJjZDg==", "license": "MIT" }, + "node_modules/@types/compression": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.8.1.tgz", + "integrity": "sha512-kCFuWS0ebDbmxs0AXYn6e2r2nrGAb5KwQhknjSPSPgJcGd8+HVSILlUyFhGqML2gk39HcG7D1ydW9/qpYkN00Q==", + "license": "MIT", + "dependencies": { + "@types/express": "*", + "@types/node": "*" + } + }, "node_modules/@types/connect": { "version": "3.4.38", "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz", diff --git a/package.json b/package.json index deecd02..b36a29d 100644 --- a/package.json +++ b/package.json @@ -45,6 +45,7 @@ "@radix-ui/react-tooltip": "^1.2.0", "@tanstack/react-query": "^5.60.5", "@types/bcryptjs": "^2.4.6", + "@types/compression": "^1.8.1", "@types/memoizee": "^0.4.12", "@types/multer": "^2.0.0", "@types/node-fetch": "^2.6.13", diff --git a/server/routes.ts b/server/routes.ts index 20baae1..603bb05 100644 --- a/server/routes.ts +++ b/server/routes.ts @@ -13,6 +13,7 @@ import multer from "multer"; import { randomUUID } from "crypto"; import path from "path"; import session from "express-session"; +import sharp from "sharp"; // Extend express session declare module "express-session" { @@ -690,32 +691,64 @@ export async function registerRoutes(app: Express): Promise { }); // Favicon generation endpoint - app.get('/api/favicon', (req, res) => { + app.get('/api/favicon', async (req, res) => { try { const size = req.query.size ? parseInt(req.query.size as string) : 32; + const format = req.query.format as string || 'svg'; const padding = Math.max(2, size * 0.1); const logoSize = size - (padding * 2); const cornerRadius = Math.max(2, size * 0.15); - // Generate SVG favicon with just the logo - const svg = ` - - - - - - - - - - - - - `; + if (format === 'png') { + // Ustvarimo PNG ikono za iOS PWA + // Ustvarimo SVG za pretvorbo v PNG + const svg = ` + + + + + + + + + + + + + + + ${size >= 120 ? `go4` : ''} + `; - res.setHeader('Content-Type', 'image/svg+xml'); - res.setHeader('Cache-Control', 'public, max-age=86400'); // Cache for 24 hours - res.send(svg); + // Pretvorimo SVG v PNG z Sharp + const pngBuffer = await sharp(Buffer.from(svg)) + .png({ quality: 100, compressionLevel: 0 }) + .toBuffer(); + + res.setHeader('Content-Type', 'image/png'); + res.setHeader('Cache-Control', 'public, max-age=86400'); // Cache for 24 hours + res.send(pngBuffer); + } else { + // Originalni SVG favicon + const svg = ` + + + + + + + + + + + + + `; + + res.setHeader('Content-Type', 'image/svg+xml'); + res.setHeader('Cache-Control', 'public, max-age=86400'); // Cache for 24 hours + res.send(svg); + } } catch (error) { console.error('Error generating favicon:', error); res.status(500).send('Error generating favicon');