Coffee journaling on ATProto (alpha) alpha.arabica.social
coffee

fix: stats display fix

pdewey.com 6fd5b0f6 3e52c048

verified
+55 -6
+9
templates/partials/profile_content.tmpl
··· 1 {{define "profile_content"}} 2 <!-- Brews Tab --> 3 <div x-show="activeTab === 'brews'"> 4 {{template "brew_list_content" .}}
··· 1 {{define "profile_content"}} 2 + <!-- Stats data to be read by JavaScript --> 3 + <div id="profile-stats-data" 4 + data-brews="{{len .Brews}}" 5 + data-beans="{{len .Beans}}" 6 + data-roasters="{{len .Roasters}}" 7 + data-grinders="{{len .Grinders}}" 8 + data-brewers="{{len .Brewers}}" 9 + style="display: none;"></div> 10 + 11 <!-- Brews Tab --> 12 <div x-show="activeTab === 'brews'"> 13 {{template "brew_list_content" .}}
+10 -6
templates/profile.tmpl
··· 2 {{if .IsOwnProfile}} 3 <!-- Load manage page JavaScript before Alpine.js processes the page --> 4 <script src="/static/js/manage-page.js"></script> 5 <div class="max-w-4xl mx-auto" x-data="managePage()"> 6 {{else}} 7 <div class="max-w-4xl mx-auto"> ··· 35 <!-- Stats (load immediately with placeholder values) --> 36 <div class="grid grid-cols-2 md:grid-cols-5 gap-4 mb-6"> 37 <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 38 - <div class="text-2xl font-bold text-brown-800">-</div> 39 <div class="text-sm text-brown-700">Brews</div> 40 </div> 41 <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 42 - <div class="text-2xl font-bold text-brown-800">-</div> 43 <div class="text-sm text-brown-700">Beans</div> 44 </div> 45 <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 46 - <div class="text-2xl font-bold text-brown-800">-</div> 47 <div class="text-sm text-brown-700">Roasters</div> 48 </div> 49 <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 50 - <div class="text-2xl font-bold text-brown-800">-</div> 51 <div class="text-sm text-brown-700">Grinders</div> 52 </div> 53 <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 54 - <div class="text-2xl font-bold text-brown-800">-</div> 55 <div class="text-sm text-brown-700">Brewers</div> 56 </div> 57 </div> ··· 83 </div> 84 85 <!-- Tab content loaded via HTMX --> 86 - <div hx-get="/api/profile/{{.Profile.Handle}}" hx-trigger="load" hx-swap="innerHTML"> 87 <!-- Loading skeleton --> 88 <div class="animate-pulse"> 89 <!-- Brews Tab Skeleton -->
··· 2 {{if .IsOwnProfile}} 3 <!-- Load manage page JavaScript before Alpine.js processes the page --> 4 <script src="/static/js/manage-page.js"></script> 5 + {{end}} 6 + <!-- Load profile stats updater --> 7 + <script src="/static/js/profile-stats.js"></script> 8 + {{if .IsOwnProfile}} 9 <div class="max-w-4xl mx-auto" x-data="managePage()"> 10 {{else}} 11 <div class="max-w-4xl mx-auto"> ··· 39 <!-- Stats (load immediately with placeholder values) --> 40 <div class="grid grid-cols-2 md:grid-cols-5 gap-4 mb-6"> 41 <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 42 + <div class="text-2xl font-bold text-brown-800" data-stat="brews">-</div> 43 <div class="text-sm text-brown-700">Brews</div> 44 </div> 45 <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 46 + <div class="text-2xl font-bold text-brown-800" data-stat="beans">-</div> 47 <div class="text-sm text-brown-700">Beans</div> 48 </div> 49 <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 50 + <div class="text-2xl font-bold text-brown-800" data-stat="roasters">-</div> 51 <div class="text-sm text-brown-700">Roasters</div> 52 </div> 53 <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 54 + <div class="text-2xl font-bold text-brown-800" data-stat="grinders">-</div> 55 <div class="text-sm text-brown-700">Grinders</div> 56 </div> 57 <div class="bg-gradient-to-br from-brown-100 to-brown-200 rounded-lg shadow-md p-4 text-center border border-brown-300"> 58 + <div class="text-2xl font-bold text-brown-800" data-stat="brewers">-</div> 59 <div class="text-sm text-brown-700">Brewers</div> 60 </div> 61 </div> ··· 87 </div> 88 89 <!-- Tab content loaded via HTMX --> 90 + <div id="profile-content" hx-get="/api/profile/{{.Profile.Handle}}" hx-trigger="load" hx-swap="innerHTML"> 91 <!-- Loading skeleton --> 92 <div class="animate-pulse"> 93 <!-- Brews Tab Skeleton -->
+36
web/static/js/profile-stats.js
···
··· 1 + /** 2 + * Profile stats updater 3 + * Listens for HTMX content swap and updates stats from data attributes 4 + */ 5 + 6 + document.addEventListener('DOMContentLoaded', function() { 7 + // Listen for HTMX afterSwap event on the profile content 8 + document.body.addEventListener('htmx:afterSwap', function(evt) { 9 + // Only handle swaps in the profile-content element 10 + if (evt.detail.target.id === 'profile-content') { 11 + updateProfileStats(); 12 + } 13 + }); 14 + }); 15 + 16 + function updateProfileStats() { 17 + // Get stats data from the hidden div 18 + const statsData = document.getElementById('profile-stats-data'); 19 + if (!statsData) return; 20 + 21 + const stats = [ 22 + { selector: '[data-stat="brews"]', key: 'brews' }, 23 + { selector: '[data-stat="beans"]', key: 'beans' }, 24 + { selector: '[data-stat="roasters"]', key: 'roasters' }, 25 + { selector: '[data-stat="grinders"]', key: 'grinders' }, 26 + { selector: '[data-stat="brewers"]', key: 'brewers' } 27 + ]; 28 + 29 + stats.forEach(function(stat) { 30 + const value = statsData.dataset[stat.key]; 31 + const el = document.querySelector(stat.selector); 32 + if (el && value !== undefined) { 33 + el.textContent = value; 34 + } 35 + }); 36 + }