From de947f9d350fcecd77d0b9b41b621c3fb75031d1 Mon Sep 17 00:00:00 2001 From: AgendaPro Dev Date: Mon, 27 Jul 2026 16:20:36 -0600 Subject: [PATCH] feat: add AgendaMax PWA metadata and icons --- index.html | 7 ++++++- package.json | 4 +++- public/icon-192.png | Bin 0 -> 2932 bytes public/icon-512.png | Bin 0 -> 9282 bytes public/manifest.webmanifest | 15 +++++++++++++++ scripts/generate-pwa-icons.mjs | 20 ++++++++++++++++++++ 6 files changed, 44 insertions(+), 2 deletions(-) create mode 100644 public/icon-192.png create mode 100644 public/icon-512.png create mode 100644 public/manifest.webmanifest create mode 100644 scripts/generate-pwa-icons.mjs diff --git a/index.html b/index.html index 91d0f77..6f175ef 100644 --- a/index.html +++ b/index.html @@ -3,9 +3,14 @@ - + + + + + + diff --git a/package.json b/package.json index 839c03d..96b7cd0 100644 --- a/package.json +++ b/package.json @@ -22,7 +22,9 @@ "test:admin": "node admin-test.mjs", "test:unit": "node --import tsx --test server/lib/scheduling.test.ts server/lib/time.test.ts server/lib/metrics.test.ts", "test:booking": "node server/scripts/booking-e2e.mjs", - "audit:visual": "node visual-audit.mjs" + "audit:visual": "node visual-audit.mjs", + "generate:pwa-icons": "node scripts/generate-pwa-icons.mjs", + "test:pwa": "node pwa-e2e.mjs" }, "dependencies": { "@dnd-kit/core": "^6.1.0", diff --git a/public/icon-192.png b/public/icon-192.png new file mode 100644 index 0000000000000000000000000000000000000000..3a1d80f5ff48d874f1356150577cb0d08a5ec8ff GIT binary patch literal 2932 zcmZuzc{mhY7oQm#BTU1PJ(HnE)=<_MJ1P5%O4c;iETgf7F~}feCaGkJED^FiGPWdR z%bTqbCj0o1Ey>vPO})?i-}}e8_c`Zxf6smHIp>~plB_IDc#ex42LJ#(W~PQVtiAQO zKtQZ@qGjI-0N|1_Gt{#S%U+oX4;&f>a(oZKshwpH&cI&=9Z!fQAT&`65NQyBZ9I=Z zse?@>&Lgebs@xM*(N!B`m#pNT8H@v$Ao-K>GaNz1MFM(vfXCn{v*Tt6L5+*_?NM_4 zt+c5%`r)cMb3Zeup1krp{qP4fw0UZKObp6FD9;lTR4DklS3!T18$HCKc+t_iU2OyA)DKoIbWVbc`Y1*@8r&KnaG|EgwiI1h9SPl>$P^Z+T7n zKYV3~>jlY}!b{DRjpy!rc=p|Bb&*r8Q!S~PgD84w=EL+EO2;NuRCHs%;)%ea!0%FgzlqEfdl@*{^+wrvsAGzrCY_UQCsDWrCkQ%RYN0DFFY;IIN)F(D<0X@B`*JxTFS5*8y8c(zhF* z%8y<|-_SJ{u)Ir=4GtWmGZh2428MmbqPx?XaRdIq@od^mqPDj#$&?#S z><+29Ztaiea!q)tfjli*U#!QD6KiMY&kioO?mtJ%M)(^}Q3%J<;=W$ni9ZnVHmU^l z_MtEFTLT7Duyw}HY)Q4-hyh~sM`rWw9K9PgCzqm)+ORPak{?* z7=7b8>iJ`k!U@V^s>Fx>ohQok7Qz?GN;+SyYAO&5<{FevpFVZX_WQJJ;g;c3S=2)= zYhsMUyubjt80a&CqOmFVEN5SX$mW?Yp+ldr=Hwd0^) zM*G~@=^EN@f57kYt75q#!)+$^WS%DgOq$F@P;0 zqe%{9GX6_PF4*N^k-E+cxl{AAin3&@8B;m`E0=6^f4R~MQ&JD};S<|!ZS9Pb)Xc%M zh-+^xBU}6|r=0g~EGC>5V}Zx3-RhbXs#Df$_Hg)yfyn^>-edzFILwFJs(aLmieL_x z4vNlHu8fxtUkJD;`RIv6AW~Cx7I}GUMblRL5+Q6SS-~>-rT(H4`ZVI=V~0)*cTE)7 zlZM<*dC6xaL@<*MGnnz;2gomPUMl2*llu2lve`V6M(vM~EqiRGmr ziUec0KR#)+k5|cAOSRZI08Q>CI{OCWLk=L3K797?K5aDKy#F=sf^PaeOhMY1|3p9ciMcB6f0s&b;)y05o7M+vqTTfZ`(On6JhD_bPY&+|rO|xK z&HXD?Y_$bAosS)VM||{%jr!{#UT5Spgv7;+<&tH-cgm)C1hQD6<92!Noo^f)n z*}m!g#_Ug!kH;>P9zC~T({a*0+0#-Yv6t0BpIIF;S21%YP*$_(&ALPd-SR0DxEt1sw6Mh+bEBUK!Gw7Qkq(c8e2!Zc z@~CvibrUn^SncNeZK=MTHa%i9oMt)l=&^1cdx@`HZZ1f&pMn1Db8^`q`vP;7ec=g( zgLA`QP_j`TJxB?|i4ebrM@P`N>c^ck&PSD}bbKPl=YCK=xDnuFX%i2p&!>7Dlld4Xq`C5GJE-)&wity^oi!?$KGH*aCjM(zqL z0&5%@kWQX&N>Y;{8zYhPZzqkik&){Q^)U$4JtFl+^U_ToRjQ%-gNg!7K>N7(Xbs2E zQj{*6Vx#8m#fO6cjl86*SJSD*c^ElIO(8!7xa`6a`7OXEsH;a^{u_NWjQjM5XUSci zwI6M^lAZ&DUscdJ_8I5C%xC05Uq(7;UlLABGYR28DCS4J{C537S}BDpyrorCxU}j`t_*&nU@PF}{V}Sqw literal 0 HcmV?d00001 diff --git a/public/icon-512.png b/public/icon-512.png new file mode 100644 index 0000000000000000000000000000000000000000..a19de4d3bcd04c4a50f8d8e4ce037a0e7df60d1a GIT binary patch literal 9282 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 PXaw9*(YjTtWEJvX&`C}i literal 0 HcmV?d00001 diff --git a/public/manifest.webmanifest b/public/manifest.webmanifest new file mode 100644 index 0000000..20e148b --- /dev/null +++ b/public/manifest.webmanifest @@ -0,0 +1,15 @@ +{ + "name": "AgendaMax", + "short_name": "AgendaMax", + "description": "Gestión visual de citas, empleados e ingresos para tu negocio.", + "start_url": "/", + "scope": "/", + "display": "standalone", + "orientation": "portrait-primary", + "background_color": "#f6f7fb", + "theme_color": "#3b66ff", + "icons": [ + { "src": "/icon-192.png", "sizes": "192x192", "type": "image/png" }, + { "src": "/icon-512.png", "sizes": "512x512", "type": "image/png", "purpose": "any maskable" } + ] +} diff --git a/scripts/generate-pwa-icons.mjs b/scripts/generate-pwa-icons.mjs new file mode 100644 index 0000000..165248b --- /dev/null +++ b/scripts/generate-pwa-icons.mjs @@ -0,0 +1,20 @@ +import { chromium } from "playwright"; +import fs from "node:fs/promises"; +import path from "node:path"; +import { fileURLToPath } from "node:url"; + +const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); +const svg = await fs.readFile(path.join(root, "public", "favicon.svg"), "utf8"); +const svgDataUrl = `data:image/svg+xml;base64,${Buffer.from(svg).toString("base64")}`; +const browser = await chromium.launch({ headless: true }); + +try { + for (const size of [192, 512]) { + const page = await browser.newPage({ viewport: { width: size, height: size }, deviceScaleFactor: 1 }); + await page.setContent(``); + await page.screenshot({ path: path.join(root, "public", `icon-${size}.png`), type: "png" }); + await page.close(); + } +} finally { + await browser.close(); +}