From 4e2399a0b39e03b0fb400a574026224909238c99 Mon Sep 17 00:00:00 2001 From: Max Wofford Date: Mon, 12 May 2025 14:39:22 -0400 Subject: [PATCH] Add async loading for mini leaderboard --- app/assets/stylesheets/leaderboard.css | 15 ++ app/controllers/static_pages_controller.rb | 26 ++-- .../leaderboards/_mini_leaderboard.html.erb | 142 +++++++++--------- .../_mini_leaderboard_loading.html.erb | 17 +++ app/views/static_pages/index.html.erb | 4 +- config/routes.rb | 1 + 6 files changed, 123 insertions(+), 82 deletions(-) create mode 100644 app/views/leaderboards/_mini_leaderboard_loading.html.erb diff --git a/app/assets/stylesheets/leaderboard.css b/app/assets/stylesheets/leaderboard.css index fd93ee4..30b8be8 100644 --- a/app/assets/stylesheets/leaderboard.css +++ b/app/assets/stylesheets/leaderboard.css @@ -151,4 +151,19 @@ h3+.mini-leaderboard { .period-toggle-btn:hover:not(.active) { background-color: rgba(255, 255, 255, 0.1); } +} + +.mini-leaderboard.loading .leaderboard-entry { + opacity: 0.7; + animation: pulse 1.5s infinite; +} + +@keyframes pulse { + 0% { opacity: 0.7; } + 50% { opacity: 0.4; } + 100% { opacity: 0.7; } +} + +turbo-frame#mini_leaderboard[aria-busy="true"]::before { + display: none !important; } \ No newline at end of file diff --git a/app/controllers/static_pages_controller.rb b/app/controllers/static_pages_controller.rb index 6ee7c15..6a30651 100644 --- a/app/controllers/static_pages_controller.rb +++ b/app/controllers/static_pages_controller.rb @@ -5,16 +5,6 @@ class StaticPagesController < ApplicationController ] def index - @leaderboard = Leaderboard.where.associated(:entries) - .where(start_date: Date.current) - .where(deleted_at: nil) - .where(period_type: :daily) - .distinct - .first - - # Get active projects for the mini leaderboard - @active_projects = Cache::ActiveProjectsJob.perform_now - if current_user flavor_texts = FlavorText.motto + FlavorText.conditional_mottos(current_user) flavor_texts += FlavorText.rare_motto if Random.rand(10) < 1 @@ -80,6 +70,22 @@ class StaticPagesController < ApplicationController end end + def mini_leaderboard + @leaderboard = Leaderboard.where.associated(:entries) + .where(start_date: Date.current) + .where(deleted_at: nil) + .where(period_type: :daily) + .distinct + .first + + @active_projects = Cache::ActiveProjectsJob.perform_now + + render partial: "leaderboards/mini_leaderboard", locals: { + leaderboard: @leaderboard, + current_user: current_user + } + end + def project_durations return unless current_user diff --git a/app/views/leaderboards/_mini_leaderboard.html.erb b/app/views/leaderboards/_mini_leaderboard.html.erb index 83f5d8f..879bb9d 100644 --- a/app/views/leaderboards/_mini_leaderboard.html.erb +++ b/app/views/leaderboards/_mini_leaderboard.html.erb @@ -1,78 +1,80 @@ -<% - entries = leaderboard.entries.order(total_seconds: :desc) - if current_user - user_rank = entries.find_index { |entry| entry.user_id == current_user.id } - if user_rank && user_rank >= 3 - # Show top 2 entries and immediate competition - top_entries = entries[0..1] - competition_entries = entries[[user_rank - 1, 2].max..[user_rank + 1, entries.size - 1].min] - mini_leaderboard_entries = top_entries + competition_entries - show_top_entries = false +<%= turbo_frame_tag "mini_leaderboard" do %> + <% + entries = leaderboard.entries.order(total_seconds: :desc) + if current_user + user_rank = entries.find_index { |entry| entry.user_id == current_user.id } + if user_rank && user_rank >= 3 + # Show top 2 entries and immediate competition + top_entries = entries[0..1] + competition_entries = entries[[user_rank - 1, 2].max..[user_rank + 1, entries.size - 1].min] + mini_leaderboard_entries = top_entries + competition_entries + show_top_entries = false + else + # Show top 3 entries (either user is in top 3 or not on leaderboard) + mini_leaderboard_entries = entries.first(3) + show_top_entries = true + end else - # Show top 3 entries (either user is in top 3 or not on leaderboard) + # Not logged in, show top 3 mini_leaderboard_entries = entries.first(3) show_top_entries = true end - else - # Not logged in, show top 3 - mini_leaderboard_entries = entries.first(3) - show_top_entries = true - end -%> + %> -<% if mini_leaderboard_entries&.any? %> -
-

- This leaderboard is in <%= Leaderboard::GLOBAL_TIMEZONE %>. - <% if current_user && timezone_difference_in_seconds(Leaderboard::GLOBAL_TIMEZONE, current_user.timezone) != 0 %> - <%= timezone_difference_in_words(Leaderboard::GLOBAL_TIMEZONE, current_user.timezone) %> - <% end %> -

