diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/assets/css/tailwind.css | 31 | ||||
-rw-r--r-- | src/components/group/GroupMaker.vue | 21 | ||||
-rw-r--r-- | src/components/group/GroupSender.vue | 62 | ||||
-rw-r--r-- | src/components/group/Message.vue | 20 | ||||
-rw-r--r-- | src/components/searcher/Searcher.vue | 41 | ||||
-rw-r--r-- | src/components/searcher/Sugestion.vue | 21 | ||||
-rw-r--r-- | src/main.js | 2 | ||||
-rw-r--r-- | src/services/ChatService.js | 12 | ||||
-rw-r--r-- | src/views/Home.vue | 52 | ||||
-rw-r--r-- | src/views/Login.vue | 12 | ||||
-rw-r--r-- | src/views/Register.vue | 14 |
11 files changed, 182 insertions, 106 deletions
diff --git a/src/assets/css/tailwind.css b/src/assets/css/tailwind.css new file mode 100644 index 0000000..1028353 --- /dev/null +++ b/src/assets/css/tailwind.css | |||
@@ -0,0 +1,31 @@ | |||
1 | @tailwind base; | ||
2 | @tailwind components; | ||
3 | @tailwind utilities; | ||
4 | |||
5 | @layer base { | ||
6 | .inset-center { | ||
7 | position: absolute; | ||
8 | top: 50%; | ||
9 | left: 50%; | ||
10 | transform: translate(-50%, -50%); | ||
11 | } | ||
12 | |||
13 | kbd { | ||
14 | @apply bg-gray-600; | ||
15 | @apply p-1; | ||
16 | @apply rounded-md; | ||
17 | @apply border-gray-800; | ||
18 | @apply font-fira; | ||
19 | } | ||
20 | |||
21 | .searcher { | ||
22 | @apply inset-center; | ||
23 | @apply w-2/3; | ||
24 | @apply h-90; | ||
25 | @apply shadow-lg; | ||
26 | @apply bg-gray-900; | ||
27 | @apply p-4 rounded-lg; | ||
28 | @apply border-2; | ||
29 | @apply border-blue-900; | ||
30 | } | ||
31 | } | ||
diff --git a/src/components/group/GroupMaker.vue b/src/components/group/GroupMaker.vue index f3da293..06963e3 100644 --- a/src/components/group/GroupMaker.vue +++ b/src/components/group/GroupMaker.vue | |||
@@ -1,15 +1,17 @@ | |||
1 | <template> | 1 | <template> |
2 | <div class="group_maker"> | 2 | <div class="searcher"> |
3 | Group maker | 3 | <div class="text-2xl p-2"> Group maker </div> |
4 | <form @submit="make_group"> | 4 | <form @submit="make_group"> |
5 | <input | 5 | <input |
6 | v-model="group_name" | 6 | v-model="group_name" |
7 | ref='input' | 7 | ref='input' |
8 | type="text" | 8 | type="text" |
9 | placeholder="Type group name..." | 9 | placeholder="Nazwa grupy..." |
10 | class="w-full bg-gray-800 mb-2 mt-10 p-2" | ||
11 | @keydown="hotkeys" | ||
10 | /> | 12 | /> |
11 | 13 | ||
12 | <select multiple v-model="users_selection"> | 14 | <select multiple class="w-full bg-gray-800 p-4 mb-10" v-model="users_selection"> |
13 | 15 | ||
14 | <option | 16 | <option |
15 | v-for="user in users" | 17 | v-for="user in users" |
@@ -19,6 +21,8 @@ | |||
19 | </option> | 21 | </option> |
20 | 22 | ||
21 | </select> | 23 | </select> |
24 | |||
25 | <input type="submit" class="w-full p-2 bg-gray-800"> | ||
22 | </form> | 26 | </form> |
23 | </div> | 27 | </div> |
24 | </template> | 28 | </template> |
@@ -69,6 +73,15 @@ export default { | |||
69 | this.close() | 73 | this.close() |
70 | 74 | ||
71 | console.log(this.users) | 75 | console.log(this.users) |
76 | }, | ||
77 | |||
78 | hotkeys(e) { | ||
79 | switch(e.code) { | ||
80 | case 'Delete': | ||
81 | e.preventDefault() | ||
82 | this.$emit('close') | ||
83 | break | ||
84 | } | ||
72 | } | 85 | } |
73 | }, | 86 | }, |
74 | 87 | ||
diff --git a/src/components/group/GroupSender.vue b/src/components/group/GroupSender.vue index ba36949..a815561 100644 --- a/src/components/group/GroupSender.vue +++ b/src/components/group/GroupSender.vue | |||
@@ -1,12 +1,25 @@ | |||
1 | <template> | 1 | <template> |
2 | <div class="group_view"> | 2 | <div |
3 | <h1> {{group.name}} </h1> | 3 | class="bg-gray-900 w-full m-2 mb-0 border-4" |
4 | <div class="messages"> | 4 | :class="{ |
5 | 'border-red-900': isFocus, | ||
6 | 'border-blue-900': !isFocus | ||
7 | }" | ||
8 | > | ||
9 | |||
10 | <h1 class="text-2xl p-2 bg-blue-900"> {{group.name}} </h1> | ||
11 | <div class="overflow-auto h-64 p-2" ref="messages"> | ||
5 | <Message v-for="message in messages" :key="message.id" :message="message" /> | 12 | <Message v-for="message in messages" :key="message.id" :message="message" /> |
6 | </div> | 13 | </div> |
7 | 14 | ||
8 | <form @submit="send_message"> | 15 | <form @submit="send_message"> |
9 | <input v-model="message" type="text" ref="input" /> | 16 | <input |
17 | v-model="message" | ||
18 | class="w-full bg-blue-900 p-2" placeholder="Napisz cos..." type="text" ref="input" | ||
19 | @focus="isFocus=true" | ||
20 | @blur="isFocus=false" | ||
21 | @keydown="hotkeys" | ||
22 | /> | ||
10 | </form> | 23 | </form> |
11 | </div> | 24 | </div> |
12 | </template> | 25 | </template> |
@@ -20,6 +33,7 @@ export default { | |||
20 | return { | 33 | return { |
21 | message: "", | 34 | message: "", |
22 | messages: [], | 35 | messages: [], |
36 | isFocus: false | ||
23 | } | 37 | } |
24 | }, | 38 | }, |
25 | 39 | ||
@@ -45,13 +59,38 @@ export default { | |||
45 | 59 | ||
46 | console.log(data) | 60 | console.log(data) |
47 | 61 | ||
48 | if(status===200) | 62 | if(status===200){ |
49 | this.messages = data.messages | 63 | this.messages = data.messages |
64 | this.scroll_down() | ||
65 | } | ||
50 | }, | 66 | }, |
51 | 67 | ||
52 | push_message(message) { | 68 | push_message(message) { |
53 | if(message.receiver == this.group.id) | 69 | if(message.receiver == this.group.id){ |
54 | this.messages.push(message) | 70 | this.messages.push(message) |
71 | this.scroll_down() | ||
72 | } | ||
73 | }, | ||
74 | |||
75 | scroll_down() { | ||
76 | this.$nextTick(function () { | ||
77 | const messages = this.$refs.messages | ||
78 | console.log(messages) | ||
79 | messages.scrollTop = messages.scrollHeight | ||
80 | }) | ||
81 | }, | ||
82 | |||
83 | hotkeys(e) { | ||
84 | switch(e.code) { | ||
85 | case 'Delete': | ||
86 | e.preventDefault() | ||
87 | this.$emit('close', this.group.id) | ||
88 | break | ||
89 | case 'Escape': | ||
90 | e.preventDefault() | ||
91 | this.$refs.input.blur() | ||
92 | break | ||
93 | } | ||
55 | } | 94 | } |
56 | }, | 95 | }, |
57 | 96 | ||
@@ -72,14 +111,3 @@ export default { | |||
72 | } | 111 | } |
73 | } | 112 | } |
74 | </script> | 113 | </script> |
75 | |||
76 | <style scoped> | ||
77 | .group_view { | ||
78 | width: 25%; | ||
79 | } | ||
80 | |||
81 | .messages { | ||
82 | overflow:auto; | ||
83 | height: 300px; | ||
84 | } | ||
85 | </style> | ||
diff --git a/src/components/group/Message.vue b/src/components/group/Message.vue index eedcc6e..556deb9 100644 --- a/src/components/group/Message.vue +++ b/src/components/group/Message.vue | |||
@@ -1,8 +1,8 @@ | |||
1 | <template> | 1 | <template> |
2 | <div class="message" :class="{mine: is_message_mine}"> | 2 | <div class="w-full text-left mt-2" :class="{'text-right': is_message_mine}"> |
3 | <div class="sender">{{ get_message_user }}</div> | 3 | <div class="">{{ get_message_user }}</div> |
4 | <div class="content">{{ get_message_content }}</div> | 4 | <div class="">{{ get_message_content }}</div> |
5 | <div class="date">{{ get_message_date }}</div> | 5 | <div class="">{{ get_message_date }}</div> |
6 | </div> | 6 | </div> |
7 | </template> | 7 | </template> |
8 | 8 | ||
@@ -29,15 +29,3 @@ export default { | |||
29 | } | 29 | } |
30 | } | 30 | } |
31 | </script> | 31 | </script> |
32 | |||
33 | <style scoped> | ||
34 | .message { | ||
35 | width: 100%; | ||
36 | margin-bottom: 10px; | ||
37 | color: white; | ||
38 | } | ||
39 | |||
40 | .mine { | ||
41 | color: red; | ||
42 | } | ||
43 | </style> | ||
diff --git a/src/components/searcher/Searcher.vue b/src/components/searcher/Searcher.vue index f8dd51f..e74600a 100644 --- a/src/components/searcher/Searcher.vue +++ b/src/components/searcher/Searcher.vue | |||
@@ -1,7 +1,8 @@ | |||
1 | <template> | 1 | <template> |
2 | <div id="searcher"> | 2 | <div class="searcher"> |
3 | <input | 3 | <input |
4 | type="text" | 4 | type="text" |
5 | class="w-full bg-gray-800 p-2 mb-4" | ||
5 | v-model='search' | 6 | v-model='search' |
6 | ref='input' | 7 | ref='input' |
7 | @keydown="hotkeys" | 8 | @keydown="hotkeys" |
@@ -13,7 +14,7 @@ | |||
13 | v-for="sugestion in sugestions" | 14 | v-for="sugestion in sugestions" |
14 | :key="sugestion[0]" | 15 | :key="sugestion[0]" |
15 | :sugestion="sugestion" | 16 | :sugestion="sugestion" |
16 | :class="{selected: sugestion[0] === current[0]}" | 17 | :class="{'bg-gray-800': sugestion[0] === current[0]}" |
17 | /> | 18 | /> |
18 | </div> | 19 | </div> |
19 | </template> | 20 | </template> |
@@ -72,7 +73,11 @@ export default { | |||
72 | 73 | ||
73 | hotkeys(e) { | 74 | hotkeys(e) { |
74 | switch(e.code) { | 75 | switch(e.code) { |
75 | case 'Escape': | 76 | case 'Escape': |
77 | e.preventDefault() | ||
78 | this.close() | ||
79 | break | ||
80 | case 'Delete': | ||
76 | e.preventDefault() | 81 | e.preventDefault() |
77 | this.close() | 82 | this.close() |
78 | break | 83 | break |
@@ -127,31 +132,3 @@ export default { | |||
127 | } | 132 | } |
128 | } | 133 | } |
129 | </script> | 134 | </script> |
130 | |||
131 | <style scoped> | ||
132 | #searcher { | ||
133 | position: absolute; | ||
134 | width: 30%; | ||
135 | height: 80%; | ||
136 | top: 50%; | ||
137 | left: 50%; | ||
138 | background-color: #202020; | ||
139 | padding: 20px; | ||
140 | border-radius: 10px; | ||
141 | transform: translate(-50%, -50%); | ||
142 | } | ||
143 | |||
144 | #searcher input { | ||
145 | width: 100%; | ||
146 | margin-bottom: 20px; | ||
147 | padding: 10px; | ||
148 | padding-right: 0px; | ||
149 | height: 20px; | ||
150 | border: none; | ||
151 | background-color: #303030; | ||
152 | } | ||
153 | |||
154 | .selected { | ||
155 | background-color: #505050; | ||
156 | } | ||
157 | </style> | ||
diff --git a/src/components/searcher/Sugestion.vue b/src/components/searcher/Sugestion.vue index 4721ca2..15a177d 100644 --- a/src/components/searcher/Sugestion.vue +++ b/src/components/searcher/Sugestion.vue | |||
@@ -1,5 +1,5 @@ | |||
1 | <template> | 1 | <template> |
2 | <div class="sugestion"> | 2 | <div class="w-auto bg-gray-700 p-2 text-center mt-5"> |
3 | <span>{{sugestion[0]}}</span> | 3 | <span>{{sugestion[0]}}</span> |
4 | </div> | 4 | </div> |
5 | </template> | 5 | </template> |
@@ -9,24 +9,5 @@ export default { | |||
9 | props: { | 9 | props: { |
10 | sugestion: Array | 10 | sugestion: Array |
11 | }, | 11 | }, |
12 | |||
13 | created() { | ||
14 | this.$nextTick(function () { | ||
15 | }) | ||
16 | } | ||
17 | |||
18 | } | 12 | } |
19 | </script> | 13 | </script> |
20 | |||
21 | <style scoped> | ||
22 | .sugestion { | ||
23 | width: 100%; | ||
24 | margin-left: auto; | ||
25 | margin-right: auto; | ||
26 | background-color: #303030; | ||
27 | |||
28 | margin-top: 10px; | ||
29 | padding: 5px; | ||
30 | padding-right: 0px; | ||
31 | } | ||
32 | </style> | ||
diff --git a/src/main.js b/src/main.js index fd31090..50babcd 100644 --- a/src/main.js +++ b/src/main.js | |||
@@ -6,6 +6,8 @@ import Axios from 'axios' | |||
6 | import Notifications from 'vue-notification' | 6 | import Notifications from 'vue-notification' |
7 | import VueHotkey from 'v-hotkey' | 7 | import VueHotkey from 'v-hotkey' |
8 | 8 | ||
9 | import '@/assets/css/tailwind.css' | ||
10 | |||
9 | Vue.config.productionTip = false | 11 | Vue.config.productionTip = false |
10 | 12 | ||
11 | Axios.defaults.headers.common['Authorization'] = store.state.token !== "" && `Token ${store.state.token}`; | 13 | Axios.defaults.headers.common['Authorization'] = store.state.token !== "" && `Token ${store.state.token}`; |
diff --git a/src/services/ChatService.js b/src/services/ChatService.js index d077e9b..d03f250 100644 --- a/src/services/ChatService.js +++ b/src/services/ChatService.js | |||
@@ -37,5 +37,17 @@ export default { | |||
37 | } | 37 | } |
38 | }) | 38 | }) |
39 | .catch(error => error_notify(error)) | 39 | .catch(error => error_notify(error)) |
40 | }, | ||
41 | |||
42 | async get_group_detail(group_pk) { | ||
43 | return await axios | ||
44 | .get(url+`groups/detail/${group_pk}/`) | ||
45 | .then(res => { | ||
46 | return { | ||
47 | status: res.status, | ||
48 | data: res.data | ||
49 | } | ||
50 | }) | ||
51 | .catch(error => error_notify(error)) | ||
40 | } | 52 | } |
41 | } | 53 | } |
diff --git a/src/views/Home.vue b/src/views/Home.vue index d85760b..205a260 100644 --- a/src/views/Home.vue +++ b/src/views/Home.vue | |||
@@ -1,11 +1,19 @@ | |||
1 | <template> | 1 | <template> |
2 | <div class="home" v-hotkey="keymap"> | 2 | <div class="home" v-hotkey="keymap"> |
3 | Hi {{get_username}}! | 3 | <div class="inset-center"> |
4 | <div class="text-center bg-gray-900 p-5 rounded-lg"> | ||
5 | <p class="text-3xl capitalize">Witaj, {{get_username}}!</p> | ||
6 | <p class="mt-5"><kbd>Ctl</kbd> + <kbd>Shift</kbd> + <kbd>P</kbd> </p> | ||
7 | </div> | ||
8 | </div> | ||
4 | 9 | ||
5 | <div v-for="group in groups" :key="group.name" > | 10 | <div class="flex flex-row justify-around"> |
6 | <GroupSender | 11 | <GroupSender |
12 | v-for="group in groups" | ||
7 | :group="group" | 13 | :group="group" |
8 | :socket="socket" | 14 | :socket="socket" |
15 | :key="group.name" | ||
16 | @close="closeGroupSender" | ||
9 | /> | 17 | /> |
10 | </div> | 18 | </div> |
11 | 19 | ||
@@ -27,6 +35,7 @@ | |||
27 | import Searcher from '@/components/searcher/Searcher.vue' | 35 | import Searcher from '@/components/searcher/Searcher.vue' |
28 | import GroupMaker from '@/components/group/GroupMaker.vue' | 36 | import GroupMaker from '@/components/group/GroupMaker.vue' |
29 | import GroupSender from '@/components/group/GroupSender.vue' | 37 | import GroupSender from '@/components/group/GroupSender.vue' |
38 | import ChatService from '@/services/ChatService.js' | ||
30 | import io from 'socket.io-client' | 39 | import io from 'socket.io-client' |
31 | 40 | ||
32 | const popups = { | 41 | const popups = { |
@@ -62,12 +71,29 @@ export default { | |||
62 | let groups = this.groups.slice() | 71 | let groups = this.groups.slice() |
63 | let index = groups.findIndex(o => o.name===group.name) | 72 | let index = groups.findIndex(o => o.name===group.name) |
64 | 73 | ||
74 | if(groups.length >=3) | ||
75 | groups.shift() | ||
76 | |||
65 | if(index >= 0) | 77 | if(index >= 0) |
66 | groups.splice(index, 1) | 78 | groups.splice(index, 1) |
67 | else | 79 | else |
68 | groups.push(group) | 80 | groups.push(group) |
69 | 81 | ||
70 | this.groups = groups | 82 | this.groups = groups |
83 | }, | ||
84 | |||
85 | async joinAllGroupsSocket() { | ||
86 | const {data, status} = await ChatService.get_all_user_groups() | ||
87 | |||
88 | if(status === 200) | ||
89 | data.forEach(group => { | ||
90 | this.socket.emit("join_group", {group_id: group.id}) | ||
91 | }) | ||
92 | }, | ||
93 | |||
94 | closeGroupSender(group_id) { | ||
95 | const index = this.groups.findIndex(group => group.id === group_id) | ||
96 | this.groups.splice(index, 1) | ||
71 | } | 97 | } |
72 | }, | 98 | }, |
73 | 99 | ||
@@ -82,7 +108,7 @@ export default { | |||
82 | 'ctrl+shift+p': this.toogleSearcherShow, | 108 | 'ctrl+shift+p': this.toogleSearcherShow, |
83 | 'esc': this.hideGroup | 109 | 'esc': this.hideGroup |
84 | } | 110 | } |
85 | } | 111 | }, |
86 | }, | 112 | }, |
87 | 113 | ||
88 | components: { | 114 | components: { |
@@ -99,6 +125,7 @@ export default { | |||
99 | this.socket = io() | 125 | this.socket = io() |
100 | this.socket.auth = { token: this.$store.getters.get_token }; | 126 | this.socket.auth = { token: this.$store.getters.get_token }; |
101 | this.socket.connect(); | 127 | this.socket.connect(); |
128 | this.joinAllGroupsSocket() | ||
102 | 129 | ||
103 | this.socket.on("connect", () => { | 130 | this.socket.on("connect", () => { |
104 | console.log("Socket connected!") | 131 | console.log("Socket connected!") |
@@ -107,7 +134,24 @@ export default { | |||
107 | this.socket.on("disconnect", () => { | 134 | this.socket.on("disconnect", () => { |
108 | console.log("Scoket dsiconected") | 135 | console.log("Scoket dsiconected") |
109 | }) | 136 | }) |
137 | |||
138 | this.socket.on("receive_group_message", async ({message}) => { | ||
139 | const index = this.groups.findIndex(group => {return group.id === message.receiver}) | ||
140 | |||
141 | if(index<0) { | ||
142 | const {status, data} = await ChatService.get_group_detail(message.receiver) | ||
143 | if(status!==200) | ||
144 | return | ||
145 | |||
146 | this.$notify({ | ||
147 | type: 'success', | ||
148 | title: `Groupa: ${data.name}`, | ||
149 | text: `${message.sender.username}, napisal "${message.message}"`, | ||
150 | duration: -1 | ||
151 | }) | ||
152 | } | ||
153 | }) | ||
110 | } | 154 | } |
111 | 155 | ||
112 | } | 156 | } |
113 | </script> | 157 | </script> |
diff --git a/src/views/Login.vue b/src/views/Login.vue index cb5c8d8..2763840 100644 --- a/src/views/Login.vue +++ b/src/views/Login.vue | |||
@@ -1,13 +1,13 @@ | |||
1 | <template> | 1 | <template> |
2 | <div id="login"> | 2 | <div id="login" class="inset-center bg-gray-900 p-4 rounded-lg shadow-lg"> |
3 | <form @submit="log_in"> | 3 | <form @submit="log_in"> |
4 | <input type="text" placeholder="Login" v-model="login"> | 4 | <input type="text" placeholder="Login" v-model="login" class="w-full bg-gray-800 p-2 mb-2"> |
5 | <input type="password" placeholder="Password" v-model="password"> | 5 | <input type="password" placeholder="Password" v-model="password" class="w-full bg-gray-800 p-2 mb-4"> |
6 | 6 | ||
7 | <input type="submit" value="Login!"> | 7 | <input type="submit" value="Login!" class="w-full bg-gray-800 p-2 mb-2"> |
8 | </form> | 8 | </form> |
9 | 9 | ||
10 | <router-link to="/register"> Still don't have an account? </router-link> | 10 | <router-link to="/register"> Nadal nie masz konta? </router-link> |
11 | 11 | ||
12 | </div> | 12 | </div> |
13 | </template> | 13 | </template> |
@@ -54,4 +54,4 @@ export default { | |||
54 | 54 | ||
55 | <style> | 55 | <style> |
56 | 56 | ||
57 | </style> \ No newline at end of file | 57 | </style> |
diff --git a/src/views/Register.vue b/src/views/Register.vue index eb382c5..fa8822b 100644 --- a/src/views/Register.vue +++ b/src/views/Register.vue | |||
@@ -1,14 +1,14 @@ | |||
1 | <template> | 1 | <template> |
2 | <div id="register"> | 2 | <div id="register" class="inset-center bg-gray-900 p-4 rounded-lg shadow-lg"> |
3 | <form @submit="register"> | 3 | <form @submit="register"> |
4 | <input type="text" placeholder="Login" v-model="login"> | 4 | <input type="text" placeholder="Login" v-model="login" class="w-full bg-gray-800 p-2 mb-2"> |
5 | <input type="password" placeholder="Password" v-model="password"> | 5 | <input type="password" placeholder="Password" v-model="password" class="w-full bg-gray-800 p-2 mb-2"> |
6 | <input type="password" placeholder="Repeat password" v-model="repeat_password"> | 6 | <input type="password" placeholder="Repeat password" v-model="repeat_password" class="w-full bg-gray-800 p-2 mb-4"> |
7 | 7 | ||
8 | <input type="submit" value="Register!"> | 8 | <input type="submit" value="Register!" class="w-full bg-gray-800 p-2 mb-2"> |
9 | </form> | 9 | </form> |
10 | 10 | ||
11 | <router-link to="/login">Already have an account?</router-link> | 11 | <router-link to="/login">Juz masz konto?</router-link> |
12 | 12 | ||
13 | </div> | 13 | </div> |
14 | </template> | 14 | </template> |
@@ -66,4 +66,4 @@ export default { | |||
66 | 66 | ||
67 | <style> | 67 | <style> |
68 | 68 | ||
69 | </style> \ No newline at end of file | 69 | </style> |