alfredtam commited on
Commit
146b550
·
verified ·
1 Parent(s): ff496d6

Add 2 files

Browse files
Files changed (2) hide show
  1. README.md +7 -5
  2. index.html +579 -19
README.md CHANGED
@@ -1,10 +1,12 @@
1
  ---
2
- title: Al Space
3
- emoji: 🏆
4
- colorFrom: gray
5
- colorTo: purple
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: al-space
3
+ emoji: 🐳
4
+ colorFrom: yellow
5
+ colorTo: gray
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,579 @@
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>Business Invoice Generator</title>
7
+ <script src="https://cdn.tailwindcss.com"></script>
8
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script>
9
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/html2canvas/1.4.1/html2canvas.min.js"></script>
10
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
11
+ <style>
12
+ @keyframes fadeIn {
13
+ from { opacity: 0; transform: translateY(10px); }
14
+ to { opacity: 1; transform: translateY(0); }
15
+ }
16
+
17
+ .invoice-item:last-child {
18
+ border-bottom: none;
19
+ }
20
+
21
+ .modal {
22
+ animation: fadeIn 0.3s ease-out;
23
+ }
24
+
25
+ #invoice-preview {
26
+ background-color: white;
27
+ color: black;
28
+ box-shadow: 0 0 20px rgba(0,0,0,0.1);
29
+ }
30
+ </style>
31
+ </head>
32
+ <body class="bg-gray-100 min-h-screen">
33
+ <div class="container mx-auto px-4 py-8">
34
+ <div class="flex justify-between items-center mb-8">
35
+ <h1 class="text-3xl font-bold text-gray-800">
36
+ <i class="fas fa-file-invoice-dollar mr-2 text-blue-600"></i>
37
+ Invoice Generator
38
+ </h1>
39
+ <button id="preview-btn" class="bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg transition flex items-center">
40
+ <i class="fas fa-eye mr-2"></i> Preview Invoice
41
+ </button>
42
+ </div>
43
+
44
+ <div class="grid grid-cols-1 lg:grid-cols-3 gap-6">
45
+ <!-- Invoice Form -->
46
+ <div class="lg:col-span-2 bg-white rounded-xl shadow-md p-6">
47
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">Invoice Details</h2>
48
+
49
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-4 mb-6">
50
+ <div>
51
+ <label class="block text-sm font-medium text-gray-700 mb-1">Invoice Number</label>
52
+ <input type="text" id="invoice-number" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" value="INV-0001">
53
+ </div>
54
+ <div>
55
+ <label class="block text-sm font-medium text-gray-700 mb-1">Date</label>
56
+ <input type="date" id="invoice-date" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
57
+ </div>
58
+ <div>
59
+ <label class="block text-sm font-medium text-gray-700 mb-1">Due Date</label>
60
+ <input type="date" id="due-date" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
61
+ </div>
62
+ <div>
63
+ <label class="block text-sm font-medium text-gray-700 mb-1">Currency</label>
64
+ <select id="currency" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
65
+ <option value="$">USD ($)</option>
66
+ <option value="€">EUR (€)</option>
67
+ <option value="£">GBP (£)</option>
68
+ <option value="¥">JPY (¥)</option>
69
+ </select>
70
+ </div>
71
+ </div>
72
+
73
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mb-6">
74
+ <!-- From Section -->
75
+ <div>
76
+ <h3 class="text-lg font-medium mb-2 text-gray-800 flex items-center">
77
+ <i class="fas fa-building mr-2 text-blue-600"></i> From
78
+ </h3>
79
+ <div class="space-y-3">
80
+ <div>
81
+ <label class="block text-sm font-medium text-gray-700 mb-1">Business Name</label>
82
+ <input type="text" id="from-name" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" value="Your Company Name">
83
+ </div>
84
+ <div>
85
+ <label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
86
+ <input type="email" id="from-email" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" value="contact@yourcompany.com">
87
+ </div>
88
+ <div>
89
+ <label class="block text-sm font-medium text-gray-700 mb-1">Phone</label>
90
+ <input type="text" id="from-phone" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" value="+1 (555) 123-4567">
91
+ </div>
92
+ <div>
93
+ <label class="block text-sm font-medium text-gray-700 mb-1">Address</label>
94
+ <textarea id="from-address" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">123 Business St, Suite 100
95
+ City, State 12345
96
+ Country</textarea>
97
+ </div>
98
+ </div>
99
+ </div>
100
+
101
+ <!-- To Section -->
102
+ <div>
103
+ <h3 class="text-lg font-medium mb-2 text-gray-800 flex items-center">
104
+ <i class="fas fa-user-tie mr-2 text-blue-600"></i> To
105
+ </h3>
106
+ <div class="space-y-3">
107
+ <div>
108
+ <label class="block text-sm font-medium text-gray-700 mb-1">Client Name</label>
109
+ <input type="text" id="to-name" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" value="Client Company Name">
110
+ </div>
111
+ <div>
112
+ <label class="block text-sm font-medium text-gray-700 mb-1">Email</label>
113
+ <input type="email" id="to-email" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" value="contact@clientcompany.com">
114
+ </div>
115
+ <div>
116
+ <label class="block text-sm font-medium text-gray-700 mb-1">Phone</label>
117
+ <input type="text" id="to-phone" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" value="+1 (555) 987-6543">
118
+ </div>
119
+ <div>
120
+ <label class="block text-sm font-medium text-gray-700 mb-1">Address</label>
121
+ <textarea id="to-address" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">456 Client Ave, Floor 5
122
+ City, State 67890
123
+ Country</textarea>
124
+ </div>
125
+ </div>
126
+ </div>
127
+ </div>
128
+
129
+ <!-- Items Section -->
130
+ <div>
131
+ <h3 class="text-lg font-medium mb-2 text-gray-800 flex items-center">
132
+ <i class="fas fa-list-ul mr-2 text-blue-600"></i> Items
133
+ </h3>
134
+ <div class="mb-4">
135
+ <div id="invoice-items" class="space-y-4">
136
+ <!-- Item rows will be added here -->
137
+ </div>
138
+ <button id="add-item-btn" class="mt-4 bg-blue-600 hover:bg-blue-700 text-white font-medium py-2 px-4 rounded-lg transition flex items-center">
139
+ <i class="fas fa-plus mr-2"></i> Add Item
140
+ </button>
141
+ </div>
142
+ </div>
143
+
144
+ <!-- Notes & Terms -->
145
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-6 mt-6">
146
+ <div>
147
+ <label class="block text-sm font-medium text-gray-700 mb-1">Notes</label>
148
+ <textarea id="notes" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">Thank you for your business!</textarea>
149
+ </div>
150
+ <div>
151
+ <label class="block text-sm font-medium text-gray-700 mb-1">Terms & Conditions</label>
152
+ <textarea id="terms" rows="3" class="w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">Payment due within 30 days. Late payments subject to 1.5% monthly interest.</textarea>
153
+ </div>
154
+ </div>
155
+ </div>
156
+
157
+ <!-- Preview Section -->
158
+ <div class="lg:col-span-1">
159
+ <div class="bg-white rounded-xl shadow-md p-6 sticky top-6">
160
+ <h2 class="text-xl font-semibold mb-4 text-gray-800">Summary</h2>
161
+
162
+ <div class="space-y-4 mb-6">
163
+ <div class="flex justify-between">
164
+ <span class="text-gray-600">Subtotal:</span>
165
+ <span id="subtotal" class="font-medium">$0.00</span>
166
+ </div>
167
+
168
+ <div class="flex justify-between">
169
+ <span class="text-gray-600">Tax Rate:</span>
170
+ <div class="flex items-center">
171
+ <input type="number" id="tax-rate" min="0" max="100" step="0.1" value="10" class="w-16 px-2 py-1 border border-gray-300 rounded-md text-right">
172
+ <span class="ml-1">%</span>
173
+ </div>
174
+ </div>
175
+
176
+ <div class="flex justify-between">
177
+ <span class="text-gray-600">Tax Amount:</span>
178
+ <span id="tax-amount" class="font-medium">$0.00</span>
179
+ </div>
180
+
181
+ <div class="border-t border-gray-200 pt-2 flex justify-between">
182
+ <span class="text-gray-800 font-semibold">Total:</span>
183
+ <span id="total" class="text-lg font-bold text-blue-600">$0.00</span>
184
+ </div>
185
+ </div>
186
+
187
+ <button id="download-pdf-btn" class="w-full bg-green-600 hover:bg-green-700 text-white font-medium py-3 px-4 rounded-lg transition flex items-center justify-center">
188
+ <i class="fas fa-file-pdf mr-2"></i> Download PDF
189
+ </button>
190
+
191
+ <button id="clear-form-btn" class="w-full mt-3 bg-gray-200 hover:bg-gray-300 text-gray-800 font-medium py-3 px-4 rounded-lg transition flex items-center justify-center">
192
+ <i class="fas fa-trash-alt mr-2"></i> Clear Form
193
+ </button>
194
+ </div>
195
+ </div>
196
+ </div>
197
+ </div>
198
+
199
+ <!-- Invoice Preview Modal -->
200
+ <div id="preview-modal" class="fixed inset-0 bg-black bg-opacity-70 flex items-center justify-center p-4 hidden modal">
201
+ <div class="bg-white rounded-xl max-w-4xl w-full max-h-[90vh] overflow-auto">
202
+ <div class="flex justify-between items-center p-4 border-b">
203
+ <h2 class="text-xl font-bold">Invoice Preview</h2>
204
+ <button id="close-preview-btn" class="text-gray-500 hover:text-gray-700">
205
+ <i class="fas fa-times text-2xl"></i>
206
+ </button>
207
+ </div>
208
+ <div id="invoice-preview" class="p-8">
209
+ <!-- Preview content will be generated here -->
210
+ </div>
211
+ <div class="p-4 border-t flex justify-end">
212
+ <button id="download-from-preview-btn" class="bg-green-600 hover:bg-green-700 text-white font-medium py-2 px-6 rounded-lg transition flex items-center">
213
+ <i class="fas fa-file-pdf mr-2"></i> Download PDF
214
+ </button>
215
+ </div>
216
+ </div>
217
+ </div>
218
+
219
+ <script>
220
+ // Initialize jsPDF
221
+ const { jsPDF } = window.jspdf;
222
+
223
+ document.addEventListener('DOMContentLoaded', () => {
224
+ // Set today's date as default
225
+ const today = new Date();
226
+ const formattedDate = today.toISOString().split('T')[0];
227
+ document.getElementById('invoice-date').value = formattedDate;
228
+
229
+ // Set due date to 30 days from today
230
+ const dueDate = new Date();
231
+ dueDate.setDate(today.getDate() + 30);
232
+ const formattedDueDate = dueDate.toISOString().split('T')[0];
233
+ document.getElementById('due-date').value = formattedDueDate;
234
+
235
+ // Add first item row
236
+ addItemRow();
237
+
238
+ // Event listeners
239
+ document.getElementById('add-item-btn').addEventListener('click', addItemRow);
240
+ document.getElementById('download-pdf-btn').addEventListener('click', generatePDF);
241
+ document.getElementById('clear-form-btn').addEventListener('click', clearForm);
242
+ document.getElementById('preview-btn').addEventListener('click', showPreview);
243
+ document.getElementById('close-preview-btn').addEventListener('click', () => {
244
+ document.getElementById('preview-modal').classList.add('hidden');
245
+ });
246
+ document.getElementById('download-from-preview-btn').addEventListener('click', generatePDFFromPreview);
247
+
248
+ // Add input event listeners for calculations
249
+ document.getElementById('tax-rate').addEventListener('input', calculateTotals);
250
+
251
+ // Initialize calculations
252
+ calculateTotals();
253
+ });
254
+
255
+ // Add a new item row
256
+ function addItemRow() {
257
+ const itemsContainer = document.getElementById('invoice-items');
258
+ const itemId = Date.now(); // Unique ID for each item
259
+
260
+ const itemRow = document.createElement('div');
261
+ itemRow.className = 'invoice-item border-b border-gray-200 pb-4';
262
+ itemRow.dataset.id = itemId;
263
+
264
+ itemRow.innerHTML = `
265
+ <div class="grid grid-cols-12 gap-2 items-end">
266
+ <div class="col-span-5">
267
+ <label class="block text-sm font-medium text-gray-700 mb-1">Description</label>
268
+ <input type="text" class="item-description w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500" placeholder="Item description">
269
+ </div>
270
+ <div class="col-span-2">
271
+ <label class="block text-sm font-medium text-gray-700 mb-1">Quantity</label>
272
+ <input type="number" min="1" value="1" class="item-quantity w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
273
+ </div>
274
+ <div class="col-span-2">
275
+ <label class="block text-sm font-medium text-gray-700 mb-1">Rate</label>
276
+ <input type="number" min="0" step="0.01" value="0.00" class="item-rate w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500">
277
+ </div>
278
+ <div class="col-span-2">
279
+ <label class="block text-sm font-medium text-gray-700 mb-1">Amount</label>
280
+ <input type="text" class="item-amount w-full px-3 py-2 border border-gray-300 rounded-md bg-gray-50" readonly>
281
+ </div>
282
+ <div class="col-span-1 flex justify-end">
283
+ <button class="remove-item-btn text-red-500 hover:text-red-700 p-2">
284
+ <i class="fas fa-trash"></i>
285
+ </button>
286
+ </div>
287
+ </div>
288
+ `;
289
+
290
+ itemsContainer.appendChild(itemRow);
291
+
292
+ // Add event listeners for the new row
293
+ const quantityInput = itemRow.querySelector('.item-quantity');
294
+ const rateInput = itemRow.querySelector('.item-rate');
295
+ const amountInput = itemRow.querySelector('.item-amount');
296
+ const removeBtn = itemRow.querySelector('.remove-item-btn');
297
+
298
+ quantityInput.addEventListener('input', () => {
299
+ calculateItemAmount(itemRow);
300
+ calculateTotals();
301
+ });
302
+
303
+ rateInput.addEventListener('input', () => {
304
+ calculateItemAmount(itemRow);
305
+ calculateTotals();
306
+ });
307
+
308
+ removeBtn.addEventListener('click', () => {
309
+ itemRow.remove();
310
+ calculateTotals();
311
+ });
312
+
313
+ // Calculate initial amount for the new row
314
+ calculateItemAmount(itemRow);
315
+ }
316
+
317
+ // Calculate amount for a single item
318
+ function calculateItemAmount(itemRow) {
319
+ const quantity = parseFloat(itemRow.querySelector('.item-quantity').value) || 0;
320
+ const rate = parseFloat(itemRow.querySelector('.item-rate').value) || 0;
321
+ const amount = quantity * rate;
322
+
323
+ itemRow.querySelector('.item-amount').value = formatCurrency(amount);
324
+ }
325
+
326
+ // Calculate all totals
327
+ function calculateTotals() {
328
+ const items = document.querySelectorAll('.invoice-item');
329
+ let subtotal = 0;
330
+
331
+ items.forEach(item => {
332
+ const amount = parseFloat(item.querySelector('.item-amount').value.replace(/[^0-9.-]+/g,"")) || 0;
333
+ subtotal += amount;
334
+ });
335
+
336
+ const taxRate = parseFloat(document.getElementById('tax-rate').value) || 0;
337
+ const taxAmount = subtotal * (taxRate / 100);
338
+ const total = subtotal + taxAmount;
339
+
340
+ const currencySymbol = document.getElementById('currency').value;
341
+
342
+ document.getElementById('subtotal').textContent = `${currencySymbol}${formatCurrency(subtotal)}`;
343
+ document.getElementById('tax-amount').textContent = `${currencySymbol}${formatCurrency(taxAmount)}`;
344
+ document.getElementById('total').textContent = `${currencySymbol}${formatCurrency(total)}`;
345
+ }
346
+
347
+ // Format currency
348
+ function formatCurrency(amount) {
349
+ return amount.toFixed(2).replace(/\d(?=(\d{3})+\.)/g, '$&,');
350
+ }
351
+
352
+ // Generate PDF from form
353
+ function generatePDF() {
354
+ // First generate the preview HTML
355
+ generatePreview();
356
+
357
+ // Then use html2canvas to capture it
358
+ const invoicePreview = document.getElementById('invoice-preview');
359
+
360
+ html2canvas(invoicePreview).then(canvas => {
361
+ const imgData = canvas.toDataURL('image/png');
362
+ const pdf = new jsPDF({
363
+ orientation: 'portrait',
364
+ unit: 'mm'
365
+ });
366
+
367
+ // Calculate the PDF dimensions to maintain aspect ratio
368
+ const imgWidth = 210; // A4 width in mm
369
+ const imgHeight = canvas.height * imgWidth / canvas.width;
370
+
371
+ pdf.addImage(imgData, 'PNG', 0, 0, imgWidth, imgHeight);
372
+
373
+ // Get invoice number for filename
374
+ const invoiceNumber = document.getElementById('invoice-number').value || 'invoice';
375
+
376
+ // Save the PDF
377
+ pdf.save(`${invoiceNumber}.pdf`);
378
+ });
379
+ }
380
+
381
+ // Generate PDF from preview modal
382
+ function generatePDFFromPreview() {
383
+ generatePDF();
384
+ document.getElementById('preview-modal').classList.add('hidden');
385
+ }
386
+
387
+ // Show preview modal
388
+ function showPreview() {
389
+ generatePreview();
390
+ document.getElementById('preview-modal').classList.remove('hidden');
391
+ }
392
+
393
+ // Generate the preview HTML
394
+ function generatePreview() {
395
+ const previewContainer = document.getElementById('invoice-preview');
396
+ const currencySymbol = document.getElementById('currency').value;
397
+
398
+ // Get all form values
399
+ const invoiceNumber = document.getElementById('invoice-number').value;
400
+ const invoiceDate = formatDate(document.getElementById('invoice-date').value);
401
+ const dueDate = formatDate(document.getElementById('due-date').value);
402
+
403
+ const fromName = document.getElementById('from-name').value;
404
+ const fromEmail = document.getElementById('from-email').value;
405
+ const fromPhone = document.getElementById('from-phone').value;
406
+ const fromAddress = document.getElementById('from-address').value.replace(/\n/g, '<br>');
407
+
408
+ const toName = document.getElementById('to-name').value;
409
+ const toEmail = document.getElementById('to-email').value;
410
+ const toPhone = document.getElementById('to-phone').value;
411
+ const toAddress = document.getElementById('to-address').value.replace(/\n/g, '<br>');
412
+
413
+ const notes = document.getElementById('notes').value.replace(/\n/g, '<br>');
414
+ const terms = document.getElementById('terms').value.replace(/\n/g, '<br>');
415
+
416
+ const subtotal = document.getElementById('subtotal').textContent;
417
+ const taxAmount = document.getElementById('tax-amount').textContent;
418
+ const total = document.getElementById('total').textContent;
419
+ const taxRate = document.getElementById('tax-rate').value;
420
+
421
+ // Generate items HTML
422
+ let itemsHTML = '';
423
+ const items = document.querySelectorAll('.invoice-item');
424
+
425
+ items.forEach(item => {
426
+ const description = item.querySelector('.item-description').value || 'Item';
427
+ const quantity = item.querySelector('.item-quantity').value || '0';
428
+ const rate = `${currencySymbol}${parseFloat(item.querySelector('.item-rate').value || 0).toFixed(2)}`;
429
+ const amount = item.querySelector('.item-amount').value || '0.00';
430
+
431
+ itemsHTML += `
432
+ <tr class="border-b border-gray-200">
433
+ <td class="py-3">${description}</td>
434
+ <td class="text-center py-3">${quantity}</td>
435
+ <td class="text-right py-3">${rate}</td>
436
+ <td class="text-right py-3">${currencySymbol}${amount}</td>
437
+ </tr>
438
+ `;
439
+ });
440
+
441
+ // Build the preview HTML
442
+ previewContainer.innerHTML = `
443
+ <div class="max-w-4xl mx-auto">
444
+ <div class="flex justify-between items-start mb-8">
445
+ <div>
446
+ <h1 class="text-3xl font-bold text-blue-600 mb-1">${fromName}</h1>
447
+ <div class="text-gray-600">
448
+ ${fromAddress}<br>
449
+ ${fromEmail}<br>
450
+ ${fromPhone}
451
+ </div>
452
+ </div>
453
+ <div class="text-right">
454
+ <h2 class="text-2xl font-bold mb-2">INVOICE</h2>
455
+ <div class="text-gray-600">
456
+ <div class="mb-1"><strong>Invoice #:</strong> ${invoiceNumber}</div>
457
+ <div class="mb-1"><strong>Date:</strong> ${invoiceDate}</div>
458
+ <div><strong>Due Date:</strong> ${dueDate}</div>
459
+ </div>
460
+ </div>
461
+ </div>
462
+
463
+ <div class="flex justify-between mb-8">
464
+ <div class="bg-gray-100 p-4 rounded-lg w-1/2">
465
+ <h3 class="font-bold text-gray-800 mb-2">From:</h3>
466
+ <div class="text-gray-600">
467
+ ${fromName}<br>
468
+ ${fromAddress}<br>
469
+ ${fromEmail}<br>
470
+ ${fromPhone}
471
+ </div>
472
+ </div>
473
+ <div class="bg-gray-100 p-4 rounded-lg w-1/2 ml-4">
474
+ <h3 class="font-bold text-gray-800 mb-2">To:</h3>
475
+ <div class="text-gray-600">
476
+ ${toName}<br>
477
+ ${toAddress}<br>
478
+ ${toEmail}<br>
479
+ ${toPhone}
480
+ </div>
481
+ </div>
482
+ </div>
483
+
484
+ <table class="w-full mb-8">
485
+ <thead>
486
+ <tr class="bg-gray-100 text-left border-b border-gray-200">
487
+ <th class="py-3 font-bold">Description</th>
488
+ <th class="py-3 font-bold text-center">Quantity</th>
489
+ <th class="py-3 font-bold text-right">Rate</th>
490
+ <th class="py-3 font-bold text-right">Amount</th>
491
+ </tr>
492
+ </thead>
493
+ <tbody>
494
+ ${itemsHTML}
495
+ </tbody>
496
+ </table>
497
+
498
+ <div class="flex justify-end mb-8">
499
+ <div class="w-1/3">
500
+ <div class="flex justify-between py-2 border-b border-gray-200">
501
+ <span class="font-bold">Subtotal:</span>
502
+ <span>${subtotal}</span>
503
+ </div>
504
+ <div class="flex justify-between py-2 border-b border-gray-200">
505
+ <span class="font-bold">Tax (${taxRate}%):</span>
506
+ <span>${taxAmount}</span>
507
+ </div>
508
+ <div class="flex justify-between py-2">
509
+ <span class="font-bold text-lg">Total:</span>
510
+ <span class="font-bold text-lg">${total}</span>
511
+ </div>
512
+ </div>
513
+ </div>
514
+
515
+ <div class="grid grid-cols-1 md:grid-cols-2 gap-8">
516
+ <div>
517
+ <h3 class="font-bold text-gray-800 mb-2">Notes</h3>
518
+ <div class="text-gray-600">${notes}</div>
519
+ </div>
520
+ <div>
521
+ <h3 class="font-bold text-gray-800 mb-2">Terms & Conditions</h3>
522
+ <div class="text-gray-600">${terms}</div>
523
+ </div>
524
+ </div>
525
+
526
+ <div class="mt-12 pt-4 border-t border-gray-200 text-center text-gray-500 text-sm">
527
+ Thank you for your business!
528
+ </div>
529
+ </div>
530
+ `;
531
+ }
532
+
533
+ // Format date from YYYY-MM-DD to Month Day, Year
534
+ function formatDate(dateString) {
535
+ if (!dateString) return '';
536
+
537
+ const options = { year: 'numeric', month: 'long', day: 'numeric' };
538
+ const date = new Date(dateString);
539
+ return date.toLocaleDateString('en-US', options);
540
+ }
541
+
542
+ // Clear form
543
+ function clearForm() {
544
+ if (confirm('Are you sure you want to clear the entire form? All data will be lost.')) {
545
+ // Reset form fields
546
+ document.getElementById('invoice-number').value = 'INV-' + Math.floor(1000 + Math.random() * 9000);
547
+
548
+ const today = new Date();
549
+ document.getElementById('invoice-date').value = today.toISOString().split('T')[0];
550
+
551
+ const dueDate = new Date();
552
+ dueDate.setDate(today.getDate() + 30);
553
+ document.getElementById('due-date').value = dueDate.toISOString().split('T')[0];
554
+
555
+ document.getElementById('from-name').value = 'Your Company Name';
556
+ document.getElementById('from-email').value = 'contact@yourcompany.com';
557
+ document.getElementById('from-phone').value = '+1 (555) 123-4567';
558
+ document.getElementById('from-address').value = '123 Business St, Suite 100\nCity, State 12345\nCountry';
559
+
560
+ document.getElementById('to-name').value = 'Client Company Name';
561
+ document.getElementById('to-email').value = 'contact@clientcompany.com';
562
+ document.getElementById('to-phone').value = '+1 (555) 987-6543';
563
+ document.getElementById('to-address').value = '456 Client Ave, Floor 5\nCity, State 67890\nCountry';
564
+
565
+ document.getElementById('notes').value = 'Thank you for your business!';
566
+ document.getElementById('terms').value = 'Payment due within 30 days. Late payments subject to 1.5% monthly interest.';
567
+ document.getElementById('tax-rate').value = '10';
568
+
569
+ // Clear items and add one empty row
570
+ document.getElementById('invoice-items').innerHTML = '';
571
+ addItemRow();
572
+
573
+ // Recalculate totals
574
+ calculateTotals();
575
+ }
576
+ }
577
+ </script>
578
+ <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=alfredtam/al-space" style="color: #fff;text-decoration: underline;" target="_blank" >🧬 Remix</a></p></body>
579
+ </html>