From 3ef30ef7c73b8a98c4b21ba64ea420f0b51a7435 Mon Sep 17 00:00:00 2001 From: Simon Martens Date: Fri, 20 Dec 2024 01:10:39 +0100 Subject: [PATCH] Fonts + Only Pointers in sync.Maps --- app/kgpz.go | 2 +- providers/gnd/gnd.go | 6 +- providers/xmlprovider/issues.go | 6 +- providers/xmlprovider/xmlprovider.go | 40 +++++----- server/server.go | 36 ++++++--- viewmodels/agentsvm.go | 33 ++++++++ viewmodels/issuevm.go | 6 +- viewmodels/piecevm.go | 4 +- viewmodels/singleissuevm.go | 6 +- viewmodels/yearvm.go | 4 +- views/assets/css/fonts.css | 71 ++++++++++++++++++ views/assets/scripts.js | 33 +++----- views/assets/style.css | 108 --------------------------- views/layouts/default/root.gohtml | 4 +- views/package-lock.json | 77 ++++++++++++++++++- views/public/css/fonts.css | 71 ++++++++++++++++++ views/transform/site.css | 71 ------------------ 17 files changed, 323 insertions(+), 255 deletions(-) create mode 100644 views/assets/css/fonts.css create mode 100644 views/public/css/fonts.css diff --git a/app/kgpz.go b/app/kgpz.go index ef9adc8..08b5c6e 100644 --- a/app/kgpz.go +++ b/app/kgpz.go @@ -87,7 +87,7 @@ func (k *KGPZ) Enrich() error { // INFO: We pass agents by value since we don't want to block the library agents := k.Library.Agents.Everything() - go func(agents []xmlprovider.Agent) { + go func(agents []*xmlprovider.Agent) { k.GND.FetchPersons(agents) k.GND.WriteCache(k.Config.GNDPath) }(agents) diff --git a/providers/gnd/gnd.go b/providers/gnd/gnd.go index cf8e293..9299025 100644 --- a/providers/gnd/gnd.go +++ b/providers/gnd/gnd.go @@ -168,7 +168,7 @@ func (p *GNDProvider) Person(id string) *Person { return &pers } -func (p *GNDProvider) FetchPersons(persons []xmlprovider.Agent) { +func (p *GNDProvider) FetchPersons(persons []*xmlprovider.Agent) { wg := sync.WaitGroup{} for _, person := range persons { if person.ID == "" || person.GND == "" { @@ -187,9 +187,9 @@ func (p *GNDProvider) FetchPersons(persons []xmlprovider.Agent) { p.errmu.Unlock() wg.Add(1) - go func(person xmlprovider.Agent) { + go func(person *xmlprovider.Agent) { defer wg.Done() - p.fetchPerson(person) + p.fetchPerson(*person) }(person) } wg.Wait() diff --git a/providers/xmlprovider/issues.go b/providers/xmlprovider/issues.go index 5d76140..b4d6bc1 100644 --- a/providers/xmlprovider/issues.go +++ b/providers/xmlprovider/issues.go @@ -24,9 +24,9 @@ type Nummer struct { type Additional struct { XMLName xml.Name `xml:"beilage"` - Nummer string `xml:"nummer,attr"` - Von string `xml:"von"` - Bis string `xml:"bis"` + Nummer int `xml:"nummer,attr"` + Von int `xml:"von"` + Bis int `xml:"bis"` } func (i Issue) GetIDs() []string { diff --git a/providers/xmlprovider/xmlprovider.go b/providers/xmlprovider/xmlprovider.go index d36fadd..da30bec 100644 --- a/providers/xmlprovider/xmlprovider.go +++ b/providers/xmlprovider/xmlprovider.go @@ -22,21 +22,18 @@ type XMLItem interface { GetIDs() []string } -type Collection[T XMLItem] struct { - Collection []T - lock sync.Mutex -} - // An XMLProvider is a struct that holds holds serialized XML data of a specific type. It combines multiple parses IF a succeeded parse can not serialize the data from a path. type XMLProvider[T XMLItem] struct { Paths []string - // INFO: map is type [string]T + // INFO: map is type [string]*T Items sync.Map // INFO: map is type [string]ItemInfo // It keeps information about parsing status of the items. Infos sync.Map - mu sync.Mutex + mu sync.Mutex + // TODO: This is not populated yet + Array []T failed []string parses []ParseMeta } @@ -74,13 +71,16 @@ func (p *XMLProvider[T]) Serialize(dataholder XMLRootElement[T], path string) er // INFO: Mostly it's just one ID, so the double loop is not that bad. for _, id := range item.GetIDs() { p.Infos.Store(id, ItemInfo{Source: path, Parse: commit}) - p.Items.Store(id, item) + p.Items.Store(id, &item) } } return nil } +// INFO: Cleanup is called after all paths have been serialized. +// It deletes all items that have not been parsed in the last commit, +// and whose filepath has not been marked as failed. func (p *XMLProvider[T]) Cleanup() { p.mu.Lock() defer p.mu.Unlock() @@ -147,26 +147,26 @@ func (p *XMLProvider[T]) Item(id string) *T { return nil } - i := item.(T) - return &i + i := item.(*T) + return i } -func (p *XMLProvider[T]) Find(fn func(T) bool) []T { - var items []T +func (p *XMLProvider[T]) Find(fn func(*T) bool) []*T { + var items []*T p.Items.Range(func(key, value interface{}) bool { - if fn(value.(T)) { - items = append(items, value.(T)) + if fn(value.(*T)) { + items = append(items, value.(*T)) } return true }) return items } -func (p *XMLProvider[T]) FindKey(fn func(string) bool) []T { - var items []T +func (p *XMLProvider[T]) FindKey(fn func(string) bool) []*T { + var items []*T p.Items.Range(func(key, value interface{}) bool { if fn(key.(string)) { - items = append(items, value.(T)) + items = append(items, value.(*T)) } return true }) @@ -177,10 +177,10 @@ func (p *XMLProvider[T]) FindKey(fn func(string) bool) []T { // Maps are slow to iterate, but many of the Iterations can only be done once, so it doesn´t matter for a // few thousand objects. We prefer to lookup objects by key and have multiple meaningful keys; along with // sensible caching rules to keep the application responsive. -func (p *XMLProvider[T]) Everything() []T { - var items []T +func (p *XMLProvider[T]) Everything() []*T { + var items []*T p.Items.Range(func(key, value interface{}) bool { - items = append(items, value.(T)) + items = append(items, value.(*T)) return true }) return items diff --git a/server/server.go b/server/server.go index 69d0a50..96b3203 100644 --- a/server/server.go +++ b/server/server.go @@ -20,17 +20,30 @@ import ( const ( // INFO: This timeout is stupid. Uploads can take a long time, others might not. It's messy. - REQUEST_TIMEOUT = 8 * time.Second - SERVER_TIMEOUT = 8 * time.Second + REQUEST_TIMEOUT = 16 * time.Second + SERVER_TIMEOUT = 16 * time.Second + // INFO: Maybe this is too long/short? CACHE_TIME = 24 * time.Hour +) - STATIC_PREFIX = "/assets" +const ( + ASSETS_URL_PREFIX = "/assets" EDITION_URL = "/edition/" PRIVACY_URL = "/datenschutz/" CONTACT_URL = "/kontakt/" CITATION_URL = "/zitation/" + + INDEX_URL = "/1764" + + YEAR_OVERVIEW_URL = "/:year" + PLACE_OVERVIEW_URL = "/ort/:place" + AGENTS_OVERVIEW_URL = "/akteure/:letterorid" + CATEGORY_OVERVIEW_URL = "/kategorie/:category" + + ISSSUE_URL = "/:year/:issue/:page?" + ADDITIONS_URL = "/:year/:issue/beilage/:page?" ) const ( @@ -120,7 +133,7 @@ func (s *Server) Start() { srv.Use(recover.New()) - srv.Use("assets", static(&views.StaticFS)) + srv.Use(ASSETS_URL_PREFIX, static(&views.StaticFS)) // TODO: Dont cache static assets, bc storage gets huge // INFO: Maybe fiber does this already? @@ -144,18 +157,19 @@ func (s *Server) Start() { // And probably creates problems with static files, and in case we add a front page later. // That's why we redirect to /1764 on "/ " and don´t use an optional /:year? srv.Get("/", func(c *fiber.Ctx) error { - c.Redirect("/1764") + c.Redirect(INDEX_URL) return nil }) - srv.Get("/ort/:place?", controllers.GetPlace(s.kgpz)) - srv.Get("/kategorie/:category?", controllers.GetCategory(s.kgpz)) - srv.Get("/akteure/:letterorid?", controllers.GetAgents(s.kgpz)) + + srv.Get(PLACE_OVERVIEW_URL, controllers.GetPlace(s.kgpz)) + srv.Get(CATEGORY_OVERVIEW_URL, controllers.GetCategory(s.kgpz)) + srv.Get(AGENTS_OVERVIEW_URL, controllers.GetAgents(s.kgpz)) // TODO: Same here, this prob applies to all paths with two or three segments, which is bad. // Prob better to do /ausgabe/:year/:issue/:page? here and /jahrgang/:year? above. - srv.Get("/:year", controllers.GetYear(s.kgpz)) - srv.Get("/:year/:issue/:page?", controllers.GetIssue(s.kgpz)) - srv.Get("/:year/:issue/beilage/:page?", controllers.GetIssue(s.kgpz)) + srv.Get(YEAR_OVERVIEW_URL, controllers.GetYear(s.kgpz)) + srv.Get(ISSSUE_URL, controllers.GetIssue(s.kgpz)) + srv.Get(ADDITIONS_URL, controllers.GetIssue(s.kgpz)) srv.Get(EDITION_URL, controllers.Get(EDITION_URL)) srv.Get(PRIVACY_URL, controllers.Get(PRIVACY_URL)) diff --git a/viewmodels/agentsvm.go b/viewmodels/agentsvm.go index dc8d108..9a06b1a 100644 --- a/viewmodels/agentsvm.go +++ b/viewmodels/agentsvm.go @@ -8,6 +8,8 @@ import ( type AgentView struct { Agents []xmlprovider.Agent + Works map[string][]xmlprovider.Work + Pieces map[string][]xmlprovider.Piece } func AgentsView(letterorid string, lib *xmlprovider.Library) *AgentView { @@ -21,5 +23,36 @@ func AgentsView(letterorid string, lib *xmlprovider.Library) *AgentView { return true }) + res.Works = make(map[string][]xmlprovider.Work) + res.Pieces = make(map[string][]xmlprovider.Piece) + + lib.Works.Items.Range(func(key, value interface{}) bool { + w := value.(xmlprovider.Work) + for _, a := range res.Agents { + if strings.HasPrefix(a.ID, letterorid) { + _, ok := res.Works[a.ID] + if !ok { + res.Works[a.ID] = []xmlprovider.Work{} + } + res.Works[a.ID] = append(res.Works[a.ID], w) + } + } + return true + }) + + lib.Pieces.Items.Range(func(key, value interface{}) bool { + p := value.(xmlprovider.Piece) + for _, a := range res.Agents { + if strings.HasPrefix(a.ID, letterorid) { + _, ok := res.Pieces[a.ID] + if !ok { + res.Pieces[a.ID] = []xmlprovider.Piece{} + } + res.Pieces[a.ID] = append(res.Pieces[a.ID], p) + } + } + return true + }) + return &res } diff --git a/viewmodels/issuevm.go b/viewmodels/issuevm.go index 2193bda..3ade4b4 100644 --- a/viewmodels/issuevm.go +++ b/viewmodels/issuevm.go @@ -10,7 +10,7 @@ import ( const TLAYOUT = "2006-01-02" type IssueViewModel struct { - xmlprovider.Issue + *xmlprovider.Issue Day int Month int Year int @@ -23,11 +23,11 @@ func IssueView(y string, No string, lib *xmlprovider.Library) (*IssueViewModel, return nil, errors.New("Issue not found") } - return FromIssue(*issue) + return FromIssue(issue) } -func FromIssue(i xmlprovider.Issue) (*IssueViewModel, error) { +func FromIssue(i *xmlprovider.Issue) (*IssueViewModel, error) { t, err := time.Parse(TLAYOUT, i.Datum.When) if err != nil { return nil, err diff --git a/viewmodels/piecevm.go b/viewmodels/piecevm.go index ac239fa..643c290 100644 --- a/viewmodels/piecevm.go +++ b/viewmodels/piecevm.go @@ -5,12 +5,12 @@ import ( ) type PieceViewModel struct { - xmlprovider.Piece + *xmlprovider.Piece // TODO: this is a bit hacky, but it refences the page number of the piece in the issue Von int Bis int } -func NewPieceView(p xmlprovider.Piece) (PieceViewModel, error) { +func NewPieceView(p *xmlprovider.Piece) (PieceViewModel, error) { return PieceViewModel{Piece: p}, nil } diff --git a/viewmodels/singleissuevm.go b/viewmodels/singleissuevm.go index 9fffbb1..ae820f2 100644 --- a/viewmodels/singleissuevm.go +++ b/viewmodels/singleissuevm.go @@ -28,10 +28,6 @@ func NewSingleIssueView(y string, No string, lib *xmlprovider.Library) (*SingleI return nil, err } - if err != nil { - return nil, err - } - no, err := strconv.Atoi(No) if err != nil { return nil, err @@ -61,7 +57,7 @@ func (issue *SingleIssueViewModel) PiecesForIsssue(lib *xmlprovider.Library) err lib.Pieces.Items.Range(func(key, value interface{}) bool { k := key.(string) if strings.HasPrefix(k, lookfor) { - a := value.(xmlprovider.Piece) + a := value.(*xmlprovider.Piece) p, err := NewPieceView(a) if err != nil { logging.ObjErr(&a, err) diff --git a/viewmodels/yearvm.go b/viewmodels/yearvm.go index 7ec0f95..3145bac 100644 --- a/viewmodels/yearvm.go +++ b/viewmodels/yearvm.go @@ -35,7 +35,7 @@ func YearView(year string, lib *xmlprovider.Library) (*YearViewModel, error) { } if date == year { - issue := value.(xmlprovider.Issue) + issue := value.(*xmlprovider.Issue) res.PushIssue(issue) } return true @@ -55,7 +55,7 @@ func (y *YearViewModel) Sort() { y.Issues.Sort() } -func (y *YearViewModel) PushIssue(i xmlprovider.Issue) { +func (y *YearViewModel) PushIssue(i *xmlprovider.Issue) { iv, err := FromIssue(i) if err != nil { return diff --git a/views/assets/css/fonts.css b/views/assets/css/fonts.css new file mode 100644 index 0000000..55440cd --- /dev/null +++ b/views/assets/css/fonts.css @@ -0,0 +1,71 @@ +@font-face { + font-family: "Rancho"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(/assets/fonts/Rancho-Regular.ttf) format("truetype"); +} + +@font-face { + font-family: "Merriweather"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(/assets/fonts/Merriweather-Regular.ttf) format("truetype"); +} + +@font-face { + font-family: "Merriweather"; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(/assets/fonts/Merriweather-Italic.ttf) format("truetype"); +} + +@font-face { + font-family: "Merriweather"; + font-style: normal; + font-weight: bold; + font-display: swap; + src: url(/assets/fonts/Merriweather-Bold.ttf) format("truetype"); +} + +@font-face { + font-family: "Merriweather"; + font-style: italic; + font-weight: bold; + font-display: swap; + src: url(/assets/fonts/SourceSans3-BoldItalic.ttf) format("truetype"); +} + +@font-face { + font-family: "Source Sans 3"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(/assets/fonts/SourceSans3-Medium.ttf) format("truetype"); +} + +@font-face { + font-family: "Source Sans 3"; + font-style: italic; + font-weight: 500; + font-display: swap; + src: url(/assets/fonts/SourceSans3-MediumItalic.ttf) format("truetype"); +} + +@font-face { + font-family: "Source Sans 3"; + font-style: normal; + font-weight: bold; + font-display: swap; + src: url(/assets/fonts/SourceSans3-Bold.ttf) format("truetype"); +} + +@font-face { + font-family: "Source Sans 3"; + font-style: italic; + font-weight: bold; + font-display: swap; + src: url(/assets/fonts/SourceSans3-BoldItalic.ttf) format("truetype"); +} diff --git a/views/assets/scripts.js b/views/assets/scripts.js index 5af9d6c..1c3f876 100644 --- a/views/assets/scripts.js +++ b/views/assets/scripts.js @@ -1,31 +1,22 @@ -function setup() { - let templates = document.querySelectorAll("template[simple]"); - templates.forEach((template) => { - let templateId = template.getAttribute("id"); - let templateContent = template.content; - customElements.define(templateId, class extends HTMLElement { +function a() { + document.querySelectorAll("template[simple]").forEach((l) => { + let s = l.getAttribute("id"), n = l.content; + customElements.define(s, class extends HTMLElement { constructor() { - super(); - this.appendChild(templateContent.cloneNode(true)); - this.slots = this.querySelectorAll("slot"); + super(), this.appendChild(n.cloneNode(!0)), this.slots = this.querySelectorAll("slot"); } connectedCallback() { - let toremove = []; - this.slots.forEach((tslot) => { - let slotName = tslot.getAttribute("name"); - let slotContent = this.querySelector(`[slot="${slotName}"]`); - if (slotContent) { - tslot.replaceWith(slotContent.cloneNode(true)); - toremove.push(slotContent); - } - }); - toremove.forEach((element) => { - element.remove(); + let o = []; + this.slots.forEach((e) => { + let r = e.getAttribute("name"), t = this.querySelector(`[slot="${r}"]`); + t && (e.replaceWith(t.cloneNode(!0)), o.push(t)); + }), o.forEach((e) => { + e.remove(); }); } }); }); } export { - setup + a as setup }; diff --git a/views/assets/style.css b/views/assets/style.css index e6fb2f9..ef8d43d 100644 --- a/views/assets/style.css +++ b/views/assets/style.css @@ -554,114 +554,6 @@ video { display: none; } -@font-face { - font-family: "Rancho"; - - font-style: normal; - - font-weight: 500; - - font-display: swap; - - src: url(/publi/public/fonts/Rancho-Regular.ttf) format("truetype"); -} - -@font-face { - font-family: "Merriweather"; - - font-style: normal; - - font-weight: 500; - - font-display: swap; - - src: url(/public/fonts/Merriweather-Regular.ttf) format("truetype"); -} - -@font-face { - font-family: "Merriweather"; - - font-style: italic; - - font-weight: 500; - - font-display: swap; - - src: url(/public/fonts/Merriweather-Italic.ttf) format("truetype"); -} - -@font-face { - font-family: "Merriweather"; - - font-style: normal; - - font-weight: bold; - - font-display: swap; - - src: url(/public/fonts/Merriweather-Bold.ttf) format("truetype"); -} - -@font-face { - font-family: "Merriweather"; - - font-style: italic; - - font-weight: bold; - - font-display: swap; - - src: url(/public/fonts/SourceSans3-BoldItalic.ttf) format("truetype"); -} - -@font-face { - font-family: "Source Sans 3"; - - font-style: normal; - - font-weight: 500; - - font-display: swap; - - src: url(/public/fonts/SourceSans3-Medium.ttf) format("truetype"); -} - -@font-face { - font-family: "Source Sans 3"; - - font-style: italic; - - font-weight: 500; - - font-display: swap; - - src: url(/public/fonts/SourceSans3-MediumItalic.ttf) format("truetype"); -} - -@font-face { - font-family: "Source Sans 3"; - - font-style: normal; - - font-weight: bold; - - font-display: swap; - - src: url(/public/fonts/SourceSans3-Bold.ttf) format("truetype"); -} - -@font-face { - font-family: "Source Sans 3"; - - font-style: italic; - - font-weight: bold; - - font-display: swap; - - src: url(/public/fonts/SourceSans3-BoldItalic.ttf) format("truetype"); -} - html { font-size: 15.5px; } diff --git a/views/layouts/default/root.gohtml b/views/layouts/default/root.gohtml index ba4f0c1..323c983 100644 --- a/views/layouts/default/root.gohtml +++ b/views/layouts/default/root.gohtml @@ -14,12 +14,14 @@ {{ end }} - + + +