tangled
alpha
login
or
join now
arabica.social
/
arabica
7
fork
atom
Coffee journaling on ATProto (alpha)
alpha.arabica.social
coffee
7
fork
atom
overview
issues
pulls
pipelines
fix: stats display fix
pdewey.com
1 month ago
6fd5b0f6
3e52c048
verified
This commit was signed with the committer's
known signature
.
pdewey.com
SSH Key Fingerprint:
SHA256:ePOVkJstqVLchGK8m9/OGQG+aFNHD5XN3xjvW9wKCA4=
+55
-6
3 changed files
expand all
collapse all
unified
split
templates
partials
profile_content.tmpl
profile.tmpl
web
static
js
profile-stats.js
+9
templates/partials/profile_content.tmpl
···
1
1
{{define "profile_content"}}
2
2
+
<!-- Stats data to be read by JavaScript -->
3
3
+
<div id="profile-stats-data"
4
4
+
data-brews="{{len .Brews}}"
5
5
+
data-beans="{{len .Beans}}"
6
6
+
data-roasters="{{len .Roasters}}"
7
7
+
data-grinders="{{len .Grinders}}"
8
8
+
data-brewers="{{len .Brewers}}"
9
9
+
style="display: none;"></div>
10
10
+
2
11
<!-- Brews Tab -->
3
12
<div x-show="activeTab === 'brews'">
4
13
{{template "brew_list_content" .}}
+10
-6
templates/profile.tmpl
···
2
2
{{if .IsOwnProfile}}
3
3
<!-- Load manage page JavaScript before Alpine.js processes the page -->
4
4
<script src="/static/js/manage-page.js"></script>
5
5
+
{{end}}
6
6
+
<!-- Load profile stats updater -->
7
7
+
<script src="/static/js/profile-stats.js"></script>
8
8
+
{{if .IsOwnProfile}}
5
9
<div class="max-w-4xl mx-auto" x-data="managePage()">
6
10
{{else}}
7
11
<div class="max-w-4xl mx-auto">
···
35
39
<!-- Stats (load immediately with placeholder values) -->
36
40
<div class="grid grid-cols-2 md:grid-cols-5 gap-4 mb-6">
37
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">
38
38
-
<div class="text-2xl font-bold text-brown-800">-</div>
42
42
+
<div class="text-2xl font-bold text-brown-800" data-stat="brews">-</div>
39
43
<div class="text-sm text-brown-700">Brews</div>
40
44
</div>
41
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">
42
42
-
<div class="text-2xl font-bold text-brown-800">-</div>
46
46
+
<div class="text-2xl font-bold text-brown-800" data-stat="beans">-</div>
43
47
<div class="text-sm text-brown-700">Beans</div>
44
48
</div>
45
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">
46
46
-
<div class="text-2xl font-bold text-brown-800">-</div>
50
50
+
<div class="text-2xl font-bold text-brown-800" data-stat="roasters">-</div>
47
51
<div class="text-sm text-brown-700">Roasters</div>
48
52
</div>
49
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">
50
50
-
<div class="text-2xl font-bold text-brown-800">-</div>
54
54
+
<div class="text-2xl font-bold text-brown-800" data-stat="grinders">-</div>
51
55
<div class="text-sm text-brown-700">Grinders</div>
52
56
</div>
53
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">
54
54
-
<div class="text-2xl font-bold text-brown-800">-</div>
58
58
+
<div class="text-2xl font-bold text-brown-800" data-stat="brewers">-</div>
55
59
<div class="text-sm text-brown-700">Brewers</div>
56
60
</div>
57
61
</div>
···
83
87
</div>
84
88
85
89
<!-- Tab content loaded via HTMX -->
86
86
-
<div hx-get="/api/profile/{{.Profile.Handle}}" hx-trigger="load" hx-swap="innerHTML">
90
90
+
<div id="profile-content" hx-get="/api/profile/{{.Profile.Handle}}" hx-trigger="load" hx-swap="innerHTML">
87
91
<!-- Loading skeleton -->
88
92
<div class="animate-pulse">
89
93
<!-- Brews Tab Skeleton -->
+36
web/static/js/profile-stats.js
···
1
1
+
/**
2
2
+
* Profile stats updater
3
3
+
* Listens for HTMX content swap and updates stats from data attributes
4
4
+
*/
5
5
+
6
6
+
document.addEventListener('DOMContentLoaded', function() {
7
7
+
// Listen for HTMX afterSwap event on the profile content
8
8
+
document.body.addEventListener('htmx:afterSwap', function(evt) {
9
9
+
// Only handle swaps in the profile-content element
10
10
+
if (evt.detail.target.id === 'profile-content') {
11
11
+
updateProfileStats();
12
12
+
}
13
13
+
});
14
14
+
});
15
15
+
16
16
+
function updateProfileStats() {
17
17
+
// Get stats data from the hidden div
18
18
+
const statsData = document.getElementById('profile-stats-data');
19
19
+
if (!statsData) return;
20
20
+
21
21
+
const stats = [
22
22
+
{ selector: '[data-stat="brews"]', key: 'brews' },
23
23
+
{ selector: '[data-stat="beans"]', key: 'beans' },
24
24
+
{ selector: '[data-stat="roasters"]', key: 'roasters' },
25
25
+
{ selector: '[data-stat="grinders"]', key: 'grinders' },
26
26
+
{ selector: '[data-stat="brewers"]', key: 'brewers' }
27
27
+
];
28
28
+
29
29
+
stats.forEach(function(stat) {
30
30
+
const value = statsData.dataset[stat.key];
31
31
+
const el = document.querySelector(stat.selector);
32
32
+
if (el && value !== undefined) {
33
33
+
el.textContent = value;
34
34
+
}
35
35
+
});
36
36
+
}