chore: add generate pwa icons script (#2130)
|
@ -6,6 +6,8 @@
|
|||
*.txt
|
||||
Dockerfile
|
||||
public/
|
||||
public-dev/
|
||||
public-staging/
|
||||
https-dev-config/localhost.crt
|
||||
https-dev-config/localhost.key
|
||||
Dockerfile
|
||||
|
|
|
@ -15,6 +15,16 @@ export const pwa: VitePWANuxtOptions = {
|
|||
injectManifest: {
|
||||
globPatterns: ['**/*.{js,json,css,html,txt,svg,png,ico,webp,woff,woff2,ttf,eot,otf,wasm}'],
|
||||
globIgnores: ['emojis/**', 'shiki/**', 'manifest**.webmanifest'],
|
||||
manifestTransforms: [(entries) => {
|
||||
const manifest = entries.map((entry) => {
|
||||
if (entry.url.length > 1 && entry.url[0] !== '/')
|
||||
entry.url = `/${entry.url}`
|
||||
|
||||
return entry
|
||||
})
|
||||
|
||||
return { manifest, warnings: [] }
|
||||
}],
|
||||
},
|
||||
devOptions: {
|
||||
enabled: process.env.VITE_DEV_PWA === 'true',
|
||||
|
|
|
@ -103,6 +103,16 @@ Elk will generate 2 web manifests per locale, one for light theme and one for da
|
|||
|
||||
You can check web manifest generation on [modules/pwa/i18n.ts](https://github.com/elk-zone/elk/blob/main/modules/pwa/i18n.ts) module.
|
||||
|
||||
### PWA Icons
|
||||
|
||||
Elk's favicon and PWA icons are generated from [Elk's SVG Logo](https://github.com/elk-zone/elk/blob/main/public/logo.svg) via [custom script](https://github.com/elk-zone/elk/blob/main/scripts/generate-pwa-icons.ts), using [sharp](https://github.com/lovell/sharp/) and [sharp-io](https://github.com/ssnangua/sharp-ico) libraries:
|
||||
- favicon.ico: transparent 64x64 32-bits icon
|
||||
- pwa-64x64.png: transparent 64x64 8-bits icon (optimized from 32-bitss color)
|
||||
- pwa-192x192.png: transparent 192x192 8-bits icon (optimized from 32-bits color)
|
||||
- pwa-512x512.png: transparent 512x512 8-bits icon (optimized from 32-bit color)
|
||||
- maskable-icon.png: white background 512x512 8-bits icon (optimized from 32-bits color)
|
||||
- apple-touch-icon.png: white background 180x180 8-bits icon (optimized from 32-bits color)
|
||||
|
||||
### PWA UI Components
|
||||
|
||||
Elk will provide a set of UI components to allow you to customize the PWA installation prompt on browsers with [beforeinstallprompt](https://web.dev/customize-install/) support.
|
||||
|
|
|
@ -76,8 +76,13 @@ export async function createI18n(): Promise<LocalizedWebManifest> {
|
|||
orientation: 'natural',
|
||||
display: 'standalone',
|
||||
display_override: ['window-controls-overlay'],
|
||||
categories: ['social', 'social networking'],
|
||||
categories: ['social', 'social networking', 'news'],
|
||||
icons: [
|
||||
{
|
||||
src: 'pwa-64x64.png',
|
||||
sizes: '64x64',
|
||||
type: 'image/png',
|
||||
},
|
||||
{
|
||||
src: 'pwa-192x192.png',
|
||||
sizes: '192x192',
|
||||
|
@ -114,6 +119,8 @@ export async function createI18n(): Promise<LocalizedWebManifest> {
|
|||
},
|
||||
}
|
||||
|
||||
// TODO: add related_applications, only when env === 'release'
|
||||
|
||||
const locales: RequiredWebManifestEntry[] = await Promise.all(
|
||||
pwaLocales
|
||||
.filter(l => l.code !== 'en-US')
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
"update:team:avatars": "tsx scripts/avatars.ts",
|
||||
"cleanup-translations": "tsx scripts/cleanup-translations.ts",
|
||||
"prepare-translation-status": "tsx scripts/prepare-translation-status.ts",
|
||||
"generate-pwa-icons": "tsx scripts/generate-pwa-icons.ts",
|
||||
"postinstall": "ignore-dependency-scripts \"stale-dep -u && simple-git-hooks && nuxi prepare && nr prepare-translation-status\"",
|
||||
"release": "stale-dep && bumpp && tsx scripts/release.ts"
|
||||
},
|
||||
|
@ -94,7 +95,7 @@
|
|||
"ufo": "^1.1.2",
|
||||
"ultrahtml": "^1.2.0",
|
||||
"unimport": "^3.0.7",
|
||||
"vite-plugin-pwa": "^0.15.0",
|
||||
"vite-plugin-pwa": "^0.15.1",
|
||||
"vue-advanced-cropper": "^2.8.8",
|
||||
"vue-virtual-scroller": "2.0.0-beta.8",
|
||||
"workbox-build": "^6.5.4",
|
||||
|
@ -120,6 +121,8 @@
|
|||
"lint-staged": "^13.2.2",
|
||||
"nuxt": "3.5.2",
|
||||
"prettier": "^2.8.8",
|
||||
"sharp": "^0.32.1",
|
||||
"sharp-ico": "^0.1.5",
|
||||
"simple-git-hooks": "^2.8.1",
|
||||
"tsx": "^3.12.7",
|
||||
"typescript": "^5.0.4",
|
||||
|
|
208
pnpm-lock.yaml
|
@ -205,8 +205,8 @@ importers:
|
|||
specifier: ^3.0.7
|
||||
version: 3.0.7(rollup@2.79.1)
|
||||
vite-plugin-pwa:
|
||||
specifier: ^0.15.0
|
||||
version: 0.15.0(vite@4.3.9)(workbox-build@6.5.4)(workbox-window@6.5.4)
|
||||
specifier: ^0.15.1
|
||||
version: 0.15.1(vite@4.3.9)(workbox-build@6.5.4)(workbox-window@6.5.4)
|
||||
vue-advanced-cropper:
|
||||
specifier: ^2.8.8
|
||||
version: 2.8.8(vue@3.3.4)
|
||||
|
@ -277,6 +277,12 @@ importers:
|
|||
prettier:
|
||||
specifier: ^2.8.8
|
||||
version: 2.8.8
|
||||
sharp:
|
||||
specifier: ^0.32.1
|
||||
version: 0.32.1
|
||||
sharp-ico:
|
||||
specifier: ^0.1.5
|
||||
version: 0.1.5
|
||||
simple-git-hooks:
|
||||
specifier: ^2.8.1
|
||||
version: 2.8.1
|
||||
|
@ -1599,6 +1605,10 @@ packages:
|
|||
'@babel/helper-validator-identifier': 7.19.1
|
||||
to-fast-properties: 2.0.0
|
||||
|
||||
/@canvas/image-data@1.0.0:
|
||||
resolution: {integrity: sha512-BxOqI5LgsIQP1odU5KMwV9yoijleOPzHL18/YvNqF9KFSGF2K/DLlYAbDQsWqd/1nbaFuSkYD/191dpMtNh4vw==}
|
||||
dev: true
|
||||
|
||||
/@cloudflare/kv-asset-handler@0.3.0:
|
||||
resolution: {integrity: sha512-9CB/MKf/wdvbfkUdfrj+OkEwZ5b7rws0eogJ4293h+7b6KX5toPwym+VQKmILafNB9YiehqY0DlNrDcDhdWHSQ==}
|
||||
dependencies:
|
||||
|
@ -5908,6 +5918,10 @@ packages:
|
|||
optionalDependencies:
|
||||
fsevents: 2.3.2
|
||||
|
||||
/chownr@1.1.4:
|
||||
resolution: {integrity: sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg==}
|
||||
dev: true
|
||||
|
||||
/chownr@2.0.0:
|
||||
resolution: {integrity: sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==}
|
||||
engines: {node: '>=10'}
|
||||
|
@ -6023,10 +6037,25 @@ packages:
|
|||
/color-name@1.1.4:
|
||||
resolution: {integrity: sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==}
|
||||
|
||||
/color-string@1.9.1:
|
||||
resolution: {integrity: sha512-shrVawQFojnZv6xM40anx4CkoDP+fZsw/ZerEMsW/pyzsRbElpsL/DBVW7q3ExxwusdNXI3lXpuhEZkzs8p5Eg==}
|
||||
dependencies:
|
||||
color-name: 1.1.4
|
||||
simple-swizzle: 0.2.2
|
||||
dev: true
|
||||
|
||||
/color-support@1.1.3:
|
||||
resolution: {integrity: sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==}
|
||||
hasBin: true
|
||||
|
||||
/color@4.2.3:
|
||||
resolution: {integrity: sha512-1rXeuUUiGGrykh+CeBdu5Ie7OJwinCgQY0bc7GCRxy5xVHy+moaqkpL/jqQq0MtQOeYcrqEz4abc5f0KtU7W4A==}
|
||||
engines: {node: '>=12.5.0'}
|
||||
dependencies:
|
||||
color-convert: 2.0.1
|
||||
color-string: 1.9.1
|
||||
dev: true
|
||||
|
||||
/colord@2.9.3:
|
||||
resolution: {integrity: sha512-jeC1axXpnb0/2nn/Y1LPuLdgXBLH7aDcHu4KEKfqw3CUhX7ZpfBSlPKyqXE6btIgEzfWtrX3/tyBCaCvXvMkOw==}
|
||||
|
||||
|
@ -6343,18 +6372,47 @@ packages:
|
|||
dependencies:
|
||||
ms: 2.1.2
|
||||
|
||||
/decode-bmp@0.2.1:
|
||||
resolution: {integrity: sha512-NiOaGe+GN0KJqi2STf24hfMkFitDUaIoUU3eKvP/wAbLe8o6FuW5n/x7MHPR0HKvBokp6MQY/j7w8lewEeVCIA==}
|
||||
engines: {node: '>=8.6.0'}
|
||||
dependencies:
|
||||
'@canvas/image-data': 1.0.0
|
||||
to-data-view: 1.1.0
|
||||
dev: true
|
||||
|
||||
/decode-ico@0.4.1:
|
||||
resolution: {integrity: sha512-69NZfbKIzux1vBOd31al3XnMnH+2mqDhEgLdpygErm4d60N+UwA5Sq5WFjmEDQzumgB9fElojGwWG0vybVfFmA==}
|
||||
engines: {node: '>=8.6'}
|
||||
dependencies:
|
||||
'@canvas/image-data': 1.0.0
|
||||
decode-bmp: 0.2.1
|
||||
to-data-view: 1.1.0
|
||||
dev: true
|
||||
|
||||
/decode-named-character-reference@1.0.2:
|
||||
resolution: {integrity: sha512-O8x12RzrUF8xyVcY0KJowWsmaJxQbmy0/EtnNtHRpsOcT7dFk5W598coHqBVpmWo1oQQfsCqfCmkZN5DJrZVdg==}
|
||||
dependencies:
|
||||
character-entities: 2.0.2
|
||||
dev: true
|
||||
|
||||
/decompress-response@6.0.0:
|
||||
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
mimic-response: 3.1.0
|
||||
dev: true
|
||||
|
||||
/deep-eql@4.1.3:
|
||||
resolution: {integrity: sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==}
|
||||
engines: {node: '>=6'}
|
||||
dependencies:
|
||||
type-detect: 4.0.8
|
||||
|
||||
/deep-extend@0.6.0:
|
||||
resolution: {integrity: sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==}
|
||||
engines: {node: '>=4.0.0'}
|
||||
dev: true
|
||||
|
||||
/deep-is@0.1.4:
|
||||
resolution: {integrity: sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==}
|
||||
|
||||
|
@ -7418,6 +7476,11 @@ packages:
|
|||
signal-exit: 3.0.7
|
||||
strip-final-newline: 3.0.0
|
||||
|
||||
/expand-template@2.0.3:
|
||||
resolution: {integrity: sha512-XYfuKMvj4O35f/pOXLObndIRvyQ+/+6AhODh+OKWj9S9498pHHn/IMszH+gt0fBCRWMNfk1ZSp5x3AifmnI2vg==}
|
||||
engines: {node: '>=6'}
|
||||
dev: true
|
||||
|
||||
/extend@3.0.2:
|
||||
resolution: {integrity: sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==}
|
||||
dev: true
|
||||
|
@ -7811,6 +7874,10 @@ packages:
|
|||
dependencies:
|
||||
git-up: 7.0.0
|
||||
|
||||
/github-from-package@0.0.0:
|
||||
resolution: {integrity: sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==}
|
||||
dev: true
|
||||
|
||||
/github-reserved-names@2.0.4:
|
||||
resolution: {integrity: sha512-T2azXbRJTJGQc28G6x89LpzQmuVjzl0hzJXPRD2t9yMh7URYUW8Opqr5ptHvjAVDJ+hwhBtoYmVx3VyFawRoFg==}
|
||||
dev: false
|
||||
|
@ -8194,6 +8261,10 @@ packages:
|
|||
ms: 2.1.3
|
||||
dev: false
|
||||
|
||||
/ico-endec@0.1.6:
|
||||
resolution: {integrity: sha512-ZdLU38ZoED3g1j3iEyzcQj+wAkY2xfWNkymszfJPoxucIUhK7NayQ+/C4Kv0nDFMIsbtbEHldv3V8PU494/ueQ==}
|
||||
dev: true
|
||||
|
||||
/iconv-lite@0.4.24:
|
||||
resolution: {integrity: sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
|
@ -8377,6 +8448,10 @@ packages:
|
|||
resolution: {integrity: sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==}
|
||||
dev: true
|
||||
|
||||
/is-arrayish@0.3.2:
|
||||
resolution: {integrity: sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==}
|
||||
dev: true
|
||||
|
||||
/is-bigint@1.0.4:
|
||||
resolution: {integrity: sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==}
|
||||
dependencies:
|
||||
|
@ -9724,6 +9799,11 @@ packages:
|
|||
resolution: {integrity: sha512-vqiC06CuhBTUdZH+RYl8sFrL096vA45Ok5ISO6sE/Mr1jRbGH4Csnhi8f3wKVl7x8mO4Au7Ir9D3Oyv1VYMFJw==}
|
||||
engines: {node: '>=12'}
|
||||
|
||||
/mimic-response@3.1.0:
|
||||
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
|
||||
engines: {node: '>=10'}
|
||||
dev: true
|
||||
|
||||
/min-indent@1.0.1:
|
||||
resolution: {integrity: sha512-I9jwMn07Sy/IwOj3zVkVik2JTvgpaykDZEigL6Rx6N9LbMywwUSMtxET+7lVoDLLd3O3IXwJwvuuns8UB/HeAg==}
|
||||
engines: {node: '>=4'}
|
||||
|
@ -9839,6 +9919,10 @@ packages:
|
|||
resolution: {integrity: sha512-ILj2TpLiysu2wkBbWjAmww7TkZb65aiQO+DkVdUTBpBXq+MHYiETENkKFMtsJZX1Lf4pe4QOrTSjIfUwN5lRdg==}
|
||||
dev: false
|
||||
|
||||
/mkdirp-classic@0.5.3:
|
||||
resolution: {integrity: sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==}
|
||||
dev: true
|
||||
|
||||
/mkdirp@0.5.6:
|
||||
resolution: {integrity: sha512-FP+p8RB8OWpF3YZBCrP5gtADmtXApB5AMLn+vdyA+PyxCjrCs00mjyUozssO33cwDeT3wNGdLxJ5M//YqtHAJw==}
|
||||
hasBin: true
|
||||
|
@ -9917,6 +10001,10 @@ packages:
|
|||
engines: {node: ^14 || ^16 || >=18}
|
||||
hasBin: true
|
||||
|
||||
/napi-build-utils@1.0.2:
|
||||
resolution: {integrity: sha512-ONmRUqK7zj7DWX0D9ADe03wbwOBZxNAfF20PlGfCWQcD3+/MakShIHrMqx9YwPTfxDdF1zLeL+RGZiR9kGMLdg==}
|
||||
dev: true
|
||||
|
||||
/natural-compare-lite@1.4.0:
|
||||
resolution: {integrity: sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==}
|
||||
dev: true
|
||||
|
@ -10019,6 +10107,17 @@ packages:
|
|||
lower-case: 2.0.2
|
||||
tslib: 2.5.2
|
||||
|
||||
/node-abi@3.40.0:
|
||||
resolution: {integrity: sha512-zNy02qivjjRosswoYmPi8hIKJRr8MpQyeKT6qlcq/OnOgA3Rhoae+IYOqsM9V5+JnHWmxKnWOT2GxvtqdtOCXA==}
|
||||
engines: {node: '>=10'}
|
||||
dependencies:
|
||||
semver: 7.5.1
|
||||
dev: true
|
||||
|
||||
/node-addon-api@6.1.0:
|
||||
resolution: {integrity: sha512-+eawOlIgy680F0kBzPUNFhMZGtJ1YmqM6l4+Crf4IkImjYrO/mqPwRMh352g23uIaQKFItcQ64I7KMaJxHgAVA==}
|
||||
dev: true
|
||||
|
||||
/node-domexception@1.0.0:
|
||||
resolution: {integrity: sha512-/jKZoMpw0F8GRwl4/eLROPA3cfcXtLApP0QzLmUT/HuPCZWyB7IY9ZrMeKw2O/nFIqPQB3PVM9aYm0F312AXDQ==}
|
||||
engines: {node: '>=10.5.0'}
|
||||
|
@ -11301,6 +11400,25 @@ packages:
|
|||
picocolors: 1.0.0
|
||||
source-map-js: 1.0.2
|
||||
|
||||
/prebuild-install@7.1.1:
|
||||
resolution: {integrity: sha512-jAXscXWMcCK8GgCoHOfIr0ODh5ai8mj63L2nWrjuAgXE6tDyYGnx4/8o/rCgU+B4JSyZBKbeZqzhtwtC3ovxjw==}
|
||||
engines: {node: '>=10'}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
detect-libc: 2.0.1
|
||||
expand-template: 2.0.3
|
||||
github-from-package: 0.0.0
|
||||
minimist: 1.2.8
|
||||
mkdirp-classic: 0.5.3
|
||||
napi-build-utils: 1.0.2
|
||||
node-abi: 3.40.0
|
||||
pump: 3.0.0
|
||||
rc: 1.2.8
|
||||
simple-get: 4.0.1
|
||||
tar-fs: 2.1.1
|
||||
tunnel-agent: 0.6.0
|
||||
dev: true
|
||||
|
||||
/prelude-ls@1.2.1:
|
||||
resolution: {integrity: sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
@ -11521,6 +11639,13 @@ packages:
|
|||
resolution: {integrity: sha512-b/YwNhb8lk1Zz2+bXXpS/LK9OisiZZ1SNsSLxN1x2OXVEhW2Ckr/7mWE5vrC1ZTiJlD9g19jWszTmJsB+oEpFQ==}
|
||||
dev: false
|
||||
|
||||
/pump@3.0.0:
|
||||
resolution: {integrity: sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==}
|
||||
dependencies:
|
||||
end-of-stream: 1.4.4
|
||||
once: 1.4.0
|
||||
dev: true
|
||||
|
||||
/punycode@2.3.0:
|
||||
resolution: {integrity: sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -11554,6 +11679,16 @@ packages:
|
|||
destr: 1.2.2
|
||||
flat: 5.0.2
|
||||
|
||||
/rc@1.2.8:
|
||||
resolution: {integrity: sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==}
|
||||
hasBin: true
|
||||
dependencies:
|
||||
deep-extend: 0.6.0
|
||||
ini: 1.3.8
|
||||
minimist: 1.2.8
|
||||
strip-json-comments: 2.0.1
|
||||
dev: true
|
||||
|
||||
/react-is@17.0.2:
|
||||
resolution: {integrity: sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w==}
|
||||
|
||||
|
@ -12153,6 +12288,29 @@ packages:
|
|||
/setprototypeof@1.2.0:
|
||||
resolution: {integrity: sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==}
|
||||
|
||||
/sharp-ico@0.1.5:
|
||||
resolution: {integrity: sha512-a3jODQl82NPp1d5OYb0wY+oFaPk7AvyxipIowCHk7pBsZCWgbe0yAkU2OOXdoH0ENyANhyOQbs9xkAiRHcF02Q==}
|
||||
dependencies:
|
||||
decode-ico: 0.4.1
|
||||
ico-endec: 0.1.6
|
||||
sharp: 0.32.1
|
||||
dev: true
|
||||
|
||||
/sharp@0.32.1:
|
||||
resolution: {integrity: sha512-kQTFtj7ldpUqSe8kDxoGLZc1rnMFU0AO2pqbX6pLy3b7Oj8ivJIdoKNwxHVQG2HN6XpHPJqCSM2nsma2gOXvOg==}
|
||||
engines: {node: '>=14.15.0'}
|
||||
requiresBuild: true
|
||||
dependencies:
|
||||
color: 4.2.3
|
||||
detect-libc: 2.0.1
|
||||
node-addon-api: 6.1.0
|
||||
prebuild-install: 7.1.1
|
||||
semver: 7.5.1
|
||||
simple-get: 4.0.1
|
||||
tar-fs: 2.1.1
|
||||
tunnel-agent: 0.6.0
|
||||
dev: true
|
||||
|
||||
/shebang-command@2.0.0:
|
||||
resolution: {integrity: sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -12213,6 +12371,18 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/simple-concat@1.0.1:
|
||||
resolution: {integrity: sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==}
|
||||
dev: true
|
||||
|
||||
/simple-get@4.0.1:
|
||||
resolution: {integrity: sha512-brv7p5WgH0jmQJr1ZDDfKDOSeWWg+OVypG99A/5vYGPqJ6pxiaHLy8nxtFjBA7oMa01ebA9gfh1uMCFqOuXxvA==}
|
||||
dependencies:
|
||||
decompress-response: 6.0.0
|
||||
once: 1.4.0
|
||||
simple-concat: 1.0.1
|
||||
dev: true
|
||||
|
||||
/simple-git-hooks@2.8.1:
|
||||
resolution: {integrity: sha512-DYpcVR1AGtSfFUNzlBdHrQGPsOhuuEJ/FkmPOOlFysP60AHd3nsEpkGq/QEOdtUyT1Qhk7w9oLmFoMG+75BDog==}
|
||||
hasBin: true
|
||||
|
@ -12229,6 +12399,12 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/simple-swizzle@0.2.2:
|
||||
resolution: {integrity: sha512-JA//kQgZtbuY83m+xT+tXJkmJncGMTFT+C+g2h2R9uxkYIrE2yy9sgmcLhCnw57/WSD+Eh3J97FPEDFnbXnDUg==}
|
||||
dependencies:
|
||||
is-arrayish: 0.3.2
|
||||
dev: true
|
||||
|
||||
/sirv@2.0.3:
|
||||
resolution: {integrity: sha512-O9jm9BsID1P+0HOi81VpXPoDxYP374pkOLzACAoyUQ/3OUVndNpsz6wMnY2z+yOxzbllCKZrM+9QrWsv4THnyA==}
|
||||
engines: {node: '>= 10'}
|
||||
|
@ -12574,6 +12750,11 @@ packages:
|
|||
min-indent: 1.0.1
|
||||
dev: true
|
||||
|
||||
/strip-json-comments@2.0.1:
|
||||
resolution: {integrity: sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==}
|
||||
engines: {node: '>=0.10.0'}
|
||||
dev: true
|
||||
|
||||
/strip-json-comments@3.1.1:
|
||||
resolution: {integrity: sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==}
|
||||
engines: {node: '>=8'}
|
||||
|
@ -12671,6 +12852,15 @@ packages:
|
|||
resolution: {integrity: sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
||||
/tar-fs@2.1.1:
|
||||
resolution: {integrity: sha512-V0r2Y9scmbDRLCNex/+hYzvp/zyYjvFbHPNgVTKfQvVrb6guiE/fxP+XblDNR011utopbkex2nM4dHNV6GDsng==}
|
||||
dependencies:
|
||||
chownr: 1.1.4
|
||||
mkdirp-classic: 0.5.3
|
||||
pump: 3.0.0
|
||||
tar-stream: 2.2.0
|
||||
dev: true
|
||||
|
||||
/tar-stream@2.2.0:
|
||||
resolution: {integrity: sha512-ujeqbceABgwMZxEJnk2HDY2DlnUZ+9oEcb1KzTVfYHio0UE6dG71n60d8D2I4qNvleWrrXpmjpt7vZeF1LnMZQ==}
|
||||
engines: {node: '>=6'}
|
||||
|
@ -12819,6 +13009,10 @@ packages:
|
|||
dependencies:
|
||||
os-tmpdir: 1.0.2
|
||||
|
||||
/to-data-view@1.1.0:
|
||||
resolution: {integrity: sha512-1eAdufMg6mwgmlojAx3QeMnzB/BTVp7Tbndi3U7ftcT2zCZadjxkkmLmd97zmaxWi+sgGcgWrokmpEoy0Dn0vQ==}
|
||||
dev: true
|
||||
|
||||
/to-fast-properties@2.0.0:
|
||||
resolution: {integrity: sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==}
|
||||
engines: {node: '>=4'}
|
||||
|
@ -12910,6 +13104,12 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/tunnel-agent@0.6.0:
|
||||
resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==}
|
||||
dependencies:
|
||||
safe-buffer: 5.2.1
|
||||
dev: true
|
||||
|
||||
/type-check@0.4.0:
|
||||
resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==}
|
||||
engines: {node: '>= 0.8.0'}
|
||||
|
@ -13698,8 +13898,8 @@ packages:
|
|||
- supports-color
|
||||
dev: false
|
||||
|
||||
/vite-plugin-pwa@0.15.0(vite@4.3.9)(workbox-build@6.5.4)(workbox-window@6.5.4):
|
||||
resolution: {integrity: sha512-gpmx3BeubsRIXRBkjPToOTJbo8fknNmZFQs24i0TPZyaNVa0n27YHDo0Y72amnO70WvHKGE3e1fn8SYUP7e8SA==}
|
||||
/vite-plugin-pwa@0.15.1(vite@4.3.9)(workbox-build@6.5.4)(workbox-window@6.5.4):
|
||||
resolution: {integrity: sha512-lJVzEYda/Y9AfwxFzX0rV+QCQ2+WdBoEGtR1RBZKWxvrJ4NWEH1VZaHOMyzvRiYhWQsi7aFhewsp1CDvN/R1Og==}
|
||||
peerDependencies:
|
||||
vite: ^3.1.0 || ^4.0.0
|
||||
workbox-build: ^6.5.4
|
||||
|
|
Before Width: | Height: | Size: 4.4 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 993 B |
|
@ -18,7 +18,7 @@
|
|||
maskUnits="userSpaceOnUse"
|
||||
style="mask-type:alpha">
|
||||
<path
|
||||
fill="#D9D9D9"
|
||||
fill="white"
|
||||
d="M244 123c0 64.617-38.383 112-103 112-64.617 0-103-30.883-103-95.5C38 111.194-8.729 36.236 8 16 29.46-9.959 88.689 6 125 6c64.617 0 119 52.383 119 117Z"
|
||||
id="path19" />
|
||||
</mask>
|
||||
|
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 2.7 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 3.5 KiB |
BIN
public-dev/pwa-64x64.png
Normal file
After Width: | Height: | Size: 630 B |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 1.1 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 965 B |
|
@ -18,7 +18,7 @@
|
|||
maskUnits="userSpaceOnUse"
|
||||
style="mask-type:alpha">
|
||||
<path
|
||||
fill="#D9D9D9"
|
||||
fill="white"
|
||||
d="M244 123c0 64.617-38.383 112-103 112-64.617 0-103-30.883-103-95.5C38 111.194-8.729 36.236 8 16 29.46-9.959 88.689 6 125 6c64.617 0 119 52.383 119 117Z"
|
||||
id="path19" />
|
||||
</mask>
|
||||
|
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 2.6 KiB |
Before Width: | Height: | Size: 5.4 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
public-staging/pwa-64x64.png
Normal file
After Width: | Height: | Size: 603 B |
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 982 B |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 1 KiB |
|
@ -18,7 +18,7 @@
|
|||
maskUnits="userSpaceOnUse"
|
||||
style="mask-type:alpha">
|
||||
<path
|
||||
fill="#D9D9D9"
|
||||
fill="white"
|
||||
d="M244 123c0 64.617-38.383 112-103 112-64.617 0-103-30.883-103-95.5C38 111.194-8.729 36.236 8 16 29.46-9.959 88.689 6 125 6c64.617 0 119 52.383 119 117Z"
|
||||
id="path19" />
|
||||
</mask>
|
||||
|
|
Before Width: | Height: | Size: 2.9 KiB After Width: | Height: | Size: 2.9 KiB |
Before Width: | Height: | Size: 5 KiB After Width: | Height: | Size: 2.4 KiB |
Before Width: | Height: | Size: 5.9 KiB After Width: | Height: | Size: 1.4 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 3.4 KiB |
BIN
public/pwa-64x64.png
Normal file
After Width: | Height: | Size: 641 B |
208
scripts/generate-pwa-icons.ts
Normal file
|
@ -0,0 +1,208 @@
|
|||
import { rm, writeFile } from 'node:fs/promises'
|
||||
import { resolve } from 'pathe'
|
||||
import type { PngOptions, ResizeOptions } from 'sharp'
|
||||
import sharp from 'sharp'
|
||||
import ico from 'sharp-ico'
|
||||
|
||||
interface Icon {
|
||||
sizes: number[]
|
||||
padding: number
|
||||
resizeOptions?: ResizeOptions
|
||||
}
|
||||
|
||||
type IconType = 'transparent' | 'maskable' | 'apple'
|
||||
|
||||
/**
|
||||
* PWA Icons definition:
|
||||
* - transparent: [{ sizes: [192, 512], padding: 0.05, resizeOptions: { fit: 'contain', background: 'transparent' } }]
|
||||
* - maskable: [{ sizes: [512], padding: 0.3 }, resizeOptions: { fit: 'contain', background: 'white' } }]
|
||||
* - apple: [{ sizes: [180], padding: 0.3 }, resizeOptions: { fit: 'contain', background: 'white' } }]
|
||||
*/
|
||||
interface Icons extends Record<IconType, Icon> {
|
||||
/**
|
||||
* @default: { compressionLevel: 9, quality: 60 }`
|
||||
*/
|
||||
png?: PngOptions
|
||||
/**
|
||||
* @default `pwa-<size>x<size>.png`, `maskable-icon-<size>x<size>.png`, `apple-touch-icon-<size>x<size>.png`
|
||||
*/
|
||||
iconName?: (type: IconType, size: number) => string
|
||||
/**
|
||||
* Generate `favicon.ico` from transparent icons (from `pwa-<size>x<size>.png` ones)
|
||||
*/
|
||||
ico?: {
|
||||
/**
|
||||
* @default `favicon-<size>x<size>.ico`
|
||||
*/
|
||||
icoName?: (size: number) => string
|
||||
sizes: number[]
|
||||
}
|
||||
}
|
||||
|
||||
interface ResolvedIcons extends Required<Omit<Icons, 'ico'>> {
|
||||
ico?: {
|
||||
/**
|
||||
* @default `favicon-<size>x<size>.ico`
|
||||
*/
|
||||
icoName?: (size: number) => string
|
||||
sizes: number[]
|
||||
}
|
||||
}
|
||||
|
||||
const defaultIcons: Icons = {
|
||||
transparent: {
|
||||
sizes: [192, 512],
|
||||
padding: 0.05,
|
||||
resizeOptions: {
|
||||
fit: 'contain',
|
||||
background: 'transparent',
|
||||
},
|
||||
},
|
||||
maskable: {
|
||||
sizes: [512],
|
||||
padding: 0.3,
|
||||
resizeOptions: {
|
||||
fit: 'contain',
|
||||
background: 'white',
|
||||
},
|
||||
},
|
||||
apple: {
|
||||
sizes: [180],
|
||||
padding: 0.3,
|
||||
resizeOptions: {
|
||||
fit: 'contain',
|
||||
background: 'white',
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
const root = process.cwd()
|
||||
|
||||
const publicFolders = ['public', 'public-dev', 'public-staging'].map(folder => resolve(root, folder))
|
||||
|
||||
async function optimizePng(filePath: string, png: PngOptions) {
|
||||
await sharp(filePath).png(png).toFile(`${filePath.replace(/-temp\.png$/, '.png')}`)
|
||||
await rm(filePath)
|
||||
}
|
||||
|
||||
async function generateTransparentIcons(icons: ResolvedIcons, svgLogo: string, folder: string) {
|
||||
const { sizes, padding, resizeOptions } = icons.transparent
|
||||
await Promise.all(sizes.map(async (size) => {
|
||||
const filePath = resolve(folder, icons.iconName('transparent', size))
|
||||
await sharp({
|
||||
create: {
|
||||
width: size,
|
||||
height: size,
|
||||
channels: 4,
|
||||
background: { r: 0, g: 0, b: 0, alpha: 0 },
|
||||
},
|
||||
}).composite([{
|
||||
input: await sharp(svgLogo)
|
||||
.resize(
|
||||
Math.round(size * (1 - padding)),
|
||||
Math.round(size * (1 - padding)),
|
||||
resizeOptions,
|
||||
).toBuffer(),
|
||||
}]).toFile(filePath)
|
||||
await optimizePng(filePath, icons.png)
|
||||
}))
|
||||
}
|
||||
|
||||
async function generateMaskableIcons(type: IconType, icons: ResolvedIcons, svgLogo: string, folder: string) {
|
||||
const { sizes, padding, resizeOptions } = icons[type]
|
||||
await Promise.all(sizes.map(async (size) => {
|
||||
const filePath = resolve(folder, icons.iconName(type, size))
|
||||
await sharp({
|
||||
create: {
|
||||
width: size,
|
||||
height: size,
|
||||
channels: 4,
|
||||
background: resizeOptions?.background ?? 'white',
|
||||
},
|
||||
}).composite([{
|
||||
input: await sharp(svgLogo)
|
||||
.resize(
|
||||
Math.round(size * (1 - padding)),
|
||||
Math.round(size * (1 - padding)),
|
||||
resizeOptions,
|
||||
).toBuffer(),
|
||||
}]).toFile(filePath)
|
||||
await optimizePng(filePath, icons.png)
|
||||
}))
|
||||
}
|
||||
|
||||
async function generatePWAIconForEnv(folder: string, icons: ResolvedIcons) {
|
||||
const svgLogo = resolve(folder, 'logo.svg')
|
||||
await Promise.all([
|
||||
generateTransparentIcons(icons, svgLogo, folder),
|
||||
generateMaskableIcons('maskable', icons, svgLogo, folder),
|
||||
generateMaskableIcons('apple', icons, svgLogo, folder),
|
||||
])
|
||||
|
||||
if (icons.ico) {
|
||||
const {
|
||||
icoName = size => `favicon-${size}x${size}.ico`,
|
||||
} = icons.ico
|
||||
await Promise.all(icons.ico.sizes.map(async (size) => {
|
||||
const png = await sharp(
|
||||
resolve(folder, icons.iconName('transparent', size).replace(/-temp\.png$/, '.png')),
|
||||
).toFormat('png').toBuffer()
|
||||
await writeFile(resolve(folder, icoName(size)), ico.encode([png]))
|
||||
}))
|
||||
}
|
||||
}
|
||||
|
||||
async function generatePWAIcons(folders: string[], icons: Icons) {
|
||||
const {
|
||||
png = { compressionLevel: 9, quality: 60 },
|
||||
iconName = (type, size) => {
|
||||
switch (type) {
|
||||
case 'transparent':
|
||||
return `pwa-${size}x${size}.png`
|
||||
case 'maskable':
|
||||
return `maskable-icon-${size}x${size}.png`
|
||||
case 'apple':
|
||||
return `apple-touch-icon-${size}x${size}.png`
|
||||
}
|
||||
},
|
||||
transparent = { ...defaultIcons.transparent },
|
||||
maskable = { ...defaultIcons.maskable },
|
||||
apple = { ...defaultIcons.apple },
|
||||
ico,
|
||||
} = icons
|
||||
|
||||
if (!transparent.resizeOptions)
|
||||
transparent.resizeOptions = { ...defaultIcons.transparent.resizeOptions }
|
||||
|
||||
if (!maskable.resizeOptions)
|
||||
maskable.resizeOptions = { ...defaultIcons.maskable.resizeOptions }
|
||||
|
||||
if (!apple.resizeOptions)
|
||||
apple.resizeOptions = { ...defaultIcons.apple.resizeOptions }
|
||||
|
||||
await Promise.all(folders.map(folder => generatePWAIconForEnv(folder, {
|
||||
png,
|
||||
iconName,
|
||||
transparent,
|
||||
maskable,
|
||||
apple,
|
||||
ico,
|
||||
})))
|
||||
}
|
||||
|
||||
console.log('Generating Elk PWA Icons...')
|
||||
|
||||
generatePWAIcons(publicFolders, <Icons>{
|
||||
transparent: { ...defaultIcons.transparent, sizes: [64, 192, 512] },
|
||||
ico: { sizes: [64], icoName: _ => 'favicon.ico' },
|
||||
iconName: (type, size) => {
|
||||
switch (type) {
|
||||
case 'transparent':
|
||||
return `pwa-${size}x${size}-temp.png`
|
||||
case 'maskable':
|
||||
return 'maskable-icon-temp.png'
|
||||
case 'apple':
|
||||
return 'apple-touch-icon-temp.png'
|
||||
}
|
||||
},
|
||||
}).then(() => console.log('Elk PWA Icons generated')).catch(console.error)
|