add modal to add new imap mailbox

This commit is contained in:
grimhilt 2023-02-27 22:34:36 +01:00
parent b0a0fe2f83
commit ea0bfd5a54
18 changed files with 673 additions and 97 deletions

View File

@ -1,5 +1,3 @@
module.exports = { <svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
presets: [ <path d="M21.2756 4.69628C21.8922 4.07969 21.8922 3.08 21.2756 2.46342C20.659 1.84683 19.6593 1.84683 19.0427 2.46342L11.8917 9.61447L4.74063 2.46342C4.12404 1.84683 3.12436 1.84683 2.50777 2.46342C1.89118 3.08 1.89118 4.07969 2.50777 4.69628L9.65882 11.8473L2.20145 19.3047C1.58487 19.9213 1.58487 20.921 2.20145 21.5376C2.81804 22.1541 3.81773 22.1541 4.43431 21.5376L11.8917 14.0802L19.349 21.5375C19.9656 22.1541 20.9653 22.1541 21.5819 21.5375C22.1985 20.921 22.1985 19.9213 21.5819 19.3047L14.1245 11.8473L21.2756 4.69628Z" fill="#737D8C"/>
'@vue/cli-plugin-babel/preset' </svg>
]
}

Before

Width:  |  Height:  |  Size: 73 B

After

Width:  |  Height:  |  Size: 650 B

196
front/package-lock.json generated
View File

