qsl designer
This commit is contained in:
@@ -0,0 +1,76 @@
|
||||
package qslcard
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"hamlog/internal/applog"
|
||||
)
|
||||
|
||||
// CountryInfo resolves the "auto" country element: a display label and the
|
||||
// ISO code of the embedded flag ("" = no flag available).
|
||||
type CountryInfo struct {
|
||||
Label string `json:"label"`
|
||||
FlagISO string `json:"flag_iso"`
|
||||
}
|
||||
|
||||
// RenderModel is a template with every placeholder filled, ready for the
|
||||
// frontend to instantiate as SVG (editor preview and final rasterization use
|
||||
// the same model so output cannot drift from preview).
|
||||
type RenderModel struct {
|
||||
Template Template `json:"template"`
|
||||
QSOFields map[string]string `json:"qso_fields"` // values for qso_box.fields
|
||||
}
|
||||
|
||||
// warnedPlaceholders dedupes the "unknown placeholder" log line so a bulk
|
||||
// render doesn't flood the log.
|
||||
var warnedPlaceholders sync.Map
|
||||
|
||||
// Resolve substitutes {profile.*} and {qso.*} placeholders from vars (keys
|
||||
// are the full "namespace.key" form) and resolves the country element. An
|
||||
// unknown placeholder resolves to "" and is logged once.
|
||||
func Resolve(t Template, vars map[string]string, country CountryInfo) RenderModel {
|
||||
resolve := func(text string) string {
|
||||
return placeholderRe.ReplaceAllStringFunc(text, func(m string) string {
|
||||
key := m[1 : len(m)-1] // strip braces → "namespace.key"
|
||||
if v, ok := vars[key]; ok {
|
||||
return v
|
||||
}
|
||||
if _, seen := warnedPlaceholders.LoadOrStore(key, true); !seen {
|
||||
applog.Printf("qslcard: unknown placeholder %q resolves to empty", m)
|
||||
}
|
||||
return ""
|
||||
})
|
||||
}
|
||||
|
||||
out := t
|
||||
out.Elements = make([]Element, len(t.Elements))
|
||||
copy(out.Elements, t.Elements)
|
||||
for i := range out.Elements {
|
||||
e := &out.Elements[i]
|
||||
switch e.Type {
|
||||
case ElemCallsign, ElemOperator, ElemInfoLine:
|
||||
e.Text = resolve(e.Text)
|
||||
case ElemCountry:
|
||||
if e.Flag == "auto" {
|
||||
e.Flag = country.FlagISO
|
||||
}
|
||||
if e.Label == "auto" {
|
||||
e.Label = country.Label
|
||||
}
|
||||
}
|
||||
}
|
||||
if t.QSOBox != nil {
|
||||
box := *t.QSOBox
|
||||
box.Title = resolve(box.Title)
|
||||
box.Footer = resolve(box.Footer)
|
||||
out.QSOBox = &box
|
||||
}
|
||||
|
||||
model := RenderModel{Template: out, QSOFields: map[string]string{}}
|
||||
if out.QSOBox != nil {
|
||||
for _, f := range out.QSOBox.Fields {
|
||||
model.QSOFields[f] = vars["qso."+f]
|
||||
}
|
||||
}
|
||||
return model
|
||||
}
|
||||
Reference in New Issue
Block a user