summary history files

commute/index.html
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Commute Calculator</title>
  <style>
* {
  box-sizing: border-box;
}

body {
  font-family: Helvetica, Arial, sans-serif;
  line-height: 1.6;
  max-width: 800px;
  margin: 0 auto;
  padding: 20px;
  background-color: #f5f5f5;
  color: #333;
}

h1 {
  margin-bottom: 8px;
}

.subtitle {
  color: #666;
  margin-bottom: 24px;
}

.card {
  background: white;
  padding: 24px;
  border-radius: 8px;
  box-shadow: 0 2px 4px rgba(0,0,0,0.1);
  margin-bottom: 20px;
}

.mode-toggle {
  display: flex;
  gap: 8px;
  margin-bottom: 24px;
  flex-wrap: wrap;
}

.mode-btn {
  flex: 1;
  min-width: 100px;
  padding: 12px;
  border: 2px solid #ddd;
  background: white;
  cursor: pointer;
  border-radius: 6px;
  font-size: 14px;
  font-weight: 500;
  transition: all 0.2s;
}

.mode-btn.active {
  border-color: #0066cc;
  background: #0066cc;
  color: white;
}

.pt-type-toggle {
  display: flex;
  gap: 8px;
  margin-bottom: 20px;
}

.pt-type-btn {
  flex: 1;
  padding: 10px;
  border: 2px solid #e0e0e0;
  background: white;
  cursor: pointer;
  border-radius: 6px;
  font-size: 14px;
  transition: all 0.2s;
}

.pt-type-btn.active {
  border-color: #4a90d9;
  color: #4a90d9;
  background: #f0f7ff;
}

.input-group {
  margin-bottom: 16px;
}

label {
  display: block;
  margin-bottom: 6px;
  font-weight: 500;
  font-size: 14px;
}

input, select {
  width: 100%;
  padding: 12px;
  border: 1px solid #ddd;
  border-radius: 6px;
  font-size: 16px;
  font-family: Helvetica, Arial, sans-serif;
}

input:focus, select:focus {
  outline: none;
  border-color: #0066cc;
}

.row {
  display: grid;
  grid-template-columns: 1fr 1fr;
  gap: 16px;
}

.cost-period {
  display: grid;
  grid-template-columns: 1fr auto;
  gap: 8px;
  align-items: end;
}

.cost-period select {
  width: 110px;
}

.section-title {
  font-size: 16px;
  font-weight: 600;
  margin-bottom: 16px;
  padding-bottom: 8px;
  border-bottom: 2px solid #f0f0f0;
  color: #555;
}

.chart-container {
  display: flex;
  align-items: center;
  justify-content: center;
  gap: 40px;
  flex-wrap: wrap;
  margin-top: 20px;
}

.chart-svg {
  width: 200px;
  height: 200px;
}

.chart-legend {
  display: flex;
  flex-direction: column;
  gap: 12px;
}

.legend-item {
  display: flex;
  align-items: center;
  gap: 10px;
  font-size: 14px;
}

.legend-color {
  width: 16px;
  height: 16px;
  border-radius: 4px;
}

.legend-value {
  font-weight: 600;
  margin-left: auto;
  padding-left: 20px;
}

.results {
  background: #f8f9fa;
  border-left: 4px solid #0066cc;
}

.result-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
  gap: 16px;
  margin-top: 16px;
}

.result-item {
  text-align: center;
}

.result-value {
  font-size: 26px;
  font-weight: bold;
  color: #0066cc;
  margin-bottom: 4px;
}

.result-label {
  font-size: 12px;
  color: #666;
}

.hidden {
  display: none;
}

.pt-costs {
  display: grid;
  gap: 12px;
}

@media (max-width: 600px) {
  body {
    padding: 12px;
  }

  .card {
    padding: 16px;
  }

  .row {
    grid-template-columns: 1fr;
  }

  .cost-period {
    grid-template-columns: 1fr;
  }

  .cost-period select {
    width: 100%;
  }

  .mode-btn {
    font-size: 13px;
    padding: 10px;
  }

  .result-value {
    font-size: 22px;
  }

  .chart-container {
    gap: 20px;
  }

  .chart-svg {
    width: 160px;
    height: 160px;
  }
}
  </style>
