Merge remote-tracking branch 'origin/master' into chatInformations
# Conflicts: # src/App.vue
37
api.js
Normal file
@ -0,0 +1,37 @@
|
||||
const ws = require('ws')
|
||||
|
||||
//WS server
|
||||
const wss = new ws.Server({
|
||||
port: 8090,
|
||||
perMessageDeflate: {
|
||||
zlibDeflateOptions: {
|
||||
chunkSize: 1024,
|
||||
memLevel: 7,
|
||||
level: 3
|
||||
},
|
||||
zlibInflateOptions: {
|
||||
chunkSize: 10 * 1024
|
||||
},
|
||||
clientNoContextTakeover: true,
|
||||
serverNoContextTakeover: true,
|
||||
serverMaxWindowBits: 10,
|
||||
concurrencyLimit: 10,
|
||||
threshold: 1024
|
||||
}
|
||||
});
|
||||
|
||||
//WS handler
|
||||
wss.on('connection', (ws, req) => {
|
||||
console.log(`${req.socket.remoteAddress} connected`)
|
||||
ws.on('message', msgJSON => {
|
||||
let msg = JSON.parse(msgJSON)
|
||||
console.log(`${req.socket.remoteAddress} => ${msgJSON}`)
|
||||
if (msg.type === 'message') wss.clients.forEach(client => client.send(msgJSON))
|
||||
})
|
||||
let msg = {
|
||||
type: "info",
|
||||
time: Date.now(),
|
||||
content: "connected"
|
||||
}
|
||||
ws.send(JSON.stringify(msg))
|
||||
})
|
194
package-lock.json
generated
@ -1744,16 +1744,6 @@
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||
"dev": true
|
||||
},
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"cacache": {
|
||||
"version": "13.0.1",
|
||||
"resolved": "https://registry.npmjs.org/cacache/-/cacache-13.0.1.tgz",
|
||||
@ -1780,34 +1770,6 @@
|
||||
"unique-filename": "^1.1.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"find-cache-dir": {
|
||||
"version": "3.3.1",
|
||||
"resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.1.tgz",
|
||||
@ -1829,25 +1791,6 @@
|
||||
"path-exists": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"locate-path": {
|
||||
"version": "5.0.0",
|
||||
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
|
||||
@ -1912,16 +1855,6 @@
|
||||
"minipass": "^3.1.1"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
},
|
||||
"terser-webpack-plugin": {
|
||||
"version": "2.3.8",
|
||||
"resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-2.3.8.tgz",
|
||||
@ -1938,18 +1871,6 @@
|
||||
"terser": "^4.6.12",
|
||||
"webpack-sources": "^1.4.3"
|
||||
}
|
||||
},
|
||||
"vue-loader-v16": {
|
||||
"version": "npm:vue-loader@16.0.0-beta.9",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.9.tgz",
|
||||
"integrity": "sha512-mu9pg6554GbXDSO8LlxkQM6qUJzUkb/A0FJc9LgRqnU9MCnhzEXwCt1Zx5NObvFpzs2mH2dH/uUCDwL8Qaz9sA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
"hash-sum": "^2.0.0",
|
||||
"loader-utils": "^2.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -11019,6 +10940,93 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-loader-v16": {
|
||||
"version": "npm:vue-loader@16.0.0-beta.9",
|
||||
"resolved": "https://registry.npmjs.org/vue-loader/-/vue-loader-16.0.0-beta.9.tgz",
|
||||
"integrity": "sha512-mu9pg6554GbXDSO8LlxkQM6qUJzUkb/A0FJc9LgRqnU9MCnhzEXwCt1Zx5NObvFpzs2mH2dH/uUCDwL8Qaz9sA==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"chalk": "^4.1.0",
|
||||
"hash-sum": "^2.0.0",
|
||||
"loader-utils": "^2.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"ansi-styles": {
|
||||
"version": "4.3.0",
|
||||
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
|
||||
"integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-convert": "^2.0.1"
|
||||
}
|
||||
},
|
||||
"chalk": {
|
||||
"version": "4.1.0",
|
||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz",
|
||||
"integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"ansi-styles": "^4.1.0",
|
||||
"supports-color": "^7.1.0"
|
||||
}
|
||||
},
|
||||
"color-convert": {
|
||||
"version": "2.0.1",
|
||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||
"integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"color-name": "~1.1.4"
|
||||
}
|
||||
},
|
||||
"color-name": {
|
||||
"version": "1.1.4",
|
||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
|
||||
"integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"has-flag": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
|
||||
"integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
|
||||
"dev": true,
|
||||
"optional": true
|
||||
},
|
||||
"loader-utils": {
|
||||
"version": "2.0.0",
|
||||
"resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.0.tgz",
|
||||
"integrity": "sha512-rP4F0h2RaWSvPEkD7BLDFQnvSf+nK+wr3ESUjNTyAGobqrijmW92zc+SO6d4p4B1wh7+B/Jg1mkQe5NYUEHtHQ==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"big.js": "^5.2.2",
|
||||
"emojis-list": "^3.0.0",
|
||||
"json5": "^2.1.2"
|
||||
}
|
||||
},
|
||||
"supports-color": {
|
||||
"version": "7.2.0",
|
||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
|
||||
"integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
|
||||
"dev": true,
|
||||
"optional": true,
|
||||
"requires": {
|
||||
"has-flag": "^4.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"vue-router": {
|
||||
"version": "3.4.9",
|
||||
"resolved": "https://registry.npmjs.org/vue-router/-/vue-router-3.4.9.tgz",
|
||||
"integrity": "sha512-CGAKWN44RqXW06oC+u4mPgHLQQi2t6vLD/JbGRDAXm0YpMv0bgpKuU5bBd7AvMgfTz9kXVRIWKHqRwGEb8xFkA==",
|
||||
"dev": true
|
||||
},
|
||||
"vue-style-loader": {
|
||||
"version": "4.1.2",
|
||||
"resolved": "https://registry.npmjs.org/vue-style-loader/-/vue-style-loader-4.1.2.tgz",
|
||||
@ -11268,6 +11276,15 @@
|
||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||
"integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==",
|
||||
"dev": true
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
|
||||
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
@ -11579,6 +11596,15 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
|
||||
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
},
|
||||
"yargs": {
|
||||
"version": "13.3.2",
|
||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz",
|
||||
@ -11744,13 +11770,9 @@
|
||||
}
|
||||
},
|
||||
"ws": {
|
||||
"version": "6.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-6.2.1.tgz",
|
||||
"integrity": "sha512-GIyAXC2cB7LjvpgMt9EKS2ldqr0MTrORaleiOno6TweZ6r3TKtoFQWay/2PceJ3RuBasOHzXNn5Lrw1X0bEjqA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"async-limiter": "~1.0.0"
|
||||
}
|
||||
"version": "7.3.1",
|
||||
"resolved": "https://registry.npmjs.org/ws/-/ws-7.3.1.tgz",
|
||||
"integrity": "sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA=="
|
||||
},
|
||||
"xtend": {
|
||||
"version": "4.0.2",
|
||||
|
@ -9,7 +9,8 @@
|
||||
},
|
||||
"dependencies": {
|
||||
"core-js": "^3.6.5",
|
||||
"vue": "^2.6.11"
|
||||
"vue": "^2.6.11",
|
||||
"ws": "^7.3.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vue/cli-plugin-babel": "~4.5.0",
|
||||
@ -18,6 +19,7 @@
|
||||
"babel-eslint": "^10.1.0",
|
||||
"eslint": "^6.7.2",
|
||||
"eslint-plugin-vue": "^6.2.2",
|
||||
"vue-router": "^3.4.9",
|
||||
"vue-template-compiler": "^2.6.11"
|
||||
},
|
||||
"eslintConfig": {
|
||||
|
Before Width: | Height: | Size: 210 B After Width: | Height: | Size: 210 B |
4
public/sym/ic_close_white_24px.svg
Executable file
@ -0,0 +1,4 @@
|
||||
<svg fill="#FFFFFF" height="24" viewBox="0 0 24 24" width="24" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/>
|
||||
<path d="M0 0h24v24H0z" fill="none"/>
|
||||
</svg>
|
After Width: | Height: | Size: 265 B |
Before Width: | Height: | Size: 201 B After Width: | Height: | Size: 201 B |
Before Width: | Height: | Size: 350 B After Width: | Height: | Size: 350 B |
Before Width: | Height: | Size: 465 B After Width: | Height: | Size: 465 B |
71
src/App.vue
@ -1,68 +1,19 @@
|
||||
<template>
|
||||
<div id="app">
|
||||
<div class="content">
|
||||
<div class="messages">
|
||||
<div class="spacer" style="height: 4rem;"></div>
|
||||
<message msg="Hey :D" />
|
||||
<message msg="Du bist blööööd xD" />
|
||||
<messageReceive msg="Du auch" />
|
||||
<message msg="lol" />
|
||||
<messageReceive msg="Du bist voll blöd, ich hasse dich, warum tust du das?!" />
|
||||
<message msg="Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Ut imperdiet vel risus tristique mollis. Proin aliquam felis non vehicula ornare.
|
||||
Fusce scelerisque pellentesque erat quis sollicitudin.
|
||||
Quisque aliquet, ligula ut volutpat vulputate, ligula lorem dictum velit, et aliquam sapien orci sed magna.
|
||||
Nam suscipit ex eget urna accumsan pulvinar. Pellentesque fringilla placerat feugiat.
|
||||
Aenean aliquam vestibulum metus. Nulla augue turpis, consectetur vitae quam ac, porttitor rhoncus nunc.
|
||||
Nullam non turpis consequat, placerat lectus nec, ornare orci.
|
||||
Fusce lorem tortor, viverra ac suscipit sit amet, scelerisque id eros.
|
||||
Suspendisse et ultricies elit, vitae pretium ipsum. Suspendisse vel ex in turpis pulvinar feugiat. "
|
||||
/>
|
||||
<messageReceive msg="Du hast Pizza!" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<div class="spacer" style="height: 1rem;"></div>
|
||||
</div>
|
||||
<newMessage />
|
||||
<topBanner />
|
||||
<chatInformations />
|
||||
<router-view />
|
||||
<error />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import message from './components/message.vue';
|
||||
import messageReceive from './components/messageReceive.vue';
|
||||
import newMessage from './components/newMessage.vue';
|
||||
import topBanner from './components/topBanner.vue';
|
||||
import chatInformations from './components/chatInformations.vue';
|
||||
import error from "@/components/error.vue";
|
||||
|
||||
export default {
|
||||
name: 'App',
|
||||
components: {
|
||||
message,
|
||||
messageReceive,
|
||||
newMessage,
|
||||
topBanner,
|
||||
chatInformations
|
||||
components:{
|
||||
error
|
||||
}
|
||||
}
|
||||
</script>
|
||||
@ -86,20 +37,10 @@ body{
|
||||
padding: 0;
|
||||
min-height: calc(100%);
|
||||
width: 50rem;
|
||||
min-width: 15rem;
|
||||
min-width: 18rem;
|
||||
background-color: #313131;
|
||||
box-shadow: 3px 3px 10px #111;
|
||||
}
|
||||
.messages{
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
left: 0;
|
||||
top: 0;
|
||||
height: calc(100% - 4rem);
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
|
||||
@media (max-width: 55rem){
|
||||
.content{
|
||||
width: calc(100%);
|
||||
|
68
src/components/error.vue
Normal file
@ -0,0 +1,68 @@
|
||||
<template>
|
||||
<div id="errorBox" class="errorBox">
|
||||
<icon class="errorBtn" onclick="this.parentNode.style.display = 'none'" ic="./sym/ic_close_white_24px.svg" />
|
||||
<div id="errorMessage" class="btnText">
|
||||
{{msg}}
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import icon from './icon.vue';
|
||||
|
||||
export default {
|
||||
name: "error",
|
||||
components: {
|
||||
icon
|
||||
},
|
||||
props:{
|
||||
msg: String
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.errorBox{
|
||||
position: absolute;
|
||||
bottom: 1rem;
|
||||
left: 1rem;
|
||||
height: 10rem;
|
||||
width: 16rem;
|
||||
background-color: #E53935;
|
||||
border-radius: 15px;
|
||||
box-shadow: 3px 3px 10px #111;
|
||||
}
|
||||
#errorBox{
|
||||
display: none;
|
||||
}
|
||||
.btnText {
|
||||
position: absolute;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
font-size: 1.2rem;
|
||||
color: #fff;
|
||||
font-family:Arial, "lucida console", sans-serif;
|
||||
}
|
||||
.errorBtn{
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
background-color: #0000;
|
||||
box-shadow: none;
|
||||
}
|
||||
|
||||
@keyframes slide-from-left{
|
||||
from{left:-30rem;opacity: 0}
|
||||
to{left:1rem;opacity: 1}
|
||||
}
|
||||
|
||||
@media (max-width: 35rem) {
|
||||
.errorBox {
|
||||
bottom: 1rem;
|
||||
left: 1rem;
|
||||
height: 8rem;
|
||||
width: calc(100% - 2rem);
|
||||
}
|
||||
}
|
||||
</style>
|
@ -1,7 +1,7 @@
|
||||
<template>
|
||||
<div class="iconContainer" >
|
||||
<img class="icon" :src="ic" alt="" />
|
||||
</div>
|
||||
<button class="iconContainer" >
|
||||
<img class="icon" v-bind:src=ic alt="" />
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
@ -22,12 +22,14 @@ name: "icon",
|
||||
box-shadow: 3px 3px 10px #111;
|
||||
cursor: pointer;
|
||||
user-select: none;
|
||||
border: none;
|
||||
}
|
||||
.icon{
|
||||
position: absolute;
|
||||
height: 1.5rem;
|
||||
width: auto;
|
||||
top: 0.75rem;
|
||||
left: 0.75rem;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
}
|
||||
</style>
|
@ -18,7 +18,7 @@ export default {
|
||||
<style scoped>
|
||||
.messageContainer{
|
||||
position: relative;
|
||||
margin-top: 0.5rem;
|
||||
margin-top: 0.25rem;
|
||||
width: calc(100% - 2rem);
|
||||
left: 1rem;
|
||||
}
|
||||
@ -28,10 +28,18 @@ export default {
|
||||
width: max-content;
|
||||
min-width: 5rem;
|
||||
max-width: calc(100% - 3rem);
|
||||
padding: 1rem;
|
||||
padding: 0.7rem 1rem 0.45rem 1rem;
|
||||
right: 0;
|
||||
background-color: #42b983;
|
||||
background-color: #42a7b9;
|
||||
border-radius: 1rem 1rem 0 1rem;
|
||||
text-align: left;
|
||||
word-break: break-word;
|
||||
}
|
||||
|
||||
@media (min-width: 45rem){
|
||||
.message{
|
||||
margin-left: 0; margin-right: auto;
|
||||
border-radius: 1rem 1rem 1rem 0;
|
||||
}
|
||||
}
|
||||
</style>
|
@ -18,7 +18,7 @@ export default {
|
||||
<style scoped>
|
||||
.messageContainer{
|
||||
position: relative;
|
||||
margin-top: 0.5rem;
|
||||
margin-top: 0.25rem;
|
||||
width: calc(100% - 2rem);
|
||||
left: 1rem;
|
||||
}
|
||||
@ -27,9 +27,9 @@ export default {
|
||||
width: max-content;
|
||||
min-width: 5rem;
|
||||
max-width: calc(100% - 3rem);
|
||||
padding: 1rem;
|
||||
padding: 0.7rem 1rem 0.45rem 1rem;
|
||||
left: 0;
|
||||
background-color: #42a7b9;
|
||||
background-color: #42b983;
|
||||
border-radius: 1rem 1rem 1rem 0;
|
||||
text-align: left;
|
||||
}
|
||||
|
@ -1,33 +1,53 @@
|
||||
<template>
|
||||
<div class="newMessageBanner">
|
||||
<textarea name="input" id="newMessageInput" class="newMessageInput" placeholder="type a message ..." type="text" v-model="content" />
|
||||
<icon style="position: absolute; right: 1rem; bottom: 0.5rem;" ic="./sym/ic_send_white_24px.svg" />
|
||||
<label for="newMessageInput"></label>
|
||||
<textarea @input="resizeMessageBanner()" ref="newMessageInput" id="newMessageInput" class="newMessageInput"
|
||||
autocomplete="off" placeholder="type a message ..." v-model="msg.content.text" />
|
||||
<icon @click.native="sendMessage()" id="sendMessageBtn" style="position: absolute; right: 1rem; bottom: 0.5rem;"
|
||||
ic="./sym/ic_send_white_24px.svg" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import icon from './icon.vue';
|
||||
import main from '../main.js';
|
||||
|
||||
export default {
|
||||
name: "newMessage",
|
||||
components: {
|
||||
icon
|
||||
},
|
||||
props: {
|
||||
content: String,
|
||||
methods: {
|
||||
sendMessage(){
|
||||
if (this.msg.content.text !== "") {
|
||||
this.msg.time = Date.now()
|
||||
main.methods.sendWebSocket(this.msg)
|
||||
this.msg.content.text = ""
|
||||
this.resizeMessageBanner()
|
||||
}
|
||||
},
|
||||
resizeMessageBanner(){
|
||||
let id = this.$refs.newMessageInput
|
||||
id.style.height = '1.25rem'
|
||||
id.style.height = `${id.scrollHeight}px`
|
||||
let msgContainer = document.getElementById("messagesContainer")
|
||||
msgContainer.style.height
|
||||
= `calc(100% - ${id.parentElement.clientHeight}px - 3rem)`
|
||||
//msgContainer.scrollTo(0, msgContainer.scrollHeight)
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
ResizeListener(document.getElementById("newMessageInput"));
|
||||
data(){
|
||||
return {
|
||||
msg: {
|
||||
type: "message",
|
||||
time: Date.now(),
|
||||
content: {
|
||||
text: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export const ResizeListener = (id) => {
|
||||
id.addEventListener("input", resize);
|
||||
}
|
||||
function resize() {
|
||||
this.style.height = "auto";
|
||||
this.style.height = `${this.scrollHeight}px`;
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
@ -43,12 +63,13 @@ function resize() {
|
||||
}
|
||||
.newMessageInput{
|
||||
position: relative;
|
||||
margin-top: 0.5rem;
|
||||
margin-bottom: 0.5rem;
|
||||
margin-top: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
left: 2rem;
|
||||
min-height: 3rem;
|
||||
min-height: 1.25rem;
|
||||
max-height: 14rem;
|
||||
width: calc(100% - 7rem);
|
||||
height: 1.25rem;
|
||||
background-color: #fff0;
|
||||
border: 0 solid #fff0;
|
||||
color: #fff;
|
||||
|
34
src/components/textbtn.vue
Normal file
@ -0,0 +1,34 @@
|
||||
<template>
|
||||
<button class="btn">
|
||||
<div class="btnText">{{text}}</div>
|
||||
</button>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
name: "textbtn",
|
||||
props:{
|
||||
text: String
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.btn{
|
||||
cursor: pointer;
|
||||
border: none;
|
||||
height: 2.5rem;
|
||||
padding-left: 2rem;
|
||||
padding-right: 2rem;
|
||||
background-color: #00BCD4;
|
||||
box-shadow: 3px 3px 10px #222;
|
||||
border-radius: 1.25rem;
|
||||
margin: 1rem;
|
||||
}
|
||||
.btnText {
|
||||
position: relative;
|
||||
font-size: 1.4rem;
|
||||
color:#fff;
|
||||
font-family:Arial, "lucida console", sans-serif;
|
||||
}
|
||||
</style>
|
@ -1,50 +1,60 @@
|
||||
<template>
|
||||
<div class="topBanner">
|
||||
<div>
|
||||
<div id = "icon-arrow" ><img alt="arrow" class="arrow-Top-Left" src="../sym/arrow_back-24px.svg"></div>
|
||||
<div id = "picTop"><img alt="Bild" id="picTopPic" src="../sym/supervisor_account-24px.svg"></div>
|
||||
<icon class="smallIcon" id="icon-arrow" ic="./sym/arrow_back-24px.svg" />
|
||||
<icon class="smallIcon" id="picTop" ic="./sym/supervisor_account-24px.svg" />
|
||||
<div id="container">
|
||||
<div id = "chatName"> OpenChat</div>
|
||||
<div id = "users">9 Mitglieder</div>
|
||||
<div id="chatName">{{roomInfo.name}}</div>
|
||||
<div id="users">{{roomInfo.user.length}} members</div>
|
||||
</div>
|
||||
<div id = "icon-menu"><img alt="menu" class="menu-Top-Right" src="../sym/menu-24px.svg"></div>
|
||||
<icon class="smallIcon" id="icon-menu" ic="./sym/menu-24px.svg" />
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script >
|
||||
export default {
|
||||
name: "topBanner"
|
||||
<script>
|
||||
import icon from '@/components/icon.vue';
|
||||
|
||||
export default {
|
||||
name: "topBanner",
|
||||
components:{
|
||||
icon
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
roomInfo: {
|
||||
name: "open chat",
|
||||
user: []
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
<style scoped>
|
||||
.topBanner{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 3rem;
|
||||
background-color: #1d1d1d;
|
||||
box-shadow: 0 3px 10px #111;
|
||||
}
|
||||
.smallIcon{
|
||||
top: 0.25rem;
|
||||
background-color: #2d2d2d;
|
||||
height: 2.5rem;
|
||||
width: 2.5rem;
|
||||
}
|
||||
#icon-arrow{
|
||||
position: absolute;
|
||||
top: 0.24rem;
|
||||
left: 1rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 2.3rem;
|
||||
max-width: 2.3rem;
|
||||
border-radius: 1.5rem;
|
||||
text-align: center;
|
||||
background-color: #2d2d2d;
|
||||
|
||||
}
|
||||
.arrow-Top-Left{
|
||||
margin-top: 0.2rem;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
}
|
||||
#picTop{
|
||||
top: 0.24rem;
|
||||
position: absolute;
|
||||
fill: #42a7b9;
|
||||
left: 4rem;
|
||||
background-color: #42a7b9;
|
||||
}
|
||||
#picTopPic{
|
||||
width: 2.3rem;
|
||||
height: 2.3rem;
|
||||
border-radius: 1.5rem;
|
||||
#icon-menu{
|
||||
position: absolute;
|
||||
right: 1rem;
|
||||
background-color: #2d2d2d;
|
||||
}
|
||||
#container{
|
||||
@ -53,35 +63,11 @@
|
||||
left: 7.5rem;
|
||||
}
|
||||
#chatName{
|
||||
font-size: medium;
|
||||
font-size: 1rem;
|
||||
color: #ededed;
|
||||
}
|
||||
#users{
|
||||
font-size: x-small;
|
||||
font-size: 0.75rem;
|
||||
color: #9c9c9c;
|
||||
}
|
||||
#icon-menu{
|
||||
position: absolute;
|
||||
top: 0.24rem;
|
||||
right: 1rem;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
max-height: 2.3rem;
|
||||
max-width: 2.3rem;
|
||||
border-radius: 1.5rem;
|
||||
text-align: center;
|
||||
background-color: #2d2d2d;
|
||||
|
||||
}
|
||||
.menu-Top-Right {
|
||||
margin-top: 0.2rem;
|
||||
height: 2rem;
|
||||
width: 2rem;
|
||||
}
|
||||
.topBanner{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 3rem;
|
||||
background-color: #1d1d1d;
|
||||
}
|
||||
</style>
|
101
src/main.js
@ -1,8 +1,107 @@
|
||||
import Vue from 'vue'
|
||||
import VueRouter from 'vue-router'
|
||||
import App from './App.vue'
|
||||
import login from './views/login.vue'
|
||||
import chat from './views/chat.vue'
|
||||
|
||||
Vue.config.productionTip = false
|
||||
Vue.use(VueRouter)
|
||||
|
||||
const router = new VueRouter({
|
||||
routes: [
|
||||
{
|
||||
path: '/',
|
||||
name: 'home',
|
||||
component: login
|
||||
},
|
||||
{
|
||||
path: '/login',
|
||||
name: 'login',
|
||||
component: login
|
||||
},
|
||||
{
|
||||
path: '/chat',
|
||||
name: 'chat',
|
||||
component: chat
|
||||
}
|
||||
]
|
||||
})
|
||||
|
||||
new Vue({
|
||||
render: h => h(App),
|
||||
el: '#app',
|
||||
router,
|
||||
template: '<App/>',
|
||||
components: {App}
|
||||
}).$mount('#app')
|
||||
|
||||
export default {
|
||||
mounted() {
|
||||
sendMessage()
|
||||
},
|
||||
methods: {
|
||||
sendMessage(message){
|
||||
let msg = {
|
||||
type: "message",
|
||||
time: Date.now(),
|
||||
content: {
|
||||
message: message
|
||||
}
|
||||
}
|
||||
socket.send(JSON.stringify(msg))
|
||||
},
|
||||
sendWebSocket(msg){
|
||||
socket.send(JSON.stringify(msg))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const wsurl = 'ws://127.0.0.1:8090'
|
||||
const socket = new WebSocket(wsurl)
|
||||
|
||||
function element(id){ return document.getElementById(id)}
|
||||
|
||||
socket.onopen = () => {
|
||||
let msg = {
|
||||
type: "info",
|
||||
time: Date.now(),
|
||||
content: "new session"
|
||||
}
|
||||
socket.send(JSON.stringify(msg))
|
||||
}
|
||||
socket.onerror = (error) => {
|
||||
console.log(`WebSocket error: ${error}`)
|
||||
}
|
||||
socket.onclose = () => show_error('session ended (refresh)')
|
||||
socket.onmessage = (e) => {
|
||||
console.log(`data received => ${e.data}`)
|
||||
let msg = JSON.parse(e.data)
|
||||
if (msg.type === 'error') show_error(msg.content)
|
||||
else if (msg.type === 'message'){
|
||||
//just for now, ik it's dirty
|
||||
element('messages').innerHTML +=
|
||||
`<div class="messageContainer" data-v-032da2b2="">
|
||||
<div class="message" data-v-032da2b2="">
|
||||
${msg.content.text}
|
||||
</div>
|
||||
</div>`;
|
||||
}
|
||||
}
|
||||
|
||||
function show_error(msg) {
|
||||
let error_style = element('errorBox').style
|
||||
element('errorMessage').innerText = msg
|
||||
error_style.display = "block"
|
||||
error_style.animation = "slide-from-left alternate 0.2s"
|
||||
setTimeout(() => {error_style.animation = ""}, 200)
|
||||
}
|
||||
|
||||
function sendMessage(message){
|
||||
let msg = {
|
||||
type: "message",
|
||||
time: Date.now(),
|
||||
content: {
|
||||
message: message
|
||||
}
|
||||
}
|
||||
socket.send(JSON.stringify(msg))
|
||||
}
|
0
src/router/index.js
Normal file
65
src/views/chat.vue
Normal file
@ -0,0 +1,65 @@
|
||||
<template>
|
||||
<div>
|
||||
<div ref="msgContainer" id="messagesContainer" class="messagesContainer">
|
||||
<div id="messages" class="messages">
|
||||
<message msg="Hey :D" />
|
||||
<message msg="Du bist blööööd xD" />
|
||||
<messageReceive msg="Du auch" />
|
||||
<message msg="lol" />
|
||||
<messageReceive msg="Du bist voll blöd, ich hasse dich, warum tust du das?!" />
|
||||
<message msg="Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||
Ut imperdiet vel risus tristique mollis. Proin aliquam felis non vehicula ornare.
|
||||
Fusce scelerisque pellentesque erat quis sollicitudin.
|
||||
Quisque aliquet, ligula ut volutpat vulputate, ligula lorem dictum velit, et aliquam sapien orci sed magna.
|
||||
Nam suscipit ex eget urna accumsan pulvinar. Pellentesque fringilla placerat feugiat.
|
||||
Aenean aliquam vestibulum metus. Nulla augue turpis, consectetur vitae quam ac, porttitor rhoncus nunc.
|
||||
Nullam non turpis consequat, placerat lectus nec, ornare orci.
|
||||
Fusce lorem tortor, viverra ac suscipit sit amet, scelerisque id eros.
|
||||
Suspendisse et ultricies elit, vitae pretium ipsum. Suspendisse vel ex in turpis pulvinar feugiat. "
|
||||
/>
|
||||
<messageReceive msg="Du hast Pizza!" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
<message msg="und Kuchen :P" />
|
||||
</div>
|
||||
</div>
|
||||
<newMessage />
|
||||
<topBanner />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import message from '@/components/message.vue';
|
||||
import messageReceive from '@/components/messageReceive.vue';
|
||||
import newMessage from '@/components/newMessage.vue';
|
||||
import topBanner from "@/components/topBanner";
|
||||
|
||||
export default {
|
||||
name: 'chat',
|
||||
components: {
|
||||
message,
|
||||
messageReceive,
|
||||
newMessage,
|
||||
topBanner
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
.messagesContainer{
|
||||
position: absolute;
|
||||
margin: 0;
|
||||
left: 0;
|
||||
top: 3rem;
|
||||
height: calc(100% - 7rem);
|
||||
width: 100%;
|
||||
overflow-y: auto;
|
||||
}
|
||||
.messages{
|
||||
position: relative;
|
||||
margin-top: 1rem;
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
</style>
|
66
src/views/login.vue
Normal file
@ -0,0 +1,66 @@
|
||||
<template>
|
||||
<div id="login">
|
||||
<h1 class="title">open chat</h1>
|
||||
<div class="input-field" id="longurl">
|
||||
<label for="longurl-input"></label>
|
||||
<input v-model="session.content.user" class="input" id="longurl-input" type="text" autocomplete="off" maxlength="20" placeholder="chose nickname">
|
||||
</div>
|
||||
<input type="hidden" value="search" name="login">
|
||||
<textbtn text="login" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import textbtn from '@/components/textbtn';
|
||||
|
||||
export default {
|
||||
name: "login.vue",
|
||||
components: {
|
||||
textbtn
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
session: {
|
||||
type: "session",
|
||||
time: Date.now(),
|
||||
content: {
|
||||
user: ""
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<style scoped>
|
||||
#login{
|
||||
position: absolute;
|
||||
top: 40%;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
text-align: center;
|
||||
height: min-content;
|
||||
width: 100%;
|
||||
}
|
||||
input{
|
||||
padding: 0 2rem 0 2rem;
|
||||
height: 2.5rem;
|
||||
color: #fff;
|
||||
background-color: #1d1d1d;
|
||||
border-radius: 1.25rem;
|
||||
border: 1px solid #fff;
|
||||
text-align: center;
|
||||
font-size: 1.1rem;
|
||||
}
|
||||
input:focus{
|
||||
color: #000;
|
||||
background-color: #fff;
|
||||
}
|
||||
|
||||
|
||||
@media (max-width: 35rem) {
|
||||
input {
|
||||
width: calc(100% - 8rem);
|
||||
}
|
||||
}
|
||||
</style>
|
3
vue.config.js
Normal file
@ -0,0 +1,3 @@
|
||||
module.exports = {
|
||||
runtimeCompiler: true
|
||||
}
|