Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
90 changes: 77 additions & 13 deletions index.html
Original file line number Diff line number Diff line change
@@ -1,16 +1,80 @@
<html>
<head>
<script src="script.js"></script>
<link rel="stylesheet" href="style.css">
</head>
<body>
<h1>Simple Interest Calculator</h1>
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>Simple Interest Calculator</title>

Amount <input type="number" id="principal"> <br/>
Rate <input type="number" id="rate"> <br/>
No. of Years <input type="number" id="years"> <br/>
Interest : <span id="result"></span><br>
<!-- Styles first -->
<link rel="stylesheet" href="style.css" />

<button onclick="compute()">Compute</button>
</body>
<!-- Script deferred so DOM is ready when it runs -->
<script src="script.js" defer></script>
</head>
<body>
<main class="container" role="main" aria-labelledby="page-title">
<header class="header">
<h1 id="page-title">Simple Interest Calculator</h1>
<div class="header-actions">
<button id="theme-toggle" type="button" aria-pressed="false" aria-label="Toggle light and dark theme">
☀️ Light
</button>
</div>
</header>

<form id="si-form" novalidate>
<div class="row">
<label for="principal">Amount</label>
<input
type="number"
id="principal"
name="principal"
min="0"
step="0.01"
inputmode="decimal"
placeholder="e.g. 1000"
required
/>
</div>

<div class="row">
<label for="rate">Rate (% per year)</label>
<input
type="number"
id="rate"
name="rate"
min="0"
step="0.01"
inputmode="decimal"
placeholder="e.g. 5"
required
/>
</div>

<div class="row">
<label for="years">No. of Years</label>
<input
type="number"
id="years"
name="years"
min="0"
step="0.01"
inputmode="decimal"
placeholder="e.g. 2"
required
/>
</div>

<div class="row result-row" aria-live="polite">
<strong>Interest:</strong>
<span id="result" class="result-value">—</span>
</div>

<div class="buttons">
<button type="submit" id="compute" class="primary">Compute</button>
<button type="button" id="reset" class="ghost">Reset</button>
</div>
</form>
</main>
</body>
</html>
109 changes: 103 additions & 6 deletions script.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,103 @@
function compute()
{
p = document.getElementById("principal").value;

}

// script.js
// Modern, safe code: event-driven, input validation, accessible updates.

document.addEventListener('DOMContentLoaded', () => {
const form = document.getElementById('si-form');
const principalEl = document.getElementById('principal');
const rateEl = document.getElementById('rate');
const yearsEl = document.getElementById('years');
const resultEl = document.getElementById('result');
const resetBtn = document.getElementById('reset');
const themeToggle = document.getElementById('theme-toggle');

// Format numbers to 2 decimal places with locale formatting
function formatAmount(n) {
return Number(n).toLocaleString(undefined, {
minimumFractionDigits: 2,
maximumFractionDigits: 2
});
}

function showError(message) {
resultEl.textContent = message;
resultEl.classList.add('error');
}

function clearError() {
resultEl.classList.remove('error');
}

function compute() {
// parseFloat used to accept decimal input
const p = parseFloat(principalEl.value);
const r = parseFloat(rateEl.value);
const y = parseFloat(yearsEl.value);

// Validate numbers and non-negative
if (Number.isNaN(p) || Number.isNaN(r) || Number.isNaN(y)) {
showError('Please enter numeric values for all fields.');
return;
}
if (p < 0 || r < 0 || y < 0) {
showError('Please enter non-negative values.');
return;
}

clearError();

// Simple interest formula: interest = (p * r * y) / 100
const interest = (p * r * y) / 100;
const total = p + interest;

resultEl.innerHTML = `${formatAmount(interest)} (Interest). Total: ${formatAmount(total)}`;
}

// handle form submit
form.addEventListener('submit', (ev) => {
ev.preventDefault();
compute();
});

// reset handler
resetBtn.addEventListener('click', () => {
form.reset();
resultEl.textContent = '—';
resultEl.classList.remove('error');
});

// make compute available globally in case someone expects window.compute()
window.compute = compute;

/* -----------------------
Theme toggle (light/dark)
- persists selection in localStorage
- respects system preference if no saved choice
----------------------- */
const THEME_KEY = 'si.theme';

function applyTheme(theme) {
document.documentElement.setAttribute('data-theme', theme);
const isDark = theme === 'dark';
themeToggle.setAttribute('aria-pressed', String(isDark));
themeToggle.textContent = isDark ? '🌙 Dark' : '☀️ Light';
localStorage.setItem(THEME_KEY, theme);
}

// Initialize theme
(function initTheme() {
const stored = localStorage.getItem(THEME_KEY);
if (stored === 'dark' || stored === 'light') {
applyTheme(stored);
return;
}
// fallback to system preference
const prefersDark = window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches;
applyTheme(prefersDark ? 'dark' : 'light');
})();

// Toggle handler
themeToggle.addEventListener('click', () => {
const current = document.documentElement.getAttribute('data-theme') === 'dark' ? 'dark' : 'light';
applyTheme(current === 'dark' ? 'light' : 'dark');
});
});
98 changes: 96 additions & 2 deletions style.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,98 @@
body {background-color:tan;}
h1{color:green;}
/* Themeable variables */
:root{
--bg: #f5efe6;
--card: #ffffff;
--accent: #2e8b57;
--accent-600: #237246;
--text: #1f2933;
--muted: #505a63;
--input-bg: #ffffff;
--input-border: #e6e6e6;
--input-text: #1f2933;
--shadow: 0 10px 30px rgba(18, 24, 28, 0.08);
--soft-shadow: 0 6px 18px rgba(18, 24, 28, 0.06);
--btn-radius: 10px;
--focus-ring: rgba(46,139,87,0.18);
--surface: rgba(255,255,255,0.6);
}

