diff --git a/nginx.conf b/nginx.conf index b16a6fd..4caf7d6 100644 --- a/nginx.conf +++ b/nginx.conf @@ -9,6 +9,10 @@ server { return 302 "https://events.neeldhara.com/?year=$1#events"; } + location = /gh-cost-estimator { + return 301 "https://events.neeldhara.com/gh-cost-estimator/"; + } + location / { try_files $uri $uri/ =404; } diff --git a/src/pages/gh-cost-estimator.astro b/src/pages/gh-cost-estimator.astro index c18a63c..a0db606 100644 --- a/src/pages/gh-cost-estimator.astro +++ b/src/pages/gh-cost-estimator.astro @@ -22,8 +22,14 @@ const currency = new Intl.NumberFormat("en-IN", {
-

Utility

-

Basic Calculator

+

Utility

+

+ Basic Calculator + Guest House Cost Estimate +

+
+ + + + + Double Occupancy + + + + + + Lunch + + + + + + Dinner + + + @@ -176,6 +210,7 @@ const currency = new Intl.NumberFormat("en-IN", { const totalCost = document.querySelector("[data-total-cost]"); const totalNote = document.querySelector("[data-total-note]"); const printButton = document.querySelector("[data-print-estimate]"); + const columnToggleButtons = Array.from(document.querySelectorAll("[data-toggle-column]")); function getPeopleCount() { return Number(peopleInput?.value ?? 1); @@ -199,6 +234,36 @@ const currency = new Intl.NumberFormat("en-IN", { if (totalNote) totalNote.textContent = `For ${peopleCount} ${peopleCount === 1 ? "person" : "people"}.`; } + function getVisibleRows() { + return rows.filter((row) => !row.hidden); + } + + function getColumnInputs(cost: keyof typeof rateMap) { + return getVisibleRows() + .map((row) => row.querySelector(`input[data-cost='${cost}']`)) + .filter((input): input is HTMLInputElement => Boolean(input)); + } + + function syncColumnToggles() { + columnToggleButtons.forEach((button) => { + const cost = button.dataset.toggleColumn as keyof typeof rateMap | undefined; + if (!cost) return; + + const inputs = getColumnInputs(cost); + const allChecked = inputs.length > 0 && inputs.every((input) => input.checked); + button.setAttribute("aria-pressed", allChecked ? "true" : "false"); + }); + } + + function syncPrintValues() { + rows.forEach((row) => { + row.querySelectorAll(".check-cell").forEach((label) => { + const input = label.querySelector("input[type='checkbox']"); + label.dataset.printValue = input?.checked ? "Yes" : "No"; + }); + }); + } + function updateTotal() { let total = 0; @@ -212,6 +277,8 @@ const currency = new Intl.NumberFormat("en-IN", { }); if (totalCost) totalCost.textContent = currencyFormatter.format(total); + syncColumnToggles(); + syncPrintValues(); } peopleInput?.addEventListener("input", () => { @@ -234,7 +301,32 @@ const currency = new Intl.NumberFormat("en-IN", { }); }); + columnToggleButtons.forEach((button) => { + button.addEventListener("click", () => { + const cost = button.dataset.toggleColumn as keyof typeof rateMap | undefined; + if (!cost) return; + + const inputs = getColumnInputs(cost); + const shouldCheck = !inputs.every((input) => input.checked); + + inputs.forEach((input) => { + const row = input.closest("[data-estimate-row]"); + + if (shouldCheck && (cost === "single" || cost === "double")) { + row?.querySelectorAll("[data-accommodation]").forEach((accommodationInput) => { + if (accommodationInput !== input) accommodationInput.checked = false; + }); + } + + input.checked = shouldCheck; + }); + + updateTotal(); + }); + }); + printButton?.addEventListener("click", () => { + syncPrintValues(); window.print(); }); @@ -261,6 +353,10 @@ const currency = new Intl.NumberFormat("en-IN", { font-size: clamp(2.2rem, 5vw, 3.4rem); } + .print-only { + display: none; + } + .calculator-shell { display: grid; gap: 1rem; @@ -371,6 +467,34 @@ const currency = new Intl.NumberFormat("en-IN", { white-space: nowrap; } + .column-heading { + display: grid; + gap: 0.36rem; + align-items: start; + } + + .column-heading button { + width: fit-content; + min-height: 32px; + border: 0; + border-radius: 999px; + background: var(--card); + color: color-mix(in oklch, var(--foreground) 70%, var(--muted)); + cursor: pointer; + font: inherit; + font-size: 0.72rem; + font-weight: 700; + line-height: 1; + padding: 0.35rem 0.58rem; + box-shadow: 0 0 0 1px var(--border); + } + + .column-heading button[aria-pressed="true"] { + background: color-mix(in oklch, var(--primary) 11%, white); + color: var(--foreground); + box-shadow: 0 0 0 1px color-mix(in oklch, var(--primary) 24%, var(--border)); + } + .calculator-table td { padding: 0.6rem 0.7rem; vertical-align: middle; @@ -481,6 +605,10 @@ const currency = new Intl.NumberFormat("en-IN", { } @media print { + @page { + margin: 16mm 14mm; + } + .site-header, .site-footer, .print-button, @@ -488,8 +616,20 @@ const currency = new Intl.NumberFormat("en-IN", { display: none !important; } + .screen-only, + .screen-title { + display: none !important; + } + + .print-only { + display: block; + } + body { background: #fff !important; + color: #151812; + font-size: 11pt; + line-height: 1.35; } .calculator-page { @@ -497,47 +637,175 @@ const currency = new Intl.NumberFormat("en-IN", { padding: 0; } + .calculator-heading { + display: block; + margin-bottom: 0.5rem; + border-bottom: 1px solid #20231d; + padding-bottom: 0.45rem; + } + + .calculator-heading h1 { + color: #151812; + font-size: 24pt; + line-height: 1; + } + + .print-report-note { + margin-top: 0.35rem; + color: #50554c; + font-size: 9.5pt; + } + .calculator-panel { + border-radius: 0; box-shadow: none; - padding: 0.5rem 0; + padding: 0.35rem 0; } .calculator-shell { - gap: 0.45rem; + gap: 0.25rem; + } + + .people-control, + .table-head { + margin-bottom: 0.35rem; + } + + .people-control h2, + .table-head h2 { + color: #151812; + font-size: 14pt; + } + + .people-control p, + .table-head p, + .total-bar p { + color: #50554c; + font-size: 9pt; + } + + .people-count { + min-width: 0; + background: transparent; + box-shadow: none; + color: #151812; + font-family: var(--font-body); + font-size: 12pt; + font-weight: 700; + padding: 0; } .rate-grid { grid-template-columns: repeat(4, minmax(0, 1fr)); + gap: 0; + margin-top: 0.45rem; + border: 1px solid #d6d8d1; + border-right: 0; + } + + .rate-grid div { + border-radius: 0; + background: #fff; + box-shadow: none; + border-right: 1px solid #d6d8d1; + padding: 0.35rem 0.45rem; + } + + .rate-grid dt { + color: #50554c; + font-size: 8pt; + } + + .rate-grid dd { + color: #151812; + font-size: 10.5pt; } .calculator-table-wrap { overflow: visible; - box-shadow: 0 0 0 1px #ddd; + border-radius: 0; + box-shadow: none; } .calculator-table { min-width: 0; + border: 1px solid #d6d8d1; + border-bottom: 0; } .calculator-table th, .calculator-table td { - padding: 0.35rem 0.4rem; + border-bottom: 1px solid #d6d8d1; + padding: 0.26rem 0.34rem; + } + + .calculator-table th { + background: #f4f2ec; + color: #30342d; + font-size: 8pt; + } + + .column-heading { + display: block; + } + + .column-heading button { + display: none; } .check-cell span { display: none; } + .check-cell { + display: flex; + min-height: 0; + justify-content: center; + color: #151812; + font-size: 9pt; + font-weight: 400; + } + + .check-cell input { + display: none; + } + + .check-cell::after { + content: attr(data-print-value); + } + .name-input { min-height: 0; box-shadow: none; background: transparent; + color: #151812; + font-size: 9pt; padding: 0; } .total-bar { + display: block; + margin-top: 0.5rem; + border-radius: 0; + background: #f8f6ef; box-shadow: none; - border: 1px solid #ddd; + border: 1px solid #d6d8d1; + padding: 0.45rem 0.55rem; + text-align: right; + } + + .total-bar span { + color: #50554c; + font-size: 8pt; + } + + .total-bar strong { + color: #151812; + font-size: 20pt; + } + + tr { + break-inside: avoid; } }