</head>
<body>
  <h1>Commute Calculator</h1>
  <p class="subtitle">Calculate the true cost and time of your daily commute</p>

  <div class="card">
    <div class="mode-toggle">
      <button class="mode-btn active" data-mode="public">Public Transport</button>
      <button class="mode-btn" data-mode="driving">Driving</button>
      <button class="mode-btn" data-mode="mixed">PT + Driving</button>
    </div>

    <div class="row">
      <div class="input-group">
        <label for="daysPerWeek">Days per week</label>
        <input type="number" id="daysPerWeek" min="1" max="7" step="1" value="5">
      </div>
      <div class="input-group">
        <label for="weeksPerYear">Weeks per year</label>
        <input type="number" id="weeksPerYear" min="1" max="52" step="1" value="48">
      </div>
    </div>
  </div>

  <div id="publicSection" class="card transport-section">
    <div class="section-title">Public Transport Details</div>

    <div class="pt-type-toggle">
      <button class="pt-type-btn active" data-pttype="bus">Bus</button>
      <button class="pt-type-btn" data-pttype="train">Train</button>
      <button class="pt-type-btn" data-pttype="mixed">Bus + Train</button>
    </div>

    <div class="input-group">
      <label for="ptTime">One-way PT commute time (minutes)</label>
      <input type="number" id="ptTime" min="0" step="1" placeholder="30">
    </div>

    <div id="ptCostSingle" class="pt-costs">
      <div class="input-group cost-period">
        <div>
          <label for="ptCost">Ticket cost</label>
          <input type="number" id="ptCost" min="0" step="0.01" placeholder="0.00">
        </div>
        <div>
          <label for="ptCostPeriod">Period</label>
          <select id="ptCostPeriod">
            <option value="day">Daily</option>
            <option value="week">Weekly</option>
            <option value="month">Monthly</option>
            <option value="year">Yearly</option>
          </select>
        </div>
      </div>
    </div>

    <div id="ptCostDouble" class="pt-costs hidden">
      <div class="row">
        <div class="input-group cost-period">
          <div>
            <label for="busCost">Bus ticket cost</label>
            <input type="number" id="busCost" min="0" step="0.01" placeholder="0.00">
          </div>
          <div>
            <label for="busCostPeriod">Period</label>
            <select id="busCostPeriod">
              <option value="day">Daily</option>
              <option value="week">Weekly</option>
              <option value="month">Monthly</option>
              <option value="year">Yearly</option>
            </select>
          </div>
        </div>
        <div class="input-group cost-period">
          <div>
            <label for="trainCost">Train ticket cost</label>
            <input type="number" id="trainCost" min="0" step="0.01" placeholder="0.00">
          </div>
          <div>
            <label for="trainCostPeriod">Period</label>
            <select id="trainCostPeriod">
              <option value="day">Daily</option>
              <option value="week">Weekly</option>
              <option value="month">Monthly</option>
              <option value="year">Yearly</option>
            </select>
          </div>
        </div>
      </div>
    </div>
  </div>

  <div id="drivingSection" class="card transport-section hidden">
    <div class="section-title">Driving Details</div>

    <div class="input-group">
      <label for="driveTime">One-way driving time (minutes)</label>
      <input type="number" id="driveTime" min="0" step="1" placeholder="25">
    </div>
    <div class="input-group">
      <label for="parkingCost">Parking cost per day ($)</label>
      <input type="number" id="parkingCost" min="0" step="0.01" placeholder="0.00">
    </div>
  </div>

  <div class="card">
    <div class="section-title">Time in a Year</div>
    <div class="chart-container">
      <svg class="chart-svg" viewBox="0 0 200 200">
        <circle cx="100" cy="100" r="80" fill="none" stroke="#e0e0e0" stroke-width="20"/>
        <circle id="commuteArc" cx="100" cy="100" r="80" fill="none" stroke="#0066cc" stroke-width="20" 
                stroke-dasharray="0 502" stroke-linecap="round" transform="rotate(-90 100 100)"/>
        <text x="100" y="95" text-anchor="middle" font-size="14" font-weight="bold" fill="#333" id="percentText">0%</text>
        <text x="100" y="115" text-anchor="middle" font-size="10" fill="#666">commuting</text>
      </svg>
      <div class="chart-legend">
        <div class="legend-item">
          <div class="legend-color" style="background: #0066cc;"></div>
          <span>Commute Hours</span>
          <span class="legend-value" id="commuteLegend">0</span>
        </div>
        <div class="legend-item">
          <div class="legend-color" style="background: #e0e0e0;"></div>
          <span>Other Hours</span>
          <span class="legend-value" id="otherLegend">8,760</span>
        </div>
      </div>
    </div>
  </div>

  <div class="card results">
    <h2>Annual Impact</h2>
    <div class="result-grid">
      <div class="result-item">
        <div class="result-value" id="annualHours">0</div>
        <div class="result-label">Hours commuting</div>
      </div>
      <div class="result-item">
        <div class="result-value" id="workDays">0</div>
        <div class="result-label">8-hour work days</div>
      </div>
      <div class="result-item">
        <div class="result-value" id="annualCost">$0</div>
        <div class="result-label">Total annual cost</div>
      </div>
      <div class="result-item">
        <div class="result-value" id="costPerHour">$0</div>
        <div class="result-label">Cost per hour</div>
      </div>
    </div>
  </div>

  <script type="module">
