Files
hammerfest/layouts/partials/savings-calc.html
T
2026-10-20 08:32:39 -06:00

78 lines
4.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{/*
The savings calculator: pick the apps you pay for today and your team
size, and compare their yearly retail cost with the smallest Federated plan
that replaces every app picked (the highest `tier` among them).
Input: dict with "key" (unique id), "apps" (name, cost, tier, perSeat,
selected), "plans" (name, tier, annual; cheapest first), optional "note", "compact" (one result, no cost breakdown) and
"more" (a link to the full calculator). The totals need JS; without it,
the app list still shows each app's retail price.
*/}}
{{ $key := .key }}
<form class="savings-calc{{ if .compact }} is-compact{{ end }}" id="{{ $key }}-calc" data-plans="{{ .plans | jsonify }}" onsubmit="return false">
<fieldset class="calc-apps">
<legend class="plan-subhead">{{ if .compact }}Which of these do you pay for?{{ else }}Which apps do you pay for today?{{ end }}</legend>
<div class="calc-app-grid">
{{ range .apps }}
<label class="calc-app">
<input type="checkbox" value="{{ .cost }}" data-tier="{{ .tier }}" data-per-seat="{{ .perSeat }}"{{ if .selected }} checked{{ end }}>
<span class="calc-app-name">{{ .name }}</span>
<span class="calc-app-cost">${{ .cost }}{{ if .perSeat }}/person{{ else }} flat{{ end }}</span>
</label>
{{ end }}
</div>
</fieldset>
<div class="calc-users">
<label class="plan-subhead" for="{{ $key }}-users">How many people work at your company?</label>
<div class="calc-users-row">
<input type="range" id="{{ $key }}-users" min="1" max="28" step="1" value="2">
<output class="calc-users-value" for="{{ $key }}-users">10</output>
</div>
</div>
<div class="calc-result" aria-live="polite">
{{ if not .compact }}
<div class="calc-stat"><span class="calc-stat-label">Apps replaced</span><span class="calc-stat-value" data-out="count">0</span></div>
<div class="calc-stat"><span class="calc-stat-label">Their retail cost</span><span class="calc-stat-value" data-out="cost">$0</span><span class="calc-stat-unit">/year</span></div>
{{ end }}
<div class="calc-stat is-highlight"><span class="calc-stat-label">You save</span><span class="calc-stat-value" data-out="savings">$0</span><span class="calc-stat-unit">/year on the <span data-out="plan">Good</span> plan</span></div>
{{ with .more }}<a class="more calc-more" href="{{ .url | relURL }}">{{ .label }}<span class="arrow" aria-hidden="true">→</span></a>{{ end }}
</div>
{{ with .note }}<p class="plan-note">{{ . | markdownify }}</p>{{ end }}
</form>
<script>
(function () {
var form = document.getElementById('{{ $key }}-calc');
if (!form) return;
var plans = JSON.parse(form.dataset.plans || '[]');
var range = form.querySelector('input[type=range]');
var shown = form.querySelector('.calc-users-value');
var fmt = function (n) { return '$' + Math.round(n).toLocaleString('en-US'); };
function out(name, text) { var el = form.querySelector('[data-out=' + name + ']'); if (el) el.textContent = text; }
// The slider's 28 steps: 1, then 10–100 by 10, 200–1,000 by 100, 1,500–5,000 by 500.
function users(step) {
if (step <= 1) return 1;
if (step <= 11) return (step - 1) * 10;
if (step <= 20) return (step - 10) * 100;
return 1000 + (step - 20) * 500;
}
function update() {
var n = users(+range.value), count = 0, cost = 0, need = 0;
shown.textContent = n.toLocaleString('en-US') + (+range.value === +range.max ? '+' : '');
range.setAttribute('aria-valuetext', shown.textContent + ' people');
form.querySelectorAll('.calc-app input:checked').forEach(function (box) {
count++;
need = Math.max(need, plans.findIndex(function (p) { return p.tier === box.dataset.tier; }));
cost += +box.value * (box.dataset.perSeat === 'true' ? n : 1) * 12;
});
out('count', count);
out('cost', fmt(cost));
var plan = plans[need] || plans[plans.length - 1] || { name: '', annual: 0 };
out('savings', fmt(Math.max(0, cost - plan.annual)));
out('plan', plan.name);
}
form.addEventListener('input', update);
update();
})();
</script>