chat 0.0.1 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (68) hide show
  1. checksums.yaml +4 -4
  2. data/MIT-LICENSE +20 -0
  3. data/README.md +47 -22
  4. data/Rakefile +27 -1
  5. data/app/assets/config/chat_manifest.js +2 -0
  6. data/app/assets/javascripts/chat.js +16 -0
  7. data/app/assets/javascripts/chat/cable.js +13 -0
  8. data/app/assets/javascripts/chat/channels/message.coffee +75 -0
  9. data/app/assets/javascripts/chat/channels/notification.coffee +44 -0
  10. data/app/assets/javascripts/chat/channels/status.coffee +13 -0
  11. data/app/assets/javascripts/chat/emojionearea.min.js +1 -0
  12. data/app/assets/javascripts/chat/messages.coffee +44 -0
  13. data/app/assets/stylesheets/chat.css +15 -0
  14. data/app/assets/stylesheets/chat/chat.sass +25 -0
  15. data/app/assets/stylesheets/chat/checkbox.sass +80 -0
  16. data/app/assets/stylesheets/chat/emojionearea.min.css +1 -0
  17. data/app/assets/stylesheets/chat/header.sass +50 -0
  18. data/app/assets/stylesheets/chat/launch.sass +26 -0
  19. data/app/assets/stylesheets/chat/list.sass +45 -0
  20. data/app/assets/stylesheets/chat/message_form.sass +50 -0
  21. data/app/assets/stylesheets/chat/new.sass +53 -0
  22. data/app/assets/stylesheets/chat/transcript.sass +76 -0
  23. data/app/channels/chat/messages_channel.rb +11 -0
  24. data/app/channels/chat/notification_channel.rb +10 -0
  25. data/app/channels/chat/status_channel.rb +12 -0
  26. data/app/controllers/chat/application_controller.rb +5 -0
  27. data/app/controllers/chat/conversations_controller.rb +30 -0
  28. data/app/controllers/chat/messages_controller.rb +28 -0
  29. data/app/helpers/chat/application_helper.rb +62 -0
  30. data/app/jobs/chat/application_job.rb +5 -0
  31. data/app/jobs/chat/message_relay_job.rb +40 -0
  32. data/app/jobs/chat/notification_relay_job.rb +11 -0
  33. data/app/jobs/chat/status_relay_job.rb +9 -0
  34. data/app/mailers/chat/application_mailer.rb +6 -0
  35. data/app/models/chat/application_record.rb +3 -0
  36. data/app/models/chat/conversation.rb +9 -0
  37. data/app/models/chat/dot_command.rb +26 -0
  38. data/app/models/chat/dot_command/gif.rb +17 -0
  39. data/app/models/chat/dot_command/leave.rb +16 -0
  40. data/app/models/chat/dot_command/shrug.rb +27 -0
  41. data/app/models/chat/dot_command/validator.rb +23 -0
  42. data/app/models/chat/message.rb +29 -0
  43. data/app/models/chat/session.rb +10 -0
  44. data/app/views/chat/_chat.html.haml +14 -0
  45. data/app/views/chat/conversations/_index.html.haml +11 -0
  46. data/app/views/chat/conversations/_new.html.haml +10 -0
  47. data/app/views/chat/conversations/_show.html.haml +9 -0
  48. data/app/views/chat/conversations/create.js.erb +21 -0
  49. data/app/views/chat/conversations/show.js.erb +12 -0
  50. data/app/views/chat/messages/_message.haml +13 -0
  51. data/app/views/layouts/chat/application.html.erb +14 -0
  52. data/config/routes.rb +5 -0
  53. data/lib/chat.rb +29 -3
  54. data/lib/chat/engine.rb +5 -0
  55. data/lib/chat/user.rb +51 -0
  56. data/lib/chat/version.rb +1 -1
  57. data/lib/generators/chat/install/install_generator.rb +68 -0
  58. data/lib/generators/chat/install/templates/add_chat_to_users.rb +9 -0
  59. data/lib/generators/chat/install/templates/chat.rb +11 -0
  60. data/lib/generators/chat/install/templates/create_chat.rb +29 -0
  61. data/lib/tasks/chat_tasks.rake +4 -0
  62. metadata +296 -16
  63. data/.gitignore +0 -9
  64. data/Gemfile +0 -4
  65. data/LICENSE.txt +0 -21
  66. data/bin/console +0 -14
  67. data/bin/setup +0 -8
  68. data/chat.gemspec +0 -22
