@vuepress/plugin-pwa 2.0.0-rc.3 → 2.0.0-rc.31

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (69) hide show
  1. package/lib/client/components/PwaFoundPopup.d.ts +21 -0
  2. package/lib/client/components/PwaFoundPopup.js +56 -0
  3. package/lib/client/components/PwaInstall.d.ts +16 -0
  4. package/lib/client/components/PwaInstall.js +85 -0
  5. package/lib/client/components/PwaInstallModal.d.ts +33 -0
  6. package/lib/client/components/PwaInstallModal.js +169 -0
  7. package/lib/client/components/PwaReadyPopup.d.ts +21 -0
  8. package/lib/client/components/PwaReadyPopup.js +50 -0
  9. package/lib/client/components/icons.d.ts +9 -0
  10. package/lib/client/components/icons.js +25 -0
  11. package/lib/client/components/index.d.ts +3 -0
  12. package/lib/client/components/index.js +3 -0
  13. package/lib/client/composables/index.d.ts +3 -1
  14. package/lib/client/composables/index.js +3 -1
  15. package/lib/client/composables/setupPwa.d.ts +1 -0
  16. package/lib/client/composables/setupPwa.js +28 -0
  17. package/lib/client/composables/setupViewPoint.d.ts +1 -0
  18. package/lib/client/composables/setupViewPoint.js +18 -0
  19. package/lib/client/composables/usePwaEvent.js +2 -3
  20. package/lib/client/composables/useRegisterSW.d.ts +2 -0
  21. package/lib/client/composables/useRegisterSW.js +29 -0
  22. package/lib/client/index.d.ts +2 -0
  23. package/lib/client/index.js +2 -0
  24. package/lib/client/styles/modal.css +402 -0
  25. package/lib/client/styles/popup.css +66 -0
  26. package/lib/client/styles/vars.css +12 -0
  27. package/lib/client/utils/forceUpdate.d.ts +6 -0
  28. package/lib/client/utils/forceUpdate.js +16 -0
  29. package/lib/client/utils/index.d.ts +4 -0
  30. package/lib/client/utils/index.js +4 -0
  31. package/lib/client/utils/registerSW.d.ts +15 -0
  32. package/lib/client/utils/registerSW.js +57 -0
  33. package/lib/client/utils/skipWaiting.d.ts +6 -0
  34. package/lib/client/utils/skipWaiting.js +15 -0
  35. package/lib/client/utils/unregisterSW.d.ts +10 -0
  36. package/lib/client/utils/unregisterSW.js +24 -0
  37. package/lib/node/generateManifest.d.ts +3 -0
  38. package/lib/node/generateManifest.js +12 -0
  39. package/lib/node/generateServiceWorker.d.ts +2 -3
  40. package/lib/node/generateServiceWorker.js +50 -23
  41. package/lib/node/getManifest.d.ts +4 -0
  42. package/lib/node/getManifest.js +31 -0
  43. package/lib/node/helper.d.ts +4 -0
  44. package/lib/node/helper.js +38 -0
  45. package/lib/node/index.d.ts +3 -3
  46. package/lib/node/index.js +3 -3
  47. package/lib/node/injectLinksToHead.d.ts +3 -0
  48. package/lib/node/injectLinksToHead.js +62 -0
  49. package/lib/node/locales.d.ts +3 -0
  50. package/lib/node/locales.js +263 -0
  51. package/lib/node/logger.d.ts +3 -0
  52. package/lib/node/logger.js +3 -0
  53. package/lib/node/options.d.ts +183 -0
  54. package/lib/node/options.js +1 -0
  55. package/lib/node/prepareConfigFile.d.ts +3 -0
  56. package/lib/node/prepareConfigFile.js +48 -0
  57. package/lib/node/pwaPlugin.d.ts +3 -17
  58. package/lib/node/pwaPlugin.js +47 -14
  59. package/lib/shared/index.d.ts +2 -0
  60. package/lib/shared/index.js +2 -0
  61. package/lib/shared/locales.d.ts +70 -0
  62. package/lib/shared/locales.js +1 -0
  63. package/lib/shared/manifest.d.ts +129 -0
  64. package/lib/shared/manifest.js +2 -0
  65. package/package.json +19 -8
  66. package/lib/client/composables/useSkipWaiting.d.ts +0 -4
  67. package/lib/client/composables/useSkipWaiting.js +0 -13
  68. package/lib/client/config.d.ts +0 -3
  69. package/lib/client/config.js +0 -50
