|
313 | 313 | </div> |
314 | 314 | </section> |
315 | 315 |
|
| 316 | + <!-- Most Loved GeoKrety --> |
| 317 | + <section class="statistics-section"> |
| 318 | + <h2>❤️ {t}Most Loved GeoKrety{/t}</h2> |
| 319 | + <p class="help-block">{t}The top 10 GeoKrety that received the most love from the community.{/t}</p> |
| 320 | + <div class="row"> |
| 321 | + <div class="col-md-12"> |
| 322 | + <div class="panel panel-default"> |
| 323 | + <div class="panel-heading"> |
| 324 | + <h3 class="panel-title">❤️ {t}Top 10 Most Loved GeoKrety{/t}</h3> |
| 325 | + </div> |
| 326 | + <div class="panel-body"> |
| 327 | + {if $top_loved_geokrety} |
| 328 | + <div style="max-height: 600px; overflow-y: auto;"> |
| 329 | + <table class="table table-striped table-hover"> |
| 330 | + <thead> |
| 331 | + <tr> |
| 332 | + <th class="text-right">#</th> |
| 333 | + <th>{t}GeoKret{/t}</th> |
| 334 | + <th>{t}Owner{/t}</th> |
| 335 | + <th class="text-right">❤️ {t}Loves{/t}</th> |
| 336 | + <th class="text-center">{t}Trend{/t}</th> |
| 337 | + </tr> |
| 338 | + </thead> |
| 339 | + <tbody> |
| 340 | + {foreach from=$top_loved_geokrety item=gk name=loves_rank} |
| 341 | + <tr> |
| 342 | + <td class="text-right">{$smarty.foreach.loves_rank.iteration}</td> |
| 343 | + <td> |
| 344 | + <a href="{'geokret_details'|alias:sprintf('@gkid=%s', $gk.gkid_formatted)}"> |
| 345 | + {$gk.gkid_formatted} - {$gk.name|escape} |
| 346 | + </a> |
| 347 | + </td> |
| 348 | + <td> |
| 349 | + {if $gk.owner_username} |
| 350 | + <a href="{'user_details'|alias:sprintf('@userid=%d', $gk.owner)}">{$gk.owner_username|escape}</a> |
| 351 | + {else} |
| 352 | + <em>{t}Abandoned{/t}</em> |
| 353 | + {/if} |
| 354 | + </td> |
| 355 | + <td class="text-right"><strong>{$gk.loves_count}</strong></td> |
| 356 | + <td class="text-center loves-trend-col" data-gkid="{$gk.id}"><span class="text-muted">-</span></td> |
| 357 | + </tr> |
| 358 | + {/foreach} |
| 359 | + </tbody> |
| 360 | + </table> |
| 361 | + </div> |
| 362 | + {else} |
| 363 | + <p class="text-muted text-center"><em>{t}No loved GeoKrety yet. Be the first to show some love!{/t}</em></p> |
| 364 | + {/if} |
| 365 | + </div> |
| 366 | + </div> |
| 367 | + </div> |
| 368 | + </div> |
| 369 | + <div class="row" style="margin-top: 20px;"> |
| 370 | + <div class="col-md-12"> |
| 371 | + <div class="panel panel-default"> |
| 372 | + <div class="panel-heading"> |
| 373 | + <h3 class="panel-title">❤️ {t}Love Trend{/t}</h3> |
| 374 | + </div> |
| 375 | + <div class="panel-body"> |
| 376 | + <p class="help-block">{t}Monthly love activity on the platform.{/t}</p> |
| 377 | + <div id="loves-chart-container" style="width: 100%; height: 350px;"> |
| 378 | + <svg id="loves-chart" style="width: 100%; height: 100%;"></svg> |
| 379 | + </div> |
| 380 | + <div id="loves-cache-info" class="text-muted small text-center" style="margin-top: 10px;"></div> |
| 381 | + </div> |
| 382 | + </div> |
| 383 | + </div> |
| 384 | + </div> |
| 385 | + </section> |
| 386 | + |
316 | 387 | <!-- Media & Engagement --> |
317 | 388 | <section class="statistics-section"> |
318 | 389 | <h2>{t}Media & Engagement{/t}</h2> |
@@ -819,7 +890,14 @@ $(document).ready(function() { |
819 | 890 | formatCacheDuration: formatCacheDuration |
820 | 891 | }); |
821 | 892 |
|
822 | | - // Time series mode switcher |
| 893 | + initTimeSeriesChart({ |
| 894 | + anchor: "#loves-chart", |
| 895 | + dataUrl: "{/literal}{'api_v1_stats_loves_registrations'|alias}{literal}", |
| 896 | + title: "{/literal}{t}Love Votes{/t}{literal}", |
| 897 | + color: "#d9534f", |
| 898 | + cacheInfoElement: "#loves-cache-info", |
| 899 | + formatCacheDuration: formatCacheDuration |
| 900 | + }); |
823 | 901 | $(document).on("click", ".time-series-mode button", function() { |
824 | 902 | const $button = $(this); |
825 | 903 | const mode = $button.data("mode"); |
@@ -884,6 +962,30 @@ $(document).ready(function() { |
884 | 962 | } |
885 | 963 | }); |
886 | 964 |
|
| 965 | + // Load love trends for Most Loved GeoKrety table |
| 966 | + $.ajax({ |
| 967 | + url: "{/literal}{'api_v1_stats_loves_registrations'|alias}{literal}", |
| 968 | + method: "GET", |
| 969 | + dataType: "json", |
| 970 | + success: function(response) { |
| 971 | + const data = response.data || response; |
| 972 | + if (data && data.length > 0) { |
| 973 | + // Build a map of love counts by month |
| 974 | + const lovesTrend = data.map(item => item.count); |
| 975 | +
|
| 976 | + // Populate all trend cells with the same sparkline |
| 977 | + $(".loves-trend-col").each(function() { |
| 978 | + const $cell = $(this); |
| 979 | + const sparkline = createSparkline(lovesTrend, 80, 25, "loves"); |
| 980 | + $cell.html(sparkline); |
| 981 | + }); |
| 982 | + } |
| 983 | + }, |
| 984 | + error: function() { |
| 985 | + // Silently fail - trend is optional |
| 986 | + } |
| 987 | + }); |
| 988 | + |
887 | 989 | // Year filter state |
888 | 990 | let currentFilterYear = "all"; |
889 | 991 | const currentYear = new Date().getFullYear(); |
|
0 commit comments