@@ -0,0 +1 @@
1
+ .dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea]{position:absolute;z-index:1000;min-width:160px;padding:5px 0;margin:2px 0 0;font-size:14px;text-align:left;list-style:none;background-color:#fff;-webkit-background-clip:padding-box;background-clip:padding-box;border:1px solid #ccc;border:1px solid rgba(0,0,0,.15);-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;-moz-box-shadow:0 6px 12px rgba(0,0,0,.175);-webkit-box-shadow:0 6px 12px rgba(0,0,0,.175);box-shadow:0 6px 12px rgba(0,0,0,.175)}.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item{font-size:14px;padding:1px 3px;border:0}.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item a{text-decoration:none;display:block;height:100%;line-height:1.8em;padding:0 1.54em 0 .615em;color:#4f4f4f}.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item.active,.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item:hover{background-color:#e4e4e4}.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item.active a,.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item:hover a{color:#333}.dropdown-menu.textcomplete-dropdown[data-strategy=emojionearea] li.textcomplete-item .emojioneemoji{font-size:inherit;height:2ex;width:2.1ex;min-height:20px;min-width:20px;display:inline-block;margin:0 5px .2ex 0;line-height:normal;vertical-align:middle;max-width:100%;top:0}.emojionearea,.emojionearea *{-moz-box-sizing:border-box;-webkit-box-sizing:border-box;box-sizing:border-box}.emojionearea,.emojionearea.form-control{display:block;position:relative!important;width:100%;height:auto;padding:0;font-size:14px}.emojionearea .emojionearea-editor{display:block;height:auto;max-height:80px;overflow:auto;padding:6px 57px 6px 0;line-height:1.42857143;font-size:17px;color:#212121;background-color:transparent;border:0;cursor:text;margin-right:1px;border-bottom:1px solid rgba(0,0,0,.26);word-wrap:break-word}.emojionearea .emojionearea-editor:empty:before{content:attr(placeholder);display:block;color:#bbb}.emojionearea .emojionearea-editor:focus{border:0;outline:0;-moz-box-shadow:none;-webkit-box-shadow:none;box-shadow:none}.emojionearea .emojionearea-editor .emojioneemoji,.emojionearea .emojionearea-editor [class*=emojione-]{font-size:inherit;height:2ex;width:2.1ex;min-height:20px;min-width:20px;display:inline-block;margin:-.2ex .15em .2ex;line-height:normal;vertical-align:middle;max-width:100%;top:0}.emojionearea.emojionearea-inline{height:34px}.emojionearea.emojionearea-inline>.emojionearea-editor{height:32px;min-height:20px;overflow:hidden;white-space:nowrap;position:absolute;top:0;left:12px;right:24px;padding:6px 0}.emojionearea.emojionearea-inline>.emojionearea-button{top:4px}.emojionearea .emojionearea-button{z-index:5;position:absolute;right:3px;top:3px;width:24px;height:24px;opacity:.6;cursor:pointer;-moz-transition:opacity .3s ease-in-out;-o-transition:opacity .3s ease-in-out;-webkit-transition:opacity .3s ease-in-out;transition:opacity .3s ease-in-out}.emojionearea .emojionearea-button:hover{opacity:1}.emojionearea .emojionearea-button>div{display:block;width:24px;height:24px;position:absolute;-moz-transition:all .4s ease-in-out;-o-transition:all .4s ease-in-out;-webkit-transition:all .4s ease-in-out;transition:all .4s ease-in-out}.emojionearea .emojionearea-button>div.emojionearea-button-open{background-position:0 -24px;filter:alpha(enabled=false);opacity:1}.emojionearea .emojionearea-button>div.emojionearea-button-close{background-position:0 0;-webkit-transform:rotate(-45deg);-o-transform:rotate(-45deg);transform:rotate(-45deg);filter:alpha(Opacity=0);opacity:0}.emojionearea .emojionearea-button.active>div.emojionearea-button-open{-webkit-transform:rotate(45deg);-o-transform:rotate(45deg);transform:rotate(45deg);filter:alpha(Opacity=0);opacity:0}.emojionearea .emojionearea-button.active>div.emojionearea-button-close{-webkit-transform:rotate(0);-o-transform:rotate(0);transform:rotate(0);filter:alpha(enabled=false);opacity:1}.emojionearea .emojionearea-picker{background:#fff;position:absolute;-moz-box-shadow:0 1px 5px rgba(0,0,0,.32);-webkit-box-shadow:0 1px 5px rgba(0,0,0,.32);box-shadow:0 1px 5px rgba(0,0,0,.32);-moz-border-radius:5px;-webkit-border-radius:5px;border-radius:5px;height:236px;width:316px;top:-15px;right:-15px;z-index:90;-moz-transition:all .25s ease-in-out;-o-transition:all .25s ease-in-out;-webkit-transition:all .25s ease-in-out;transition:all .25s ease-in-out;filter:alpha(Opacity=0);opacity:0;-moz-user-select:-moz-none;-ms-user-select:none;-webkit-user-select:none;user-select:none}.emojionearea .emojionearea-picker.hidden{display:none}.emojionearea .emojionearea-picker .emojionearea-wrapper{position:relative;height:236px;width:316px}.emojionearea .emojionearea-picker .emojionearea-wrapper:after{content:"";display:block;position:absolute;background-repeat:no-repeat;z-index:91}.emojionearea .emojionearea-picker .emojionearea-filters{width:100%;position:absolute;background:#F5F7F9;padding:0 0 0 7px;height:40px;z-index:95}.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter{display:block;float:left;height:40px;width:32px;padding:7px 1px 0;cursor:pointer;-webkit-filter:grayscale(1);filter:grayscale(1)}.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter.active{background:#fff}.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter.active,.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter:hover{-webkit-filter:grayscale(0);filter:grayscale(0)}.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter>i{width:24px;height:24px;top:0}.emojionearea .emojionearea-picker .emojionearea-filters .emojionearea-filter>img{width:24px;height:24px;margin:0 3px}.emojionearea .emojionearea-picker .emojionearea-scroll-area{height:196px;overflow:auto;overflow-x:hidden;width:100%;position:absolute;padding:0 0 5px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-emojis-list{z-index:1}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones{position:absolute;top:6px;right:10px;height:22px;z-index:2}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone{display:inline-block;padding:0;border:0;vertical-align:middle;outline:0;background:0 0;cursor:pointer;position:relative}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-0,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-0:after{background-color:#ffcf3e}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-1,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-1:after{background-color:#fae3c5}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-2,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-2:after{background-color:#e2cfa5}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-3,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-3:after{background-color:#daa478}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-4,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-4:after{background-color:#a78058}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-5,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones>.btn-tone.btn-tone-5:after{background-color:#5e4d43}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-bullet>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-square>.btn-tone{width:20px;height:20px;margin:0;background-color:transparent}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-bullet>.btn-tone:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-square>.btn-tone:after{content:"";position:absolute;display:block;top:4px;left:4px;width:12px;height:12px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-bullet>.btn-tone.active:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-square>.btn-tone.active:after{top:0;left:0;width:20px;height:20px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-checkbox>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-radio>.btn-tone{width:16px;height:16px;margin:0 2px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-checkbox>.btn-tone.active:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-radio>.btn-tone.active:after{content:"";position:absolute;display:block;background-color:transparent;border:2px solid #fff;width:8px;height:8px;top:2px;left:2px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-category:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-category:before,.emojionearea .emojionearea-picker .emojionearea-scroll-area h1:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area h1:before{content:" ";clear:both;display:block}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-bullet>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-bullet>.btn-tone:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-radio>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-radio>.btn-tone:after{-moz-border-radius:100%;-webkit-border-radius:100%;border-radius:100%}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-checkbox>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-checkbox>.btn-tone:after,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-square>.btn-tone,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-tones.emojionearea-tones-square>.btn-tone:after{-moz-border-radius:1px;-webkit-border-radius:1px;border-radius:1px}.emojionearea .emojionearea-picker .emojionearea-scroll-area h1{display:block;font-family:Arial,'Helvetica Neue',Helvetica,sans-serif;font-size:13px;font-weight:400;color:#b2b2b2;background:#fff;line-height:20px;margin:0;padding:7px 0 5px 6px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojionearea-category{padding:0 0 0 7px}.emojionearea .emojionearea-picker .emojionearea-scroll-area [class*=emojione-]{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;margin:0;width:24px;height:24px;top:0}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojibtn{-moz-box-sizing:content-box;-webkit-box-sizing:content-box;box-sizing:content-box;width:24px;height:24px;float:left;display:block;margin:1px;padding:3px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojibtn:hover{-moz-border-radius:4px;-webkit-border-radius:4px;border-radius:4px;background-color:#e4e4e4;cursor:pointer}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojibtn i,.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojibtn img{float:left;display:block;width:24px;height:24px}.emojionearea .emojionearea-picker .emojionearea-scroll-area .emojibtn img.lazy-emoji{filter:alpha(Opacity=0);opacity:0}.emojionearea .emojionearea-picker.emojionearea-filters-position-top .emojionearea-filters{top:0;-moz-border-radius-topleft:5px;-webkit-border-top-left-radius:5px;border-top-left-radius:5px;-moz-border-radius-topright:5px;-webkit-border-top-right-radius:5px;border-top-right-radius:5px}.emojionearea .emojionearea-picker.emojionearea-filters-position-top .emojionearea-scroll-area{bottom:0}.emojionearea .emojionearea-picker.emojionearea-filters-position-bottom .emojionearea-filters{bottom:0;-moz-border-radius-bottomleft:5px;-webkit-border-bottom-left-radius:5px;border-bottom-left-radius:5px;-moz-border-radius-bottomright:5px;-webkit-border-bottom-right-radius:5px;border-bottom-right-radius:5px}.emojionearea .emojionearea-picker.emojionearea-filters-position-bottom .emojionearea-scroll-area{top:0}.emojionearea .emojionearea-picker.emojionearea-picker-position-top{margin-top:-246px;right:-14px}.emojionearea .emojionearea-picker.emojionearea-picker-position-top .emojionearea-wrapper:after{width:19px;height:10px;background-position:-2px -49px;bottom:-10px;right:20px}.emojionearea .emojionearea-picker.emojionearea-picker-position-top.emojionearea-filters-position-bottom .emojionearea-wrapper:after{background-position:-2px -80px}.emojionearea .emojionearea-picker.emojionearea-picker-position-left,.emojionearea .emojionearea-picker.emojionearea-picker-position-right{margin-right:-326px;top:-8px}.emojionearea .emojionearea-picker.emojionearea-picker-position-left .emojionearea-wrapper:after,.emojionearea .emojionearea-picker.emojionearea-picker-position-right .emojionearea-wrapper:after{width:10px;height:19px;background-position:0 -60px;top:13px;left:-10px}.emojionearea .emojionearea-picker.emojionearea-picker-position-left.emojionearea-filters-position-bottom .emojionearea-wrapper:after,.emojionearea .emojionearea-picker.emojionearea-picker-position-right.emojionearea-filters-position-bottom .emojionearea-wrapper:after{background-position:right -60px}.emojionearea .emojionearea-picker.emojionearea-picker-position-bottom{margin-top:10px;right:-14px;top:47px}.emojionearea .emojionearea-picker.emojionearea-picker-position-bottom .emojionearea-wrapper:after{width:19px;height:10px;background-position:-2px -100px;top:-10px;right:20px}.emojionearea .emojionearea-picker.emojionearea-picker-position-bottom.emojionearea-filters-position-bottom .emojionearea-wrapper:after{background-position:-2px -90px}.emojionearea .emojionearea-button.active+.emojionearea-picker{filter:alpha(enabled=false);opacity:1}.emojionearea .emojionearea-button.active+.emojionearea-picker-position-top{margin-top:-229px}.emojionearea .emojionearea-button.active+.emojionearea-picker-position-left,.emojionearea .emojionearea-button.active+.emojionearea-picker-position-right{margin-right:-309px}.emojionearea .emojionearea-button.active+.emojionearea-picker-position-bottom{margin-top:-7px}.emojionearea.emojionearea-standalone{display:inline-block;width:auto;box-shadow:none}.emojionearea.emojionearea-standalone .emojionearea-editor{min-height:33px;position:relative;padding:6px 42px 6px 6px}.emojionearea.emojionearea-standalone .emojionearea-editor::before{content:"";position:absolute;top:4px;left:50%;bottom:4px;border-left:1px solid #e6e6e6}.emojionearea.emojionearea-standalone .emojionearea-editor.has-placeholder .emojioneemoji{opacity:.4}.emojionearea.emojionearea-standalone .emojionearea-button{top:0;right:0;bottom:0;left:0;width:auto;height:auto}.emojionearea.emojionearea-standalone .emojionearea-button>div{right:6px;top:5px}.emojionearea.emojionearea-standalone .emojionearea-picker.emojionearea-picker-position-bottom .emojionearea-wrapper:after,.emojionearea.emojionearea-standalone .emojionearea-picker.emojionearea-picker-position-top .emojionearea-wrapper:after{right:23px}.emojionearea.emojionearea-standalone .emojionearea-picker.emojionearea-picker-position-left .emojionearea-wrapper:after,.emojionearea.emojionearea-standalone .emojionearea-picker.emojionearea-picker-position-right .emojionearea-wrapper:after{top:15px}.emojionearea .emojionearea-button>div,.emojionearea .emojionearea-picker .emojionearea-wrapper:after{background-image:url(data:image/png;base64,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)!important}.emojionearea.emojionearea-standalone .emojionearea-editor.has-placeholder{background-repeat:no-repeat;background-position:20px 4px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMAQMAAABsu86kAAAABlBMVEUAAAC/v79T5hyIAAAAAXRSTlMAQObYZgAAABNJREFUCNdjYGNgQEb/P4AQqiAASiUEG6Vit44AAAAASUVORK5CYII=)!important}
@@ -0,0 +1,50 @@
1
+ @import "https://fonts.googleapis.com/css?family=Lato:300&subset=latin-ext"
2
+
3
+ #chat .chat__header
4
+ font-family: 'Lato' !important
5
+ letter-spacing: 1.5px !important
6
+ height: 48px
7
+ background-color: #fff
8
+ box-shadow: 0px 2px 2px 0px rgba(0, 0, 0, 0.2)
9
+ display: flex
10
+ flex-direction: row
11
+ align-items: center
12
+ h6
13
+ font-family: 'Lato' !important
14
+ letter-spacing: 1.5px !important
15
+ margin: 0
16
+ font-weight: 300
17
+ font-size: 19px
18
+ i
19
+ margin: 0 10px 0 10px
20
+ color: #BDBDBD
21
+ transition: all .3s ease
22
+ cursor: pointer
23
+ &:hover
24
+ color: #212121
25
+
26
+ #chat .chat__badge
27
+ position: relative
28
+ #chat .chat__badge[data-badge]:after, .chat__launch.chat__badge[data-badge]:after
29
+ content: attr(data-badge)
30
+ display: flex
31
+ flex-direction: row
32
+ flex-wrap: wrap
33
+ justify-content: center
34
+ align-content: center
35
+ align-items: center
36
+ position: absolute
37
+ top: -7px
38
+ right: -10px
39
+ font-size: 12px
40
+ width: 22px
41
+ height: 22px
42
+ border-radius: 50%
43
+ background: #ff4081
44
+ color: #fff
45
+ font-family: 'Lato' !important
46
+ .chat__launch.chat__badge[data-badge]:after
47
+ position: fixed
48
+ bottom: 51px
49
+ right: 14px
50
+ top: initial
@@ -0,0 +1,26 @@
1
+ .chat__launch
2
+ position: fixed
3
+ right: 15px
4
+ bottom: 15px
5
+ border-radius: 50%
6
+ height: 56px
7
+ margin: auto
8
+ min-width: 56px
9
+ width: 56px
10
+ padding: 0
11
+ overflow: hidden
12
+ box-shadow: 0 1px 1.5px 0 rgba(0, 0, 0, 0.12), 0 1px 1px 0 rgba(0, 0, 0, 0.24)
13
+ line-height: normal
14
+ border: none
15
+ will-change: box-shadow
16
+ transition: box-shadow 0.2s cubic-bezier(0.4, 0, 1, 1), background-color 0.2s cubic-bezier(0.4, 0, 0.2, 1), color 0.2s cubic-bezier(0.4, 0, 0.2, 1)
17
+ outline: none
18
+ cursor: pointer
19
+ text-decoration: none
20
+ i
21
+ position: fixed
22
+ right: 28px
23
+ bottom: 28px
24
+ font-size: 30px
25
+ &:active
26
+ box-shadow: 0 4px 5px 0 rgba(0, 0, 0, 0.14), 0 1px 10px 0 rgba(0, 0, 0, 0.12), 0 2px 4px -1px rgba(0, 0, 0, 0.2)
@@ -0,0 +1,45 @@
1
+ @keyframes pulse
2
+ 50%
3
+ background-color: #C8E6C9
4
+
5
+ #chat .chat__list
6
+ height: calc(100% - 58px)
7
+ display: flex
8
+ flex-direction: column
9
+ padding-top: 10px
10
+ a
11
+ padding: 10px
12
+ text-align: center
13
+ transition: all 0.3s ease
14
+ text-decoration: none
15
+ color: #212121
16
+ &:hover
17
+ background: #BDBDBD
18
+ .chat__index
19
+ display: flex
20
+ flex-direction: column
21
+ overflow-y: auto
22
+ &::-webkit-scrollbar
23
+ display: none
24
+ .chat__has_new_message
25
+ animation: pulse 1s ease-out infinite
26
+
27
+ #chat .chat__start-new
28
+ font-weight: 300
29
+ border-top: 1px solid #BDBDBD
30
+ margin: 0 !important
31
+ font-size: 17px
32
+
33
+ #chat .chat__none-available
34
+ height: 100%
35
+ display: flex
36
+ flex-direction: column
37
+ align-items: center
38
+ justify-content: center
39
+ color: #bdbdbd
40
+ h5
41
+ font-weight: 400
42
+ font-size: 15px
43
+ margin: 5px 0px 5px 0px
44
+ i
45
+ font-size: 60px
@@ -0,0 +1,50 @@
1
+ @import "https://fonts.googleapis.com/css?family=Lato:300&subset=latin-ext"
2
+
3
+ #chat .new_message
4
+ margin: 0px 40px 36px 40px
5
+ flex-direction: column
6
+ display: flex
7
+ position: relative
8
+ .chat__insert-image
9
+ position: absolute
10
+ right: 28px
11
+ top: 4px
12
+ color: #bdbdbd
13
+ transition: all 0.3s ease
14
+ z-index: 10
15
+ cursor: pointer
16
+ font-size: 22px
17
+ &:hover
18
+ color: #212121
19
+ input[type='text'], textarea
20
+ font-size: 17px
21
+ font-family: "Lato" !important
22
+ letter-spacing: 1.5px !important
23
+ background: transparent
24
+ border: none
25
+ font-weight: 300
26
+ border-bottom: 1px solid rgba(0,0,0,.26)
27
+ height: 28px
28
+ outline: none
29
+ resize: none
30
+ .bar, .emojionearea-bar
31
+ position: relative
32
+ &:before, &:after
33
+ content: ''
34
+ height: 2px
35
+ width: 0
36
+ bottom: 0px
37
+ position: absolute
38
+ background: #3f51b5
39
+ transition: 0.2s ease all
40
+ -moz-transition: 0.2s ease all
41
+ -webkit-transition: 0.2s ease all
42
+ &:before
43
+ left: 50%
44
+ &:after
45
+ right: 50%
46
+ input[type='text']:focus ~ .bar:before, input[type='text']:focus ~ .bar:after,
47
+ textarea:focus ~ .bar:before, textarea:focus ~ .bar:after, .emojionearea-editor:focus ~ .emojionearea-bar:before, .emojionearea-editor:focus ~ .emojionearea-bar:after
48
+ width: 50%
49
+ input[type='file']
50
+ display: none !important
@@ -0,0 +1,53 @@
1
+ @import "https://fonts.googleapis.com/css?family=Lato:300&subset=latin-ext"
2
+
3
+ #chat .new_conversation
4
+ height: calc(100% - 48px)
5
+ display: none
6
+ flex-direction: column
7
+ .chat__user-check-boxes
8
+ margin: 10px 20px 0px 20px
9
+ display: flex
10
+ flex-direction: column
11
+ height: calc(100% - 48px)
12
+ overflow-y: auto
13
+ &::-webkit-scrollbar
14
+ display: none
15
+ label
16
+ position: relative
17
+ margin: 1rem
18
+ line-height: 135%
19
+ cursor: pointer
20
+ font-size: 18px
21
+ font-family: "Lato" !important
22
+ letter-spacing: 1.5px !important
23
+ padding-left: 40px
24
+ .chat__status
25
+ &:after
26
+ content: "\2022"
27
+ &.offline
28
+ &:after
29
+ color: #EF5350
30
+ &.online
31
+ &:after
32
+ color: #AED581
33
+
34
+ input[type='submit']
35
+ border-top: 1px solid #BDBDBD
36
+ border-left: none
37
+ border-bottom: none
38
+ border-right: none
39
+ font-family: "Lato" !important
40
+ letter-spacing: 1.5px !important
41
+ font-size: 17px
42
+ background: transparent
43
+ width: 100%
44
+ padding: 10px 0 10px 0
45
+ cursor: pointer
46
+ transition: all 0.3s ease
47
+ z-index: 10
48
+ &:hover
49
+ background: #BDBDBD
50
+
51
+ #chat .chat__errors
52
+ text-align: center
53
+ color: #F44336
@@ -0,0 +1,76 @@
1
+ #chat .current_chat
2
+ height: calc(100% - 48px)
3
+ flex-direction: column
4
+ img.chat__user-avatar
5
+ width: 50px
6
+ height: 50px
7
+ object-fit: cover
8
+ border-radius: 50%
9
+ i.chat__user-avatar
10
+ font-size: 50px
11
+ .chat__transcript
12
+ max-height: calc(100% - 78px)
13
+ overflow-y: auto
14
+ &::-webkit-scrollbar
15
+ display: none
16
+ .chat__image-message
17
+ width: 100%
18
+ padding-top: 10px
19
+ padding-bottom: 10px
20
+ img
21
+ width: 100%
22
+ border-bottom: 4px solid #C8E6C9
23
+ &.current img
24
+ border-bottom: 4px solid #B2EBF2
25
+ .chat__message
26
+ padding: 10px
27
+ display: flex
28
+ flex-direction: row
29
+ img
30
+ font-size: inherit
31
+ height: 2ex
32
+ width: 2.1ex
33
+ min-height: 20px
34
+ min-width: 20px
35
+ display: inline-block
36
+ margin: -.2ex .15em .2ex
37
+ line-height: normal
38
+ vertical-align: middle
39
+ max-width: 100%
40
+ top: 0
41
+ .text
42
+ padding: 5px
43
+ flex: 1
44
+ position: relative
45
+ &.right
46
+ margin-right: 10px
47
+ border-radius: 5px 0px 5px 5px
48
+ background: #B2EBF2
49
+ border: none
50
+ &:after
51
+ content: ""
52
+ position: absolute
53
+ border-style: solid
54
+ border-width: 0px 0 13px 15px
55
+ border-color: transparent #B2EBF2
56
+ display: block
57
+ width: 0
58
+ z-index: 1
59
+ right: -15px
60
+ top: 0px
61
+ &.left
62
+ margin-left: 10px
63
+ border-radius: 0px 5px 5px 5px
64
+ background: #C8E6C9
65
+ border: none
66
+ &:after
67
+ content: ""
68
+ position: absolute
69
+ border-style: solid
70
+ border-width: 0px 15px 13px 0px
71
+ border-color: transparent #C8E6C9
72
+ display: block
73
+ width: 0
74
+ z-index: 1
75
+ left: -15px
76
+ top: 0px
@@ -0,0 +1,11 @@
1
+ class Chat::MessagesChannel < ApplicationCable::Channel
2
+ def follow(data)
3
+ stop_all_streams
4
+ stream_from "chats::#{data['chat_id']}::messages"
5
+ end
6
+
7
+ def unfollow
8
+ stop_all_streams
9
+ end
10
+ alias unsubscribed unfollow
11
+ end
@@ -0,0 +1,10 @@
1
+ class Chat::NotificationChannel < ApplicationCable::Channel
2
+ def follow(data)
3
+ stop_all_streams
4
+ stream_from "users::#{data['user_id']}::chats"
5
+ end
6
+
7
+ def unsubscribed
8
+ stop_all_streams
9
+ end
10
+ end
@@ -0,0 +1,12 @@
1
+ class Chat::StatusChannel < ApplicationCable::Channel
2
+ def online
3
+ stop_all_streams
4
+ stream_from "chat::status"
5
+ current_user.online
6
+ end
7
+
8
+ def unsubscribed
9
+ current_user.offline
10
+ stop_all_streams
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module Chat
2
+ class ApplicationController < ActionController::Base
3
+ protect_from_forgery with: :exception
4
+ end
5
+ end
@@ -0,0 +1,30 @@
1
+ module Chat
2
+ class ConversationsController < ApplicationController
3
+ before_action Chat.logged_in_check
4
+ before_action :set_conversation, only: :show
5
+
6
+ def show
7
+ end
8
+
9
+ def create
10
+ @conversation = Chat::Conversation.create(conversation_params)
11
+ end
12
+
13
+ private
14
+
15
+ def set_conversation
16
+ @conversation = Chat::Conversation.includes(
17
+ :users, messages: :user
18
+ ).find(params[:id])
19
+ end
20
+
21
+ def conversation_params
22
+ chat_params = params.require(:conversation).permit(user_ids: [])
23
+ if chat_params[:user_ids].reject(&:blank?).present?
24
+ chat_params[:user_ids] << current_user.id
25
+ end
26
+
27
+ chat_params
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,28 @@
1
+ module Chat
2
+ class MessagesController < ApplicationController
3
+ before_action Chat.logged_in_check
4
+ before_action :set_conversation
5
+
6
+ def create
7
+ @conversation.messages.create(message_params)
8
+
9
+ head :ok
10
+ end
11
+
12
+ def destroy
13
+ @conversation.destroy
14
+ end
15
+
16
+ private
17
+
18
+ def set_conversation
19
+ @conversation = Chat::Conversation.find(params[:conversation_id])
20
+ end
21
+
22
+ def message_params
23
+ params.require(:message).permit(:text, :image).merge(
24
+ user_id: current_user.id
25
+ )
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,62 @@
1
+ module Chat
2
+ module ApplicationHelper
3
+ def render_chat(background = nil, color = nil)
4
+ return unless send Chat.signed_in
5
+
6
+ render "chat/chat", background: background, color: color
7
+ end
8
+
9
+ def launch_chat_fab(background = "#4CAF50", color = "light")
10
+ attrs = {
11
+ class: "chat__launch", style: "background: #{background}",
12
+ data: { "current-user" => current_user.id }
13
+ }
14
+ button_tag(attrs) do
15
+ material_icon.forum.css_class("md-#{color}").to_s.html_safe
16
+ end
17
+ end
18
+
19
+ def chatable_users
20
+ @chatable_users ||= ::User.where.not(id: current_user.id)
21
+ end
22
+
23
+ def chatable_user_check_boxes(f)
24
+ f.collection_check_boxes(:user_ids, chatable_users, :id, :name) do |b|
25
+ b.check_box + b.label(class: b.object.chat_status) do
26
+ content_tag(
27
+ :div, b.text,
28
+ class: "chat__status #{b.object.chat_status}"
29
+ )
30
+ end
31
+ end
32
+ end
33
+
34
+ def chat_avatar(user)
35
+ if user.send(Chat.user_avatar.to_s + "?")
36
+ image_tag(user.send(Chat.user_avatar), class: "chat__user-avatar")
37
+ else
38
+ MaterialIcon.new.css_class("chat__user-avatar").person
39
+ end
40
+ end
41
+
42
+ def chat_list
43
+ @chat_list ||=
44
+ Chat::Conversation.joins(:users)
45
+ .group("chat_sessions.conversation_id")
46
+ .select(:id, group_concat)
47
+ .merge(current_user.conversations)
48
+ .order(created_at: :desc)
49
+ end
50
+
51
+ private
52
+
53
+ def group_concat
54
+ if ActiveRecord::Base.connection.adapter_name == "SQLite"
55
+ "GROUP_CONCAT(users.#{::User.first_name} || ' ' || users.#{::User.last_name}, ', ') as names"
56
+ elsif ActiveRecord::Base.connection.adapter_name == "MySQL"
57
+ "GROUP_CONCAT(CONCAT(\"users.#{User.first_name}\",\" \", \"users.#{User.last_name}\") "\
58
+ "SEPARATOR ', ') as names"
59
+ end
60
+ end
61
+ end
62
+ end