@ -8,6 +8,8 @@
"name": "mail", "name": "mail",
"version": "0.1.0", "version": "0.1.0",
"dependencies": { "dependencies": {
"@vueuse/components": "^9.13.0",
"@vueuse/core": "^9.13.0",
"axios": "^1.3.4", "axios": "^1.3.4",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"vue": "^3.2.13", "vue": "^3.2.13",
@ -2420,6 +2422,12 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"node_modules/@types/web-bluetooth": {
"version": "0.0.16",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ==",
"license": "MIT"
},
"node_modules/@types/ws": { "node_modules/@types/ws": {
"version": "8.5.4", "version": "8.5.4",
"resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.4.tgz", "resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.4.tgz",
@ -3131,6 +3139,131 @@
"dev": true, "dev": true,
"license": "MIT" "license": "MIT"
}, },
"node_modules/@vueuse/components": {
"version": "9.13.0",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/components/-/components-9.13.0.tgz",
"integrity": "sha512-UJ8PjQ4SGb2rsVIy9vhEc6aCu+3+2cc+xEfGNX8/M1NKIuL2Vo6c2Kc2fYFaRzWZkP8HWXu+IcwvnAzL44IEFA==",
"license": "MIT",
"dependencies": {
"@vueuse/core": "9.13.0",
"@vueuse/shared": "9.13.0",
"vue-demi": "*"
}
},
"node_modules/@vueuse/components/node_modules/vue-demi": {
"version": "0.13.11",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@vueuse/core": {
"version": "9.13.0",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/core/-/core-9.13.0.tgz",
"integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
"license": "MIT",
"dependencies": {
"@types/web-bluetooth": "^0.0.16",
"@vueuse/metadata": "9.13.0",
"@vueuse/shared": "9.13.0",
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/core/node_modules/vue-demi": {
"version": "0.13.11",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@vueuse/metadata": {
"version": "9.13.0",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/metadata/-/metadata-9.13.0.tgz",
"integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ==",
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared": {
"version": "9.13.0",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/shared/-/shared-9.13.0.tgz",
"integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
"license": "MIT",
"dependencies": {
"vue-demi": "*"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
}
},
"node_modules/@vueuse/shared/node_modules/vue-demi": {
"version": "0.13.11",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"hasInstallScript": true,
"license": "MIT",
"bin": {
"vue-demi-fix": "bin/vue-demi-fix.js",
"vue-demi-switch": "bin/vue-demi-switch.js"
},
"engines": {
"node": ">=12"
},
"funding": {
"url": "https://github.com/sponsors/antfu"
},
"peerDependencies": {
"@vue/composition-api": "^1.0.0-rc.1",
"vue": "^3.0.0-0 || ^2.6.0"
},
"peerDependenciesMeta": {
"@vue/composition-api": {
"optional": true
}
}
},
"node_modules/@webassemblyjs/ast": { "node_modules/@webassemblyjs/ast": {
"version": "1.11.1", "version": "1.11.1",
"resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.1.tgz", "resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.1.tgz",
@ -13155,6 +13288,11 @@
"@types/node": "*" "@types/node": "*"
} }
}, },
"@types/web-bluetooth": {
"version": "0.0.16",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz",
"integrity": "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
},
"@types/ws": { "@types/ws": {
"version": "8.5.4", "version": "8.5.4",
"resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.4.tgz", "resolved": "https://registry.npmmirror.com/@types/ws/-/ws-8.5.4.tgz",
@ -13682,6 +13820,64 @@
"integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==", "integrity": "sha512-Iu8Tbg3f+emIIMmI2ycSI8QcEuAUgPTgHwesDU1eKMLE4YC/c/sFbGc70QgMq31ijRftV0R7vCm9co6rldCeOA==",
"dev": true "dev": true
}, },
"@vueuse/components": {
"version": "9.13.0",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/components/-/components-9.13.0.tgz",
"integrity": "sha512-UJ8PjQ4SGb2rsVIy9vhEc6aCu+3+2cc+xEfGNX8/M1NKIuL2Vo6c2Kc2fYFaRzWZkP8HWXu+IcwvnAzL44IEFA==",
"requires": {
"@vueuse/core": "9.13.0",
"@vueuse/shared": "9.13.0",
"vue-demi": "*"
},
"dependencies": {
"vue-demi": {
"version": "0.13.11",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"requires": {}
}
}
},
"@vueuse/core": {
"version": "9.13.0",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/core/-/core-9.13.0.tgz",
"integrity": "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw==",
"requires": {
"@types/web-bluetooth": "^0.0.16",
"@vueuse/metadata": "9.13.0",
"@vueuse/shared": "9.13.0",
"vue-demi": "*"
},
"dependencies": {
"vue-demi": {
"version": "0.13.11",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"requires": {}
}
}
},
"@vueuse/metadata": {
"version": "9.13.0",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/metadata/-/metadata-9.13.0.tgz",
"integrity": "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ=="
},
"@vueuse/shared": {
"version": "9.13.0",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/shared/-/shared-9.13.0.tgz",
"integrity": "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw==",
"requires": {
"vue-demi": "*"
},
"dependencies": {
"vue-demi": {
"version": "0.13.11",
"resolved": "https://repo.plus4u.net/operatorGate/repository/public-javascript/vue-demi/-/vue-demi-0.13.11.tgz",
"integrity": "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A==",
"requires": {}
}
}
},
"@webassemblyjs/ast": { "@webassemblyjs/ast": {
"version": "1.11.1", "version": "1.11.1",
"resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.1.tgz", "resolved": "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.1.tgz",

View File

@ -8,6 +8,8 @@
"lint": "vue-cli-service lint" "lint": "vue-cli-service lint"
}, },
"dependencies": { "dependencies": {
"@vueuse/components": "^9.13.0",
"@vueuse/core": "^9.13.0",
"axios": "^1.3.4", "axios": "^1.3.4",
"core-js": "^3.8.3", "core-js": "^3.8.3",
"vue": "^3.2.13", "vue": "^3.2.13",

View File

@ -12,15 +12,15 @@ import { RouterView } from "vue-router";
</template> </template>
<script> <script>
import Sidebar from './views/sidebar/Sidebar'; import Sidebar from './views/sidebar/Sidebar'
import RoomView from './views/room/RoomView'; import RoomView from './views/room/RoomView'
export default { export default {
name: 'App', name: 'App',
components: { components: {
Sidebar, Sidebar,
RoomView RoomView,
} },
} }
</script> </script>

View File

@ -0,0 +1,3 @@
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M21.2756 4.69628C21.8922 4.07969 21.8922 3.08 21.2756 2.46342C20.659 1.84683 19.6593 1.84683 19.0427 2.46342L11.8917 9.61447L4.74063 2.46342C4.12404 1.84683 3.12436 1.84683 2.50777 2.46342C1.89118 3.08 1.89118 4.07969 2.50777 4.69628L9.65882 11.8473L2.20145 19.3047C1.58487 19.9213 1.58487 20.921 2.20145 21.5376C2.81804 22.1541 3.81773 22.1541 4.43431 21.5376L11.8917 14.0802L19.349 21.5375C19.9656 22.1541 20.9653 22.1541 21.5819 21.5375C22.1985 20.921 22.1985 19.9213 21.5819 19.3047L14.1245 11.8473L21.2756 4.69628Z" fill="#737D8C"/>
</svg>

After

Width:  |  Height:  |  Size: 650 B

View File

@ -0,0 +1,7 @@
import axios from 'axios'
export default(url='localhost') => {
return axios.create({
baseURL: url,
});
}

View File

@ -0,0 +1,7 @@
import API from './API'
export default {
getQuote() {
return API().get('/');
}
}

View File

@ -0,0 +1,222 @@
<script setup>
import { ref, computed, watchEffect } from 'vue'
import Modal from './Modal'
import API from '../../services/imapAPI';
const modal = ref(true);
const email = ref("");
const pwd = ref("");
const xoauth = ref("");
const xoauth2 = ref("");
const host = ref("");
const port = ref("993");
const error = ref("");
const knownHosts = {
'outlook.com': {
'host': 'outlook.office365.com',
},
'hotmail.com': {
'host': 'outlook.office365.com',
},
'live.com': {
'host': 'outlook.office365.com',
},
'zoho.com': {
'host': 'imap.zoho.eu',
},
'yahoo.com': {
'host': 'imap.mail.yahoo.com',
},
'icloud.com': {
'host': 'imap.mail.me.com',
},
}
const refHost = computed({
set: (val) => {
host.value = val
}
});
const err = computed({
set: (val) => { error.value = val }
});
function validateEmail(email) {
const re = /^(([^<>()[\]\\.,;:\s@"]+(\.[^<>()[\]\\.,;:\s@"]+)*)|(".+"))@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\])|(([a-zA-Z\-0-9]+\.)+[a-zA-Z]{2,}))$/;
return re.test(String(email).toLowerCase());
}
function checkError() {
if (!validateEmail(email.value)) {
err.value = "The email is not valid.";
} else if (pwd.value == xoauth.value == xoauth2.value == "") {
err.value = "You need at least one authentification method.";
} else if ([pwd.value, xoauth.value, xoauth2.value].filter((val) => val != "").length > 1) {
err.value = "You need only one authentification method.";
} else if (host.value == "" || port.value == "") {
err.value = "You need to complete the port and the host.";
} else {
err.value = "";
}
}
function addMailboxRequest(event) {
console.log(event.target.disabled = true)
checkError();
API.getQuote().then((res) => {
console.log(res.status);
}).catch((err) => {
console.log(err.request.status)
});
}
watchEffect(() => {
if (error.value != "") {
checkError();
}
});
function mailChange() {
if (email.value.includes('@')) {
const domain = email.value.split('@')[1];
if (!knownHosts[domain]) {
refHost.value = ("imap."+domain);
} else {
refHost.value = (knownHosts[domain].host);
}
// todo check if manual
}
}
</script>
<template>
<div>
<button
@click="modal = true"
>
Open Modal!
</button>
<Modal
v-if="modal"
title="Add mailbox"
@close-modal="modal = false"
>
<template v-slot:body>
<div class="field">
<label>Email: </label>
<input @change="mailChange" v-model="email" type="email" required>
</div>
<fieldset>
<legend>Authentification method</legend>
<div class="field">
<label>Plain password:</label>
<input v-model="pwd" type="password">
</div>
<div class="field">
<label>Xoauth:</label>
<input v-model="xoauth" type="text">
</div>
<div class="field">
<label>Xoauth2:</label>
<input v-model="xoauth2" type="text">
</div>
</fieldset>
<div class="config">
<input v-model="host" id="host" type="text" placeholder="imap host">
<input v-model="port" id="port" type="number" placeholder="port">
</div>
<!-- tls -->
<div>
<button :disabled="error != ''" @click="addMailboxRequest">Add</button>
{{ error }}
</div>
</template>
</Modal>
</div>
</template>
<style>
/* Chrome, Safari, Edge, Opera */
input::-webkit-outer-spin-button,
input::-webkit-inner-spin-button {
-webkit-appearance: none;
margin: 0;
}
/* Firefox */
input[type=number] {
appearance: textfield;
}
.field {
margin-bottom: 5px;
}
.field > input {
margin-top: 2px;
width: 95%;
}
fieldset {
margin-top: 5px;
border-radius: 5px;
display: grid;
}
.config {
margin: 10px 0;
}
#host {
margin-right: 8px;
width: calc(95% - 100px);
}
#port {
width: 70px;
}
button {
padding: 5px;
padding: 7px 18px;
background-color: #09a35b;
color: white;
border-radius: 5px;
border: none;
text-decoration: none;
display: inline-block;
transition: opacity 0.5s;
}
button:hover {
opacity: 0.6;
}
input {
-webkit-box-flex: 1;
background-color: #303a46;
border: none;
border-radius: 4px;
color: #fff;
-ms-flex: 1;
flex: 1;
font-family: inherit;
font-size: 1.4rem;
font-weight: 400;
min-width: 0;
padding: 8px 9px;
}
input:focus {
outline: none;
}
</style>