const elements = {
  modeButtons: document.querySelectorAll('.mode-btn'),
  ptTypeButtons: document.querySelectorAll('.pt-type-btn'),
  publicSection: document.getElementById('publicSection'),
  drivingSection: document.getElementById('drivingSection'),
  ptCostSingle: document.getElementById('ptCostSingle'),
  ptCostDouble: document.getElementById('ptCostDouble'),
  daysPerWeek: document.getElementById('daysPerWeek'),
  weeksPerYear: document.getElementById('weeksPerYear'),
  ptTime: document.getElementById('ptTime'),
  ptCost: document.getElementById('ptCost'),
  ptCostPeriod: document.getElementById('ptCostPeriod'),
  busCost: document.getElementById('busCost'),
  busCostPeriod: document.getElementById('busCostPeriod'),
  trainCost: document.getElementById('trainCost'),
  trainCostPeriod: document.getElementById('trainCostPeriod'),
  driveTime: document.getElementById('driveTime'),
  parkingCost: document.getElementById('parkingCost'),
  annualHours: document.getElementById('annualHours'),
  workDays: document.getElementById('workDays'),
  annualCost: document.getElementById('annualCost'),
  costPerHour: document.getElementById('costPerHour'),
  commuteArc: document.getElementById('commuteArc'),
  percentText: document.getElementById('percentText'),
  commuteLegend: document.getElementById('commuteLegend'),
  otherLegend: document.getElementById('otherLegend')
};

const HOURS_IN_YEAR = 8760;
const ARC_LENGTH = 502;

let currentMode = 'public';
let currentPtType = 'bus';

function formatCurrency(value) {
  return '$' + Math.round(value).toLocaleString();
}

function calculateAnnualCost(cost, period) {
  const days = parseFloat(elements.daysPerWeek.value) || 0;
  const weeks = parseFloat(elements.weeksPerYear.value) || 0;

  switch(period) {
    case 'day':
      return cost * days * weeks;
    case 'week':
      return cost * weeks;
    case 'month':
      return cost * 12;
    case 'year':
      return cost;
    default:
      return 0;
  }
}

function updateChart(commuteHours) {
  const percentage = Math.min(commuteHours / HOURS_IN_YEAR, 1);
  const dashArray = percentage * ARC_LENGTH;
  const remaining = ARC_LENGTH - dashArray;

  elements.commuteArc.setAttribute('stroke-dasharray', `${dashArray} ${remaining}`);
  elements.percentText.textContent = (percentage * 100).toFixed(1) + '%';
  elements.commuteLegend.textContent = Math.round(commuteHours).toLocaleString();
  elements.otherLegend.textContent = Math.round(HOURS_IN_YEAR - commuteHours).toLocaleString();
}

