1. notification via SW 2.manifest json for home screen app 3. icons for mobile/desktop shortcut app
1
.gitignore
vendored
|
|
@ -1,6 +1,7 @@
|
||||||
.DS_Store
|
.DS_Store
|
||||||
node_modules
|
node_modules
|
||||||
/dist
|
/dist
|
||||||
|
*.pem
|
||||||
|
|
||||||
|
|
||||||
# local env files
|
# local env files
|
||||||
|
|
|
||||||
BIN
public/icons/icon-128x128.png
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
public/icons/icon-144x144.png
Normal file
|
After Width: | Height: | Size: 17 KiB |
BIN
public/icons/icon-152x152.png
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
public/icons/icon-192x192.png
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
public/icons/icon-384x384.png
Normal file
|
After Width: | Height: | Size: 86 KiB |
BIN
public/icons/icon-512x512.png
Normal file
|
After Width: | Height: | Size: 126 KiB |
BIN
public/icons/icon-72x72.png
Normal file
|
After Width: | Height: | Size: 6 KiB |
BIN
public/icons/icon-96x96.png
Normal file
|
After Width: | Height: | Size: 9.3 KiB |
|
|
@ -6,6 +6,16 @@
|
||||||
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
<meta name="viewport" content="width=device-width,initial-scale=1.0">
|
||||||
<link rel="icon" id="favicon" href="<%= BASE_URL %>favicon.ico">
|
<link rel="icon" id="favicon" href="<%= BASE_URL %>favicon.ico">
|
||||||
<title><%= htmlWebpackPlugin.options.title %></title>
|
<title><%= htmlWebpackPlugin.options.title %></title>
|
||||||
|
<meta name="apple-mobile-web-app-capable" content="yes">
|
||||||
|
<link rel="apple-touch-icon" href="<%= BASE_URL %>icons/icon-72x72.png" sizes="72x72">
|
||||||
|
<link rel="apple-touch-icon" href="<%= BASE_URL %>icons/icon-96x96.png" sizes="96x96">
|
||||||
|
<link rel="apple-touch-icon" href="<%= BASE_URL %>icons/icon-128x128.png" sizes="128x128">
|
||||||
|
<link rel="apple-touch-icon" href="<%= BASE_URL %>icons/icon-144x144.png" sizes="144x144">
|
||||||
|
<link rel="apple-touch-icon" href="<%= BASE_URL %>icons/icon-152x152.png" sizes="152x152">
|
||||||
|
<link rel="apple-touch-icon" href="<%= BASE_URL %>icons/icon-192x192.png" sizes="192x192">
|
||||||
|
<link rel="apple-touch-icon" href="<%= BASE_URL %>icons/icon-384x384.png" sizes="384x384">
|
||||||
|
<link rel="apple-touch-icon" href="<%= BASE_URL %>icons/icon-512x512.png" sizes="512x512">
|
||||||
|
<link rel="manifest" href="<%= BASE_URL %>manifest.json">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<noscript>
|
<noscript>
|
||||||
|
|
|
||||||
52
public/manifest.json
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
{
|
||||||
|
"id": "/",
|
||||||
|
"start_url": "/",
|
||||||
|
"name": "Convene - Chat for everyone ",
|
||||||
|
"short_name": "Convene",
|
||||||
|
"theme_color": "#FFFFFF",
|
||||||
|
"background_color": "#FFFFFF",
|
||||||
|
"display": "standalone",
|
||||||
|
"icons": [
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-72x72.png",
|
||||||
|
"sizes": "72x72",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-96x96.png",
|
||||||
|
"sizes": "96x96",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-128x128.png",
|
||||||
|
"sizes": "128x128",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-144x144.png",
|
||||||
|
"sizes": "144x144",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-152x152.png",
|
||||||
|
"sizes": "152x152",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-192x192.png",
|
||||||
|
"sizes": "192x192",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-384x384.png",
|
||||||
|
"sizes": "384x384",
|
||||||
|
"type": "image/png"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"src": "/icons/icon-512x512.png",
|
||||||
|
"sizes": "512x512",
|
||||||
|
"type": "image/png"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"splash_pages": null
|
||||||
|
}
|
||||||
0
public/sw.js
Normal file
45
src/App.vue
|
|
@ -31,7 +31,7 @@
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
import stickers from "./plugins/stickers";
|
import stickers from "./plugins/stickers";
|
||||||
import logoMixin from "./components/logoMixin";
|
import { notificationCount } from "./plugins/notificationAndServiceWorker.js"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "App",
|
name: "App",
|
||||||
|
|
@ -42,7 +42,6 @@ export default {
|
||||||
availableJsonTranslation: null
|
availableJsonTranslation: null
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
mixins: [logoMixin],
|
|
||||||
beforeMount() {
|
beforeMount() {
|
||||||
this.setDefaultLanguage();
|
this.setDefaultLanguage();
|
||||||
},
|
},
|
||||||
|
|
@ -113,43 +112,10 @@ export default {
|
||||||
|
|
||||||
// Set language
|
// Set language
|
||||||
this.$i18n.locale = this.$store.state.language || "en";
|
this.$i18n.locale = this.$store.state.language || "en";
|
||||||
},
|
|
||||||
showNotification() {
|
|
||||||
if(document.visibilityState === "visible") {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const title = this.$t('notification.title');
|
|
||||||
const notification = new Notification(title, {icon: this.logotype});
|
|
||||||
notification.onclick = () => {
|
|
||||||
notification.close();
|
|
||||||
window.parent.focus();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
requestAndShowPermission(notificationCount) {
|
|
||||||
Notification.requestPermission(function (permission) {
|
|
||||||
if(notificationCount > 0 && permission === "granted") {
|
|
||||||
this.showNotification();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
requestNotificationPermission(notificationCount) {
|
|
||||||
if ('Notification' in window) {
|
|
||||||
Notification.requestPermission().then((permission) => {
|
|
||||||
if(notificationCount > 0 && permission === 'granted') {
|
|
||||||
this.showNotification();
|
|
||||||
} else if(permission === "default") {
|
|
||||||
this.requestAndShowPermission(notificationCount);
|
|
||||||
} else {
|
|
||||||
this.requestAndShowPermission(notificationCount);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
computed: {
|
computed: {
|
||||||
notificationCount() {
|
notificationCount,
|
||||||
return this.$matrix.notificationCount
|
|
||||||
},
|
|
||||||
currentUser() {
|
currentUser() {
|
||||||
return this.$store.state.auth.user;
|
return this.$store.state.auth.user;
|
||||||
},
|
},
|
||||||
|
|
@ -217,13 +183,8 @@ export default {
|
||||||
document.getElementById("favicon").setAttribute('href', favicon);
|
document.getElementById("favicon").setAttribute('href', favicon);
|
||||||
},
|
},
|
||||||
immediate: true,
|
immediate: true,
|
||||||
},
|
|
||||||
notificationCount: {
|
|
||||||
handler(nCount) {
|
|
||||||
this.requestNotificationPermission(nCount)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,9 @@
|
||||||
"minutes": "1 minute ago | {n} minutes ago",
|
"minutes": "1 minute ago | {n} minutes ago",
|
||||||
"hours": "1 hour ago | {n} hours ago",
|
"hours": "1 hour ago | {n} hours ago",
|
||||||
"days": "1 day ago | {n} days ago"
|
"days": "1 day ago | {n} days ago"
|
||||||
}
|
},
|
||||||
|
"close": "close",
|
||||||
|
"notify": "Notify"
|
||||||
},
|
},
|
||||||
"menu": {
|
"menu": {
|
||||||
"start_private_chat": "Private chat with this user",
|
"start_private_chat": "Private chat with this user",
|
||||||
|
|
@ -353,7 +355,13 @@
|
||||||
"export_filename": "Exported chat {date}"
|
"export_filename": "Exported chat {date}"
|
||||||
},
|
},
|
||||||
"notification": {
|
"notification": {
|
||||||
"title": "New message received"
|
"title": "New message received",
|
||||||
|
"dialog" : {
|
||||||
|
"title": "Stay Connected with Chat Notifications!",
|
||||||
|
"body": "Never miss a message or important conversation again! Be notified whenever someone sends you a message or replies to your chat.",
|
||||||
|
"enable": "Enable"
|
||||||
|
},
|
||||||
|
"blocked_message": "Notifications blocked. Please reset the permissions"
|
||||||
},
|
},
|
||||||
"emoji": {
|
"emoji": {
|
||||||
"search": "Search...",
|
"search": "Search...",
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
no-gutters
|
no-gutters
|
||||||
align-content="center"
|
align-content="center"
|
||||||
v-on="$listeners"
|
v-on="$listeners"
|
||||||
|
v-show="icon === 'notifications_active' ? this.windowNotificationPermission() !== 'granted' : true"
|
||||||
>
|
>
|
||||||
<v-col cols="auto" class="me-2">
|
<v-col cols="auto" class="me-2">
|
||||||
<v-icon :size="iconSize">{{ icon }}</v-icon>
|
<v-icon :size="iconSize">{{ icon }}</v-icon>
|
||||||
|
|
@ -13,6 +14,8 @@
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script>
|
<script>
|
||||||
|
import { windowNotificationPermission } from "../plugins/notificationAndServiceWorker.js"
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "ActionRow",
|
name: "ActionRow",
|
||||||
props: {
|
props: {
|
||||||
|
|
@ -35,6 +38,9 @@ export default {
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
methods: {
|
||||||
|
windowNotificationPermission
|
||||||
|
}
|
||||||
};
|
};
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,10 @@
|
||||||
<template>
|
<template>
|
||||||
<div class="chat-root fill-height d-flex flex-column">
|
<div class="chat-root fill-height d-flex flex-column">
|
||||||
<ChatHeader class="chat-header flex-grow-0 flex-shrink-0" v-on:header-click="onHeaderClick" v-on:view-room-details="viewRoomDetails" v-if="!useFileModeNonAdmin" />
|
<ChatHeader class="chat-header flex-grow-0 flex-shrink-0"
|
||||||
|
v-on:header-click="onHeaderClick"
|
||||||
|
v-on:view-room-details="viewRoomDetails"
|
||||||
|
v-on:notify="onNotificationDialog"
|
||||||
|
v-if="!useFileModeNonAdmin" />
|
||||||
<AudioLayout ref="chatContainer" class="auto-audio-player-root" v-if="useVoiceMode" :room="room"
|
<AudioLayout ref="chatContainer" class="auto-audio-player-root" v-if="useVoiceMode" :room="room"
|
||||||
:events="events" :autoplay="!showRecorder"
|
:events="events" :autoplay="!showRecorder"
|
||||||
:timelineSet="timelineSet"
|
:timelineSet="timelineSet"
|
||||||
|
|
@ -15,10 +19,10 @@
|
||||||
<VoiceRecorder class="audio-layout" v-if="useVoiceMode" :micButtonRef="$refs.mic_button" :ptt="showRecorderPTT" :show="showRecorder"
|
<VoiceRecorder class="audio-layout" v-if="useVoiceMode" :micButtonRef="$refs.mic_button" :ptt="showRecorderPTT" :show="showRecorder"
|
||||||
v-on:close="showRecorder = false" v-on:file="onVoiceRecording" :sendTypingIndicators="useVoiceMode" />
|
v-on:close="showRecorder = false" v-on:file="onVoiceRecording" :sendTypingIndicators="useVoiceMode" />
|
||||||
|
|
||||||
<FileDropLayout class="file-drop-root" v-if="useFileModeNonAdmin" :room="room"
|
<FileDropLayout class="file-drop-root" v-if="useFileModeNonAdmin" :room="room"
|
||||||
v-on:pick-file="showAttachmentPicker()"
|
v-on:pick-file="showAttachmentPicker()"
|
||||||
v-on:add-file="addAttachment($event)"
|
v-on:add-file="addAttachment($event)"
|
||||||
v-on:remove-file="currentFileInputs.splice($event, 1)"
|
v-on:remove-file="currentFileInputs.splice($event, 1)"
|
||||||
v-on:reset="resetAttachments"
|
v-on:reset="resetAttachments"
|
||||||
:attachments="currentFileInputs"
|
:attachments="currentFileInputs"
|
||||||
/>
|
/>
|
||||||
|
|
@ -282,6 +286,46 @@
|
||||||
</v-dialog>
|
</v-dialog>
|
||||||
|
|
||||||
<CreatePollDialog :show="showCreatePollDialog" @close="showCreatePollDialog = false" />
|
<CreatePollDialog :show="showCreatePollDialog" @close="showCreatePollDialog = false" />
|
||||||
|
|
||||||
|
<!-- Dialog for request Notification and register service worker-->
|
||||||
|
<v-dialog
|
||||||
|
v-model="notificationDialog"
|
||||||
|
persistent
|
||||||
|
class="ma-0 pa-0"
|
||||||
|
:width="$vuetify.breakpoint.smAndUp ? '688px' : '95%'"
|
||||||
|
>
|
||||||
|
<div class="dialog-content text-center">
|
||||||
|
<v-icon size="30">notifications_active</v-icon>
|
||||||
|
<h2 class="dialog-title">
|
||||||
|
{{ $t("notification.dialog.title") }}
|
||||||
|
</h2>
|
||||||
|
<div class="dialog-text">{{ $t("notification.dialog.body") }}</div>
|
||||||
|
<v-container fluid>
|
||||||
|
<v-row cols="12">
|
||||||
|
<v-col cols="6">
|
||||||
|
<v-btn
|
||||||
|
depressed
|
||||||
|
text
|
||||||
|
block
|
||||||
|
class="text-button"
|
||||||
|
@click="notificationDialog = false"
|
||||||
|
>{{ $t("global.close") }}</v-btn
|
||||||
|
>
|
||||||
|
</v-col>
|
||||||
|
<v-col cols="6" align="center">
|
||||||
|
<v-btn
|
||||||
|
color="primary"
|
||||||
|
depressed
|
||||||
|
block
|
||||||
|
class="filled-button"
|
||||||
|
@click.stop="onRequestNotificationAndServiceWorker"
|
||||||
|
>{{ $t("notification.dialog.enable") }}</v-btn
|
||||||
|
>
|
||||||
|
</v-col>
|
||||||
|
</v-row>
|
||||||
|
</v-container>
|
||||||
|
</div>
|
||||||
|
</v-dialog>
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
|
|
@ -304,6 +348,8 @@ import CreatePollDialog from "./CreatePollDialog.vue";
|
||||||
import chatMixin from "./chatMixin";
|
import chatMixin from "./chatMixin";
|
||||||
import AudioLayout from "./AudioLayout.vue";
|
import AudioLayout from "./AudioLayout.vue";
|
||||||
import FileDropLayout from "./file_mode/FileDropLayout";
|
import FileDropLayout from "./file_mode/FileDropLayout";
|
||||||
|
import { requestNotificationAndServiceWorker, windowNotificationPermission, notificationCount } from "../plugins/notificationAndServiceWorker.js"
|
||||||
|
import logoMixin from "./logoMixin";
|
||||||
|
|
||||||
const sizeOf = require("image-size");
|
const sizeOf = require("image-size");
|
||||||
const dataUriToBuffer = require("data-uri-to-buffer");
|
const dataUriToBuffer = require("data-uri-to-buffer");
|
||||||
|
|
@ -339,7 +385,7 @@ ScrollPosition.prototype.prepareFor = function (direction) {
|
||||||
|
|
||||||
export default {
|
export default {
|
||||||
name: "Chat",
|
name: "Chat",
|
||||||
mixins: [chatMixin],
|
mixins: [chatMixin, logoMixin],
|
||||||
components: {
|
components: {
|
||||||
ChatHeader,
|
ChatHeader,
|
||||||
MessageOperations,
|
MessageOperations,
|
||||||
|
|
@ -433,7 +479,8 @@ export default {
|
||||||
Symbols: this.$t("emoji.categories.symbols"),
|
Symbols: this.$t("emoji.categories.symbols"),
|
||||||
Places: this.$t("emoji.categories.places")
|
Places: this.$t("emoji.categories.places")
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
|
notificationDialog: false
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
@ -470,6 +517,7 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
computed: {
|
computed: {
|
||||||
|
notificationCount,
|
||||||
nonImageFiles() {
|
nonImageFiles() {
|
||||||
return this.isCurrentFileInputsAnArray && this.currentFileInputs.filter(file => !file.type.includes("image/"))
|
return this.isCurrentFileInputsAnArray && this.currentFileInputs.filter(file => !file.type.includes("image/"))
|
||||||
},
|
},
|
||||||
|
|
@ -636,6 +684,13 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
watch: {
|
watch: {
|
||||||
|
notificationCount: {
|
||||||
|
handler(nCount) {
|
||||||
|
if (nCount > 0 && this.windowNotificationPermission() === "granted") {
|
||||||
|
this.showNotification()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
initialLoadDone: {
|
initialLoadDone: {
|
||||||
immediate: true,
|
immediate: true,
|
||||||
handler(value, oldValue) {
|
handler(value, oldValue) {
|
||||||
|
|
@ -726,6 +781,34 @@ export default {
|
||||||
},
|
},
|
||||||
|
|
||||||
methods: {
|
methods: {
|
||||||
|
windowNotificationPermission,
|
||||||
|
showNotification() {
|
||||||
|
if(document.visibilityState === "visible") {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const title = this.$t('notification.title');
|
||||||
|
const self = this;
|
||||||
|
|
||||||
|
navigator.serviceWorker.ready.then(function(registration) {
|
||||||
|
registration.showNotification(title, {
|
||||||
|
icon: self.logotype,
|
||||||
|
tag: "new-message-notification",
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
},
|
||||||
|
onNotificationDialog() {
|
||||||
|
if(this.windowNotificationPermission() === 'denied') {
|
||||||
|
alert(this.$t("notification.blocked_message"));
|
||||||
|
} else if(this.windowNotificationPermission() === 'default') {
|
||||||
|
this.notificationDialog = true;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
onRequestNotificationAndServiceWorker() {
|
||||||
|
requestNotificationAndServiceWorker()
|
||||||
|
this.notificationDialog = false;
|
||||||
|
},
|
||||||
onRoomJoined(initialEventId) {
|
onRoomJoined(initialEventId) {
|
||||||
// Was this room just created (by you)? Show a small info header in
|
// Was this room just created (by you)? Show a small info header in
|
||||||
// that case!
|
// that case!
|
||||||
|
|
@ -954,7 +1037,7 @@ export default {
|
||||||
this.handleScrolledToBottom(scrollToSeeNew);
|
this.handleScrolledToBottom(scrollToSeeNew);
|
||||||
|
|
||||||
// If kick or ban event, redirect to "goodbye"...
|
// If kick or ban event, redirect to "goodbye"...
|
||||||
if (event.getType() === "m.room.member" &&
|
if (event.getType() === "m.room.member" &&
|
||||||
event.getStateKey() == this.$matrix.currentUserId &&
|
event.getStateKey() == this.$matrix.currentUserId &&
|
||||||
(event.getPrevContent() || {}).membership == "join" &&
|
(event.getPrevContent() || {}).membership == "join" &&
|
||||||
(
|
(
|
||||||
|
|
|
||||||
|
|
@ -177,6 +177,11 @@ export default {
|
||||||
this.$emit("view-room-details", { event: this.event });
|
this.$emit("view-room-details", { event: this.event });
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
items.push({
|
||||||
|
icon: 'notifications_active', text: this.$t('global.notify'), handler: () => {
|
||||||
|
this.$emit("notify");
|
||||||
|
}
|
||||||
|
});
|
||||||
items.push({
|
items.push({
|
||||||
icon: '$vuetify.icons.ic_member-leave', text: this.$t('leave.leave'), handler: () => {
|
icon: '$vuetify.icons.ic_member-leave', text: this.$t('leave.leave'), handler: () => {
|
||||||
this.leaveRoom();
|
this.leaveRoom();
|
||||||
|
|
|
||||||
29
src/plugins/notificationAndServiceWorker.js
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
const registerServiceWorker = async () => {
|
||||||
|
const swRegistration = await navigator.serviceWorker.register("/sw.js");
|
||||||
|
return swRegistration;
|
||||||
|
};
|
||||||
|
|
||||||
|
const requestNotificationPermission = async () => {
|
||||||
|
// return value: 'granted', 'default', 'denied'
|
||||||
|
return await window.Notification.requestPermission();
|
||||||
|
};
|
||||||
|
|
||||||
|
export async function requestNotificationAndServiceWorker() {
|
||||||
|
if (!("serviceWorker" in navigator)) {
|
||||||
|
throw new Error("No Service Worker support!");
|
||||||
|
}
|
||||||
|
if (!("PushManager" in window)) {
|
||||||
|
throw new Error("No Push API Support!");
|
||||||
|
}
|
||||||
|
const permission = await requestNotificationPermission();
|
||||||
|
if(permission==='granted') await registerServiceWorker();
|
||||||
|
return permission
|
||||||
|
}
|
||||||
|
|
||||||
|
export function windowNotificationPermission() {
|
||||||
|
return window.Notification.permission
|
||||||
|
}
|
||||||
|
|
||||||
|
export function notificationCount() {
|
||||||
|
return this.$matrix.notificationCount
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
const CopyWebpackPlugin = require("copy-webpack-plugin");
|
||||||
const webpack = require("webpack");
|
const webpack = require("webpack");
|
||||||
|
//const fs = require('fs')
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
transpileDependencies: ["vuetify"],
|
transpileDependencies: ["vuetify"],
|
||||||
|
|
@ -47,5 +48,15 @@ module.exports = {
|
||||||
|
|
||||||
devServer: {
|
devServer: {
|
||||||
//https: true,
|
//https: true,
|
||||||
},
|
|
||||||
|
/***
|
||||||
|
* For testing notification via service worker in Mobile
|
||||||
|
* Run your site locally with secure HTTPS using mkcert
|
||||||
|
* https://web.dev/how-to-use-local-https/#running-your-site-locally-with-https-using-mkcert-recommended
|
||||||
|
*/
|
||||||
|
// https: {
|
||||||
|
// key: fs.readFileSync('./your-local-ip-address-key.pem'),
|
||||||
|
// cert: fs.readFileSync('./your-local-ip-address.pem'),
|
||||||
|
// }
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
|
||||||