From 6a2c56e7f466017bad635ac4df61c3636d92284e Mon Sep 17 00:00:00 2001 From: saurabhraghuvanshii Date: Sat, 27 Dec 2025 01:23:08 +0530 Subject: [PATCH 1/3] fix:side bar lazyload issue --- .../stylesheets/application/sidebar.css | 37 ++++++++++++++++++- .../lazy_involvement_controller.js | 19 ++++++++++ .../lazy_involvement_trigger_controller.js | 18 +++++++++ .../controllers/sidebar_loading_controller.js | 24 ++++++++++++ app/helpers/users/sidebar_helper.rb | 16 ++++++-- .../users/sidebars/rooms/_shared.html.erb | 19 +++++++--- 6 files changed, 122 insertions(+), 11 deletions(-) create mode 100644 app/frontend/controllers/lazy_involvement_controller.js create mode 100644 app/frontend/controllers/lazy_involvement_trigger_controller.js create mode 100644 app/frontend/controllers/sidebar_loading_controller.js diff --git a/app/assets/stylesheets/application/sidebar.css b/app/assets/stylesheets/application/sidebar.css index 5a9e69f7..f3c04c81 100644 --- a/app/assets/stylesheets/application/sidebar.css +++ b/app/assets/stylesheets/application/sidebar.css @@ -419,12 +419,45 @@ padding-inline-end: 0; /* Remove padding on the right side */ } -/* Style for the star button container */ -[data-type="list_node"] .txt-small { +/* Style for the involvement button container */ +[data-type="list_node"] .txt-small, +[data-type="list_node"] turbo-frame.txt-small { margin-inline-start: 0; /* Reset left margin to maintain spacing with timestamp */ margin-inline-end: -1ch; /* Pull from the right side only */ } +/* Lazy-loaded involvement button placeholder */ +turbo-frame[data-controller*="lazy-involvement"]:not([src]):empty::before { + content: ""; + display: inline-block; + width: 20px; + height: 20px; +} + +/* Sidebar loading indicator */ +.sidebar__loading { + display: flex; + align-items: center; + justify-content: center; + padding: var(--block-space); + min-height: 200px; +} + +.sidebar__loading .spinner { + color: var(--color-text); + opacity: 0.6; +} + +/* Show loading indicator when turbo frame is loading */ +turbo-frame#user_sidebar[src]:not([src=""]):not([complete]) .sidebar__loading { + display: flex; +} + +turbo-frame#user_sidebar:not([src]) .sidebar__loading, +turbo-frame#user_sidebar[complete] .sidebar__loading { + display: none; +} + .rooms__new-btn { position: relative; z-index: 4; diff --git a/app/frontend/controllers/lazy_involvement_controller.js b/app/frontend/controllers/lazy_involvement_controller.js new file mode 100644 index 00000000..25a9d8a6 --- /dev/null +++ b/app/frontend/controllers/lazy_involvement_controller.js @@ -0,0 +1,19 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static values = { src: String, loaded: Boolean } + + connect() { + this.loadedValue = false + } + + load() { + if (this.loadedValue) return + + const frame = this.element + if (this.srcValue && !frame.src) { + frame.src = this.srcValue + this.loadedValue = true + } + } +} diff --git a/app/frontend/controllers/lazy_involvement_trigger_controller.js b/app/frontend/controllers/lazy_involvement_trigger_controller.js new file mode 100644 index 00000000..4914c2b0 --- /dev/null +++ b/app/frontend/controllers/lazy_involvement_trigger_controller.js @@ -0,0 +1,18 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static values = { target: String } + + load() { + if (!this.targetValue) return + + const frame = document.getElementById(this.targetValue) + if (frame) { + // Trigger the lazy-involvement controller to load + const lazyController = this.application.getControllerForElementAndIdentifier(frame, "lazy-involvement") + if (lazyController) { + lazyController.load() + } + } + } +} diff --git a/app/frontend/controllers/sidebar_loading_controller.js b/app/frontend/controllers/sidebar_loading_controller.js new file mode 100644 index 00000000..f6226176 --- /dev/null +++ b/app/frontend/controllers/sidebar_loading_controller.js @@ -0,0 +1,24 @@ +import { Controller } from "@hotwired/stimulus" + +export default class extends Controller { + static targets = ["indicator"] + + connect() { + // Hide loading indicator if content is already loaded + if (this.hasIndicatorTarget && this.element.querySelector(".sidebar__container")) { + this.hide() + } + } + + show() { + if (this.hasIndicatorTarget) { + this.indicatorTarget.style.display = "flex" + } + } + + hide() { + if (this.hasIndicatorTarget) { + this.indicatorTarget.style.display = "none" + } + } +} diff --git a/app/helpers/users/sidebar_helper.rb b/app/helpers/users/sidebar_helper.rb index 15a9f4f2..7f81b72e 100644 --- a/app/helpers/users/sidebar_helper.rb +++ b/app/helpers/users/sidebar_helper.rb @@ -6,11 +6,21 @@ def has_unreads? end def sidebar_turbo_frame_tag(src: nil, &) + content = if block_given? + yield + else + content_tag :div, class: "sidebar__loading", data: { sidebar_loading_target: "indicator" } do + content_tag :div, "", class: "spinner" + end + end + turbo_frame_tag :user_sidebar, src: src, target: "_top", data: { - controller: "rooms-list read-rooms turbo-frame", + controller: "rooms-list read-rooms turbo-frame sidebar-loading", rooms_list_unread_class: "unread", rooms_list_badge_class: "badge", - action: "presence:present@window->rooms-list#read read-rooms:read->rooms-list#read turbo:frame-load->rooms-list#loaded refresh-room:visible@window->turbo-frame#reload".html_safe # otherwise -> is escaped - }, & + action: "presence:present@window->rooms-list#read read-rooms:read->rooms-list#read turbo:frame-load->rooms-list#loaded turbo:frame-load->sidebar-loading#hide turbo:before-frame-render->sidebar-loading#show refresh-room:visible@window->turbo-frame#reload".html_safe # otherwise -> is escaped + } do + content + end end end diff --git a/app/views/users/sidebars/rooms/_shared.html.erb b/app/views/users/sidebars/rooms/_shared.html.erb index 90fa1012..59b8f5a1 100644 --- a/app/views/users/sidebars/rooms/_shared.html.erb +++ b/app/views/users/sidebars/rooms/_shared.html.erb @@ -13,7 +13,12 @@ data-sidebar-starred-rooms-target="room" data-involvement="<%= involvement %>" data-type="list_node" <%= "hidden" if hide_in_starred_list %> - class="flex gap align-center justify-space-between"> + class="flex gap align-center justify-space-between" + <% unless room.conversation_room? %> + data-controller="lazy-involvement-trigger" + data-lazy-involvement-trigger-target-value="<%= dom_id(room, dom_prefix(:sidebar, :involvement)) %>" + data-action="mouseenter->lazy-involvement-trigger#load" + <% end %>> <%= link_to_room room, class: [ "flex flex-item-grow gap align-center justify-space-between room full-height txt-nowrap overflow-ellipsis txt-lighter txt-undecorated pad-block position-relative", "unread": unread, "badge": has_notifications ], style: "padding-block: calc(var(--block-space) / 4);" do %> @@ -25,10 +30,12 @@ <% end %> <% unless room.conversation_room? %> - - <%= turbo_frame_tag dom_id(room, dom_prefix(:sidebar, :involvement)) do %> - <%= button_to_change_involvement(room, involvement, from_sidebar: true) %> - <% end %> - + <%= turbo_frame_tag dom_id(room, dom_prefix(:sidebar, :involvement)), + class: "txt-small", + data: { + controller: "lazy-involvement", + lazy_involvement_src_value: room_involvement_path(room, from_sidebar: true) + } do %> + <% end %> <% end %> \ No newline at end of file From e77a6637b702bb5d715ec5d6ec0d4fa03e05c957 Mon Sep 17 00:00:00 2001 From: saurabhraghuvanshii Date: Sat, 27 Dec 2025 01:24:17 +0530 Subject: [PATCH 2/3] lint fix --- .../lazy_involvement_controller.js | 22 +++++++-------- .../lazy_involvement_trigger_controller.js | 24 ++++++++-------- .../controllers/sidebar_loading_controller.js | 28 +++++++++---------- 3 files changed, 37 insertions(+), 37 deletions(-) diff --git a/app/frontend/controllers/lazy_involvement_controller.js b/app/frontend/controllers/lazy_involvement_controller.js index 25a9d8a6..eae5b19c 100644 --- a/app/frontend/controllers/lazy_involvement_controller.js +++ b/app/frontend/controllers/lazy_involvement_controller.js @@ -1,19 +1,19 @@ import { Controller } from "@hotwired/stimulus" export default class extends Controller { - static values = { src: String, loaded: Boolean } + static values = { src: String, loaded: Boolean } - connect() { - this.loadedValue = false - } + connect() { + this.loadedValue = false + } - load() { - if (this.loadedValue) return + load() { + if (this.loadedValue) return - const frame = this.element - if (this.srcValue && !frame.src) { - frame.src = this.srcValue - this.loadedValue = true + const frame = this.element + if (this.srcValue && !frame.src) { + frame.src = this.srcValue + this.loadedValue = true + } } - } } diff --git a/app/frontend/controllers/lazy_involvement_trigger_controller.js b/app/frontend/controllers/lazy_involvement_trigger_controller.js index 4914c2b0..24994b3b 100644 --- a/app/frontend/controllers/lazy_involvement_trigger_controller.js +++ b/app/frontend/controllers/lazy_involvement_trigger_controller.js @@ -1,18 +1,18 @@ import { Controller } from "@hotwired/stimulus" export default class extends Controller { - static values = { target: String } + static values = { target: String } - load() { - if (!this.targetValue) return - - const frame = document.getElementById(this.targetValue) - if (frame) { - // Trigger the lazy-involvement controller to load - const lazyController = this.application.getControllerForElementAndIdentifier(frame, "lazy-involvement") - if (lazyController) { - lazyController.load() - } + load() { + if (!this.targetValue) return + + const frame = document.getElementById(this.targetValue) + if (frame) { + // Trigger the lazy-involvement controller to load + const lazyController = this.application.getControllerForElementAndIdentifier(frame, "lazy-involvement") + if (lazyController) { + lazyController.load() + } + } } - } } diff --git a/app/frontend/controllers/sidebar_loading_controller.js b/app/frontend/controllers/sidebar_loading_controller.js index f6226176..409fdba6 100644 --- a/app/frontend/controllers/sidebar_loading_controller.js +++ b/app/frontend/controllers/sidebar_loading_controller.js @@ -1,24 +1,24 @@ import { Controller } from "@hotwired/stimulus" export default class extends Controller { - static targets = ["indicator"] + static targets = ["indicator"] - connect() { - // Hide loading indicator if content is already loaded - if (this.hasIndicatorTarget && this.element.querySelector(".sidebar__container")) { - this.hide() + connect() { + // Hide loading indicator if content is already loaded + if (this.hasIndicatorTarget && this.element.querySelector(".sidebar__container")) { + this.hide() + } } - } - show() { - if (this.hasIndicatorTarget) { - this.indicatorTarget.style.display = "flex" + show() { + if (this.hasIndicatorTarget) { + this.indicatorTarget.style.display = "flex" + } } - } - hide() { - if (this.hasIndicatorTarget) { - this.indicatorTarget.style.display = "none" + hide() { + if (this.hasIndicatorTarget) { + this.indicatorTarget.style.display = "none" + } } - } } From b88a5136e671070568fe6ed0d6f7ae90a82359ee Mon Sep 17 00:00:00 2001 From: saurabhraghuvanshii Date: Sat, 27 Dec 2025 01:31:56 +0530 Subject: [PATCH 3/3] fix side bar rendering issue --- app/helpers/users/sidebar_helper.rb | 31 +++++++++++++++++------------ 1 file changed, 18 insertions(+), 13 deletions(-) diff --git a/app/helpers/users/sidebar_helper.rb b/app/helpers/users/sidebar_helper.rb index 7f81b72e..87b78cbb 100644 --- a/app/helpers/users/sidebar_helper.rb +++ b/app/helpers/users/sidebar_helper.rb @@ -6,21 +6,26 @@ def has_unreads? end def sidebar_turbo_frame_tag(src: nil, &) - content = if block_given? - yield + if block_given? + turbo_frame_tag :user_sidebar, src: src, target: "_top", data: { + controller: "rooms-list read-rooms turbo-frame", + rooms_list_unread_class: "unread", + rooms_list_badge_class: "badge", + action: "presence:present@window->rooms-list#read read-rooms:read->rooms-list#read turbo:frame-load->rooms-list#loaded refresh-room:visible@window->turbo-frame#reload".html_safe # otherwise -> is escaped + } do + yield + end else - content_tag :div, class: "sidebar__loading", data: { sidebar_loading_target: "indicator" } do - content_tag :div, "", class: "spinner" + turbo_frame_tag :user_sidebar, src: src, target: "_top", data: { + controller: "rooms-list read-rooms turbo-frame sidebar-loading", + rooms_list_unread_class: "unread", + rooms_list_badge_class: "badge", + action: "presence:present@window->rooms-list#read read-rooms:read->rooms-list#read turbo:frame-load->rooms-list#loaded turbo:frame-load->sidebar-loading#hide refresh-room:visible@window->turbo-frame#reload".html_safe # otherwise -> is escaped + } do + content_tag :div, class: "sidebar__loading", data: { sidebar_loading_target: "indicator" } do + content_tag :div, "", class: "spinner" + end end end - - turbo_frame_tag :user_sidebar, src: src, target: "_top", data: { - controller: "rooms-list read-rooms turbo-frame sidebar-loading", - rooms_list_unread_class: "unread", - rooms_list_badge_class: "badge", - action: "presence:present@window->rooms-list#read read-rooms:read->rooms-list#read turbo:frame-load->rooms-list#loaded turbo:frame-load->sidebar-loading#hide turbo:before-frame-render->sidebar-loading#show refresh-room:visible@window->turbo-frame#reload".html_safe # otherwise -> is escaped - } do - content - end end end