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