├── .browserslistrc ├── .eslintrc.js ├── .gitignore ├── .postcssrc.js ├── .travis.yml ├── CITATION.cff ├── README.md ├── babel.config.js ├── basic-vue-chat.png ├── build └── rollup.config.js ├── jest.config.js ├── package-lock.json ├── package.json ├── preview.png ├── public ├── favicon.ico └── index.html ├── src ├── App.vue ├── assets │ └── scss │ │ ├── main.scss │ │ ├── modules │ │ ├── _all.scss │ │ ├── _animations.scss │ │ ├── _colors.scss │ │ ├── _defaults.scss │ │ ├── _mixins.scss │ │ ├── _responsiveness.scss │ │ ├── _typography.scss │ │ └── _variables.scss │ │ └── partials │ │ ├── _base.scss │ │ ├── _features.scss │ │ ├── _header.scss │ │ ├── _input.scss │ │ ├── _message.scss │ │ ├── _messages.scss │ │ ├── _picker.scss │ │ └── _window.scss ├── components │ └── basic-vue-chat │ │ ├── BasicVueChat.vue │ │ ├── entry.js │ │ ├── input │ │ ├── InputButton.vue │ │ ├── InputContainer.vue │ │ └── InputField.vue │ │ ├── messages │ │ ├── MessageForeign.vue │ │ ├── MessageOwn.vue │ │ └── MessagesList.vue │ │ └── mocks │ │ └── mock-messages-list.js ├── helpers │ └── scroll.js ├── main.js └── wrapper.js └── tests └── unit ├── .eslintrc.js ├── messages └── messages-list.spec.js ├── mocks └── mock-messages-list.js └── props.spec.js /.browserslistrc: -------------------------------------------------------------------------------- 1 | > 1% 2 | last 2 versions 3 | not ie <= 8 -------------------------------------------------------------------------------- /.eslintrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | root: true, 3 | env: { 4 | node: true 5 | }, 6 | extends: [ 7 | 'plugin:vue/recommended', 8 | '@vue/standard' 9 | ], 10 | rules: { 11 | 'no-console': process.env.NODE_ENV === 'production' ? 'error' : 'off', 12 | 'no-debugger': process.env.NODE_ENV === 'production' ? 'error' : 'off' 13 | }, 14 | parserOptions: { 15 | parser: 'babel-eslint' 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (https://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # TypeScript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # Yarn Integrity file 55 | .yarn-integrity 56 | 57 | # dotenv environment variables file 58 | .env 59 | 60 | # next.js build output 61 | .next 62 | 63 | .DS_Store 64 | node_modules 65 | /dist 66 | 67 | /tests/e2e/videos/ 68 | /tests/e2e/screenshots/ 69 | 70 | # local env files 71 | .env.local 72 | .env.*.local 73 | 74 | # Log files 75 | npm-debug.log* 76 | yarn-debug.log* 77 | yarn-error.log* 78 | 79 | # Editor directories and files 80 | .idea 81 | .vscode 82 | *.suo 83 | *.ntvs* 84 | *.njsproj 85 | *.sln 86 | *.sw* 87 | -------------------------------------------------------------------------------- /.postcssrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | autoprefixer: {} 4 | } 5 | } 6 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "node" 4 | cache: npm -------------------------------------------------------------------------------- /CITATION.cff: -------------------------------------------------------------------------------- 1 | cff-version: 1.2.0 2 | message: "If you use this software, please cite it as below." 3 | authors: 4 | - family-names: "Maczan" 5 | given-names: "Jędrzej Paweł" 6 | orcid: "https://orcid.org/0000-0003-1741-6064" 7 | title: "Basic Vue Chat" 8 | date-released: 2022-09-08 9 | url: "https://github.com/jmaczan/basic-vue-chat" 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

basic-vue-chat logo

2 | 3 | # basic-vue-chat 4 | 5 | [![Version](https://img.shields.io/npm/v/basic-vue-chat.svg)](https://www.npmjs.com/package/basic-vue-chat) 6 | 7 | 8 | 9 | Implementation of Vue-based chat. 10 | 11 | - [basic-vue-chat](#basic-vue-chat) 12 | * [Installation](#installation) 13 | + [npm](#npm) 14 | + [yarn](#yarn) 15 | + [using repository](#using-repository) 16 | * [Dependencies](#dependencies) 17 | * [Usage](#usage) 18 | + [Pushing messages](#pushing-messages) 19 | + [Handling messages from user](#handling-messages-from-user) 20 | + [Images](#images) 21 | + [Commands](#commands) 22 | + [Mock data](#mock-data) 23 | * [Customization](#customization) 24 | + [Styles](#styles) 25 | + [Title](#title) 26 | + [Initial data](#initial-data) 27 | + [Styling](#styling) 28 | * [Code structure](#code-structure) 29 | * [Technologies used](#technologies-used) 30 | 31 | ## Installation 32 | 33 | You can install the component using package managers, such as npm or yarn or install component from the repository. 34 | 35 | ### npm 36 | ```bash 37 | npm i basic-vue-chat 38 | ``` 39 | 40 | ### yarn 41 | ```bash 42 | yarn add basic-vue-chat 43 | ``` 44 | 45 | ### using repository 46 | ```bash 47 | git clone https://github.com/jmaczan/basic-vue-chat.git 48 | cd basic-vue-chat 49 | npm i 50 | ``` 51 | 52 | ## Dependencies 53 | 54 | Components uses Vue (`vue` package), Fontawesome and Moment.js for Vue (`vue-moment`). 55 | 56 | ## Usage 57 | 58 | Chat is a single Vue component, which you can find in `/src/components/basic-vue-chat/`. To start, just import BasicVueChat component and put the following line into your html code: 59 | ```html 60 | 61 | ``` 62 | 63 | ### Pushing messages 64 | 65 | To push message to chat, just **pass newMessage prop to BasicVueChat**. Example: 66 | ```html 67 | 68 | ``` 69 | 70 | The `message` object above may be part of `data` in your Vue component in which you will use BasicVueChat. 71 | 72 | Example of correct message structure: 73 | ```javascript 74 | { 75 | id: 0, 76 | author: 'Person', 77 | imageUrl: 'http://path/to/image', 78 | image: '', 79 | contents: 'hi there', 80 | date: '16:30' 81 | } 82 | ``` 83 | 84 | You can find example of message pushing in `App.vue` file. 85 | 86 | ### Handling messages from user 87 | 88 | When user sends message, **the message is propagated to BasicVueChat component** and **event newOwnMessage is emitted**. To handle this event, you can for example do this: 89 | ```html 90 | 91 | ``` 92 | where `onNewOwnMessage(message)` is a method in your Vue component in which you will use BasicVueChat. 93 | 94 | Example of correct event payload structure: 95 | ```javascript 96 | { 97 | id: 1, 98 | imageUrl: 'http://path/to/image', 99 | image: File(), 100 | contents: 'hello', 101 | date: '16:31' 102 | } 103 | ``` 104 | 105 | ### Images 106 | 107 | You can upload and receive images. To attach image, use paperclip button. Image will be emitted in message on `image` (as `File` object) and `imageUrl` (path `string`) properties. 108 | 109 | ### Commands 110 | 111 | To start development, you can use hot reload mode: 112 | ``` 113 | npm run serve 114 | ``` 115 | 116 | To build production version: 117 | ``` 118 | npm run build 119 | ``` 120 | 121 | To run tests: 122 | ``` 123 | npm test 124 | ``` 125 | 126 | ### Mock data 127 | 128 | To attach mock data, just pass logic prop `attachMock` to BasicVueChat. 129 | 130 | ## Customization 131 | 132 | ### Styles 133 | Styles are imported in main `BasicVueChat` component and variables have `!default` values, so it means that you can override default values by defining your own variables before styles import. 134 | 135 | ```scss 136 | 141 | ``` 142 | 143 | ### Title 144 | 145 | Pass prop `title` to BasicVueChat component. 146 | ```html 147 | 148 | ``` 149 | 150 | ### Initial data 151 | 152 | Pass prop `initialFeed` to BasicVueChat component. 153 | ```html 154 | 155 | ``` 156 | Example of correct data structure: 157 | ```javascript 158 | const feed = [ 159 | { 160 | id: 1, 161 | author: 'Person', 162 | imageUrl: 'http://path/to/image', 163 | contents: 'hi there', 164 | date: '16:30' 165 | }, 166 | { 167 | id: 0, 168 | author: 'Me', 169 | contents: 'hello', 170 | date: '16:30' 171 | } 172 | ] 173 | ``` 174 | 175 | Pass prop `initialAuthorId` to BasicVueChat component to define current user's ID. Default value is `0`. 176 | 177 | ### Styling 178 | 179 | Chat uses SCSS, so you can easily override variables used in project. You can find them in `/src/assets/scss/modules/_variables.scss`. All variables have default values. 180 | 181 | | Description | Variable | Default value | 182 | |---|---|---| 183 | | Primary color | $primary | $slate-blue (#6B63D8) | 184 | | Secondary color | $secondary | $lavender (#B284ED) | 185 | | Header color | $header-color | $ghost-white (#FAF9FF) | 186 | | Input background color | $input-background-color | $alice-blue (#F2EFFF) | 187 | | Font family | $font-family | 'Source Sans Pro', sans-serif | 188 | | Font weight | $font-weight | 400 | 189 | | Font size | $font-size | 14px | 190 | | Dark text color | $dark-text-color | $madison (#2C3E50) | 191 | | Light text color | $light-text-color | $ghost-white (#FAF9FF) | 192 | | Dark background color | $dark-bg | $madison (#2C3E50) | 193 | | Light background color | $light-bg | $white (#FFFFFF) | 194 | | Chat window width | $window-width | 500px | 195 | | Chat window height | $window-height | 400px | 196 | | Message max width | $message-max-width | 200px | 197 | 198 | ## Code structure 199 | 200 | 1. assets 201 | - Sass standard CSS code structure 202 | - Components styles in `partials` directory 203 | - Variables and settings in `modules` directory 204 | 2. components 205 | - chat's components are in subdirectories of `basic-vue-chat` directory 206 | 3. helpers 207 | - reusable helpers for scrolling functionalities 208 | 4. App.vue - runner file 209 | 5. main.js - project config 210 | 211 | 212 | ## Technologies used 213 | 214 | 1. JavaScript 215 | * Vue 216 | * Moment.js 217 | 2. HTML5 218 | 3. CSS 219 | * SCSS 220 | * BEM 221 | 4. Tests 222 | * Jest 223 | * Vue test utils 224 | 5. Tooling 225 | * npm 226 | 6. Continuous Integration 227 | * Travis CI 228 | 7. Linting 229 | * ESLint standard config 230 | 231 | Developed and tested under macOS High Sierra 10.13 and Google Chrome 69. -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | presets: [ 3 | '@vue/app' 4 | ] 5 | } 6 | -------------------------------------------------------------------------------- /basic-vue-chat.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmaczan/basic-vue-chat/723a6281188e6a6cbb0bc6fe494b93c537f8d711/basic-vue-chat.png -------------------------------------------------------------------------------- /build/rollup.config.js: -------------------------------------------------------------------------------- 1 | import vue from 'rollup-plugin-vue' // Handle .vue SFC files 2 | import buble from 'rollup-plugin-buble' // Transpile/polyfill with reasonable browser support 3 | 4 | export default { 5 | input: 'src/wrapper.js', // Path relative to package.json 6 | output: { 7 | name: 'BasicVueChat', 8 | exports: 'named' 9 | }, 10 | plugins: [ 11 | vue({ 12 | css: true, // Dynamically inject css as a 25 | -------------------------------------------------------------------------------- /src/assets/scss/main.scss: -------------------------------------------------------------------------------- 1 | @import "partials/base"; 2 | 3 | @import "partials/header"; 4 | @import "partials/features"; 5 | @import "partials/input"; 6 | @import "partials/message"; 7 | @import "partials/messages"; 8 | @import "partials/picker"; 9 | @import "partials/window"; -------------------------------------------------------------------------------- /src/assets/scss/modules/_all.scss: -------------------------------------------------------------------------------- 1 | @import "animations"; 2 | @import "colors"; 3 | @import "typography"; 4 | @import "mixins"; 5 | @import "variables"; 6 | @import "responsiveness"; -------------------------------------------------------------------------------- /src/assets/scss/modules/_animations.scss: -------------------------------------------------------------------------------- 1 | .messages-list-item { 2 | transition: all 0.2s; 3 | } 4 | 5 | .messages-list-enter, .messages-list-leave-to 6 | /* .messages-list-leave-active below version 2.1.8 */ { 7 | opacity: 0; 8 | transform: translateY(30px); 9 | } 10 | .messages-list-leave-active { 11 | position: absolute; 12 | } -------------------------------------------------------------------------------- /src/assets/scss/modules/_colors.scss: -------------------------------------------------------------------------------- 1 | $liberty: #5F5AA2; 2 | $amethyst: #9067C6; 3 | $purple-navy: #4E4A85; 4 | $slate-blue: #6B63D8; 5 | $lavender: #B284ED; 6 | $lavender-gray: #CBC9D6; 7 | $white: #FFFFFF; 8 | $ghost-white: #FAF9FF; 9 | $alice-blue: #F2EFFF; 10 | $madison: #2C3E50; -------------------------------------------------------------------------------- /src/assets/scss/modules/_defaults.scss: -------------------------------------------------------------------------------- 1 | $base-font-family: $source-sans-pro-font !default; 2 | $base-font-weight: $regular !default; 3 | $base-font-size: 14px !default; 4 | 5 | $base-window-width: 500px !default; 6 | $base-window-height: 400px !default; 7 | $base-message-max-width: 200px !default; -------------------------------------------------------------------------------- /src/assets/scss/modules/_mixins.scss: -------------------------------------------------------------------------------- 1 | @mixin just-flex { 2 | display: -webkit-flex; 3 | display: flex; 4 | } 5 | 6 | @mixin flex($direction: column, $justify-content: center) { 7 | @include just-flex; 8 | flex-direction: $direction; 9 | justify-content: $justify-content; 10 | } 11 | 12 | @mixin box-shadow($values...) { 13 | @each $val in $values { 14 | -webkit-box-shadow: #{$val}; 15 | box-shadow: #{$val}; 16 | } 17 | } -------------------------------------------------------------------------------- /src/assets/scss/modules/_responsiveness.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jmaczan/basic-vue-chat/723a6281188e6a6cbb0bc6fe494b93c537f8d711/src/assets/scss/modules/_responsiveness.scss -------------------------------------------------------------------------------- /src/assets/scss/modules/_typography.scss: -------------------------------------------------------------------------------- 1 | @import url('https://fonts.googleapis.com/css?family=Source+Sans+Pro'); 2 | 3 | $light: 100; 4 | $regular: 400; 5 | $bold: 600; 6 | 7 | $source-sans-pro-font: 'Source Sans Pro', sans-serif; -------------------------------------------------------------------------------- /src/assets/scss/modules/_variables.scss: -------------------------------------------------------------------------------- 1 | @import "defaults"; 2 | 3 | $primary: $slate-blue !default; 4 | $secondary: $lavender !default; 5 | 6 | $header-color: $ghost-white !default; 7 | 8 | $input-background-color: $alice-blue !default; 9 | 10 | $font-family: $base-font-family; 11 | $font-weight: $base-font-weight; 12 | $font-size: $base-font-size; 13 | 14 | $dark-text-color: $madison !default; 15 | $light-text-color: $ghost-white !default; 16 | 17 | $dark-bg: $madison !default; 18 | $light-bg: $white !default; 19 | 20 | $window-width: $base-window-width !default; 21 | $window-height: $base-window-height !default; 22 | $message-max-width: $base-message-max-width !default; -------------------------------------------------------------------------------- /src/assets/scss/partials/_base.scss: -------------------------------------------------------------------------------- 1 | @import "../modules/all"; 2 | 3 | body { 4 | font-family: $font-family; 5 | font-weight: $base-font-weight; 6 | font-size: $base-font-size; 7 | background-color: $light-bg; 8 | color: $dark-text-color; 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | text-align: center; 12 | } -------------------------------------------------------------------------------- /src/assets/scss/partials/_features.scss: -------------------------------------------------------------------------------- 1 | .features { 2 | &__container { 3 | @include just-flex; 4 | position: relative; 5 | bottom: 0; 6 | } 7 | } -------------------------------------------------------------------------------- /src/assets/scss/partials/_header.scss: -------------------------------------------------------------------------------- 1 | .window { 2 | &__header { 3 | 4 | &__container { 5 | background: linear-gradient(90deg, $primary, $secondary); 6 | padding: 10px 5px; 7 | color: $header-color; 8 | font-weight: $bold; 9 | z-index: 1; 10 | 11 | @include box-shadow(0 2px 2px -2px $madison); 12 | } 13 | 14 | } 15 | } -------------------------------------------------------------------------------- /src/assets/scss/partials/_input.scss: -------------------------------------------------------------------------------- 1 | .window { 2 | &__input { 3 | 4 | &__container { 5 | position: relative; 6 | bottom: 0; 7 | 8 | input[type="file"] { 9 | height: 0.1px !important; 10 | width: 0.1px !important; 11 | opacity: 0; 12 | overflow: hidden; 13 | position: absolute; 14 | z-index: -1; 15 | } 16 | 17 | input[type="text"] { 18 | font-size: 12px; 19 | } 20 | 21 | .image { 22 | &--uploaded { 23 | max-width: 50px; 24 | max-height: 50px; 25 | margin-right: 5px; 26 | border-radius: 12px; 27 | } 28 | } 29 | 30 | .image + label { 31 | @include just-flex; 32 | align-self: center; 33 | margin-right: 5px; 34 | color: $primary; 35 | cursor: pointer; 36 | } 37 | 38 | .image:focus + label, 39 | .image + label:hover { 40 | color: $secondary; 41 | cursor: pointer; 42 | } 43 | 44 | .input { 45 | &__container { 46 | @include flex(row, space-between); 47 | padding: 7px 5px; 48 | align-items: center; 49 | } 50 | 51 | &-images-upload { 52 | @include just-flex; 53 | align-self: center; 54 | margin-right: 5px; 55 | color: $primary; 56 | cursor: pointer; 57 | } 58 | 59 | &-emoji-picker { 60 | 61 | &__container { 62 | position: absolute; 63 | bottom: 30px; 64 | right: 5px; 65 | z-index: 3; 66 | } 67 | } 68 | 69 | &__field { 70 | @include just-flex; 71 | flex-grow: 9999; 72 | padding: 5px 10px; 73 | margin-right: 5px; 74 | border-radius: 12px; 75 | background-color: $input-background-color; 76 | 77 | input { 78 | border: none; 79 | background-color: inherit; 80 | color: $dark-text-color; 81 | width: 100%; 82 | 83 | &:focus { 84 | outline: none; 85 | } 86 | } 87 | } 88 | 89 | &__button { 90 | @include just-flex; 91 | padding: 5px 10px; 92 | border-radius: 12px; 93 | background-color: $primary; 94 | color: $light-text-color; 95 | font-weight: $bold; 96 | cursor: pointer; 97 | } 98 | } 99 | } 100 | } 101 | } -------------------------------------------------------------------------------- /src/assets/scss/partials/_message.scss: -------------------------------------------------------------------------------- 1 | .window { 2 | 3 | %message { 4 | padding: 3px 5px; 5 | 6 | &__contents { 7 | max-width: $message-max-width !important; 8 | word-wrap: break-word; 9 | } 10 | } 11 | 12 | .message { 13 | 14 | @mixin message__contents($border-color: $alice-blue, $color: inherit, $background-color: $ghost-white) { 15 | border: 1px solid $border-color; 16 | border-radius: 12px; 17 | color: $color; 18 | background-color: $background-color; 19 | padding: 3px 5px; 20 | } 21 | 22 | &--foreign { 23 | @extend %message; 24 | @include flex(row, flex-start); 25 | 26 | .message { 27 | &__author { 28 | @include flex(column, center); 29 | font-weight: $bold; 30 | margin-right: 5px; 31 | } 32 | 33 | &__contents { 34 | @include message__contents(transparent); 35 | margin-right: 5px; 36 | } 37 | 38 | &__date { 39 | @include flex(column, center); 40 | color: $lavender-gray; 41 | } 42 | } 43 | } 44 | 45 | &--own { 46 | @extend %message; 47 | @include flex(row, flex-end); 48 | 49 | .message { 50 | &__contents { 51 | @extend %message__contents; 52 | @include message__contents(transparent, $ghost-white, $secondary); 53 | } 54 | 55 | &__date { 56 | @include flex(column, center); 57 | color: $lavender-gray; 58 | margin-right: 5px; 59 | } 60 | } 61 | } 62 | } 63 | } -------------------------------------------------------------------------------- /src/assets/scss/partials/_messages.scss: -------------------------------------------------------------------------------- 1 | .window { 2 | &__messages { 3 | 4 | &__container { 5 | @include flex(column, flex-start); 6 | flex-grow: 999; 7 | overflow: auto; 8 | padding: 3px 0; 9 | border-left: 1px solid $alice-blue; 10 | border-right: 1px solid $alice-blue; 11 | border-bottom: 1px solid $alice-blue; 12 | transition: all 0.5s; 13 | overflow: scroll; 14 | overflow-x: hidden; 15 | 16 | &::-webkit-scrollbar { 17 | width: 0px; /* remove scrollbar space */ 18 | background: transparent; /* optional: just make scrollbar invisible */ 19 | } 20 | 21 | &::-webkit-scrollbar { 22 | width: 0; 23 | } 24 | 25 | &::-webkit-scrollbar-track { 26 | } 27 | 28 | &::-webkit-scrollbar-thumb { 29 | background-color: transparent; 30 | } 31 | } 32 | } 33 | } -------------------------------------------------------------------------------- /src/assets/scss/partials/_picker.scss: -------------------------------------------------------------------------------- 1 | .emoji-mart { 2 | height: 250px !important; 3 | } -------------------------------------------------------------------------------- /src/assets/scss/partials/_window.scss: -------------------------------------------------------------------------------- 1 | .window { 2 | @include flex(column); 3 | @include box-shadow(0 0 2px $madison); 4 | max-width: $window-width; 5 | height: $window-height; 6 | border: 0px solid transparent; 7 | border-radius: 15px; 8 | overflow: hidden; 9 | } -------------------------------------------------------------------------------- /src/components/basic-vue-chat/BasicVueChat.vue: -------------------------------------------------------------------------------- 1 | 33 | 34 | 133 | 134 | 137 | -------------------------------------------------------------------------------- /src/components/basic-vue-chat/entry.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import BasicVueChat from './BasicVueChat.vue' 3 | 4 | const Components = { 5 | BasicVueChat 6 | } 7 | 8 | Object.keys(Components).forEach(name => { 9 | Vue.component(name, Components[name]) 10 | }) 11 | 12 | export default Components 13 | -------------------------------------------------------------------------------- /src/components/basic-vue-chat/input/InputButton.vue: -------------------------------------------------------------------------------- 1 | 8 | 9 | 20 | 21 | 24 | -------------------------------------------------------------------------------- /src/components/basic-vue-chat/input/InputContainer.vue: -------------------------------------------------------------------------------- 1 | 53 | 54 | 121 | 122 | 127 | -------------------------------------------------------------------------------- /src/components/basic-vue-chat/input/InputField.vue: -------------------------------------------------------------------------------- 1 | 15 | 16 | 33 | 34 | 37 | -------------------------------------------------------------------------------- /src/components/basic-vue-chat/messages/MessageForeign.vue: -------------------------------------------------------------------------------- 1 | 20 | 21 | 48 | 49 | 52 | -------------------------------------------------------------------------------- /src/components/basic-vue-chat/messages/MessageOwn.vue: -------------------------------------------------------------------------------- 1 | 17 | 18 | 45 | 46 | 49 | -------------------------------------------------------------------------------- /src/components/basic-vue-chat/messages/MessagesList.vue: -------------------------------------------------------------------------------- 1 | 23 | 24 | 50 | 51 | 54 | -------------------------------------------------------------------------------- /src/components/basic-vue-chat/mocks/mock-messages-list.js: -------------------------------------------------------------------------------- 1 | export default { 2 | authorId: 1, 3 | feed: [ 4 | { 5 | id: 0, 6 | author: 'Person', 7 | contents: 'hi there', 8 | date: '16:30' 9 | }, 10 | { 11 | id: 1, 12 | author: 'Me', 13 | contents: 'hello', 14 | date: '16:30' 15 | }, 16 | { 17 | id: 1, 18 | author: 'Me', 19 | contents: 'lol', 20 | date: '16:31' 21 | } 22 | ] 23 | } 24 | -------------------------------------------------------------------------------- /src/helpers/scroll.js: -------------------------------------------------------------------------------- 1 | export function scrollToBottom () { 2 | setTimeout(function () { 3 | var scrollContainer = document.getElementById('window__messages__container') 4 | var isScrolledToBottom = scrollContainer.scrollHeight - scrollContainer.clientHeight <= scrollContainer.scrollTop + 1 5 | if (!isScrolledToBottom) { scrollContainer.scrollTop = scrollContainer.scrollHeight } 6 | }, 201) 7 | } 8 | -------------------------------------------------------------------------------- /src/main.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue' 2 | import App from './App.vue' 3 | import { library } from '@fortawesome/fontawesome-svg-core' 4 | import { faPaperclip, faSmile } from '@fortawesome/free-solid-svg-icons' 5 | import { FontAwesomeIcon } from '@fortawesome/vue-fontawesome' 6 | 7 | Vue.use(require('vue-moment')) 8 | 9 | library.add(faPaperclip) 10 | library.add(faSmile) 11 | 12 | Vue.component('font-awesome-icon', FontAwesomeIcon) 13 | 14 | Vue.config.productionTip = false 15 | 16 | new Vue({ 17 | render: h => h(App) 18 | }).$mount('#app') 19 | -------------------------------------------------------------------------------- /src/wrapper.js: -------------------------------------------------------------------------------- 1 | // Import vue component 2 | import BasicVueChat from './components/basic-vue-chat/BasicVueChat.vue' 3 | 4 | // Declare install function executed by Vue.use() 5 | export function install (Vue) { 6 | if (install.installed) return 7 | install.installed = true 8 | Vue.component('BasicVueChat', BasicVueChat) 9 | } 10 | 11 | // Create module definition for Vue.use() 12 | const plugin = { 13 | install 14 | } 15 | 16 | // Auto-install when vue is found (eg. in browser via