├── .editorconfig ├── .eslintrc.js ├── .gitignore ├── .prettierrc ├── BeforeInstallPromptEvent.d.ts ├── README.md ├── demo ├── .gitignore ├── README.md ├── babel.config.js ├── jsconfig.json ├── package.json ├── public │ ├── favicon.ico │ └── index.html ├── src │ ├── App.vue │ ├── assets │ │ └── logo.png │ ├── components │ │ └── HelloWorld.vue │ └── main.js ├── vue.config.js └── yarn.lock ├── dist ├── vue-addtohomescreen.mjs └── vue-addtohomescreen.umd.js ├── package.json ├── src ├── addToHomescreen.vue ├── assets │ ├── addios.svg │ ├── logo.png │ ├── shareios.svg │ └── x.svg ├── i18n │ └── index.ts ├── index.ts ├── shims │ └── vue.d.ts ├── types │ └── index.ts ├── utils.ts └── utils │ └── isStandalone.ts ├── tsconfig.json ├── vite.config.ts └── yarn.lock /.editorconfig: -------------------------------------------------------------------------------- 1 | root = true 2 | 3 | [*] 4 | charset = utf-8 5 | indent_style = space 6 | indent_size = 2 7 | end_of_line = lf 8 | insert_final_newline = true 9 | trim_trailing_whitespace = true 10 | -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | env: { 3 | node: true, 4 | browser: true, 5 | es2021: true, 6 | }, 7 | extends: [ 8 | 'plugin:vue/vue3-essential', 9 | 'eslint:recommended', 10 | 'plugin:@typescript-eslint/eslint-recommended', 11 | 'plugin:@typescript-eslint/recommended', 12 | ], 13 | overrides: [], 14 | parser: 'vue-eslint-parser', 15 | parserOptions: { 16 | parser: '@typescript-eslint/parser', 17 | ecmaVersion: 'latest', 18 | sourceType: 'module', 19 | }, 20 | plugins: ['vue'], 21 | rules: { 22 | quotes: ['warn', 'single', { avoidEscape: true }], 23 | }, 24 | }; 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | pnpm-debug.log* 8 | lerna-debug.log* 9 | 10 | node_modules 11 | *.local 12 | 13 | # Editor directories and files 14 | .vscode/* 15 | !.vscode/extensions.json 16 | .idea 17 | .DS_Store 18 | *.suo 19 | *.ntvs* 20 | *.njsproj 21 | *.sln 22 | *.sw? 23 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true, 3 | "semi": true 4 | } 5 | -------------------------------------------------------------------------------- /BeforeInstallPromptEvent.d.ts: -------------------------------------------------------------------------------- 1 | interface BeforeInstallPromptEvent extends Event { 2 | readonly platforms: string[]; 3 | readonly userChoice: Promise<{ 4 | outcome: 'accepted' | 'dismissed'; 5 | platform: string; 6 | }>; 7 | prompt(): Promise; 8 | } 9 | 10 | declare global { 11 | interface WindowEventMap { 12 | beforeinstallprompt: BeforeInstallPromptEvent; 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # vue-addtohomescreen 2 | 3 | Vue-addtohomescreen is a plugin allowing you to trigger a box asking the user if he wants to install the PWA version of your website at the place you want. 4 | 5 | You can for example display it after a connection process or when reading an article. 6 | 7 | **Only for Vue 3 ! For Vue 2, check @owliehq/vue-addtohomescreen@legacy** 8 | 9 | ## Installation 10 | 11 | Install it with npm 12 | 13 | ```bash 14 | npm install @owliehq/vue-addtohomescreen 15 | ``` 16 | 17 | Or Yarn 18 | 19 | ```bash 20 | yarn add @owliehq/vue-addtohomescreen 21 | ``` 22 | 23 | ## Usage 24 | 25 | ### Vue 3 - Usage as plugin 26 | 27 | You'll need to initialize the plugin and ask you app instance to use it, you can pass parameters for customization: 28 | 29 | ```javascript 30 | import App from './App.vue'; 31 | import { createApp } from 'vue'; 32 | import AddToHomescreen from '@owliehq/vue-addtohomescreen'; 33 | 34 | const app = createApp(App); 35 | app.use(AddToHomescreen, { 36 | buttonColor: 'blue', 37 | }); 38 | 39 | app.mount('#app'); 40 | ``` 41 | 42 | ### Vue 3 - Usage inside your app 43 | 44 | Import useAddToHomescreen 45 | 46 | ```javascript 47 | import { useAddToHomescreen } from '@owliehq/vue-addtohomescreen'; 48 | ``` 49 | 50 | And use it (for example here directly in the setup hook), you can pass parameters for customization: 51 | 52 | ```javascript 53 | export default { 54 | name: 'App', 55 | setup() { 56 | useAddToHomescreen({ buttonColor: 'red' }); 57 | }, 58 | }; 59 | ``` 60 | 61 | ## Parameters list 62 | 63 | ```javascript 64 | title: { 65 | type: String, 66 | default: '' 67 | }, 68 | content: { 69 | type: String, 70 | }, 71 | titleColor: { 72 | type: String, 73 | default: '#000' 74 | }, 75 | contentColor: { 76 | type: String, 77 | default: '#000' 78 | }, 79 | iconPath: { 80 | type: String, 81 | default: '' 82 | }, 83 | iconColor: { 84 | type: String, 85 | default: '#000' 86 | }, 87 | iconTextColor: { 88 | type: String, 89 | default: '#fff' 90 | }, 91 | buttonColor: { 92 | type: String, 93 | default: '#000' 94 | }, 95 | buttonTextColor: { 96 | type: String, 97 | default: '#fff' 98 | }, 99 | background: { 100 | type: String, 101 | default: '#fff' 102 | }, 103 | lang: { 104 | type: String, 105 | default: 'en_GB' // See Available lang 106 | }, 107 | expires: { 108 | type: Number, 109 | default: 8 110 | } 111 | 112 | ``` 113 | 114 | ## Available languages 115 | 116 | en_GB: English\ 117 | fr_FR: French\ 118 | ru_RU: Russian\ 119 | de_DE: German\ 120 | es_ES: Spanish\ 121 | pt_PT: Portuguese\ 122 | nl_NL: Dutch\ 123 | pl_PL: Polish\ 124 | ja_JP: Japanese\ 125 | zh_CN: Chinese\ 126 | id_ID: Indonesian 127 | 128 | ## Credits 129 | 130 | Made with <3 in Metz, a small town in France by Owlie. 131 | 132 | Feel free to patch / edit / optimize / add features. MR are Welcome. 133 | -------------------------------------------------------------------------------- /demo/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules 3 | /dist 4 | 5 | 6 | # local env files 7 | .env.local 8 | .env.*.local 9 | 10 | # Log files 11 | npm-debug.log* 12 | yarn-debug.log* 13 | yarn-error.log* 14 | pnpm-debug.log* 15 | 16 | # Editor directories and files 17 | .idea 18 | .vscode 19 | *.suo 20 | *.ntvs* 21 | *.njsproj 22 | *.sln 23 | *.sw? 24 | -------------------------------------------------------------------------------- /demo/README.md: -------------------------------------------------------------------------------- 1 | # vue3 2 | 3 | ## Project setup 4 | ``` 5 | yarn install 6 | ``` 7 | 8 | ### Compiles and hot-reloads for development 9 | ``` 10 | yarn serve 11 | ``` 12 | 13 | ### Compiles and minifies for production 14 | ``` 15 | yarn build 16 | ``` 17 | 18 | ### Lints and fixes files 19 | ``` 20 | yarn lint 21 | ``` 22 | 23 | ### Customize configuration 24 | See [Configuration Reference](https://cli.vuejs.org/config/). 25 | -------------------------------------------------------------------------------- /demo/babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/cli-plugin-babel/preset' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /demo/jsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "esnext", 5 | "baseUrl": "./", 6 | "moduleResolution": "node", 7 | "paths": { 8 | "@/*": [ 9 | "src/*" 10 | ] 11 | }, 12 | "lib": [ 13 | "esnext", 14 | "dom", 15 | "dom.iterable", 16 | "scripthost" 17 | ] 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /demo/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue3", 3 | "version": "0.1.0", 4 | "private": true, 5 | "scripts": { 6 | "serve": "vue-cli-service serve", 7 | "build": "vue-cli-service build", 8 | "lint": "vue-cli-service lint" 9 | }, 10 | "dependencies": { 11 | "core-js": "^3.8.3", 12 | "vue": "^3.2.13" 13 | }, 14 | "devDependencies": { 15 | "@babel/core": "^7.12.16", 16 | "@babel/eslint-parser": "^7.12.16", 17 | "@vue/cli-plugin-babel": "~5.0.0", 18 | "@vue/cli-plugin-eslint": "~5.0.0", 19 | "@vue/cli-service": "~5.0.0", 20 | "eslint": "^7.32.0", 21 | "eslint-plugin-vue": "^8.0.3" 22 | }, 23 | "eslintConfig": { 24 | "root": true, 25 | "env": { 26 | "node": true 27 | }, 28 | "extends": [ 29 | "plugin:vue/vue3-essential", 30 | "eslint:recommended" 31 | ], 32 | "parserOptions": { 33 | "parser": "@babel/eslint-parser" 34 | }, 35 | "rules": {} 36 | }, 37 | "browserslist": [ 38 | "> 1%", 39 | "last 2 versions", 40 | "not dead", 41 | "not ie 11" 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /demo/public/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owliehq/vue-addtohomescreen/949b5ad2af285c593a51fba4136cc219ae7c94ec/demo/public/favicon.ico -------------------------------------------------------------------------------- /demo/public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <%= htmlWebpackPlugin.options.title %> 9 | 10 | 11 | 14 |
15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /demo/src/App.vue: -------------------------------------------------------------------------------- 1 | 7 | 8 | 23 | 24 | 34 | -------------------------------------------------------------------------------- /demo/src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owliehq/vue-addtohomescreen/949b5ad2af285c593a51fba4136cc219ae7c94ec/demo/src/assets/logo.png -------------------------------------------------------------------------------- /demo/src/components/HelloWorld.vue: -------------------------------------------------------------------------------- 1 | 32 | 33 | 41 | 42 | 43 | 59 | -------------------------------------------------------------------------------- /demo/src/main.js: -------------------------------------------------------------------------------- 1 | import App from './App.vue'; 2 | import { createApp } from 'vue'; 3 | import AddToHomescreen from '../../dist/vue-addtohomescreen.mjs'; 4 | 5 | const app = createApp(App); 6 | app.use(AddToHomescreen, { 7 | buttonColor: 'blue', 8 | }); 9 | app.mount('#app'); 10 | -------------------------------------------------------------------------------- /demo/vue.config.js: -------------------------------------------------------------------------------- 1 | const { defineConfig } = require('@vue/cli-service') 2 | module.exports = defineConfig({ 3 | transpileDependencies: true 4 | }) 5 | -------------------------------------------------------------------------------- /dist/vue-addtohomescreen.mjs: -------------------------------------------------------------------------------- 1 | (function(){"use strict";try{if(typeof document!="undefined"){var e=document.createElement("style");e.appendChild(document.createTextNode(".add-to-homescreen-plugin-container .add-to-homescreen-container{z-index:10000;border-top:1px solid #e0e0e0;font-family:-apple-system,BlinkMacSystemFont,Roboto,sans-serif;width:100%;box-sizing:border-box;background:white;position:fixed;bottom:0;left:0;padding:16px;align-items:center;transition:all .5s}.add-to-homescreen-plugin-container .add-to-homescreen-container.add-to-homescreen-visible{transform:translateY(0)}.add-to-homescreen-plugin-container .add-to-homescreen-container.add-to-homescreen-hidden{transform:translateY(100%)}.add-to-homescreen-plugin-container button{cursor:pointer}.add-to-homescreen-plugin-container .close_btn{cursor:pointer;position:absolute;top:15px;right:15px;width:20px;height:20px;border:0;background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXIteCI+PGxpbmUgeDE9IjE4IiB5MT0iNiIgeDI9IjYiIHkyPSIxOCI+PC9saW5lPjxsaW5lIHgxPSI2IiB5MT0iNiIgeDI9IjE4IiB5Mj0iMTgiPjwvbGluZT48L3N2Zz4=)}.add-to-homescreen-plugin-container .flex{display:flex;flex-wrap:wrap}.add-to-homescreen-plugin-container .col{flex:1}.add-to-homescreen-plugin-container .icon{background-size:contain;background-repeat:no-repeat;background-position:center}.add-to-homescreen-plugin-container .icon-container .icon{width:60px;height:60px;display:block;line-height:60px;text-align:center;border-radius:30px;font-size:1.3rem;margin-right:15px;text-transform:uppercase}.add-to-homescreen-plugin-container .app-title{font-size:1.3rem;display:inline-block}.add-to-homescreen-plugin-container .app-content{font-size:.8rem;display:inline-block}.add-to-homescreen-plugin-container .btn-container{float:right}.add-to-homescreen-plugin-container .add-button,.add-to-homescreen-plugin-container .add-button:hover,.add-to-homescreen-plugin-container .add-button:visited{width:100%;border:0;outline:0;font-size:1rem;padding:5px}.add-to-homescreen-plugin-container .close:hover,.add-to-homescreen-plugin-container .close:focus{color:#000;text-decoration:none;cursor:pointer}.add-to-homescreen-plugin-container .modal{display:none;position:fixed;z-index:10000;left:0;top:0;width:100%;height:100%;background-color:#0006}.add-to-homescreen-plugin-container .modal-content{background-color:#fff;border-radius:1rem;text-align:center;margin:50% auto;border:1px solid #27e9b8;width:80%}.add-to-homescreen-plugin-container .modal-content ul{padding:0 0 0 15px;text-align:left;list-style-type:none}.add-to-homescreen-plugin-container .shareIOS,.add-to-homescreen-plugin-container .addIOS{width:20px;vertical-align:top}.add-to-homescreen-plugin-container .modal-content .closeModal{border:0;outline:0;font-size:1rem;padding:5px;margin-bottom:15px}")),document.head.appendChild(e)}}catch(n){console.error("vite-plugin-css-injected-by-js",n)}})(); 2 | import { defineComponent as Ce, ref as ke, computed as P, onMounted as xe, openBlock as Me, createElementBlock as ze, createElementVNode as M, normalizeClass as Le, normalizeStyle as R, Fragment as Ie, createTextVNode as te, toDisplayString as U, createCommentVNode as De, h as Oe, render as Ae } from "vue"; 3 | /*! js-cookie v3.0.1 | MIT */ 4 | function Y(n) { 5 | for (var b = 1; b < arguments.length; b++) { 6 | var h = arguments[b]; 7 | for (var m in h) 8 | n[m] = h[m]; 9 | } 10 | return n; 11 | } 12 | var Ee = { 13 | read: function(n) { 14 | return n[0] === '"' && (n = n.slice(1, -1)), n.replace(/(%[\dA-F]{2})+/gi, decodeURIComponent); 15 | }, 16 | write: function(n) { 17 | return encodeURIComponent(n).replace( 18 | /%(2[346BF]|3[AC-F]|40|5[BDE]|60|7[BCD])/g, 19 | decodeURIComponent 20 | ); 21 | } 22 | }; 23 | function se(n, b) { 24 | function h(v, y, w) { 25 | if (!(typeof document > "u")) { 26 | w = Y({}, b, w), typeof w.expires == "number" && (w.expires = new Date(Date.now() + w.expires * 864e5)), w.expires && (w.expires = w.expires.toUTCString()), v = encodeURIComponent(v).replace(/%(2[346B]|5E|60|7C)/g, decodeURIComponent).replace(/[()]/g, escape); 27 | var z = ""; 28 | for (var j in w) 29 | w[j] && (z += "; " + j, w[j] !== !0 && (z += "=" + w[j].split(";")[0])); 30 | return document.cookie = v + "=" + n.write(y, v) + z; 31 | } 32 | } 33 | function m(v) { 34 | if (!(typeof document > "u" || arguments.length && !v)) { 35 | for (var y = document.cookie ? document.cookie.split("; ") : [], w = {}, z = 0; z < y.length; z++) { 36 | var j = y[z].split("="), x = j.slice(1).join("="); 37 | try { 38 | var N = decodeURIComponent(j[0]); 39 | if (w[N] = n.read(x, N), v === N) 40 | break; 41 | } catch { 42 | } 43 | } 44 | return v ? w[v] : w; 45 | } 46 | } 47 | return Object.create( 48 | { 49 | set: h, 50 | get: m, 51 | remove: function(v, y) { 52 | h( 53 | v, 54 | "", 55 | Y({}, y, { 56 | expires: -1 57 | }) 58 | ); 59 | }, 60 | withAttributes: function(v) { 61 | return se(this.converter, Y({}, this.attributes, v)); 62 | }, 63 | withConverter: function(v) { 64 | return se(Y({}, this.converter, v), this.attributes); 65 | } 66 | }, 67 | { 68 | attributes: { value: Object.freeze(b) }, 69 | converter: { value: Object.freeze(n) } 70 | } 71 | ); 72 | } 73 | var de = se(Ee, { path: "/" }); 74 | const _e = { 75 | en_GB: { 76 | addToHomescreen: "Add to homescreen", 77 | addMessages: { 78 | ios1: "1. On Safari browser, open Share menu", 79 | ios2: '2. Tap on "Add to Home Screen" button', 80 | android: `1. Open browser parameters 81 | 2. Tap on "Add to homescreen"`, 82 | windows: { 83 | chrome: "Click on (+) button to the right of your navigation bar.", 84 | firefox: `1. Resize your browser so you can see your desktop 85 | 2. Drag and drop the (i) button left of your navigation bar to your desktop` 86 | }, 87 | macos: { 88 | chrome: "Click on (+) button to the right of your navigation bar.", 89 | safari: `1. Resize your browser so you can see your desktop 90 | 2. Drag & drop the earth icon left of your notification bar to your desktop`, 91 | firefox: `1. Resize your browser so you can see your desktop 92 | 2. Drag and drop the (i) button left of your navigation bar to your desktop` 93 | }, 94 | others: "Looks like your browser doesn't support add to homescreen natively. Feel free to update/change your browser." 95 | } 96 | }, 97 | fr_FR: { 98 | addToHomescreen: "Installer l'application", 99 | addMessages: { 100 | ios1: "1. Sur le navigateur Safari, ouvrir le menu de partage", 101 | ios2: `2. Appuyez sur le bouton "Sur l'écran d'accueil"`, 102 | android: `1. Ouvrez les paramètres de la page 103 | 2. Appuyez sur le bouton "Ajouter à l'écran d'accueil"`, 104 | windows: { 105 | chrome: "Cliquez sur le bouton (+) présent à droite dans votre barre de navigation", 106 | firefox: `1. Redimensionnez votre navigateur pour voir votre bureau 107 | 2. Cliquez & glissez l'icône (i) présent à gauche de votre barre de navigation sur votre bureau` 108 | }, 109 | macos: { 110 | chrome: "Cliquez sur le bouton (+) présent à droite dans votre barre de navigation", 111 | safari: `1. Redimensionnez votre navigateur pour voir votre bureau 112 | 2. Cliquez & glissez l'icône 'terre' présent à gauche de votre barre de navigation sur votre bureau`, 113 | firefox: `1. Redimensionnez votre navigateur pour voir votre bureau 114 | 2. Cliquez & glissez l'icône (i) présent à gauche de votre barre de navigation sur votre bureau` 115 | }, 116 | others: "Il semblerait que votre navigateur ne supporte pas la fonctionnalité d'ajout à la page d'accueil. Mettez-le à jour ou changez de navigateur." 117 | } 118 | }, 119 | ru_RU: { 120 | addToHomescreen: "Добавить на рабочий стол", 121 | addMessages: { 122 | ios1: "1. Откройте меню «Поделиться»", 123 | ios2: "2. Нажмите на кнопку «Добавить на главный экран»", 124 | android: `1. Откройте параметры браузера. 125 | 2. Нажмите «Добавить на рабочий стол»`, 126 | windows: { 127 | chrome: "Нажмите кнопку (+) справа от панели навигации.", 128 | firefox: `1. Измените размер браузера, чтобы Вы могли видеть свой рабочий стол 129 | 2. Перетащите кнопку (i) слева от панели навигации на рабочий стол.` 130 | }, 131 | macos: { 132 | chrome: "Нажмите кнопку (+) справа от панели навигации", 133 | safari: `1. Измените размер браузера, чтобы Вы могли видеть свой рабочий стол 134 | 2. Перетащите значок "Земля" слева от панели уведомлений на рабочий стол`, 135 | firefox: `1. Измените размер браузера, чтобы Вы могли видеть свой рабочий стол 136 | 2. Перетащите кнопку (i) слева от панели навигации на рабочий стол.` 137 | }, 138 | others: "Похоже, Ваш браузер изначально не поддерживает добавление на рабочий стол. Попробуйте обновить/изменить свой браузер." 139 | } 140 | }, 141 | de_DE: { 142 | addToHomescreen: "Zum Startbildschirm hinzufügen", 143 | addMessages: { 144 | ios1: "1. Öffnen Sie im Safari-Browser das Teilen-Menü", 145 | ios2: '2. Tippen Sie auf die Schaltfläche "Zum Startbildschirm hinzufügen"', 146 | android: `1. Öffnen Sie die Browsereinstellungen 147 | 2. Tippen Sie auf "Zum Startbildschirm hinzufügen"`, 148 | windows: { 149 | chrome: "Klicken Sie auf die (+) Schaltfläche rechts neben Ihrer Navigationsleiste.", 150 | firefox: `1. Ändern Sie die Größe Ihres Browsers, sodass Sie Ihren Desktop sehen können 151 | 2. Ziehen Sie die (i)-Schaltfläche links von der Navigationsleiste auf Ihren Desktop` 152 | }, 153 | macos: { 154 | chrome: "Klicken Sie auf die (+) Schaltfläche rechts neben Ihrer Navigationsleiste.", 155 | safari: `1. Ändern Sie die Größe Ihres Browsers, sodass Sie Ihren Desktop sehen können 156 | 2. Ziehen Sie das Erdensymbol links neben Ihrer Benachrichtigungsleiste auf Ihren Desktop`, 157 | firefox: `1. Ändern Sie die Größe Ihres Browsers, sodass Sie Ihren Desktop sehen können 158 | 2. Ziehen Sie die (i)-Schaltfläche links von der Navigationsleiste auf Ihren Desktop` 159 | }, 160 | others: "Es scheint, dass Ihr Browser das Hinzufügen zum Startbildschirm nicht nativ unterstützt. Fühlen Sie sich frei, Ihren Browser zu aktualisieren/zu wechseln." 161 | } 162 | }, 163 | es_ES: { 164 | addToHomescreen: "Añadir a la pantalla de inicio", 165 | addMessages: { 166 | ios1: "1. En el navegador Safari, abre el menú Compartir", 167 | ios2: '2. Toca el botón "Añadir a la pantalla de inicio"', 168 | android: `1. Abre los ajustes del navegador 169 | 2. Toca en "Añadir a la pantalla de inicio"`, 170 | windows: { 171 | chrome: "Haz clic en el botón (+) a la derecha de tu barra de navegación.", 172 | firefox: `1. Redimensiona tu navegador para que puedas ver tu escritorio 173 | 2. Arrastra y suelta el botón (i) a la izquierda de tu barra de navegación a tu escritorio` 174 | }, 175 | macos: { 176 | chrome: "Haz clic en el botón (+) a la derecha de tu barra de navegación.", 177 | safari: `1. Redimensiona tu navegador para que puedas ver tu escritorio 178 | 2. Arrastra y suelta el icono de la Tierra a la izquierda de tu barra de notificaciones a tu escritorio`, 179 | firefox: `1. Redimensiona tu navegador para que puedas ver tu escritorio 180 | 2. Arrastra y suelta el botón (i) a la izquierda de tu barra de navegación a tu escritorio` 181 | }, 182 | others: "Parece que tu navegador no admite la función de añadir a la pantalla de inicio de forma nativa. Siéntete libre de actualizar o cambiar tu navegador." 183 | } 184 | }, 185 | pt_PT: { 186 | addToHomescreen: "Adicionar à tela inicial", 187 | addMessages: { 188 | ios1: "1. No navegador Safari, abra o menu Compartilhar", 189 | ios2: '2. Toque no botão "Adicionar à tela inicial"', 190 | android: `1. Abra as configurações do navegador 191 | 2. Toque em "Adicionar à tela inicial"`, 192 | windows: { 193 | chrome: "Clique no botão (+) à direita da barra de navegação.", 194 | firefox: `1. Redimensione o navegador para visualizar a área de trabalho 195 | 2. Arraste e solte o botão (i) à esquerda da barra de navegação para a área de trabalho` 196 | }, 197 | macos: { 198 | chrome: "Clique no botão (+) à direita da barra de navegação.", 199 | safari: `1. Redimensione o navegador para visualizar a área de trabalho 200 | 2. Arraste e solte o ícone da Terra à esquerda da barra de notificações para a área de trabalho`, 201 | firefox: `1. Redimensione o navegador para visualizar a área de trabalho 202 | 2. Arraste e solte o botão (i) à esquerda da barra de navegação para a área de trabalho` 203 | }, 204 | others: "Parece que seu navegador não suporta adicionar à tela inicial de forma nativa. Sinta-se à vontade para atualizar ou alterar o navegador." 205 | } 206 | }, 207 | nl_NL: { 208 | addToHomescreen: "Toevoegen aan startscherm", 209 | addMessages: { 210 | ios1: "1. Open in de Safari-browser het deelmenu", 211 | ios2: '2. Tik op de knop "Aan startscherm toevoegen"', 212 | android: `1. Open browserinstellingen 213 | 2. Tik op "Toevoegen aan startscherm"`, 214 | windows: { 215 | chrome: "Klik op de (+) knop rechts van uw navigatiebalk.", 216 | firefox: `1. Verander het formaat van uw browser zodat u uw bureaublad kunt zien 217 | 2. Sleep het (i)-pictogram links van uw navigatiebalk naar uw bureaublad` 218 | }, 219 | macos: { 220 | chrome: "Klik op de (+) knop rechts van uw navigatiebalk.", 221 | safari: `1. Verander het formaat van uw browser zodat u uw bureaublad kunt zien 222 | 2. Sleep het aarde-icoon links van uw notificatiebalk naar uw bureaublad`, 223 | firefox: `1. Verander het formaat van uw browser zodat u uw bureaublad kunt zien 224 | 2. Sleep het (i)-pictogram links van uw navigatiebalk naar uw bureaublad` 225 | }, 226 | others: 'Het lijkt erop dat uw browser niet native de functie "Toevoegen aan startscherm" ondersteunt. Voel je vrij om je browser bij te werken of te veranderen.' 227 | } 228 | }, 229 | pl_PL: { 230 | addToHomescreen: "Dodaj do ekranu głównego", 231 | addMessages: { 232 | ios1: "1. W przeglądarce Safari otwórz menu Udostępnij", 233 | ios2: '2. Stuknij przycisk "Dodaj do ekranu głównego"', 234 | android: `1. Otwórz ustawienia przeglądarki 235 | 2. Stuknij "Dodaj do ekranu głównego"`, 236 | windows: { 237 | chrome: "Kliknij przycisk (+) po prawej stronie paska nawigacji.", 238 | firefox: `1. Zmień rozmiar przeglądarki, aby zobaczyć pulpit 239 | 2. Przeciągnij i upuść przycisk (i) po lewej stronie paska nawigacji na pulpit` 240 | }, 241 | macos: { 242 | chrome: "Kliknij przycisk (+) po prawej stronie paska nawigacji.", 243 | safari: `1. Zmień rozmiar przeglądarki, aby zobaczyć pulpit 244 | 2. Przeciągnij i upuść ikonę ziemi po lewej stronie paska powiadomień na pulpit`, 245 | firefox: `1. Zmień rozmiar przeglądarki, aby zobaczyć pulpit 246 | 2. Przeciągnij i upuść przycisk (i) po lewej stronie paska nawigacji na pulpit` 247 | }, 248 | others: "Wygląda na to, że Twoja przeglądarka nie obsługuje natywnie dodawania do ekranu głównego. Śmiało zaktualizuj lub zmień przeglądarkę." 249 | } 250 | }, 251 | ja_JP: { 252 | addToHomescreen: "ホーム画面に追加", 253 | addMessages: { 254 | ios1: "1. Safariブラウザで共有メニューを開く", 255 | ios2: '2. "ホーム画面に追加"ボタンをタップする', 256 | android: `1. ブラウザの設定を開く 257 | 2. "ホーム画面に追加"をタップする`, 258 | windows: { 259 | chrome: "ナビゲーションバーの右側にある (+) ボタンをクリックします。", 260 | firefox: `1. デスクトップが見えるようにブラウザのサイズを変更する 261 | 2. ナビゲーションバーの左側にある (i) ボタンをデスクトップにドラッグ&ドロップする` 262 | }, 263 | macos: { 264 | chrome: "ナビゲーションバーの右側にある (+) ボタンをクリックします。", 265 | safari: `1. デスクトップが見えるようにブラウザのサイズを変更する 266 | 2. 通知バーの左側にある地球のアイコンをデスクトップにドラッグ&ドロップする`, 267 | firefox: `1. デスクトップが見えるようにブラウザのサイズを変更する 268 | 2. ナビゲーションバーの左側にある (i) ボタンをデスクトップにドラッグ&ドロップする` 269 | }, 270 | others: "お使いのブラウザはホーム画面に追加をネイティブにサポートしていないようです。ブラウザを更新/変更してください。" 271 | } 272 | }, 273 | zh_CN: { 274 | addToHomescreen: "添加到主屏幕", 275 | addMessages: { 276 | ios1: "1. 在 Safari 浏览器中打开分享菜单", 277 | ios2: '2. 点击"添加到主屏幕"按钮', 278 | android: `1. 打开浏览器设置 279 | 2. 点击"添加到主屏幕"`, 280 | windows: { 281 | chrome: "点击导航栏右侧的 (+) 按钮。", 282 | firefox: `1. 调整浏览器大小以便看到桌面 283 | 2. 将导航栏左侧的 (i) 按钮拖放到桌面` 284 | }, 285 | macos: { 286 | chrome: "点击导航栏右侧的 (+) 按钮。", 287 | safari: `1. 调整浏览器大小以便看到桌面 288 | 2. 将通知栏左侧的地球图标拖放到桌面`, 289 | firefox: `1. 调整浏览器大小以便看到桌面 290 | 2. 将导航栏左侧的 (i) 按钮拖放到桌面` 291 | }, 292 | others: "看起来您的浏览器不支持原生添加到主屏幕功能。请随时更新/更换浏览器。" 293 | } 294 | } 295 | }, Pe = () => { 296 | const n = ["file:", "cordova:", "capacitor:"]; 297 | return window.matchMedia("(display-mode: standalone)").matches || window.location && window.location.protocol && n.indexOf(window.location.protocol) !== -1; 298 | }; 299 | var Re = typeof globalThis < "u" ? globalThis : typeof window < "u" ? window : typeof global < "u" ? global : typeof self < "u" ? self : {}, K = {}, Ue = { 300 | get exports() { 301 | return K; 302 | }, 303 | set exports(n) { 304 | K = n; 305 | } 306 | }; 307 | (function(n, b) { 308 | (function(h, m) { 309 | var v = "1.0.33", y = "", w = "?", z = "function", j = "undefined", x = "object", N = "string", D = "major", o = "model", a = "name", e = "type", i = "vendor", r = "version", d = "architecture", g = "console", t = "mobile", s = "tablet", S = "smarttv", O = "wearable", le = "embedded", J = 350, X = "Amazon", H = "Apple", ce = "ASUS", ue = "BlackBerry", L = "Browser", q = "Chrome", je = "Edge", B = "Firefox", Z = "Google", be = "Huawei", $ = "LG", ee = "Microsoft", we = "Motorola", V = "Opera", ie = "Samsung", pe = "Sharp", G = "Sony", oe = "Xiaomi", ae = "Zebra", me = "Facebook", Ne = function(l, p) { 310 | var c = {}; 311 | for (var k in l) 312 | p[k] && p[k].length % 2 === 0 ? c[k] = p[k].concat(l[k]) : c[k] = l[k]; 313 | return c; 314 | }, Q = function(l) { 315 | for (var p = {}, c = 0; c < l.length; c++) 316 | p[l[c].toUpperCase()] = l[c]; 317 | return p; 318 | }, ge = function(l, p) { 319 | return typeof l === N ? A(p).indexOf(A(l)) !== -1 : !1; 320 | }, A = function(l) { 321 | return l.toLowerCase(); 322 | }, Se = function(l) { 323 | return typeof l === N ? l.replace(/[^\d\.]/g, y).split(".")[0] : m; 324 | }, re = function(l, p) { 325 | if (typeof l === N) 326 | return l = l.replace(/^\s\s*/, y), typeof p === j ? l : l.substring(0, J); 327 | }, E = function(l, p) { 328 | for (var c = 0, k, u, F, f, _, C; c < p.length && !_; ) { 329 | var ve = p[c], ye = p[c + 1]; 330 | for (k = u = 0; k < ve.length && !_; ) 331 | if (_ = ve[k++].exec(l), _) 332 | for (F = 0; F < ye.length; F++) 333 | C = _[++u], f = ye[F], typeof f === x && f.length > 0 ? f.length === 2 ? typeof f[1] == z ? this[f[0]] = f[1].call(this, C) : this[f[0]] = f[1] : f.length === 3 ? typeof f[1] === z && !(f[1].exec && f[1].test) ? this[f[0]] = C ? f[1].call(this, C, f[2]) : m : this[f[0]] = C ? C.replace(f[1], f[2]) : m : f.length === 4 && (this[f[0]] = C ? f[3].call(this, C.replace(f[1], f[2])) : m) : this[f] = C || m; 334 | c += 2; 335 | } 336 | }, ne = function(l, p) { 337 | for (var c in p) 338 | if (typeof p[c] === x && p[c].length > 0) { 339 | for (var k = 0; k < p[c].length; k++) 340 | if (ge(p[c][k], l)) 341 | return c === w ? m : c; 342 | } else if (ge(p[c], l)) 343 | return c === w ? m : c; 344 | return l; 345 | }, Te = { 346 | "1.0": "/8", 347 | "1.2": "/1", 348 | "1.3": "/3", 349 | "2.0": "/412", 350 | "2.0.2": "/416", 351 | "2.0.3": "/417", 352 | "2.0.4": "/419", 353 | "?": "/" 354 | }, fe = { 355 | ME: "4.90", 356 | "NT 3.11": "NT3.51", 357 | "NT 4.0": "NT4.0", 358 | 2e3: "NT 5.0", 359 | XP: ["NT 5.1", "NT 5.2"], 360 | Vista: "NT 6.0", 361 | 7: "NT 6.1", 362 | 8: "NT 6.2", 363 | "8.1": "NT 6.3", 364 | 10: ["NT 6.4", "NT 10.0"], 365 | RT: "ARM" 366 | }, he = { 367 | browser: [ 368 | [ 369 | /\b(?:crmo|crios)\/([\w\.]+)/i 370 | // Chrome for Android/iOS 371 | ], 372 | [r, [a, "Chrome"]], 373 | [ 374 | /edg(?:e|ios|a)?\/([\w\.]+)/i 375 | // Microsoft Edge 376 | ], 377 | [r, [a, "Edge"]], 378 | [ 379 | // Presto based 380 | /(opera mini)\/([-\w\.]+)/i, 381 | // Opera Mini 382 | /(opera [mobiletab]{3,6})\b.+version\/([-\w\.]+)/i, 383 | // Opera Mobi/Tablet 384 | /(opera)(?:.+version\/|[\/ ]+)([\w\.]+)/i 385 | // Opera 386 | ], 387 | [a, r], 388 | [ 389 | /opios[\/ ]+([\w\.]+)/i 390 | // Opera mini on iphone >= 8.0 391 | ], 392 | [r, [a, V + " Mini"]], 393 | [ 394 | /\bopr\/([\w\.]+)/i 395 | // Opera Webkit 396 | ], 397 | [r, [a, V]], 398 | [ 399 | // Mixed 400 | /(kindle)\/([\w\.]+)/i, 401 | // Kindle 402 | /(lunascape|maxthon|netfront|jasmine|blazer)[\/ ]?([\w\.]*)/i, 403 | // Lunascape/Maxthon/Netfront/Jasmine/Blazer 404 | // Trident based 405 | /(avant |iemobile|slim)(?:browser)?[\/ ]?([\w\.]*)/i, 406 | // Avant/IEMobile/SlimBrowser 407 | /(ba?idubrowser)[\/ ]?([\w\.]+)/i, 408 | // Baidu Browser 409 | /(?:ms|\()(ie) ([\w\.]+)/i, 410 | // Internet Explorer 411 | // Webkit/KHTML based // Flock/RockMelt/Midori/Epiphany/Silk/Skyfire/Bolt/Iron/Iridium/PhantomJS/Bowser/QupZilla/Falkon 412 | /(flock|rockmelt|midori|epiphany|silk|skyfire|ovibrowser|bolt|iron|vivaldi|iridium|phantomjs|bowser|quark|qupzilla|falkon|rekonq|puffin|brave|whale|qqbrowserlite|qq|duckduckgo)\/([-\w\.]+)/i, 413 | // Rekonq/Puffin/Brave/Whale/QQBrowserLite/QQ, aka ShouQ 414 | /(weibo)__([\d\.]+)/i 415 | // Weibo 416 | ], 417 | [a, r], 418 | [ 419 | /(?:\buc? ?browser|(?:juc.+)ucweb)[\/ ]?([\w\.]+)/i 420 | // UCBrowser 421 | ], 422 | [r, [a, "UC" + L]], 423 | [ 424 | /microm.+\bqbcore\/([\w\.]+)/i, 425 | // WeChat Desktop for Windows Built-in Browser 426 | /\bqbcore\/([\w\.]+).+microm/i 427 | ], 428 | [r, [a, "WeChat(Win) Desktop"]], 429 | [ 430 | /micromessenger\/([\w\.]+)/i 431 | // WeChat 432 | ], 433 | [r, [a, "WeChat"]], 434 | [ 435 | /konqueror\/([\w\.]+)/i 436 | // Konqueror 437 | ], 438 | [r, [a, "Konqueror"]], 439 | [ 440 | /trident.+rv[: ]([\w\.]{1,9})\b.+like gecko/i 441 | // IE11 442 | ], 443 | [r, [a, "IE"]], 444 | [ 445 | /yabrowser\/([\w\.]+)/i 446 | // Yandex 447 | ], 448 | [r, [a, "Yandex"]], 449 | [ 450 | /(avast|avg)\/([\w\.]+)/i 451 | // Avast/AVG Secure Browser 452 | ], 453 | [[a, /(.+)/, "$1 Secure " + L], r], 454 | [ 455 | /\bfocus\/([\w\.]+)/i 456 | // Firefox Focus 457 | ], 458 | [r, [a, B + " Focus"]], 459 | [ 460 | /\bopt\/([\w\.]+)/i 461 | // Opera Touch 462 | ], 463 | [r, [a, V + " Touch"]], 464 | [ 465 | /coc_coc\w+\/([\w\.]+)/i 466 | // Coc Coc Browser 467 | ], 468 | [r, [a, "Coc Coc"]], 469 | [ 470 | /dolfin\/([\w\.]+)/i 471 | // Dolphin 472 | ], 473 | [r, [a, "Dolphin"]], 474 | [ 475 | /coast\/([\w\.]+)/i 476 | // Opera Coast 477 | ], 478 | [r, [a, V + " Coast"]], 479 | [ 480 | /miuibrowser\/([\w\.]+)/i 481 | // MIUI Browser 482 | ], 483 | [r, [a, "MIUI " + L]], 484 | [ 485 | /fxios\/([-\w\.]+)/i 486 | // Firefox for iOS 487 | ], 488 | [r, [a, B]], 489 | [ 490 | /\bqihu|(qi?ho?o?|360)browser/i 491 | // 360 492 | ], 493 | [[a, "360 " + L]], 494 | [ 495 | /(oculus|samsung|sailfish|huawei)browser\/([\w\.]+)/i 496 | ], 497 | [[a, /(.+)/, "$1 " + L], r], 498 | [ 499 | // Oculus/Samsung/Sailfish/Huawei Browser 500 | /(comodo_dragon)\/([\w\.]+)/i 501 | // Comodo Dragon 502 | ], 503 | [[a, /_/g, " "], r], 504 | [ 505 | /(electron)\/([\w\.]+) safari/i, 506 | // Electron-based App 507 | /(tesla)(?: qtcarbrowser|\/(20\d\d\.[-\w\.]+))/i, 508 | // Tesla 509 | /m?(qqbrowser|baiduboxapp|2345Explorer)[\/ ]?([\w\.]+)/i 510 | // QQBrowser/Baidu App/2345 Browser 511 | ], 512 | [a, r], 513 | [ 514 | /(metasr)[\/ ]?([\w\.]+)/i, 515 | // SouGouBrowser 516 | /(lbbrowser)/i, 517 | // LieBao Browser 518 | /\[(linkedin)app\]/i 519 | // LinkedIn App for iOS & Android 520 | ], 521 | [a], 522 | [ 523 | // WebView 524 | /((?:fban\/fbios|fb_iab\/fb4a)(?!.+fbav)|;fbav\/([\w\.]+);)/i 525 | // Facebook App for iOS & Android 526 | ], 527 | [[a, me], r], 528 | [ 529 | /safari (line)\/([\w\.]+)/i, 530 | // Line App for iOS 531 | /\b(line)\/([\w\.]+)\/iab/i, 532 | // Line App for Android 533 | /(chromium|instagram)[\/ ]([-\w\.]+)/i 534 | // Chromium/Instagram 535 | ], 536 | [a, r], 537 | [ 538 | /\bgsa\/([\w\.]+) .*safari\//i 539 | // Google Search Appliance on iOS 540 | ], 541 | [r, [a, "GSA"]], 542 | [ 543 | /headlesschrome(?:\/([\w\.]+)| )/i 544 | // Chrome Headless 545 | ], 546 | [r, [a, q + " Headless"]], 547 | [ 548 | / wv\).+(chrome)\/([\w\.]+)/i 549 | // Chrome WebView 550 | ], 551 | [[a, q + " WebView"], r], 552 | [ 553 | /droid.+ version\/([\w\.]+)\b.+(?:mobile safari|safari)/i 554 | // Android Browser 555 | ], 556 | [r, [a, "Android " + L]], 557 | [ 558 | /(chrome|omniweb|arora|[tizenoka]{5} ?browser)\/v?([\w\.]+)/i 559 | // Chrome/OmniWeb/Arora/Tizen/Nokia 560 | ], 561 | [a, r], 562 | [ 563 | /version\/([\w\.\,]+) .*mobile\/\w+ (safari)/i 564 | // Mobile Safari 565 | ], 566 | [r, [a, "Mobile Safari"]], 567 | [ 568 | /version\/([\w(\.|\,)]+) .*(mobile ?safari|safari)/i 569 | // Safari & Safari Mobile 570 | ], 571 | [r, a], 572 | [ 573 | /webkit.+?(mobile ?safari|safari)(\/[\w\.]+)/i 574 | // Safari < 3.0 575 | ], 576 | [a, [r, ne, Te]], 577 | [ 578 | /(webkit|khtml)\/([\w\.]+)/i 579 | ], 580 | [a, r], 581 | [ 582 | // Gecko based 583 | /(navigator|netscape\d?)\/([-\w\.]+)/i 584 | // Netscape 585 | ], 586 | [[a, "Netscape"], r], 587 | [ 588 | /mobile vr; rv:([\w\.]+)\).+firefox/i 589 | // Firefox Reality 590 | ], 591 | [r, [a, B + " Reality"]], 592 | [ 593 | /ekiohf.+(flow)\/([\w\.]+)/i, 594 | // Flow 595 | /(swiftfox)/i, 596 | // Swiftfox 597 | /(icedragon|iceweasel|camino|chimera|fennec|maemo browser|minimo|conkeror|klar)[\/ ]?([\w\.\+]+)/i, 598 | // IceDragon/Iceweasel/Camino/Chimera/Fennec/Maemo/Minimo/Conkeror/Klar 599 | /(seamonkey|k-meleon|icecat|iceape|firebird|phoenix|palemoon|basilisk|waterfox)\/([-\w\.]+)$/i, 600 | // Firefox/SeaMonkey/K-Meleon/IceCat/IceApe/Firebird/Phoenix 601 | /(firefox)\/([\w\.]+)/i, 602 | // Other Firefox-based 603 | /(mozilla)\/([\w\.]+) .+rv\:.+gecko\/\d+/i, 604 | // Mozilla 605 | // Other 606 | /(polaris|lynx|dillo|icab|doris|amaya|w3m|netsurf|sleipnir|obigo|mosaic|(?:go|ice|up)[\. ]?browser)[-\/ ]?v?([\w\.]+)/i, 607 | // Polaris/Lynx/Dillo/iCab/Doris/Amaya/w3m/NetSurf/Sleipnir/Obigo/Mosaic/Go/ICE/UP.Browser 608 | /(links) \(([\w\.]+)/i 609 | // Links 610 | ], 611 | [a, r], 612 | [ 613 | /(cobalt)\/([\w\.]+)/i 614 | // Cobalt 615 | ], 616 | [a, [r, /master.|lts./, ""]] 617 | ], 618 | cpu: [ 619 | [ 620 | /(?:(amd|x(?:(?:86|64)[-_])?|wow|win)64)[;\)]/i 621 | // AMD64 (x64) 622 | ], 623 | [[d, "amd64"]], 624 | [ 625 | /(ia32(?=;))/i 626 | // IA32 (quicktime) 627 | ], 628 | [[d, A]], 629 | [ 630 | /((?:i[346]|x)86)[;\)]/i 631 | // IA32 (x86) 632 | ], 633 | [[d, "ia32"]], 634 | [ 635 | /\b(aarch64|arm(v?8e?l?|_?64))\b/i 636 | // ARM64 637 | ], 638 | [[d, "arm64"]], 639 | [ 640 | /\b(arm(?:v[67])?ht?n?[fl]p?)\b/i 641 | // ARMHF 642 | ], 643 | [[d, "armhf"]], 644 | [ 645 | // PocketPC mistakenly identified as PowerPC 646 | /windows (ce|mobile); ppc;/i 647 | ], 648 | [[d, "arm"]], 649 | [ 650 | /((?:ppc|powerpc)(?:64)?)(?: mac|;|\))/i 651 | // PowerPC 652 | ], 653 | [[d, /ower/, y, A]], 654 | [ 655 | /(sun4\w)[;\)]/i 656 | // SPARC 657 | ], 658 | [[d, "sparc"]], 659 | [ 660 | /((?:avr32|ia64(?=;))|68k(?=\))|\barm(?=v(?:[1-7]|[5-7]1)l?|;|eabi)|(?=atmel )avr|(?:irix|mips|sparc)(?:64)?\b|pa-risc)/i 661 | // IA64, 68K, ARM/64, AVR/32, IRIX/64, MIPS/64, SPARC/64, PA-RISC 662 | ], 663 | [[d, A]] 664 | ], 665 | device: [ 666 | [ 667 | ////////////////////////// 668 | // MOBILES & TABLETS 669 | // Ordered by popularity 670 | ///////////////////////// 671 | // Samsung 672 | /\b(sch-i[89]0\d|shw-m380s|sm-[ptx]\w{2,4}|gt-[pn]\d{2,4}|sgh-t8[56]9|nexus 10)/i 673 | ], 674 | [o, [i, ie], [e, s]], 675 | [ 676 | /\b((?:s[cgp]h|gt|sm)-\w+|galaxy nexus)/i, 677 | /samsung[- ]([-\w]+)/i, 678 | /sec-(sgh\w+)/i 679 | ], 680 | [o, [i, ie], [e, t]], 681 | [ 682 | // Apple 683 | /\((ip(?:hone|od)[\w ]*);/i 684 | // iPod/iPhone 685 | ], 686 | [o, [i, H], [e, t]], 687 | [ 688 | /\((ipad);[-\w\),; ]+apple/i, 689 | // iPad 690 | /applecoremedia\/[\w\.]+ \((ipad)/i, 691 | /\b(ipad)\d\d?,\d\d?[;\]].+ios/i 692 | ], 693 | [o, [i, H], [e, s]], 694 | [ 695 | /(macintosh);/i 696 | ], 697 | [o, [i, H]], 698 | [ 699 | // Huawei 700 | /\b((?:ag[rs][23]?|bah2?|sht?|btv)-a?[lw]\d{2})\b(?!.+d\/s)/i 701 | ], 702 | [o, [i, be], [e, s]], 703 | [ 704 | /(?:huawei|honor)([-\w ]+)[;\)]/i, 705 | /\b(nexus 6p|\w{2,4}e?-[atu]?[ln][\dx][012359c][adn]?)\b(?!.+d\/s)/i 706 | ], 707 | [o, [i, be], [e, t]], 708 | [ 709 | // Xiaomi 710 | /\b(poco[\w ]+)(?: bui|\))/i, 711 | // Xiaomi POCO 712 | /\b; (\w+) build\/hm\1/i, 713 | // Xiaomi Hongmi 'numeric' models 714 | /\b(hm[-_ ]?note?[_ ]?(?:\d\w)?) bui/i, 715 | // Xiaomi Hongmi 716 | /\b(redmi[\-_ ]?(?:note|k)?[\w_ ]+)(?: bui|\))/i, 717 | // Xiaomi Redmi 718 | /\b(mi[-_ ]?(?:a\d|one|one[_ ]plus|note lte|max|cc)?[_ ]?(?:\d?\w?)[_ ]?(?:plus|se|lite)?)(?: bui|\))/i 719 | // Xiaomi Mi 720 | ], 721 | [[o, /_/g, " "], [i, oe], [e, t]], 722 | [ 723 | /\b(mi[-_ ]?(?:pad)(?:[\w_ ]+))(?: bui|\))/i 724 | // Mi Pad tablets 725 | ], 726 | [[o, /_/g, " "], [i, oe], [e, s]], 727 | [ 728 | // OPPO 729 | /; (\w+) bui.+ oppo/i, 730 | /\b(cph[12]\d{3}|p(?:af|c[al]|d\w|e[ar])[mt]\d0|x9007|a101op)\b/i 731 | ], 732 | [o, [i, "OPPO"], [e, t]], 733 | [ 734 | // Vivo 735 | /vivo (\w+)(?: bui|\))/i, 736 | /\b(v[12]\d{3}\w?[at])(?: bui|;)/i 737 | ], 738 | [o, [i, "Vivo"], [e, t]], 739 | [ 740 | // Realme 741 | /\b(rmx[12]\d{3})(?: bui|;|\))/i 742 | ], 743 | [o, [i, "Realme"], [e, t]], 744 | [ 745 | // Motorola 746 | /\b(milestone|droid(?:[2-4x]| (?:bionic|x2|pro|razr))?:?( 4g)?)\b[\w ]+build\//i, 747 | /\bmot(?:orola)?[- ](\w*)/i, 748 | /((?:moto[\w\(\) ]+|xt\d{3,4}|nexus 6)(?= bui|\)))/i 749 | ], 750 | [o, [i, we], [e, t]], 751 | [ 752 | /\b(mz60\d|xoom[2 ]{0,2}) build\//i 753 | ], 754 | [o, [i, we], [e, s]], 755 | [ 756 | // LG 757 | /((?=lg)?[vl]k\-?\d{3}) bui| 3\.[-\w; ]{10}lg?-([06cv9]{3,4})/i 758 | ], 759 | [o, [i, $], [e, s]], 760 | [ 761 | /(lm(?:-?f100[nv]?|-[\w\.]+)(?= bui|\))|nexus [45])/i, 762 | /\blg[-e;\/ ]+((?!browser|netcast|android tv)\w+)/i, 763 | /\blg-?([\d\w]+) bui/i 764 | ], 765 | [o, [i, $], [e, t]], 766 | [ 767 | // Lenovo 768 | /(ideatab[-\w ]+)/i, 769 | /lenovo ?(s[56]000[-\w]+|tab(?:[\w ]+)|yt[-\d\w]{6}|tb[-\d\w]{6})/i 770 | ], 771 | [o, [i, "Lenovo"], [e, s]], 772 | [ 773 | // Nokia 774 | /(?:maemo|nokia).*(n900|lumia \d+)/i, 775 | /nokia[-_ ]?([-\w\.]*)/i 776 | ], 777 | [[o, /_/g, " "], [i, "Nokia"], [e, t]], 778 | [ 779 | // Google 780 | /(pixel c)\b/i 781 | // Google Pixel C 782 | ], 783 | [o, [i, Z], [e, s]], 784 | [ 785 | /droid.+; (pixel[\daxl ]{0,6})(?: bui|\))/i 786 | // Google Pixel 787 | ], 788 | [o, [i, Z], [e, t]], 789 | [ 790 | // Sony 791 | /droid.+ (a?\d[0-2]{2}so|[c-g]\d{4}|so[-gl]\w+|xq-a\w[4-7][12])(?= bui|\).+chrome\/(?![1-6]{0,1}\d\.))/i 792 | ], 793 | [o, [i, G], [e, t]], 794 | [ 795 | /sony tablet [ps]/i, 796 | /\b(?:sony)?sgp\w+(?: bui|\))/i 797 | ], 798 | [[o, "Xperia Tablet"], [i, G], [e, s]], 799 | [ 800 | // OnePlus 801 | / (kb2005|in20[12]5|be20[12][59])\b/i, 802 | /(?:one)?(?:plus)? (a\d0\d\d)(?: b|\))/i 803 | ], 804 | [o, [i, "OnePlus"], [e, t]], 805 | [ 806 | // Amazon 807 | /(alexa)webm/i, 808 | /(kf[a-z]{2}wi)( bui|\))/i, 809 | // Kindle Fire without Silk 810 | /(kf[a-z]+)( bui|\)).+silk\//i 811 | // Kindle Fire HD 812 | ], 813 | [o, [i, X], [e, s]], 814 | [ 815 | /((?:sd|kf)[0349hijorstuw]+)( bui|\)).+silk\//i 816 | // Fire Phone 817 | ], 818 | [[o, /(.+)/g, "Fire Phone $1"], [i, X], [e, t]], 819 | [ 820 | // BlackBerry 821 | /(playbook);[-\w\),; ]+(rim)/i 822 | // BlackBerry PlayBook 823 | ], 824 | [o, i, [e, s]], 825 | [ 826 | /\b((?:bb[a-f]|st[hv])100-\d)/i, 827 | /\(bb10; (\w+)/i 828 | // BlackBerry 10 829 | ], 830 | [o, [i, ue], [e, t]], 831 | [ 832 | // Asus 833 | /(?:\b|asus_)(transfo[prime ]{4,10} \w+|eeepc|slider \w+|nexus 7|padfone|p00[cj])/i 834 | ], 835 | [o, [i, ce], [e, s]], 836 | [ 837 | / (z[bes]6[027][012][km][ls]|zenfone \d\w?)\b/i 838 | ], 839 | [o, [i, ce], [e, t]], 840 | [ 841 | // HTC 842 | /(nexus 9)/i 843 | // HTC Nexus 9 844 | ], 845 | [o, [i, "HTC"], [e, s]], 846 | [ 847 | /(htc)[-;_ ]{1,2}([\w ]+(?=\)| bui)|\w+)/i, 848 | // HTC 849 | // ZTE 850 | /(zte)[- ]([\w ]+?)(?: bui|\/|\))/i, 851 | /(alcatel|geeksphone|nexian|panasonic|sony(?!-bra))[-_ ]?([-\w]*)/i 852 | // Alcatel/GeeksPhone/Nexian/Panasonic/Sony 853 | ], 854 | [i, [o, /_/g, " "], [e, t]], 855 | [ 856 | // Acer 857 | /droid.+; ([ab][1-7]-?[0178a]\d\d?)/i 858 | ], 859 | [o, [i, "Acer"], [e, s]], 860 | [ 861 | // Meizu 862 | /droid.+; (m[1-5] note) bui/i, 863 | /\bmz-([-\w]{2,})/i 864 | ], 865 | [o, [i, "Meizu"], [e, t]], 866 | [ 867 | // Sharp 868 | /\b(sh-?[altvz]?\d\d[a-ekm]?)/i 869 | ], 870 | [o, [i, pe], [e, t]], 871 | [ 872 | // MIXED 873 | /(blackberry|benq|palm(?=\-)|sonyericsson|acer|asus|dell|meizu|motorola|polytron)[-_ ]?([-\w]*)/i, 874 | // BlackBerry/BenQ/Palm/Sony-Ericsson/Acer/Asus/Dell/Meizu/Motorola/Polytron 875 | /(hp) ([\w ]+\w)/i, 876 | // HP iPAQ 877 | /(asus)-?(\w+)/i, 878 | // Asus 879 | /(microsoft); (lumia[\w ]+)/i, 880 | // Microsoft Lumia 881 | /(lenovo)[-_ ]?([-\w]+)/i, 882 | // Lenovo 883 | /(jolla)/i, 884 | // Jolla 885 | /(oppo) ?([\w ]+) bui/i 886 | // OPPO 887 | ], 888 | [i, o, [e, t]], 889 | [ 890 | /(archos) (gamepad2?)/i, 891 | // Archos 892 | /(hp).+(touchpad(?!.+tablet)|tablet)/i, 893 | // HP TouchPad 894 | /(kindle)\/([\w\.]+)/i, 895 | // Kindle 896 | /(nook)[\w ]+build\/(\w+)/i, 897 | // Nook 898 | /(dell) (strea[kpr\d ]*[\dko])/i, 899 | // Dell Streak 900 | /(le[- ]+pan)[- ]+(\w{1,9}) bui/i, 901 | // Le Pan Tablets 902 | /(trinity)[- ]*(t\d{3}) bui/i, 903 | // Trinity Tablets 904 | /(gigaset)[- ]+(q\w{1,9}) bui/i, 905 | // Gigaset Tablets 906 | /(vodafone) ([\w ]+)(?:\)| bui)/i 907 | // Vodafone 908 | ], 909 | [i, o, [e, s]], 910 | [ 911 | /(surface duo)/i 912 | // Surface Duo 913 | ], 914 | [o, [i, ee], [e, s]], 915 | [ 916 | /droid [\d\.]+; (fp\du?)(?: b|\))/i 917 | // Fairphone 918 | ], 919 | [o, [i, "Fairphone"], [e, t]], 920 | [ 921 | /(u304aa)/i 922 | // AT&T 923 | ], 924 | [o, [i, "AT&T"], [e, t]], 925 | [ 926 | /\bsie-(\w*)/i 927 | // Siemens 928 | ], 929 | [o, [i, "Siemens"], [e, t]], 930 | [ 931 | /\b(rct\w+) b/i 932 | // RCA Tablets 933 | ], 934 | [o, [i, "RCA"], [e, s]], 935 | [ 936 | /\b(venue[\d ]{2,7}) b/i 937 | // Dell Venue Tablets 938 | ], 939 | [o, [i, "Dell"], [e, s]], 940 | [ 941 | /\b(q(?:mv|ta)\w+) b/i 942 | // Verizon Tablet 943 | ], 944 | [o, [i, "Verizon"], [e, s]], 945 | [ 946 | /\b(?:barnes[& ]+noble |bn[rt])([\w\+ ]*) b/i 947 | // Barnes & Noble Tablet 948 | ], 949 | [o, [i, "Barnes & Noble"], [e, s]], 950 | [ 951 | /\b(tm\d{3}\w+) b/i 952 | ], 953 | [o, [i, "NuVision"], [e, s]], 954 | [ 955 | /\b(k88) b/i 956 | // ZTE K Series Tablet 957 | ], 958 | [o, [i, "ZTE"], [e, s]], 959 | [ 960 | /\b(nx\d{3}j) b/i 961 | // ZTE Nubia 962 | ], 963 | [o, [i, "ZTE"], [e, t]], 964 | [ 965 | /\b(gen\d{3}) b.+49h/i 966 | // Swiss GEN Mobile 967 | ], 968 | [o, [i, "Swiss"], [e, t]], 969 | [ 970 | /\b(zur\d{3}) b/i 971 | // Swiss ZUR Tablet 972 | ], 973 | [o, [i, "Swiss"], [e, s]], 974 | [ 975 | /\b((zeki)?tb.*\b) b/i 976 | // Zeki Tablets 977 | ], 978 | [o, [i, "Zeki"], [e, s]], 979 | [ 980 | /\b([yr]\d{2}) b/i, 981 | /\b(dragon[- ]+touch |dt)(\w{5}) b/i 982 | // Dragon Touch Tablet 983 | ], 984 | [[i, "Dragon Touch"], o, [e, s]], 985 | [ 986 | /\b(ns-?\w{0,9}) b/i 987 | // Insignia Tablets 988 | ], 989 | [o, [i, "Insignia"], [e, s]], 990 | [ 991 | /\b((nxa|next)-?\w{0,9}) b/i 992 | // NextBook Tablets 993 | ], 994 | [o, [i, "NextBook"], [e, s]], 995 | [ 996 | /\b(xtreme\_)?(v(1[045]|2[015]|[3469]0|7[05])) b/i 997 | // Voice Xtreme Phones 998 | ], 999 | [[i, "Voice"], o, [e, t]], 1000 | [ 1001 | /\b(lvtel\-)?(v1[12]) b/i 1002 | // LvTel Phones 1003 | ], 1004 | [[i, "LvTel"], o, [e, t]], 1005 | [ 1006 | /\b(ph-1) /i 1007 | // Essential PH-1 1008 | ], 1009 | [o, [i, "Essential"], [e, t]], 1010 | [ 1011 | /\b(v(100md|700na|7011|917g).*\b) b/i 1012 | // Envizen Tablets 1013 | ], 1014 | [o, [i, "Envizen"], [e, s]], 1015 | [ 1016 | /\b(trio[-\w\. ]+) b/i 1017 | // MachSpeed Tablets 1018 | ], 1019 | [o, [i, "MachSpeed"], [e, s]], 1020 | [ 1021 | /\btu_(1491) b/i 1022 | // Rotor Tablets 1023 | ], 1024 | [o, [i, "Rotor"], [e, s]], 1025 | [ 1026 | /(shield[\w ]+) b/i 1027 | // Nvidia Shield Tablets 1028 | ], 1029 | [o, [i, "Nvidia"], [e, s]], 1030 | [ 1031 | /(sprint) (\w+)/i 1032 | // Sprint Phones 1033 | ], 1034 | [i, o, [e, t]], 1035 | [ 1036 | /(kin\.[onetw]{3})/i 1037 | // Microsoft Kin 1038 | ], 1039 | [[o, /\./g, " "], [i, ee], [e, t]], 1040 | [ 1041 | /droid.+; (cc6666?|et5[16]|mc[239][23]x?|vc8[03]x?)\)/i 1042 | // Zebra 1043 | ], 1044 | [o, [i, ae], [e, s]], 1045 | [ 1046 | /droid.+; (ec30|ps20|tc[2-8]\d[kx])\)/i 1047 | ], 1048 | [o, [i, ae], [e, t]], 1049 | [ 1050 | /////////////////// 1051 | // CONSOLES 1052 | /////////////////// 1053 | /(ouya)/i, 1054 | // Ouya 1055 | /(nintendo) ([wids3utch]+)/i 1056 | // Nintendo 1057 | ], 1058 | [i, o, [e, g]], 1059 | [ 1060 | /droid.+; (shield) bui/i 1061 | // Nvidia 1062 | ], 1063 | [o, [i, "Nvidia"], [e, g]], 1064 | [ 1065 | /(playstation [345portablevi]+)/i 1066 | // Playstation 1067 | ], 1068 | [o, [i, G], [e, g]], 1069 | [ 1070 | /\b(xbox(?: one)?(?!; xbox))[\); ]/i 1071 | // Microsoft Xbox 1072 | ], 1073 | [o, [i, ee], [e, g]], 1074 | [ 1075 | /////////////////// 1076 | // SMARTTVS 1077 | /////////////////// 1078 | /smart-tv.+(samsung)/i 1079 | // Samsung 1080 | ], 1081 | [i, [e, S]], 1082 | [ 1083 | /hbbtv.+maple;(\d+)/i 1084 | ], 1085 | [[o, /^/, "SmartTV"], [i, ie], [e, S]], 1086 | [ 1087 | /(nux; netcast.+smarttv|lg (netcast\.tv-201\d|android tv))/i 1088 | // LG SmartTV 1089 | ], 1090 | [[i, $], [e, S]], 1091 | [ 1092 | /(apple) ?tv/i 1093 | // Apple TV 1094 | ], 1095 | [i, [o, H + " TV"], [e, S]], 1096 | [ 1097 | /crkey/i 1098 | // Google Chromecast 1099 | ], 1100 | [[o, q + "cast"], [i, Z], [e, S]], 1101 | [ 1102 | /droid.+aft(\w)( bui|\))/i 1103 | // Fire TV 1104 | ], 1105 | [o, [i, X], [e, S]], 1106 | [ 1107 | /\(dtv[\);].+(aquos)/i, 1108 | /(aquos-tv[\w ]+)\)/i 1109 | // Sharp 1110 | ], 1111 | [o, [i, pe], [e, S]], 1112 | [ 1113 | /(bravia[\w ]+)( bui|\))/i 1114 | // Sony 1115 | ], 1116 | [o, [i, G], [e, S]], 1117 | [ 1118 | /(mitv-\w{5}) bui/i 1119 | // Xiaomi 1120 | ], 1121 | [o, [i, oe], [e, S]], 1122 | [ 1123 | /\b(roku)[\dx]*[\)\/]((?:dvp-)?[\d\.]*)/i, 1124 | // Roku 1125 | /hbbtv\/\d+\.\d+\.\d+ +\([\w ]*; *(\w[^;]*);([^;]*)/i 1126 | // HbbTV devices 1127 | ], 1128 | [[i, re], [o, re], [e, S]], 1129 | [ 1130 | /\b(android tv|smart[- ]?tv|opera tv|tv; rv:)\b/i 1131 | // SmartTV from Unidentified Vendors 1132 | ], 1133 | [[e, S]], 1134 | [ 1135 | /////////////////// 1136 | // WEARABLES 1137 | /////////////////// 1138 | /((pebble))app/i 1139 | // Pebble 1140 | ], 1141 | [i, o, [e, O]], 1142 | [ 1143 | /droid.+; (glass) \d/i 1144 | // Google Glass 1145 | ], 1146 | [o, [i, Z], [e, O]], 1147 | [ 1148 | /droid.+; (wt63?0{2,3})\)/i 1149 | ], 1150 | [o, [i, ae], [e, O]], 1151 | [ 1152 | /(quest( 2)?)/i 1153 | // Oculus Quest 1154 | ], 1155 | [o, [i, me], [e, O]], 1156 | [ 1157 | /////////////////// 1158 | // EMBEDDED 1159 | /////////////////// 1160 | /(tesla)(?: qtcarbrowser|\/[-\w\.]+)/i 1161 | // Tesla 1162 | ], 1163 | [i, [e, le]], 1164 | [ 1165 | //////////////////// 1166 | // MIXED (GENERIC) 1167 | /////////////////// 1168 | /droid .+?; ([^;]+?)(?: bui|\) applew).+? mobile safari/i 1169 | // Android Phones from Unidentified Vendors 1170 | ], 1171 | [o, [e, t]], 1172 | [ 1173 | /droid .+?; ([^;]+?)(?: bui|\) applew).+?(?! mobile) safari/i 1174 | // Android Tablets from Unidentified Vendors 1175 | ], 1176 | [o, [e, s]], 1177 | [ 1178 | /\b((tablet|tab)[;\/]|focus\/\d(?!.+mobile))/i 1179 | // Unidentifiable Tablet 1180 | ], 1181 | [[e, s]], 1182 | [ 1183 | /(phone|mobile(?:[;\/]| [ \w\/\.]*safari)|pda(?=.+windows ce))/i 1184 | // Unidentifiable Mobile 1185 | ], 1186 | [[e, t]], 1187 | [ 1188 | /(android[-\w\. ]{0,9});.+buil/i 1189 | // Generic Android Device 1190 | ], 1191 | [o, [i, "Generic"]] 1192 | ], 1193 | engine: [ 1194 | [ 1195 | /windows.+ edge\/([\w\.]+)/i 1196 | // EdgeHTML 1197 | ], 1198 | [r, [a, je + "HTML"]], 1199 | [ 1200 | /webkit\/537\.36.+chrome\/(?!27)([\w\.]+)/i 1201 | // Blink 1202 | ], 1203 | [r, [a, "Blink"]], 1204 | [ 1205 | /(presto)\/([\w\.]+)/i, 1206 | // Presto 1207 | /(webkit|trident|netfront|netsurf|amaya|lynx|w3m|goanna)\/([\w\.]+)/i, 1208 | // WebKit/Trident/NetFront/NetSurf/Amaya/Lynx/w3m/Goanna 1209 | /ekioh(flow)\/([\w\.]+)/i, 1210 | // Flow 1211 | /(khtml|tasman|links)[\/ ]\(?([\w\.]+)/i, 1212 | // KHTML/Tasman/Links 1213 | /(icab)[\/ ]([23]\.[\d\.]+)/i 1214 | // iCab 1215 | ], 1216 | [a, r], 1217 | [ 1218 | /rv\:([\w\.]{1,9})\b.+(gecko)/i 1219 | // Gecko 1220 | ], 1221 | [r, a] 1222 | ], 1223 | os: [ 1224 | [ 1225 | // Windows 1226 | /microsoft (windows) (vista|xp)/i 1227 | // Windows (iTunes) 1228 | ], 1229 | [a, r], 1230 | [ 1231 | /(windows) nt 6\.2; (arm)/i, 1232 | // Windows RT 1233 | /(windows (?:phone(?: os)?|mobile))[\/ ]?([\d\.\w ]*)/i, 1234 | // Windows Phone 1235 | /(windows)[\/ ]?([ntce\d\. ]+\w)(?!.+xbox)/i 1236 | ], 1237 | [a, [r, ne, fe]], 1238 | [ 1239 | /(win(?=3|9|n)|win 9x )([nt\d\.]+)/i 1240 | ], 1241 | [[a, "Windows"], [r, ne, fe]], 1242 | [ 1243 | // iOS/macOS 1244 | /ip[honead]{2,4}\b(?:.*os ([\w]+) like mac|; opera)/i, 1245 | // iOS 1246 | /cfnetwork\/.+darwin/i 1247 | ], 1248 | [[r, /_/g, "."], [a, "iOS"]], 1249 | [ 1250 | /(mac os x) ?([\w\. ]*)/i, 1251 | /(macintosh|mac_powerpc\b)(?!.+haiku)/i 1252 | // Mac OS 1253 | ], 1254 | [[a, "Mac OS"], [r, /_/g, "."]], 1255 | [ 1256 | // Mobile OSes 1257 | /droid ([\w\.]+)\b.+(android[- ]x86|harmonyos)/i 1258 | // Android-x86/HarmonyOS 1259 | ], 1260 | [r, a], 1261 | [ 1262 | // Android/WebOS/QNX/Bada/RIM/Maemo/MeeGo/Sailfish OS 1263 | /(android|webos|qnx|bada|rim tablet os|maemo|meego|sailfish)[-\/ ]?([\w\.]*)/i, 1264 | /(blackberry)\w*\/([\w\.]*)/i, 1265 | // Blackberry 1266 | /(tizen|kaios)[\/ ]([\w\.]+)/i, 1267 | // Tizen/KaiOS 1268 | /\((series40);/i 1269 | // Series 40 1270 | ], 1271 | [a, r], 1272 | [ 1273 | /\(bb(10);/i 1274 | // BlackBerry 10 1275 | ], 1276 | [r, [a, ue]], 1277 | [ 1278 | /(?:symbian ?os|symbos|s60(?=;)|series60)[-\/ ]?([\w\.]*)/i 1279 | // Symbian 1280 | ], 1281 | [r, [a, "Symbian"]], 1282 | [ 1283 | /mozilla\/[\d\.]+ \((?:mobile|tablet|tv|mobile; [\w ]+); rv:.+ gecko\/([\w\.]+)/i 1284 | // Firefox OS 1285 | ], 1286 | [r, [a, B + " OS"]], 1287 | [ 1288 | /web0s;.+rt(tv)/i, 1289 | /\b(?:hp)?wos(?:browser)?\/([\w\.]+)/i 1290 | // WebOS 1291 | ], 1292 | [r, [a, "webOS"]], 1293 | [ 1294 | // Google Chromecast 1295 | /crkey\/([\d\.]+)/i 1296 | // Google Chromecast 1297 | ], 1298 | [r, [a, q + "cast"]], 1299 | [ 1300 | /(cros) [\w]+ ([\w\.]+\w)/i 1301 | // Chromium OS 1302 | ], 1303 | [[a, "Chromium OS"], r], 1304 | [ 1305 | // Console 1306 | /(nintendo|playstation) ([wids345portablevuch]+)/i, 1307 | // Nintendo/Playstation 1308 | /(xbox); +xbox ([^\);]+)/i, 1309 | // Microsoft Xbox (360, One, X, S, Series X, Series S) 1310 | // Other 1311 | /\b(joli|palm)\b ?(?:os)?\/?([\w\.]*)/i, 1312 | // Joli/Palm 1313 | /(mint)[\/\(\) ]?(\w*)/i, 1314 | // Mint 1315 | /(mageia|vectorlinux)[; ]/i, 1316 | // Mageia/VectorLinux 1317 | /([kxln]?ubuntu|debian|suse|opensuse|gentoo|arch(?= linux)|slackware|fedora|mandriva|centos|pclinuxos|red ?hat|zenwalk|linpus|raspbian|plan 9|minix|risc os|contiki|deepin|manjaro|elementary os|sabayon|linspire)(?: gnu\/linux)?(?: enterprise)?(?:[- ]linux)?(?:-gnu)?[-\/ ]?(?!chrom|package)([-\w\.]*)/i, 1318 | // Ubuntu/Debian/SUSE/Gentoo/Arch/Slackware/Fedora/Mandriva/CentOS/PCLinuxOS/RedHat/Zenwalk/Linpus/Raspbian/Plan9/Minix/RISCOS/Contiki/Deepin/Manjaro/elementary/Sabayon/Linspire 1319 | /(hurd|linux) ?([\w\.]*)/i, 1320 | // Hurd/Linux 1321 | /(gnu) ?([\w\.]*)/i, 1322 | // GNU 1323 | /\b([-frentopcghs]{0,5}bsd|dragonfly)[\/ ]?(?!amd|[ix346]{1,2}86)([\w\.]*)/i, 1324 | // FreeBSD/NetBSD/OpenBSD/PC-BSD/GhostBSD/DragonFly 1325 | /(haiku) (\w+)/i 1326 | // Haiku 1327 | ], 1328 | [a, r], 1329 | [ 1330 | /(sunos) ?([\w\.\d]*)/i 1331 | // Solaris 1332 | ], 1333 | [[a, "Solaris"], r], 1334 | [ 1335 | /((?:open)?solaris)[-\/ ]?([\w\.]*)/i, 1336 | // Solaris 1337 | /(aix) ((\d)(?=\.|\)| )[\w\.])*/i, 1338 | // AIX 1339 | /\b(beos|os\/2|amigaos|morphos|openvms|fuchsia|hp-ux)/i, 1340 | // BeOS/OS2/AmigaOS/MorphOS/OpenVMS/Fuchsia/HP-UX 1341 | /(unix) ?([\w\.]*)/i 1342 | // UNIX 1343 | ], 1344 | [a, r] 1345 | ] 1346 | }, T = function(l, p) { 1347 | if (typeof l === x && (p = l, l = m), !(this instanceof T)) 1348 | return new T(l, p).getResult(); 1349 | var c = l || (typeof h !== j && h.navigator && h.navigator.userAgent ? h.navigator.userAgent : y), k = p ? Ne(he, p) : he; 1350 | return this.getBrowser = function() { 1351 | var u = {}; 1352 | return u[a] = m, u[r] = m, E.call(u, c, k.browser), u.major = Se(u.version), u; 1353 | }, this.getCPU = function() { 1354 | var u = {}; 1355 | return u[d] = m, E.call(u, c, k.cpu), u; 1356 | }, this.getDevice = function() { 1357 | var u = {}; 1358 | return u[i] = m, u[o] = m, u[e] = m, E.call(u, c, k.device), u; 1359 | }, this.getEngine = function() { 1360 | var u = {}; 1361 | return u[a] = m, u[r] = m, E.call(u, c, k.engine), u; 1362 | }, this.getOS = function() { 1363 | var u = {}; 1364 | return u[a] = m, u[r] = m, E.call(u, c, k.os), u; 1365 | }, this.getResult = function() { 1366 | return { 1367 | ua: this.getUA(), 1368 | browser: this.getBrowser(), 1369 | engine: this.getEngine(), 1370 | os: this.getOS(), 1371 | device: this.getDevice(), 1372 | cpu: this.getCPU() 1373 | }; 1374 | }, this.getUA = function() { 1375 | return c; 1376 | }, this.setUA = function(u) { 1377 | return c = typeof u === N && u.length > J ? re(u, J) : u, this; 1378 | }, this.setUA(c), this; 1379 | }; 1380 | T.VERSION = v, T.BROWSER = Q([a, r, D]), T.CPU = Q([d]), T.DEVICE = Q([o, i, e, g, t, S, s, O, le]), T.ENGINE = T.OS = Q([a, r]), n.exports && (b = n.exports = T), b.UAParser = T; 1381 | var I = typeof h !== j && (h.jQuery || h.Zepto); 1382 | if (I && !I.ua) { 1383 | var W = new T(); 1384 | I.ua = W.getResult(), I.ua.get = function() { 1385 | return W.getUA(); 1386 | }, I.ua.set = function(l) { 1387 | W.setUA(l); 1388 | var p = W.getResult(); 1389 | for (var c in p) 1390 | I.ua[c] = p[c]; 1391 | }; 1392 | } 1393 | })(typeof window == "object" ? window : Re); 1394 | })(Ue, K); 1395 | const He = K, qe = Ce({ 1396 | name: "addToHomescreen", 1397 | props: { 1398 | title: { 1399 | type: String, 1400 | required: !1 1401 | }, 1402 | content: { 1403 | type: String, 1404 | required: !1 1405 | }, 1406 | titleColor: { 1407 | type: String, 1408 | required: !1 1409 | }, 1410 | contentColor: { 1411 | type: String, 1412 | required: !1 1413 | }, 1414 | iconPath: { 1415 | type: String, 1416 | required: !1 1417 | }, 1418 | iconColor: { 1419 | type: String, 1420 | required: !1 1421 | }, 1422 | iconTextColor: { 1423 | type: String, 1424 | required: !1 1425 | }, 1426 | buttonColor: { 1427 | type: String, 1428 | required: !1 1429 | }, 1430 | buttonTextColor: { 1431 | type: String, 1432 | required: !1 1433 | }, 1434 | background: { 1435 | type: String, 1436 | required: !1 1437 | }, 1438 | lang: { 1439 | type: String, 1440 | required: !1 1441 | }, 1442 | expires: { 1443 | type: Number, 1444 | required: !1 1445 | } 1446 | }, 1447 | setup(n) { 1448 | const b = (d) => n ? n[d] : void 0, h = (d) => { 1449 | const g = n ? n[d] : d; 1450 | return g && typeof g == "string" ? g : d; 1451 | }, m = b("lang") || "en_GB", v = _e[m], y = (d) => d.split(".").reduce((g, t) => { 1452 | if (g) 1453 | return g[t]; 1454 | }, v), w = ke(), z = P(() => document.title), j = P(() => window.location.href), x = P(() => z.value.substring(0, 1)), N = ke(!1), D = () => { 1455 | let d = new Date(); 1456 | const g = n.expires || 365; 1457 | d.setDate(d.getDate() + g), de.set("addToHomescreenCalled", "true", { 1458 | expires: d 1459 | }); 1460 | }, o = P(() => { 1461 | const d = b("iconColor"), g = b("iconPath"), t = b("iconTextColor"); 1462 | return { 1463 | backgroundColor: d && typeof d == "string" ? d : "transparent", 1464 | backgroundImage: g ? "url(" + b("iconPath") + ")" : "none", 1465 | color: t && typeof t == "string" ? t : "black" 1466 | }; 1467 | }), a = P(() => { 1468 | const d = b("buttonTextColor"), g = b("buttonColor"); 1469 | return { 1470 | color: d && d === "string" ? d : "white", 1471 | backgroundColor: g && typeof g == "string" ? g : "black" 1472 | }; 1473 | }), e = () => { 1474 | D(), N.value = !1; 1475 | }, i = () => { 1476 | const d = document.getElementById("IOSmodal"); 1477 | d && (d.style.display = "none"); 1478 | }, r = () => { 1479 | const g = new He().getResult(), t = { 1480 | os: g.os.name, 1481 | browser: g.browser.name 1482 | }, s = document.getElementById("IOSmodal"); 1483 | w.value ? w.value.prompt() : t.os === "iOS" ? s && (s.style.display = "block") : t.os === "Android" ? alert(y("addMessages.android")) : t.os === "Windows" && (t.browser === "Chrome" || t.browser === "Edge") ? alert(y("addMessages.windows.chrome")) : t.os === "Windows" && t.browser === "Firefox" ? alert(y("addMessages.windows.firefox")) : t.os === "Mac OS" ? "ontouchstart" in window || navigator.maxTouchPoints > 0 ? s && (s.style.display = "block") : t.browser === "Firefox" ? alert(y("addMessages.macos.firefox")) : t.browser === "Chrome" ? alert(y("addMessages.macos.chrome")) : t.browser === "Safari" && alert(y("addMessages.macos.safari")) : alert(y("addMessages.others")), N.value = !1; 1484 | }; 1485 | return xe(() => { 1486 | window.addEventListener("beforeinstallprompt", (g) => { 1487 | g.preventDefault(), w.value = g; 1488 | }); 1489 | const d = de.get("addToHomescreenCalled"); 1490 | !Pe() && !d && (N.value = !0, D()); 1491 | }), { 1492 | t: y, 1493 | addToHomescreen: r, 1494 | closeModal: i, 1495 | close: e, 1496 | buttonStyle: a, 1497 | iconStyle: o, 1498 | getCssOpt: h, 1499 | getOpt: b, 1500 | appUrl: j, 1501 | firstCharTitle: x, 1502 | appTitle: z, 1503 | opened: N 1504 | }; 1505 | } 1506 | }), Be = "data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE3LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDMzMy4zMjQgMzMzLjMyNCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzMzLjMyNCAzMzMuMzI0OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBzdHlsZT0iZmlsbDojMjIyMjIwOyIgZD0iTTEyNS4yNTUsNTkuNTEzbDMzLjkwNy0zMy45MDd2MTQ5LjQ1MWMwLDQuMTQzLDMuMzU4LDcuNSw3LjUsNy41czcuNS0zLjM1Nyw3LjUtNy41VjI1LjYwNg0KCQlsMzMuOTA3LDMzLjkwN2MxLjQ2NCwxLjQ2NCwzLjM4NCwyLjE5Niw1LjMwMywyLjE5NnMzLjgzOS0wLjczMiw1LjMwMy0yLjE5NmMyLjkyOS0yLjkzLDIuOTI5LTcuNjc4LDAtMTAuNjA3bC00Ni43MS00Ni43MQ0KCQljLTIuOTI5LTIuOTI4LTcuNjc4LTIuOTI4LTEwLjYwNiwwbC00Ni43MSw0Ni43MWMtMi45MjksMi45My0yLjkyOSw3LjY3OCwwLDEwLjYwN0MxMTcuNTc3LDYyLjQ0MSwxMjIuMzI2LDYyLjQ0MSwxMjUuMjU1LDU5LjUxM3oNCgkJIi8+DQoJPHBhdGggc3R5bGU9ImZpbGw6IzIyMjIyMDsiIGQ9Ik0yNjMuMzI4LDg3LjU1N2gtNjEuNjQ1Yy00LjE0MiwwLTcuNSwzLjM1Ny03LjUsNy41czMuMzU4LDcuNSw3LjUsNy41aDU0LjE0NXYyMTUuNzY3SDc3LjQ5NQ0KCQlWMTAyLjU1N2g1NC4xNDVjNC4xNDIsMCw3LjUtMy4zNTcsNy41LTcuNXMtMy4zNTgtNy41LTcuNS03LjVINjkuOTk1Yy00LjE0MiwwLTcuNSwzLjM1Ny03LjUsNy41djIzMC43NjcNCgkJYzAsNC4xNDMsMy4zNTgsNy41LDcuNSw3LjVoMTkzLjMzM2M0LjE0MiwwLDcuNS0zLjM1Nyw3LjUtNy41Vjk1LjA1N0MyNzAuODI4LDkwLjkxNSwyNjcuNDcsODcuNTU3LDI2My4zMjgsODcuNTU3eiIvPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo=", Ze = "data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0Ij48cGF0aCBkPSJNMCAwaDI0djI0SDBWMHoiIGZpbGw9Im5vbmUiLz48cGF0aCBkPSJNMTkgM0g1Yy0xLjExIDAtMiAuOS0yIDJ2MTRjMCAxLjEuODkgMiAyIDJoMTRjMS4xIDAgMi0uOSAyLTJWNWMwLTEuMS0uOS0yLTItMnptMCAxNkg1VjVoMTR2MTR6bS04LTJoMnYtNGg0di0yaC00VjdoLTJ2NEg3djJoNHoiLz48L3N2Zz4="; 1507 | const Ve = (n, b) => { 1508 | const h = n.__vccOpts || n; 1509 | for (const [m, v] of b) 1510 | h[m] = v; 1511 | return h; 1512 | }, Ge = { class: "add-to-homescreen-plugin-container" }, Qe = { class: "flex" }, We = { class: "icon-container" }, Fe = { class: "col" }, Ye = /* @__PURE__ */ M("br", null, null, -1), Ke = ["innerHTML"], Je = { class: "flex" }, Xe = { class: "col" }, $e = { class: "btn-container" }, ei = { 1513 | id: "IOSmodal", 1514 | class: "modal add-to-homescreen-visible" 1515 | }, ii = { class: "modal-content" }, oi = /* @__PURE__ */ M("img", { 1516 | class: "shareIOS", 1517 | src: Be, 1518 | alt: "share IOS" 1519 | }, null, -1), ai = /* @__PURE__ */ M("img", { 1520 | class: "addIOS", 1521 | src: Ze, 1522 | alt: "add IOS" 1523 | }, null, -1); 1524 | function ri(n, b, h, m, v, y) { 1525 | return Me(), ze("div", Ge, [ 1526 | M("div", { 1527 | class: Le([ 1528 | "add-to-homescreen-container", 1529 | n.opened ? "add-to-homescreen-visible" : "add-to-homescreen-hidden" 1530 | ]) 1531 | }, [ 1532 | M("div", Qe, [ 1533 | M("div", We, [ 1534 | M("span", { 1535 | class: "icon", 1536 | style: R(n.iconStyle) 1537 | }, [ 1538 | n.getOpt("iconPath") ? De("", !0) : (Me(), ze(Ie, { key: 0 }, [ 1539 | te(U(n.firstCharTitle), 1) 1540 | ], 64)) 1541 | ], 4) 1542 | ]), 1543 | M("div", Fe, [ 1544 | M("span", { 1545 | class: "app-title", 1546 | style: R(n.getCssOpt("titleColor")) 1547 | }, U(n.getOpt("title") ? n.getOpt("title") : n.appTitle), 5), 1548 | Ye, 1549 | M("span", { 1550 | class: "app-content", 1551 | style: R({ color: n.getCssOpt("contentColor") }), 1552 | innerHTML: n.getOpt("content") || n.appUrl 1553 | }, null, 12, Ke) 1554 | ]) 1555 | ]), 1556 | M("div", Je, [ 1557 | M("div", Xe, [ 1558 | M("div", $e, [ 1559 | M("button", { 1560 | onClick: b[0] || (b[0] = (...w) => n.addToHomescreen && n.addToHomescreen(...w)), 1561 | class: "add-button", 1562 | style: R(n.buttonStyle) 1563 | }, U(n.t("addToHomescreen")), 5) 1564 | ]) 1565 | ]) 1566 | ]), 1567 | M("button", { 1568 | class: "close_btn", 1569 | onClick: b[1] || (b[1] = (...w) => n.close && n.close(...w)) 1570 | }) 1571 | ], 2), 1572 | M("div", ei, [ 1573 | M("div", ii, [ 1574 | M("ul", null, [ 1575 | M("li", null, [ 1576 | te(U(n.t("addMessages.ios1")) + " ", 1), 1577 | oi 1578 | ]), 1579 | M("li", null, [ 1580 | te(U(n.t("addMessages.ios2")) + " ", 1), 1581 | ai 1582 | ]) 1583 | ]), 1584 | M("button", { 1585 | class: "closeModal", 1586 | style: R(n.buttonStyle), 1587 | label: "OK", 1588 | onClick: b[2] || (b[2] = (...w) => n.closeModal && n.closeModal(...w)) 1589 | }, " OK ", 4) 1590 | ]) 1591 | ]) 1592 | ]); 1593 | } 1594 | const ni = /* @__PURE__ */ Ve(qe, [["render", ri]]), ti = () => { 1595 | const n = ["file:", "cordova:", "capacitor:"]; 1596 | return window.matchMedia("(display-mode: standalone)").matches || window.location && window.location.protocol && n.indexOf(window.location.protocol) !== -1; 1597 | }; 1598 | function si(n) { 1599 | if (!ti() || !de.get("addToHomescreenCalled")) { 1600 | const b = Oe(ni, n), h = document.createElement("div"); 1601 | return document.body.appendChild(h), Ae(b, h), b.component; 1602 | } 1603 | } 1604 | const li = { 1605 | install(n, b) { 1606 | si(b); 1607 | } 1608 | }; 1609 | export { 1610 | li as default, 1611 | si as useAddToHomescreen 1612 | }; 1613 | -------------------------------------------------------------------------------- /dist/vue-addtohomescreen.umd.js: -------------------------------------------------------------------------------- 1 | (function(){"use strict";try{if(typeof document!="undefined"){var e=document.createElement("style");e.appendChild(document.createTextNode(".add-to-homescreen-plugin-container .add-to-homescreen-container{z-index:10000;border-top:1px solid #e0e0e0;font-family:-apple-system,BlinkMacSystemFont,Roboto,sans-serif;width:100%;box-sizing:border-box;background:white;position:fixed;bottom:0;left:0;padding:16px;align-items:center;transition:all .5s}.add-to-homescreen-plugin-container .add-to-homescreen-container.add-to-homescreen-visible{transform:translateY(0)}.add-to-homescreen-plugin-container .add-to-homescreen-container.add-to-homescreen-hidden{transform:translateY(100%)}.add-to-homescreen-plugin-container button{cursor:pointer}.add-to-homescreen-plugin-container .close_btn{cursor:pointer;position:absolute;top:15px;right:15px;width:20px;height:20px;border:0;background:url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIyNCIgaGVpZ2h0PSIyNCIgdmlld0JveD0iMCAwIDI0IDI0IiBmaWxsPSJub25lIiBzdHJva2U9ImN1cnJlbnRDb2xvciIgc3Ryb2tlLXdpZHRoPSIyIiBzdHJva2UtbGluZWNhcD0icm91bmQiIHN0cm9rZS1saW5lam9pbj0icm91bmQiIGNsYXNzPSJmZWF0aGVyIGZlYXRoZXIteCI+PGxpbmUgeDE9IjE4IiB5MT0iNiIgeDI9IjYiIHkyPSIxOCI+PC9saW5lPjxsaW5lIHgxPSI2IiB5MT0iNiIgeDI9IjE4IiB5Mj0iMTgiPjwvbGluZT48L3N2Zz4=)}.add-to-homescreen-plugin-container .flex{display:flex;flex-wrap:wrap}.add-to-homescreen-plugin-container .col{flex:1}.add-to-homescreen-plugin-container .icon{background-size:contain;background-repeat:no-repeat;background-position:center}.add-to-homescreen-plugin-container .icon-container .icon{width:60px;height:60px;display:block;line-height:60px;text-align:center;border-radius:30px;font-size:1.3rem;margin-right:15px;text-transform:uppercase}.add-to-homescreen-plugin-container .app-title{font-size:1.3rem;display:inline-block}.add-to-homescreen-plugin-container .app-content{font-size:.8rem;display:inline-block}.add-to-homescreen-plugin-container .btn-container{float:right}.add-to-homescreen-plugin-container .add-button,.add-to-homescreen-plugin-container .add-button:hover,.add-to-homescreen-plugin-container .add-button:visited{width:100%;border:0;outline:0;font-size:1rem;padding:5px}.add-to-homescreen-plugin-container .close:hover,.add-to-homescreen-plugin-container .close:focus{color:#000;text-decoration:none;cursor:pointer}.add-to-homescreen-plugin-container .modal{display:none;position:fixed;z-index:10000;left:0;top:0;width:100%;height:100%;background-color:#0006}.add-to-homescreen-plugin-container .modal-content{background-color:#fff;border-radius:1rem;text-align:center;margin:50% auto;border:1px solid #27e9b8;width:80%}.add-to-homescreen-plugin-container .modal-content ul{padding:0 0 0 15px;text-align:left;list-style-type:none}.add-to-homescreen-plugin-container .shareIOS,.add-to-homescreen-plugin-container .addIOS{width:20px;vertical-align:top}.add-to-homescreen-plugin-container .modal-content .closeModal{border:0;outline:0;font-size:1rem;padding:5px;margin-bottom:15px}")),document.head.appendChild(e)}}catch(n){console.error("vite-plugin-css-injected-by-js",n)}})(); 2 | (function(x,t){typeof exports=="object"&&typeof module<"u"?t(exports,require("vue")):typeof define=="function"&&define.amd?define(["exports","vue"],t):(x=typeof globalThis<"u"?globalThis:x||self,t(x["vue-addtohomescreen"]={},x.Vue))})(this,function(x,t){"use strict";/*! js-cookie v3.0.1 | MIT */function R(n){for(var w=1;w"u")){p=R({},w,p),typeof p.expires=="number"&&(p.expires=new Date(Date.now()+p.expires*864e5)),p.expires&&(p.expires=p.expires.toUTCString()),y=encodeURIComponent(y).replace(/%(2[346B]|5E|60|7C)/g,decodeURIComponent).replace(/[()]/g,escape);var z="";for(var N in p)p[N]&&(z+="; "+N,p[N]!==!0&&(z+="="+p[N].split(";")[0]));return document.cookie=y+"="+n.write(k,y)+z}}function g(y){if(!(typeof document>"u"||arguments.length&&!y)){for(var k=document.cookie?document.cookie.split("; "):[],p={},z=0;z{const n=["file:","cordova:","capacitor:"];return window.matchMedia("(display-mode: standalone)").matches||window.location&&window.location.protocol&&n.indexOf(window.location.protocol)!==-1};var Me=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{},U={},ze={get exports(){return U},set exports(n){U=n}};(function(n,w){(function(v,g){var y="1.0.33",k="",p="?",z="function",N="undefined",L="object",S="string",D="major",o="model",a="name",e="type",i="vendor",r="version",l="architecture",f="console",s="mobile",d="tablet",j="smarttv",O="wearable",se="embedded",J=350,X="Amazon",V="Apple",de="ASUS",le="BlackBerry",I="Browser",H="Chrome",Qe="Edge",q="Firefox",B="Google",ce="Huawei",$="LG",ee="Microsoft",ue="Motorola",Z="Opera",ie="Samsung",be="Sharp",G="Sony",oe="Xiaomi",ae="Zebra",we="Facebook",We=function(c,m){var u={};for(var M in c)m[M]&&m[M].length%2===0?u[M]=m[M].concat(c[M]):u[M]=c[M];return u},Q=function(c){for(var m={},u=0;u0?h.length===2?typeof h[1]==z?this[h[0]]=h[1].call(this,C):this[h[0]]=h[1]:h.length===3?typeof h[1]===z&&!(h[1].exec&&h[1].test)?this[h[0]]=C?h[1].call(this,C,h[2]):g:this[h[0]]=C?C.replace(h[1],h[2]):g:h.length===4&&(this[h[0]]=C?h[3].call(this,C.replace(h[1],h[2])):g):this[h]=C||g;u+=2}},ne=function(c,m){for(var u in m)if(typeof m[u]===L&&m[u].length>0){for(var M=0;MJ?re(b,J):b,this},this.setUA(u),this};T.VERSION=y,T.BROWSER=Q([a,r,D]),T.CPU=Q([l]),T.DEVICE=Q([o,i,e,f,s,j,d,O,se]),T.ENGINE=T.OS=Q([a,r]),n.exports&&(w=n.exports=T),w.UAParser=T;var E=typeof v!==N&&(v.jQuery||v.Zepto);if(E&&!E.ua){var W=new T;E.ua=W.getResult(),E.ua.get=function(){return W.getUA()},E.ua.set=function(c){W.setUA(c);var m=W.getResult();for(var u in m)E.ua[u]=m[u]}}})(typeof window=="object"?window:Me)})(ze,U);const Ne=U,Se=t.defineComponent({name:"addToHomescreen",props:{title:{type:String,required:!1},content:{type:String,required:!1},titleColor:{type:String,required:!1},contentColor:{type:String,required:!1},iconPath:{type:String,required:!1},iconColor:{type:String,required:!1},iconTextColor:{type:String,required:!1},buttonColor:{type:String,required:!1},buttonTextColor:{type:String,required:!1},background:{type:String,required:!1},lang:{type:String,required:!1},expires:{type:Number,required:!1}},setup(n){const w=l=>n?n[l]:void 0,v=l=>{const f=n?n[l]:l;return f&&typeof f=="string"?f:l},g=w("lang")||"en_GB",y=ye[g],k=l=>l.split(".").reduce((f,s)=>{if(f)return f[s]},y),p=t.ref(),z=t.computed(()=>document.title),N=t.computed(()=>window.location.href),L=t.computed(()=>z.value.substring(0,1)),S=t.ref(!1),D=()=>{let l=new Date;const f=n.expires||365;l.setDate(l.getDate()+f),K.set("addToHomescreenCalled","true",{expires:l})},o=t.computed(()=>{const l=w("iconColor"),f=w("iconPath"),s=w("iconTextColor");return{backgroundColor:l&&typeof l=="string"?l:"transparent",backgroundImage:f?"url("+w("iconPath")+")":"none",color:s&&typeof s=="string"?s:"black"}}),a=t.computed(()=>{const l=w("buttonTextColor"),f=w("buttonColor");return{color:l&&l==="string"?l:"white",backgroundColor:f&&typeof f=="string"?f:"black"}}),e=()=>{D(),S.value=!1},i=()=>{const l=document.getElementById("IOSmodal");l&&(l.style.display="none")},r=()=>{const f=new Ne().getResult(),s={os:f.os.name,browser:f.browser.name},d=document.getElementById("IOSmodal");p.value?p.value.prompt():s.os==="iOS"?d&&(d.style.display="block"):s.os==="Android"?alert(k("addMessages.android")):s.os==="Windows"&&(s.browser==="Chrome"||s.browser==="Edge")?alert(k("addMessages.windows.chrome")):s.os==="Windows"&&s.browser==="Firefox"?alert(k("addMessages.windows.firefox")):s.os==="Mac OS"?"ontouchstart"in window||navigator.maxTouchPoints>0?d&&(d.style.display="block"):s.browser==="Firefox"?alert(k("addMessages.macos.firefox")):s.browser==="Chrome"?alert(k("addMessages.macos.chrome")):s.browser==="Safari"&&alert(k("addMessages.macos.safari")):alert(k("addMessages.others")),S.value=!1};return t.onMounted(()=>{window.addEventListener("beforeinstallprompt",f=>{f.preventDefault(),p.value=f});const l=K.get("addToHomescreenCalled");!ke()&&!l&&(S.value=!0,D())}),{t:k,addToHomescreen:r,closeModal:i,close:e,buttonStyle:a,iconStyle:o,getCssOpt:v,getOpt:w,appUrl:N,firstCharTitle:L,appTitle:z,opened:S}}}),je="data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iaXNvLTg4NTktMSI/Pg0KPCEtLSBHZW5lcmF0b3I6IEFkb2JlIElsbHVzdHJhdG9yIDE3LjEuMCwgU1ZHIEV4cG9ydCBQbHVnLUluIC4gU1ZHIFZlcnNpb246IDYuMDAgQnVpbGQgMCkgIC0tPg0KPCFET0NUWVBFIHN2ZyBQVUJMSUMgIi0vL1czQy8vRFREIFNWRyAxLjEvL0VOIiAiaHR0cDovL3d3dy53My5vcmcvR3JhcGhpY3MvU1ZHLzEuMS9EVEQvc3ZnMTEuZHRkIj4NCjxzdmcgdmVyc2lvbj0iMS4xIiBpZD0iQ2FwYV8xIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB4PSIwcHgiIHk9IjBweCINCgkgdmlld0JveD0iMCAwIDMzMy4zMjQgMzMzLjMyNCIgc3R5bGU9ImVuYWJsZS1iYWNrZ3JvdW5kOm5ldyAwIDAgMzMzLjMyNCAzMzMuMzI0OyIgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+DQo8Zz4NCgk8cGF0aCBzdHlsZT0iZmlsbDojMjIyMjIwOyIgZD0iTTEyNS4yNTUsNTkuNTEzbDMzLjkwNy0zMy45MDd2MTQ5LjQ1MWMwLDQuMTQzLDMuMzU4LDcuNSw3LjUsNy41czcuNS0zLjM1Nyw3LjUtNy41VjI1LjYwNg0KCQlsMzMuOTA3LDMzLjkwN2MxLjQ2NCwxLjQ2NCwzLjM4NCwyLjE5Niw1LjMwMywyLjE5NnMzLjgzOS0wLjczMiw1LjMwMy0yLjE5NmMyLjkyOS0yLjkzLDIuOTI5LTcuNjc4LDAtMTAuNjA3bC00Ni43MS00Ni43MQ0KCQljLTIuOTI5LTIuOTI4LTcuNjc4LTIuOTI4LTEwLjYwNiwwbC00Ni43MSw0Ni43MWMtMi45MjksMi45My0yLjkyOSw3LjY3OCwwLDEwLjYwN0MxMTcuNTc3LDYyLjQ0MSwxMjIuMzI2LDYyLjQ0MSwxMjUuMjU1LDU5LjUxM3oNCgkJIi8+DQoJPHBhdGggc3R5bGU9ImZpbGw6IzIyMjIyMDsiIGQ9Ik0yNjMuMzI4LDg3LjU1N2gtNjEuNjQ1Yy00LjE0MiwwLTcuNSwzLjM1Ny03LjUsNy41czMuMzU4LDcuNSw3LjUsNy41aDU0LjE0NXYyMTUuNzY3SDc3LjQ5NQ0KCQlWMTAyLjU1N2g1NC4xNDVjNC4xNDIsMCw3LjUtMy4zNTcsNy41LTcuNXMtMy4zNTgtNy41LTcuNS03LjVINjkuOTk1Yy00LjE0MiwwLTcuNSwzLjM1Ny03LjUsNy41djIzMC43NjcNCgkJYzAsNC4xNDMsMy4zNTgsNy41LDcuNSw3LjVoMTkzLjMzM2M0LjE0MiwwLDcuNS0zLjM1Nyw3LjUtNy41Vjk1LjA1N0MyNzAuODI4LDkwLjkxNSwyNjcuNDcsODcuNTU3LDI2My4zMjgsODcuNTU3eiIvPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPGc+DQo8L2c+DQo8Zz4NCjwvZz4NCjxnPg0KPC9nPg0KPC9zdmc+DQo=",Te="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGhlaWdodD0iMjQiIHZpZXdCb3g9IjAgMCAyNCAyNCIgd2lkdGg9IjI0Ij48cGF0aCBkPSJNMCAwaDI0djI0SDBWMHoiIGZpbGw9Im5vbmUiLz48cGF0aCBkPSJNMTkgM0g1Yy0xLjExIDAtMiAuOS0yIDJ2MTRjMCAxLjEuODkgMiAyIDJoMTRjMS4xIDAgMi0uOSAyLTJWNWMwLTEuMS0uOS0yLTItMnptMCAxNkg1VjVoMTR2MTR6bS04LTJoMnYtNGg0di0yaC00VjdoLTJ2NEg3djJoNHoiLz48L3N2Zz4=",Ke="",Ce=(n,w)=>{const v=n.__vccOpts||n;for(const[g,y]of w)v[g]=y;return v},xe={class:"add-to-homescreen-plugin-container"},Le={class:"flex"},Ie={class:"icon-container"},Ee={class:"col"},De=t.createElementVNode("br",null,null,-1),Oe=["innerHTML"],Ae={class:"flex"},_e={class:"col"},Pe={class:"btn-container"},Re={id:"IOSmodal",class:"modal add-to-homescreen-visible"},Ue={class:"modal-content"},Ve=t.createElementVNode("img",{class:"shareIOS",src:je,alt:"share IOS"},null,-1),He=t.createElementVNode("img",{class:"addIOS",src:Te,alt:"add IOS"},null,-1);function qe(n,w,v,g,y,k){return t.openBlock(),t.createElementBlock("div",xe,[t.createElementVNode("div",{class:t.normalizeClass(["add-to-homescreen-container",n.opened?"add-to-homescreen-visible":"add-to-homescreen-hidden"])},[t.createElementVNode("div",Le,[t.createElementVNode("div",Ie,[t.createElementVNode("span",{class:"icon",style:t.normalizeStyle(n.iconStyle)},[n.getOpt("iconPath")?t.createCommentVNode("",!0):(t.openBlock(),t.createElementBlock(t.Fragment,{key:0},[t.createTextVNode(t.toDisplayString(n.firstCharTitle),1)],64))],4)]),t.createElementVNode("div",Ee,[t.createElementVNode("span",{class:"app-title",style:t.normalizeStyle(n.getCssOpt("titleColor"))},t.toDisplayString(n.getOpt("title")?n.getOpt("title"):n.appTitle),5),De,t.createElementVNode("span",{class:"app-content",style:t.normalizeStyle({color:n.getCssOpt("contentColor")}),innerHTML:n.getOpt("content")||n.appUrl},null,12,Oe)])]),t.createElementVNode("div",Ae,[t.createElementVNode("div",_e,[t.createElementVNode("div",Pe,[t.createElementVNode("button",{onClick:w[0]||(w[0]=(...p)=>n.addToHomescreen&&n.addToHomescreen(...p)),class:"add-button",style:t.normalizeStyle(n.buttonStyle)},t.toDisplayString(n.t("addToHomescreen")),5)])])]),t.createElementVNode("button",{class:"close_btn",onClick:w[1]||(w[1]=(...p)=>n.close&&n.close(...p))})],2),t.createElementVNode("div",Re,[t.createElementVNode("div",Ue,[t.createElementVNode("ul",null,[t.createElementVNode("li",null,[t.createTextVNode(t.toDisplayString(n.t("addMessages.ios1"))+" ",1),Ve]),t.createElementVNode("li",null,[t.createTextVNode(t.toDisplayString(n.t("addMessages.ios2"))+" ",1),He])]),t.createElementVNode("button",{class:"closeModal",style:t.normalizeStyle(n.buttonStyle),label:"OK",onClick:w[2]||(w[2]=(...p)=>n.closeModal&&n.closeModal(...p))}," OK ",4)])])])}const Be=Ce(Se,[["render",qe]]),Ze=()=>{const n=["file:","cordova:","capacitor:"];return window.matchMedia("(display-mode: standalone)").matches||window.location&&window.location.protocol&&n.indexOf(window.location.protocol)!==-1};function te(n){if(!Ze()||!K.get("addToHomescreenCalled")){const w=t.h(Be,n),v=document.createElement("div");return document.body.appendChild(v),t.render(w,v),w.component}}const Ge={install(n,w){te(w)}};x.default=Ge,x.useAddToHomescreen=te,Object.defineProperties(x,{__esModule:{value:!0},[Symbol.toStringTag]:{value:"Module"}})}); 43 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@owliehq/vue-addtohomescreen", 3 | "version": "2.0.3", 4 | "description": "Add to homescreen prompt solution for all devices (desktop PC/OSX, IOS, Android). Now Vue3 powered (still vue2 compatible).", 5 | "keywords": [ 6 | "vuejs", 7 | "addtohomescreen", 8 | "pwa" 9 | ], 10 | "author": "Jordan Matejicek ", 11 | "license": "MIT", 12 | "main": "dist/vue-addtohomescreen.mjs", 13 | "scripts": { 14 | "dev": "vite", 15 | "build": "vue-tsc --noEmit && vite build --emptyOutDir", 16 | "preview": "vite preview" 17 | }, 18 | "devDependencies": { 19 | "@rollup/plugin-node-resolve": "^15.0.1", 20 | "@types/js-cookie": "^3.0.2", 21 | "@types/node": "^18.11.18", 22 | "@types/ua-parser-js": "^0.7.36", 23 | "@typescript-eslint/eslint-plugin": "^5.48.2", 24 | "@typescript-eslint/parser": "^5.48.2", 25 | "@vitejs/plugin-vue": "^4.0.0", 26 | "eslint": "^8.31.0", 27 | "eslint-config-prettier": "^8.6.0", 28 | "eslint-config-standard-with-typescript": "^26.0.0", 29 | "eslint-plugin-import": "^2.25.2", 30 | "eslint-plugin-n": "^15.0.0", 31 | "eslint-plugin-promise": "^6.0.0", 32 | "eslint-plugin-vue": "^9.8.0", 33 | "prettier": "^2.8.2", 34 | "sass": "^1.57.1", 35 | "typescript": "*", 36 | "vite": "^4.0.4", 37 | "vite-plugin-css-injected-by-js": "^2.4.0", 38 | "vue": "^3.2.45", 39 | "vue-tsc": "^1.0.24" 40 | }, 41 | "dependencies": { 42 | "js-cookie": "^3.0.1", 43 | "ua-parser-js": "^1.0.33" 44 | }, 45 | "repository": { 46 | "type": "git", 47 | "url": "git+https://github.com/owliehq/vue-addtohomescreen.git" 48 | }, 49 | "bugs": { 50 | "url": "https://github.com/owliehq/vue-addtohomescreen/issues" 51 | }, 52 | "homepage": "https://github.com/owliehq/vue-addtohomescreen#readme" 53 | } 54 | -------------------------------------------------------------------------------- /src/addToHomescreen.vue: -------------------------------------------------------------------------------- 1 | 69 | 70 | 292 | 293 | 433 | -------------------------------------------------------------------------------- /src/assets/addios.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/assets/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/owliehq/vue-addtohomescreen/949b5ad2af285c593a51fba4136cc219ae7c94ec/src/assets/logo.png -------------------------------------------------------------------------------- /src/assets/shareios.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 6 | 7 | 11 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /src/assets/x.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/i18n/index.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | en_GB: { 3 | addToHomescreen: 'Add to homescreen', 4 | addMessages: { 5 | ios1: '1. On Safari browser, open Share menu', 6 | ios2: '2. Tap on "Add to Home Screen" button', 7 | android: `1. Open browser parameters 8 | 2. Tap on "Add to homescreen"`, 9 | windows: { 10 | chrome: 'Click on (+) button to the right of your navigation bar.', 11 | firefox: `1. Resize your browser so you can see your desktop 12 | 2. Drag and drop the (i) button left of your navigation bar to your desktop`, 13 | }, 14 | macos: { 15 | chrome: 'Click on (+) button to the right of your navigation bar.', 16 | safari: `1. Resize your browser so you can see your desktop 17 | 2. Drag & drop the earth icon left of your notification bar to your desktop`, 18 | firefox: `1. Resize your browser so you can see your desktop 19 | 2. Drag and drop the (i) button left of your navigation bar to your desktop`, 20 | }, 21 | others: 22 | "Looks like your browser doesn't support add to homescreen natively. Feel free to update/change your browser.", 23 | }, 24 | }, 25 | fr_FR: { 26 | addToHomescreen: "Installer l'application", 27 | addMessages: { 28 | ios1: '1. Sur le navigateur Safari, ouvrir le menu de partage', 29 | ios2: '2. Appuyez sur le bouton "Sur l\'écran d\'accueil"', 30 | android: `1. Ouvrez les paramètres de la page 31 | 2. Appuyez sur le bouton "Ajouter à l'écran d'accueil"`, 32 | windows: { 33 | chrome: 34 | 'Cliquez sur le bouton (+) présent à droite dans votre barre de navigation', 35 | firefox: `1. Redimensionnez votre navigateur pour voir votre bureau 36 | 2. Cliquez & glissez l'icône (i) présent à gauche de votre barre de navigation sur votre bureau`, 37 | }, 38 | macos: { 39 | chrome: 40 | 'Cliquez sur le bouton (+) présent à droite dans votre barre de navigation', 41 | safari: `1. Redimensionnez votre navigateur pour voir votre bureau 42 | 2. Cliquez & glissez l'icône 'terre' présent à gauche de votre barre de navigation sur votre bureau`, 43 | firefox: `1. Redimensionnez votre navigateur pour voir votre bureau 44 | 2. Cliquez & glissez l'icône (i) présent à gauche de votre barre de navigation sur votre bureau`, 45 | }, 46 | others: 47 | "Il semblerait que votre navigateur ne supporte pas la fonctionnalité d'ajout à la page d'accueil. Mettez-le à jour ou changez de navigateur.", 48 | }, 49 | }, 50 | ru_RU: { 51 | addToHomescreen: 'Добавить на рабочий стол', 52 | addMessages: { 53 | ios1: '1. Откройте меню «Поделиться»', 54 | ios2: '2. Нажмите на кнопку «Добавить на главный экран»', 55 | android: `1. Откройте параметры браузера. 56 | 2. Нажмите «Добавить на рабочий стол»`, 57 | windows: { 58 | chrome: 'Нажмите кнопку (+) справа от панели навигации.', 59 | firefox: `1. Измените размер браузера, чтобы Вы могли видеть свой рабочий стол 60 | 2. Перетащите кнопку (i) слева от панели навигации на рабочий стол.`, 61 | }, 62 | macos: { 63 | chrome: 'Нажмите кнопку (+) справа от панели навигации', 64 | safari: `1. Измените размер браузера, чтобы Вы могли видеть свой рабочий стол 65 | 2. Перетащите значок "Земля" слева от панели уведомлений на рабочий стол`, 66 | firefox: `1. Измените размер браузера, чтобы Вы могли видеть свой рабочий стол 67 | 2. Перетащите кнопку (i) слева от панели навигации на рабочий стол.`, 68 | }, 69 | others: 70 | 'Похоже, Ваш браузер изначально не поддерживает добавление на рабочий стол. Попробуйте обновить/изменить свой браузер.', 71 | }, 72 | }, 73 | de_DE: { 74 | addToHomescreen: 'Zum Home-Bildschrim hinzufügen', 75 | addMessages: { 76 | ios1: '1. Öffnen Sie im Safari-Browser das Teilen-Menü', 77 | ios2: '2. Tippen Sie auf die Schaltfläche "Zum Home-Bildschrim hinzufügen"', 78 | android: `1. Öffnen Sie die Browsereinstellungen 79 | 2. Tippen Sie auf "Zum Home-Bildschrim hinzufügen"`, 80 | windows: { 81 | chrome: 'Klicken Sie auf die (+) Schaltfläche rechts neben Ihrer Navigationsleiste.', 82 | firefox: `1. Ändern Sie die Größe Ihres Browsers, sodass Sie Ihren Desktop sehen können 83 | 2. Ziehen Sie die (i)-Schaltfläche links von der Navigationsleiste auf Ihren Desktop`, 84 | }, 85 | macos: { 86 | chrome: 'Klicken Sie auf die (+) Schaltfläche rechts neben Ihrer Navigationsleiste.', 87 | safari: `1. Ändern Sie die Größe Ihres Browsers, sodass Sie Ihren Desktop sehen können 88 | 2. Ziehen Sie das Erdensymbol links neben Ihrer Benachrichtigungsleiste auf Ihren Desktop`, 89 | firefox: `1. Ändern Sie die Größe Ihres Browsers, sodass Sie Ihren Desktop sehen können 90 | 2. Ziehen Sie die (i)-Schaltfläche links von der Navigationsleiste auf Ihren Desktop`, 91 | }, 92 | others: 93 | 'Es scheint, dass Ihr Browser das Hinzufügen zum Home-Bildschrim nicht nativ unterstützt. Fühlen Sie sich frei, Ihren Browser zu aktualisieren/zu wechseln.', 94 | }, 95 | }, 96 | es_ES: { 97 | addToHomescreen: 'Añadir a la pantalla de inicio', 98 | addMessages: { 99 | ios1: '1. En el navegador Safari, abre el menú Compartir', 100 | ios2: '2. Toca el botón "Añadir a la pantalla de inicio"', 101 | android: `1. Abre los ajustes del navegador 102 | 2. Toca en "Añadir a la pantalla de inicio"`, 103 | windows: { 104 | chrome: 'Haz clic en el botón (+) a la derecha de tu barra de navegación.', 105 | firefox: `1. Redimensiona tu navegador para que puedas ver tu escritorio 106 | 2. Arrastra y suelta el botón (i) a la izquierda de tu barra de navegación a tu escritorio`, 107 | }, 108 | macos: { 109 | chrome: 'Haz clic en el botón (+) a la derecha de tu barra de navegación.', 110 | safari: `1. Redimensiona tu navegador para que puedas ver tu escritorio 111 | 2. Arrastra y suelta el icono de la Tierra a la izquierda de tu barra de notificaciones a tu escritorio`, 112 | firefox: `1. Redimensiona tu navegador para que puedas ver tu escritorio 113 | 2. Arrastra y suelta el botón (i) a la izquierda de tu barra de navegación a tu escritorio`, 114 | }, 115 | others: 116 | 'Parece que tu navegador no admite la función de añadir a la pantalla de inicio de forma nativa. Siéntete libre de actualizar o cambiar tu navegador.', 117 | }, 118 | }, 119 | pt_PT: { 120 | addToHomescreen: 'Adicionar à tela inicial', 121 | addMessages: { 122 | ios1: '1. No navegador Safari, abra o menu Compartilhar', 123 | ios2: '2. Toque no botão "Adicionar à tela inicial"', 124 | android: `1. Abra as configurações do navegador 125 | 2. Toque em "Adicionar à tela inicial"`, 126 | windows: { 127 | chrome: 'Clique no botão (+) à direita da barra de navegação.', 128 | firefox: `1. Redimensione o navegador para visualizar a área de trabalho 129 | 2. Arraste e solte o botão (i) à esquerda da barra de navegação para a área de trabalho`, 130 | }, 131 | macos: { 132 | chrome: 'Clique no botão (+) à direita da barra de navegação.', 133 | safari: `1. Redimensione o navegador para visualizar a área de trabalho 134 | 2. Arraste e solte o ícone da Terra à esquerda da barra de notificações para a área de trabalho`, 135 | firefox: `1. Redimensione o navegador para visualizar a área de trabalho 136 | 2. Arraste e solte o botão (i) à esquerda da barra de navegação para a área de trabalho`, 137 | }, 138 | others: 139 | 'Parece que seu navegador não suporta adicionar à tela inicial de forma nativa. Sinta-se à vontade para atualizar ou alterar o navegador.', 140 | }, 141 | }, 142 | nl_NL: { 143 | addToHomescreen: 'Toevoegen aan startscherm', 144 | addMessages: { 145 | ios1: '1. Open in de Safari-browser het deelmenu', 146 | ios2: '2. Tik op de knop "Aan startscherm toevoegen"', 147 | android: `1. Open browserinstellingen 148 | 2. Tik op "Toevoegen aan startscherm"`, 149 | windows: { 150 | chrome: 'Klik op de (+) knop rechts van uw navigatiebalk.', 151 | firefox: `1. Verander het formaat van uw browser zodat u uw bureaublad kunt zien 152 | 2. Sleep het (i)-pictogram links van uw navigatiebalk naar uw bureaublad`, 153 | }, 154 | macos: { 155 | chrome: 'Klik op de (+) knop rechts van uw navigatiebalk.', 156 | safari: `1. Verander het formaat van uw browser zodat u uw bureaublad kunt zien 157 | 2. Sleep het aarde-icoon links van uw notificatiebalk naar uw bureaublad`, 158 | firefox: `1. Verander het formaat van uw browser zodat u uw bureaublad kunt zien 159 | 2. Sleep het (i)-pictogram links van uw navigatiebalk naar uw bureaublad`, 160 | }, 161 | others: 162 | 'Het lijkt erop dat uw browser niet native de functie "Toevoegen aan startscherm" ondersteunt. Voel je vrij om je browser bij te werken of te veranderen.', 163 | } 164 | }, 165 | pl_PL: { 166 | addToHomescreen: 'Dodaj do ekranu głównego', 167 | addMessages: { 168 | ios1: '1. W przeglądarce Safari otwórz menu Udostępnij', 169 | ios2: '2. Stuknij przycisk "Dodaj do ekranu głównego"', 170 | android: `1. Otwórz ustawienia przeglądarki 171 | 2. Stuknij "Dodaj do ekranu głównego"`, 172 | windows: { 173 | chrome: 'Kliknij przycisk (+) po prawej stronie paska nawigacji.', 174 | firefox: `1. Zmień rozmiar przeglądarki, aby zobaczyć pulpit 175 | 2. Przeciągnij i upuść przycisk (i) po lewej stronie paska nawigacji na pulpit`, 176 | }, 177 | macos: { 178 | chrome: 'Kliknij przycisk (+) po prawej stronie paska nawigacji.', 179 | safari: `1. Zmień rozmiar przeglądarki, aby zobaczyć pulpit 180 | 2. Przeciągnij i upuść ikonę ziemi po lewej stronie paska powiadomień na pulpit`, 181 | firefox: `1. Zmień rozmiar przeglądarki, aby zobaczyć pulpit 182 | 2. Przeciągnij i upuść przycisk (i) po lewej stronie paska nawigacji na pulpit`, 183 | }, 184 | others: 185 | 'Wygląda na to, że Twoja przeglądarka nie obsługuje natywnie dodawania do ekranu głównego. Śmiało zaktualizuj lub zmień przeglądarkę.', 186 | } 187 | }, 188 | ja_JP: { 189 | addToHomescreen: 'ホーム画面に追加', 190 | addMessages: { 191 | ios1: '1. Safariブラウザで共有メニューを開く', 192 | ios2: '2. "ホーム画面に追加"ボタンをタップする', 193 | android: `1. ブラウザの設定を開く 194 | 2. "ホーム画面に追加"をタップする`, 195 | windows: { 196 | chrome: 'ナビゲーションバーの右側にある (+) ボタンをクリックします。', 197 | firefox: `1. デスクトップが見えるようにブラウザのサイズを変更する 198 | 2. ナビゲーションバーの左側にある (i) ボタンをデスクトップにドラッグ&ドロップする`, 199 | }, 200 | macos: { 201 | chrome: 'ナビゲーションバーの右側にある (+) ボタンをクリックします。', 202 | safari: `1. デスクトップが見えるようにブラウザのサイズを変更する 203 | 2. 通知バーの左側にある地球のアイコンをデスクトップにドラッグ&ドロップする`, 204 | firefox: `1. デスクトップが見えるようにブラウザのサイズを変更する 205 | 2. ナビゲーションバーの左側にある (i) ボタンをデスクトップにドラッグ&ドロップする`, 206 | }, 207 | others: 208 | 'お使いのブラウザはホーム画面に追加をネイティブにサポートしていないようです。ブラウザを更新/変更してください。', 209 | }, 210 | }, 211 | zh_CN: { 212 | addToHomescreen: '添加到主屏幕', 213 | addMessages: { 214 | ios1: '1. 在 Safari 浏览器中打开分享菜单', 215 | ios2: '2. 点击"添加到主屏幕"按钮', 216 | android: `1. 打开浏览器设置 217 | 2. 点击"添加到主屏幕"`, 218 | windows: { 219 | chrome: '点击导航栏右侧的 (+) 按钮。', 220 | firefox: `1. 调整浏览器大小以便看到桌面 221 | 2. 将导航栏左侧的 (i) 按钮拖放到桌面`, 222 | }, 223 | macos: { 224 | chrome: '点击导航栏右侧的 (+) 按钮。', 225 | safari: `1. 调整浏览器大小以便看到桌面 226 | 2. 将通知栏左侧的地球图标拖放到桌面`, 227 | firefox: `1. 调整浏览器大小以便看到桌面 228 | 2. 将导航栏左侧的 (i) 按钮拖放到桌面`, 229 | }, 230 | others: 231 | '看起来您的浏览器不支持原生添加到主屏幕功能。请随时更新/更换浏览器。', 232 | }, 233 | }, 234 | id_ID: { 235 | addToHomescreen: 'Pasang Aplikasi', 236 | addMessages: { 237 | ios1: '1. Pada peramban Safari, klik tombol "Bagikan', 238 | ios2: '2. Pilih opsi "Tambahkan ke Layar Beranda"', 239 | android: `1. Buka menu peramban 240 | 2. Pilih opsi "Tambahkan ke Layar Beranda"`, 241 | windows: { 242 | chrome: 'Klik tombol (+) di sebelah kanan navigation bar.', 243 | firefox: `1. Ubah ukuran jendela peramban hingga desktop Anda terlihat 244 | 2. Seret dan lepas tombol (i) di sebelah kiri navigation bar ke desktop Anda`, 245 | }, 246 | macos: { 247 | chrome: 'Klik tombol (+) di sebelah kanan navigation bar.', 248 | safari: `1. Ubah ukuran jendela peramban hingga desktop Anda terlihat 249 | 2. Seret & lepas ikon bumi di kiri bilah notifikasi ke desktop Anda`, 250 | firefox: `1. Ubah ukuran jendela peramban hingga desktop Anda terlihat 251 | 2. Seret dan lepas tombol (i) di sebelah kiri navigation bar ke desktop Anda`, 252 | }, 253 | others: 254 | "Sepertinya browser Anda tidak mendukung penambahan ke layar beranda. Jangan ragu untuk memperbarui/mengubah browser Anda.", 255 | }, 256 | }, 257 | }; 258 | -------------------------------------------------------------------------------- /src/index.ts: -------------------------------------------------------------------------------- 1 | import AddToHomescreenComponent from './addToHomescreen.vue'; 2 | import isStandalone from './utils/isStandalone'; 3 | import Cookies from 'js-cookie'; 4 | import { h, render, App, Plugin } from 'vue'; 5 | import { Props } from './types'; 6 | 7 | function useAddToHomescreen(opts: Props) { 8 | if (!isStandalone() || !Cookies.get('addToHomescreenCalled')) { 9 | const addToHomescreenNode = h(AddToHomescreenComponent, opts); 10 | const container = document.createElement('div'); 11 | document.body.appendChild(container); 12 | render(addToHomescreenNode, container); 13 | return addToHomescreenNode.component; 14 | } 15 | } 16 | 17 | const install: Plugin = { 18 | install(app: App, opts: Props) { 19 | useAddToHomescreen(opts); 20 | }, 21 | }; 22 | export default install; 23 | export { useAddToHomescreen }; 24 | -------------------------------------------------------------------------------- /src/shims/vue.d.ts: -------------------------------------------------------------------------------- 1 | declare module "*.vue" { 2 | import { defineComponent, DefineComponent } from "vue"; 3 | const component: ReturnType; 4 | export default component; 5 | } 6 | -------------------------------------------------------------------------------- /src/types/index.ts: -------------------------------------------------------------------------------- 1 | interface DeviceInfos { 2 | os?: string; 3 | browser?: string; 4 | } 5 | 6 | interface Props { 7 | title?: string; 8 | content?: string; 9 | titleColor?: string; 10 | contentColor?: string; 11 | iconPath?: string; 12 | iconColor?: string; 13 | iconTextColor?: string; 14 | buttonColor?: string; 15 | buttonTextColor?: string; 16 | background?: string; 17 | lang?: string; 18 | expires?: number; 19 | } 20 | 21 | type PropsKeys = keyof Props; 22 | 23 | enum availableLang { 24 | en_GB = 'en_GB', 25 | fr_FR = 'fr_FR', 26 | ru_RU = 'ru_RU', 27 | } 28 | 29 | export { Props, PropsKeys, DeviceInfos, availableLang }; 30 | -------------------------------------------------------------------------------- /src/utils.ts: -------------------------------------------------------------------------------- 1 | export const isStandalone = () => { 2 | const webappsProtocols = ["file:", "cordova:", "capacitor:"]; 3 | return ( 4 | window.matchMedia("(display-mode: standalone)").matches || 5 | (window.location && 6 | window.location.protocol && 7 | webappsProtocols.indexOf(window.location.protocol) !== -1) 8 | ); 9 | }; 10 | /* 11 | isInWebAppiOS = (window.navigator.standalone == true); 12 | isInWebAppChrome = (window.matchMedia('(display-mode: standalone)').matches); 13 | */ 14 | -------------------------------------------------------------------------------- /src/utils/isStandalone.ts: -------------------------------------------------------------------------------- 1 | const isStandalone = () => { 2 | const webappsProtocols = ["file:", "cordova:", "capacitor:"]; 3 | return ( 4 | window.matchMedia("(display-mode: standalone)").matches || 5 | (window.location && 6 | window.location.protocol && 7 | webappsProtocols.indexOf(window.location.protocol) !== -1) 8 | ); 9 | }; 10 | 11 | export default isStandalone; 12 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "ESNext", 4 | "module": "commonjs", 5 | "esModuleInterop": true, 6 | "forceConsistentCasingInFileNames": true, 7 | "strict": true, 8 | "sourceMap": true, 9 | "skipLibCheck": true, 10 | "resolveJsonModule": true 11 | }, 12 | "include": ["src/**/*.ts", "src/**/*.d.ts", "src/**/*.tsx", "src/**/*.vue"], 13 | "exclude": ["**/node_modules"] 14 | } 15 | -------------------------------------------------------------------------------- /vite.config.ts: -------------------------------------------------------------------------------- 1 | import { defineConfig } from 'vite'; 2 | import { dirname, resolve } from 'path'; 3 | import vue from '@vitejs/plugin-vue'; 4 | import cssInjectedByJsPlugin from 'vite-plugin-css-injected-by-js'; 5 | import { nodeResolve } from '@rollup/plugin-node-resolve'; 6 | 7 | // https://vitejs.dev/config/ 8 | export default defineConfig({ 9 | plugins: [nodeResolve(), vue(), cssInjectedByJsPlugin()], 10 | root: 'src', 11 | build: { 12 | outDir: '../dist', 13 | lib: { 14 | // Could also be a dictionary or array of multiple entry points 15 | entry: resolve(__dirname, 'src/index.ts'), 16 | name: 'vue-addtohomescreen', 17 | // the proper extensions will be added 18 | fileName: 'vue-addtohomescreen', 19 | }, 20 | rollupOptions: { 21 | // make sure to externalize deps that shouldn't be bundled 22 | // into your library 23 | external: ['vue'], 24 | output: { 25 | exports: 'named', 26 | manualChunks: undefined, 27 | // Provide global variables to use in the UMD build 28 | // for externalized deps 29 | globals: { 30 | vue: 'Vue', 31 | }, 32 | }, 33 | }, 34 | }, 35 | }); 36 | --------------------------------------------------------------------------------