Add async loading for mini leaderboard

This commit is contained in:
Max Wofford
2025-05-12 14:39:22 -04:00
parent 9a2f4ffdeb
commit 4e2399a0b3
6 changed files with 123 additions and 82 deletions

View File

@@ -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;
}

View File

@@ -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

View File

@@ -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? %>
<div class="mini-leaderboard">
<p class="super">
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 %>
</p>
<div class="leaderboard-entries">
<% mini_leaderboard_entries.each_with_index do |entry, idx| %>
<% is_competition = !show_top_entries && idx >= 2 %>
<div class="leaderboard-entry <%= 'current-user' if entry.user_id == current_user&.id %>">
<% if !is_competition %>
<% rank_emoji = case entries.index(entry)
when 0 then "🥇"
when 1 then "🥈"
when 2 then "🥉"
end %>
<span class="rank"><%= rank_emoji %></span>
<% else %>
<% if idx == 2 && entries.index(entry) - entries.index(mini_leaderboard_entries[1]) > 1 %>
<div class="leaderboard-break">...</div>
<% if mini_leaderboard_entries&.any? %>
<div class="mini-leaderboard">
<p class="super">
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 %>
</p>
<div class="leaderboard-entries">
<% mini_leaderboard_entries.each_with_index do |entry, idx| %>
<% is_competition = !show_top_entries && idx >= 2 %>
<div class="leaderboard-entry <%= 'current-user' if entry.user_id == current_user&.id %>">
<% if !is_competition %>
<% rank_emoji = case entries.index(entry)
when 0 then "🥇"
when 1 then "🥈"
when 2 then "🥉"
end %>
<span class="rank"><%= rank_emoji %></span>
<% else %>
<% if idx == 2 && entries.index(entry) - entries.index(mini_leaderboard_entries[1]) > 1 %>
<div class="leaderboard-break">...</div>
<% end %>
<span class="rank"><%= (entries.index(entry) + 1).ordinalize %></span>
<% end %>
<span class="rank"><%= (entries.index(entry) + 1).ordinalize %></span>
<% end %>
<span class="user">
<%= render "shared/user_mention", user: entry.user, show: [:neighborhood] %>
<% if entry.user == current_user && current_user.github_username.blank? %>
<span class="super">
<%= link_to "Link active projects", my_settings_path(anchor: "user_github_account"), target: "_blank" %>
</span>
<% end %>
<% if @active_projects&.dig(entry.user_id).present? %>
<span class="super">
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 %>
</span>
<% end %>
<% if entry.streak_count > 7 %>
<span class="super" title="7+ daily streak">
🔥 7+
</span>
<% elsif entry.streak_count > 0 %>
<span class="super" title="<%= entry.streak_count %> day streak">
🔥 <%= entry.streak_count %>
</span>
<% end %>
</span>
<span class="time"><%= short_time_detailed entry.total_seconds %></span>
</div>
<% end %>
<span class="user">
<%= render "shared/user_mention", user: entry.user, show: [:neighborhood] %>
<% if entry.user == current_user && current_user.github_username.blank? %>
<span class="super">
<%= link_to "Link active projects", my_settings_path(anchor: "user_github_account"), target: "_blank" %>
</span>
<% end %>
<% if @active_projects&.dig(entry.user_id).present? %>
<span class="super">
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 %>
</span>
<% end %>
<% if entry.streak_count > 7 %>
<span class="super" title="7+ daily streak">
🔥 7+
</span>
<% elsif entry.streak_count > 0 %>
<span class="super" title="<%= entry.streak_count %> day streak">
🔥 <%= entry.streak_count %>
</span>
<% end %>
</span>
<span class="time"><%= short_time_detailed entry.total_seconds %></span>
</div>
<% end %>
</div>
</div>
</div>
<% end %>
<% end %>

View File

@@ -0,0 +1,17 @@
<div class="mini-leaderboard loading">
<p class="super">
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 %>
</p>
<div class="leaderboard-entries">
<% (current_user ? 5 : 3).times do %>
<div class="leaderboard-entry">
<span class="rank">...</span>
<span class="user">Loading...</span>
<span class="time">...</span>
</div>
<% end %>
</div>
</div>

View File

@@ -93,8 +93,8 @@
<% end %>
</p>
<% 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 %>

View File

@@ -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