feat: add pwa install button (#27)

* feat: add pwa tooltip

* feat: add pwa install button
This commit is contained in:
云游君
2022-04-30 20:39:24 +08:00
committed by GitHub
parent 50156534c2
commit 2712616683
9 changed files with 154 additions and 68 deletions

View File

@@ -47,7 +47,7 @@
"pnpm": "^6.32.11",
"sass": "^1.51.0",
"star-markdown-css": "^0.3.3",
"typescript": "^4.6.3",
"typescript": "^4.6.4",
"unocss": "^0.32.1",
"unplugin-auto-import": "^0.7.1",
"unplugin-vue-components": "^0.19.3",
@@ -60,6 +60,6 @@
"vite-ssg": "^0.19.2",
"vite-ssg-sitemap": "^0.2.4",
"vue-toastification": "^2.0.0-rc.5",
"vue-tsc": "^0.34.10"
"vue-tsc": "^0.34.11"
}
}

132
pnpm-lock.yaml generated
View File

@@ -27,7 +27,7 @@ specifiers:
prism-theme-vars: ^0.2.2
sass: ^1.51.0
star-markdown-css: ^0.3.3
typescript: ^4.6.3
typescript: ^4.6.4
unocss: ^0.32.1
unplugin-auto-import: ^0.7.1
unplugin-vue-components: ^0.19.3
@@ -44,14 +44,14 @@ specifiers:
vue-demi: ^0.12.5
vue-router: ^4.0.14
vue-toastification: ^2.0.0-rc.5
vue-tsc: ^0.34.10
vue-tsc: ^0.34.11
dependencies:
'@gtm-support/vue-gtm': 1.4.0_vue@3.2.33
'@vueuse/core': 8.3.1_vue@3.2.33
'@vueuse/head': 0.7.6_vue@3.2.33
nprogress: 0.2.0
pinia: 2.0.13_typescript@4.6.3+vue@3.2.33
pinia: 2.0.13_typescript@4.6.4+vue@3.2.33
prism-theme-vars: 0.2.2
vue: 3.2.33
vue-about-me: 1.2.7
@@ -59,7 +59,7 @@ dependencies:
vue-router: 4.0.14_vue@3.2.33
devDependencies:
'@antfu/eslint-config': 0.21.1_eslint@8.14.0+typescript@4.6.3
'@antfu/eslint-config': 0.21.1_eslint@8.14.0+typescript@4.6.4
'@iconify-json/fe': 1.1.1
'@iconify-json/gg': 1.1.1
'@iconify-json/ic': 1.1.2
@@ -79,7 +79,7 @@ devDependencies:
pnpm: 6.32.11
sass: 1.51.0
star-markdown-css: 0.3.3
typescript: 4.6.3
typescript: 4.6.4
unocss: 0.32.1_vite@2.9.6
unplugin-auto-import: 0.7.1_@vueuse+core@8.3.1+vite@2.9.6
unplugin-vue-components: 0.19.3_vite@2.9.6+vue@3.2.33
@@ -92,7 +92,7 @@ devDependencies:
vite-ssg: 0.19.2_df629b3e0950eaa377a8a831fd5df6d0
vite-ssg-sitemap: 0.2.4
vue-toastification: 2.0.0-rc.5_vue@3.2.33
vue-tsc: 0.34.10_typescript@4.6.3
vue-tsc: 0.34.11_typescript@4.6.4
packages:
@@ -103,13 +103,13 @@ packages:
'@jridgewell/trace-mapping': 0.3.9
dev: true
/@antfu/eslint-config-basic/0.21.1_eslint@8.14.0+typescript@4.6.3:
/@antfu/eslint-config-basic/0.21.1_eslint@8.14.0+typescript@4.6.4:
resolution: {integrity: sha512-2VSzSxEgr2ouboDQ8lVtODjrxXtWmCgOv1B2f/4hEJJZbWI16by/E0TcZuwZTCkVRbmhfIFXNTwmputyyF5Kog==}
peerDependencies:
eslint: '>=7.4.0'
dependencies:
eslint: 8.14.0
eslint-plugin-antfu: 0.21.1_eslint@8.14.0+typescript@4.6.3
eslint-plugin-antfu: 0.21.1_eslint@8.14.0+typescript@4.6.4
eslint-plugin-eslint-comments: 3.2.0_eslint@8.14.0
eslint-plugin-html: 6.2.0
eslint-plugin-import: 2.26.0_eslint@8.14.0
@@ -126,12 +126,12 @@ packages:
- typescript
dev: true
/@antfu/eslint-config-react/0.21.1_eslint@8.14.0+typescript@4.6.3:
/@antfu/eslint-config-react/0.21.1_eslint@8.14.0+typescript@4.6.4:
resolution: {integrity: sha512-hKnr34URRK97J1Bd+1rfSnVO0zDyEemYDQweaWsiOTJ0iXe1IirZPR2VdxIUozj41kMd/VQCXrrg/phTU2ZhkQ==}
peerDependencies:
eslint: '>=7.4.0'
dependencies:
'@antfu/eslint-config-ts': 0.21.1_eslint@8.14.0+typescript@4.6.3
'@antfu/eslint-config-ts': 0.21.1_eslint@8.14.0+typescript@4.6.4
eslint: 8.14.0
eslint-plugin-react: 7.29.4_eslint@8.14.0
transitivePeerDependencies:
@@ -139,27 +139,27 @@ packages:
- typescript
dev: true
/@antfu/eslint-config-ts/0.21.1_eslint@8.14.0+typescript@4.6.3:
/@antfu/eslint-config-ts/0.21.1_eslint@8.14.0+typescript@4.6.4:
resolution: {integrity: sha512-GoJCur/CZBSRIwocvHYBRhzvtk7jr7oTJfIMPi9MOae171nocIBCu67RHlc0Wx/ziLnZ+k5NPzBcrm0ssKTCRQ==}
peerDependencies:
eslint: '>=7.4.0'
typescript: '>=3.9'
dependencies:
'@antfu/eslint-config-basic': 0.21.1_eslint@8.14.0+typescript@4.6.3
'@typescript-eslint/eslint-plugin': 5.21.0_829e74f28e9c9eb05edda582d47d45b8
'@typescript-eslint/parser': 5.21.0_eslint@8.14.0+typescript@4.6.3
'@antfu/eslint-config-basic': 0.21.1_eslint@8.14.0+typescript@4.6.4
'@typescript-eslint/eslint-plugin': 5.21.0_ade6595cb7be1524e723c025c098ae5d
'@typescript-eslint/parser': 5.21.0_eslint@8.14.0+typescript@4.6.4
eslint: 8.14.0
typescript: 4.6.3
typescript: 4.6.4
transitivePeerDependencies:
- supports-color
dev: true
/@antfu/eslint-config-vue/0.21.1_eslint@8.14.0+typescript@4.6.3:
/@antfu/eslint-config-vue/0.21.1_eslint@8.14.0+typescript@4.6.4:
resolution: {integrity: sha512-O5SCfWRGtcTtCDwMxQBYFrq8u/lxEIyuJBz82C0kKvjJdZblTqyDaS/vyKLniqIAiYj/QiwoL6i6yvEFhQ/OZg==}
peerDependencies:
eslint: '>=7.4.0'
dependencies:
'@antfu/eslint-config-ts': 0.21.1_eslint@8.14.0+typescript@4.6.3
'@antfu/eslint-config-ts': 0.21.1_eslint@8.14.0+typescript@4.6.4
eslint: 8.14.0
eslint-plugin-vue: 8.7.1_eslint@8.14.0
transitivePeerDependencies:
@@ -167,15 +167,15 @@ packages:
- typescript
dev: true
/@antfu/eslint-config/0.21.1_eslint@8.14.0+typescript@4.6.3:
/@antfu/eslint-config/0.21.1_eslint@8.14.0+typescript@4.6.4:
resolution: {integrity: sha512-DMRn6gPlYO3zorIrbzTd5GTzbw1l5/QvxxofLa950kRhLWK72vLEk93eoz5jllNPBlxP1R0kgZcjuw3DGNm3Sg==}
peerDependencies:
eslint: '>=7.4.0'
dependencies:
'@antfu/eslint-config-react': 0.21.1_eslint@8.14.0+typescript@4.6.3
'@antfu/eslint-config-vue': 0.21.1_eslint@8.14.0+typescript@4.6.3
'@typescript-eslint/eslint-plugin': 5.21.0_829e74f28e9c9eb05edda582d47d45b8
'@typescript-eslint/parser': 5.21.0_eslint@8.14.0+typescript@4.6.3
'@antfu/eslint-config-react': 0.21.1_eslint@8.14.0+typescript@4.6.4
'@antfu/eslint-config-vue': 0.21.1_eslint@8.14.0+typescript@4.6.4
'@typescript-eslint/eslint-plugin': 5.21.0_ade6595cb7be1524e723c025c098ae5d
'@typescript-eslint/parser': 5.21.0_eslint@8.14.0+typescript@4.6.4
eslint: 8.14.0
eslint-plugin-eslint-comments: 3.2.0_eslint@8.14.0
eslint-plugin-html: 6.2.0
@@ -1621,7 +1621,7 @@ packages:
resolution: {integrity: sha512-PBjIUxZHOuj0R15/xuwJYjFi+KZdNFrehocChv4g5hu6aFroHue8m0lBP0POdK2nKzbw0cgV1mws8+V/JAcEkQ==}
dev: true
/@typescript-eslint/eslint-plugin/5.21.0_829e74f28e9c9eb05edda582d47d45b8:
/@typescript-eslint/eslint-plugin/5.21.0_ade6595cb7be1524e723c025c098ae5d:
resolution: {integrity: sha512-fTU85q8v5ZLpoZEyn/u1S2qrFOhi33Edo2CZ0+q1gDaWWm0JuPh3bgOyU8lM0edIEYgKLDkPFiZX2MOupgjlyg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1632,23 +1632,23 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/parser': 5.21.0_eslint@8.14.0+typescript@4.6.3
'@typescript-eslint/parser': 5.21.0_eslint@8.14.0+typescript@4.6.4
'@typescript-eslint/scope-manager': 5.21.0
'@typescript-eslint/type-utils': 5.21.0_eslint@8.14.0+typescript@4.6.3
'@typescript-eslint/utils': 5.21.0_eslint@8.14.0+typescript@4.6.3
'@typescript-eslint/type-utils': 5.21.0_eslint@8.14.0+typescript@4.6.4
'@typescript-eslint/utils': 5.21.0_eslint@8.14.0+typescript@4.6.4
debug: 4.3.4
eslint: 8.14.0
functional-red-black-tree: 1.0.1
ignore: 5.2.0
regexpp: 3.2.0
semver: 7.3.7
tsutils: 3.21.0_typescript@4.6.3
typescript: 4.6.3
tsutils: 3.21.0_typescript@4.6.4
typescript: 4.6.4
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/parser/5.21.0_eslint@8.14.0+typescript@4.6.3:
/@typescript-eslint/parser/5.21.0_eslint@8.14.0+typescript@4.6.4:
resolution: {integrity: sha512-8RUwTO77hstXUr3pZoWZbRQUxXcSXafZ8/5gpnQCfXvgmP9gpNlRGlWzvfbEQ14TLjmtU8eGnONkff8U2ui2Eg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1660,10 +1660,10 @@ packages:
dependencies:
'@typescript-eslint/scope-manager': 5.21.0
'@typescript-eslint/types': 5.21.0
'@typescript-eslint/typescript-estree': 5.21.0_typescript@4.6.3
'@typescript-eslint/typescript-estree': 5.21.0_typescript@4.6.4
debug: 4.3.4
eslint: 8.14.0
typescript: 4.6.3
typescript: 4.6.4
transitivePeerDependencies:
- supports-color
dev: true
@@ -1676,7 +1676,7 @@ packages:
'@typescript-eslint/visitor-keys': 5.21.0
dev: true
/@typescript-eslint/type-utils/5.21.0_eslint@8.14.0+typescript@4.6.3:
/@typescript-eslint/type-utils/5.21.0_eslint@8.14.0+typescript@4.6.4:
resolution: {integrity: sha512-MxmLZj0tkGlkcZCSE17ORaHl8Th3JQwBzyXL/uvC6sNmu128LsgjTX0NIzy+wdH2J7Pd02GN8FaoudJntFvSOw==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1686,11 +1686,11 @@ packages:
typescript:
optional: true
dependencies:
'@typescript-eslint/utils': 5.21.0_eslint@8.14.0+typescript@4.6.3
'@typescript-eslint/utils': 5.21.0_eslint@8.14.0+typescript@4.6.4
debug: 4.3.4
eslint: 8.14.0
tsutils: 3.21.0_typescript@4.6.3
typescript: 4.6.3
tsutils: 3.21.0_typescript@4.6.4
typescript: 4.6.4
transitivePeerDependencies:
- supports-color
dev: true
@@ -1700,7 +1700,7 @@ packages:
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
dev: true
/@typescript-eslint/typescript-estree/5.21.0_typescript@4.6.3:
/@typescript-eslint/typescript-estree/5.21.0_typescript@4.6.4:
resolution: {integrity: sha512-Y8Y2T2FNvm08qlcoSMoNchh9y2Uj3QmjtwNMdRQkcFG7Muz//wfJBGBxh8R7HAGQFpgYpdHqUpEoPQk+q9Kjfg==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1715,13 +1715,13 @@ packages:
globby: 11.1.0
is-glob: 4.0.3
semver: 7.3.7
tsutils: 3.21.0_typescript@4.6.3
typescript: 4.6.3
tsutils: 3.21.0_typescript@4.6.4
typescript: 4.6.4
transitivePeerDependencies:
- supports-color
dev: true
/@typescript-eslint/utils/5.21.0_eslint@8.14.0+typescript@4.6.3:
/@typescript-eslint/utils/5.21.0_eslint@8.14.0+typescript@4.6.4:
resolution: {integrity: sha512-q/emogbND9wry7zxy7VYri+7ydawo2HDZhRZ5k6yggIvXa7PvBbAAZ4PFH/oZLem72ezC4Pr63rJvDK/sTlL8Q==}
engines: {node: ^12.22.0 || ^14.17.0 || >=16.0.0}
peerDependencies:
@@ -1730,7 +1730,7 @@ packages:
'@types/json-schema': 7.0.11
'@typescript-eslint/scope-manager': 5.21.0
'@typescript-eslint/types': 5.21.0
'@typescript-eslint/typescript-estree': 5.21.0_typescript@4.6.3
'@typescript-eslint/typescript-estree': 5.21.0_typescript@4.6.4
eslint: 8.14.0
eslint-scope: 5.1.1
eslint-utils: 3.0.0_eslint@8.14.0
@@ -1881,32 +1881,32 @@ packages:
vue: 3.2.33
dev: true
/@volar/code-gen/0.34.10:
resolution: {integrity: sha512-Pygl26uA4CuQcDgNndeTSNOYF+NbShcV+rwWRy/nRNv1JB++1EbaQ60/ti8c5zTRoL4a8OtipKMq9Sw8LzpRIw==}
/@volar/code-gen/0.34.11:
resolution: {integrity: sha512-A4w+y+zP8qCDFyZ0KIm2oydRerp14a+IAYXro9wLt0LLvvqUGHEu/6y87uAj6TDqiX4OL/W8r1cEdhOJqFrBlA==}
dependencies:
'@volar/source-map': 0.34.10
'@volar/source-map': 0.34.11
dev: true
/@volar/source-map/0.34.10:
resolution: {integrity: sha512-DBSUGNJB2B08U6Ut14ZJSEOcBS7eV/aiinhoLbMrEe/HJtZRcnPuyE8f0c2BvmRM2LK8WQx77V54/lw/Ra8WDA==}
/@volar/source-map/0.34.11:
resolution: {integrity: sha512-ZsNZqFPUDDL1y6hK0ok7EriFb3CnCeapTLQrziTAbi3yOhcE4yM4G59XtRzc1i9EB+RXscm9a6Q6TgzD5KvoeA==}
dev: true
/@volar/vue-code-gen/0.34.10:
resolution: {integrity: sha512-oK5gat5AHllSMJzY+UMbttJvAjoUGzicXxLHoIwb6DTHpfcf2pADYUndiw5kSYHo+2Xd/+U1c9D8FUOJ+JHAFw==}
/@volar/vue-code-gen/0.34.11:
resolution: {integrity: sha512-r/tnLd1eyy/PI0fBUYU7hKXkCyHb0JqBidTiADrazzkYMraRcwL6JNLOj/D7Pk75W0ObzlMUfHJdrAuxKvAHRg==}
dependencies:
'@volar/code-gen': 0.34.10
'@volar/source-map': 0.34.10
'@volar/code-gen': 0.34.11
'@volar/source-map': 0.34.11
'@vue/compiler-core': 3.2.33
'@vue/compiler-dom': 3.2.33
'@vue/shared': 3.2.33
dev: true
/@volar/vue-typescript/0.34.10:
resolution: {integrity: sha512-FCGSqLC+T/AcBUFXoFniPKLa/fLslBuHsepUmId8dG5ROXZhQaJ5h4fkA87247SWb7z4o9mI6v86xevXEjRVKw==}
/@volar/vue-typescript/0.34.11:
resolution: {integrity: sha512-pZkIeCPIjRRc/Oj9uxyOk6UvE43ecD71B/CSbmtiMU9sqrSwpP8cdDr/B/cqm1jwebkChTaa1gLodNHS8BOLuw==}
dependencies:
'@volar/code-gen': 0.34.10
'@volar/source-map': 0.34.10
'@volar/vue-code-gen': 0.34.10
'@volar/code-gen': 0.34.11
'@volar/source-map': 0.34.11
'@volar/vue-code-gen': 0.34.11
'@vue/compiler-sfc': 3.2.33
'@vue/reactivity': 3.2.33
dev: true
@@ -3366,10 +3366,10 @@ packages:
find-up: 2.1.0
dev: true
/eslint-plugin-antfu/0.21.1_eslint@8.14.0+typescript@4.6.3:
/eslint-plugin-antfu/0.21.1_eslint@8.14.0+typescript@4.6.4:
resolution: {integrity: sha512-J6sHezsuBHRavyp13pUVnlEcJjPglGNnjRWw1uGMqhkhzuYSgVekyxngn2EDbmQ/Ql5ptoIybuYFsCeQtD3LBA==}
dependencies:
'@typescript-eslint/utils': 5.21.0_eslint@8.14.0+typescript@4.6.3
'@typescript-eslint/utils': 5.21.0_eslint@8.14.0+typescript@4.6.4
transitivePeerDependencies:
- eslint
- supports-color
@@ -5236,7 +5236,7 @@ packages:
resolution: {integrity: sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==}
engines: {node: '>=8.6'}
/pinia/2.0.13_typescript@4.6.3+vue@3.2.33:
/pinia/2.0.13_typescript@4.6.4+vue@3.2.33:
resolution: {integrity: sha512-B7rSqm1xNpwcPMnqns8/gVBfbbi7lWTByzS6aPZ4JOXSJD4Y531rZHDCoYWBwLyHY/8hWnXljgiXp6rRyrofcw==}
peerDependencies:
'@vue/composition-api': ^1.4.0
@@ -5249,7 +5249,7 @@ packages:
optional: true
dependencies:
'@vue/devtools-api': 6.1.4
typescript: 4.6.3
typescript: 4.6.4
vue: 3.2.33
vue-demi: 0.12.5_vue@3.2.33
dev: false
@@ -6013,14 +6013,14 @@ packages:
resolution: {integrity: sha512-77EbyPPpMz+FRFRuAFlWMtmgUWGe9UOG2Z25NqCwiIjRhOf5iKGuzSe5P2w1laq+FkRy4p+PCuVkJSGkzTEKVw==}
dev: true
/tsutils/3.21.0_typescript@4.6.3:
/tsutils/3.21.0_typescript@4.6.4:
resolution: {integrity: sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==}
engines: {node: '>= 6'}
peerDependencies:
typescript: '>=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta'
dependencies:
tslib: 1.14.1
typescript: 4.6.3
typescript: 4.6.4
dev: true
/type-check/0.3.2:
@@ -6065,8 +6065,8 @@ packages:
mime-types: 2.1.35
dev: true
/typescript/4.6.3:
resolution: {integrity: sha512-yNIatDa5iaofVozS/uQJEl3JRWLKKGJKh6Yaiv0GLGSuhpFJe7P3SbHZ8/yjAHRQwKRoA6YZqlfjXWmVzoVSMw==}
/typescript/4.6.4:
resolution: {integrity: sha512-9ia/jWHIEbo49HfjrLGfKbZSuWo9iTMwXO+Ca3pRsSpbsMbc7/IU8NKdCZVRRBafVPGnoJeFL76ZOAA84I9fEg==}
engines: {node: '>=4.2.0'}
hasBin: true
dev: true
@@ -6499,14 +6499,14 @@ packages:
vue: 3.2.33
dev: true
/vue-tsc/0.34.10_typescript@4.6.3:
resolution: {integrity: sha512-rWU4SjDqk9ylQN2hbnyP+rEu8W2a712DWUmciX6rDnId1m8sN/cuypTKjWjHHjaBLWNKULoEakRTOvrQ4ainhw==}
/vue-tsc/0.34.11_typescript@4.6.4:
resolution: {integrity: sha512-5NM4oR8U/c3mTlJ9aNXbXkAGT2bhq+FJpCgZDqOKPpCjW5QDx1BXPC+nrBXNMwg8TRL6pK4fl+x+hrK97Siq/Q==}
hasBin: true
peerDependencies:
typescript: '*'
dependencies:
'@volar/vue-typescript': 0.34.10
typescript: 4.6.3
'@volar/vue-typescript': 0.34.11
typescript: 4.6.4
dev: true
/vue/3.2.33:

View File

@@ -1,4 +1,5 @@
<script setup lang="ts">
import { installPrompt } from './utils/pwa'
import { isDark } from '~/composables'
// https://github.com/vueuse/head
// you can use this to manipulate the document head in any components,
@@ -16,6 +17,8 @@ useHead({
},
],
})
installPrompt()
</script>
<template>

1
src/components.d.ts vendored
View File

@@ -10,6 +10,7 @@ declare module '@vue/runtime-core' {
ChooseFood: typeof import('./components/ChooseFood.vue')['default']
Counter: typeof import('./components/Counter.vue')['default']
DishTag: typeof import('./components/tags/DishTag.vue')['default']
InstallPwa: typeof import('./components/InstallPwa.vue')['default']
MeatTag: typeof import('./components/tags/MeatTag.vue')['default']
Menu: typeof import('./components/Menu.vue')['default']
README: typeof import('./components/README.md')['default']

View File

@@ -0,0 +1,29 @@
<script lang="ts" setup>
import { useAppStore } from '~/stores/app'
const app = useAppStore()
const install = () => {
const deferredPrompt = app.deferredPrompt
// Show the install prompt
deferredPrompt.prompt()
// Wait for the user to respond to the prompt
deferredPrompt.userChoice.then((choiceResult: any) => {
if (choiceResult.outcome === 'accepted')
// eslint-disable-next-line no-console
console.log('User accepted the install prompt')
else
// eslint-disable-next-line no-console
console.log('User dismissed the install prompt')
})
}
</script>
<template>
<Transition>
<div v-if="app.deferredPrompt" text="center" m="t-2">
<button class="shadow" bg="green-500" p="x-4 y-0" m="2" @click="install">
安装
</button>
</div>
</Transition>
</template>

View File

@@ -25,6 +25,8 @@ title: 帮助
- 点击首页最上方的大锅图标,可清空所选食材和工具。
- 本项目支持 PWA使用浏览器打开时可将其添加到主屏幕以获得近原生 APP 的体验。
<InstallPwa />
## FAQ
### 页面无法点击、资源加载失败?

4
src/shims.d.ts vendored
View File

@@ -1,6 +1,10 @@
declare interface Window {
// extend the window
wx: any
/**
* pwa install prompt event
*/
deferredPrompt: Event | any
}
// with vite-plugin-md, markdowns can be treat as Vue components

12
src/stores/app.ts Normal file
View File

@@ -0,0 +1,12 @@
import { acceptHMRUpdate, defineStore } from 'pinia'
export const useAppStore = defineStore('app', () => {
const deferredPrompt = ref<Event | any>()
return {
deferredPrompt,
}
})
if (import.meta.hot)
import.meta.hot.accept(acceptHMRUpdate(useAppStore, import.meta.hot))

35
src/utils/pwa.ts Normal file
View File

@@ -0,0 +1,35 @@
import { isClient } from '@vueuse/core'
import { useAppStore } from '~/stores/app'
/**
* https://web.dev/customize-install/#detect-install
* @returns
*/
export function installPrompt() {
if (!isClient)
return
const app = useAppStore()
window.addEventListener('beforeinstallprompt', (e) => {
// Prevent the mini-infobar from appearing on mobile
// e.preventDefault()
// Stash the event so it can be triggered later.
app.deferredPrompt = e
// Update UI notify the user they can install the PWA
// showInstallPromotion()
// Optionally, send analytics event that PWA install promo was shown.
// eslint-disable-next-line no-console
console.log('\'beforeinstallprompt\' event was fired.')
})
window.addEventListener('appinstalled', () => {
// Hide the app-provided install promotion
// hideInstallPromotion()
// Clear the deferredPrompt so it can be garbage collected
app.deferredPrompt = null
// Optionally, send analytics event to indicate successful install
// eslint-disable-next-line no-console
console.log('PWA was installed')
})
}