Bezbednosni audit i refaktoring: HP popravke, RBAC, flash poruke, go:embed, CSP

This commit is contained in:
2026-06-07 16:10:41 +02:00
parent 301bcaf5c4
commit 16b993933c
37 changed files with 1513 additions and 1949 deletions
+20 -136
View File
@@ -4,142 +4,26 @@
<meta charset="UTF-8" />
<title>NTech — Konfiguracija</title>
<style>
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
background: #1a1a2e;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.kartica {
background: #16213e;
padding: 2rem;
border-radius: 12px;
box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4);
width: 410px;
border: 1px solid #0f3460;
}
.zaglavlje {
text-align: center;
margin-bottom: 1.3rem;
}
.zaglavlje h1 {
color: #f8e45c;
font-size: 1.4rem;
margin-bottom: 0.25rem;
}
.zaglavlje p {
color: #a0a0b0;
font-size: 0.85rem;
}
.sekcija-naslov {
color: #a0a0b0;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 0.4rem;
}
.port-opcija {
display: flex;
justify-content: space-between;
align-items: center;
padding: 0.5rem 0.75rem;
margin: 0.25rem 0;
border: 2px solid #0f3460;
border-radius: 8px;
cursor: pointer;
transition: all 0.2s;
color: #e0e0e0;
}
.port-opcija:hover {
border-color: #e94560;
}
.port-opcija.izabran {
border-color: #e94560;
background: rgba(233, 69, 96, 0.1);
}
.port-opcija.zauzet {
opacity: 0.5;
cursor: not-allowed;
}
.slobodan {
color: #2ecc71;
font-size: 0.85rem;
}
.zauzet-tekst {
color: #e74c3c;
font-size: 0.85rem;
}
.razdvojnik {
border: none;
border-top: 1px solid #0f3460;
margin: 0.75rem 0;
}
input[type="number"] {
width: 100%;
padding: 0.5rem 0.75rem;
background: #0f3460;
border: 2px solid #0f3460;
border-radius: 8px;
font-size: 0.9rem;
color: #e0e0e0;
outline: none;
transition: border-color 0.2s;
}
input[type="number"]:focus {
border-color: #e94560;
}
input[type="number"]::placeholder {
color: #606080;
}
button {
width: 100%;
padding: 0.65rem;
margin-top: 0.75rem;
background: #e94560;
color: white;
border: none;
border-radius: 8px;
font-size: 0.95rem;
font-weight: 600;
cursor: pointer;
transition: background 0.2s;
}
button:hover {
background: #c73652;
}
.poruka {
text-align: center;
padding: 0.5rem;
font-size: 0.85rem;
color: #2ecc71;
display: none;
}
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; background: #1a1a2e; display: flex; justify-content: center; align-items: center; height: 100vh; }
.kartica { background: #16213e; padding: 2rem; border-radius: 12px; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.4); width: 410px; border: 1px solid #0f3460; }
.zaglavlje { text-align: center; margin-bottom: 1.3rem; }
.zaglavlje h1 { color: #f8e45c; font-size: 1.4rem; margin-bottom: 0.25rem; }
.zaglavlje p { color: #a0a0b0; font-size: 0.85rem; }
.sekcija-naslov { color: #a0a0b0; font-size: 0.75rem; text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 0.4rem; }
.port-opcija { display: flex; justify-content: space-between; align-items: center; padding: 0.5rem 0.75rem; margin: 0.25rem 0; border: 2px solid #0f3460; border-radius: 8px; cursor: pointer; transition: all 0.2s; color: #e0e0e0; }
.port-opcija:hover { border-color: #e94560; }
.port-opcija.izabran { border-color: #e94560; background: rgba(233, 69, 96, 0.1); }
.port-opcija.zauzet { opacity: 0.5; cursor: not-allowed; }
.slobodan { color: #2ecc71; font-size: 0.85rem; }
.zauzet-tekst { color: #e74c3c; font-size: 0.85rem; }
.razdvojnik { border: none; border-top: 1px solid #0f3460; margin: 0.75rem 0; }
input[type="number"] { width: 100%; padding: 0.5rem 0.75rem; background: #0f3460; border: 2px solid #0f3460; border-radius: 8px; font-size: 0.9rem; color: #e0e0e0; outline: none; transition: border-color 0.2s; }
input[type="number"]:focus { border-color: #e94560; }
input[type="number"]::placeholder { color: #606080; }
button { width: 100%; padding: 0.65rem; margin-top: 0.75rem; background: #e94560; color: white; border: none; border-radius: 8px; font-size: 0.95rem; font-weight: 600; cursor: pointer; transition: background 0.2s; }
button:hover { background: #c73652; }
.poruka { text-align: center; padding: 0.5rem; font-size: 0.85rem; color: #2ecc71; display: none; }
</style>
</head>
+1 -10
View File
@@ -10,16 +10,7 @@
.dozvole-tabela tbody tr:nth-child(4) { animation-delay: 0.16s; }
.dozvole-tabela tbody tr:nth-child(5) { animation-delay: 0.20s; }
.matrica-modul td {
padding: 8px 16px;
font-size: 12px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.05em;
color: var(--tekst-sporedni);
background: var(--pozadina);
border-top: 0.5px solid var(--ivica);
}
.matrica-modul td { padding: 8px 16px; font-size: 12px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.05em; color: var(--tekst-sporedni); background: var(--pozadina); border-top: 0.5px solid var(--ivica); }
.matrica-checkbox { text-align: center; padding: 8px 16px; }
.matrica-checkbox input[type=checkbox] { width: 16px; height: 16px; cursor: pointer; accent-color: var(--sb-akcent); }
+1 -3
View File
@@ -17,9 +17,7 @@
.korisnici-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.korisnici-tabela tbody tr:nth-child(10) { animation-delay: 0.40s; }
.nova-forma-kartica {
animation-delay: 0.30s;
}
.nova-forma-kartica { animation-delay: 0.30s; }
</style>
{{end}}
@@ -1,86 +1,59 @@
{{template "base" .}}
{{define "naslov"}}Istorija prijava — NTech{{end}}
{{define "dodatni-css"}}
{{template "base" .}} {{define "naslov"}}Istorija prijava — NTech{{end}} {{define "dodatni-css"}}
<style>
.animiraj:nth-child(1) { animation-delay: 0.10s; }
.animiraj:nth-child(2) { animation-delay: 0.16s; }
.animiraj:nth-child(3) { animation-delay: 0.22s; }
.animiraj:nth-child(4) { animation-delay: 0.28s; }
.animiraj:nth-child(1) { animation-delay: 0.1s; }
.animiraj:nth-child(2) { animation-delay: 0.16s; }
.animiraj:nth-child(3) { animation-delay: 0.22s; }
.animiraj:nth-child(4) { animation-delay: 0.28s; }
</style>
{{end}}
{{end}} {{define "sadrzaj"}}
<div style="display: flex; flex-direction: column; gap: 16px">
<div style="display: flex; align-items: center; gap: 12px; flex-wrap: wrap">
<a href="/admin/korisnici" style="display: inline-flex; align-items: center; gap: 6px; padding: 7px 14px; border: 0.5px solid var(--ivica); border-radius: 8px; color: var(--tekst-sporedni); font-size: 13px; text-decoration: none">← Nazad</a>
<span style="font-size: 15px; font-weight: 500; color: var(--tekst-glavni)">Istorija prijava — {{.PrikazKorisnik.KorisnickoIme}}</span>
</div>
{{define "sadrzaj"}}
<div style="display:flex;flex-direction:column;gap:16px;">
<div style="display:flex;align-items:center;gap:12px;flex-wrap:wrap;">
<a href="/admin/korisnici"
style="display:inline-flex;align-items:center;gap:6px;padding:7px 14px;border:0.5px solid var(--ivica);border-radius:8px;color:var(--tekst-sporedni);font-size:13px;text-decoration:none;">
← Nazad
</a>
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">
Istorija prijava — {{.PrikazKorisnik.KorisnickoIme}}
</span>
<div class="kartica animiraj" style="padding: 0; overflow: hidden">
<div style="padding: 16px 20px; border-bottom: 0.5px solid var(--ivica); display: flex; align-items: center; justify-content: space-between">
<span style="font-size: 15px; font-weight: 500; color: var(--tekst-glavni)">Poslednjih 50 pokušaja</span>
<span style="font-size: 12px; color: var(--tekst-sporedni)">Vreme prikazano po lokalnom vremenu servera</span>
</div>
<div class="kartica animiraj" style="padding:0;overflow:hidden;">
<div style="padding:16px 20px;border-bottom:0.5px solid var(--ivica);display:flex;align-items:center;justify-content:space-between;">
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Poslednjih 50 pokušaja</span>
<span style="font-size:12px;color:var(--tekst-sporedni);">Vreme prikazano po lokalnom vremenu servera</span>
</div>
{{if .Istorija}}
<div style="overflow-x:auto;">
<table style="width:100%;border-collapse:collapse;">
<thead>
<tr style="border-bottom:0.5px solid var(--ivica);">
<th style="padding:10px 20px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);white-space:nowrap;">Datum i vreme</th>
<th style="padding:10px 20px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">IP adresa</th>
<th style="padding:10px 20px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Pregledač</th>
<th style="padding:10px 20px;text-align:center;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Status</th>
<th style="padding:10px 20px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Razlog</th>
</tr>
</thead>
<tbody>
{{range .Istorija}}
<tr class="animiraj" style="border-bottom:0.5px solid var(--ivica);">
<td style="padding:10px 20px;font-size:13px;color:var(--tekst-sporedni);white-space:nowrap;">
{{.Vreme.Format "02.01.2006. 15:04:05"}}
</td>
<td style="padding:10px 20px;font-size:13px;color:var(--tekst-glavni);font-family:monospace;">
{{.IP}}
</td>
<td style="padding:10px 20px;font-size:12px;color:var(--tekst-sporedni);max-width:260px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">
{{.UserAgent}}
</td>
<td style="padding:10px 20px;text-align:center;">
{{if .Uspeh}}
<span style="display:inline-block;padding:2px 10px;border-radius:20px;background:#f0fdf4;color:#16a34a;font-size:11px;font-weight:500;">Uspeh</span>
{{else}}
<span style="display:inline-block;padding:2px 10px;border-radius:20px;background:#fef2f2;color:#dc2626;font-size:11px;font-weight:500;">Neuspeh</span>
{{end}}
</td>
<td style="padding:10px 20px;font-size:13px;color:var(--tekst-sporedni);">
{{if eq .Razlog "korisnik_ne_postoji"}}Korisnik ne postoji
{{else if eq .Razlog "nalog_neaktivan"}}Nalog neaktivan
{{else if eq .Razlog "pogrešna_lozinka"}}Pogrešna lozinka
{{else if eq .Razlog "ip_zaklucano"}}IP zaključano
{{else if .Uspeh}}—
{{else}}{{.Razlog}}
{{end}}
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{else}}
<div style="padding:40px 20px;text-align:center;color:var(--tekst-sporedni);font-size:14px;">
Nema zabeleženih pokušaja prijave za ovog korisnika.
</div>
{{end}}
{{if .Istorija}}
<div style="overflow-x: auto">
<table style="width: 100%; border-collapse: collapse">
<thead>
<tr style="border-bottom: 0.5px solid var(--ivica)">
<th style="padding: 10px 20px; text-align: left; font-size: 12px; font-weight: 500; color: var(--tekst-sporedni); white-space: nowrap">Datum i vreme</th>
<th style="padding: 10px 20px; text-align: left; font-size: 12px; font-weight: 500; color: var(--tekst-sporedni)">IP adresa</th>
<th style="padding: 10px 20px; text-align: left; font-size: 12px; font-weight: 500; color: var(--tekst-sporedni)">Pregledač</th>
<th style="padding: 10px 20px; text-align: center; font-size: 12px; font-weight: 500; color: var(--tekst-sporedni)">Status</th>
<th style="padding: 10px 20px; text-align: left; font-size: 12px; font-weight: 500; color: var(--tekst-sporedni)">Razlog</th>
</tr>
</thead>
<tbody>
{{range .Istorija}}
<tr class="animiraj" style="border-bottom: 0.5px solid var(--ivica)">
<td style="padding: 10px 20px; font-size: 13px; color: var(--tekst-sporedni); white-space: nowrap">{{.Vreme.Format "02.01.2006. 15:04:05"}}</td>
<td style="padding: 10px 20px; font-size: 13px; color: var(--tekst-glavni); font-family: monospace">{{.IP}}</td>
<td style="padding: 10px 20px; font-size: 12px; color: var(--tekst-sporedni); max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap">{{.UserAgent}}</td>
<td style="padding: 10px 20px; text-align: center">
{{if .Uspeh}}
<span style="display: inline-block; padding: 2px 10px; border-radius: 20px; background: #035f1f; color: #16a34a; font-size: 11px; font-weight: 500">Uspeh</span>
{{else}}
<span style="display: inline-block; padding: 2px 10px; border-radius: 20px; background: #e21313; color: #dc2626; font-size: 11px; font-weight: 500">Neuspeh</span>
{{end}}
</td>
<td style="padding: 10px 20px; font-size: 13px; color: var(--tekst-sporedni)">
{{if eq .Razlog "korisnik_ne_postoji"}}Korisnik ne postoji {{else if eq .Razlog "nalog_neaktivan"}}Nalog neaktivan {{else if eq .Razlog "pogrešna_lozinka"}}Pogrešna lozinka {{else if eq .Razlog "ip_zaklucano"}}IP zaključano {{else if .Uspeh}}— {{else}}{{.Razlog}} {{end}}
</td>
</tr>
{{end}}
</tbody>
</table>
</div>
{{else}}
<div style="padding: 40px 20px; text-align: center; color: var(--tekst-sporedni); font-size: 14px">Nema zabeleženih pokušaja prijave za ovog korisnika.</div>
{{end}}
</div>
</div>
{{end}}
+98 -120
View File
@@ -1,133 +1,111 @@
{{template "base" .}}
{{define "naslov"}}Moj profil — NTech{{end}}
{{define "dodatni-css"}}
{{ template "base" . }} {{ define "naslov" }}Moj profil — NTech{{ end }}
{{ define "dodatni-css" }}
<style>
.animiraj:nth-child(1) { animation-delay: 0.10s; }
.animiraj:nth-child(2) { animation-delay: 0.16s; }
.animiraj:nth-child(3) { animation-delay: 0.22s; }
.animiraj:nth-child(4) { animation-delay: 0.28s; }
.animiraj:nth-child(5) { animation-delay: 0.34s; }
.animiraj:nth-child(1) { animation-delay: 0.1s; }
.animiraj:nth-child(2) { animation-delay: 0.16s; }
.animiraj:nth-child(3) { animation-delay: 0.22s; }
.animiraj:nth-child(4) { animation-delay: 0.28s; }
.animiraj:nth-child(5) { animation-delay: 0.34s; }
</style>
{{end}}
{{ end }}
{{ define "sadrzaj" }}
<div style="display: flex; flex-direction: column; gap: 16px; max-width: 560px">
<!-- promena lozinke -->
<div class="kartica animiraj">
<div style="font-size: 15px; font-weight: 500; color: var(--tekst-glavni); margin-bottom: 16px; padding-bottom: 12px; border-bottom: 0.5px solid var(--ivica)">Promena lozinke</div>
{{define "sadrzaj"}}
<div style="display:flex;flex-direction:column;gap:16px;max-width:560px;">
<form method="POST" action="/admin/profil/lozinka">
<div style="display: flex; flex-direction: column; gap: 12px">
<div>
<label style="font-size: 13px; color: var(--tekst-sporedni); display: block; margin-bottom: 6px">Trenutna lozinka</label>
<input type="password" name="stara_lozinka" required style="width: 100%" />
</div>
<div>
<label style="font-size: 13px; color: var(--tekst-sporedni); display: block; margin-bottom: 6px">Nova lozinka</label>
<input type="password" name="nova_lozinka" required minlength="8" style="width: 100%" />
</div>
<div>
<label style="font-size: 13px; color: var(--tekst-sporedni); display: block; margin-bottom: 6px">Potvrda nove lozinke</label>
<input type="password" name="nova_lozinka_potvrda" required style="width: 100%" />
</div>
<div>
<button type="submit" style="padding: 9px 20px; background: var(--sb-akcent); color: #fff; border: none; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer">Sačuvaj novu lozinku</button>
</div>
</div>
</form>
</div>
<!-- promena lozinke -->
<div class="kartica animiraj">
<div style="font-size:15px;font-weight:500;color:var(--tekst-glavni);margin-bottom:16px;padding-bottom:12px;border-bottom:0.5px solid var(--ivica);">
Promena lozinke
</div>
<!-- TOTP / 2FA -->
<div class="kartica animiraj">
<div style="font-size: 15px; font-weight: 500; color: var(--tekst-glavni); margin-bottom: 16px; padding-bottom: 12px; border-bottom: 0.5px solid var(--ivica)">Dvostepena verifikacija (2FA)</div>
<form method="POST" action="/admin/profil/lozinka">
<div style="display:flex;flex-direction:column;gap:12px;">
<div>
<label style="font-size:13px;color:var(--tekst-sporedni);display:block;margin-bottom:6px;">Trenutna lozinka</label>
<input type="password" name="stara_lozinka" required style="width:100%;">
</div>
<div>
<label style="font-size:13px;color:var(--tekst-sporedni);display:block;margin-bottom:6px;">Nova lozinka</label>
<input type="password" name="nova_lozinka" required minlength="8" style="width:100%;">
</div>
<div>
<label style="font-size:13px;color:var(--tekst-sporedni);display:block;margin-bottom:6px;">Potvrda nove lozinke</label>
<input type="password" name="nova_lozinka_potvrda" required style="width:100%;">
</div>
<div>
<button type="submit"
style="padding:9px 20px;background:var(--sb-akcent);color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;">
Sačuvaj novu lozinku
</button>
</div>
</div>
</form>
</div>
{{ if .TotpURI }}
<!-- postavljanje TOTP -->
{{ if eq .Greska "totp" }}
<div class="poruka-greska" style="margin-bottom: 14px">Neispravan kod. Pokušajte ponovo.</div>
{{ end }}
<!-- TOTP / 2FA -->
<div class="kartica animiraj">
<div style="font-size:15px;font-weight:500;color:var(--tekst-glavni);margin-bottom:16px;padding-bottom:12px;border-bottom:0.5px solid var(--ivica);">
Dvostepena verifikacija (2FA)
</div>
<p style="font-size: 13px; color: var(--tekst-sporedni); margin-bottom: 16px; line-height: 1.5">Skenirajte QR kod u aplikaciji (Google Authenticator, Authy...), pa unesite generisani kod da potvrdite podešavanje.</p>
{{if .TotpURI}}
<!-- postavljanje TOTP -->
{{if eq .Greska "totp"}}
<div class="poruka-greska" style="margin-bottom:14px;">Neispravan kod. Pokušajte ponovo.</div>
{{end}}
<div style="text-align: center; margin-bottom: 16px">
<img src="{{ .TotpQR }}" alt="QR kod" style="width: 200px; height: 200px; border-radius: 8px; display: block; margin: 0 auto" />
</div>
<p style="font-size:13px;color:var(--tekst-sporedni);margin-bottom:16px;line-height:1.5;">
Skenirajte QR kod u aplikaciji (Google Authenticator, Authy...), pa unesite generisani kod da potvrdite podešavanje.
</p>
<details style="margin-bottom: 16px">
<summary style="font-size: 12px; color: var(--tekst-sporedni); cursor: pointer">Prikaži tajnu ručno</summary>
<code style="font-size: 12px; background: var(--pozadina); padding: 6px 10px; border-radius: 6px; display: block; margin-top: 8px; word-break: break-all; color: var(--tekst-glavni)">{{ .TotpTajna }}</code>
</details>
<div style="text-align:center;margin-bottom:16px;">
<img src="{{.TotpQR}}" alt="QR kod" style="width:200px;height:200px;border-radius:8px;display:block;margin:0 auto;">
</div>
<form method="POST" action="/admin/profil/totp/aktiviraj">
<input type="hidden" name="totp_tajna" value="{{ .TotpTajna }}" />
<div style="margin-bottom: 12px">
<label style="font-size: 13px; color: var(--tekst-sporedni); display: block; margin-bottom: 6px">Verifikacioni kod</label>
<input type="text" name="kod" inputmode="numeric" pattern="[0-9]{6}" maxlength="6" required autofocus style="width: 160px; font-size: 18px; text-align: center; letter-spacing: 4px" />
</div>
<button type="submit" style="padding: 9px 20px; background: var(--sb-akcent); color: #fff; border: none; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer">Potvrdi i uključi 2FA</button>
</form>
<details style="margin-bottom:16px;">
<summary style="font-size:12px;color:var(--tekst-sporedni);cursor:pointer;">Prikaži tajnu ručno</summary>
<code style="font-size:12px;background:var(--pozadina);padding:6px 10px;border-radius:6px;display:block;margin-top:8px;word-break:break-all;color:var(--tekst-glavni);">{{.TotpTajna}}</code>
</details>
{{ else if .TotpAktivan }}
<!-- 2FA je uključena -->
<div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px">
<div>
<div style="font-size: 14px; color: #16a34a; margin-bottom: 4px; font-weight: 500">✓ Dvostepena verifikacija je uključena</div>
<div style="font-size: 13px; color: var(--tekst-sporedni)">Prijava zahteva TOTP kod pored lozinke.</div>
</div>
<form method="POST" action="/admin/profil/totp/deaktiviraj" onsubmit="return confirm('Da li ste sigurni? Ovo će isključiti dvostepenu verifikaciju.');">
<button type="submit" style="padding: 9px 18px; background: #dc2626; color: #fff; border: none; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer">Deaktiviraj 2FA</button>
</form>
</div>
<form method="POST" action="/admin/profil/totp/aktiviraj">
<input type="hidden" name="totp_tajna" value="{{.TotpTajna}}">
<div style="margin-bottom:12px;">
<label style="font-size:13px;color:var(--tekst-sporedni);display:block;margin-bottom:6px;">Verifikacioni kod</label>
<input type="text" name="kod" inputmode="numeric" pattern="[0-9]{6}"
maxlength="6" required autofocus
style="width:160px;font-size:18px;text-align:center;letter-spacing:4px;">
</div>
<button type="submit"
style="padding:9px 20px;background:var(--sb-akcent);color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;">
Potvrdi i uključi 2FA
</button>
</form>
{{else if .TotpAktivan}}
<!-- 2FA je uključena -->
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;">
<div>
<div style="font-size:14px;color:#16a34a;margin-bottom:4px;font-weight:500;">✓ Dvostepena verifikacija je uključena</div>
<div style="font-size:13px;color:var(--tekst-sporedni);">Prijava zahteva TOTP kod pored lozinke.</div>
</div>
<form method="POST" action="/admin/profil/totp/deaktiviraj"
onsubmit="return confirm('Da li ste sigurni? Ovo će isključiti dvostepenu verifikaciju.')">
<button type="submit"
style="padding:9px 18px;background:#dc2626;color:#fff;border:none;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;">
Deaktiviraj 2FA
</button>
</form>
</div>
{{else}}
<!-- 2FA nije uključena -->
<div style="display:flex;align-items:center;justify-content:space-between;flex-wrap:wrap;gap:12px;">
<div>
<div style="font-size:14px;color:var(--tekst-glavni);margin-bottom:4px;">Status: <strong>Isključena</strong></div>
<div style="font-size:13px;color:var(--tekst-sporedni);">Preporučujemo uključivanje dvostepene verifikacije.</div>
</div>
<a href="/admin/profil/totp/pokreni"
style="padding:9px 18px;background:var(--sb-akcent);color:#fff;border-radius:8px;font-size:14px;font-weight:500;text-decoration:none;">
Podesi 2FA
</a>
</div>
{{end}}
</div>
{{if index .Dozvole "tema.lokalno"}}
<div class="kartica animiraj" style="background:var(--pozadina);border:0.5px solid var(--ivica);">
<div style="display:flex;align-items:center;gap:10px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--sb-akcent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="3"/><path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83"/></svg>
<span style="font-size:14px;color:var(--tekst-glavni);">
Podešavanja teme i pozadine nalaze se na
<a href="/profil/tema" style="color:var(--sb-akcent);text-decoration:none;font-weight:500;">stranici Tema</a>.
</span>
</div>
</div>
{{end}}
{{ else }}
<!-- 2FA nije uključena -->
<div style="display: flex; align-items: center; justify-content: space-between; flex-wrap: wrap; gap: 12px">
<div>
<div style="font-size: 14px; color: var(--tekst-glavni); margin-bottom: 4px">
Status:
<strong>Isključena</strong>
</div>
<div style="font-size: 13px; color: var(--tekst-sporedni)">Preporučujemo uključivanje dvostepene verifikacije.</div>
</div>
<a href="/admin/profil/totp/pokreni" style="padding: 9px 18px; background: var(--sb-akcent); color: #fff; border-radius: 8px; font-size: 14px; font-weight: 500; text-decoration: none">Podesi 2FA</a>
</div>
{{ end }}
</div>
{{ if index .Dozvole "tema.lokalno" }}
<div class="kartica animiraj" style="background: var(--pozadina); border: 0.5px solid var(--ivica)">
<div style="display: flex; align-items: center; gap: 10px">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="var(--sb-akcent)" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="12" cy="12" r="3" />
<path d="M12 1v4M12 19v4M4.22 4.22l2.83 2.83M16.95 16.95l2.83 2.83M1 12h4M19 12h4M4.22 19.78l2.83-2.83M16.95 7.05l2.83-2.83" />
</svg>
<span style="font-size: 14px; color: var(--tekst-glavni)">
Podešavanja teme i pozadine nalaze se na
<a href="/profil/tema" style="color: var(--sb-akcent); text-decoration: none; font-weight: 500">stranici Tema</a>
.
</span>
</div>
</div>
{{ end }}
</div>
{{end}}
{{ end }}
+123 -109
View File
@@ -1,125 +1,139 @@
{{template "base" .}}
{{ template "base" . }}
{{define "naslov"}}Dashboard — NTech{{end}}
{{ define "naslov" }}Dashboard — NTech{{ end }}
{{define "dodatni-css"}}
{{ define "dodatni-css" }}
<style>
.dash-stat:nth-child(1) { animation-delay: 0.04s; }
.dash-stat:nth-child(2) { animation-delay: 0.10s; }
.dash-stat:nth-child(3) { animation-delay: 0.16s; }
.dash-stat:nth-child(4) { animation-delay: 0.22s; }
.dash-stat:nth-child(5) { animation-delay: 0.28s; }
.dash-kartica:nth-child(1) { animation-delay: 0.20s; }
.dash-kartica:nth-child(2) { animation-delay: 0.28s; }
.dash-kartica:nth-child(3) { animation-delay: 0.36s; }
.dash-stat:nth-child(1) { animation-delay: 0.04s; }
.dash-stat:nth-child(2) { animation-delay: 0.10s; }
.dash-stat:nth-child(3) { animation-delay: 0.16s; }
.dash-stat:nth-child(4) { animation-delay: 0.22s; }
.dash-stat:nth-child(5) { animation-delay: 0.28s; }
.dash-kartica:nth-child(1) { animation-delay: 0.20s; }
.dash-kartica:nth-child(2) { animation-delay: 0.28s; }
.dash-kartica:nth-child(3) { animation-delay: 0.36s; }
</style>
{{end}}
{{ end }}
{{define "sadrzaj"}}
{{if .FlashGreska}}
<div class="poruka-greska animiraj" style="margin-bottom:16px;">{{.FlashGreska}}</div>
{{end}}
{{ define "sadrzaj" }}
{{ if .FlashGreska }}
<div class="poruka-greska animiraj" style="margin-bottom:16px;">{{ .FlashGreska }}</div>
{{ end }}
<div class="grid grid-cols-2 md:grid-cols-5 gap-3 mb-6">
<!-- stat kartice -->
<div class="kartica dash-stat animiraj">
<div style="width:36px;height:36px;border-radius:8px;background:#eff2ff;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#4f7ef8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z"/></svg>
</div>
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{.BrojArtikala}}</div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Artikala na stanju</div>
</div>
<!-- stat kartice -->
<div class="kartica dash-stat animiraj">
<div style="width:36px;height:36px;border-radius:8px;background:#eff2ff;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#4f7ef8" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M21 16V8a2 2 0 0 0-1-1.73l-7-4a2 2 0 0 0-2 0l-7 4A2 2 0 0 0 3 8v8a2 2 0 0 0 1 1.73l7 4a2 2 0 0 0 2 0l7-4A2 2 0 0 0 21 16z" />
</svg>
</div>
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{ .BrojArtikala }}</div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Artikala na stanju</div>
</div>
<div class="kartica dash-stat animiraj">
<div style="width:36px;height:36px;border-radius:8px;background:#f0fdf4;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z"/></svg>
</div>
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{.AktivniServisi}}</div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Aktivnih servisa</div>
</div>
<div class="kartica dash-stat animiraj">
<div style="width:36px;height:36px;border-radius:8px;background:#f0fdf4;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#16a34a" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94l-3.76 3.76z" />
</svg>
</div>
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{ .AktivniServisi }}</div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Aktivnih servisa</div>
</div>
{{if index .Dozvole "dashboard.prihod"}}
<div class="kartica dash-stat animiraj">
<div style="width:36px;height:36px;border-radius:8px;background:#fff7ed;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ea580c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><circle cx="9" cy="21" r="1"/><circle cx="20" cy="21" r="1"/><path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6"/></svg>
</div>
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{printf "%.0f" .PrihodOvogMeseca}} din</div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Prihod ovog meseca</div>
</div>
{{end}}
{{ if index .Dozvole "dashboard.prihod" }}
<div class="kartica dash-stat animiraj">
<div style="width:36px;height:36px;border-radius:8px;background:#fff7ed;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#ea580c" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<circle cx="9" cy="21" r="1" />
<circle cx="20" cy="21" r="1" />
<path d="M1 1h4l2.68 13.39a2 2 0 0 0 2 1.61h9.72a2 2 0 0 0 2-1.61L23 6H6" />
</svg>
</div>
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{ printf "%.0f" .PrihodOvogMeseca }} din</div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Prihod ovog meseca</div>
</div>
{{ end }}
<div class="kartica dash-stat animiraj">
<div style="width:36px;height:36px;border-radius:8px;background:#fef2f2;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#dc2626" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
</div>
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{.KriticnaZaliha}}</div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Kritično niska zaliha</div>
</div>
<div class="kartica dash-stat animiraj">
<div style="width:36px;height:36px;border-radius:8px;background:#fef2f2;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#dc2626" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M10.29 3.86L1.82 18a2 2 0 0 0 1.71 3h16.94a2 2 0 0 0 1.71-3L13.71 3.86a2 2 0 0 0-3.42 0z" />
<line x1="12" y1="9" x2="12" y2="13" />
<line x1="12" y1="17" x2="12.01" y2="17" />
</svg>
</div>
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{ .KriticnaZaliha }}</div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Kritično niska zaliha</div>
</div>
<a href="/podsetnici" class="kartica dash-stat animiraj" style="text-decoration:none;display:block;">
<div style="width:36px;height:36px;border-radius:8px;background:#f0f9ff;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#0284c7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9"/><path d="M13.73 21a2 2 0 0 1-3.46 0"/></svg>
</div>
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{.AktivniPodsetnici}}</div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Aktivnih podsetnika</div>
</a>
<a href="/podsetnici" class="kartica dash-stat animiraj" style="text-decoration:none;display:block;">
<div style="width:36px;height:36px;border-radius:8px;background:#f0f9ff;display:flex;align-items:center;justify-content:center;margin-bottom:10px;">
<svg xmlns="http://www.w3.org/2000/svg" width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="#0284c7" stroke-width="2" stroke-linecap="round" stroke-linejoin="round">
<path d="M18 8A6 6 0 0 0 6 8c0 7-3 9-3 9h18s-3-2-3-9" />
<path d="M13.73 21a2 2 0 0 1-3.46 0" />
</svg>
</div>
<div style="font-size:22px;font-weight:500;color:var(--tekst-glavni);">{{ .AktivniPodsetnici }}</div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:4px;">Aktivnih podsetnika</div>
</a>
</div>
<div class="grid grid-cols-1 md:grid-cols-3 gap-4">
<!-- poslednji servisi -->
<div class="kartica dash-kartica animiraj">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
<span style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">Poslednji servisi</span>
</div>
{{range .PoslednjiServisi}}
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:0.5px solid var(--ivica);">
<div style="width:8px;height:8px;border-radius:50%;flex-shrink:0;background:{{.BojaTacke}};"></div>
<span style="font-size:13px;color:var(--tekst-glavni);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{{.Uredjaj}}</span>
<span style="font-size:11px;color:var(--tekst-sporedni);white-space:nowrap;">{{.DatumPrijema}}</span>
</div>
{{else}}
<div style="font-size:13px;color:var(--tekst-sporedni);padding:8px 0;">Nema servisnih naloga.</div>
{{end}}
</div>
<!-- poslednji servisi -->
<div class="kartica dash-kartica animiraj">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
<span style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">Poslednji servisi</span>
</div>
{{ range .PoslednjiServisi }}
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:0.5px solid var(--ivica);">
<div style="width:8px;height:8px;border-radius:50%;flex-shrink:0;background:{{ .BojaTacke }};"></div>
<span style="font-size:13px;color:var(--tekst-glavni);flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{{ .Uredjaj }}</span>
<span style="font-size:11px;color:var(--tekst-sporedni);white-space:nowrap;">{{ .DatumPrijema }}</span>
</div>
{{ else }}
<div style="font-size:13px;color:var(--tekst-sporedni);padding:8px 0;">Nema servisnih naloga.</div>
{{ end }}
</div>
<!-- kritične zalihe -->
<div class="kartica dash-kartica animiraj">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
<span style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">Kritične zalihe</span>
<span style="font-size:11px;padding:2px 8px;border-radius:20px;background:rgba(220,38,38,0.15);color:#ef4444;font-weight:500;">Upozorenje</span>
</div>
{{range .KriticneZalihe}}
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:0.5px solid var(--ivica);">
<div style="width:8px;height:8px;border-radius:50%;flex-shrink:0;background:{{.BojaTacke}};"></div>
<span style="font-size:13px;color:var(--tekst-glavni);flex:1;">{{.Naziv}}</span>
<span style="font-size:12px;color:var(--tekst-sporedni);">{{.Kolicina}} kom</span>
</div>
{{else}}
<div style="font-size:13px;color:var(--tekst-sporedni);padding:8px 0;">Sve zalihe su uredne.</div>
{{end}}
</div>
<!-- kritične zalihe -->
<div class="kartica dash-kartica animiraj">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
<span style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">Kritične zalihe</span>
<span style="font-size:11px;padding:2px 8px;border-radius:20px;background:rgba(220,38,38,0.15);color:#ef4444;font-weight:500;">Upozorenje</span>
</div>
{{ range .KriticneZalihe }}
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:0.5px solid var(--ivica);">
<div style="width:8px;height:8px;border-radius:50%;flex-shrink:0;background:{{ .BojaTacke }};"></div>
<span style="font-size:13px;color:var(--tekst-glavni);flex:1;">{{ .Naziv }}</span>
<span style="font-size:12px;color:var(--tekst-sporedni);">{{ .Kolicina }} kom</span>
</div>
{{ else }}
<div style="font-size:13px;color:var(--tekst-sporedni);padding:8px 0;">Sve zalihe su uredne.</div>
{{ end }}
</div>
<!-- poslednje prodaje -->
<div class="kartica dash-kartica animiraj">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
<span style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">Poslednje prodaje</span>
</div>
{{range .PoslednjeProdaje}}
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:0.5px solid var(--ivica);">
<div style="flex:1;min-width:0;">
<div style="font-size:13px;color:var(--tekst-glavni);font-family:monospace;">{{.BrojNaloga}}</div>
{{if .KlijentNaziv}}
<div style="font-size:11px;color:var(--tekst-sporedni);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{{.KlijentNaziv}}</div>
{{end}}
</div>
<div style="text-align:right;flex-shrink:0;">
<div style="font-size:13px;font-weight:500;color:var(--tekst-glavni);">{{printf "%.0f" .Ukupno}} din</div>
<div style="font-size:11px;color:var(--tekst-sporedni);margin-top:1px;">{{.Datum}}</div>
</div>
</div>
{{else}}
<div style="font-size:13px;color:var(--tekst-sporedni);padding:8px 0;">Nema prodajnih naloga.</div>
{{end}}
</div>
<!-- poslednje prodaje -->
<div class="kartica dash-kartica animiraj">
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:14px;">
<span style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">Poslednje prodaje</span>
</div>
{{ range .PoslednjeProdaje }}
<div style="display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:0.5px solid var(--ivica);">
<div style="flex:1;min-width:0;">
<div style="font-size:13px;color:var(--tekst-glavni);font-family:monospace;">{{ .BrojNaloga }}</div>
{{ if .KlijentNaziv }}
<div style="font-size:11px;color:var(--tekst-sporedni);margin-top:1px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;">{{ .KlijentNaziv }}</div>
{{ end }}
</div>
<div style="text-align:right;flex-shrink:0;">
<div style="font-size:13px;font-weight:500;color:var(--tekst-glavni);">{{ printf "%.0f" .Ukupno }} din</div>
<div style="font-size:11px;color:var(--tekst-sporedni);margin-top:1px;">{{ .Datum }}</div>
</div>
</div>
{{ else }}
<div style="font-size:13px;color:var(--tekst-sporedni);padding:8px 0;">Nema prodajnih naloga.</div>
{{ end }}
</div>
</div>
{{end}}
{{ end }}
+25 -28
View File
@@ -4,35 +4,32 @@
{{define "dodatni-css"}}
<style>
.poruka-animacija { animation: slideDown 0.3s ease forwards; }
/* stagger — svaki red se pojavljuje malo kasnije */
.dobavljaci-tabela tbody tr:nth-child(1) { animation-delay: 0.04s; }
.dobavljaci-tabela tbody tr:nth-child(2) { animation-delay: 0.08s; }
.dobavljaci-tabela tbody tr:nth-child(3) { animation-delay: 0.12s; }
.dobavljaci-tabela tbody tr:nth-child(4) { animation-delay: 0.16s; }
.dobavljaci-tabela tbody tr:nth-child(5) { animation-delay: 0.20s; }
.dobavljaci-tabela tbody tr:nth-child(6) { animation-delay: 0.24s; }
.dobavljaci-tabela tbody tr:nth-child(7) { animation-delay: 0.28s; }
.dobavljaci-tabela tbody tr:nth-child(8) { animation-delay: 0.32s; }
.dobavljaci-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.dobavljaci-tabela tbody tr:nth-child(10) { animation-delay: 0.40s; }
.dobavljaci-kartice {
display: none;
flex-direction: column;
gap: 12px;
}
.dobavljac-kartica:nth-child(1) { animation-delay: 0.04s; }
.dobavljac-kartica:nth-child(2) { animation-delay: 0.10s; }
.dobavljac-kartica:nth-child(3) { animation-delay: 0.16s; }
.dobavljac-kartica:nth-child(4) { animation-delay: 0.22s; }
.dobavljac-kartica:nth-child(5) { animation-delay: 0.28s; }
.poruka-animacija { animation: slideDown 0.3s ease forwards; }
.dobavljaci-tabela tbody tr:nth-child(1) { animation-delay: 0.04s; }
.dobavljaci-tabela tbody tr:nth-child(2) { animation-delay: 0.08s; }
.dobavljaci-tabela tbody tr:nth-child(3) { animation-delay: 0.12s; }
.dobavljaci-tabela tbody tr:nth-child(4) { animation-delay: 0.16s; }
.dobavljaci-tabela tbody tr:nth-child(5) { animation-delay: 0.20s; }
.dobavljaci-tabela tbody tr:nth-child(6) { animation-delay: 0.24s; }
.dobavljaci-tabela tbody tr:nth-child(7) { animation-delay: 0.28s; }
.dobavljaci-tabela tbody tr:nth-child(8) { animation-delay: 0.32s; }
.dobavljaci-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.dobavljaci-tabela tbody tr:nth-child(10) { animation-delay: 0.40s; }
.dobavljaci-kartice { display: none; flex-direction: column; gap: 12px; }
.dobavljac-kartica:nth-child(1) { animation-delay: 0.04s; }
.dobavljac-kartica:nth-child(2) { animation-delay: 0.10s; }
.dobavljac-kartica:nth-child(3) { animation-delay: 0.16s; }
.dobavljac-kartica:nth-child(4) { animation-delay: 0.22s; }
.dobavljac-kartica:nth-child(5) { animation-delay: 0.28s; }
@media (max-width: 768px) {
.dobavljaci-tabela { display: none; }
.dobavljaci-kartice { display: flex; }
.dobavljaci-tabela {
display: none;
}
.dobavljaci-kartice {
display: flex;
}
}
</style>
{{end}}
@@ -163,4 +160,4 @@
</div>
</div>
{{end}}
{{end}}
+8 -74
View File
@@ -5,88 +5,22 @@
{{define "dodatni-css"}}
<script src="https://cdn.jsdelivr.net/npm/chart.js@4.4.4/dist/chart.umd.min.js"></script>
<style>
.izv-naslov {
font-size: 13px;
font-weight: 500;
color: var(--tekst-sporedni);
text-transform: uppercase;
letter-spacing: 0.05em;
margin-bottom: 14px;
}
.toggle-red {
display: flex;
align-items: center;
gap: 10px;
margin-bottom: 16px;
}
.toggle-switch {
position: relative;
display: inline-block;
width: 40px;
height: 22px;
flex-shrink: 0;
}
.izv-naslov { font-size: 13px; font-weight: 500; color: var(--tekst-sporedni); text-transform: uppercase; letter-spacing: 0.05em; margin-bottom: 14px; }
.toggle-red { display: flex; align-items: center; gap: 10px; margin-bottom: 16px; }
.toggle-switch { position: relative; display: inline-block; width: 40px; height: 22px; flex-shrink: 0; }
.toggle-switch input { opacity: 0; width: 0; height: 0; }
.toggle-slider {
position: absolute;
inset: 0;
background: var(--ivica);
border-radius: 22px;
cursor: pointer;
transition: background 0.2s;
}
.toggle-slider::before {
content: '';
position: absolute;
width: 16px;
height: 16px;
left: 3px;
top: 3px;
background: #fff;
border-radius: 50%;
transition: transform 0.2s;
}
.toggle-slider { position: absolute; inset: 0; background: var(--ivica); border-radius: 22px; cursor: pointer; transition: background 0.2s; }
.toggle-slider::before { content: ''; position: absolute; width: 16px; height: 16px; left: 3px; top: 3px; background: #fff; border-radius: 50%; transition: transform 0.2s; }
.toggle-switch input:checked + .toggle-slider { background: var(--sb-akcent); }
.toggle-switch input:checked + .toggle-slider::before { transform: translateX(18px); }
.rang-broj {
display: inline-flex;
align-items: center;
justify-content: center;
width: 22px;
height: 22px;
border-radius: 50%;
background: var(--pozadina);
font-size: 11px;
font-weight: 600;
color: var(--tekst-sporedni);
flex-shrink: 0;
}
.rang-broj { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border-radius: 50%; background: var(--pozadina); font-size: 11px; font-weight: 600; color: var(--tekst-sporedni); flex-shrink: 0; }
.rang-broj.zlatni { background: #fef3c7; color: #92400e; }
.badge-dana {
display: inline-block;
padding: 2px 8px;
border-radius: 20px;
font-size: 11px;
font-weight: 500;
white-space: nowrap;
}
.badge-dana { display: inline-block; padding: 2px 8px; border-radius: 20px; font-size: 11px; font-weight: 500; white-space: nowrap; }
.badge-dana.upozorenje { background: #fffbeb; color: #b45309; }
.badge-dana.kritican { background: #fef2f2; color: #dc2626; }
.badge-dana.kritican { background: #fef2f2; color: #dc2626; }
.izv-sekcija:nth-child(1) { animation-delay: 0.04s; }
.izv-sekcija:nth-child(2) { animation-delay: 0.12s; }
.izv-sekcija:nth-child(3) { animation-delay: 0.20s; }
.izv-grid-kartica:nth-child(1) { animation-delay: 0.24s; }
.izv-grid-kartica:nth-child(2) { animation-delay: 0.32s; }
</style>
+1 -5
View File
@@ -5,11 +5,7 @@
{{define "dodatni-css"}}
<style>
.poruka-animacija { animation: slideDown 0.3s ease forwards; }
.kat-forma-kartica {
animation-delay: 0.04s;
}
.kat-forma-kartica { animation-delay: 0.04s; }
.kat-red:nth-child(1) { animation-delay: 0.12s; }
.kat-red:nth-child(2) { animation-delay: 0.18s; }
.kat-red:nth-child(3) { animation-delay: 0.24s; }
+16 -27
View File
@@ -5,34 +5,23 @@
{{define "dodatni-css"}}
<style>
.poruka-animacija { animation: slideDown 0.3s ease forwards; }
.klijenti-tabela tbody tr:nth-child(1) { animation-delay: 0.04s; }
.klijenti-tabela tbody tr:nth-child(2) { animation-delay: 0.08s; }
.klijenti-tabela tbody tr:nth-child(3) { animation-delay: 0.12s; }
.klijenti-tabela tbody tr:nth-child(4) { animation-delay: 0.16s; }
.klijenti-tabela tbody tr:nth-child(5) { animation-delay: 0.20s; }
.klijenti-tabela tbody tr:nth-child(6) { animation-delay: 0.24s; }
.klijenti-tabela tbody tr:nth-child(7) { animation-delay: 0.28s; }
.klijenti-tabela tbody tr:nth-child(8) { animation-delay: 0.32s; }
.klijenti-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.klijenti-tabela tbody tr:nth-child(1) { animation-delay: 0.04s; }
.klijenti-tabela tbody tr:nth-child(2) { animation-delay: 0.08s; }
.klijenti-tabela tbody tr:nth-child(3) { animation-delay: 0.12s; }
.klijenti-tabela tbody tr:nth-child(4) { animation-delay: 0.16s; }
.klijenti-tabela tbody tr:nth-child(5) { animation-delay: 0.20s; }
.klijenti-tabela tbody tr:nth-child(6) { animation-delay: 0.24s; }
.klijenti-tabela tbody tr:nth-child(7) { animation-delay: 0.28s; }
.klijenti-tabela tbody tr:nth-child(8) { animation-delay: 0.32s; }
.klijenti-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.klijenti-tabela tbody tr:nth-child(10) { animation-delay: 0.40s; }
.klijenti-kartice {
display: none;
flex-direction: column;
gap: 12px;
}
.klijent-kartica:nth-child(1) { animation-delay: 0.04s; }
.klijent-kartica:nth-child(2) { animation-delay: 0.10s; }
.klijent-kartica:nth-child(3) { animation-delay: 0.16s; }
.klijent-kartica:nth-child(4) { animation-delay: 0.22s; }
.klijent-kartica:nth-child(5) { animation-delay: 0.28s; }
@media (max-width: 768px) {
.klijenti-tabela { display: none; }
.klijenti-kartice { display: flex; }
}
.klijenti-kartice { display: none; flex-direction: column; gap: 12px; }
.klijent-kartica:nth-child(1) { animation-delay: 0.04s; }
.klijent-kartica:nth-child(2) { animation-delay: 0.10s; }
.klijent-kartica:nth-child(3) { animation-delay: 0.16s; }
.klijent-kartica:nth-child(4) { animation-delay: 0.22s; }
.klijent-kartica:nth-child(5) { animation-delay: 0.28s; }
@media (max-width: 768px) { .klijenti-tabela { display: none; } .klijenti-kartice { display: flex; } }
</style>
{{end}}
+11 -21
View File
@@ -4,33 +4,23 @@
{{define "dodatni-css"}}
<style>
.magacin-tabela tbody tr:nth-child(1) { animation-delay: 0.04s; }
.magacin-tabela tbody tr:nth-child(2) { animation-delay: 0.08s; }
.magacin-tabela tbody tr:nth-child(3) { animation-delay: 0.12s; }
.magacin-tabela tbody tr:nth-child(4) { animation-delay: 0.16s; }
.magacin-tabela tbody tr:nth-child(5) { animation-delay: 0.20s; }
.magacin-tabela tbody tr:nth-child(6) { animation-delay: 0.24s; }
.magacin-tabela tbody tr:nth-child(7) { animation-delay: 0.28s; }
.magacin-tabela tbody tr:nth-child(8) { animation-delay: 0.32s; }
.magacin-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.magacin-tabela tbody tr:nth-child(1) { animation-delay: 0.04s; }
.magacin-tabela tbody tr:nth-child(2) { animation-delay: 0.08s; }
.magacin-tabela tbody tr:nth-child(3) { animation-delay: 0.12s; }
.magacin-tabela tbody tr:nth-child(4) { animation-delay: 0.16s; }
.magacin-tabela tbody tr:nth-child(5) { animation-delay: 0.20s; }
.magacin-tabela tbody tr:nth-child(6) { animation-delay: 0.24s; }
.magacin-tabela tbody tr:nth-child(7) { animation-delay: 0.28s; }
.magacin-tabela tbody tr:nth-child(8) { animation-delay: 0.32s; }
.magacin-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.magacin-tabela tbody tr:nth-child(10) { animation-delay: 0.40s; }
.magacin-kartice {
display: none;
flex-direction: column;
gap: 12px;
}
.magacin-kartice { display: none; flex-direction: column; gap: 12px; }
.magacin-kartica:nth-child(1) { animation-delay: 0.04s; }
.magacin-kartica:nth-child(2) { animation-delay: 0.10s; }
.magacin-kartica:nth-child(3) { animation-delay: 0.16s; }
.magacin-kartica:nth-child(4) { animation-delay: 0.22s; }
.magacin-kartica:nth-child(5) { animation-delay: 0.28s; }
@media (max-width: 768px) {
.magacin-tabela { display: none; }
.magacin-kartice { display: flex; }
}
@media (max-width: 768px) { .magacin-tabela { display: none; } .magacin-kartice { display: flex; } }
</style>
{{end}}
+2 -12
View File
@@ -7,23 +7,13 @@
.detalji-kartica:nth-child(1) { animation-delay: 0.04s; }
.detalji-kartica:nth-child(2) { animation-delay: 0.12s; }
.detalji-kartica:nth-child(3) { animation-delay: 0.20s; }
.stavke-tabela tbody tr:nth-child(1) { animation-delay: 0.16s; }
.stavke-tabela tbody tr:nth-child(2) { animation-delay: 0.20s; }
.stavke-tabela tbody tr:nth-child(3) { animation-delay: 0.24s; }
.stavke-tabela tbody tr:nth-child(4) { animation-delay: 0.28s; }
.stavke-tabela tbody tr:nth-child(5) { animation-delay: 0.32s; }
.stavke-kartice {
display: none;
flex-direction: column;
gap: 10px;
}
@media (max-width: 768px) {
.stavke-tabela-wrapper { display: none; }
.stavke-kartice { display: flex; }
}
.stavke-kartice { display: none; flex-direction: column; gap: 10px; }
@media (max-width: 768px) { .stavke-tabela-wrapper { display: none; } .stavke-kartice { display: flex; } }
</style>
{{end}}
+2 -12
View File
@@ -4,22 +4,12 @@
{{define "dodatni-css"}}
<style>
@keyframes modalIn {
from { opacity: 0; transform: translateY(-16px) scale(0.97); }
to { opacity: 1; transform: translateY(0) scale(1); }
}
@keyframes modalIn { from { opacity: 0; transform: translateY(-16px) scale(0.97); } to { opacity: 1; transform: translateY(0) scale(1); } }
.forma-kartica:nth-child(1) { animation-delay: 0.04s; }
.forma-kartica:nth-child(2) { animation-delay: 0.12s; }
.greska-animacija { animation: shake 0.4s ease; }
.modal-sadrzaj { animation: modalIn 0.25s ease forwards; }
@media (max-width: 768px) {
.stavke-tabela-wrapper { display: none; }
.stavke-kartice { display: flex !important; }
}
@media (max-width: 768px) { .stavke-tabela-wrapper { display: none; } .stavke-kartice { display: flex !important; } }
</style>
{{end}}
+11 -22
View File
@@ -5,34 +5,23 @@
{{define "dodatni-css"}}
<style>
.poruka-animacija { animation: slideDown 0.3s ease forwards; }
.nabavke-tabela tbody tr:nth-child(1) { animation-delay: 0.04s; }
.nabavke-tabela tbody tr:nth-child(2) { animation-delay: 0.08s; }
.nabavke-tabela tbody tr:nth-child(3) { animation-delay: 0.12s; }
.nabavke-tabela tbody tr:nth-child(4) { animation-delay: 0.16s; }
.nabavke-tabela tbody tr:nth-child(5) { animation-delay: 0.20s; }
.nabavke-tabela tbody tr:nth-child(6) { animation-delay: 0.24s; }
.nabavke-tabela tbody tr:nth-child(7) { animation-delay: 0.28s; }
.nabavke-tabela tbody tr:nth-child(8) { animation-delay: 0.32s; }
.nabavke-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.nabavke-tabela tbody tr:nth-child(1) { animation-delay: 0.04s; }
.nabavke-tabela tbody tr:nth-child(2) { animation-delay: 0.08s; }
.nabavke-tabela tbody tr:nth-child(3) { animation-delay: 0.12s; }
.nabavke-tabela tbody tr:nth-child(4) { animation-delay: 0.16s; }
.nabavke-tabela tbody tr:nth-child(5) { animation-delay: 0.20s; }
.nabavke-tabela tbody tr:nth-child(6) { animation-delay: 0.24s; }
.nabavke-tabela tbody tr:nth-child(7) { animation-delay: 0.28s; }
.nabavke-tabela tbody tr:nth-child(8) { animation-delay: 0.32s; }
.nabavke-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.nabavke-tabela tbody tr:nth-child(10) { animation-delay: 0.40s; }
.nabavke-kartice {
display: none;
flex-direction: column;
gap: 12px;
}
.nabavke-kartice { display: none; flex-direction: column; gap: 12px; }
.nabavka-kartica:nth-child(1) { animation-delay: 0.04s; }
.nabavka-kartica:nth-child(2) { animation-delay: 0.10s; }
.nabavka-kartica:nth-child(3) { animation-delay: 0.16s; }
.nabavka-kartica:nth-child(4) { animation-delay: 0.22s; }
.nabavka-kartica:nth-child(5) { animation-delay: 0.28s; }
@media (max-width: 768px) {
.nabavke-tabela { display: none; }
.nabavke-kartice { display: flex; }
}
@media (max-width: 768px) { .nabavke-tabela { display: none; } .nabavke-kartice { display: flex; } }
</style>
{{end}}
+9 -66
View File
@@ -8,74 +8,17 @@
.animiraj:nth-child(2) { animation-delay: 0.16s; }
.animiraj:nth-child(3) { animation-delay: 0.22s; }
.animiraj:nth-child(4) { animation-delay: 0.28s; }
/* dvostupčani raspored za app pozadinu */
.app-poz-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
align-items: start;
}
@media (max-width: 680px) {
.app-poz-grid { grid-template-columns: 1fr; }
}
/* custom file input */
.custom-file-label {
display: flex;
align-items: center;
gap: 8px;
padding: 8px 12px;
background: var(--pozadina);
border: 0.5px solid var(--ivica);
border-radius: 8px;
font-size: 13px;
color: var(--tekst-sporedni);
cursor: pointer;
transition: border-color 0.2s;
min-width: 0;
overflow: hidden;
}
.app-poz-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }
@media (max-width: 680px) { .app-poz-grid { grid-template-columns: 1fr; } }
.custom-file-label { display: flex; align-items: center; gap: 8px; padding: 8px 12px; background: var(--pozadina); border: 0.5px solid var(--ivica); border-radius: 8px; font-size: 13px; color: var(--tekst-sporedni); cursor: pointer; transition: border-color 0.2s; min-width: 0; overflow: hidden; }
.custom-file-label:hover { border-color: var(--sb-akcent); color: var(--tekst-glavni); }
.custom-file-label span { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
.toast {
position: fixed;
bottom: 24px;
right: 24px;
z-index: 9999;
display: flex;
align-items: center;
gap: 10px;
padding: 12px 18px;
border-radius: 10px;
font-size: 13px;
font-weight: 500;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
animation: toastIn 0.3s ease forwards;
max-width: 340px;
}
.toast-greska {
background: #fef2f2;
color: #dc2626;
border: 0.5px solid #fca5a5;
}
.toast-uspeh {
background: #f0fdf4;
color: #16a34a;
border: 0.5px solid #86efac;
}
@keyframes toastIn {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes toastOut {
from { opacity: 1; transform: translateY(0); }
to { opacity: 0; transform: translateY(12px); }
}
.toast.nestaje {
animation: toastOut 0.3s ease forwards;
}
.toast { position: fixed; bottom: 24px; right: 24px; z-index: 9999; display: flex; align-items: center; gap: 10px; padding: 12px 18px; border-radius: 10px; font-size: 13px; font-weight: 500; box-shadow: 0 4px 20px rgba(0,0,0,0.15); animation: toastIn 0.3s ease forwards; max-width: 340px; }
.toast-greska { background: #fef2f2; color: #dc2626; border: 0.5px solid #fca5a5; }
.toast-uspeh { background: #f0fdf4; color: #16a34a; border: 0.5px solid #86efac; }
@keyframes toastIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
@keyframes toastOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(12px); } }
.toast.nestaje { animation: toastOut 0.3s ease forwards; }
</style>
{{end}}
+2 -10
View File
@@ -7,16 +7,8 @@
.animiraj:nth-child(1) { animation-delay: 0.10s; }
.animiraj:nth-child(2) { animation-delay: 0.16s; }
.animiraj:nth-child(3) { animation-delay: 0.22s; }
.app-poz-grid {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
align-items: start;
}
@media (max-width: 680px) {
.app-poz-grid { grid-template-columns: 1fr; }
}
.app-poz-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; align-items: start; }
@media (max-width: 680px) { .app-poz-grid { grid-template-columns: 1fr; } }
</style>
{{end}}
+6 -37
View File
@@ -7,43 +7,12 @@
.animiraj:nth-child(1) { animation-delay: 0.10s; }
.animiraj:nth-child(2) { animation-delay: 0.16s; }
.toast {
position: fixed;
bottom: 24px;
right: 24px;
z-index: 9999;
display: flex;
align-items: center;
gap: 10px;
padding: 12px 18px;
border-radius: 10px;
font-size: 13px;
font-weight: 500;
box-shadow: 0 4px 20px rgba(0,0,0,0.15);
animation: toastIn 0.3s ease forwards;
max-width: 340px;
}
.toast-greska {
background: #fef2f2;
color: #dc2626;
border: 0.5px solid #fca5a5;
}
.toast-uspeh {
background: #f0fdf4;
color: #16a34a;
border: 0.5px solid #86efac;
}
@keyframes toastIn {
from { opacity: 0; transform: translateY(12px); }
to { opacity: 1; transform: translateY(0); }
}
@keyframes toastOut {
from { opacity: 1; transform: translateY(0); }
to { opacity: 0; transform: translateY(12px); }
}
.toast.nestaje {
animation: toastOut 0.3s ease forwards;
}
.toast { position: fixed; bottom: 24px; right: 24px; z-index: 9999; display: flex; align-items: center; gap: 10px; padding: 12px 18px; border-radius: 10px; font-size: 13px; font-weight: 500; box-shadow: 0 4px 20px rgba(0,0,0,0.15); animation: toastIn 0.3s ease forwards; max-width: 340px; }
.toast-greska { background: #fef2f2; color: #dc2626; border: 0.5px solid #fca5a5; }
.toast-uspeh { background: #f0fdf4; color: #16a34a; border: 0.5px solid #86efac; }
@keyframes toastIn { from { opacity: 0; transform: translateY(12px); } to { opacity: 1; transform: translateY(0); } }
@keyframes toastOut { from { opacity: 1; transform: translateY(0); } to { opacity: 0; transform: translateY(12px); } }
.toast.nestaje { animation: toastOut 0.3s ease forwards; }
</style>
{{end}}
+3 -15
View File
@@ -17,26 +17,14 @@
.pod-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.pod-tabela tbody tr:nth-child(10) { animation-delay: 0.40s; }
.pod-kartice {
display: none;
flex-direction: column;
gap: 12px;
}
.pod-kartice { display: none; flex-direction: column; gap: 12px; }
.pod-kartica:nth-child(1) { animation-delay: 0.04s; }
.pod-kartica:nth-child(2) { animation-delay: 0.10s; }
.pod-kartica:nth-child(3) { animation-delay: 0.16s; }
.pod-kartica:nth-child(4) { animation-delay: 0.22s; }
.pod-kartica:nth-child(5) { animation-delay: 0.28s; }
.red-prekoracen td {
background: rgba(207, 87, 87, 0.06);
}
@media (max-width: 768px) {
.pod-tabela { display: none; }
.pod-kartice { display: flex; }
}
.red-prekoracen td { background: rgba(207, 87, 87, 0.06); }
@media (max-width: 768px) { .pod-tabela { display: none; } .pod-kartice { display: flex; } }
</style>
{{end}}
+1 -3
View File
@@ -4,9 +4,7 @@
{{define "dodatni-css"}}
<style>
.greska-animacija {
animation: shake 0.4s ease;
}
.greska-animacija { animation: shake 0.4s ease; }
</style>
{{end}}
+66 -152
View File
@@ -1,160 +1,74 @@
<!DOCTYPE html>
<html lang="sr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Prijava — NTech</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #0f1117;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
position: relative;
}
.kartica {
background: #1a1d27;
border: 0.5px solid #2d3148;
border-radius: 16px;
padding: 40px;
width: 100%;
max-width: 380px;
}
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Prijava — NTech</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0f1117; min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 16px; position: relative; }
.kartica { background: #1a1d27; border: 0.5px solid #2d3148; border-radius: 16px; padding: 40px; width: 100%; max-width: 380px; }
{{if .LoginPozadina}}.kartica { background: rgba(0, 0, 0, {{.LoginPozadinaZatamnjenjeKartice}}%) !important; backdrop-filter: blur({{.LoginPozadinaBlurKartice}}px); -webkit-backdrop-filter: blur({{.LoginPozadinaBlurKartice}}px); border: 1px solid rgba(255, 255, 255, 0.18) !important; box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); }{{end}}
.logo { text-align: center; margin-bottom: 32px; }
.logo-naziv { font-size: 22px; font-weight: 600; color: #fff; letter-spacing: -0.3px; }
.logo-podnazlov { font-size: 13px; color: #6b7280; margin-top: 4px; }
h1 { font-size: 18px; font-weight: 600; color: #fff; margin-bottom: 24px; }
.polje { margin-bottom: 16px; }
label { display: block; font-size: 13px; color: #9ca3af; margin-bottom: 6px; }
input { width: 100%; padding: 8px 12px; background: #0f1117; border: 0.5px solid #2d3148; border-radius: 8px; font-size: 14px; color: #fff; outline: none; transition: border-color 0.2s; }
input:focus { border-color: #e53e3e; }
.dugme { width: 100%; padding: 11px; background: #e53e3e; color: #fff; border: none; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; margin-top: 8px; transition: opacity 0.2s; }
.dugme:hover { opacity: 0.88; }
.greska { background: #fef2f2; border: 0.5px solid #fca5a5; color: #dc2626; border-radius: 8px; padding: 10px 14px; font-size: 13px; margin-bottom: 20px; }
.uspeh { background: #f0fdf4; border: 0.5px solid #86efac; color: #16a34a; border-radius: 8px; padding: 10px 14px; font-size: 13px; margin-bottom: 20px; }
</style>
</head>
<body>
{{if .LoginPozadina}}
.kartica {
background: rgba(0,0,0,{{.LoginPozadinaZatamnjenjeKartice}}%) !important;
backdrop-filter: blur({{.LoginPozadinaBlurKartice}}px);
-webkit-backdrop-filter: blur({{.LoginPozadinaBlurKartice}}px);
border: 1px solid rgba(255,255,255,0.18) !important;
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
}
{{end}}
.logo {
text-align: center;
margin-bottom: 32px;
}
.logo-naziv {
font-size: 22px;
font-weight: 600;
color: #fff;
letter-spacing: -0.3px;
}
.logo-podnazlov {
font-size: 13px;
color: #6b7280;
margin-top: 4px;
}
h1 {
font-size: 18px;
font-weight: 600;
color: #fff;
margin-bottom: 24px;
}
.polje { margin-bottom: 16px; }
label {
display: block;
font-size: 13px;
color: #9ca3af;
margin-bottom: 6px;
}
input {
width: 100%;
padding: 8px 12px;
background: #0f1117;
border: 0.5px solid #2d3148;
border-radius: 8px;
font-size: 14px;
color: #fff;
outline: none;
transition: border-color 0.2s;
}
input:focus { border-color: #e53e3e; }
.dugme {
width: 100%;
padding: 11px;
background: #e53e3e;
color: #fff;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
margin-top: 8px;
transition: opacity 0.2s;
}
.dugme:hover { opacity: 0.88; }
.greska {
background: #fef2f2;
border: 0.5px solid #fca5a5;
color: #dc2626;
border-radius: 8px;
padding: 10px 14px;
font-size: 13px;
margin-bottom: 20px;
}
.uspeh {
background: #f0fdf4;
border: 0.5px solid #86efac;
color: #16a34a;
border-radius: 8px;
padding: 10px 14px;
font-size: 13px;
margin-bottom: 20px;
}
</style>
</head>
<body>
{{if .LoginPozadina}}
<div style="position:fixed;inset:0;z-index:-1;background-image:url('{{.LoginPozadina}}');background-size:cover;background-position:center;{{if ne .LoginPozadinaBlurPozadine "0"}}filter:blur({{.LoginPozadinaBlurPozadine}}px);transform:scale(1.05);{{end}}"></div>
<div style="position:fixed;inset:0;z-index:0;background:rgba(0,0,0,{{.LoginPozadinaOpacity}}%);"></div>
<div style="position:fixed;inset:0;display:flex;align-items:center;justify-content:center;z-index:1;padding:16px;">
{{end}}
<div style="position:fixed;inset:0;z-index:-1;background-image:url('{{.LoginPozadina}}');background-size:cover;background-position:center;{{if ne .LoginPozadinaBlurPozadine " 0"}}filter:blur({{.LoginPozadinaBlurPozadine}}px);transform:scale(1.05);{{end}}"></div>
<div style="position:fixed;inset:0;z-index:0;background:rgba(0,0,0,{{.LoginPozadinaOpacity}}%);"></div>
<div style="position:fixed;inset:0;display:flex;align-items:center;justify-content:center;z-index:1;padding:16px;">
{{end}}
<div class="kartica animiraj">
<div class="logo">
<div class="logo-naziv">NTech</div>
<div class="logo-podnazlov">Sistem za upravljanje</div>
</div>
<div class="kartica animiraj">
<div class="logo">
<div class="logo-naziv">NTech</div>
<div class="logo-podnazlov">Sistem za upravljanje</div>
</div>
<h1>Prijava</h1>
<h1>Prijava</h1>
{{if eq .Greska "1"}}
<div class="greska">Pogrešno korisničko ime ili lozinka.</div>
{{else if eq .Greska "2"}}
<div class="greska">Greška na serveru. Pokušajte ponovo.</div>
{{else if eq .Greska "zakljucano"}}
<div class="greska">
Previše neuspelih pokušaja prijave. IP adresa je privremeno blokirana.
{{if .Preostalo}}<br>Pokušajte ponovo za: <strong>{{.Preostalo}}</strong>{{end}}
{{if eq .Greska "1"}}
<div class="greska">Pogrešno korisničko ime ili lozinka.</div>
{{else if eq .Greska "2"}}
<div class="greska">Greška na serveru. Pokušajte ponovo.</div>
{{else if eq .Greska "zakljucano"}}
<div class="greska">
Previše neuspelih pokušaja prijave. IP adresa je privremeno blokirana.
{{if .Preostalo}}<br>Pokušajte ponovo za: <strong>{{.Preostalo}}</strong>{{end}}
</div>
{{end}}
{{if .Sacuvano}}
<div class="uspeh">Nalog je kreiran. Možete se prijaviti.</div>
{{end}}
<form method="POST" action="/prijava">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<div class="polje">
<label for="korisnicko_ime">Korisničko ime</label>
<input type="text" id="korisnicko_ime" name="korisnicko_ime" autocomplete="username" autofocus required>
</div>
<div class="polje">
<label for="lozinka">Lozinka</label>
<input type="password" id="lozinka" name="lozinka" autocomplete="current-password" required>
</div>
<button type="submit" class="dugme">Prijavi se</button>
</form>
</div>
{{if .LoginPozadina}}
</div>
{{end}}
{{if .Sacuvano}}
<div class="uspeh">Nalog je kreiran. Možete se prijaviti.</div>
{{end}}
<form method="POST" action="/prijava">
<input type="hidden" name="_csrf" value="{{.CsrfToken}}">
<div class="polje">
<label for="korisnicko_ime">Korisničko ime</label>
<input type="text" id="korisnicko_ime" name="korisnicko_ime"
autocomplete="username" autofocus required>
</div>
<div class="polje">
<label for="lozinka">Lozinka</label>
<input type="password" id="lozinka" name="lozinka"
autocomplete="current-password" required>
</div>
<button type="submit" class="dugme">Prijavi se</button>
</form>
</div>
{{if .LoginPozadina}}
</div>
{{end}}
</body>
</html>
</body>
</html>
+57 -102
View File
@@ -1,103 +1,71 @@
{{template "base" .}}
{{define "naslov"}}Prodaja — NTech{{end}}
{{define "dodatni-css"}}
{{template "base" .}} {{define "naslov"}}Prodaja — NTech{{end}} {{define "dodatni-css"}}
<style>
.poruka-animacija { animation: slideDown 0.3s ease forwards; }
.prodaja-tabela tbody tr:nth-child(1) { animation-delay: 0.04s; }
.prodaja-tabela tbody tr:nth-child(2) { animation-delay: 0.08s; }
.prodaja-tabela tbody tr:nth-child(3) { animation-delay: 0.12s; }
.prodaja-tabela tbody tr:nth-child(4) { animation-delay: 0.16s; }
.prodaja-tabela tbody tr:nth-child(5) { animation-delay: 0.20s; }
.prodaja-tabela tbody tr:nth-child(6) { animation-delay: 0.24s; }
.prodaja-tabela tbody tr:nth-child(7) { animation-delay: 0.28s; }
.prodaja-tabela tbody tr:nth-child(8) { animation-delay: 0.32s; }
.prodaja-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.prodaja-tabela tbody tr:nth-child(10) { animation-delay: 0.40s; }
.prodaja-kartice {
display: none;
flex-direction: column;
gap: 12px;
}
.prodaja-kartica:nth-child(1) { animation-delay: 0.04s; }
.prodaja-kartica:nth-child(2) { animation-delay: 0.10s; }
.prodaja-kartica:nth-child(3) { animation-delay: 0.16s; }
.prodaja-kartica:nth-child(4) { animation-delay: 0.22s; }
.prodaja-kartica:nth-child(5) { animation-delay: 0.28s; }
@media (max-width: 768px) {
.prodaja-tabela { display: none; }
.prodaja-kartice { display: flex; }
}
.poruka-animacija { animation: slideDown 0.3s ease forwards; }
.prodaja-tabela tbody tr:nth-child(1) { animation-delay: 0.04s; }
.prodaja-tabela tbody tr:nth-child(2) { animation-delay: 0.08s; }
.prodaja-tabela tbody tr:nth-child(3) { animation-delay: 0.12s; }
.prodaja-tabela tbody tr:nth-child(4) { animation-delay: 0.16s; }
.prodaja-tabela tbody tr:nth-child(5) { animation-delay: 0.2s; }
.prodaja-tabela tbody tr:nth-child(6) { animation-delay: 0.24s; }
.prodaja-tabela tbody tr:nth-child(7) { animation-delay: 0.28s; }
.prodaja-tabela tbody tr:nth-child(8) { animation-delay: 0.32s; }
.prodaja-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.prodaja-tabela tbody tr:nth-child(10) { animation-delay: 0.4s; }
.prodaja-kartice { display: none; flex-direction: column; gap: 12px; }
.prodaja-kartica:nth-child(1) { animation-delay: 0.04s; }
.prodaja-kartica:nth-child(2) { animation-delay: 0.1s; }
.prodaja-kartica:nth-child(3) { animation-delay: 0.16s; }
.prodaja-kartica:nth-child(4) { animation-delay: 0.22s; }
.prodaja-kartica:nth-child(5) { animation-delay: 0.28s; }
@media (max-width: 768px) { .prodaja-tabela { display: none; } .prodaja-kartice { display: flex; } }
</style>
{{end}}
{{define "sadrzaj"}}
<div style="display:flex;flex-direction:column;gap:16px;">
{{end}} {{define "sadrzaj"}}
<div style="display: flex; flex-direction: column; gap: 16px">
{{if .Sacuvano}}
<div class="poruka-uspeh poruka-animacija">Prodaja je uspešno sačuvana.</div>
{{end}}
{{if .Obrisan}}
{{end}} {{if .Obrisan}}
<div class="poruka-uspeh poruka-animacija">Prodajni nalog je uspešno obrisan.</div>
{{end}}
<!-- zaglavlje sa pretragom i dugmetom -->
<div style="display:flex;align-items:center;gap:10px;flex-wrap:wrap;">
<form method="GET" action="/prodaja" style="display:flex;gap:8px;flex:1;min-width:200px;">
<input type="text" name="pretraga" value="{{.Pretraga}}"
placeholder="Pretraži po broju naloga..."
style="flex:1;">
<button type="submit" class="btn-sekundarno" style="white-space:nowrap;">Pretraži</button>
<div style="display: flex; align-items: center; gap: 10px; flex-wrap: wrap">
<form method="GET" action="/prodaja" style="display: flex; gap: 8px; flex: 1; min-width: 200px">
<input type="text" name="pretraga" value="{{.Pretraga}}" placeholder="Pretraži po broju naloga..." style="flex: 1" />
<button type="submit" class="btn-sekundarno" style="white-space: nowrap">Pretraži</button>
{{if .Pretraga}}
<a href="/prodaja" class="btn-sekundarno" style="white-space:nowrap;">✕ Resetuj</a>
<a href="/prodaja" class="btn-sekundarno" style="white-space: nowrap">✕ Resetuj</a>
{{end}}
</form>
<a href="/prodaja/nova" class="btn-primarno">+ Nova prodaja</a>
</div>
<!-- desktop tabela -->
<div class="kartica prodaja-tabela animiraj" style="padding:0;overflow:hidden;">
<div style="overflow-x:auto;">
<table style="width:100%;border-collapse:collapse;">
<div class="kartica prodaja-tabela animiraj" style="padding: 0; overflow: hidden">
<div style="overflow-x: auto">
<table style="width: 100%; border-collapse: collapse">
<thead>
<tr style="border-bottom:0.5px solid var(--ivica);">
<th style="padding:12px 16px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Broj naloga</th>
<th style="padding:12px 16px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Datum</th>
<th style="padding:12px 16px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Klijent</th>
<th style="padding:12px 16px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Ukupno</th>
<th style="padding:12px 16px;text-align:center;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Akcije</th>
<tr style="border-bottom: 0.5px solid var(--ivica)">
<th style="padding: 12px 16px; text-align: left; font-size: 12px; font-weight: 500; color: var(--tekst-sporedni)">Broj naloga</th>
<th style="padding: 12px 16px; text-align: left; font-size: 12px; font-weight: 500; color: var(--tekst-sporedni)">Datum</th>
<th style="padding: 12px 16px; text-align: left; font-size: 12px; font-weight: 500; color: var(--tekst-sporedni)">Klijent</th>
<th style="padding: 12px 16px; text-align: right; font-size: 12px; font-weight: 500; color: var(--tekst-sporedni)">Ukupno</th>
<th style="padding: 12px 16px; text-align: center; font-size: 12px; font-weight: 500; color: var(--tekst-sporedni)">Akcije</th>
</tr>
</thead>
<tbody>
{{range .Nalozi}}
<tr class="animiraj red-tabele">
<td style="padding:12px 16px;font-size:13px;font-family:monospace;color:var(--tekst-glavni);">
{{.BrojNaloga}}
</td>
<td style="padding:12px 16px;font-size:13px;color:var(--tekst-sporedni);white-space:nowrap;">
{{.Datum.Format "02.01.2006."}}
</td>
<td style="padding:12px 16px;font-size:14px;font-weight:500;color:var(--tekst-glavni);">
{{if .KlijentNaziv}}{{.KlijentNaziv}}{{else}}—{{end}}
</td>
<td style="padding:12px 16px;text-align:right;font-size:14px;font-weight:500;color:var(--tekst-glavni);">
{{printf "%.2f" .Ukupno}} din
</td>
<td style="padding:12px 16px;text-align:center;">
<div style="display:flex;align-items:center;justify-content:center;gap:8px;">
<td style="padding: 12px 16px; font-size: 13px; font-family: monospace; color: var(--tekst-glavni)">{{.BrojNaloga}}</td>
<td style="padding: 12px 16px; font-size: 13px; color: var(--tekst-sporedni); white-space: nowrap">{{.Datum.Format "02.01.2006."}}</td>
<td style="padding: 12px 16px; font-size: 14px; font-weight: 500; color: var(--tekst-glavni)">{{if .KlijentNaziv}}{{.KlijentNaziv}}{{else}}—{{end}}</td>
<td style="padding: 12px 16px; text-align: right; font-size: 14px; font-weight: 500; color: var(--tekst-glavni)">{{printf "%.2f" .Ukupno}} din</td>
<td style="padding: 12px 16px; text-align: center">
<div style="display: flex; align-items: center; justify-content: center; gap: 8px">
<a href="/prodaja/{{.ID}}" class="btn-primarno-malo">Detalji</a>
{{if index $.Dozvole "prodaja.storno"}}
<form method="POST" action="/prodaja/storno/{{.ID}}" style="margin:0;padding:0;">
<input type="hidden" name="_csrf" value="{{$.CsrfToken}}">
<button type="submit" class="btn-obrisi-malo"
data-potvrda="Da li ste sigurni da želite da stornirate ovaj nalog? Artikli će biti vraćeni na stanje.">
Storno
</button>
<form method="POST" action="/prodaja/storno/{{.ID}}" style="margin: 0; padding: 0">
<input type="hidden" name="_csrf" value="{{$.CsrfToken}}" />
<button type="submit" class="btn-obrisi-malo" data-potvrda="Da li ste sigurni da želite da stornirate ovaj nalog? Artikli će biti vraćeni na stanje.">Storno</button>
</form>
{{end}}
</div>
@@ -105,11 +73,9 @@
</tr>
{{else}}
<tr>
<td colspan="5" style="padding:32px;text-align:center;font-size:14px;color:var(--tekst-sporedni);">
{{if $.Pretraga}}
Nema naloga koji odgovaraju pretrazi.
{{else}}
Nema prodajnih naloga. <a href="/prodaja/nova" style="color:var(--sb-akcent);">Dodaj prvu prodaju.</a>
<td colspan="5" style="padding: 32px; text-align: center; font-size: 14px; color: var(--tekst-sporedni)">
{{if $.Pretraga}} Nema naloga koji odgovaraju pretrazi. {{else}} Nema prodajnih naloga.
<a href="/prodaja/nova" style="color: var(--sb-akcent)">Dodaj prvu prodaju.</a>
{{end}}
</td>
</tr>
@@ -123,34 +89,23 @@
<div class="prodaja-kartice">
{{range .Nalozi}}
<div class="kartica prodaja-kartica animiraj">
<div style="display:flex;justify-content:space-between;align-items:flex-start;gap:12px;margin-bottom:10px;">
<div style="display: flex; justify-content: space-between; align-items: flex-start; gap: 12px; margin-bottom: 10px">
<div>
<div style="font-size:13px;font-family:monospace;color:var(--tekst-glavni);">{{.BrojNaloga}}</div>
<div style="font-size:14px;font-weight:500;color:var(--tekst-glavni);margin-top:2px;">
{{if .KlijentNaziv}}{{.KlijentNaziv}}{{else}}Bez klijenta{{end}}
</div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-top:2px;">
{{.Datum.Format "02.01.2006."}}
</div>
</div>
<div style="font-size:15px;font-weight:500;color:var(--tekst-glavni);white-space:nowrap;">
{{printf "%.2f" .Ukupno}} din
<div style="font-size: 13px; font-family: monospace; color: var(--tekst-glavni)">{{.BrojNaloga}}</div>
<div style="font-size: 14px; font-weight: 500; color: var(--tekst-glavni); margin-top: 2px">{{if .KlijentNaziv}}{{.KlijentNaziv}}{{else}}Bez klijenta{{end}}</div>
<div style="font-size: 12px; color: var(--tekst-sporedni); margin-top: 2px">{{.Datum.Format "02.01.2006."}}</div>
</div>
<div style="font-size: 15px; font-weight: 500; color: var(--tekst-glavni); white-space: nowrap">{{printf "%.2f" .Ukupno}} din</div>
</div>
<a href="/prodaja/{{.ID}}" class="btn-primarno-malo" style="justify-content:center;width:100%;box-sizing:border-box;">
Detalji
</a>
<a href="/prodaja/{{.ID}}" class="btn-primarno-malo" style="justify-content: center; width: 100%; box-sizing: border-box">Detalji</a>
</div>
{{else}}
<div style="padding:32px;text-align:center;font-size:14px;color:var(--tekst-sporedni);">
{{if $.Pretraga}}
Nema naloga koji odgovaraju pretrazi.
{{else}}
Nema prodajnih naloga. <a href="/prodaja/nova" style="color:var(--sb-akcent);">Dodaj prvu prodaju.</a>
<div style="padding: 32px; text-align: center; font-size: 14px; color: var(--tekst-sporedni)">
{{if $.Pretraga}} Nema naloga koji odgovaraju pretrazi. {{else}} Nema prodajnih naloga.
<a href="/prodaja/nova" style="color: var(--sb-akcent)">Dodaj prvu prodaju.</a>
{{end}}
</div>
{{end}}
</div>
</div>
{{end}}
+292 -107
View File
@@ -1,119 +1,304 @@
{{template "base" .}}
{{define "naslov"}}Detalji prodaje — NTech{{end}}
{{define "dodatni-css"}}
{{template "base" .}} {{define "naslov"}}Detalji prodaje — NTech{{end}} {{define
"dodatni-css"}}
<style>
.detalji-kartica:nth-child(1) { animation-delay: 0.04s; }
.detalji-kartica:nth-child(2) { animation-delay: 0.12s; }
.detalji-kartica:nth-child(3) { animation-delay: 0.20s; }
.poruka-animacija { animation: slideDown 0.3s ease forwards; }
.detalji-kartica:nth-child(1) { animation-delay: 0.04s; }
.detalji-kartica:nth-child(2) { animation-delay: 0.12s; }
.detalji-kartica:nth-child(3) { animation-delay: 0.2s; }
.poruka-animacija { animation: slideDown 0.3s ease forwards; }
</style>
{{end}}
{{end}} {{define "sadrzaj"}}
<div style="display: flex; flex-direction: column; gap: 16px">
{{if .Sacuvano}}
<div class="poruka-uspeh poruka-animacija">Prodaja je uspešno sačuvana.</div>
{{end}}
{{define "sadrzaj"}}
<div style="display:flex;flex-direction:column;gap:16px;">
<!-- nazad dugme -->
<a href="/prodaja" class="nazad-link">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true">
<polyline points="15 18 9 12 15 6" />
</svg>
Nazad na prodaju
</a>
{{if .Sacuvano}}
<div class="poruka-uspeh poruka-animacija">Prodaja je uspešno sačuvana.</div>
{{end}}
<!-- nazad dugme -->
<a href="/prodaja" class="nazad-link">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
Nazad na prodaju
</a>
<!-- zaglavlje naloga -->
<div class="kartica detalji-kartica animiraj">
<div style="display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:10px;margin-bottom:16px;padding-bottom:14px;border-bottom:0.5px solid var(--ivica);">
<span style="font-size:20px;font-weight:600;color:var(--tekst-glavni);font-family:monospace;">
{{.Nalog.BrojNaloga}}
</span>
<a href="/prodaja/{{.Nalog.ID}}/stampa" target="_blank" class="btn-sekundarno" style="gap:6px;">
<svg xmlns="http://www.w3.org/2000/svg" width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="6 9 6 2 18 2 18 9"/><path d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2"/><rect x="6" y="14" width="12" height="8"/></svg>
Štampaj
</a>
</div>
<div style="display:grid;grid-template-columns:repeat(auto-fit, minmax(140px, 1fr));gap:16px;">
<div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Datum prodaje</div>
<div style="font-size:14px;color:var(--tekst-glavni);">{{.Nalog.Datum.Format "02.01.2006. u 15:04"}}</div>
</div>
<div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Klijent</div>
<div style="font-size:14px;font-weight:500;color:var(--tekst-glavni);">
{{if .KlijentNaziv}}{{.KlijentNaziv}}{{else}}—{{end}}
</div>
</div>
<div>
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Ukupno</div>
<div style="font-size:20px;font-weight:600;color:var(--sb-akcent);">{{printf "%.2f" .Nalog.Ukupno}} din</div>
</div>
{{if .Nalog.Napomena}}
<div style="grid-column:1/-1;">
<div style="font-size:12px;color:var(--tekst-sporedni);margin-bottom:4px;">Napomena</div>
<div style="font-size:13px;color:var(--tekst-sporedni);">{{.Nalog.Napomena}}</div>
</div>
{{end}}
</div>
<!-- zaglavlje naloga -->
<div class="kartica detalji-kartica animiraj">
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 16px;
padding-bottom: 14px;
border-bottom: 0.5px solid var(--ivica);
">
<span
style="
font-size: 20px;
font-weight: 600;
color: var(--tekst-glavni);
font-family: monospace;
">
{{.Nalog.BrojNaloga}}
</span>
<a
href="/prodaja/{{.Nalog.ID}}/stampa"
target="_blank"
class="btn-sekundarno"
style="gap: 6px">
<svg
xmlns="http://www.w3.org/2000/svg"
width="14"
height="14"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true">
<polyline points="6 9 6 2 18 2 18 9" />
<path
d="M6 18H4a2 2 0 0 1-2-2v-5a2 2 0 0 1 2-2h16a2 2 0 0 1 2 2v5a2 2 0 0 1-2 2h-2" />
<rect x="6" y="14" width="12" height="8" />
</svg>
Štampaj
</a>
</div>
<!-- stavke -->
<div class="kartica detalji-kartica animiraj" style="padding:0;overflow:hidden;">
<div style="padding:16px 20px;border-bottom:0.5px solid var(--ivica);">
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Stavke</span>
<div
style="
display: grid;
grid-template-columns: repeat(auto-fit, minmax(140px, 1fr));
gap: 16px;
">
<div>
<div
style="
font-size: 12px;
color: var(--tekst-sporedni);
margin-bottom: 4px;
">
Datum prodaje
</div>
<div style="overflow-x:auto;">
<table style="width:100%;border-collapse:collapse;">
<thead>
<tr style="border-bottom:0.5px solid var(--ivica);">
<th style="padding:10px 20px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Artikal</th>
<th style="padding:10px 20px;text-align:center;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:90px;">Količina</th>
<th style="padding:10px 20px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:140px;">Cena/kom</th>
<th style="padding:10px 20px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:120px;">Ukupno</th>
</tr>
</thead>
<tbody>
{{range .Stavke}}
<tr style="border-bottom:0.5px solid var(--ivica);">
<td style="padding:10px 20px;font-size:14px;color:var(--tekst-glavni);">{{.ArtikalNaziv}}</td>
<td style="padding:10px 20px;text-align:center;font-size:14px;color:var(--tekst-glavni);">{{.Kolicina}}</td>
<td style="padding:10px 20px;text-align:right;font-size:14px;color:var(--tekst-sporedni);">{{printf "%.2f" .CenaPoKomadu}} din</td>
<td style="padding:10px 20px;text-align:right;font-size:14px;font-weight:500;color:var(--tekst-glavni);">{{printf "%.2f" .Ukupno}} din</td>
</tr>
{{end}}
</tbody>
<tfoot>
<tr style="border-top:0.5px solid var(--ivica);">
<td colspan="3" style="padding:12px 20px;text-align:right;font-size:13px;font-weight:500;color:var(--tekst-sporedni);">Ukupno:</td>
<td style="padding:12px 20px;text-align:right;font-size:16px;font-weight:600;color:var(--sb-akcent);">{{printf "%.2f" .Nalog.Ukupno}} din</td>
</tr>
</tfoot>
</table>
<div style="font-size: 14px; color: var(--tekst-glavni)">
{{.Nalog.Datum.Format "02.01.2006. u 15:04"}}
</div>
</div>
<div>
<div
style="
font-size: 12px;
color: var(--tekst-sporedni);
margin-bottom: 4px;
">
Klijent
</div>
<div
style="font-size: 14px; font-weight: 500; color: var(--tekst-glavni)">
{{if .KlijentNaziv}}{{.KlijentNaziv}}{{else}}—{{end}}
</div>
</div>
<div>
<div
style="
font-size: 12px;
color: var(--tekst-sporedni);
margin-bottom: 4px;
">
Ukupno
</div>
<div style="font-size: 20px; font-weight: 600; color: var(--sb-akcent)">
{{printf "%.2f" .Nalog.Ukupno}} din
</div>
</div>
{{if .Nalog.Napomena}}
<div style="grid-column: 1/-1">
<div
style="
font-size: 12px;
color: var(--tekst-sporedni);
margin-bottom: 4px;
">
Napomena
</div>
<div style="font-size: 13px; color: var(--tekst-sporedni)">
{{.Nalog.Napomena}}
</div>
</div>
{{end}}
</div>
</div>
{{if index $.Dozvole "prodaja.obrisi"}}
<!-- zona za brisanje -->
<div class="kartica detalji-kartica animiraj" style="border-color:#dc262633;">
<div style="display:flex;align-items:flex-start;gap:12px;flex-wrap:wrap;">
<div style="flex:1;min-width:200px;">
<div style="font-size:14px;font-weight:500;color:#dc2626;margin-bottom:4px;">Brisanje naloga</div>
<div style="font-size:13px;color:var(--tekst-sporedni);">
Brisanje je trajno. Količine artikala biće vraćene na stanje u magacinu.
</div>
</div>
<form method="POST" action="/prodaja/obrisi/{{.Nalog.ID}}">
<button type="submit" class="btn-primarno" style="background:#dc2626;"
data-potvrda="Da li ste sigurni da želite da obrišete nalog {{.Nalog.BrojNaloga}}? Količine artikala biće vraćene na stanje.">
Obriši nalog
</button>
</form>
</div>
<!-- stavke -->
<div
class="kartica detalji-kartica animiraj"
style="padding: 0; overflow: hidden">
<div style="padding: 16px 20px; border-bottom: 0.5px solid var(--ivica)">
<span
style="font-size: 15px; font-weight: 500; color: var(--tekst-glavni)">Stavke</span>
</div>
{{end}}
<div style="overflow-x: auto">
<table style="width: 100%; border-collapse: collapse">
<thead>
<tr style="border-bottom: 0.5px solid var(--ivica)">
<th
style="
padding: 10px 20px;
text-align: left;
font-size: 12px;
font-weight: 500;
color: var(--tekst-sporedni);
">
Artikal
</th>
<th
style="
padding: 10px 20px;
text-align: center;
font-size: 12px;
font-weight: 500;
color: var(--tekst-sporedni);
width: 90px;
">
Količina
</th>
<th
style="
padding: 10px 20px;
text-align: right;
font-size: 12px;
font-weight: 500;
color: var(--tekst-sporedni);
width: 140px;
">
Cena/kom
</th>
<th
style="
padding: 10px 20px;
text-align: right;
font-size: 12px;
font-weight: 500;
color: var(--tekst-sporedni);
width: 120px;
">
Ukupno
</th>
</tr>
</thead>
<tbody>
{{range .Stavke}}
<tr style="border-bottom: 0.5px solid var(--ivica)">
<td
style="
padding: 10px 20px;
font-size: 14px;
color: var(--tekst-glavni);
">
{{.ArtikalNaziv}}
</td>
<td
style="
padding: 10px 20px;
text-align: center;
font-size: 14px;
color: var(--tekst-glavni);
">
{{.Kolicina}}
</td>
<td
style="
padding: 10px 20px;
text-align: right;
font-size: 14px;
color: var(--tekst-sporedni);
">
{{printf "%.2f" .CenaPoKomadu}} din
</td>
<td
style="
padding: 10px 20px;
text-align: right;
font-size: 14px;
font-weight: 500;
color: var(--tekst-glavni);
">
{{printf "%.2f" .Ukupno}} din
</td>
</tr>
{{end}}
</tbody>
<tfoot>
<tr style="border-top: 0.5px solid var(--ivica)">
<td
colspan="3"
style="
padding: 12px 20px;
text-align: right;
font-size: 13px;
font-weight: 500;
color: var(--tekst-sporedni);
">
Ukupno:
</td>
<td
style="
padding: 12px 20px;
text-align: right;
font-size: 16px;
font-weight: 600;
color: var(--sb-akcent);
">
{{printf "%.2f" .Nalog.Ukupno}} din
</td>
</tr>
</tfoot>
</table>
</div>
</div>
{{if index $.Dozvole "prodaja.obrisi"}}
<!-- zona za brisanje -->
<div class="kartica detalji-kartica animiraj" style="border-color: #dc262633">
<div
style="display: flex; align-items: flex-start; gap: 12px; flex-wrap: wrap">
<div style="flex: 1; min-width: 200px">
<div
style="
font-size: 14px;
font-weight: 500;
color: #dc2626;
margin-bottom: 4px;
">
Brisanje naloga
</div>
<div style="font-size: 13px; color: var(--tekst-sporedni)">
Brisanje je trajno. Količine artikala biće vraćene na stanje u
magacinu.
</div>
</div>
<form method="POST" action="/prodaja/obrisi/{{.Nalog.ID}}">
<button
type="submit"
class="btn-primarno"
style="background: #dc2626"
data-potvrda="Da li ste sigurni da želite da obrišete nalog {{.Nalog.BrojNaloga}}? Količine artikala biće vraćene na stanje.">
Obriši nalog
</button>
</form>
</div>
</div>
{{end}}
</div>
{{end}}
{{end}}
+414 -194
View File
@@ -1,28 +1,21 @@
{{template "base" .}}
{{define "naslov"}}Nova prodaja — NTech{{end}}
{{define "dodatni-css"}}
{{template "base" .}} {{define "naslov"}}Nova prodaja — NTech{{end}} {{define
"dodatni-css"}}
<style>
.forma-kartica:nth-child(1) { animation-delay: 0.04s; }
.forma-kartica:nth-child(2) { animation-delay: 0.12s; }
.greska-animacija { animation: shake 0.4s ease; }
@media (max-width: 768px) {
.stavke-tabela-wrapper { display: none; }
.stavke-kartice { display: flex !important; }
}
.forma-kartica:nth-child(1) { animation-delay: 0.04s; }
.forma-kartica:nth-child(2) { animation-delay: 0.12s; }
.greska-animacija { animation: shake 0.4s ease; }
@media (max-width: 768px) { .stavke-tabela-wrapper { display: none; } .stavke-kartice { display: flex !important; } }
</style>
{{end}}
{{define "sadrzaj"}}
{{end}} {{define "sadrzaj"}}
<!-- lista artikala kao JSON — sadrži id, naziv i prodajnu cenu -->
<script>var _ntechArtikli = {{.ArtikliJSON}};</script>
<script>
var _ntechArtikli = {{.ArtikliJSON }};
</script>
<div style="width:100%;"
x-data="{
<div
style="width: 100%"
x-data="{
stavke: [{artikal_id: '', kolicina: 1, cena: 0}],
artikliOpcije: _ntechArtikli,
isMobile: window.matchMedia('(max-width: 768px)').matches,
@@ -66,190 +59,417 @@
return this.stavke.reduce((z, s) => z + (parseFloat(s.kolicina) * parseFloat(s.cena) || 0), 0).toFixed(2);
}
}">
<!-- nazad dugme -->
<a href="/prodaja" class="nazad-link">
<svg
xmlns="http://www.w3.org/2000/svg"
width="16"
height="16"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
aria-hidden="true">
<polyline points="15 18 9 12 15 6" />
</svg>
Nazad na prodaju
</a>
<!-- nazad dugme -->
<a href="/prodaja" class="nazad-link">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><polyline points="15 18 9 12 15 6"/></svg>
Nazad na prodaju
</a>
<form method="POST" action="/prodaja/nova">
{{if .Greska}}
<div class="poruka-greska greska-animacija">{{.Greska}}</div>
{{end}}
<form method="POST" action="/prodaja/nova">
<!-- zaglavlje prodaje -->
<div class="kartica forma-kartica animiraj" style="margin-bottom: 16px">
<div
style="
margin-bottom: 16px;
padding-bottom: 14px;
border-bottom: 0.5px solid var(--ivica);
">
<span
style="font-size: 16px; font-weight: 500; color: var(--tekst-glavni)">Nova prodaja</span>
</div>
<div style="display: flex; flex-direction: column; gap: 14px">
<div>
<label
style="
font-size: 13px;
color: var(--tekst-sporedni);
display: block;
margin-bottom: 6px;
">Klijent</label>
<select name="klijent_id" style="width: 100%">
<option value="">— bez klijenta —</option>
{{range .Klijenti}}
<option value="{{.ID}}">
{{if .NazivFirme}}{{.NazivFirme}}{{else}}{{.Ime}}
{{.Prezime}}{{end}}
</option>
{{end}}
</select>
</div>
<div>
<label
style="
font-size: 13px;
color: var(--tekst-sporedni);
display: block;
margin-bottom: 6px;
">Napomena</label>
<textarea
name="napomena"
rows="2"
placeholder="Interna napomena o prodaji..."
style="width: 100%; resize: vertical"></textarea>
</div>
</div>
</div>
{{if .Greska}}
<div class="poruka-greska greska-animacija">{{.Greska}}</div>
{{end}}
<!-- stavke -->
<div class="kartica forma-kartica animiraj" style="margin-bottom: 16px">
<div
style="
margin-bottom: 16px;
padding-bottom: 14px;
border-bottom: 0.5px solid var(--ivica);
display: flex;
justify-content: space-between;
align-items: center;
flex-wrap: wrap;
gap: 8px;
">
<span
style="font-size: 16px; font-weight: 500; color: var(--tekst-glavni)">Stavke</span>
<button
type="button"
@click="dodajStavku()"
class="btn-primarno"
style="font-size: 13px; padding: 6px 14px">
+ Dodaj stavku
</button>
</div>
<!-- zaglavlje prodaje -->
<div class="kartica forma-kartica animiraj" style="margin-bottom:16px;">
<div style="margin-bottom:16px;padding-bottom:14px;border-bottom:0.5px solid var(--ivica);">
<span style="font-size:16px;font-weight:500;color:var(--tekst-glavni);">Nova prodaja</span>
<!-- desktop tabela stavki -->
<div class="stavke-tabela-wrapper" style="overflow-x: auto">
<table style="width: 100%; border-collapse: collapse">
<thead>
<tr style="border-bottom: 0.5px solid var(--ivica)">
<th
style="
padding: 8px 10px;
text-align: left;
font-size: 12px;
font-weight: 500;
color: var(--tekst-sporedni);
">
Artikal
</th>
<th
style="
padding: 8px 10px;
text-align: center;
font-size: 12px;
font-weight: 500;
color: var(--tekst-sporedni);
width: 90px;
">
Količina
</th>
<th
style="
padding: 8px 10px;
text-align: right;
font-size: 12px;
font-weight: 500;
color: var(--tekst-sporedni);
width: 140px;
">
Cena/kom (din)
</th>
<th
style="
padding: 8px 10px;
text-align: right;
font-size: 12px;
font-weight: 500;
color: var(--tekst-sporedni);
width: 110px;
">
Ukupno
</th>
<th style="width: 40px"></th>
</tr>
</thead>
<tbody>
<template x-for="(stavka, i) in stavke" :key="i">
<tr style="border-bottom: 0.5px solid var(--ivica)">
<td style="padding: 8px 10px">
<select
:name="'artikal_id[]'"
x-model="stavka.artikal_id"
@change="popuniCenu(stavka)"
:disabled="isMobile"
style="width: 100%">
<option value="">— odaberi artikal —</option>
<template x-for="a in artikliOpcije" :key="a.id">
<option :value="a.id" x-text="a.naziv"></option>
</template>
</select>
</td>
<td style="padding: 8px 10px">
<input
type="number"
:name="'kolicina[]'"
x-model="stavka.kolicina"
min="1"
:disabled="isMobile"
:style="prekoracenje(i) ? 'border-color:#dc2626;' : ''"
style="width: 100%; text-align: center" />
<div
x-show="stavka.artikal_id"
:style="prekoracenje(i) ? 'color:#dc2626' : 'color:var(--tekst-sporedni)'"
x-text="'Na stanju: ' + dostupnaKolicina(i)"
style="
font-size: 11px;
margin-top: 3px;
text-align: center;
white-space: nowrap;
"></div>
<div
x-show="prekoracenje(i)"
style="
font-size: 11px;
color: #dc2626;
margin-top: 1px;
text-align: center;
white-space: nowrap;
">
Prekoračena količina
</div>
</td>
<td style="padding: 8px 10px">
<input
type="number"
:name="'cena_po_komadu[]'"
x-model="stavka.cena"
min="0"
step="0.01"
:disabled="isMobile"
style="width: 100%; text-align: right" />
</td>
<td
style="
padding: 8px 10px;
text-align: right;
font-size: 14px;
font-weight: 500;
color: var(--tekst-glavni);
">
<span x-text="ukupnoStavke(stavka) + ' din'"></span>
</td>
<td style="padding: 8px 10px; text-align: center">
<button
type="button"
@click="ukloniStavku(i)"
x-show="stavke.length > 1"
style="
background: none;
border: none;
cursor: pointer;
color: #dc2626;
font-size: 18px;
line-height: 1;
padding: 2px 6px;
border-radius: 4px;
transition: background 0.15s;
"
onmouseover="this.style.background = 'rgba(220,38,38,0.08)'"
onmouseout="this.style.background = 'none'"
title="Ukloni stavku">
×
</button>
</td>
</tr>
</template>
</tbody>
<tfoot>
<tr style="border-top: 0.5px solid var(--ivica)">
<td
colspan="3"
style="
padding: 10px;
text-align: right;
font-size: 13px;
color: var(--tekst-sporedni);
font-weight: 500;
">
Ukupno:
</td>
<td
style="
padding: 10px;
text-align: right;
font-size: 15px;
font-weight: 600;
color: var(--tekst-glavni);
">
<span x-text="ukupnoSvega() + ' din'"></span>
</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
<!-- mobilne kartice stavki -->
<div
class="stavke-kartice"
style="display: none; flex-direction: column; gap: 10px">
<template x-for="(stavka, i) in stavke" :key="i">
<div
style="
border: 0.5px solid var(--ivica);
border-radius: 8px;
padding: 12px;
">
<div
style="
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 10px;
">
<span
style="
font-size: 13px;
font-weight: 500;
color: var(--tekst-sporedni);
"
x-text="'Stavka ' + (i + 1)"></span>
<button
type="button"
@click="ukloniStavku(i)"
x-show="stavke.length > 1"
style="
background: none;
border: 0.5px solid #dc2626;
color: #dc2626;
cursor: pointer;
font-size: 13px;
padding: 2px 8px;
border-radius: 4px;
">
Ukloni
</button>
</div>
<div style="display:flex;flex-direction:column;gap:14px;">
<div style="display: flex; flex-direction: column; gap: 10px">
<div>
<label
style="
font-size: 12px;
color: var(--tekst-sporedni);
display: block;
margin-bottom: 4px;
">Artikal</label>
<select
:name="'artikal_id[]'"
x-model="stavka.artikal_id"
@change="popuniCenu(stavka)"
:disabled="!isMobile"
style="width: 100%">
<option value="">— odaberi artikal —</option>
<template x-for="a in artikliOpcije" :key="a.id">
<option :value="a.id" x-text="a.naziv"></option>
</template>
</select>
</div>
<div
style="display: grid; grid-template-columns: 1fr 1fr; gap: 10px">
<div>
<label style="font-size:13px;color:var(--tekst-sporedni);display:block;margin-bottom:6px;">Klijent</label>
<select name="klijent_id" style="width:100%;">
<option value="">— bez klijenta —</option>
{{range .Klijenti}}
<option value="{{.ID}}">
{{if .NazivFirme}}{{.NazivFirme}}{{else}}{{.Ime}} {{.Prezime}}{{end}}
</option>
{{end}}
</select>
<label
style="
font-size: 12px;
color: var(--tekst-sporedni);
display: block;
margin-bottom: 4px;
">Količina</label>
<input
type="number"
:name="'kolicina[]'"
x-model="stavka.kolicina"
min="1"
:disabled="!isMobile"
:style="prekoracenje(i) ? 'border-color:#dc2626;' : ''"
style="width: 100%" />
<div
x-show="stavka.artikal_id"
:style="prekoracenje(i) ? 'color:#dc2626' : 'color:var(--tekst-sporedni)'"
x-text="'Na stanju: ' + dostupnaKolicina(i)"
style="font-size: 11px; margin-top: 3px"></div>
<div
x-show="prekoracenje(i)"
style="font-size: 11px; color: #dc2626; margin-top: 1px">
Prekoračena količina
</div>
</div>
<div>
<label style="font-size:13px;color:var(--tekst-sporedni);display:block;margin-bottom:6px;">Napomena</label>
<textarea name="napomena" rows="2"
placeholder="Interna napomena o prodaji..."
style="width:100%;resize:vertical;"></textarea>
<label
style="
font-size: 12px;
color: var(--tekst-sporedni);
display: block;
margin-bottom: 4px;
">Cena/kom (din)</label>
<input
type="number"
:name="'cena_po_komadu[]'"
x-model="stavka.cena"
min="0"
step="0.01"
:disabled="!isMobile"
style="width: 100%" />
</div>
</div>
<div
style="
text-align: right;
font-size: 14px;
font-weight: 500;
color: var(--tekst-glavni);
">
Ukupno: <span x-text="ukupnoStavke(stavka) + ' din'"></span>
</div>
</div>
</div>
</template>
<div
style="
text-align: right;
font-size: 15px;
font-weight: 600;
color: var(--tekst-glavni);
padding: 8px 4px;
">
Ukupno: <span x-text="ukupnoSvega() + ' din'"></span>
</div>
</div>
</div>
<!-- stavke -->
<div class="kartica forma-kartica animiraj" style="margin-bottom:16px;">
<div style="margin-bottom:16px;padding-bottom:14px;border-bottom:0.5px solid var(--ivica);display:flex;justify-content:space-between;align-items:center;flex-wrap:wrap;gap:8px;">
<span style="font-size:16px;font-weight:500;color:var(--tekst-glavni);">Stavke</span>
<button type="button" @click="dodajStavku()" class="btn-primarno" style="font-size:13px;padding:6px 14px;">
+ Dodaj stavku
</button>
</div>
<!-- desktop tabela stavki -->
<div class="stavke-tabela-wrapper" style="overflow-x:auto;">
<table style="width:100%;border-collapse:collapse;">
<thead>
<tr style="border-bottom:0.5px solid var(--ivica);">
<th style="padding:8px 10px;text-align:left;font-size:12px;font-weight:500;color:var(--tekst-sporedni);">Artikal</th>
<th style="padding:8px 10px;text-align:center;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:90px;">Količina</th>
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:140px;">Cena/kom (din)</th>
<th style="padding:8px 10px;text-align:right;font-size:12px;font-weight:500;color:var(--tekst-sporedni);width:110px;">Ukupno</th>
<th style="width:40px;"></th>
</tr>
</thead>
<tbody>
<template x-for="(stavka, i) in stavke" :key="i">
<tr style="border-bottom:0.5px solid var(--ivica);">
<td style="padding:8px 10px;">
<select :name="'artikal_id[]'" x-model="stavka.artikal_id"
@change="popuniCenu(stavka)"
:disabled="isMobile"
style="width:100%;">
<option value="">— odaberi artikal —</option>
<template x-for="a in artikliOpcije" :key="a.id">
<option :value="a.id" x-text="a.naziv"></option>
</template>
</select>
</td>
<td style="padding:8px 10px;">
<input type="number" :name="'kolicina[]'" x-model="stavka.kolicina"
min="1" :disabled="isMobile"
:style="prekoracenje(i) ? 'border-color:#dc2626;' : ''"
style="width:100%;text-align:center;">
<div x-show="stavka.artikal_id"
:style="prekoracenje(i) ? 'color:#dc2626' : 'color:var(--tekst-sporedni)'"
x-text="'Na stanju: ' + dostupnaKolicina(i)"
style="font-size:11px;margin-top:3px;text-align:center;white-space:nowrap;"></div>
<div x-show="prekoracenje(i)"
style="font-size:11px;color:#dc2626;margin-top:1px;text-align:center;white-space:nowrap;">
Prekoračena količina
</div>
</td>
<td style="padding:8px 10px;">
<input type="number" :name="'cena_po_komadu[]'" x-model="stavka.cena"
min="0" step="0.01" :disabled="isMobile" style="width:100%;text-align:right;">
</td>
<td style="padding:8px 10px;text-align:right;font-size:14px;font-weight:500;color:var(--tekst-glavni);">
<span x-text="ukupnoStavke(stavka) + ' din'"></span>
</td>
<td style="padding:8px 10px;text-align:center;">
<button type="button" @click="ukloniStavku(i)"
x-show="stavke.length > 1"
style="background:none;border:none;cursor:pointer;color:#dc2626;font-size:18px;line-height:1;padding:2px 6px;border-radius:4px;transition:background 0.15s;"
onmouseover="this.style.background='rgba(220,38,38,0.08)'"
onmouseout="this.style.background='none'"
title="Ukloni stavku">×</button>
</td>
</tr>
</template>
</tbody>
<tfoot>
<tr style="border-top:0.5px solid var(--ivica);">
<td colspan="3" style="padding:10px;text-align:right;font-size:13px;color:var(--tekst-sporedni);font-weight:500;">Ukupno:</td>
<td style="padding:10px;text-align:right;font-size:15px;font-weight:600;color:var(--tekst-glavni);">
<span x-text="ukupnoSvega() + ' din'"></span>
</td>
<td></td>
</tr>
</tfoot>
</table>
</div>
<!-- mobilne kartice stavki -->
<div class="stavke-kartice" style="display:none;flex-direction:column;gap:10px;">
<template x-for="(stavka, i) in stavke" :key="i">
<div style="border:0.5px solid var(--ivica);border-radius:8px;padding:12px;">
<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:10px;">
<span style="font-size:13px;font-weight:500;color:var(--tekst-sporedni);"
x-text="'Stavka ' + (i + 1)"></span>
<button type="button" @click="ukloniStavku(i)"
x-show="stavke.length > 1"
style="background:none;border:0.5px solid #dc2626;color:#dc2626;cursor:pointer;font-size:13px;padding:2px 8px;border-radius:4px;">
Ukloni
</button>
</div>
<div style="display:flex;flex-direction:column;gap:10px;">
<div>
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Artikal</label>
<select :name="'artikal_id[]'" x-model="stavka.artikal_id"
@change="popuniCenu(stavka)"
:disabled="!isMobile"
style="width:100%;">
<option value="">— odaberi artikal —</option>
<template x-for="a in artikliOpcije" :key="a.id">
<option :value="a.id" x-text="a.naziv"></option>
</template>
</select>
</div>
<div style="display:grid;grid-template-columns:1fr 1fr;gap:10px;">
<div>
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Količina</label>
<input type="number" :name="'kolicina[]'" x-model="stavka.kolicina" min="1" :disabled="!isMobile"
:style="prekoracenje(i) ? 'border-color:#dc2626;' : ''"
style="width:100%;">
<div x-show="stavka.artikal_id"
:style="prekoracenje(i) ? 'color:#dc2626' : 'color:var(--tekst-sporedni)'"
x-text="'Na stanju: ' + dostupnaKolicina(i)"
style="font-size:11px;margin-top:3px;"></div>
<div x-show="prekoracenje(i)" style="font-size:11px;color:#dc2626;margin-top:1px;">Prekoračena količina</div>
</div>
<div>
<label style="font-size:12px;color:var(--tekst-sporedni);display:block;margin-bottom:4px;">Cena/kom (din)</label>
<input type="number" :name="'cena_po_komadu[]'" x-model="stavka.cena" min="0" step="0.01" :disabled="!isMobile" style="width:100%;">
</div>
</div>
<div style="text-align:right;font-size:14px;font-weight:500;color:var(--tekst-glavni);">
Ukupno: <span x-text="ukupnoStavke(stavka) + ' din'"></span>
</div>
</div>
</div>
</template>
<div style="text-align:right;font-size:15px;font-weight:600;color:var(--tekst-glavni);padding:8px 4px;">
Ukupno: <span x-text="ukupnoSvega() + ' din'"></span>
</div>
</div>
</div>
<!-- dugmad forme -->
<div style="display:flex;justify-content:flex-end;gap:10px;">
<a href="/prodaja" class="btn-sekundarno">Odustani</a>
<button type="submit" class="btn-primarno"
:disabled="imaPrekoracenja()"
:style="imaPrekoracenja() ? 'opacity:0.4;cursor:not-allowed;' : ''">
Sačuvaj prodaju
</button>
</div>
</form>
<!-- dugmad forme -->
<div style="display: flex; justify-content: flex-end; gap: 10px">
<a href="/prodaja" class="btn-sekundarno">Odustani</a>
<button
type="submit"
class="btn-primarno"
:disabled="imaPrekoracenja()"
:style="imaPrekoracenja() ? 'opacity:0.4;cursor:not-allowed;' : ''">
Sačuvaj prodaju
</button>
</div>
</form>
</div>
{{end}}
{{end}}
+121 -240
View File
@@ -1,255 +1,136 @@
<!DOCTYPE html>
<!doctype html>
<html lang="sr">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Priznanica {{.Nalog.BrojNaloga}}</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
* { box-sizing: border-box; margin: 0; padding: 0; }
body { font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif; font-size: 14px; color: #111; background: #f5f5f5; padding: 32px 16px; }
.stranica { background: #fff; max-width: 640px; margin: 0 auto; padding: 40px; border-radius: 8px; box-shadow: 0 1px 8px rgba(0, 0, 0, 0.08); }
.zaglavlje { display: flex; justify-content: space-between; align-items: flex-start; margin-bottom: 32px; padding-bottom: 24px; border-bottom: 1px solid #e5e7eb; }
.firma-naziv { font-size: 20px; font-weight: 600; color: #111; }
.firma-podnazlov { font-size: 13px; color: #6b7280; margin-top: 3px; }
.firma-kontakt { font-size: 12px; color: #6b7280; margin-top: 2px; }
.nalog-info { text-align: right; }
.nalog-broj { font-size: 16px; font-weight: 600; font-family: monospace; color: #111; }
.nalog-datum { font-size: 13px; color: #6b7280; margin-top: 3px; }
.meta { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; margin-bottom: 28px; }
.meta-stavka label { font-size: 11px; font-weight: 500; text-transform: uppercase; letter-spacing: 0.05em; color: #9ca3af; display: block; margin-bottom: 3px; }
.meta-stavka span { font-size: 14px; color: #111; }
table { width: 100%; border-collapse: collapse; margin-bottom: 0; }
thead tr { border-bottom: 1.5px solid #111; }
thead th { padding: 8px 10px; font-size: 11px; font-weight: 600; text-transform: uppercase; letter-spacing: 0.04em; color: #6b7280; text-align: left; }
thead th:not(:first-child) { text-align: right; }
tbody tr { border-bottom: 1px solid #e5e7eb; }
tbody td { padding: 10px 10px; font-size: 14px; color: #111; }
tbody td:not(:first-child) { text-align: right; }
tfoot tr { border-top: 1.5px solid #111; }
tfoot td { padding: 12px 10px; }
.ukupno-label { text-align: right; font-size: 13px; font-weight: 500; color: #6b7280; }
.ukupno-iznos { text-align: right; font-size: 18px; font-weight: 700; color: #111; }
.ekran-dugmad { display: flex; gap: 10px; justify-content: flex-end; margin-top: 28px; }
.btn { padding: 9px 20px; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; border: none; text-decoration: none; display: inline-block; }
.btn-primarni { background: #2563eb; color: #fff; }
.btn-sekundarni { background: #f3f4f6; color: #374151; }
@media print { body { background: #fff; padding: 0; } .stranica { box-shadow: none; border-radius: 0; padding: 20px; max-width: 100%; } .ekran-dugmad { display: none; } }
</style>
</head>
<body>
<div class="stranica">
<div class="zaglavlje">
<div>
<div class="firma-naziv">{{.NazivFirme}}</div>
{{if .Podnazlov}}
<div class="firma-podnazlov">{{.Podnazlov}}</div>
{{end}} {{if .Adresa}}
<div class="firma-kontakt">{{.Adresa}}</div>
{{end}} {{if .Telefon}}
<div class="firma-kontakt">{{.Telefon}}</div>
{{end}} {{if .PIB}}
<div class="firma-kontakt">PIB: {{.PIB}}</div>
{{end}}
</div>
<div class="nalog-info">
<div class="nalog-broj">{{.Nalog.BrojNaloga}}</div>
<div class="nalog-datum">
{{.Nalog.Datum.Format "02.01.2006. u 15:04"}}
</div>
</div>
</div>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
font-size: 14px;
color: #111;
background: #f5f5f5;
padding: 32px 16px;
}
{{if .KlijentNaziv}}
<div class="meta">
<div class="meta-stavka">
<label>Klijent</label>
<span>{{.KlijentNaziv}}</span>
</div>
</div>
{{end}}
.stranica {
background: #fff;
max-width: 640px;
margin: 0 auto;
padding: 40px;
border-radius: 8px;
box-shadow: 0 1px 8px rgba(0,0,0,0.08);
}
<table>
<thead>
<tr>
<th>Artikal</th>
<th>Kol.</th>
<th>Cena/kom</th>
<th>Ukupno</th>
</tr>
</thead>
<tbody>
{{range .Stavke}}
<tr>
<td>{{.ArtikalNaziv}}</td>
<td>{{.Kolicina}}</td>
<td>{{printf "%.2f" .CenaPoKomadu}} din</td>
<td>{{printf "%.2f" .Ukupno}} din</td>
</tr>
{{end}}
</tbody>
<tfoot>
<tr>
<td colspan="3" class="ukupno-label">Ukupno za naplatu:</td>
<td class="ukupno-iznos">{{printf "%.2f" .Nalog.Ukupno}} din</td>
</tr>
</tfoot>
</table>
.zaglavlje {
display: flex;
justify-content: space-between;
align-items: flex-start;
margin-bottom: 32px;
padding-bottom: 24px;
border-bottom: 1px solid #e5e7eb;
}
.firma-naziv {
font-size: 20px;
font-weight: 600;
color: #111;
}
.firma-podnazlov {
font-size: 13px;
color: #6b7280;
margin-top: 3px;
}
.firma-kontakt {
font-size: 12px;
color: #6b7280;
margin-top: 2px;
}
.nalog-info {
text-align: right;
}
.nalog-broj {
font-size: 16px;
font-weight: 600;
font-family: monospace;
color: #111;
}
.nalog-datum {
font-size: 13px;
color: #6b7280;
margin-top: 3px;
}
.meta {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 16px;
margin-bottom: 28px;
}
.meta-stavka label {
{{if .Nalog.Napomena}}
<div
style="
margin-top: 20px;
padding-top: 16px;
border-top: 1px solid #e5e7eb;
">
<div
style="
font-size: 11px;
font-weight: 500;
text-transform: uppercase;
letter-spacing: 0.05em;
color: #9ca3af;
display: block;
margin-bottom: 3px;
}
.meta-stavka span {
font-size: 14px;
color: #111;
}
table {
width: 100%;
border-collapse: collapse;
margin-bottom: 0;
}
thead tr {
border-bottom: 1.5px solid #111;
}
thead th {
padding: 8px 10px;
font-size: 11px;
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.04em;
color: #6b7280;
text-align: left;
}
thead th:not(:first-child) { text-align: right; }
tbody tr {
border-bottom: 1px solid #e5e7eb;
}
tbody td {
padding: 10px 10px;
font-size: 14px;
color: #111;
}
tbody td:not(:first-child) {
text-align: right;
}
tfoot tr {
border-top: 1.5px solid #111;
}
tfoot td {
padding: 12px 10px;
}
.ukupno-label {
text-align: right;
font-size: 13px;
font-weight: 500;
color: #6b7280;
}
.ukupno-iznos {
text-align: right;
font-size: 18px;
font-weight: 700;
color: #111;
}
.ekran-dugmad {
display: flex;
gap: 10px;
justify-content: flex-end;
margin-top: 28px;
}
.btn {
padding: 9px 20px;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
border: none;
text-decoration: none;
display: inline-block;
}
.btn-primarni {
background: #2563eb;
color: #fff;
}
.btn-sekundarni {
background: #f3f4f6;
color: #374151;
}
@media print {
body { background: #fff; padding: 0; }
.stranica { box-shadow: none; border-radius: 0; padding: 20px; max-width: 100%; }
.ekran-dugmad { display: none; }
}
</style>
</head>
<body>
<div class="stranica">
<div class="zaglavlje">
<div>
<div class="firma-naziv">{{.NazivFirme}}</div>
{{if .Podnazlov}}<div class="firma-podnazlov">{{.Podnazlov}}</div>{{end}}
{{if .Adresa}}<div class="firma-kontakt">{{.Adresa}}</div>{{end}}
{{if .Telefon}}<div class="firma-kontakt">{{.Telefon}}</div>{{end}}
{{if .PIB}}<div class="firma-kontakt">PIB: {{.PIB}}</div>{{end}}
</div>
<div class="nalog-info">
<div class="nalog-broj">{{.Nalog.BrojNaloga}}</div>
<div class="nalog-datum">{{.Nalog.Datum.Format "02.01.2006. u 15:04"}}</div>
</div>
</div>
{{if .KlijentNaziv}}
<div class="meta">
<div class="meta-stavka">
<label>Klijent</label>
<span>{{.KlijentNaziv}}</span>
</div>
</div>
{{end}}
<table>
<thead>
<tr>
<th>Artikal</th>
<th>Kol.</th>
<th>Cena/kom</th>
<th>Ukupno</th>
</tr>
</thead>
<tbody>
{{range .Stavke}}
<tr>
<td>{{.ArtikalNaziv}}</td>
<td>{{.Kolicina}}</td>
<td>{{printf "%.2f" .CenaPoKomadu}} din</td>
<td>{{printf "%.2f" .Ukupno}} din</td>
</tr>
{{end}}
</tbody>
<tfoot>
<tr>
<td colspan="3" class="ukupno-label">Ukupno za naplatu:</td>
<td class="ukupno-iznos">{{printf "%.2f" .Nalog.Ukupno}} din</td>
</tr>
</tfoot>
</table>
{{if .Nalog.Napomena}}
<div style="margin-top:20px;padding-top:16px;border-top:1px solid #e5e7eb;">
<div style="font-size:11px;font-weight:500;text-transform:uppercase;letter-spacing:0.05em;color:#9ca3af;margin-bottom:4px;">Napomena</div>
<div style="font-size:13px;color:#374151;">{{.Nalog.Napomena}}</div>
</div>
{{end}}
<div class="ekran-dugmad">
<button class="btn btn-sekundarni" onclick="window.close()">Zatvori</button>
<button class="btn btn-primarni" onclick="window.print()">Štampaj</button>
margin-bottom: 4px;
">
Napomena
</div>
<div style="font-size: 13px; color: #374151">{{.Nalog.Napomena}}</div>
</div>
{{end}}
<div class="ekran-dugmad">
<button class="btn btn-sekundarni" onclick="window.close()">
Zatvori
</button>
<button class="btn btn-primarni" onclick="window.print()">
Štampaj
</button>
</div>
</div>
<script>window.onload = function() { window.print(); };</script>
</body>
</html>
<script>
window.onload = function () {
window.print();
};
</script>
</body>
</html>
+7 -20
View File
@@ -17,26 +17,13 @@
.servis-tabela tbody tr:nth-child(9) { animation-delay: 0.36s; }
.servis-tabela tbody tr:nth-child(10) { animation-delay: 0.40s; }
.servis-kartice {
display: none;
flex-direction: column;
gap: 12px;
}
.servis-kartica:nth-child(1) { animation-delay: 0.04s; }
.servis-kartica:nth-child(2) { animation-delay: 0.10s; }
.servis-kartica:nth-child(3) { animation-delay: 0.16s; }
.servis-kartica:nth-child(4) { animation-delay: 0.22s; }
.servis-kartica:nth-child(5) { animation-delay: 0.28s; }
.status-badge {
display: inline-block;
padding: 3px 10px;
border-radius: 20px;
font-size: 12px;
font-weight: 500;
white-space: nowrap;
}
.servis-kartice { display: none; flex-direction: column; gap: 12px; }
.servis-kartica:nth-child(1) { animation-delay: 0.04s; }
.servis-kartica:nth-child(2) { animation-delay: 0.10s; }
.servis-kartica:nth-child(3) { animation-delay: 0.16s; }
.servis-kartica:nth-child(4) { animation-delay: 0.22s; }
.servis-kartica:nth-child(5) { animation-delay: 0.28s; }
.status-badge { display: inline-block; padding: 3px 10px; border-radius: 20px; font-size: 12px; font-weight: 500; white-space: nowrap; }
.status-primljeno { background: rgba(148,163,184,0.15); color: #94a3b8; }
.status-dijagnostika { background: rgba(59,130,246,0.15); color: #3b82f6; }
+7 -17
View File
@@ -9,24 +9,14 @@
.detalji-kartica:nth-child(3) { animation-delay: 0.20s; }
.detalji-kartica:nth-child(4) { animation-delay: 0.28s; }
.detalji-kartica:nth-child(5) { animation-delay: 0.36s; }
.poruka-animacija { animation: slideDown 0.3s ease forwards; }
.status-badge {
display: inline-block;
padding: 4px 12px;
border-radius: 20px;
font-size: 13px;
font-weight: 500;
white-space: nowrap;
}
.status-primljeno { background: rgba(148,163,184,0.15); color: #94a3b8; }
.status-dijagnostika { background: rgba(59,130,246,0.15); color: #3b82f6; }
.status-ceka { background: rgba(249,115,22,0.15); color: #f97316; }
.status-popravka { background: rgba(234,179,8,0.15); color: #ca8a04; }
.status-zavrseno { background: rgba(34,197,94,0.15); color: #16a34a; }
.status-preuzeto { background: rgba(21,128,61,0.15); color: #15803d; }
.status-badge { display: inline-block; padding: 4px 12px; border-radius: 20px; font-size: 13px; font-weight: 500; white-space: nowrap; }
.status-primljeno { background: rgba(148,163,184,0.15); color: #94a3b8; }
.status-dijagnostika { background: rgba(59,130,246,0.15); color: #3b82f6; }
.status-ceka { background: rgba(249,115,22,0.15); color: #f97316; }
.status-popravka { background: rgba(234,179,8,0.15); color: #ca8a04; }
.status-zavrseno { background: rgba(34,197,94,0.15); color: #16a34a; }
.status-preuzeto { background: rgba(21,128,61,0.15); color: #15803d; }
</style>
{{end}}
+6 -60
View File
@@ -6,74 +6,20 @@
<title>Dvostepena verifikacija — NTech</title>
<style>
* { box-sizing: border-box; margin: 0; padding: 0; }
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
background: #0f1117;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 16px;
}
.kartica {
background: #1a1d27;
border: 0.5px solid #2d3148;
border-radius: 16px;
padding: 40px;
width: 100%;
max-width: 380px;
}
body { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif; background: #0f1117; min-height: 100vh; display: flex; align-items: center; justify-content: center; padding: 16px; }
.kartica { background: #1a1d27; border: 0.5px solid #2d3148; border-radius: 16px; padding: 40px; width: 100%; max-width: 380px; }
.logo { text-align: center; margin-bottom: 32px; }
.logo-naziv { font-size: 22px; font-weight: 600; color: #fff; }
.opis { font-size: 13px; color: #9ca3af; margin-bottom: 24px; line-height: 1.5; }
h1 { font-size: 18px; font-weight: 600; color: #fff; margin-bottom: 8px; }
.polje { margin-bottom: 16px; }
label { display: block; font-size: 13px; color: #9ca3af; margin-bottom: 6px; }
input {
width: 100%;
padding: 8px 12px;
background: #0f1117;
border: 0.5px solid #2d3148;
border-radius: 8px;
font-size: 20px;
color: #fff;
outline: none;
text-align: center;
letter-spacing: 6px;
transition: border-color 0.2s;
}
input { width: 100%; padding: 8px 12px; background: #0f1117; border: 0.5px solid #2d3148; border-radius: 8px; font-size: 20px; color: #fff; outline: none; text-align: center; letter-spacing: 6px; transition: border-color 0.2s; }
input:focus { border-color: #e53e3e; }
.dugme {
width: 100%;
padding: 11px;
background: #e53e3e;
color: #fff;
border: none;
border-radius: 8px;
font-size: 14px;
font-weight: 500;
cursor: pointer;
margin-top: 8px;
transition: opacity 0.2s;
}
.dugme { width: 100%; padding: 11px; background: #e53e3e; color: #fff; border: none; border-radius: 8px; font-size: 14px; font-weight: 500; cursor: pointer; margin-top: 8px; transition: opacity 0.2s; }
.dugme:hover { opacity: 0.88; }
.greska {
background: #fef2f2;
border: 0.5px solid #fca5a5;
color: #dc2626;
border-radius: 8px;
padding: 10px 14px;
font-size: 13px;
margin-bottom: 20px;
}
.nazad {
display: block;
text-align: center;
margin-top: 16px;
font-size: 13px;
color: #6b7280;
text-decoration: none;
}
.greska { background: #fef2f2; border: 0.5px solid #fca5a5; color: #dc2626; border-radius: 8px; padding: 10px 14px; font-size: 13px; margin-bottom: 20px; }
.nazad { display: block; text-align: center; margin-top: 16px; font-size: 13px; color: #6b7280; text-decoration: none; }
.nazad:hover { color: #9ca3af; }
</style>
</head>
+15 -85
View File
@@ -38,91 +38,21 @@
{{if .AppPozadina}}
<style>
.app-bg {
position: fixed;
inset: {{if ne .AppPozadinaBlurPozadine "0"}}-20px{{else}}0{{end}};
background-image: url('{{.AppPozadina}}');
background-size: cover;
background-position: center;
filter: blur({{.AppPozadinaBlurPozadine}}px);
pointer-events: none;
z-index: 0;
}
.app-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,{{.AppPozadinaOpacity}}%);
pointer-events: none;
z-index: 1;
}
.raspored {
position: relative;
z-index: 2;
}
.sidebar {
background: rgba(0,0,0,{{if .AppPozadinaGlassOpacity}}{{.AppPozadinaGlassOpacity}}%{{else}}0.3{{end}}) !important;
backdrop-filter: blur({{.AppPozadinaBlur}}px);
-webkit-backdrop-filter: blur({{.AppPozadinaBlur}}px);
border-right: 1px solid rgba(255,255,255,0.12) !important;
}
.sidebar .nav-stavka,
.sidebar .logo-naziv,
.sidebar .logo-podnazlov {
text-shadow: 0 1px 3px rgba(0,0,0,0.8);
color: rgba(255,255,255,0.95) !important;
}
.sidebar .nav-stavka svg {
color: rgba(255,255,255,0.95) !important;
stroke: rgba(255,255,255,0.95) !important;
}
.sidebar .nav-oznaka {
text-shadow: 0 1px 3px rgba(0,0,0,0.8);
color: rgba(255,255,255,0.7) !important;
}
.topbar {
background: rgba(0,0,0,{{if .AppPozadinaGlassOpacity}}{{.AppPozadinaGlassOpacity}}%{{else}}0.08{{end}}) !important;
backdrop-filter: blur({{.AppPozadinaBlur}}px);
-webkit-backdrop-filter: blur({{.AppPozadinaBlur}}px);
border-bottom: 1px solid rgba(255,255,255,0.12) !important;
}
.kartica {
background: rgba(0,0,0,{{if .AppPozadinaGlassOpacity}}{{.AppPozadinaGlassOpacity}}%{{else}}0.08{{end}}) !important;
backdrop-filter: blur({{.AppPozadinaBlur}}px);
-webkit-backdrop-filter: blur({{.AppPozadinaBlur}}px);
border: 1px solid rgba(255,255,255,0.12) !important;
}
.kartica p,
.kartica span,
.kartica h1,
.kartica h2,
.kartica h3,
.kartica h4,
.kartica label,
.kartica td,
.kartica th,
.kartica li,
.kartica a {
color: rgba(255,255,255,0.95) !important;
text-shadow: 0 1px 3px rgba(0,0,0,0.7);
}
table, th, td {
color: rgba(255,255,255,0.95) !important;
text-shadow: 0 1px 3px rgba(0,0,0,0.8);
}
tr {
background: rgba(0,0,0,0.2);
}
tr:hover {
background: rgba(0,0,0,0.35);
}
thead th {
background: rgba(0,0,0,0.4) !important;
}
div:has(> canvas) {
background: rgba(0,0,0,0.3);
border-radius: 8px;
padding: 8px;
}
.app-bg { position: fixed; inset: {{if ne .AppPozadinaBlurPozadine "0"}}-20px{{else}}0{{end}}; background-image: url('{{.AppPozadina}}'); background-size: cover; background-position: center; filter: blur({{.AppPozadinaBlurPozadine}}px); pointer-events: none; z-index: 0; }
.app-overlay { position: fixed; inset: 0; background: rgba(0,0,0,{{.AppPozadinaOpacity}}%); pointer-events: none; z-index: 1; }
.raspored { position: relative; z-index: 2; }
.sidebar { background: rgba(0,0,0,{{if .AppPozadinaGlassOpacity}}{{.AppPozadinaGlassOpacity}}%{{else}}0.3{{end}}) !important; backdrop-filter: blur({{.AppPozadinaBlur}}px); -webkit-backdrop-filter: blur({{.AppPozadinaBlur}}px); border-right: 1px solid rgba(255,255,255,0.12) !important; }
.sidebar .nav-stavka, .sidebar .logo-naziv, .sidebar .logo-podnazlov { text-shadow: 0 1px 3px rgba(0,0,0,0.8); color: rgba(255,255,255,0.95) !important; }
.sidebar .nav-stavka svg { color: rgba(255,255,255,0.95) !important; stroke: rgba(255,255,255,0.95) !important; }
.sidebar .nav-oznaka { text-shadow: 0 1px 3px rgba(0,0,0,0.8); color: rgba(255,255,255,0.7) !important; }
.topbar { background: rgba(0,0,0,{{if .AppPozadinaGlassOpacity}}{{.AppPozadinaGlassOpacity}}%{{else}}0.08{{end}}) !important; backdrop-filter: blur({{.AppPozadinaBlur}}px); -webkit-backdrop-filter: blur({{.AppPozadinaBlur}}px); border-bottom: 1px solid rgba(255,255,255,0.12) !important; }
.kartica { background: rgba(0,0,0,{{if .AppPozadinaGlassOpacity}}{{.AppPozadinaGlassOpacity}}%{{else}}0.08{{end}}) !important; backdrop-filter: blur({{.AppPozadinaBlur}}px); -webkit-backdrop-filter: blur({{.AppPozadinaBlur}}px); border: 1px solid rgba(255,255,255,0.12) !important; }
.kartica p, .kartica span, .kartica h1, .kartica h2, .kartica h3, .kartica h4, .kartica label, .kartica td, .kartica th, .kartica li, .kartica a { color: rgba(255,255,255,0.95) !important; text-shadow: 0 1px 3px rgba(0,0,0,0.7); }
table, th, td { color: rgba(255,255,255,0.95) !important; text-shadow: 0 1px 3px rgba(0,0,0,0.8); }
tr { background: rgba(0,0,0,0.2); }
tr:hover { background: rgba(0,0,0,0.35); }
thead th { background: rgba(0,0,0,0.4) !important; }
div:has(> canvas) { background: rgba(0,0,0,0.3); border-radius: 8px; padding: 8px; }
</style>
<script>
document.addEventListener('DOMContentLoaded', function() {