View File

@ -0,0 +1,80 @@
<script setup>
import { vOnClickOutside } from '@vueuse/components'
import { defineEmits, defineProps } from 'vue'
const emit = defineEmits(['close-modal']);
const props = defineProps({ title: String });
function close() {
emit('close-modal');
}
</script>
<template>
<div class="modal-wrapper">
<div class="modal" v-on-click-outside="close">
<header class="modal-header">
<h2>{{ props.title }}</h2>
<div class="close-button" @click="close"></div>
</header>
<div class="modal-body">
<slot name="body">
This is the default body!
</slot>
</div>
</div>
</div>
</template>
<style scoped>
.modal-wrapper {
display: flex;
align-items: center;
position: fixed;
height: 100%;
width: 100%;
justify-content: center;
left: 0;
top: 0;
z-index: 4000;
background-color: #000;
opacity: .7;
}
.modal {
display: flex;
flex-direction: column;
border-radius: 5px;
color: white;
background-color: #1D1D23;
padding: 20px
}
.modal-header {
margin-bottom: 10px;
}
h2 {
display: inline-block;
font-size: 2.4rem;
margin: 0;
}
.close-button {
background-color: #9fa9ba;
cursor: pointer;
height: 18px;
mask: url(../../assets/close.svg);
mask-repeat: no-repeat;
mask-size: cover;
width: 18px;
float: right;
margin-top: 5px;
}
</style>