[data-theme="dark"]{
--bg: #071021;
--card: #071827;
--accent: #60b38a;
--accent-600: #4aa073;
--text: #e6eef1;
--muted: #9fb3b7;
--input-bg: #071827;
--input-border: #133042;
--input-text: #e6eef1;
--shadow: 0 8px 24px rgba(2, 8, 15, 0.6);
--soft-shadow: 0 6px 18px rgba(2,8,15,0.5);
--focus-ring: rgba(96,179,138,0.18);
--surface: rgba(255,255,255,0.02);
}

/* Reset & base */
* { box-sizing: border-box; }
html,body { height: 100%; margin: 0; font-family: Inter, ui-sans-serif, system-ui; color: var(--text); background: var(--bg); }

body { display: flex; align-items: center; justify-content: center; padding: 2rem; min-height: 100vh; }

.container {
width: 100%;
max-width: 520px;
background: var(--card);
border-radius: 12px;
padding: 1.5rem;
box-shadow: var(--shadow);
}

/* Header */
.header { display:flex; align-items:center; justify-content:space-between; margin-bottom:1rem; }
h1 { margin:0; color: var(--accent-600); font-size:1.25rem; }

/* Theme toggle */
#theme-toggle{
padding:0.35rem 0.6rem;
border-radius:999px;
border:none;
cursor:pointer;
background: var(--surface);
font-weight:600;
color: var(--text); /* <- changed: matches page text for light/dark mode */
transition: transform 120ms ease, box-shadow 160ms ease, opacity 160ms ease;
}
#theme-toggle:active { transform: translateY(1px); }
#theme-toggle:hover { opacity: 0.95; }

/* Form rows */
.row { display:flex; gap:0.8rem; align-items:center; margin-bottom:0.85rem; }
.row label { min-width:130px; font-weight:600; color: var(--muted); font-size:0.95rem; }
.row input[type="number"]{
flex:1; padding:0.65rem 0.75rem; border-radius:10px; border:1px solid var(--input-border);
background: var(--input-bg); color: var(--input-text); outline:none; box-shadow: var(--soft-shadow);
font-size:1rem; transition: all 0.15s ease;
}
.row input:focus { box-shadow: 0 8px 22px var(--focus-ring); border-color: var(--accent-600); }

/* Result row */
.result-row { align-items: baseline; margin-top: 0.25rem; padding-top: 0.5rem; border-top:1px dashed rgba(0,0,0,0.1); }
.result-value { margin-left:0.65rem; font-weight:700; font-size:1rem; }

/* Buttons area */
.buttons { display:flex; gap:0.6rem; margin-top:1.1rem; justify-content:center; }
button { padding:0.55rem 0.95rem; border-radius:var(--btn-radius); border:none; font-weight:700; font-size:0.95rem; cursor:pointer; transition: all 0.12s ease; }
button:active { transform: translateY(1px); }
button.primary { background: linear-gradient(180deg, var(--accent), var(--accent-600)); color:white; }
button.ghost { background:transparent; border:1px solid rgba(0,0,0,0.1); color: var(--muted); }

/* Error styling */
.result-value.error { color:#b00020; }

/* Responsive */
@media (max-width: 420px){
.row { flex-direction: column; align-items: stretch; }
.row label { min-width: 0; }
.header { gap: 0.5rem; }
.container { padding: 1rem; border-radius: 10px; }
}