@@ -0,0 +1,21 @@
1
+ import type { PropType, SlotsType, VNode } from 'vue';
2
+ import type { PwaPluginLocaleConfig } from '../../shared/index.js';
3
+ import '../styles/popup.css';
4
+ export declare const PwaFoundPopup: import("vue").DefineComponent<{
5
+ /** locale data */
6
+ locales: {
7
+ type: PropType<PwaPluginLocaleConfig>;
8
+ required: true;
9
+ };
10
+ }, () => VNode, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
11
+ /** locale data */
12
+ locales: {
13
+ type: PropType<PwaPluginLocaleConfig>;
14
+ required: true;
15
+ };
16
+ }>>, {}, SlotsType<{
17
+ default?: ((props: {
18
+ found: boolean;
19
+ refresh: () => void;
20
+ }) => VNode[] | VNode | null) | undefined;
21
+ }>>;
@@ -0,0 +1,56 @@
1
+ import { useLocaleConfig } from '@vuepress/helper/client';
2
+ import { defineComponent, h, onMounted, ref, Transition } from 'vue';
3
+ import { usePwaEvent } from '../composables/index.js';
4
+ import { UpdateIcon } from './icons.js';
5
+ import '../styles/popup.css';
6
+ export const PwaFoundPopup = defineComponent({
7
+ name: 'PwaFoundPopup',
8
+ props: {
9
+ /** locale data */
10
+ locales: {
11
+ type: Object,
12
+ required: true,
13
+ },
14
+ },
15
+ slots: Object,
16
+ setup(props, { slots }) {
17
+ const locale = useLocaleConfig(props.locales);
18
+ const found = ref(false);
19
+ const refresh = () => {
20
+ if (found.value) {
21
+ // force refresh
22
+ // @ts-expect-error: A non-standard API
23
+ window.location.reload(true);
24
+ found.value = false;
25
+ }
26
+ };
27
+ onMounted(() => {
28
+ const event = usePwaEvent();
29
+ event.on('updatefound', () => {
30
+ navigator.serviceWorker.getRegistration().then((registration) => {
31
+ // Check whether a valid service worker is active
32
+ if (registration && registration.active)
33
+ found.value = true;
34
+ });
35
+ });
36
+ event.on('updated', () => {
37
+ found.value = false;
38
+ });
39
+ });
40
+ return () => h(Transition, { name: 'popup' }, () => slots.default?.({
41
+ found: found.value,
42
+ refresh,
43
+ }) ||
44
+ (found.value
45
+ ? h('button', {
46
+ type: 'button',
47
+ class: 'sw-hint-popup',
48
+ tabindex: 0,
49
+ onClick: () => refresh(),
50
+ }, [
51
+ locale.value.hint,
52
+ h('span', { class: 'icon-wrapper' }, h(UpdateIcon)),
53
+ ])
54
+ : null));
55
+ },
56
+ });
@@ -0,0 +1,16 @@
1
+ import type { PropType, VNode } from 'vue';
2
+ import type { PwaPluginLocaleConfig } from '../../shared/index.js';
3
+ import '../styles/modal.css';
4
+ export declare const PwaInstall: import("vue").DefineComponent<{
5
+ /** locale data */
6
+ locales: {
7
+ type: PropType<PwaPluginLocaleConfig>;
8
+ required: true;
9
+ };
10
+ }, () => VNode, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
11
+ /** locale data */
12
+ locales: {
13
+ type: PropType<PwaPluginLocaleConfig>;
14
+ required: true;
15
+ };
16
+ }>>, {}, {}>;
@@ -0,0 +1,85 @@
1
+ import { useLocaleConfig } from '@vuepress/helper/client';
2
+ import { useToggle } from '@vueuse/core';
3
+ import { computed, defineComponent, h, onMounted, ref } from 'vue';
4
+ import { PwaInstallModal } from './PwaInstallModal.js';
5
+ import '../styles/modal.css';
6
+ export const PwaInstall = defineComponent({
7
+ name: 'PwaInstall',
8
+ props: {
9
+ /** locale data */
10
+ locales: {
11
+ type: Object,
12
+ required: true,
13
+ },
14
+ },
15
+ setup(props) {
16
+ const locale = useLocaleConfig(props.locales);
17
+ const [isOpen, toggleIsOpen] = useToggle(false);
18
+ const canInstall = ref(false);
19
+ const hasRelatedApps = ref(false);
20
+ const isIOS = ref(false);
21
+ const isSafari = ref(false);
22
+ const hinted = ref(false);
23
+ const useHint = computed(() => isIOS.value && isSafari.value && hinted.value === false);
24
+ const showInstall = computed(() => (hasRelatedApps.value && canInstall.value) || useHint.value);
25
+ const getInstalledStatus = () => {
26
+ if (navigator.standalone)
27
+ return navigator.standalone;
28
+ return matchMedia('(display-mode: standalone)').matches;
29
+ };
30
+ const hint = () => {
31
+ toggleIsOpen(false);
32
+ hinted.value = true;
33
+ // do not notify again
34
+ localStorage.setItem('iOS-pwa-hint', 'hinted');
35
+ };
36
+ onMounted(() => {
37
+ if (getInstalledStatus()) {
38
+ const { userAgent } = navigator;
39
+ // handle iOS specifically
40
+ isIOS.value =
41
+ // regular iPhone
42
+ userAgent.includes('iPhone') ||
43
+ // regular iPad
44
+ userAgent.includes('iPad') ||
45
+ // iPad pro
46
+ Boolean(userAgent.includes('Macintosh') &&
47
+ navigator.maxTouchPoints &&
48
+ navigator.maxTouchPoints > 2);
49
+ isSafari.value =
50
+ navigator.userAgent.includes('Safari') &&
51
+ !userAgent.includes('Chrome');
52
+ hinted.value = Boolean(localStorage.getItem('iOS-pwa-hint'));
53
+ }
54
+ if ('getInstalledRelatedApps' in navigator)
55
+ navigator
56
+ .getInstalledRelatedApps()
57
+ .then((result) => {
58
+ hasRelatedApps.value = result.length > 0;
59
+ });
60
+ });
61
+ return () => h('div', { id: 'pwa-install' }, [
62
+ showInstall.value
63
+ ? h('button', {
64
+ type: 'button',
65
+ class: 'modal-button',
66
+ onClick: () => {
67
+ toggleIsOpen(true);
68
+ },
69
+ }, locale.value.install)
70
+ : null,
71
+ h(PwaInstallModal, {
72
+ style: {
73
+ display: isOpen.value ? 'block' : 'none',
74
+ },
75
+ locales: props.locales,
76
+ useHint: useHint.value,
77
+ onCanInstall: (value) => {
78
+ canInstall.value = value;
79
+ },
80
+ onHint: () => hint(),
81
+ onClose: () => toggleIsOpen(false),
82
+ }),
83
+ ]);
84
+ },
85
+ });
@@ -0,0 +1,33 @@
1
+ import type { PropType, VNode } from 'vue';
2
+ import type { PwaPluginLocaleConfig } from '../../shared/index.js';
3
+ export declare const PwaInstallModal: import("vue").DefineComponent<{
4
+ /** locale data */
5
+ locales: {
6
+ type: PropType<PwaPluginLocaleConfig>;
7
+ required: true;
8
+ };
9
+ /**
10
+ * Whether use hint message instead of showing a button
11
+ *
12
+ * 是否使用提示
13
+ */
14
+ useHint: BooleanConstructor;
15
+ }, () => VNode, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, ("close" | "canInstall" | "hint")[], "close" | "canInstall" | "hint", import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
16
+ /** locale data */
17
+ locales: {
18
+ type: PropType<PwaPluginLocaleConfig>;
19
+ required: true;
20
+ };
21
+ /**
22
+ * Whether use hint message instead of showing a button
23
+ *
24
+ * 是否使用提示
25
+ */
26
+ useHint: BooleanConstructor;
27
+ }>> & {
28
+ onClose?: ((...args: any[]) => any) | undefined;
29
+ onCanInstall?: ((...args: any[]) => any) | undefined;
30
+ onHint?: ((...args: any[]) => any) | undefined;
31
+ }, {
32
+ useHint: boolean;
33
+ }, {}>;
@@ -0,0 +1,169 @@
1
+ import { useLocaleConfig } from '@vuepress/helper/client';
2
+ import { useEventListener } from '@vueuse/core';
3
+ import { defineComponent, h, onMounted, shallowRef } from 'vue';
4
+ import { withBase } from 'vuepress/client';
5
+ import { ArrowLeftIcon, ArrowRightIcon, CloseIcon } from './icons.js';
6
+ export const PwaInstallModal = defineComponent({
7
+ name: 'PwaInstallModal',
8
+ props: {
9
+ /** locale data */
10
+ locales: {
11
+ type: Object,
12
+ required: true,
13
+ },
14
+ /**
15
+ * Whether use hint message instead of showing a button
16
+ *
17
+ * 是否使用提示
18
+ */
19
+ useHint: Boolean,
20
+ },
21
+ emits: ['canInstall', 'hint', 'close'],
22
+ setup(props, { emit }) {
23
+ const locale = useLocaleConfig(props.locales);
24
+ const manifest = shallowRef({});
25
+ const deferredPrompt = shallowRef();
26
+ const getManifest = async () => {
27
+ const manifestContent = localStorage.getItem('manifest');
28
+ if (manifestContent)
29
+ manifest.value = JSON.parse(manifestContent);
30
+ else
31
+ try {
32
+ const response = await fetch(withBase('manifest.webmanifest'));
33
+ const data = (await response.json());
34
+ manifest.value = data;
35
+ localStorage.setItem('manifest', JSON.stringify(data));
36
+ }
37
+ catch (err) {
38
+ console.error('[PWA]: Error getting manifest, check that you have a valid web manifest or network connection');
39
+ }
40
+ };
41
+ const scrollToLeft = () => {
42
+ const screenshotsDiv = document.querySelector('.screenshot');
43
+ if (screenshotsDiv)
44
+ screenshotsDiv.scrollBy({
45
+ left: -screenshotsDiv.clientWidth,
46
+ top: 0,
47
+ behavior: 'smooth',
48
+ });
49
+ };
50
+ const scrollToRight = () => {
51
+ const screenshotsDiv = document.querySelector('.screenshot');
52
+ if (screenshotsDiv)
53
+ screenshotsDiv.scrollBy({
54
+ left: screenshotsDiv.clientWidth,
55
+ top: 0,
56
+ behavior: 'smooth',
57
+ });
58
+ };
59
+ const install = async () => {
60
+ if (deferredPrompt.value) {
61
+ deferredPrompt.value.prompt();
62
+ document.dispatchEvent(new CustomEvent('show'));
63
+ const choiceResult = await deferredPrompt.value.userChoice;
64
+ if (choiceResult.outcome === 'accepted') {
65
+ console.info('PWA has been installed');
66
+ emit('close', false);
67
+ emit('canInstall', false);
68
+ }
69
+ else {
70
+ console.info('You choose to not install PWA');
71
+ emit('close', false);
72
+ emit('canInstall', false);
73
+ }
74
+ }
75
+ };
76
+ const hint = () => {
77
+ console.info('You accepted the install hint');
78
+ emit('hint');
79
+ };
80
+ onMounted(() => {
81
+ // eslint-disable-next-line no-prototype-builtins
82
+ if (window.hasOwnProperty('BeforeInstallPromptEvent')) {
83
+ useEventListener(window, 'beforeinstallprompt', (event) => {
84
+ deferredPrompt.value = event;
85
+ emit('canInstall', true);
86
+ event.preventDefault();
87
+ });
88
+ useEventListener('keyup', (event) => {
89
+ if (event.key === 'Escape')
90
+ emit('close', false);
91
+ });
92
+ getManifest();
93
+ }
94
+ });
95
+ return () => h('div', { id: 'install-modal-wrapper' }, [
96
+ h('div', { class: 'background', onClick: () => emit('close', false) }),
97
+ h('div', { class: 'install-modal' }, [
98
+ h('div', { class: 'header' }, [
99
+ // close button
100
+ h('button', {
101
+ 'type': 'button',
102
+ 'class': 'close-button',
103
+ 'aria-label': locale.value.close,
104
+ 'onClick': () => emit('close', false),
105
+ }, h(CloseIcon)),
106
+ h('div', { class: 'logo' }, [
107
+ manifest.value.icons
108
+ ? h('img', {
109
+ src: manifest.value.icons[0]?.src,
110
+ alt: 'App Logo',
111
+ })
112
+ : null,
113
+ h('div', { class: 'title' }, [
114
+ h('h1', manifest.value.short_name || manifest.value.name),
115
+ h('p', { class: 'desc' }, locale.value.explain),
116
+ ]),
117
+ ]),
118
+ ]),
119
+ h('div', { class: 'content' }, [
120
+ h('div', { class: 'highlight' }, [
121
+ manifest.value.features
122
+ ? h('div', { class: 'feature-wrapper' }, [
123
+ h('h3', locale.value.feature),
124
+ h('ul', manifest.value.features.map((feature) => h('li', feature))),
125
+ ])
126
+ : null,
127
+ manifest.value.screenshots
128
+ ? h('div', { class: 'screenshot-wrapper' }, [
129
+ h('button', {
130
+ 'type': 'button',
131
+ 'aria-label': locale.value.prevImage,
132
+ 'onClick': scrollToLeft,
133
+ }, h(ArrowLeftIcon)),
134
+ h('section', { class: 'screenshot' }, [
135
+ manifest.value.screenshots.map((screenshot) => h('div', h('img', {
136
+ src: screenshot.src,
137
+ alt: 'App Screenshot',
138
+ }))),
139
+ ]),
140
+ h('button', {
141
+ 'type': 'button',
142
+ 'aria-label': locale.value.nextImage,
143
+ 'onClick': scrollToRight,
144
+ }, h(ArrowRightIcon)),
145
+ ])
146
+ : null,
147
+ ]),
148
+ h('div', { class: 'description' }, [
149
+ h('h3', locale.value.desc),
150
+ h('p', manifest.value.description),
151
+ ]),
152
+ ]),
153
+ props.useHint
154
+ ? h('div', { class: 'ios-text', onClick: hint }, [
155
+ h('p', locale.value.iOSInstall),
156
+ h('button', { type: 'button', class: 'success' }, 'Got it!'),
157
+ ])
158
+ : h('div', { class: 'button-wrapper' }, [
159
+ h('button', { type: 'button', class: 'install-button', onClick: install }, [locale.value.install, h('span', manifest.value.short_name)]),
160
+ h('button', {
161
+ type: 'button',
162
+ class: 'cancel-button',
163
+ onClick: () => emit('close', false),
164
+ }, locale.value.cancel),
165
+ ]),
166
+ ]),
167
+ ]);
168
+ },
169
+ });
@@ -0,0 +1,21 @@
1
+ import type { PropType, SlotsType, VNode } from 'vue';
2
+ import type { PwaPluginLocaleConfig } from '../../shared/index.js';
3
+ import '../styles/popup.css';
4
+ export declare const PwaReadyPopup: import("vue").DefineComponent<{
5
+ /** locale data */
6
+ locales: {
7
+ type: PropType<PwaPluginLocaleConfig>;
8
+ required: true;
9
+ };
10
+ }, () => VNode, unknown, {}, {}, import("vue").ComponentOptionsMixin, import("vue").ComponentOptionsMixin, {}, string, import("vue").PublicProps, Readonly<import("vue").ExtractPropTypes<{
11
+ /** locale data */
12
+ locales: {
13
+ type: PropType<PwaPluginLocaleConfig>;
14
+ required: true;
15
+ };
16
+ }>>, {}, SlotsType<{
17
+ default?: ((props: {
18
+ isReady: boolean;
19
+ reload: () => void;
20
+ }) => VNode[] | VNode | null) | undefined;
21
+ }>>;
@@ -0,0 +1,50 @@
1
+ import { useLocaleConfig } from '@vuepress/helper/client';
2
+ import { computed, defineComponent, h, onMounted, shallowRef, Transition, } from 'vue';
3
+ import { usePwaEvent } from '../composables/index.js';
4
+ import { skipWaiting } from '../utils/index.js';
5
+ import { UpdateIcon } from './icons.js';
6
+ import '../styles/popup.css';
7
+ export const PwaReadyPopup = defineComponent({
8
+ name: 'PwaReadyPopup',
9
+ props: {
10
+ /** locale data */
11
+ locales: {
12
+ type: Object,
13
+ required: true,
14
+ },
15
+ },
16
+ slots: Object,
17
+ setup(props, { slots }) {
18
+ const locale = useLocaleConfig(props.locales);
19
+ const registration = shallowRef();
20
+ const isReady = computed(() => Boolean(registration.value));
21
+ const reload = () => {
22
+ if (registration.value) {
23
+ skipWaiting(registration.value);
24
+ registration.value = undefined;
25
+ }
26
+ };
27
+ onMounted(() => {
28
+ const event = usePwaEvent();
29
+ event.on('updated', (reg) => {
30
+ if (reg)
31
+ registration.value = reg;
32
+ });
33
+ });
34
+ return () => h(Transition, { name: 'popup' }, () => slots.default?.({
35
+ isReady: isReady.value,
36
+ reload,
37
+ }) ||
38
+ (isReady.value
39
+ ? h('button', {
40
+ type: 'button',
41
+ class: 'sw-update-popup',
42
+ tabindex: 0,
43
+ onClick: () => reload(),
44
+ }, [
45
+ locale.value.update,
46
+ h('span', { class: 'icon-wrapper' }, h(UpdateIcon)),
47
+ ])
48
+ : null));
49
+ },
50
+ });
@@ -0,0 +1,9 @@
1
+ import type { FunctionalComponent } from 'vue';
2
+ export interface SVGWrapperProps {
3
+ name?: string;
4
+ color?: string;
5
+ }
6
+ export declare const ArrowLeftIcon: FunctionalComponent;
7
+ export declare const ArrowRightIcon: FunctionalComponent;
8
+ export declare const CloseIcon: FunctionalComponent;
9
+ export declare const UpdateIcon: FunctionalComponent;
@@ -0,0 +1,25 @@
1
+ import { h } from 'vue';
2
+ const SVGWrapper = ({ name = '', color = 'currentColor' }, { slots }) => h('svg', {
3
+ 'xmlns': 'http://www.w3.org/2000/svg',
4
+ 'class': ['icon', `${name}-icon`],
5
+ 'viewBox': '0 0 1024 1024',
6
+ 'fill': color,
7
+ 'aria-label': `${name} icon`,
8
+ }, slots.default?.());
9
+ SVGWrapper.displayName = 'SVGWrapper';
10
+ export const ArrowLeftIcon = () => h(SVGWrapper, { name: 'arrow-left' }, () => h('path', {
11
+ d: 'M802.8 448h-428l166-158.8c23.8-25 23.8-65.4 0-90.4s-62.4-25-86.4 0L178 466.8c-12 11.6-18 27.4-18 44.8v0.8c0 17.4 6 33.2 18 44.8l276.2 268c24 25 62.6 25 86.4 0 23.8-25 23.8-65.4 0-90.4l-166-158.8h428c33.8 0 61.2-28.6 61.2-64 0.2-36-27.2-64-61-64z',
12
+ }));
13
+ ArrowLeftIcon.displayName = 'ArrowLeftIcon';
14
+ export const ArrowRightIcon = () => h(SVGWrapper, { name: 'arrow-right' }, () => h('path', {
15
+ d: 'M569.8 825.2l276.2-268c12-11.6 18-27.4 18-44.8v-0.8c0-17.4-6-33.2-18-44.8l-276.2-268c-24-25-62.6-25-86.4 0-23.8 25-23.8 65.4 0 90.4l166 158.8h-428c-34 0-61.4 28.6-61.4 64 0 36 27.4 64 61.2 64h428l-166 158.8c-23.8 25-23.8 65.4 0 90.4 24 25 62.6 25 86.6 0z',
16
+ }));
17
+ ArrowRightIcon.displayName = 'ArrowRightIcon';
18
+ export const CloseIcon = () => h(SVGWrapper, { name: 'close' }, () => h('path', {
19
+ d: 'M589.654 511.965 1007.212 84.22a49.777 49.777 0 0 0-.73-70.02 49.046 49.046 0 0 0-69.687.665L519.967 441.946 85.882 14.2a49.08 49.08 0 0 0-69.687.664 49.777 49.777 0 0 0 .664 70.019l433.454 427.082L16.859 939.048a49.777 49.777 0 0 0-.664 70.019 49.013 49.013 0 0 0 69.687.663l434.085-427.746 416.828 427.083A49.013 49.013 0 0 0 972.037 1024a48.416 48.416 0 0 0 34.512-14.27 49.777 49.777 0 0 0 .73-70.019z',
20
+ }));
21
+ CloseIcon.displayName = 'CloseIcon';
22
+ export const UpdateIcon = () => h(SVGWrapper, { name: 'update' }, () => h('path', {
23
+ d: 'M949.949 146.25v255.826c0 21.981-13.989 35.97-35.97 35.97H658.154c-13.988 0-25.983-7.992-33.973-21.981-5.997-13.989-4-27.977 7.991-39.97l79.942-77.946c-55.954-51.973-121.918-77.955-199.863-77.955-37.975 0-75.95 8.002-113.924 21.99-37.975 15.985-67.948 37.976-91.934 63.957-25.982 23.987-47.973 53.96-63.957 91.934-29.983 73.955-29.983 153.895 0 227.85 15.984 37.976 37.975 67.947 63.957 91.934 23.986 25.982 53.959 47.973 91.934 63.956 37.974 13.989 75.95 21.991 113.924 21.991 45.967 0 87.942-9.998 127.913-29.982 41.976-17.99 75.951-45.967 101.931-83.943 7.993-4 11.994-5.995 13.989-5.995 5.997 0 9.998 1.994 13.988 5.995l77.958 77.946c3.989 4 5.986 7.993 5.986 11.994 0 1.994-1.996 5.995-3.99 11.994-43.973 51.962-93.941 91.934-151.9 117.914-53.958 25.983-115.92 39.972-185.874 39.972-61.961 0-119.921-11.984-169.89-33.973-57.96-25.985-105.923-57.963-139.896-93.943-35.98-33.972-67.958-81.936-93.94-139.897-45.967-101.93-45.967-237.846 0-339.777 25.982-57.96 57.96-105.923 93.94-139.896 33.973-35.98 81.936-67.958 139.896-93.94 49.968-21.99 107.928-33.974 169.89-33.974 55.963 0 109.923 9.988 161.885 29.973 53.97 21.99 101.933 51.963 139.908 89.938l73.954-73.944c9.987-9.998 23.987-13.988 39.971-8.002 13.988 8.002 21.98 19.995 21.98 33.984z',
24
+ }));
25
+ UpdateIcon.displayName = 'UpdateIcon';
@@ -0,0 +1,3 @@
1
+ export * from './PwaInstall.js';
2
+ export * from './PwaFoundPopup.js';
3
+ export * from './PwaReadyPopup.js';
@@ -0,0 +1,3 @@
1
+ export * from './PwaInstall.js';
2
+ export * from './PwaFoundPopup.js';
3
+ export * from './PwaReadyPopup.js';
@@ -1,2 +1,4 @@
1
+ export * from './setupPwa.js';
2
+ export * from './setupViewPoint.js';
1
3
  export * from './usePwaEvent.js';