View File

@ -1,18 +1,18 @@
<template> <template>
<div> <div>
<Folders /> <Mailboxes />
<Users id="users"/> <Users id="users"/>
</div> </div>
</template> </template>
<script> <script>
import Folders from './folders/Folders'; import Mailboxes from './mailboxes/Mailboxes'
import Users from './users/Users.vue'; import Users from './users/Users.vue'
export default { export default {
name: 'Sidebar', name: 'Sidebar',
components: { components: {
Folders, Mailboxes,
Users, Users,
} }
} }

View File

@ -1,35 +0,0 @@
<template>
<div id="main" @click="setActiveMailbox(data.id)">
{{ data.mail }}
</div>
</template>
<script>
import { mapMutations } from 'vuex'
export default {
name: 'Folder',
components: {
},
props: {
data: {mail: String, id: Number}
},
methods: {
...mapMutations(['setActiveMailbox'])
}
}
</script>
<style scoped>
#main {
max-width: 32px;
white-space: normal;
word-wrap: break-word;
padding: 0px;
cursor: pointer;
}
div:hover {
background-color: aqua !important;
}
</style>

View File

@ -1,47 +0,0 @@
<template>
<div id="main">
<div id="userMenu">
<!-- deconnect -->
</div>
<span class="divider"></span>
<Folder :data="{'id': -1, 'mail': 'all'}"/>
<Folder v-for="(mailbox, index) in mailboxes" :key="index" :data="mailbox"/>
<span class="divider"></span>
<!-- <h5>Folders: </h5> -->
</div>
</template>
<script>
import { mapState } from 'vuex'
import Folder from './Folder.vue'
export default {
name: 'Folders',
components: {
Folder
},
computed: {
...mapState(['mailboxes'])
}
}
</script>
<style scoped>
#main {
display: flex;
flex-direction: column;
padding: 5px;
background-color: #2A2A33;
}
#userMenu {
width: 32px;
height: 32px;
background-color: yellow !important;
}
.divider {
border-top: 1px solid #bbb;
margin: 3px 0;
}
</style>

