Dodavanje stranice podešavanja, CSS teme, logo zona
This commit is contained in:
+2
-6
@@ -14,7 +14,6 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
// učitaj .env fajl ako postoji
|
|
||||||
godotenv.Load()
|
godotenv.Load()
|
||||||
|
|
||||||
if config.JelPrvoPokretanje() {
|
if config.JelPrvoPokretanje() {
|
||||||
@@ -22,32 +21,27 @@ func main() {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// normalno pokretanje
|
|
||||||
port := os.Getenv("NTECH_PORT")
|
port := os.Getenv("NTECH_PORT")
|
||||||
if port == "" {
|
if port == "" {
|
||||||
port = "8080"
|
port = "8080"
|
||||||
}
|
}
|
||||||
|
|
||||||
// putanja do SQLite fajla
|
|
||||||
putanjaBaze := os.Getenv("NTECH_SQLITE")
|
putanjaBaze := os.Getenv("NTECH_SQLITE")
|
||||||
if putanjaBaze == "" {
|
if putanjaBaze == "" {
|
||||||
putanjaBaze = "ntech.db"
|
putanjaBaze = "ntech.db"
|
||||||
}
|
}
|
||||||
|
|
||||||
// otvaramo konekciju ka bazi
|
|
||||||
db, err := sqlite.OtvoriDB(putanjaBaze)
|
db, err := sqlite.OtvoriDB(putanjaBaze)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
log.Fatalf("Greška pri otvaranju baze: %v", err)
|
log.Fatalf("Greška pri otvaranju baze: %v", err)
|
||||||
}
|
}
|
||||||
defer db.Close()
|
defer db.Close()
|
||||||
|
|
||||||
// pokrećemo migracije
|
|
||||||
if err := sqlite.PokreniMigracije(db, "migrations"); err != nil {
|
if err := sqlite.PokreniMigracije(db, "migrations"); err != nil {
|
||||||
log.Fatalf("Greška pri migracijama: %v", err)
|
log.Fatalf("Greška pri migracijama: %v", err)
|
||||||
}
|
}
|
||||||
log.Println("Migracije uspešno izvršene")
|
log.Println("Migracije uspešno izvršene")
|
||||||
|
|
||||||
// kreiramo handler sa bazom
|
|
||||||
h := handler.Novi(db)
|
h := handler.Novi(db)
|
||||||
|
|
||||||
r := chi.NewRouter()
|
r := chi.NewRouter()
|
||||||
@@ -60,6 +54,8 @@ func main() {
|
|||||||
http.Redirect(w, r, "/dashboard", http.StatusFound)
|
http.Redirect(w, r, "/dashboard", http.StatusFound)
|
||||||
})
|
})
|
||||||
r.Get("/dashboard", h.Dashboard)
|
r.Get("/dashboard", h.Dashboard)
|
||||||
|
r.Get("/podesavanja", h.Podesavanja)
|
||||||
|
r.Post("/podesavanja/sacuvaj", h.SacuvajPodesavanja)
|
||||||
|
|
||||||
log.Printf("NTech pokrenut na portu %s", port)
|
log.Printf("NTech pokrenut na portu %s", port)
|
||||||
err = http.ListenAndServe(":"+port, r)
|
err = http.ListenAndServe(":"+port, r)
|
||||||
|
|||||||
@@ -0,0 +1,91 @@
|
|||||||
|
package handler
|
||||||
|
|
||||||
|
import (
|
||||||
|
"html/template"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"ntech/internal/db/sqlite"
|
||||||
|
"ntech/internal/model"
|
||||||
|
)
|
||||||
|
|
||||||
|
// PodaciPodesavanja su podaci za stranicu podešavanja
|
||||||
|
type PodaciPodesavanja struct {
|
||||||
|
model.PodaciStranice
|
||||||
|
NazivFirme string
|
||||||
|
Podnazlov string
|
||||||
|
LogoTip string
|
||||||
|
LogoPutanja string
|
||||||
|
Tema string
|
||||||
|
Sacuvano bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Podesavanja renderuje stranicu podešavanja
|
||||||
|
func (h *Handler) Podesavanja(w http.ResponseWriter, r *http.Request) {
|
||||||
|
podesavanja, err := sqlite.DohvatiSvaPodesavanja(r.Context(), h.DB)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Greška pri učitavanju podešavanja", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
podaci := PodaciPodesavanja{
|
||||||
|
PodaciStranice: model.PodaciStranice{
|
||||||
|
Stranica: "podesavanja",
|
||||||
|
NaslovStranice: "Podešavanja",
|
||||||
|
Tema: podesavanja["tema"],
|
||||||
|
NazivFirme: podesavanja["naziv_firme"],
|
||||||
|
Podnazlov: podesavanja["podnazlov"],
|
||||||
|
LogoTip: podesavanja["logo_tip"],
|
||||||
|
LogoPutanja: podesavanja["logo_putanja"],
|
||||||
|
Korisnik: "Admin",
|
||||||
|
},
|
||||||
|
NazivFirme: podesavanja["naziv_firme"],
|
||||||
|
Podnazlov: podesavanja["podnazlov"],
|
||||||
|
LogoTip: podesavanja["logo_tip"],
|
||||||
|
LogoPutanja: podesavanja["logo_putanja"],
|
||||||
|
Tema: podesavanja["tema"],
|
||||||
|
Sacuvano: r.URL.Query().Get("sacuvano") == "1",
|
||||||
|
}
|
||||||
|
|
||||||
|
tmpl, err := template.ParseFiles(
|
||||||
|
"web/templates/teme/podrazumevana/base.html",
|
||||||
|
"web/templates/komponente/sidebar.html",
|
||||||
|
"web/templates/komponente/topbar.html",
|
||||||
|
"web/templates/stranice/podesavanja.html",
|
||||||
|
)
|
||||||
|
if err != nil {
|
||||||
|
http.Error(w, "Greška pri učitavanju stranice", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := tmpl.ExecuteTemplate(w, "base", podaci); err != nil {
|
||||||
|
http.Error(w, "Greška pri prikazu stranice", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// SacuvajPodesavanja prima POST i čuva podešavanja u bazu
|
||||||
|
func (h *Handler) SacuvajPodesavanja(w http.ResponseWriter, r *http.Request) {
|
||||||
|
if err := r.ParseForm(); err != nil {
|
||||||
|
http.Error(w, "Greška pri čitanju forme", http.StatusBadRequest)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
polja := map[string]string{
|
||||||
|
"naziv_firme": r.FormValue("naziv_firme"),
|
||||||
|
"podnazlov": r.FormValue("podnazlov"),
|
||||||
|
"logo_tip": r.FormValue("logo_tip"),
|
||||||
|
"tema": r.FormValue("tema"),
|
||||||
|
}
|
||||||
|
|
||||||
|
for kljuc, vrednost := range polja {
|
||||||
|
if vrednost == "" {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
if err := sqlite.SacuvajPodesavanje(r.Context(), h.DB, kljuc, vrednost); err != nil {
|
||||||
|
http.Error(w, "Greška pri čuvanju podešavanja", http.StatusInternalServerError)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
http.Redirect(w, r, "/podesavanja?sacuvano=1", http.StatusSeeOther)
|
||||||
|
}
|
||||||
@@ -257,3 +257,40 @@ body {
|
|||||||
transform: translateY(-4px);
|
transform: translateY(-4px);
|
||||||
box-shadow: 0 8px 24px rgba(0,0,0,0.08);
|
box-shadow: 0 8px 24px rgba(0,0,0,0.08);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* input polja — konzistentna za sve teme */
|
||||||
|
input[type="text"],
|
||||||
|
input[type="email"],
|
||||||
|
input[type="password"],
|
||||||
|
input[type="number"],
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
background: var(--kartica) !important;
|
||||||
|
color: var(--tekst-glavni) !important;
|
||||||
|
border: 0.5px solid var(--ivica) !important;
|
||||||
|
border-radius: 8px;
|
||||||
|
padding: 8px 12px;
|
||||||
|
font-size: 14px;
|
||||||
|
outline: none;
|
||||||
|
transition: border-color 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
input[type="text"]:focus,
|
||||||
|
input[type="email"]:focus,
|
||||||
|
input[type="password"]:focus,
|
||||||
|
input[type="number"]:focus,
|
||||||
|
textarea:focus,
|
||||||
|
select:focus {
|
||||||
|
border-color: var(--sb-akcent) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* poruka o uspehu — konzistentna za sve teme */
|
||||||
|
.poruka-uspeh {
|
||||||
|
background: var(--kartica);
|
||||||
|
border: 0.5px solid var(--sb-akcent);
|
||||||
|
border-radius: 10px;
|
||||||
|
padding: 12px 16px;
|
||||||
|
margin-bottom: 20px;
|
||||||
|
font-size: 14px;
|
||||||
|
color: var(--sb-akcent);
|
||||||
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
:root {
|
:root {
|
||||||
--sb-pozadina: #1e1535;
|
--sb-pozadina: #4a3580;
|
||||||
--sb-hover: #2d2050;
|
--sb-hover: #5a4295;
|
||||||
--sb-aktivan: #3d2b6e;
|
--sb-aktivan: #6d52b0;
|
||||||
--sb-tekst: #a78bca;
|
--sb-tekst: #c4b5e8;
|
||||||
--sb-tekst-aktivan: #ffffff;
|
--sb-tekst-aktivan: #ffffff;
|
||||||
--sb-akcent: #a855f7;
|
--sb-akcent: #a855f7;
|
||||||
|
|
||||||
|
|||||||
@@ -6,10 +6,10 @@
|
|||||||
--sb-tekst-aktivan: #ffffff;
|
--sb-tekst-aktivan: #ffffff;
|
||||||
--sb-akcent: #4f7ef8;
|
--sb-akcent: #4f7ef8;
|
||||||
|
|
||||||
--pozadina: #f0f2f8;
|
--pozadina: #0f1117;
|
||||||
--kartica: #ffffff;
|
--kartica: #1a1d2e;
|
||||||
--tekst-glavni: #1a1d2e;
|
--tekst-glavni: #e2e8f0;
|
||||||
--tekst-sporedni: #6b7280;
|
--tekst-sporedni: #8892a4;
|
||||||
--ivica: #e5e7eb;
|
--ivica: #2a2d40;
|
||||||
--topbar: #ffffff;
|
--topbar: #13151f;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,8 +1,8 @@
|
|||||||
:root {
|
:root {
|
||||||
--sb-pozadina: #0f2818;
|
--sb-pozadina: #1a4d2e;
|
||||||
--sb-hover: #1a3d25;
|
--sb-hover: #245c38;
|
||||||
--sb-aktivan: #1e5631;
|
--sb-aktivan: #2d7a47;
|
||||||
--sb-tekst: #86b09a;
|
--sb-tekst: #a8d5b5;
|
||||||
--sb-tekst-aktivan: #ffffff;
|
--sb-tekst-aktivan: #ffffff;
|
||||||
--sb-akcent: #22c55e;
|
--sb-akcent: #22c55e;
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,112 @@
|
|||||||
|
{{template "base" .}}
|
||||||
|
|
||||||
|
{{define "naslov"}}Podešavanja — NTech{{end}}
|
||||||
|
|
||||||
|
{{define "sadrzaj"}}
|
||||||
|
<div style="max-width:720px;">
|
||||||
|
|
||||||
|
{{if .Sacuvano}}
|
||||||
|
<div class="poruka-uspeh">
|
||||||
|
Podešavanja su uspešno sačuvana.
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
|
|
||||||
|
<form method="POST" action="/podesavanja/sacuvaj">
|
||||||
|
|
||||||
|
<!-- sekcija: firma -->
|
||||||
|
<div class="kartica" style="margin-bottom:16px;">
|
||||||
|
<div style="display:flex;align-items:center;gap:10px;margin-bottom:16px;padding-bottom:12px;border-bottom:0.5px solid var(--ivica);">
|
||||||
|
<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"><path d="M3 9l9-7 9 7v11a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2z"/><polyline points="9 22 9 12 15 12 15 22"/></svg>
|
||||||
|
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Firma</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;">Naziv firme</label>
|
||||||
|
<input type="text" name="naziv_firme" value="{{.NazivFirme}}"
|
||||||
|
style="width:100%;padding:8px 12px;border:0.5px solid var(--ivica);border-radius:8px;font-size:14px;background:var(--pozadina);color:var(--tekst-glavni);outline:none;"
|
||||||
|
placeholder="npr. NTech">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label style="font-size:13px;color:var(--tekst-sporedni);display:block;margin-bottom:6px;">Podnazlov</label>
|
||||||
|
<input type="text" name="podnazlov" value="{{.Podnazlov}}"
|
||||||
|
style="width:100%;padding:8px 12px;border:0.5px solid var(--ivica);border-radius:8px;font-size:14px;background:var(--pozadina);color:var(--tekst-glavni);outline:none;"
|
||||||
|
placeholder="npr. Servis računara">
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label style="font-size:13px;color:var(--tekst-sporedni);display:block;margin-bottom:8px;">Logo zona</label>
|
||||||
|
<div style="display:flex;gap:10px;">
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .LogoTip "ikonica"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="logo_tip" value="ikonica" {{if eq .LogoTip "ikonica"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Ikonica</span>
|
||||||
|
</label>
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .LogoTip "tekst"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="logo_tip" value="tekst" {{if eq .LogoTip "tekst"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Bez ikonice</span>
|
||||||
|
</label>
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .LogoTip "slika"}}border-color:var(--sb-akcent);background:var(--pozadina);{{end}}">
|
||||||
|
<input type="radio" name="logo_tip" value="slika" {{if eq .LogoTip "slika"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Slika</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- sekcija: izgled -->
|
||||||
|
<div class="kartica" style="margin-bottom:16px;">
|
||||||
|
<div style="display:flex;align-items:center;gap:10px;margin-bottom:16px;padding-bottom:12px;border-bottom:0.5px solid var(--ivica);">
|
||||||
|
<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="10"/><circle cx="12" cy="12" r="6"/><circle cx="12" cy="12" r="2"/></svg>
|
||||||
|
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Izgled</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<label style="font-size:13px;color:var(--tekst-sporedni);display:block;margin-bottom:8px;">Tema</label>
|
||||||
|
<div style="display:flex;gap:10px;">
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .Tema "tamna"}}border-color:var(--sb-akcent);{{end}}">
|
||||||
|
<input type="radio" name="tema" value="tamna" {{if eq .Tema "tamna"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<div style="width:16px;height:16px;border-radius:50%;background:#1a1d2e;flex-shrink:0;"></div>
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Tamna</span>
|
||||||
|
</label>
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .Tema "svetla"}}border-color:var(--sb-akcent);{{end}}">
|
||||||
|
<input type="radio" name="tema" value="svetla" {{if eq .Tema "svetla"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<div style="width:16px;height:16px;border-radius:50%;background:#f8fafc;border:0.5px solid #cbd5e1;flex-shrink:0;"></div>
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Svetla</span>
|
||||||
|
</label>
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .Tema "zelena"}}border-color:var(--sb-akcent);{{end}}">
|
||||||
|
<input type="radio" name="tema" value="zelena" {{if eq .Tema "zelena"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<div style="width:16px;height:16px;border-radius:50%;background:#3a975c;flex-shrink:0;"></div>
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Zelena</span>
|
||||||
|
</label>
|
||||||
|
<label style="display:flex;align-items:center;gap:8px;padding:10px 14px;border:0.5px solid var(--ivica);border-radius:8px;cursor:pointer;flex:1;{{if eq .Tema "ljubicasta"}}border-color:var(--sb-akcent);{{end}}">
|
||||||
|
<input type="radio" name="tema" value="ljubicasta" {{if eq .Tema "ljubicasta"}}checked{{end}} style="accent-color:var(--sb-akcent);">
|
||||||
|
<div style="width:16px;height:16px;border-radius:50%;background:#462f80;flex-shrink:0;"></div>
|
||||||
|
<span style="font-size:13px;color:var(--tekst-glavni);">Ljubičasta</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- sekcija: sistem -->
|
||||||
|
<div class="kartica" style="margin-bottom:16px;">
|
||||||
|
<div style="display:flex;align-items:center;gap:10px;margin-bottom:16px;padding-bottom:12px;border-bottom:0.5px solid var(--ivica);">
|
||||||
|
<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="M19.4 15a1.65 1.65 0 0 0 .33 1.82l.06.06a2 2 0 0 1-2.83 2.83l-.06-.06a1.65 1.65 0 0 0-1.82-.33 1.65 1.65 0 0 0-1 1.51V21a2 2 0 0 1-4 0v-.09A1.65 1.65 0 0 0 9 19.4a1.65 1.65 0 0 0-1.82.33l-.06-.06a2 2 0 0 1-2.83-2.83l.06-.06A1.65 1.65 0 0 0 4.68 15a1.65 1.65 0 0 0-1.51-1H3a2 2 0 0 1 0-4h.09A1.65 1.65 0 0 0 4.6 9a1.65 1.65 0 0 0-.33-1.82l-.06-.06a2 2 0 0 1 2.83-2.83l.06.06A1.65 1.65 0 0 0 9 4.68a1.65 1.65 0 0 0 1-1.51V3a2 2 0 0 1 4 0v.09a1.65 1.65 0 0 0 1 1.51 1.65 1.65 0 0 0 1.82-.33l.06-.06a2 2 0 0 1 2.83 2.83l-.06.06A1.65 1.65 0 0 0 19.4 9a1.65 1.65 0 0 0 1.51 1H21a2 2 0 0 1 0 4h-.09a1.65 1.65 0 0 0-1.51 1z"/></svg>
|
||||||
|
<span style="font-size:15px;font-weight:500;color:var(--tekst-glavni);">Sistem</span>
|
||||||
|
</div>
|
||||||
|
<div style="font-size:13px;color:var(--tekst-sporedni);">Verzija programa: <span style="color:var(--tekst-glavni);font-weight:500;">1.0.0</span></div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- dugme za čuvanje -->
|
||||||
|
<div style="display:flex;justify-content:flex-end;">
|
||||||
|
<button type="submit"
|
||||||
|
style="background:var(--sb-akcent);color:#fff;border:none;padding:10px 24px;border-radius:8px;font-size:14px;font-weight:500;cursor:pointer;transition:opacity 0.2s;"
|
||||||
|
onmouseover="this.style.opacity='0.85'" onmouseout="this.style.opacity='1'">
|
||||||
|
Sačuvaj podešavanja
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
{{end}}
|
||||||
Reference in New Issue
Block a user