Skip to content

Commit f412956

Browse files
committed
- add tip calculator
1 parent 3e7b61b commit f412956

File tree

1 file changed

+191
-0
lines changed

1 file changed

+191
-0
lines changed

tools/tip_calculator.html

Lines changed: 191 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,191 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<meta charset="UTF-8">
5+
<meta name="viewport" content="width=device-width, initial-scale=1.0">
6+
<title>Tip Calculator & Bill Splitter</title>
7+
<style>
8+
*{margin:0;padding:0;box-sizing:border-box;}
9+
body{font-family:-apple-system,BlinkMacSystemFont,'Segoe UI',Roboto,Oxygen,Ubuntu,Cantarell,sans-serif;background:#f8fafc;color:#1e293b;padding:20px;min-height:100vh;display:flex;align-items:center;justify-content:center;}
10+
.container{max-width:480px;width:100%;}
11+
.header{text-align:center;margin-bottom:32px;}
12+
.header h1{font-size:32px;font-weight:700;color:#1e293b;margin-bottom:8px;}
13+
.header p{color:#64748b;font-size:14px;}
14+
.card{background:#fff;border-radius:16px;padding:28px;box-shadow:0 1px 3px rgba(0,0,0,0.1);margin-bottom:20px;}
15+
.input-group{margin-bottom:24px;}
16+
.input-group:last-child{margin-bottom:0;}
17+
label{display:block;font-size:14px;font-weight:600;color:#475569;margin-bottom:8px;}
18+
.input-wrapper{position:relative;display:flex;align-items:center;}
19+
.input-wrapper span{position:absolute;left:16px;color:#64748b;font-weight:600;font-size:18px;}
20+
input[type="number"]{width:100%;padding:14px 16px 14px 36px;font-size:18px;border:2px solid #e2e8f0;border-radius:12px;background:#f8fafc;color:#1e293b;font-weight:600;transition:all 0.2s;}
21+
input[type="number"]:focus{outline:none;border-color:#2563eb;background:#fff;}
22+
.tip-buttons{display:grid;grid-template-columns:repeat(3,1fr);gap:10px;margin-bottom:12px;}
23+
.tip-btn{padding:14px;border:2px solid #e2e8f0;background:#f8fafc;border-radius:12px;font-size:16px;font-weight:600;color:#475569;cursor:pointer;transition:all 0.2s;}
24+
.tip-btn:hover{border-color:#cbd5e1;background:#fff;}
25+
.tip-btn.active{background:#2563eb;color:#fff;border-color:#2563eb;}
26+
.custom-tip{display:flex;align-items:center;gap:8px;}
27+
.custom-tip input{padding:14px 16px;font-size:16px;}
28+
.results{background:#f8fafc;border-radius:12px;padding:20px;}
29+
.result-row{display:flex;justify-content:space-between;align-items:center;padding:16px 0;border-bottom:1px solid #e2e8f0;}
30+
.result-row:first-child{padding-top:0;}
31+
.result-row:last-child{border-bottom:none;padding-bottom:0;}
32+
.result-label{font-size:14px;color:#64748b;font-weight:500;}
33+
.result-value{font-size:24px;font-weight:700;color:#1e293b;}
34+
.result-row.highlight .result-value{color:#2563eb;}
35+
.per-person{background:#fff;border-radius:12px;padding:20px;margin-top:16px;border:2px solid #e2e8f0;}
36+
.per-person-header{text-align:center;font-size:14px;color:#64748b;margin-bottom:12px;font-weight:600;}
37+
.per-person-amount{text-align:center;font-size:42px;font-weight:700;color:#2563eb;margin-bottom:4px;}
38+
.per-person-label{text-align:center;font-size:13px;color:#64748b;}
39+
.reset-btn{width:100%;padding:16px;background:#1e293b;color:#fff;border:none;border-radius:12px;font-size:16px;font-weight:600;cursor:pointer;transition:all 0.2s;margin-top:20px;}
40+
.reset-btn:hover{background:#334155;}
41+
.divider{display:flex;align-items:center;gap:12px;margin:12px 0;color:#cbd5e1;font-size:13px;font-weight:600;}
42+
.divider::before,.divider::after{content:'';flex:1;height:1px;background:#e2e8f0;}
43+
@media (max-width:480px){
44+
.container{padding:0;}
45+
.card{border-radius:12px;padding:20px;}
46+
.header h1{font-size:28px;}
47+
.tip-buttons{grid-template-columns:repeat(2,1fr);}
48+
}
49+
</style>
50+
</head>
51+
<body>
52+
<div class="container">
53+
<div class="header">
54+
<h1>💰 Tip Calculator</h1>
55+
<p>Calculate tips and split bills with ease</p>
56+
</div>
57+
<div class="card">
58+
<div class="input-group">
59+
<label for="bill">Bill Amount</label>
60+
<div class="input-wrapper">
61+
<span>$</span>
62+
<input type="number" id="bill" placeholder="0.00" step="0.01" min="0" value="">
63+
</div>
64+
</div>
65+
<div class="input-group">
66+
<label>Select Tip %</label>
67+
<div class="tip-buttons">
68+
<button class="tip-btn" data-tip="10">10%</button>
69+
<button class="tip-btn" data-tip="15">15%</button>
70+
<button class="tip-btn" data-tip="18">18%</button>
71+
<button class="tip-btn" data-tip="20">20%</button>
72+
<button class="tip-btn" data-tip="25">25%</button>
73+
<button class="tip-btn" data-tip="custom">Custom</button>
74+
</div>
75+
<div class="custom-tip" id="customTipWrapper" style="display:none;margin-top:12px;">
76+
<div class="input-wrapper" style="flex:1;">
77+
<span>%</span>
78+
<input type="number" id="customTip" placeholder="0" step="1" min="0" max="100">
79+
</div>
80+
</div>
81+
</div>
82+
<div class="input-group">
83+
<label for="people">Number of People</label>
84+
<div class="input-wrapper">
85+
<span>👥</span>
86+
<input type="number" id="people" placeholder="1" step="1" min="1" value="1">
87+
</div>
88+
</div>
89+
</div>
90+
<div class="card">
91+
<div class="results">
92+
<div class="result-row">
93+
<span class="result-label">Tip Amount</span>
94+
<span class="result-value" id="tipAmount">$0.00</span>
95+
</div>
96+
<div class="result-row highlight">
97+
<span class="result-label">Total Amount</span>
98+
<span class="result-value" id="totalAmount">$0.00</span>
99+
</div>
100+
</div>
101+
<div class="divider">Split Between <span id="peopleCount">1</span> <span id="peopleLabel">Person</span></div>
102+
<div class="per-person">
103+
<div class="per-person-header">AMOUNT PER PERSON</div>
104+
<div class="per-person-amount" id="perPerson">$0.00</div>
105+
<div class="per-person-label">Including tip: <span id="tipPerPerson">$0.00</span></div>
106+
</div>
107+
<button class="reset-btn" id="resetBtn">Reset Calculator</button>
108+
</div>
109+
</div>
110+
<script>
111+
const billInput=document.getElementById('bill');
112+
const customTipInput=document.getElementById('customTip');
113+
const peopleInput=document.getElementById('people');
114+
const tipButtons=document.querySelectorAll('.tip-btn');
115+
const customTipWrapper=document.getElementById('customTipWrapper');
116+
const tipAmountEl=document.getElementById('tipAmount');
117+
const totalAmountEl=document.getElementById('totalAmount');
118+
const perPersonEl=document.getElementById('perPerson');
119+
const tipPerPersonEl=document.getElementById('tipPerPerson');
120+
const peopleCountEl=document.getElementById('peopleCount');
121+
const peopleLabelEl=document.getElementById('peopleLabel');
122+
const resetBtn=document.getElementById('resetBtn');
123+
let selectedTip=15;
124+
let isCustomTip=false;
125+
tipButtons.forEach(btn=>{
126+
if(btn.dataset.tip==='15'){
127+
btn.classList.add('active');
128+
}
129+
});
130+
tipButtons.forEach(btn=>{
131+
btn.addEventListener('click',()=>{
132+
tipButtons.forEach(b=>b.classList.remove('active'));
133+
btn.classList.add('active');
134+
if(btn.dataset.tip==='custom'){
135+
customTipWrapper.style.display='block';
136+
isCustomTip=true;
137+
selectedTip=parseFloat(customTipInput.value)||0;
138+
}else{
139+
customTipWrapper.style.display='none';
140+
isCustomTip=false;
141+
selectedTip=parseFloat(btn.dataset.tip);
142+
}
143+
calculate();
144+
});
145+
});
146+
customTipInput.addEventListener('input',()=>{
147+
selectedTip=parseFloat(customTipInput.value)||0;
148+
if(isCustomTip){
149+
calculate();
150+
}
151+
});
152+
billInput.addEventListener('input',calculate);
153+
peopleInput.addEventListener('input',()=>{
154+
calculate();
155+
updatePeopleLabel();
156+
});
157+
function calculate(){
158+
const bill=parseFloat(billInput.value)||0;
159+
const people=parseInt(peopleInput.value)||1;
160+
const tipPercent=isCustomTip?(parseFloat(customTipInput.value)||0):selectedTip;
161+
const tipAmount=bill*(tipPercent/100);
162+
const total=bill+tipAmount;
163+
const perPerson=total/people;
164+
const tipPerPerson=tipAmount/people;
165+
tipAmountEl.textContent='$'+tipAmount.toFixed(2);
166+
totalAmountEl.textContent='$'+total.toFixed(2);
167+
perPersonEl.textContent='$'+perPerson.toFixed(2);
168+
tipPerPersonEl.textContent='$'+tipPerPerson.toFixed(2);
169+
peopleCountEl.textContent=people;
170+
}
171+
function updatePeopleLabel(){
172+
const people=parseInt(peopleInput.value)||1;
173+
peopleLabelEl.textContent=people===1?'Person':'People';
174+
}
175+
resetBtn.addEventListener('click',()=>{
176+
billInput.value='';
177+
customTipInput.value='';
178+
peopleInput.value='1';
179+
tipButtons.forEach(b=>b.classList.remove('active'));
180+
tipButtons[1].classList.add('active');
181+
customTipWrapper.style.display='none';
182+
isCustomTip=false;
183+
selectedTip=15;
184+
calculate();
185+
updatePeopleLabel();
186+
});
187+
calculate();
188+
</script>
189+
<script src="../logo.js"></script>
190+
</body>
191+
</html>

0 commit comments

Comments
 (0)