View File

@ -0,0 +1,48 @@
<template>
<div class="container" @click="setActiveMailbox(data.id)" :class="activeMailbox == data.id && 'active'">
{{ data.mail }}
</div>
</template>
<script>
import { mapMutations, mapState } from 'vuex'
export default {
name: 'Mailbox',
components: {
},
props: {
data: {mail: String, id: Number}
},
computed: {
...mapState(['activeMailbox'])
},
methods: {
...mapMutations(['setActiveMailbox'])
}
}
</script>
<style scoped>
.container {
max-width: 32px;
white-space: normal;
word-wrap: break-word;
padding: 5px;
margin: 1px 0;
cursor: pointer;
border-radius: 8px;
border: 2px solid transparent;
}
.container:hover {
background-color: aqua !important;
}
.active {
border: 2px solid white;
opacity: 0.9;
}
</style>

View File

@ -0,0 +1,54 @@
<template>
<div id="main">
<div id="userMenu">
<!-- deconnect -->
</div>
<span class="divider"></span>
<Mailbox :data="{'id': -1, 'mail': 'all'}"/>
<Mailbox v-for="(mailbox, index) in mailboxes" :key="index" :data="mailbox"/>
<span class="divider"></span>
<AddMailboxModal />
</div>
</template>
<script>
import { mapState } from 'vuex'
import Mailbox from './Mailbox'
import AddMailboxModal from '../../modals/AddMailboxModal'
export default {
name: 'Mailboxes',
components: {
Mailbox,
AddMailboxModal
},
computed: {
...mapState(['mailboxes'])
},
}
</script>
<style scoped>
#main {
display: flex;
flex-direction: column;
align-items: center;
padding: 5px;
background-color: #2A2A33;
color: white;
}
#userMenu {
width: 32px;
height: 32px;
background-color: yellow !important;
}
.divider {
border-top: 1px solid #bbb;
margin: 5px 0;
width: 90%;
}
</style>

View File

