|
66 | 66 | html.dark .composite-type-filter[data-type="engine"].active { color:#fbbf24; border-color:#f59e0b; background:rgba(245,158,11,0.12); } |
67 | 67 | </style> |
68 | 68 |
|
69 | | - <div class="lb-filters composite-profiles-wrap" style="margin:0.5rem 0 0 0; padding:0.75rem 1rem; background:rgba(0,0,0,0.04); border-radius:8px; border:1px solid rgba(0,0,0,0.08);"> |
70 | | - <span class="lb-filters-label">Tests</span> |
71 | | - <span class="lb-filters-hint">(Toggle)</span> |
72 | | - <div class="composite-profile-filter active" data-profile="all">All</div> |
73 | | - {{ range $profiles }} |
74 | | - <div class="composite-profile-filter cp-{{ .proto }} active" data-profile="{{ .id }}">{{ .label }} <span style="font-size:0.65rem; color:#94a3b8;">({{ .sublabel }})</span></div> |
75 | | - {{ end }} |
| 69 | + <div class="composite-profiles-wrap" style="margin:0.5rem 0 0 0; padding:0.75rem 1rem; background:rgba(0,0,0,0.04); border-radius:8px; border:1px solid rgba(0,0,0,0.08); display:flex; flex-direction:column; gap:0.5rem;"> |
| 70 | + <div class="lb-filters" style="margin:0; padding:0;"> |
| 71 | + <span class="lb-filters-label">Tests</span> |
| 72 | + <span class="lb-filters-hint">(Toggle)</span> |
| 73 | + <div class="composite-profile-filter active" data-profile="all">All</div> |
| 74 | + </div> |
| 75 | + <div class="lb-filters" style="margin:0; padding:0;"> |
| 76 | + <span class="composite-proto-label composite-proto-toggle active" data-proto="h1">HTTP/1.1</span> |
| 77 | + {{ range $profiles }}{{ if eq .proto "h1" }} |
| 78 | + <div class="composite-profile-filter cp-{{ .proto }} active" data-profile="{{ .id }}">{{ .label }}</div> |
| 79 | + {{ end }}{{ end }} |
| 80 | + </div> |
| 81 | + <div class="lb-filters" style="margin:0; padding:0;"> |
| 82 | + <span class="composite-proto-label composite-proto-toggle active" data-proto="h2">HTTP/2</span> |
| 83 | + {{ range $profiles }}{{ if eq .proto "h2" }} |
| 84 | + <div class="composite-profile-filter cp-{{ .proto }} active" data-profile="{{ .id }}">{{ .label }}</div> |
| 85 | + {{ end }}{{ end }} |
| 86 | + </div> |
| 87 | + <div class="lb-filters" style="margin:0; padding:0;"> |
| 88 | + <span class="composite-proto-label composite-proto-toggle active" data-proto="h3">HTTP/3</span> |
| 89 | + {{ range $profiles }}{{ if eq .proto "h3" }} |
| 90 | + <div class="composite-profile-filter cp-{{ .proto }} active" data-profile="{{ .id }}">{{ .label }}</div> |
| 91 | + {{ end }}{{ end }} |
| 92 | + </div> |
76 | 93 | </div> |
77 | 94 | <style> |
| 95 | + .composite-proto-label { font-size:0.7rem; font-weight:700; letter-spacing:0.04em; text-transform:uppercase; align-self:center; } |
| 96 | + .composite-proto-toggle { cursor:pointer; user-select:none; padding:0.25rem 0.6rem; border-radius:5px; border:1.5px solid #e2e8f0; color:#94a3b8; background:transparent; transition:all 0.15s ease; } |
| 97 | + .composite-proto-toggle:hover { transform:translateY(-1px); box-shadow:0 2px 4px rgba(0,0,0,0.08); color:#475569; border-color:#cbd5e1; } |
| 98 | + .composite-proto-toggle.active[data-proto="h1"] { color:#3b82f6; border-color:#3b82f6; background:rgba(59,130,246,0.06); } |
| 99 | + .composite-proto-toggle.active[data-proto="h2"] { color:#d97706; border-color:#d97706; background:rgba(217,119,6,0.06); } |
| 100 | + .composite-proto-toggle.active[data-proto="h3"] { color:#16a34a; border-color:#16a34a; background:rgba(22,163,74,0.06); } |
| 101 | + .composite-proto-toggle.active[data-proto="h1"]:hover { background:rgba(59,130,246,0.12); } |
| 102 | + .composite-proto-toggle.active[data-proto="h2"]:hover { background:rgba(217,119,6,0.12); } |
| 103 | + .composite-proto-toggle.active[data-proto="h3"]:hover { background:rgba(22,163,74,0.12); } |
| 104 | + html.dark .composite-proto-toggle { color:#64748b; border-color:#334155; } |
| 105 | + html.dark .composite-proto-toggle:hover { color:#94a3b8; border-color:#475569; } |
| 106 | + html.dark .composite-proto-toggle.active[data-proto="h1"] { color:#60a5fa; border-color:#3b82f6; background:rgba(59,130,246,0.12); } |
| 107 | + html.dark .composite-proto-toggle.active[data-proto="h2"] { color:#fbbf24; border-color:#d97706; background:rgba(217,119,6,0.12); } |
| 108 | + html.dark .composite-proto-toggle.active[data-proto="h3"] { color:#4ade80; border-color:#16a34a; background:rgba(22,163,74,0.12); } |
78 | 109 | .composite-profile-filter { padding:0.3rem 0.75rem; font-size:0.8rem; font-weight:500; color:#94a3b8; cursor:pointer; border-radius:6px; border:1.5px solid #e2e8f0; background:transparent; transition:all 0.15s ease; user-select:none; } |
79 | 110 | .composite-profile-filter:hover { color:#475569; border-color:#cbd5e1; transform:translateY(-1px); box-shadow:0 2px 4px rgba(0,0,0,0.08); } |
80 | 111 | .composite-profile-filter[data-profile="all"].active { color:#8b5cf6; border-color:#8b5cf6; background:rgba(139,92,246,0.06); font-weight:600; } |
|
297 | 328 | }); |
298 | 329 |
|
299 | 330 | // For mixed: compute weighted scores and re-normalize |
300 | | - var mixedWeights = {baseline:0.1, json:1, db:15, upload:15, compression:8}; |
| 331 | + var mixedWeights = {baseline:0.15, json:1, db:10, upload:10, compression:7}; |
301 | 332 | if (activeIds.indexOf('mixed') >= 0) { |
302 | 333 | var maxWeighted = 0; |
303 | 334 | Object.keys(avgTplMixed).forEach(function(fw) { |
|
539 | 570 | // Initial render |
540 | 571 | renderComposite(); |
541 | 572 |
|
| 573 | +// Sync proto toggle active state based on child profile filters |
| 574 | +function syncProtoToggles() { |
| 575 | + document.querySelectorAll('.composite-proto-toggle').forEach(function(pt) { |
| 576 | + var proto = pt.dataset.proto; |
| 577 | + var groupFilters = document.querySelectorAll('.composite-profile-filter.cp-' + proto); |
| 578 | + var anyActive = Array.prototype.some.call(groupFilters, function(f) { return f.classList.contains('active'); }); |
| 579 | + if (anyActive) pt.classList.add('active'); |
| 580 | + else pt.classList.remove('active'); |
| 581 | + }); |
| 582 | +} |
| 583 | + |
542 | 584 | // Profile filter click handlers |
543 | 585 | document.querySelectorAll('.composite-profile-filter').forEach(function(btn) { |
544 | 586 | btn.addEventListener('click', function() { |
|
556 | 598 | allFilters.forEach(function(f) { f.classList.add('active'); }); |
557 | 599 | } |
558 | 600 | } |
| 601 | + syncProtoToggles(); |
| 602 | + renderComposite(); |
| 603 | + }); |
| 604 | +}); |
| 605 | + |
| 606 | +// Protocol group toggle handlers |
| 607 | +document.querySelectorAll('.composite-proto-toggle').forEach(function(btn) { |
| 608 | + btn.addEventListener('click', function() { |
| 609 | + var proto = btn.dataset.proto; |
| 610 | + var groupFilters = document.querySelectorAll('.composite-profile-filter.cp-' + proto); |
| 611 | + var allActive = Array.prototype.every.call(groupFilters, function(f) { return f.classList.contains('active'); }); |
| 612 | + groupFilters.forEach(function(f) { |
| 613 | + if (allActive) f.classList.remove('active'); |
| 614 | + else f.classList.add('active'); |
| 615 | + }); |
| 616 | + var allBtn = document.querySelector('.composite-profile-filter[data-profile="all"]'); |
| 617 | + allBtn.classList.remove('active'); |
| 618 | + var total = document.querySelectorAll('.composite-profile-filter[data-profile]:not([data-profile="all"])').length; |
| 619 | + var active = document.querySelectorAll('.composite-profile-filter[data-profile]:not([data-profile="all"]).active').length; |
| 620 | + if (active === 0 || active === total) { |
| 621 | + document.querySelectorAll('.composite-profile-filter').forEach(function(f) { f.classList.add('active'); }); |
| 622 | + } |
| 623 | + syncProtoToggles(); |
559 | 624 | renderComposite(); |
560 | 625 | }); |
561 | 626 | }); |
|
0 commit comments