2
- export * from './useSkipWaiting.js';
4
+ export * from './useRegisterSW.js';
@@ -1,2 +1,4 @@
1
+ export * from './setupPwa.js';
2
+ export * from './setupViewPoint.js';
1
3
  export * from './usePwaEvent.js';
2
- export * from './useSkipWaiting.js';
4
+ export * from './useRegisterSW.js';
@@ -0,0 +1 @@
1
+ export declare const setupPwa: (serviceWorkerPath: string, shouldForceUpdate?: boolean) => void;
@@ -0,0 +1,28 @@
1
+ import mitt from 'mitt';
2
+ import { onMounted, provide } from 'vue';
3
+ import { forceUpdate } from '../utils/index.js';
4
+ import { pwaEventSymbol } from './usePwaEvent.js';
5
+ import { useRegisterSW } from './useRegisterSW.js';
6
+ export const setupPwa = (serviceWorkerPath, shouldForceUpdate = false) => {
7
+ if (__VUEPRESS_SSR__)
8
+ return;
9
+ // Create event emitter and provide it
10
+ const event = mitt();
11
+ provide(pwaEventSymbol, event);
12
+ onMounted(async () => {
13
+ if (__VUEPRESS_DEV__)
14
+ return;
15
+ let refreshing = false;
16
+ // Only listen controllerchange event when a serviceWorker is active
17
+ if (navigator.serviceWorker?.controller)
18
+ navigator.serviceWorker.addEventListener('controllerchange', () => {
19
+ if (refreshing)
20
+ return;
21
+ refreshing = true;
22
+ window.location.reload();
23
+ });
24
+ if (shouldForceUpdate)
25
+ forceUpdate();
26
+ await useRegisterSW(serviceWorkerPath, event);
27
+ });
28
+ };
@@ -0,0 +1 @@
1
+ export declare const setupViewPoint: () => void;
@@ -0,0 +1,18 @@
1
+ import { onMounted } from 'vue';
2
+ export const setupViewPoint = () => {
3
+ onMounted(() => {
4
+ const isStandAlone = window.matchMedia('(display-mode: standalone)').matches;
5
+ if (isStandAlone) {
6
+ const head = document.head.querySelector('meta[name="viewport"]');
7
+ if (head) {
8
+ head.setAttribute('content', 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover');
9
+ return;
10
+ }
11
+ const viewportMeta = document.createElement('meta');
12
+ viewportMeta.name = 'viewport';
13
+ viewportMeta.content =
14
+ 'width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover';
15
+ document.head.appendChild(viewportMeta);
16
+ }
17
+ });
18
+ };
@@ -1,9 +1,8 @@
1
1
  import { inject } from 'vue';
2
- export const pwaEventSymbol = Symbol('pwaEvent');
2
+ export const pwaEventSymbol = Symbol(__VUEPRESS_DEV__ ? 'PwaEvent' : '');
3
3
  export const usePwaEvent = () => {
4
4
  const pwaEvent = inject(pwaEventSymbol);
5
- if (!pwaEvent) {
5
+ if (!pwaEvent)
6
6
  throw new Error('usePwaEvent() is called without provider.');
7
- }
8
7
  return pwaEvent;
9
8
  };
@@ -0,0 +1,2 @@
1
+ import type { PwaEvent } from './usePwaEvent.js';
2
+ export declare const useRegisterSW: (serviceWorkerPath: string, event: PwaEvent) => Promise<void>;
@@ -0,0 +1,29 @@
1
+ import { withBase } from 'vuepress/client';
2
+ import { registerSW } from '../utils/index.js';
3
+ export const useRegisterSW = async (serviceWorkerPath, event) => registerSW(withBase(serviceWorkerPath), {
4
+ ready(registration) {
5
+ event.emit('ready', registration);
6
+ },
7
+ registered(registration) {
8
+ event.emit('registered', registration);
9
+ },
10
+ cached(registration) {
11
+ event.emit('cached', registration);
12
+ },
13
+ updatefound(registration) {
14
+ event.emit('updatefound', registration);
15
+ },
16
+ updated(registration) {
17
+ const key = 'service-worker-version';
18
+ const version = Number(localStorage.getItem(key) || 0);
19
+ localStorage.setItem(key, (version + 1).toString());
20
+ localStorage.removeItem('manifest');
21
+ event.emit('updated', registration);
22
+ },
23
+ offline() {
24
+ event.emit('offline');
25
+ },
26
+ error(err) {
27
+ event.emit('error', err);
28
+ },
29
+ });
@@ -1 +1,3 @@
1
+ export * from './components/index.js';
1
2
  export * from './composables/index.js';
3
+ export * from './utils/index.js';
@@ -1 +1,3 @@
1
+ export * from './components/index.js';
1
2
  export * from './composables/index.js';
3
+ export * from './utils/index.js';