@ -5,7 +5,7 @@
</template> </template>
<script> <script>
import { mapGetters } from 'vuex'; import { mapGetters } from 'vuex'
import User from './User' import User from './User'
export default { export default {

View File

@ -1296,6 +1296,11 @@
dependencies: dependencies:
"@types/node" "*" "@types/node" "*"
"@types/web-bluetooth@^0.0.16":
"integrity" "sha512-oh8q2Zc32S6gd/j50GowEjKLoOVOwHP/bWVjKJInBwQqdOYMdPrf1oVlelTlyfFK3CKxL1uahMDAr+vy8T7yMQ=="
"resolved" "https://repo.plus4u.net/operatorGate/repository/public-javascript/@types/web-bluetooth/-/web-bluetooth-0.0.16.tgz"
"version" "0.0.16"
"@types/ws@^8.5.1": "@types/ws@^8.5.1":
"integrity" "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg==" "integrity" "sha512-zdQDHKUgcX/zBc4GrwsE/7dVdAD8JR4EuiAXiiUhhfyIJXXb2+PrGshFyeXWQPMmmZ2XxgaqclgpIC7eTXc1mg=="
"resolved" "https://registry.npmmirror.com/@types/ws/-/ws-8.5.4.tgz" "resolved" "https://registry.npmmirror.com/@types/ws/-/ws-8.5.4.tgz"
@ -1671,6 +1676,37 @@
"resolved" "https://registry.npmmirror.com/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz" "resolved" "https://registry.npmmirror.com/@vue/web-component-wrapper/-/web-component-wrapper-1.3.0.tgz"
"version" "1.3.0" "version" "1.3.0"
"@vueuse/components@^9.13.0":
"integrity" "sha512-UJ8PjQ4SGb2rsVIy9vhEc6aCu+3+2cc+xEfGNX8/M1NKIuL2Vo6c2Kc2fYFaRzWZkP8HWXu+IcwvnAzL44IEFA=="
"resolved" "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/components/-/components-9.13.0.tgz"
"version" "9.13.0"
dependencies:
"@vueuse/core" "9.13.0"
"@vueuse/shared" "9.13.0"
"vue-demi" "*"
"@vueuse/core@^9.13.0", "@vueuse/core@9.13.0":
"integrity" "sha512-pujnclbeHWxxPRqXWmdkKV5OX4Wk4YeK7wusHqRwU0Q7EFusHoqNA/aPhB6KCh9hEqJkLAJo7bb0Lh9b+OIVzw=="
"resolved" "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/core/-/core-9.13.0.tgz"
"version" "9.13.0"
dependencies:
"@types/web-bluetooth" "^0.0.16"
"@vueuse/metadata" "9.13.0"
"@vueuse/shared" "9.13.0"
"vue-demi" "*"
"@vueuse/metadata@9.13.0":
"integrity" "sha512-gdU7TKNAUVlXXLbaF+ZCfte8BjRJQWPCa2J55+7/h+yDtzw3vOoGQDRXzI6pyKyo6bXFT5/QoPE4hAknExjRLQ=="
"resolved" "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/metadata/-/metadata-9.13.0.tgz"
"version" "9.13.0"
"@vueuse/shared@9.13.0":
"integrity" "sha512-UrnhU+Cnufu4S6JLCPZnkWh0WwZGUp72ktOF2DFptMlOs3TOdVv8xJN53zhHGARmVOsz5KqOls09+J1NR6sBKw=="
"resolved" "https://repo.plus4u.net/operatorGate/repository/public-javascript/@vueuse/shared/-/shared-9.13.0.tgz"
"version" "9.13.0"
dependencies:
"vue-demi" "*"
"@webassemblyjs/ast@1.11.1": "@webassemblyjs/ast@1.11.1":
"integrity" "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw==" "integrity" "sha512-ukBh14qFLjxTQNTXocdyksN5QdM28S1CxHt2rdskFyL+xFV7VremuBLVbmCePj+URalXBENx/9Lm7lnhihtCSw=="
"resolved" "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.1.tgz" "resolved" "https://registry.npmmirror.com/@webassemblyjs/ast/-/ast-1.11.1.tgz"
@ -5907,6 +5943,11 @@
"resolved" "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz" "resolved" "https://registry.npmmirror.com/vary/-/vary-1.1.2.tgz"
"version" "1.1.2" "version" "1.1.2"
"vue-demi@*":
"integrity" "sha512-IR8HoEEGM65YY3ZJYAjMlKygDQn25D5ajNFNoKh9RSDMQtlzCxtfQjdQgv9jjK+m3377SsJXY8ysq8kLCZL25A=="
"resolved" "https://repo.plus4u.net/operatorGate/repository/public-javascript/vue-demi/-/vue-demi-0.13.11.tgz"
"version" "0.13.11"
"vue-eslint-parser@^8.0.1": "vue-eslint-parser@^8.0.1":
"integrity" "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g==" "integrity" "sha512-dzHGG3+sYwSf6zFBa0Gi9ZDshD7+ad14DGOdTLjruRVgZXe2J+DcZ9iUhyR48z5g1PqRa20yt3Njna/veLJL/g=="
"resolved" "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz" "resolved" "https://registry.npmmirror.com/vue-eslint-parser/-/vue-eslint-parser-8.3.0.tgz"
@ -5954,7 +5995,7 @@
"resolved" "https://registry.npmmirror.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz" "resolved" "https://registry.npmmirror.com/vue-template-es2015-compiler/-/vue-template-es2015-compiler-1.9.1.tgz"
"version" "1.9.1" "version" "1.9.1"
"vue@*", "vue@^2 || ^3.2.13", "vue@^3.0.2", "vue@^3.2.0", "vue@^3.2.13", "vue@3.2.47": "vue@*", "vue@^2 || ^3.2.13", "vue@^3.0.0-0 || ^2.6.0", "vue@^3.0.2", "vue@^3.2.0", "vue@^3.2.13", "vue@3.2.47":
"integrity" "sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ==" "integrity" "sha512-60188y/9Dc9WVrAZeUVSDxRQOZ+z+y5nO2ts9jWXSTkMvayiWxCWOWtBQoYjLeccfXkiiPZWAHcV+WTPhkqJHQ=="
"resolved" "https://registry.npmmirror.com/vue/-/vue-3.2.47.tgz" "resolved" "https://registry.npmmirror.com/vue/-/vue-3.2.47.tgz"
"version" "3.2.47" "version" "3.2.47"