Digiator commited on
Commit
8e146cf
·
verified ·
1 Parent(s): 61a3add

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +345 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Spend Planner
3
- emoji: 🌖
4
- colorFrom: yellow
5
- colorTo: green
6
  sdk: static
7
  pinned: false
 
 
8
  ---
9
 
10
- Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
 
1
  ---
2
+ title: spend-planner
3
+ emoji: 🐳
4
+ colorFrom: blue
5
+ colorTo: blue
6
  sdk: static
7
  pinned: false
8
+ tags:
9
+ - deepsite
10
  ---
11
 
12
+ Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
index.html CHANGED
@@ -1,19 +1,345 @@
1
- <!doctype html>
2
- <html>
3
- <head>
4
- <meta charset="utf-8" />
5
- <meta name="viewport" content="width=device-width" />
6
- <title>My static Space</title>
7
- <link rel="stylesheet" href="style.css" />
8
- </head>
9
- <body>
10
- <div class="card">
11
- <h1>Welcome to your static Space!</h1>
12
- <p>You can modify this app directly by editing <i>index.html</i> in the Files and versions tab.</p>
13
- <p>
14
- Also don't forget to check the
15
- <a href="https://huggingface.co/docs/hub/spaces" target="_blank">Spaces documentation</a>.
16
- </p>
17
- </div>
18
- </body>
19
- </html>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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>Smart Spend Planner</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
9
+ <script>
10
+ tailwind.config = {
11
+ theme: {
12
+ extend: {
13
+ animation: {
14
+ 'fade-in': 'fadeIn 0.3s ease-in-out',
15
+ },
16
+ keyframes: {
17
+ fadeIn: {
18
+ 'from': { opacity: '0', transform: 'translateY(10px)' },
19
+ 'to': { opacity: '1', transform: 'translateY(0)' },
20
+ }
21
+ }
22
+ }
23
+ }
24
+ }
25
+ </script>
26
+ <style type="text/tailwindcss">
27
+ @layer base {
28
+ input[type="number"]::-webkit-inner-spin-button,
29
+ input[type="number"]::-webkit-outer-spin-button {
30
+ -webkit-appearance: none;
31
+ margin: 0;
32
+ }
33
+ }
34
+ @layer components {
35
+ .currency-selector {
36
+ background-image: url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3e%3cpath stroke='%236b7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3e%3c/svg%3e");
37
+ background-position: right 0.5rem center;
38
+ background-repeat: no-repeat;
39
+ background-size: 1.5em 1.5em;
40
+ padding-right: 2.5rem;
41
+ }
42
+ }
43
+ </style>
44
+ </head>
45
+ <body class="bg-gray-50 min-h-screen">
46
+ <div class="container mx-auto px-4 py-8 max-w-3xl">
47
+ <div class="text-center mb-6 sm:mb-10">
48
+ <h1 class="text-2xl sm:text-3xl font-bold text-indigo-700 mb-1 sm:mb-2">Smart Spend Planner</h1>
49
+ <p class="text-sm sm:text-base text-gray-600">Track your expenses and manage your budget</p>
50
+ </div>
51
+
52
+ <!-- Salary Input Section -->
53
+ <div class="bg-white rounded-lg sm:rounded-xl shadow-sm sm:shadow-md p-4 sm:p-6 mb-4 sm:mb-6">
54
+ <h2 class="text-lg sm:text-xl font-semibold text-gray-800 mb-3 sm:mb-4">Your Salary</h2>
55
+ <div class="flex flex-col sm:flex-row items-stretch gap-3 sm:gap-4">
56
+ <div class="flex-1 min-w-0">
57
+ <select id="currencyPicker" class="currency-selector w-full border-b-2 border-gray-300 py-1 sm:py-2 px-1 focus:border-indigo-500 focus:outline-none text-base sm:text-lg bg-no-repeat">
58
+ <option value="$">USD ($)</option>
59
+ <option value="€">EUR (€)</option>
60
+ <option value="£">GBP (£)</option>
61
+ <option value="£">EGP (£)</option>
62
+ <option value="₹">INR (₹)</option>
63
+ </select>
64
+ </div>
65
+ <div class="flex-1 min-w-0 flex items-center">
66
+ <span id="currencySymbol" class="mr-2 text-gray-700 text-base sm:text-lg">$</span>
67
+ <input type="number" id="salaryInput" placeholder="Enter salary"
68
+ class="w-full border-b-2 border-gray-300 py-1 sm:py-2 px-1 focus:border-indigo-500 focus:outline-none text-base sm:text-lg">
69
+ </div>
70
+ <button id="setSalaryBtn" class="bg-indigo-600 text-white px-3 sm:px-6 py-2 sm:py-3 rounded-md sm:rounded-lg hover:bg-indigo-700 transition whitespace-nowrap text-sm sm:text-base">
71
+ Set Salary
72
+ </button>
73
+ </div>
74
+ </div>
75
+
76
+ <!-- Budget Summary -->
77
+ <div id="summarySection" class="hidden bg-white rounded-lg sm:rounded-xl shadow-sm sm:shadow-md p-4 sm:p-6 mb-4 sm:mb-6">
78
+ <div class="grid grid-cols-1 sm:grid-cols-3 gap-2 sm:gap-4">
79
+ <div class="bg-indigo-50 p-2 sm:p-4 rounded-lg">
80
+ <p class="text-xs sm:text-sm text-indigo-600 font-medium">Total Salary</p>
81
+ <p id="totalSalary" class="text-xl sm:text-2xl font-bold text-indigo-800 truncate">$0</p>
82
+ </div>
83
+ <div class="bg-red-50 p-2 sm:p-4 rounded-lg">
84
+ <p class="text-xs sm:text-sm text-red-600 font-medium">Total Expenses</p>
85
+ <p id="totalExpenses" class="text-xl sm:text-2xl font-bold text-red-800 truncate">$0</p>
86
+ </div>
87
+ <div class="bg-green-50 p-2 sm:p-4 rounded-lg">
88
+ <p class="text-xs sm:text-sm text-green-600 font-medium">Remaining</p>
89
+ <p id="remainingSalary" class="text-xl sm:text-2xl font-bold text-green-800 truncate">$0</p>
90
+ </div>
91
+ </div>
92
+ </div>
93
+
94
+ <!-- Expense Categories -->
95
+ <div id="expensesSection" class="hidden bg-white rounded-lg sm:rounded-xl shadow-sm sm:shadow-md p-4 sm:p-6 mb-4 sm:mb-6">
96
+ <div class="flex justify-between items-center mb-3 sm:mb-4">
97
+ <h2 class="text-lg sm:text-xl font-semibold text-gray-800">Your Expenses</h2>
98
+ <button id="addCategoryBtn" class="text-indigo-600 hover:text-indigo-800 flex items-center text-sm sm:text-base">
99
+ <i class="fas fa-plus-circle mr-1 text-xs sm:text-sm"></i> Add
100
+ </button>
101
+ </div>
102
+
103
+ <div id="expensesList" class="space-y-3 sm:space-y-4">
104
+ <!-- Default categories -->
105
+ <div class="expense-item animate-fade-in">
106
+ <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-2 sm:gap-0">
107
+ <div class="flex items-center sm:w-2/5">
108
+ <i class="fas fa-pills text-purple-500 mr-2 text-sm sm:text-base"></i>
109
+ <span class="text-gray-700 text-sm sm:text-base">Vitamins</span>
110
+ </div>
111
+ <div class="flex items-center sm:w-3/5">
112
+ <span class="expense-currency mr-2 text-gray-700 text-sm sm:text-base">$</span>
113
+ <input type="number" placeholder="Amount"
114
+ class="expense-input flex-1 border-b-2 border-gray-300 py-1 px-1 focus:border-indigo-500 focus:outline-none text-sm sm:text-base">
115
+ <button class="delete-btn ml-2 sm:ml-3 text-red-500 hover:text-red-700 text-sm sm:text-base">
116
+ <i class="fas fa-trash"></i>
117
+ </button>
118
+ </div>
119
+ </div>
120
+ </div>
121
+
122
+ <div class="expense-item animate-fade-in">
123
+ <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-2 sm:gap-0">
124
+ <div class="flex items-center sm:w-2/5">
125
+ <i class="fas fa-dumbbell text-blue-500 mr-2 text-sm sm:text-base"></i>
126
+ <span class="text-gray-700 text-sm sm:text-base">Sports</span>
127
+ </div>
128
+ <div class="flex items-center sm:w-3/5">
129
+ <span class="expense-currency mr-2 text-gray-700 text-sm sm:text-base">$</span>
130
+ <input type="number" placeholder="Amount"
131
+ class="expense-input flex-1 border-b-2 border-gray-300 py-1 px-1 focus:border-indigo-500 focus:outline-none text-sm sm:text-base">
132
+ <button class="delete-btn ml-2 sm:ml-3 text-red-500 hover:text-red-700 text-sm sm:text-base">
133
+ <i class="fas fa-trash"></i>
134
+ </button>
135
+ </div>
136
+ </div>
137
+ </div>
138
+
139
+ <div class="expense-item animate-fade-in">
140
+ <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-2 sm:gap-0">
141
+ <div class="flex items-center sm:w-2/5">
142
+ <i class="fas fa-utensils text-orange-500 mr-2 text-sm sm:text-base"></i>
143
+ <span class="text-gray-700 text-sm sm:text-base">Food</span>
144
+ </div>
145
+ <div class="flex items-center sm:w-3/5">
146
+ <span class="expense-currency mr-2 text-gray-700 text-sm sm:text-base">$</span>
147
+ <input type="number" placeholder="Amount"
148
+ class="expense-input flex-1 border-b-2 border-gray-300 py-1 px-1 focus:border-indigo-500 focus:outline-none text-sm sm:text-base">
149
+ <button class="delete-btn ml-2 sm:ml-3 text-red-500 hover:text-red-700 text-sm sm:text-base">
150
+ <i class="fas fa-trash"></i>
151
+ </button>
152
+ </div>
153
+ </div>
154
+ </div>
155
+ </div>
156
+ </div>
157
+
158
+ <!-- Add Custom Category Modal -->
159
+ <div id="addCategoryModal" class="hidden fixed inset-0 bg-black bg-opacity-50 flex items-center justify-center z-50 p-4">
160
+ <div class="bg-white rounded-lg sm:rounded-xl p-4 sm:p-6 w-full max-w-md">
161
+ <h3 class="text-lg sm:text-xl font-semibold text-gray-800 mb-3 sm:mb-4">Add New Category</h3>
162
+ <div class="mb-3 sm:mb-4">
163
+ <label class="block text-gray-700 mb-1 sm:mb-2 text-sm sm:text-base">Category Name</label>
164
+ <input type="text" id="newCategoryName"
165
+ class="w-full border-2 border-gray-300 rounded-lg px-3 sm:px-4 py-1 sm:py-2 focus:border-indigo-500 focus:outline-none text-sm sm:text-base">
166
+ </div>
167
+ <div class="mb-4 sm:mb-5">
168
+ <label class="block text-gray-700 mb-1 sm:mb-2 text-sm sm:text-base">Icon</label>
169
+ <select id="newCategoryIcon" class="w-full border-2 border-gray-300 rounded-lg px-3 sm:px-4 py-1 sm:py-2 focus:border-indigo-500 focus:outline-none text-sm sm:text-base">
170
+ <option value="fa-shopping-bag">Shopping</option>
171
+ <option value="fa-car">Transport</option>
172
+ <option value="fa-home">Housing</option>
173
+ <option value="fa-heart">Health</option>
174
+ <option value="fa-graduation-cap">Education</option>
175
+ <option value="fa-film">Entertainment</option>
176
+ <option value="fa-tshirt">Clothing</option>
177
+ <option value="fa-wifi">Utilities</option>
178
+ <option value="fa-gift">Gifts</option>
179
+ <option value="fa-plane">Travel</option>
180
+ </select>
181
+ </div>
182
+ <div class="flex justify-end space-x-2 sm:space-x-3">
183
+ <button id="cancelAddCategory" class="px-3 sm:px-4 py-1 sm:py-2 text-gray-600 hover:text-gray-800 text-sm sm:text-base">Cancel</button>
184
+ <button id="confirmAddCategory" class="px-3 sm:px-4 py-1 sm:py-2 bg-indigo-600 text-white rounded-lg hover:bg-indigo-700 text-sm sm:text-base">Add</button>
185
+ </div>
186
+ </div>
187
+ </div>
188
+ </div>
189
+
190
+ <script>
191
+ document.addEventListener('DOMContentLoaded', function() {
192
+ // DOM Elements
193
+ const salaryInput = document.getElementById('salaryInput');
194
+ const setSalaryBtn = document.getElementById('setSalaryBtn');
195
+ const summarySection = document.getElementById('summarySection');
196
+ const expensesSection = document.getElementById('expensesSection');
197
+ const totalSalaryDisplay = document.getElementById('totalSalary');
198
+ const totalExpensesDisplay = document.getElementById('totalExpenses');
199
+ const remainingSalaryDisplay = document.getElementById('remainingSalary');
200
+ const addCategoryBtn = document.getElementById('addCategoryBtn');
201
+ const addCategoryModal = document.getElementById('addCategoryModal');
202
+ const cancelAddCategory = document.getElementById('cancelAddCategory');
203
+ const confirmAddCategory = document.getElementById('confirmAddCategory');
204
+ const newCategoryName = document.getElementById('newCategoryName');
205
+ const newCategoryIcon = document.getElementById('newCategoryIcon');
206
+ const expensesList = document.getElementById('expensesList');
207
+ const currencyPicker = document.getElementById('currencyPicker');
208
+ const currencySymbol = document.getElementById('currencySymbol');
209
+
210
+ let salary = 0;
211
+ let currentCurrency = '$';
212
+
213
+ // Update currency symbols
214
+ function updateCurrencySymbols() {
215
+ currencySymbol.textContent = currentCurrency;
216
+
217
+ document.querySelectorAll('.expense-currency').forEach(el => {
218
+ el.textContent = currentCurrency;
219
+ });
220
+
221
+ updateSummaryDisplay();
222
+ }
223
+
224
+ // Currency picker change handler
225
+ currencyPicker.addEventListener('change', function() {
226
+ currentCurrency = this.value;
227
+ updateCurrencySymbols();
228
+ });
229
+
230
+ // Set salary
231
+ setSalaryBtn.addEventListener('click', function() {
232
+ const value = parseFloat(salaryInput.value);
233
+ if (!isNaN(value) && value > 0) {
234
+ salary = value;
235
+ updateSummaryDisplay();
236
+ summarySection.classList.remove('hidden');
237
+ expensesSection.classList.remove('hidden');
238
+ calculateRemaining();
239
+ updateCurrencySymbols();
240
+ } else {
241
+ alert('Please enter a valid salary amount');
242
+ }
243
+ });
244
+
245
+ // Add event listeners to existing expense inputs
246
+ document.querySelectorAll('.expense-input').forEach(input => {
247
+ input.addEventListener('input', calculateRemaining);
248
+ });
249
+
250
+ // Delete expense item
251
+ expensesList.addEventListener('click', function(e) {
252
+ if (e.target.classList.contains('delete-btn') || e.target.closest('.delete-btn')) {
253
+ const item = e.target.closest('.expense-item');
254
+ item.classList.add('hidden');
255
+ setTimeout(() => {
256
+ item.remove();
257
+ calculateRemaining();
258
+ }, 300);
259
+ }
260
+ });
261
+
262
+ // Show add category modal
263
+ addCategoryBtn.addEventListener('click', function() {
264
+ addCategoryModal.classList.remove('hidden');
265
+ newCategoryName.focus();
266
+ });
267
+
268
+ // Hide add category modal
269
+ cancelAddCategory.addEventListener('click', function() {
270
+ addCategoryModal.classList.add('hidden');
271
+ newCategoryName.value = '';
272
+ });
273
+
274
+ // Add new category
275
+ confirmAddCategory.addEventListener('click', function() {
276
+ const name = newCategoryName.value.trim();
277
+ const icon = newCategoryIcon.value;
278
+
279
+ if (name) {
280
+ const newItem = document.createElement('div');
281
+ newItem.className = 'expense-item animate-fade-in';
282
+ newItem.innerHTML = `
283
+ <div class="flex flex-col sm:flex-row sm:items-center justify-between gap-2 sm:gap-0">
284
+ <div class="flex items-center sm:w-2/5">
285
+ <i class="fas ${icon} text-indigo-500 mr-2 text-sm sm:text-base"></i>
286
+ <span class="text-gray-700 text-sm sm:text-base">${name}</span>
287
+ </div>
288
+ <div class="flex items-center sm:w-3/5">
289
+ <span class="expense-currency mr-2 text-gray-700 text-sm sm:text-base">${currentCurrency}</span>
290
+ <input type="number" placeholder="Amount"
291
+ class="expense-input flex-1 border-b-2 border-gray-300 py-1 px-1 focus:border-indigo-500 focus:outline-none text-sm sm:text-base">
292
+ <button class="delete-btn ml-2 sm:ml-3 text-red-500 hover:text-red-700 text-sm sm:text-base">
293
+ <i class="fas fa-trash"></i>
294
+ </button>
295
+ </div>
296
+ </div>
297
+ `;
298
+
299
+ expensesList.appendChild(newItem);
300
+ newItem.querySelector('.expense-input').addEventListener('input', calculateRemaining);
301
+
302
+ addCategoryModal.classList.add('hidden');
303
+ newCategoryName.value = '';
304
+ } else {
305
+ alert('Please enter a category name');
306
+ }
307
+ });
308
+
309
+ // Update summary display with current currency
310
+ function updateSummaryDisplay() {
311
+ totalSalaryDisplay.textContent = `${currentCurrency}${salary.toFixed(2)}`;
312
+ calculateRemaining();
313
+ }
314
+
315
+ // Calculate remaining salary
316
+ function calculateRemaining() {
317
+ let totalExpenses = 0;
318
+ document.querySelectorAll('.expense-input').forEach(input => {
319
+ const value = parseFloat(input.value);
320
+ if (!isNaN(value) && value > 0) {
321
+ totalExpenses += value;
322
+ }
323
+ });
324
+
325
+ totalExpensesDisplay.textContent = `${currentCurrency}${totalExpenses.toFixed(2)}`;
326
+
327
+ const remaining = salary - totalExpenses;
328
+ remainingSalaryDisplay.textContent = `${currentCurrency}${remaining.toFixed(2)}`;
329
+
330
+ // Change color based on remaining amount
331
+ if (remaining < 0) {
332
+ remainingSalaryDisplay.classList.remove('text-green-800', 'text-yellow-600');
333
+ remainingSalaryDisplay.classList.add('text-red-800');
334
+ } else if (remaining < salary * 0.2) {
335
+ remainingSalaryDisplay.classList.remove('text-green-800', 'text-red-800');
336
+ remainingSalaryDisplay.classList.add('text-yellow-600');
337
+ } else {
338
+ remainingSalaryDisplay.classList.remove('text-red-800', 'text-yellow-600');
339
+ remainingSalaryDisplay.classList.add('text-green-800');
340
+ }
341
+ }
342
+ });
343
+ </script>
344
+ <p style="border-radius: 8px; text-align: center; font-size: 12px; color: #fff; margin-top: 16px;position: fixed; left: 8px; bottom: 8px; z-index: 10; background: rgba(0, 0, 0, 0.8); padding: 4px 8px;">Made with <img src="https://enzostvs-deepsite.hf.space/logo.svg" alt="DeepSite Logo" style="width: 16px; height: 16px; vertical-align: middle;display:inline-block;margin-right:3px;filter:brightness(0) invert(1);"><a href="https://enzostvs-deepsite.hf.space" style="color: #fff;text-decoration: underline;" target="_blank" >DeepSite</a> - <a href="https://enzostvs-deepsite.hf.space?remix=Digiator/spend-planner" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
345
+ </html>