-
- <% mini_leaderboard_entries.each_with_index do |entry, idx| %> - <% is_competition = !show_top_entries && idx >= 2 %> -
- <% if !is_competition %> - <% rank_emoji = case entries.index(entry) - when 0 then "🥇" - when 1 then "🥈" - when 2 then "🥉" - end %> - <%= rank_emoji %> - <% else %> - <% if idx == 2 && entries.index(entry) - entries.index(mini_leaderboard_entries[1]) > 1 %> -
...
+ <% if mini_leaderboard_entries&.any? %> +
+

+ This leaderboard is in <%= Leaderboard::GLOBAL_TIMEZONE %>. + <% if current_user && timezone_difference_in_seconds(Leaderboard::GLOBAL_TIMEZONE, current_user.timezone) != 0 %> + <%= timezone_difference_in_words(Leaderboard::GLOBAL_TIMEZONE, current_user.timezone) %> + <% end %> +

+
+ <% mini_leaderboard_entries.each_with_index do |entry, idx| %> + <% is_competition = !show_top_entries && idx >= 2 %> +
+ <% if !is_competition %> + <% rank_emoji = case entries.index(entry) + when 0 then "🥇" + when 1 then "🥈" + when 2 then "🥉" + end %> + <%= rank_emoji %> + <% else %> + <% if idx == 2 && entries.index(entry) - entries.index(mini_leaderboard_entries[1]) > 1 %> +
...
+ <% end %> + <%= (entries.index(entry) + 1).ordinalize %> <% end %> - <%= (entries.index(entry) + 1).ordinalize %> - <% end %> - - <%= render "shared/user_mention", user: entry.user, show: [:neighborhood] %> - <% if entry.user == current_user && current_user.github_username.blank? %> - - <%= link_to "Link active projects", my_settings_path(anchor: "user_github_account"), target: "_blank" %> - - <% end %> - <% if @active_projects&.dig(entry.user_id).present? %> - - working on <%= link_to @active_projects[entry.user_id].project_name, @active_projects[entry.user_id].repo_url, target: "_blank" %> - <% dev_tool(nil, 'span') do %> - <%= link_to "🌌", visualize_git_url(@active_projects[entry.user_id].repo_url), target: "_blank" %> - <% end %> - - <% end %> - <% if entry.streak_count > 7 %> - - 🔥 7+ - - <% elsif entry.streak_count > 0 %> - - 🔥 <%= entry.streak_count %> - - <% end %> - - <%= short_time_detailed entry.total_seconds %> -
- <% end %> + + <%= render "shared/user_mention", user: entry.user, show: [:neighborhood] %> + <% if entry.user == current_user && current_user.github_username.blank? %> + + <%= link_to "Link active projects", my_settings_path(anchor: "user_github_account"), target: "_blank" %> + + <% end %> + <% if @active_projects&.dig(entry.user_id).present? %> + + working on <%= link_to @active_projects[entry.user_id].project_name, @active_projects[entry.user_id].repo_url, target: "_blank" %> + <% dev_tool(nil, 'span') do %> + <%= link_to "🌌", visualize_git_url(@active_projects[entry.user_id].repo_url), target: "_blank" %> + <% end %> + + <% end %> + <% if entry.streak_count > 7 %> + + 🔥 7+ + + <% elsif entry.streak_count > 0 %> + + 🔥 <%= entry.streak_count %> + + <% end %> + + <%= short_time_detailed entry.total_seconds %> +
+ <% end %> +
-
+ <% end %> <% end %> \ No newline at end of file diff --git a/app/views/leaderboards/_mini_leaderboard_loading.html.erb b/app/views/leaderboards/_mini_leaderboard_loading.html.erb new file mode 100644 index 0000000..239439a --- /dev/null +++ b/app/views/leaderboards/_mini_leaderboard_loading.html.erb @@ -0,0 +1,17 @@ +
+

+ This leaderboard is in <%= Leaderboard::GLOBAL_TIMEZONE %>. + <% if current_user && timezone_difference_in_seconds(Leaderboard::GLOBAL_TIMEZONE, current_user.timezone) != 0 %> + <%= timezone_difference_in_words(Leaderboard::GLOBAL_TIMEZONE, current_user.timezone) %> + <% end %> +

+
+ <% (current_user ? 5 : 3).times do %> +
+ ... + Loading... + ... +
+ <% end %> +
+
\ No newline at end of file diff --git a/app/views/static_pages/index.html.erb b/app/views/static_pages/index.html.erb index c91dc23..a25fa5e 100644 --- a/app/views/static_pages/index.html.erb +++ b/app/views/static_pages/index.html.erb @@ -93,8 +93,8 @@ <% end %>

- <% if @leaderboard %> - <%= render "leaderboards/mini_leaderboard", leaderboard: @leaderboard, current_user: current_user %> + <%= turbo_frame_tag "mini_leaderboard", src: mini_leaderboard_static_pages_path do %> + <%= render "leaderboards/mini_leaderboard_loading" %> <% end %> <%= turbo_frame_tag "filterable_dashboard", src: filterable_dashboard_static_pages_path do %> diff --git a/config/routes.rb b/config/routes.rb index f3579dc..1e7e4ca 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -38,6 +38,7 @@ Rails.application.routes.draw do get :currently_hacking get :filterable_dashboard_content get :filterable_dashboard + get :mini_leaderboard get "🃏", to: "static_pages#🃏", as: :wildcard get :streak end