function calculate() {
  const days = parseFloat(elements.daysPerWeek.value) || 0;
  const weeks = parseFloat(elements.weeksPerYear.value) || 0;
  const annualTrips = days * weeks;

  let oneWayTime = 0;
  let annualCost = 0;

  if (currentMode === 'public') {
    oneWayTime = parseFloat(elements.ptTime.value) || 0;

    if (currentPtType === 'mixed') {
      const bus = calculateAnnualCost(
        parseFloat(elements.busCost.value) || 0,
        elements.busCostPeriod.value
      );
      const train = calculateAnnualCost(
        parseFloat(elements.trainCost.value) || 0,
        elements.trainCostPeriod.value
      );
      annualCost = bus + train;
    } else {
      annualCost = calculateAnnualCost(
        parseFloat(elements.ptCost.value) || 0,
        elements.ptCostPeriod.value
      );
    }
  } else if (currentMode === 'driving') {
    oneWayTime = parseFloat(elements.driveTime.value) || 0;
    const parking = (parseFloat(elements.parkingCost.value) || 0) * days * weeks;
    annualCost = parking;
  } else if (currentMode === 'mixed') {
    const ptTime = parseFloat(elements.ptTime.value) || 0;
    const driveTimeVal = parseFloat(elements.driveTime.value) || 0;
    oneWayTime = ptTime + driveTimeVal;

    let ptAnnual = 0;
    if (currentPtType === 'mixed') {
      const bus = calculateAnnualCost(
        parseFloat(elements.busCost.value) || 0,
        elements.busCostPeriod.value
      );
      const train = calculateAnnualCost(
        parseFloat(elements.trainCost.value) || 0,
        elements.trainCostPeriod.value
      );
      ptAnnual = bus + train;
    } else {
      ptAnnual = calculateAnnualCost(
        parseFloat(elements.ptCost.value) || 0,
        elements.ptCostPeriod.value
      );
    }

    const parking = (parseFloat(elements.parkingCost.value) || 0) * days * weeks;
    annualCost = ptAnnual + parking;
  }

  const roundTripHours = (oneWayTime * 2) / 60;
  const totalHours = roundTripHours * annualTrips;
  const workDays = totalHours / 8;
  const costPerHour = totalHours > 0 ? annualCost / totalHours : 0;

  elements.annualHours.textContent = Math.round(totalHours).toLocaleString();
  elements.workDays.textContent = workDays.toFixed(1);
  elements.annualCost.textContent = formatCurrency(annualCost);
  elements.costPerHour.textContent = formatCurrency(costPerHour);

  updateChart(totalHours);
}

function updateVisibility() {
  elements.modeButtons.forEach(btn => {
    btn.classList.toggle('active', btn.dataset.mode === currentMode);
  });

  elements.ptTypeButtons.forEach(btn => {
    btn.classList.toggle('active', btn.dataset.pttype === currentPtType);
  });

  if (currentMode === 'public') {
    elements.publicSection.classList.remove('hidden');
    elements.drivingSection.classList.add('hidden');
  } else if (currentMode === 'driving') {
    elements.publicSection.classList.add('hidden');
    elements.drivingSection.classList.remove('hidden');
  } else {
    elements.publicSection.classList.remove('hidden');
    elements.drivingSection.classList.remove('hidden');
  }

  if (currentPtType === 'mixed') {
    elements.ptCostSingle.classList.add('hidden');
    elements.ptCostDouble.classList.remove('hidden');
  } else {
    elements.ptCostSingle.classList.remove('hidden');
    elements.ptCostDouble.classList.add('hidden');
  }

  calculate();
}

elements.modeButtons.forEach(btn => {
  btn.addEventListener('click', () => {
    currentMode = btn.dataset.mode;
    updateVisibility();
  });
});

elements.ptTypeButtons.forEach(btn => {
  btn.addEventListener('click', () => {
    currentPtType = btn.dataset.pttype;
    updateVisibility();
  });
});

const inputs = [
  elements.daysPerWeek,
  elements.weeksPerYear,
  elements.ptTime,
  elements.ptCost,
  elements.ptCostPeriod,
  elements.busCost,
  elements.busCostPeriod,
  elements.trainCost,
  elements.trainCostPeriod,
  elements.driveTime,
  elements.parkingCost
];

inputs.forEach(input => {
  if (input) input.addEventListener('input', calculate);
});

updateVisibility();
  </script>
</body>
</html>