https://hrubos.tech/blogy/content/images/20260315233355-fakturav1-running-program.png
AppImage a Windows64 exe stiahnete zadarmo na: https://hrubos.tech/repository/faktura1-release-appimage-win64.zip
Webová verzia beží na: https://projects.hrubos.tech/ Prepísal som ju do Tauri v2 :)
Takto vyzerá generovaná faktúrka:



<!DOCTYPE html>
<html lang="sk">
<head>
<meta charset="UTF-8">
<title>Faktúra PDF</title>
<script src="/jspdf.umd.min.js"></script>
<script src="/html2canvas.min.js"></script>
<script src="/index.js" defer></script>
<style>
body{
font-family: DejaVu Sans, sans-serif;
margin:50px;
color:#333;
font-size:18px;
line-height:1.6;
}
.header{
display:flex;
justify-content:space-between;
margin-bottom:50px;
}
.company{
font-size:24px;
font-weight:bold;
margin:10px 0;
}
.invoice-title{
font-size:36px;
font-weight:bold;
margin:10px 0;
}
.meta{
margin:10px 0;
}
.table{
width:100%;
border-collapse:collapse;
margin-top:40px;
}
.table th{
background:#f2f2f2;
padding:12px;
text-align:left;
border-bottom:2px solid #ddd;
}
.table td{
padding:12px;
border-bottom:1px solid #eee;
}
.total{
margin-top:40px;
width:350px;
float:right;
}
.total td{
padding:4px;
}
.grand{
font-size:20px;
font-weight:bold;
margin:5px 0;
}
.footer{
margin-top:120px;
text-align:center;
font-size:14px;
color:#777;
}
input {
width: 100%;
padding:5px;
margin:8px 0;
border:none;
font-size:16px;
}
.item {
display: flex;
gap:10px;
margin:10px 0;
}
button {
margin-top:15px;
padding:10px 16px;
cursor:pointer;
font-size:16px;
}
</style>
</head>
<body>
<div id="invoice-form">
<div class="header">
<div>
<div class="company"><input type="text" id="company-name" value="Firma s.r.o."></div>
<div><input type="text" id="company-address" value="Hlavná 123"></div>
<div><input type="text" id="company-city" value="Bratislava"></div>
</div>
<div>
<div class="invoice-title">FAKTÚRA</div>
<div class="meta">
Faktúra č.: <input type="text" id="invoice-number" value="2026-001"><br>
Dátum vystavenia: <input type="date" id="invoice-date" value="2026-03-15"><br>
Do kedy splatná: <input type="date" id="invoice-due" value="2026-03-22"><br>
DPH (%): <input type="number" id="vat-rate" value="23">
</div>
</div>
</div>
<div>
<strong>Účtovaná komu:</strong><br>
<input type="text" id="customer-name" value="Zákazník s.r.o."><br>
<input type="text" id="customer-address" value="Vedľajšia 45"><br>
<input type="text" id="customer-city" value="Košice">
</div>
<h3>Položky</h3>
<div id="items">
<div class="item">
<input type="text" placeholder="Popis" value="Programovanie">
<input type="number" placeholder="Množ." value="10">
<input type="number" placeholder="Cena" value="50">
</div>
</div>
<button id="add-item">Pridať položku</button><br><br>
<button id="save-json">Uložiť do JSON</button>
<button id="load-json">Načítať z JSON</button><br><br>
<button id="generate-pdf">Generovať PDF</button>
</div>
<script src="index.js"></script>
</body>
</html>
document.addEventListener('DOMContentLoaded', function() {
function updateTotals() {
const items = Array.from(document.querySelectorAll('.item'));
let subtotal = 0;
items.forEach(item => {
const qty = parseFloat(item.children[1].value) || 0;
const price = parseFloat(item.children[2].value) || 0;
subtotal += qty * price;
});
const vatRate = parseFloat(document.getElementById('vat-rate').value) || 23;
const vat = subtotal * (vatRate / 100);
const total = subtotal + vat;
document.querySelector('.total')?.remove();
const totalsHtml = `
<table class="table total">
<tr><td>Celkom bez DPH:</td><td>${subtotal.toFixed(2)} €</td></tr>
<tr><td>DPH ${vatRate}%:</td><td>${vat.toFixed(2)} €</td></tr>
<tr class="grand"><td><strong>SPOLU:</strong></td><td><strong>${total.toFixed(2)} €</strong></td></tr>
</table>
`;
document.getElementById('add-item').insertAdjacentHTML('afterend', totalsHtml);
}
// Add item
document.getElementById('add-item').onclick = function() {
const div = document.createElement('div');
div.className = 'item';
div.innerHTML = `
<input type="text" placeholder="Popis">
<input type="number" placeholder="Množ." step="0.1" min="0">
<input type="number" placeholder="Cena" step="0.01" min="0">
`;
document.getElementById('items').appendChild(div);
updateTotals();
};
// Save JSON (browser download)
document.getElementById('save-json').onclick = function() {
const data = {
company: document.getElementById('company-name').value,
invoiceNumber: document.getElementById('invoice-number').value,
items: Array.from(document.querySelectorAll('.item')).map(i => ({
name: i.children[0].value,
qty: parseFloat(i.children[1].value) || 0,
price: parseFloat(i.children[2].value) || 0
}))
};
const blob = new Blob([JSON.stringify(data, null, 2)], {type: 'application/json'});
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `faktura-${data.invoiceNumber}.json`;
a.click();
URL.revokeObjectURL(url);
alert('JSON stiahnutý!');
};
// Načítať JSON - vlož PO save-json funkcii
document.getElementById('load-json').onclick = function() {
const input = document.createElement('input');
input.type = 'file';
input.accept = '.json';
input.onchange = function(e) {
const file = e.target.files[0];
if (!file) return;
const reader = new FileReader();
reader.onload = function(e) {
try {
const data = JSON.parse(e.target.result);
// Naplň pole company a číslo faktúry
if (data.company) document.getElementById('company-name').value = data.company;
if (data.invoiceNumber) document.getElementById('invoice-number').value = data.invoiceNumber;
// Vyčisti a naplň položky
const itemsDiv = document.getElementById('items');
itemsDiv.innerHTML = '';
(data.items || []).forEach(item => {
const div = document.createElement('div');
div.className = 'item';
div.innerHTML = `
<input type="text" placeholder="Popis" value="${item.name || ''}">
<input type="number" placeholder="Množ." step="0.1" value="${item.qty || 0}">
<input type="number" placeholder="Cena" step="0.01" value="${item.price || 0}">
`;
itemsDiv.appendChild(div);
});
updateTotals();
alert('✅ JSON načítaný!');
} catch (err) {
alert('❌ Chybný JSON súbor!');
}
};
reader.readAsText(file);
};
input.click();
};
// PDF (PNG export)
document.getElementById('generate-pdf').onclick = function() {
html2canvas(document.getElementById('invoice-form'), {
scale: 2,
useCORS: true,
backgroundColor: '#ffffff'
}).then(canvas => {
const inputs = document.querySelectorAll('input, button');
inputs.forEach(el => el.style.display = 'none');
canvas.toBlob(blob => {
const url = URL.createObjectURL(blob);
const a = document.createElement('a');
a.href = url;
a.download = `faktura-${document.getElementById('invoice-number').value}.png`;
a.click();
URL.revokeObjectURL(url);
inputs.forEach(el => el.style.display = '');
alert('Faktúra stiahnutá ako PNG!');
});
});
};
// Real-time calculation
document.addEventListener('input', updateTotals);
updateTotals();
});

Comments “Tak som si vyskúšal napísať malú utilitu Faktura v1 pomocou jazyka Rust a systému Tauri v2, užívajte v zdraví ;)”