Files
GoNtech/web/templates/teme/podrazumevana/base.html
T

180 lines
6.1 KiB
HTML
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{define "base"}}
<!doctype html>
<html lang="sr">
<head>
<link rel="icon" type="image/svg+xml" href="/static/favicon.svg">
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{block "naslov" .}}NTech{{end}}</title>
<meta name="csrf-token" content="{{.CsrfToken}}">
<script>
if (window.innerWidth > 768 && localStorage.getItem('sidebar-skupljen') === 'true') {
document.documentElement.classList.add('sidebar-init-skupljen');
}
</script>
<!-- tema — učitava se prva -->
<link rel="stylesheet" href="/static/css/teme/{{.Tema}}.css" />
<!-- glavni stilovi -->
<link rel="stylesheet" href="/static/css/main.css" />
<!-- tailwind -->
<script src="https://cdn.tailwindcss.com"></script>
{{block "dodatni-css" .}}{{end}}
{{if .AppPozadina}}
<style>
body {
background-image: url('{{.AppPozadina}}');
background-size: cover;
background-position: center;
background-attachment: fixed;
}
.app-overlay {
position: fixed;
inset: 0;
background: rgba(0,0,0,{{.AppPozadinaOpacity}}%);
pointer-events: none;
z-index: 0;
}
.raspored {
position: relative;
z-index: 1;
}
.sidebar {
background: rgba(255,255,255,0.08) !important;
backdrop-filter: blur({{.AppPozadinaBlur}}px);
-webkit-backdrop-filter: blur({{.AppPozadinaBlur}}px);
border-right: 1px solid rgba(255,255,255,0.12) !important;
}
.topbar {
background: rgba(255,255,255,0.08) !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(255,255,255,0.08) !important;
backdrop-filter: blur({{.AppPozadinaBlur}}px);
-webkit-backdrop-filter: blur({{.AppPozadinaBlur}}px);
border: 1px solid rgba(255,255,255,0.12) !important;
}
</style>
{{end}}
</head>
<body>
{{if .AppPozadina}}<div class="app-overlay"></div>{{end}}
<div class="sidebar-overlay" id="sidebar-overlay"></div>
<div class="raspored">
{{template "sidebar" .}}
<div class="glavni-sadrzaj">
{{template "topbar" .}}
<main class="sadrzaj">{{block "sadrzaj" .}}{{end}}</main>
</div>
</div>
<!-- flash poruka — prikazuje se kao toast u gornjem desnom uglu -->
{{if .Flash}}
<div id="flash-toast" class="flash-toast flash-{{.Flash.Tip}}" role="alert">
<span class="flash-ikona">{{if eq .Flash.Tip "uspeh"}}✓{{else}}!{{end}}</span>
<span class="flash-tekst">{{.Flash.Poruka}}</span>
<button class="flash-zatvori" onclick="this.parentElement.remove()" aria-label="Zatvori">×</button>
</div>
<script>
(function() {
var t = document.getElementById('flash-toast');
if (!t) return;
setTimeout(function() {
t.classList.add('flash-izlaz');
setTimeout(function() { if (t.parentElement) t.remove(); }, 350);
}, 4000);
})();
</script>
{{end}}
<!-- alpine.js za interaktivnost -->
<script
src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"
defer
></script>
<!-- htmx za komunikaciju sa serverom -->
<script src="https://cdn.jsdelivr.net/npm/htmx.org@2.x.x/dist/htmx.min.js"></script>
<!-- sidebar logika -->
<!-- sidebar logika -->
<script>
const sidebar = document.getElementById("sidebar");
const hamburger = document.getElementById("hamburger");
const overlay = document.getElementById("sidebar-overlay");
const mobilni = () => window.innerWidth <= 768;
// učitaj stanje iz localStorage samo za desktop
if (!mobilni() && localStorage.getItem("sidebar-skupljen") === "true") {
sidebar.classList.add("skupljen");
}
document.documentElement.classList.remove('sidebar-init-skupljen');
hamburger.addEventListener("click", () => {
if (mobilni()) {
// mobilno — drawer ponašanje
sidebar.classList.toggle("otvoren");
overlay.classList.toggle("aktivan");
} else {
// desktop — skupljanje
sidebar.classList.toggle("skupljen");
localStorage.setItem(
"sidebar-skupljen",
sidebar.classList.contains("skupljen"),
);
}
});
// zatvori sidebar klikom na overlay
overlay.addEventListener("click", () => {
sidebar.classList.remove("otvoren");
overlay.classList.remove("aktivan");
});
// zatvori sidebar kada se promeni veličina prozora
window.addEventListener("resize", () => {
if (!mobilni()) {
sidebar.classList.remove("otvoren");
overlay.classList.remove("aktivan");
}
});
</script>
{{block "dodatni-js" .}}{{end}}
<!-- CSRF: automatski dodaje skriveno polje u sve POST forme -->
<script>
document.addEventListener('DOMContentLoaded', function() {
var m = document.querySelector('meta[name="csrf-token"]');
if (!m || !m.content) return;
document.querySelectorAll('form[method="POST"],form[method="post"]').forEach(function(f) {
if (f.querySelector('input[name="_csrf"]')) return;
var i = document.createElement('input');
i.type = 'hidden'; i.name = '_csrf'; i.value = m.content;
f.appendChild(i);
});
// data-potvrda: sigurna alternativa za onclick=confirm() na dugmadima i linkovima
// Vrednost atributa je poruka koja se prikazuje korisniku. Go template je HTML-escape-uje,
// JS čita originalnu vrednost — nema problema sa specijalnim karakterima u imenima.
document.querySelectorAll('[data-potvrda]').forEach(function(el) {
el.addEventListener('click', function(e) {
if (!confirm(el.getAttribute('data-potvrda'))) e.preventDefault();
});
});
});
</script>
</body>
</html>
{{end}}