diff --git a/app/assets/stylesheets/application/sidebar.css b/app/assets/stylesheets/application/sidebar.css index 5a9e69f7..aa864b19 100644 --- a/app/assets/stylesheets/application/sidebar.css +++ b/app/assets/stylesheets/application/sidebar.css @@ -627,3 +627,67 @@ font-weight: 500; } } + +/* Sidebar Loading Skeleton */ +.sidebar__loading { + padding-inline-end: var(--sidebar-tools-width); + block-size: 100dvh; +} + +.sidebar__loading-directs { + display: flex; + gap: calc(var(--inline-space) / 1.5); + padding-block: var(--block-space) var(--block-space-half); + padding-inline: var(--sidebar-inline-space); + margin-block-end: var(--block-space-half); +} + +.sidebar__loading-avatar { + width: 48px; + height: 48px; + border-radius: 50%; + background: var(--color-border); + animation: skeleton-pulse 1.5s ease-in-out infinite; +} + +.sidebar__loading-rooms { + padding-inline: var(--sidebar-inline-space); +} + +.sidebar__loading-search { + height: 2.5rem; + border-radius: 0.5rem; + background: var(--color-border); + margin-block-end: var(--block-space); + animation: skeleton-pulse 1.5s ease-in-out infinite; +} + +.sidebar__loading-section { + margin-block-end: var(--block-space); +} + +.sidebar__loading-heading { + height: 1.25rem; + width: 6rem; + border-radius: 0.25rem; + background: var(--color-border); + margin-block-end: var(--block-space); + animation: skeleton-pulse 1.5s ease-in-out infinite; +} + +.sidebar__loading-room { + height: 2rem; + border-radius: 0.25rem; + background: var(--color-border); + margin-block-end: 0.5rem; + animation: skeleton-pulse 1.5s ease-in-out infinite; +} + +@keyframes skeleton-pulse { + 0%, 100% { + opacity: 0.4; + } + 50% { + opacity: 0.7; + } +} diff --git a/app/helpers/users/sidebar_helper.rb b/app/helpers/users/sidebar_helper.rb index 15a9f4f2..29388dc3 100644 --- a/app/helpers/users/sidebar_helper.rb +++ b/app/helpers/users/sidebar_helper.rb @@ -5,12 +5,18 @@ def has_unreads? Current.user.memberships.unread.any? end - def sidebar_turbo_frame_tag(src: nil, &) + def sidebar_turbo_frame_tag(src: nil, &block) + content = if block_given? + block + elsif src + -> { render "users/sidebars/loading_skeleton" } + end + 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 - }, & + }, &content end end diff --git a/app/views/users/sidebars/_loading_skeleton.html.erb b/app/views/users/sidebars/_loading_skeleton.html.erb new file mode 100644 index 00000000..f3856bb2 --- /dev/null +++ b/app/views/users/sidebars/_loading_skeleton.html.erb @@ -0,0 +1,25 @@ +