From b60b001fcee083ce78557643948e6c13ca12439f Mon Sep 17 00:00:00 2001 From: Achilles Rasquinha Date: Mon, 8 Jan 2018 22:53:37 +0530 Subject: [PATCH] Fixed Chat Scrolling Issues --- frappe/public/css/chat.css | 145 +++++--------- frappe/public/js/frappe/chat.js | 196 +++---------------- frappe/public/less/chat.less | 323 ++++++++++---------------------- 3 files changed, 181 insertions(+), 483 deletions(-) diff --git a/frappe/public/css/chat.css b/frappe/public/css/chat.css index 5bcfb5f707..536c304832 100644 --- a/frappe/public/css/chat.css +++ b/frappe/public/css/chat.css @@ -1,19 +1,3 @@ -.frappe-chat-toggle { - height: 40px; - text-align: center; -} -.frappe-chat-toggle .octicon { - margin-top: 5px; -} -.frappe-chat .frappe-chat-popper > .frappe-chat-popper-collapse > .panel { - box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.25); -} -.frappe-chat .panel.panel-span { - border-radius: 0px; -} -.frappe-chat .panel.panel-span .panel-heading { - border-radius: 0px; -} .font-bold { font-weight: 700; } @@ -26,32 +10,58 @@ .avatar { padding: 1px; } -.frappe-fab { - width: 48px; - height: 48px; - border-radius: 50%; - box-shadow: 0px 3px 6px 0px rgba(0, 0, 0, 0.25); -} -.frappe-fab:hover { - box-shadow: 0px 5px 9px 0px rgba(0, 0, 0, 0.25); -} -.frappe-fab.frappe-fab-sm { - width: 40px; +.navbar .frappe-chat-toggle { height: 40px; + text-align: center; } -.frappe-fab.frappe-fab-lg { - width: 56px; - height: 56px; +.navbar .octicon { + margin-top: 5px; +} +.frappe-chat > .frappe-chat-popper { + position: fixed; + bottom: 0px; + right: 0px; + margin: 20px; + z-index: 1035; +} +.frappe-chat > .frappe-chat-popper > .frappe-chat-popper-collapse > .panel { + width: 350px; + height: 500px; + box-shadow: 0 5px 15px rgba(0, 0, 0, 0.5); +} +.frappe-chat > .frappe-chat-popper > .frappe-chat-popper-collapse > .panel .panel-body .frappe-chat-room-list { + height: 400px; + overflow-y: auto; +} +.frappe-chat > .frappe-chat-popper > .frappe-chat-popper-collapse > .panel .chat-list.list-group { + height: 390px; + overflow-y: scroll; +} +.frappe-chat > .frappe-chat-popper > .frappe-chat-popper-collapse > .panel .frappe-chat-room-footer { + position: absolute; + left: 0px; + right: 0px; + bottom: 0px; +} +.frappe-chat > .frappe-chat-popper > .frappe-chat-popper-collapse > .panel.panel-span { + position: fixed; + width: 100%; + height: 100%; + top: 0px; + left: 0px; + bottom: 0px; + right: 0px; + overflow: auto; + border-radius: 0px; +} +.frappe-chat > .frappe-chat-popper > .frappe-chat-popper-collapse > .panel.panel-span .panel-heading { + border-radius: 0px; } .frappe-chat .panel { margin-bottom: 0px !important; } -.frappe-chat .panel .panel-body { - padding: 10px; -} -.frappe-chat .panel .frappe-chat-room-footer { - position: absolute; - bottom: 0px; +.frappe-chat .frappe-chat-form { + margin: 1px; } .frappe-chat .frappe-chat-form .form-control { font-size: 12px; @@ -62,69 +72,12 @@ .frappe-chat .frappe-chat-form .btn { border-radius: 0px !important; } -.frappe-chat .frappe-chat-form .list-group { +.frappe-chat .frappe-chat-form .hint-list.list-group { margin-bottom: 0px !important; max-height: 150px; overflow-y: auto; } -.frappe-chat .frappe-chat-form .list-group .list-group-item:first-child, -.frappe-chat .frappe-chat-form .list-group .list-group-item:last-child { +.frappe-chat .frappe-chat-form .hint-list.list-group .hint-list.list-group-item:first-child, +.frappe-chat .frappe-chat-form .hint-list.list-group .hint-list.list-group-item:last-child { border-radius: 0px !important; } -.frappe-chat-popper { - position: fixed; - bottom: 0px; - right: 0px; - margin: 20px; - z-index: 1035; -} -.frappe-chat-popper .frappe-chat-popper-collapse { - position: fixed; - bottom: 0px; - right: 0px; - margin: 20px; -} -.frappe-chat-popper .frappe-chat-popper-collapse > .panel { - position: relative; - width: 350px; - height: 500px; - overflow-y: auto; -} -.frappe-chat-popper .frappe-chat-popper-collapse > .panel .panel-body { - width: 350px; - height: 500px; - overflow-y: auto; -} -.frappe-chat-popper .frappe-chat-popper-collapse > .panel > .panel-heading .action { - padding: 5px; -} -.frappe-chat-popper .frappe-chat-popper-collapse > .panel.panel-primary a { - color: #FFF; -} -.frappe-chat-popper .frappe-chat-popper-collapse > .panel.panel-primary .text-muted { - color: #FFF !important; -} -.frappe-chat-popper .frappe-chat-popper-collapse .panel-span { - position: fixed; - width: 100%; - height: 100%; - top: 0px; - left: 0px; - bottom: 0px; - right: 0px; - z-index: 1037; - overflow: auto; - border-radius: none; -} -.frappe-chat-emoji .dropdown-menu { - min-width: 250px; - background: none !important; - border: none !important; -} -.frappe-chat-emoji .panel { - margin-bottom: 0 !important; - height: 300px; -} -.frappe-chat-emoji .panel .form-group { - margin-bottom: 0 !important; -} diff --git a/frappe/public/js/frappe/chat.js b/frappe/public/js/frappe/chat.js index 5591a11542..6255efb4b3 100644 --- a/frappe/public/js/frappe/chat.js +++ b/frappe/public/js/frappe/chat.js @@ -1562,7 +1562,7 @@ class extends Component dialog.hide() // Don't Worry, frappe.chat.room.on.create gets triggered that then subscribes and adds to DOM. :) - frappe.chat.room.create("Direct", null, user) + frappe.chat.room.create("Direct",null,user) } } }, @@ -1614,7 +1614,7 @@ class extends Component } // Don't Worry, frappe.chat.room.on.create gets triggered that then subscribes and adds to DOM. :) - frappe.chat.room.create("Group", null, users, name) + frappe.chat.room.create("Group",null,users, name) } }, secondary: @@ -1638,7 +1638,14 @@ class extends Component const rooms = state.query ? frappe.chat.room.search(state.query, state.rooms) : frappe.chat.room.sort(state.rooms) - const RoomList = h(frappe.Chat.Widget.RoomList, { rooms: rooms, click: this.room.select }) + const RoomList = frappe._.is_empty(rooms) && !state.query ? + h("div", { style: "margin-top: 165px" }, + h("div", { class: "text-center text-extra-muted" }, + h("p","",__("You don't have any messages yet.")) + ) + ) + : + h(frappe.Chat.Widget.RoomList, { rooms: rooms, click: this.room.select }) const Room = h(frappe.Chat.Widget.Room, { ...state.room, layout: props.layout, destroy: () => { this.set_state({ room: { name: null, messages: [ ] } @@ -1660,10 +1667,10 @@ class extends Component h("div", { class: "col-md-10 col-sm-9 layout-main-section-wrapper" }, state.room.name ? Room : ( - h("div", { style: "margin-top: 240px" }, + h("div", "", h("div", { class: "text-center text-extra-muted" }, h(frappe.components.Octicon, { type: "comment-discussion", style: "font-size: 48px" }), - h("p", null, __("Select a chat to start messaging.")) + h("p","",__("Select a chat to start messaging.")) ) ) ) @@ -1816,7 +1823,7 @@ class extends Component const popper = props.layout === frappe.Chat.Layout.POPPER return ( - h("form", { oninput: this.change, onsubmit: this.submit, style: popper ? { "padding-left": "15px", "padding-right": "15px" } : null }, + h("form", { class: "frappe-chat-action-bar", oninput: this.change, onsubmit: this.submit }, h("div", { class: "form-group" }, h("div", { class: "input-group input-group-sm" }, props.span || props.layout !== frappe.Chat.Layout.PAGE ? @@ -1888,7 +1895,7 @@ class extends Component const rooms = props.rooms return rooms.length ? ( - h("ul", { class: "nav nav-pills nav-stacked" }, + h("ul", { class: "frappe-chat-room-list nav nav-pills nav-stacked" }, rooms.map(room => h(frappe.Chat.Widget.RoomList.Item, { ...room, click: props.click })) ) ) : null @@ -1981,8 +1988,8 @@ class extends Component position.class === "media-left" ? avatar : null, h("div", { class: "media-body" }, h("div", { class: "media-heading h6 ellipsis", style: `max-width: ${props.width_title || "100%"} display: inline-block` }, props.title), - props.content ? h("div", null, h("small", '', props.content)) : null, - props.subtitle ? h("div", null, h("small", { class: "text-muted" }, props.subtitle)) : null + props.content ? h("div","",h("small","",props.content)) : null, + props.subtitle ? h("div","",h("small", { class: "h6 text-muted" }, props.subtitle)) : null ), position.class === "media-right" ? avatar : null ) @@ -2106,10 +2113,10 @@ class extends Component }) : h("div", { class: "panel-body" }, - h("div", { style: "margin-top: 145px" }, + h("div", { style: "margin-top: 135px" }, h("div", { class: "text-center text-extra-muted" }, h(frappe.components.Octicon, { type: "comment-discussion", style: "font-size: 48px" }), - h("p", null, __("Start a conversation.")) + h("p","",__("Start a conversation.")) ) ) ), @@ -2172,7 +2179,7 @@ class extends Component h("div", { class: "panel-heading" }, h("div", { class: "row" }, popper ? - h("div", { class: "col-xs-1" }, + h("div", { class: "col-xs-1 vcenter" }, h("a", { onclick: props.back }, h(frappe.components.Octicon, { type: "chevron-left" })) ) : null, h("div", { class: popper ? "col-xs-10" : "col-xs-9" }, @@ -2282,11 +2289,11 @@ class extends Component { return ( h("div", { class: "frappe-chat-form" }, state.hints.length ? - h("li", { class: "list-group" }, + h("li", { class: "hint-list list-group" }, state.hints.map((item) => { return ( - h("a", { class: "list-group-item", href: "javascript:void(0)", onclick: () => + h("a", { class: "hint-list-item list-group-item", href: "javascript:void(0)", onclick: () => { this.set_state({ content: item.content, hints: [ ] }) }}, @@ -2376,111 +2383,28 @@ class extends Component return ( h("div", { class: "list-group" }, - frappe.ui.Emoji.map((category) => - { - return ( - h("div", { class: "list-group-item" }, - h("div", { class: "h6" }, frappe._.capitalize(category.name)), - h("div", null, - - ) - ) - ) - }) + ) ) } } - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -// return ( -// h("a", { class: "list-group-item", href: "#", onclick: () => { -// this.set_state({ -// content: `${this.state.content}${item.value}` -// }) -// }}, -// props.hint.component(item) -// ) -// ) - - -frappe.Chat.Widget.Account -= -class extends Component { - render ( ) { - const { props } = this - const statuses = frappe.chat.profile.STATUSES.map(s => { - return { - value: s.name, - label: s.name, - color: s.color - } - }) - return ( - h(frappe.components.Select, { value: props.status, options: statuses, click: (value) => { - if ( props.status != value ) - props.on_change_status(value) - }}) - ) - } -} - - - - - /** * @description Chat List HOC - * - * */ frappe.Chat.Widget.ChatList = class extends Component { + constructor (props) + { + super (props) + } + render ( ) { const { props } = this return !frappe._.is_empty(props.messages) ? ( - h("ul", { class: "list-group" }, + h("ul", { class: "chat-list list-group" }, props.messages.map(m => h(frappe.Chat.Widget.ChatList.Item, { ...m })) @@ -2524,66 +2448,4 @@ class extends Component { frappe.Chat.Widget.ChatList.Bubble.defaultState = { creation: "" -} - - - - - - - - - - -// frappe.components.Select -// options - (Required) array of options of the format -// { -// label: "foo", -// value: "bar" -// } -// value - (Required) default value. -// click - (Optional) click handler on click event. -frappe.components.Select -= -class extends Component { - render ( ) { - const { props } = this - const selected = props.options.find(o => o.value === props.value) - - return ( - h("div", { class: "dropdown" }, - h("button", { class: "btn btn-sm btn-default btn-block dropdown-toggle", "data-toggle": "dropdown" }, - selected.color ? - h(frappe.components.Indicator, { color: selected.color }) : null, - selected.label ? - selected.label : selected.value, - ), - h("ul", { class: "dropdown-menu" }, - props.options.map(o => h(frappe.components.Select.Option, { ...o, click: props.click })) - ) - ) - ) - } -} - -frappe.components.Select.Option -= -class extends Component { - render ( ) { - const { props } = this - - return ( - h("li", null, - h("a", { onclick: () => props.click(props.value) }, - props.color ? - h(frappe.components.Indicator, { color: props.color }) : null, - props.label ? - props.label : props.value - ) - ) - ) - } -} -// frappe.components.Select.Option props -// same as frappe.components.Select. - +} \ No newline at end of file diff --git a/frappe/public/less/chat.less b/frappe/public/less/chat.less index b92e734aaf..3a6b54c8a0 100644 --- a/frappe/public/less/chat.less +++ b/frappe/public/less/chat.less @@ -1,153 +1,128 @@ +// Author - Achilles Rasquinha + +// For most part, we haven't used the LESS framework and its language features. +// We could have written everything in CSS than introducing a compiler. +// A good start to learn the same - http://lesscss.org +// - Achilles Rasquinha + +// http://codeguide.co - @mdo (Author of Bootstrap) + +// Typography +@font-weight-bold: 700; +@font-weight-heavy: 900; + @frappe-chat-toggle-height: 40px; -@frappe-chat-popper-panel-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); // BS modal's box shadow. -.frappe-chat-toggle +@frappe-chat-popper-margin: 20px; +@frappe-chat-popper-panel-width: 350px; +@frappe-chat-popper-panel-height: 500px; +// z-index greater than FAB, lesser than modal. +@frappe-chat-popper-z-index: 1035; + +// BS modal's box-shadow +@frappe-chat-popper-panel-box-shadow: 0 5px 15px rgba(0, 0, 0, .5); + +// https://github.com/twbs/bootstrap/blob/v3.3.7/less/variables.less#L278 +// Keep z-index of the ChatPopper higher than others, lower than modal background. + +@frappe-chat-form-font-size: 12px; +@frappe-chat-form-menu-border-radius: 4px; +@frappe-chat-form-list-group-height: 150px; // Hints + + +// Typography +.font-bold { font-weight: @font-weight-bold; } +.font-heavy { font-weight: @font-weight-heavy; } + +// utilities +.cursor-pointer { cursor: pointer; } + +// Hacks and Fixes +// suggested by rushabh@frappe.io +.avatar { padding: 1px; } + +.navbar { - height: @frappe-chat-toggle-height; - text-align: center; - - .octicon + .frappe-chat-toggle { - // Hack, somewhat. - margin-top: 5px; + height: @frappe-chat-toggle-height; + text-align: center; } + + .octicon { margin-top: 5px; } // Hack, somewhat. } .frappe-chat { - .frappe-chat-popper + & > .frappe-chat-popper { + position: fixed; + bottom: 0px; + right: 0px; + margin: @frappe-chat-popper-margin; + z-index: @frappe-chat-popper-z-index; + & > .frappe-chat-popper-collapse { & > .panel { + width: @frappe-chat-popper-panel-width; + height: @frappe-chat-popper-panel-height; box-shadow: @frappe-chat-popper-panel-box-shadow; + + .panel-body + { + .frappe-chat-room-list + { + height: 400px; // Hack, sorry. :( + overflow-y: auto; + } + } + + .chat-list.list-group + { + height: 390px; + overflow-y: scroll; + } + + .frappe-chat-room-footer + { + position: absolute; + left: 0px; + right: 0px; + bottom: 0px; + } + } + + & > .panel.panel-span + { + position: fixed; + width: 100%; + height: 100%; + top: 0px; + left: 0px; + bottom: 0px; + right: 0px; + overflow: auto; + border-radius: 0px; + + .panel-heading + { + border-radius: 0px; + } } } } - .panel.panel-span - { - border-radius: 0px; - - .panel-heading - { - border-radius: 0px; - } - } -} - - - - - -// variables -@color-white: #FFF; // - -@font-weight-bold: 700; // -@font-weight-heavy: 900; // - -@frappe-chat-popper-panel-width: 350px; // -@frappe-chat-popper-panel-height: 500px; // - -@frappe-chat-form-font-size: 12px; - - -@frappe-fab-width: 48px; -@frappe-fab-height: 48px; -@frappe-fab-lg: 56px; -@frappe-fab-sm: 40px; -// https://github.com/twbs/bootstrap/blob/v3.3.7/less/variables.less#L278 -// Keep z-index of the FAB button higher than others, lower than modal background. -@frappe-fab-box-shadow: 0px 3px 6px 0px rgba(0,0,0,.25); -@frappe-fab-box-shadow-hover: 0px 5px 9px 0px rgba(0,0,0,.25); - -@frappe-chat-panel-heading-box-shadow: 0px 2px 2px 0px rgba(0,0,0,.14); // -@frappe-chat-panel-body-padding: 10px; -@frappe-chat-panel-heading-action-padding: 5px; - -@frappe-chat-popper-z-index: 1035; -@frappe-chat-popper-margin: 20px; -@frappe-chat-popper-panel-box-shadow: @frappe-fab-box-shadow; -// z-index greater than FAB, lesser than modal. -@frappe-chat-popper-panel-span-z-index: 1037; - -@frappe-chat-form-list-group-height: 150px; -@frappe-chat-form-menu-border-radius: 4px; - -@frappe-chat-emoji-width: 250px; -@frappe-chat-emoji-height: 300px; - -.font-bold -{ - font-weight: @font-weight-bold; -} - -.font-heavy -{ - font-weight: @font-weight-heavy; -} - -.cursor-pointer -{ - cursor: pointer; -} - -.avatar -{ - padding: 1px; -} - -.frappe-fab -{ - width: @frappe-fab-width; - height: @frappe-fab-height; - border-radius: 50%; - box-shadow: @frappe-fab-box-shadow; - - &:hover - { - box-shadow: @frappe-fab-box-shadow-hover; - }; - - &.frappe-fab-sm - { - width: @frappe-fab-sm; - height: @frappe-fab-sm; - }; - - &.frappe-fab-lg - { - width: @frappe-fab-lg; - height: @frappe-fab-lg; - }; -}; - -.frappe-chat -{ .panel { margin-bottom: 0px !important; - - // .panel-heading - // { - // box-shadow: @frappe-chat-panel-heading-box-shadow; - // } - - .panel-body - { - padding: @frappe-chat-panel-body-padding; - } - - .frappe-chat-room-footer - { - position: absolute; - bottom: 0px; - } } .frappe-chat-form { + margin: 1px; // Hack. + .form-control { font-size: @frappe-chat-form-font-size; @@ -163,109 +138,17 @@ border-radius: 0px !important; } - .list-group + // Hints + .hint-list.list-group { margin-bottom: 0px !important; max-height: @frappe-chat-form-list-group-height; overflow-y: auto; - .list-group-item:first-child, .list-group-item:last-child + .hint-list.list-group-item:first-child, .hint-list.list-group-item:last-child { border-radius: 0px !important; } } } -} - -.frappe-chat-popper -{ - position: fixed; - bottom: 0px; - right: 0px; - margin: @frappe-chat-popper-margin; - - z-index: @frappe-chat-popper-z-index; - - .frappe-chat-popper-collapse - { - position: fixed; - bottom: 0px; - right: 0px; - margin: @frappe-chat-popper-margin; - // margin-bottom: calc(@frappe-chat-popper-margin + 50px); - - & > .panel - { - position: relative; - // box-shadow: @frappe-chat-popper-panel-box-shadow; - width: @frappe-chat-popper-panel-width; - height: @frappe-chat-popper-panel-height; - overflow-y: auto; - - .panel-body - { - width: @frappe-chat-popper-panel-width; - height: @frappe-chat-popper-panel-height; - overflow-y: auto; - } - - & > .panel-heading - { - // box-shadow: @frappe-chat-panel-heading-box-shadow; - - .action - { - padding: @frappe-chat-panel-heading-action-padding; - } - } - - &.panel-primary - { - a - { - color: @color-white; - } - - .text-muted - { - color: @color-white !important; - } - } - }; - - .panel-span - { - position: fixed; - width: 100%; - height: 100%; - top: 0px; - left: 0px; - bottom: 0px; - right: 0px; - z-index: @frappe-chat-popper-panel-span-z-index; - overflow: auto; - border-radius: none; - }; - }; -}; - -.frappe-chat-emoji -{ - .dropdown-menu - { - min-width: @frappe-chat-emoji-width; - background: none !important; - border: none !important; - } - - .panel - { - margin-bottom: 0 !important; - height: @frappe-chat-emoji-height; - - .form-group - { - margin-bottom: 0 !important; - } - } -}; \ No newline at end of file +} \ No newline at end of file