diff --git a/dbmodels/agents.go b/dbmodels/agents.go index 6519484..acc3a60 100644 --- a/dbmodels/agents.go +++ b/dbmodels/agents.go @@ -1,8 +1,6 @@ package dbmodels import ( - "slices" - "github.com/pocketbase/dbx" "github.com/pocketbase/pocketbase/core" "golang.org/x/text/collate" @@ -12,17 +10,6 @@ import ( type AgentsEntries map[string][]*REntriesAgents type AgentsContents map[string][]*RContentsAgents -func AgentForId(app core.App, id string) (*Agent, error) { - agent := &Agent{} - err := app.RecordQuery(AGENTS_TABLE). - Where(dbx.HashExp{ID_FIELD: id}). - One(agent) - if err != nil { - return nil, err - } - return agent, nil -} - func FTS5SearchAgents(app core.App, query string) ([]*Agent, error) { a := []*Agent{} q := NormalizeQuery(query) @@ -216,13 +203,6 @@ func AgentsForLetter(app core.App, letter string) ([]*Agent, error) { return agents, nil } -func SortAgentsByName(series []*Agent) { - collator := collate.New(language.German, collate.Loose) - slices.SortFunc(series, func(i, j *Agent) int { - return collator.CompareString(i.Name(), j.Name()) - }) -} - func BasicSearchAgents(app core.App, query string) ([]*Agent, []*Agent, error) { agents, err := TitleSearchAgents(app, query) if err != nil { @@ -297,10 +277,11 @@ type AgentCount struct { ID string `db:"id"` } -func CountAgentsBaende(app core.App) (map[string]int, error) { +func CountAgentsBaende(app core.App, ids []any) (map[string]int, error) { couns := []AgentCount{} err := app.RecordQuery(RelationTableName(ENTRIES_TABLE, AGENTS_TABLE)). Select("count(*) as count, " + AGENTS_TABLE + " as id"). + Where(dbx.HashExp{ID_FIELD: ids}). GroupBy(AGENTS_TABLE). All(&couns) @@ -316,7 +297,7 @@ func CountAgentsBaende(app core.App) (map[string]int, error) { return ret, nil } -func CountAgentsContents(app core.App) (map[string]int, error) { +func CountAgentsContents(app core.App, ids []any) (map[string]int, error) { couns := []AgentCount{} err := app.RecordQuery(RelationTableName(CONTENTS_TABLE, AGENTS_TABLE)). Select("count(*) as count, " + AGENTS_TABLE + " as id"). diff --git a/dbmodels/collectionhelper.go b/dbmodels/collectionhelper.go index b379523..2361c7b 100644 --- a/dbmodels/collectionhelper.go +++ b/dbmodels/collectionhelper.go @@ -3,16 +3,30 @@ package dbmodels import ( "encoding/json" "regexp" - "sort" "strconv" "strings" ) -// CollectionInfo holds only the ID, a list of single references, and the Recorded flag. +// INFO: tries to parse the Sammlungen field of contents. +// Doesn't do a good job at all, but it's hard, there are many errors +// Safe for concurrent use: +var inrex = regexp.MustCompile(`(?is)inr[.:,;]?\s*([\d,\-(?:u.?)\v\f\t –—;\.]+)`) +var onrex = regexp.MustCompile(`(?is)obj[.:,;]?\s*([\d,\-(?:u.?)\v\f\t –—;\.]+)`) +var dashRegex = regexp.MustCompile(`[–—−‒]`) +var delims = regexp.MustCompile(`[;/]+`) +var reno = regexp.MustCompile(`\b\d+\b`) + type CollectionInfo struct { - Collection *Content - Singles []int - Recorded bool + Annotation string + Collection int + Obj []string + INr []int + Obj_Unsure []string + INr_Unsure []int + + ObjRanges []Range[string] + INrRanges []Range[int] + Recorded bool } func (ci CollectionInfo) String() string { @@ -20,107 +34,296 @@ func (ci CollectionInfo) String() string { return string(marshalled) } -// parseAnnotation detects "nicht erfasst" references (Recorded=false), -// then finds all "INr" references (both single values and ranges). -// Ranges like "100-105" are fully expanded to singles. Duplicates are removed. -// Any references not in `inos` are ignored. -func ParseAnnotation(c *Content, annotation string, inos []int) CollectionInfo { +func (ci CollectionInfo) ShortString() string { + s := strings.Builder{} + s.WriteString(strconv.Itoa(ci.Collection)) + s.WriteString(": ") + s.WriteString(ci.Annotation) + s.WriteString("\n") + + if ci.Recorded { + s.WriteString("recorded") + } else { + s.WriteString("not recorded") + } + + s.WriteString("\n") + + if len(ci.INrRanges) > 0 { + s.WriteString("INr-Ranges: ") + for _, r := range ci.INrRanges { + s.WriteString(strconv.Itoa(r.From)) + s.WriteString("-") + s.WriteString(strconv.Itoa(r.To)) + s.WriteString("; ") + } + s.WriteString("\n") + } + + if len(ci.INr) > 0 { + s.WriteString("INr-Singles: ") + for _, i := range ci.INr { + s.WriteString(strconv.Itoa(i)) + s.WriteString("; ") + } + } + + if len(ci.INr_Unsure) > 0 { + s.WriteString("INr-Unsure: ") + if len(ci.INr_Unsure) > 100 { + s.WriteString("many") + } else { + for _, i := range ci.INr_Unsure { + s.WriteString(strconv.Itoa(i)) + s.WriteString("; ") + } + s.WriteString("\n") + } + } + + if len(ci.ObjRanges) > 0 { + s.WriteString("Obj-Ranges: ") + for _, r := range ci.ObjRanges { + s.WriteString(r.From) + s.WriteString("-") + s.WriteString(r.To) + s.WriteString("; ") + } + s.WriteString("\n") + } + + if len(ci.Obj) > 0 { + s.WriteString("Obj-Singles: ") + for _, i := range ci.Obj { + s.WriteString(i) + s.WriteString("; ") + } + s.WriteString("\n") + } + + if len(ci.Obj_Unsure) > 0 { + s.WriteString("Obj-Unsure: ") + for _, i := range ci.Obj_Unsure { + s.WriteString(i) + s.WriteString("; ") + } + s.WriteString("\n") + } + + return s.String() +} + +type Range[T any] struct { + From T + To T +} + +func ParseAnnotation(c int, annotation string, inos []int, objnos []string) CollectionInfo { ci := CollectionInfo{ + Annotation: annotation, Collection: c, - Singles: []int{}, - Recorded: true, // Default + Recorded: true, } - // 1) Detect phrases like "nicht erfasst", "nicht aufgenommen", etc. - notRecordedPatterns := []string{"erfasst", "aufgenommen", "verzeichnet", "registriert"} - lowerAnn := strings.ToLower(annotation) - if strings.Contains(lowerAnn, "nicht") { - for _, kw := range notRecordedPatterns { - if strings.Contains(lowerAnn, kw) { - ci.Recorded = false - break + split := strings.Split(annotation, "/)") + + inomap := make(map[int]bool) + for _, i := range inos { + inomap[i] = true + } + + objnomap := make(map[string]bool) + for _, o := range objnos { + objnomap[o] = true + } + + unsure_inr := func(in int) { + instr := strconv.Itoa(in) + if _, ok := objnomap[instr]; ok { + ci.Obj = append(ci.Obj, instr) + } else { + ci.INr_Unsure = append(ci.INr_Unsure, in) + } + } + + unsure_inr_range := func(r Range[int]) { + cfrom := strconv.Itoa(r.From) + cto := strconv.Itoa(r.To) + _, ok := objnomap[cfrom] + _, ok2 := objnomap[cto] + if ok && ok2 { + ci.ObjRanges = append(ci.ObjRanges, Range[string]{From: cfrom, To: cto}) + } else { + for i := r.From; i <= r.To; i++ { + unsure_inr(i) } } } - // We'll keep singles in a map for deduplication - singlesMap := make(map[int]struct{}) + for _, s := range split { + l := strings.ToLower(s) - // 2) Regex that matches "INr" plus the numeric portion (including dash / punctuation). - re := regexp.MustCompile(`(?i)\bINr[.:]?\s+([\d,\-\s–—;/.]+)`) - matches := re.FindAllStringSubmatch(annotation, -1) - - // Regex to unify different dash characters into a simple '-' - dashRegex := regexp.MustCompile(`[–—−‒]`) - - // Helper to expand a range, e.g. 10615–10621 => 10615..10621 - expandRange := func(fromVal, toVal int) { - // If reversed, its a typo - if fromVal > toVal { - return - } - for v := fromVal; v <= toVal; v++ { - if inList(v, inos) { - singlesMap[v] = struct{}{} + // TODO: before this, we may cut the annotation into /) pieces + notRecordedPatterns := []string{"erfasst", "aufgenommen", "verzeichnet", "registriert"} + if strings.Contains(l, "nicht") { + for _, kw := range notRecordedPatterns { + if strings.Contains(l, kw) { + ci.Recorded = false + break + } } } + + matches := inrex.FindAllStringSubmatch(s, -1) + inRanges, inSingles := findINrRangesSingles(matches) + + // INFO: Heuristics + for _, in := range inSingles { + if _, ok := inomap[in]; ok { + ci.INr = append(ci.INr, in) + } else { + unsure_inr(in) + } + } + + for _, r := range inRanges { + if r.From < r.To { + _, ok := inomap[r.From] + _, ok2 := inomap[r.To] + if ok && ok2 { + ci.INrRanges = append(ci.INrRanges, r) + continue + } + + unsure_inr_range(r) + } else { + for i := r.From; i <= r.To; i++ { + ci.INr_Unsure = append(ci.INr_Unsure, i) + } + } + } + + matches = onrex.FindAllStringSubmatch(s, -1) + objRanges, objSingles := findONrRangesSingles(matches) + + for _, o := range objSingles { + if _, ok := objnomap[o]; ok { + ci.Obj = append(ci.Obj, o) + } else { + ci.Obj_Unsure = append(ci.Obj_Unsure, o) + } + } + + for _, r := range objRanges { + if r.From < r.To { + _, ok := objnomap[r.From] + _, ok2 := objnomap[r.To] + if ok && ok2 { + ci.ObjRanges = append(ci.ObjRanges, r) + continue + } + } + } + } - for _, m := range matches { - numericChunk := m[1] + return ci +} - // Replace typographic dashes with ASCII hyphen - numericChunk = dashRegex.ReplaceAllString(numericChunk, "-") +func findINrRangesSingles(matches [][]string) ([]Range[int], []int) { + ranges := make([]Range[int], 0) + singles := make([]int, 0) - // Also unify semicolons or slashes to commas - extraDelims := regexp.MustCompile(`[;/]+`) - numericChunk = extraDelims.ReplaceAllString(numericChunk, ",") - - // Now split on commas - parts := strings.Split(numericChunk, ",") + for _, match := range matches { + chunk := match[1] + normalized := dashRegex.ReplaceAllString(chunk, "-") + // WARNING: Replacing the OBj and INr delimiter ; with a comma here. + // It's a problem if the Obj was left out: INr 323345-323398; 23-53 + // Here is an Obj often, but not always ^ + // We do some heuristics later on to differentiate INr from Obj. + normalized = delims.ReplaceAllString(normalized, ",") + parts := strings.Split(normalized, ",") for _, p := range parts { p = strings.TrimSpace(p) if p == "" { continue } - // If we see a hyphen, treat it as a range - if strings.Contains(p, "-") { - rangeParts := strings.SplitN(p, "-", 2) - if len(rangeParts) == 2 { - fromStr := strings.TrimSpace(rangeParts[0]) - toStr := strings.TrimSpace(rangeParts[1]) - if fromVal, errFrom := strconv.Atoi(fromStr); errFrom == nil { - if toVal, errTo := strconv.Atoi(toStr); errTo == nil { - expandRange(fromVal, toVal) + + rangeParts := strings.Split(p, "-") + if len(rangeParts) == 2 { + // INFO: we have a range, most prob + fromStr := strings.TrimSpace(rangeParts[0]) + toStr := strings.TrimSpace(rangeParts[1]) + if fromVal, errFrom := strconv.Atoi(fromStr); errFrom == nil { + if toVal, errTo := strconv.Atoi(toStr); errTo == nil { + ranges = append(ranges, Range[int]{From: fromVal, To: toVal}) + continue + } + to := reno.FindAllString(toStr, -1) + if len(to) >= 1 { + if val, err := strconv.Atoi(to[0]); err == nil { + ranges = append(ranges, Range[int]{From: fromVal, To: val}) + } + if len(to) > 1 { + if val, err := strconv.Atoi(to[1]); err == nil { + singles = append(singles, val) + } } } } - } else { - // Single integer reference - if val, err := strconv.Atoi(p); err == nil { - if inList(val, inos) { - singlesMap[val] = struct{}{} + continue + } + + rangeParts = strings.Split(p, " u") + for _, r := range rangeParts { + trimmed := strings.TrimSpace(r) + matches := reno.FindAllString(trimmed, -1) + for _, m := range matches { + if val, err := strconv.Atoi(m); err == nil { + singles = append(singles, val) } } } } } - // Flatten the map into a sorted slice - for s := range singlesMap { - ci.Singles = append(ci.Singles, s) - } - sort.Ints(ci.Singles) - - return ci + return ranges, singles } -// inList checks membership in `inos` -func inList(x int, list []int) bool { - for _, item := range list { - if item == x { - return true +func findONrRangesSingles(matches [][]string) ([]Range[string], []string) { + ranges := make([]Range[string], 0) + singles := make([]string, 0) + + for _, match := range matches { + chunk := match[1] + normalized := dashRegex.ReplaceAllString(chunk, "-") + normalized = delims.ReplaceAllString(normalized, ",") + parts := strings.Split(normalized, ",") + for _, p := range parts { + p = strings.TrimSpace(p) + if p == "" { + continue + } + + rangeParts := strings.Split(p, "-") + if len(rangeParts) == 2 { + // INFO: we have a range, most prob + fromStr := strings.TrimSpace(rangeParts[0]) + toStr := strings.TrimSpace(rangeParts[1]) + ranges = append(ranges, Range[string]{From: fromStr, To: toStr}) + continue + } + + rangeParts = strings.Split(p, " u") + for _, r := range rangeParts { + trimmed := strings.TrimSpace(r) + matches := reno.FindAllString(trimmed, -1) + for _, m := range matches { + singles = append(singles, m) + } + } } } - return false + + return ranges, singles } diff --git a/dbmodels/common.go b/dbmodels/common.go deleted file mode 100644 index a724166..0000000 --- a/dbmodels/common.go +++ /dev/null @@ -1,5 +0,0 @@ -package dbmodels - -type FieldMetaData struct { - MetaData MetaData `json:",omitempty" db:"edit_fielddata"` -} diff --git a/dbmodels/contents.go b/dbmodels/contents.go deleted file mode 100644 index 81f5bac..0000000 --- a/dbmodels/contents.go +++ /dev/null @@ -1,86 +0,0 @@ -package dbmodels - -import ( - "slices" - "strings" - - "github.com/pocketbase/dbx" - "github.com/pocketbase/pocketbase/core" -) - -type ContentsAgents map[string][]*RContentsAgents - -func ContentsForEntry(app core.App, entry *Entry) ([]*Content, error) { - contents := []*Content{} - err := app.RecordQuery(CONTENTS_TABLE). - Where(dbx.HashExp{ENTRIES_TABLE: entry.Id}). - All(&contents) - if err != nil { - return nil, err - } - - slices.SortFunc(contents, func(i, j *Content) int { - r := i.Numbering() - j.Numbering() - if r == 0 { - return 0 - } - if r < 0 { - return -1 - } - return 1 - }) - - return contents, nil -} - -func ContentsForAgent(app core.App, agentId string) ([]*Content, error) { - relations := []*RContentsAgents{} - err := app.RecordQuery(RelationTableName(CONTENTS_TABLE, AGENTS_TABLE)). - Where(dbx.HashExp{AGENTS_TABLE: agentId}). - All(&relations) - if err != nil { - return nil, err - } - - cids := []any{} - for _, r := range relations { - cids = append(cids, r.Content()) - } - - contents := []*Content{} - err = app.RecordQuery(CONTENTS_TABLE). - Where(dbx.HashExp{ID_FIELD: cids}). - All(&contents) - if err != nil { - return nil, err - } - - return contents, nil -} - -func SortContentsByEntryNumbering(contents []*Content, entries map[string]*Entry) { - slices.SortFunc(contents, func(i, j *Content) int { - ii, iok := entries[i.Entry()] - ij, jok := entries[j.Entry()] - if iok && jok { - ret := ii.Year() - ij.Year() - if ret != 0 { - return ret - } - - ret = strings.Compare(ii.PreferredTitle(), ij.PreferredTitle()) - if ret != 0 { - return ret - } - } - - r := i.Numbering() - j.Numbering() - if r == 0 { - return 0 - } - if r < 0 { - return -1 - } - return 1 - }) -} diff --git a/dbmodels/places.go b/dbmodels/places.go deleted file mode 100644 index 55925ba..0000000 --- a/dbmodels/places.go +++ /dev/null @@ -1,66 +0,0 @@ -package dbmodels - -import ( - "slices" - - "github.com/pocketbase/dbx" - "github.com/pocketbase/pocketbase/core" - "golang.org/x/text/collate" - "golang.org/x/text/language" -) - -func AllPlaces(app core.App) ([]*Place, error) { - places := []*Place{} - err := app.RecordQuery(PLACES_TABLE). - OrderBy(PLACES_NAME_FIELD). - All(&places) - if err != nil { - return nil, err - } - - return places, nil -} - -func SortPlacesByName(places []*Place) { - collator := collate.New(language.German) - slices.SortFunc(places, func(i, j *Place) int { - return collator.CompareString(i.Name(), j.Name()) - }) -} - -func PlaceForId(app core.App, id string) (*Place, error) { - place := &Place{} - err := app.RecordQuery(PLACES_TABLE). - Where(dbx.HashExp{ID_FIELD: id}). - One(place) - if err != nil { - return nil, err - } - return place, nil -} - -func PlacesForEntry(app core.App, entry *Entry) (map[string]*Place, error) { - ids := []any{} - places := map[string]*Place{} - - for _, r := range entry.Places() { - ids = append(ids, r) - } - if len(ids) == 0 { - return places, nil - } - - p := []*Place{} - err := app.RecordQuery(PLACES_TABLE). - Where(dbx.HashExp{ID_FIELD: ids}). - All(&p) - if err != nil { - return nil, err - } - - for _, place := range p { - places[place.Id] = place - } - - return places, nil -} diff --git a/dbmodels/queries.go b/dbmodels/queries.go index f0cb961..e48eb9a 100644 --- a/dbmodels/queries.go +++ b/dbmodels/queries.go @@ -12,6 +12,8 @@ import ( // - any id or multiple IDs (of an indexed field) // 3. Naming convention: _[s] // For scanning, with an Iter_ prefix, yields single row results +// TODO: It would be nice if the return types of these, if arrays were custom types that implemented +// some often uses functions, like getting all IDs, or creating a map of the IDs. func REntriesAgents_Agent(app core.App, id string) ([]*REntriesAgents, error) { return TableByFields[*REntriesAgents]( diff --git a/dbmodels/queries_iter.go b/dbmodels/queries_iter.go index 9223f10..da0e34f 100644 --- a/dbmodels/queries_iter.go +++ b/dbmodels/queries_iter.go @@ -1,10 +1,6 @@ package dbmodels -import ( - "iter" - - "github.com/pocketbase/pocketbase/core" -) +import () // INFO: Iterator queries to be reused // Rules @@ -15,23 +11,24 @@ import ( // 3. Naming convention: Iter__[s] // BUG: this is not working as expected, see Iter_TableByField in queryhelpers.go -func Iter_REntriesAgents_Agent(app core.App, id string) (iter.Seq2[*REntriesAgents, error], error) { - innerIterator, err := Iter_TableByField[REntriesAgents]( - app, - RelationTableName(ENTRIES_TABLE, AGENTS_TABLE), - AGENTS_TABLE, - id, - ) - if err != nil { - return nil, err - } - - return func(yield func(*REntriesAgents, error) bool) { - for item, err := range innerIterator { - if !yield(item, err) { - return - } - } - }, nil -} +// func Iter_REntriesAgents_Agent(app core.App, id string) (iter.Seq2[*REntriesAgents, error], error) { +// innerIterator, err := Iter_TableByField[REntriesAgents]( +// app, +// RelationTableName(ENTRIES_TABLE, AGENTS_TABLE), +// AGENTS_TABLE, +// id, +// ) +// +// if err != nil { +// return nil, err +// } +// +// return func(yield func(*REntriesAgents, error) bool) { +// for item, err := range innerIterator { +// if !yield(item, err) { +// return +// } +// } +// }, nil +// } diff --git a/dbmodels/queryhelpers.go b/dbmodels/queryhelpers.go index b0bb5a6..a6b31d8 100644 --- a/dbmodels/queryhelpers.go +++ b/dbmodels/queryhelpers.go @@ -1,7 +1,6 @@ package dbmodels import ( - "iter" "reflect" "github.com/pocketbase/dbx" @@ -10,100 +9,50 @@ import ( // INFO: These functions are very abstract interfaces to the DB that help w querying -// BUG: this is not working: -// github.com/pocketbase/pocketbase/apis.NewRouter.panicRecover.func3.1() -// -// /home/simon/go/pkg/mod/github.com/pocketbase/pocketbase@v0.25.5/apis/middlewares.go:269 +0x13c -// -// panic({0x15b34c0?, 0x2831680?}) -// -// /usr/local/go/src/runtime/panic.go:787 +0x132 -// -// github.com/pocketbase/pocketbase/core.(*Record).FieldsData(0xc000632820) -// -// /home/simon/go/pkg/mod/github.com/pocketbase/pocketbase@v0.25.5/core/record_model.go:774 +0x1a -// -// github.com/pocketbase/pocketbase/core.(*Record).PostScan(0xc000632820) -// -// /home/simon/go/pkg/mod/github.com/pocketbase/pocketbase@v0.25.5/core/record_model.go:591 +0x4e -// -// github.com/pocketbase/dbx.(*Rows).ScanStruct(0xc00052e6d0, {0x175f840?, 0xc000586060?}) -// -// /home/simon/go/pkg/mod/github.com/pocketbase/dbx@v1.11.0/rows.go:97 +0x32e -// -// github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels.Iter_TableByField[...].func1() -// -// /home/simon/source/musenalm/dbmodels/queryhelpers.go:23 +0x65 -// -// github.com/Theodor-Springmann-Stiftung/musenalm/dbmodels.Iter_REntriesAgents_Agent.func1(0xc000624840) -// -// /home/simon/source/musenalm/dbmodels/queries_iter.go:30 +0xae -// -// github.com/Theodor-Springmann-Stiftung/musenalm/pages.(*PersonResult).FilterEntriesByPerson(0x1762c40?, {0x1dfba88, 0xc000438870}, {0xc00004627c, 0xf}, 0xc000064720) -// -// /home/simon/source/musenalm/pages/person.go:111 +0x248 -// -// github.com/Theodor-Springmann-Stiftung/musenalm/pages.NewPersonResult({0x1dfba88, 0xc000438870}, {0xc00004627c, 0xf}) -// -// /home/simon/source/musenalm/pages/person.go:92 +0x4f -// -// github.com/Theodor-Springmann-Stiftung/musenalm/pages.(*PersonPage).Setup.func1(0xc0002da000) -// -// /home/simon/source/musenalm/pages/person.go:46 +0x1ee -// -// github.com/pocketbase/pocketbase/tools/hook.(*Hook[...]).Trigger.func1() -// -// /home/simon/go/pkg/mod/github.com/pocketbase/pocketbase@v0.25.5/tools/hook/hook.go:169 +0x5d -// -// github.com/pocketbase/pocketbase/tools/hook.(*Event).Next(0xc0002da000?) -// -// /home/simon/go/pkg/mod/github.com/pocketbase/pocketbase@v0.25.5/tools/hook/event.go:32 +0x17 -// -// github.com/pocketbase/pocketbase/apis.NewRouter.BodyLimit.func7(0xc0002da000) -// -// /home - const ( QUERY_PARTITION_SIZE = 1200 ) -func Iter_TableByField[T interface{}](app core.App, table, field string, value interface{}) (iter.Seq2[*T, error], error) { - rows, err := app.RecordQuery(table). - Where(dbx.HashExp{field: value}). - Rows() - if err != nil { - return nil, err - } - - return func(yield func(*T, error) bool) { - for rows.Next() { - var item T - err := rows.ScanStruct(&item) - if !yield(&item, err) { - return - } - } - }, nil -} - -func Iter_TableByID[T interface{}](app core.App, table, id interface{}) (iter.Seq2[*T, error], error) { - rows, err := app.RecordQuery(table). - Where(dbx.HashExp{ID_FIELD: id}). - Rows() - if err != nil { - return nil, err - } - - return func(yield func(*T, error) bool) { - for rows.Next() { - var item T - rows.Scan(&item) - if !yield(&item, nil) { - return - } - } - }, nil -} +// BUG: this is not working, throws an exception +// github.com/pocketbase/pocketbase/apis.NewRouter.panicRecover.func3.1() +// +// func Iter_TableByField[T interface{}](app core.App, table, field string, value interface{}) (iter.Seq2[*T, error], error) { +// rows, err := app.RecordQuery(table). +// Where(dbx.HashExp{field: value}). +// Rows() +// if err != nil { +// return nil, err +// } +// +// return func(yield func(*T, error) bool) { +// for rows.Next() { +// var item T +// err := rows.ScanStruct(&item) +// if !yield(&item, err) { +// return +// } +// } +// }, nil +// } +// +// func Iter_TableByID[T interface{}](app core.App, table, id interface{}) (iter.Seq2[*T, error], error) { +// rows, err := app.RecordQuery(table). +// Where(dbx.HashExp{ID_FIELD: id}). +// Rows() +// if err != nil { +// return nil, err +// } +// +// return func(yield func(*T, error) bool) { +// for rows.Next() { +// var item T +// rows.Scan(&item) +// if !yield(&item, nil) { +// return +// } +// } +// }, nil +// } func TableByField[T interface{}](app core.App, table, field string, value string) (T, error) { var ret T diff --git a/dbmodels/sorting.go b/dbmodels/sorting.go index 738f2ee..9c64d7d 100644 --- a/dbmodels/sorting.go +++ b/dbmodels/sorting.go @@ -8,6 +8,8 @@ import ( "golang.org/x/text/language" ) +// INFO: Functions that implement sorting of which sqlite is not capable of. + func Sort_Series_Title(series []*Series) { collator := collate.New(language.German) slices.SortFunc(series, func(i, j *Series) int { @@ -55,3 +57,10 @@ func Sort_Contents_Numbering(contents []*Content) { return datatypes.CompareFloat(i.Numbering(), j.Numbering()) }) } + +func Sort_Places_Name(places []*Place) { + collator := collate.New(language.German) + slices.SortFunc(places, func(i, j *Place) int { + return collator.CompareString(i.Name(), j.Name()) + }) +} diff --git a/musenalm.go b/musenalm.go index ad336b0..292efa4 100644 --- a/musenalm.go +++ b/musenalm.go @@ -12,6 +12,7 @@ import ( _ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_einfuehrung" _ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_index" _ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_kontakt" + _ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_lesekabinett" _ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_literatur" _ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_reihen" "github.com/pocketbase/pocketbase/plugins/migratecmd" diff --git a/pagemodels/index.go b/pagemodels/index.go index d3bc8b3..cc38c54 100644 --- a/pagemodels/index.go +++ b/pagemodels/index.go @@ -43,6 +43,12 @@ func (b *IndexBilder) SetBild(bild *filesystem.File) { b.Set(F_IMAGE, bild) } +func (r *IndexBilder) BildPath() string { + img := r.Bild() + ret := "/api/files/" + r.TableName() + "/" + r.Id + "/" + img + return ret +} + func (b *IndexBilder) Vorschau() string { return b.GetString(F_PREVIEW) } @@ -51,6 +57,12 @@ func (b *IndexBilder) SetVorschau(vorschau *filesystem.File) { b.Set(F_PREVIEW, vorschau) } +func (r *IndexBilder) VorschauPath() string { + img := r.Vorschau() + ret := "/api/files/" + r.TableName() + "/" + r.Id + "/" + img + return ret +} + type IndexTexte struct { core.BaseRecordProxy } diff --git a/pagemodels/pagedata.go b/pagemodels/pagedata.go index 353a141..1647412 100644 --- a/pagemodels/pagedata.go +++ b/pagemodels/pagedata.go @@ -1,6 +1,7 @@ package pagemodels const ( + P_KABINETT_NAME = "lesekabinett" P_BEITRAG_NAME = "beitrag" P_DATENSCHUTZ_NAME = "datenschutz" diff --git a/pages/almanach.go b/pages/almanach.go index 53ce945..46cc470 100644 --- a/pages/almanach.go +++ b/pages/almanach.go @@ -159,16 +159,4 @@ func (r *AlmanachResult) Collections() { } } - ccontentcollectionmap := map[int][]dbmodels.CollectionInfo{} - ccollectioncontentmap := map[string]dbmodels.CollectionInfo{} - for _, v := range collections { - cinfo := dbmodels.ParseAnnotation(v, v.Annotation(), ids) - ccollectioncontentmap[v.Id] = cinfo - for _, c := range cinfo.Singles { - ccontentcollectionmap[c] = append(ccontentcollectionmap[c], cinfo) - } - } - - r.CInfoByCollection = ccollectioncontentmap - r.CInfoByContent = ccontentcollectionmap } diff --git a/pages/index.go b/pages/index.go index 1b0d53c..2a9644d 100644 --- a/pages/index.go +++ b/pages/index.go @@ -1,14 +1,14 @@ package pages import ( - "net/http" - "strings" + "time" "github.com/Theodor-Springmann-Stiftung/musenalm/app" "github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels" "github.com/Theodor-Springmann-Stiftung/musenalm/templating" "github.com/pocketbase/pocketbase/core" "github.com/pocketbase/pocketbase/tools/router" + "math/rand" ) func init() { @@ -27,12 +27,36 @@ type IndexPage struct { // TODO: func (p *IndexPage) Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error { router.GET("/{$}", func(e *core.RequestEvent) error { - var builder strings.Builder - err := engine.Render(&builder, "/", nil, "blank") + bilder := []*pagemodels.IndexBilder{} + err := app.RecordQuery(pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME, pagemodels.T_INDEX_BILDER)). + All(&bilder) if err != nil { - return err + return engine.Response404(e, err, nil) } - return e.HTML(http.StatusOK, builder.String()) + texte := []*pagemodels.IndexTexte{} + err = app.RecordQuery(pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME)). + All(&texte) + if err != nil { + return engine.Response404(e, err, nil) + } + + Shuffle(bilder) + data := map[string]interface{}{ + "bilder": bilder, + "texte": texte[0], + } + + return engine.Response200(e, "/", data, "blank") + }) return nil } + +func Shuffle[T any](arr []T) { + rand.Seed(time.Now().UnixNano()) // Ensure random seed + n := len(arr) + for i := n - 1; i > 0; i-- { + j := rand.Intn(i + 1) // Get a random index + arr[i], arr[j] = arr[j], arr[i] // Swap + } +} diff --git a/pages/migrations_lesekabinett/1739220544_kabinett.go b/pages/migrations_lesekabinett/1739220544_kabinett.go new file mode 100644 index 0000000..353e5eb --- /dev/null +++ b/pages/migrations_lesekabinett/1739220544_kabinett.go @@ -0,0 +1,63 @@ +package migrations_index + +import ( + "github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels" + "github.com/pocketbase/pocketbase/core" + m "github.com/pocketbase/pocketbase/migrations" +) + +var text = `

Texte zum Almanachwesen

+

Joseph Franz von Ratschky: Vorbericht. in: Wiener Musenalmanach. 1779, S. 3-6. [↓Download]

+

Gottfried August Bürger: Nothgedrungene Nachrede. in: Göttinger Musenalmanach. 1782, S. 184-192. [↓Download]

+

Christian Cay Lorenz Hirschfeld: An die Leser. in: Gartenkalender. 1783, S. 272. [↓Download]

+

Johann Heinrich Voß: Ankündigung. in: Hamburger Musenalmanach. 1784, S. 222ff. [↓Download]

+

Gotthold Friedrich Stäudlin: Nachrede. in: Schwäbischer Musenalmanach. 1786 [o. S.]. [↓Download]

+

Gottfried August Bürger: Fürbitte eines ans peinliche Kreuz der Verlegenheit genagelten Herausgebers eines Musenalmanachs. in: Göttinger Musenalmanach. 1789, S. 104. [↓Download]

+

Anonymus: Die deutschen Almanache. in: Bibliothek der redenden und bildenden Künste. Zweyten Bandes erstes Stück. Leipzig, in der Dyckischen Buchhandlung, 1806, S. 207-217. [↓Download]

+

Stephan Schütze: Die Neujahrsversammlung. Ein dramatischer Prolog. in: Taschenbuch der Liebe und Freundschaft gewidmet. 1813, S. 1-20. [↓Download]

+

N. B. E.: Die deutschen Taschenbücher für 1820. in: Hermes oder kritisches Jahrbuch der Literatur. Zweites Stück für das Jahr 1820. Amsterdam, in der Verlags-Expedition des Hermes, S. 191-235. [↓Download]

+

Ferdinand Johannes Wit: Die Almanachomanie. in: Politisches Taschenbuch. 1831, S. 102-111. [↓Download]

+

August Wilhelm Schlegel: Recept. in: Deutscher Musenalmanach (Chamisso, Schwab, Gaudy). 1836, S. 18. [↓Download]

+

Robert Eduard Prutz: Die Musenalmanache und Taschenbücher in Deutschland. in: Neue Schriften. Zur deutschen Literatur- und Kulturgeschichte. Erster Band, Halle, G. Schwetschke'scher Verlag, 1854, S. 105-165. [↓Download]

+

Allotria und Kuriosa

+

Anonymus: Woher das Wort Almanach komme. in: Neues Wochenblatt zum Nuzzen und zur Unterhaltung für Kinder und junge Leute. Erstes Bändchen, erstes Stück, Leipzig, in der Sommerschen Buchhandlung 1794, S. 8f. [↓Download]

` + +var texte_fields = core.NewFieldsList( + pagemodels.EditorField(pagemodels.F_TEXT), +) + +func init() { + m.Register(func(app core.App) error { + collection_t := texteCollection() + if err := app.Save(collection_t); err != nil { + return err + } + + r := core.NewRecord(collection_t) + page := pagemodels.NewTextPage(r) + page.SetText(text) + page.SetTitle("Lesekabinett") + + if err := app.Save(r); err != nil { + return err + } + return nil + + }, func(app core.App) error { + + collection_t, err := app.FindCollectionByNameOrId( + pagemodels.GeneratePageTableName(pagemodels.P_KABINETT_NAME)) + if err == nil && collection_t != nil { + if err := app.Delete(collection_t); err != nil { + return err + } + } + return nil + }) +} + +func texteCollection() *core.Collection { + c := pagemodels.BasePageCollection(pagemodels.P_KABINETT_NAME) + c.Fields = append(c.Fields, texte_fields...) + return c +} diff --git a/pages/personen.go b/pages/personen.go index a4cb8a1..a5cdd49 100644 --- a/pages/personen.go +++ b/pages/personen.go @@ -9,6 +9,7 @@ import ( "github.com/pocketbase/pocketbase/tools/router" ) +// INFO: V0 of these const ( URL_PERSONEN = "/personen/" PARAM_FILTER = "filter" @@ -86,17 +87,22 @@ func (p *PersonenPage) FilterRequest(app core.App, engine *templating.Engine, e if err != nil { return engine.Response404(e, err, data) } - dbmodels.SortAgentsByName(agents) + dbmodels.Sort_Agents_Name(agents) data["agents"] = agents data["filter"] = filter data["letter"] = letter - bcount, err := dbmodels.CountAgentsBaende(app) + ids := []any{} + for _, a := range agents { + ids = append(ids, a.Id) + } + + bcount, err := dbmodels.CountAgentsBaende(app, ids) if err == nil { data["bcount"] = bcount } - count, err := dbmodels.CountAgentsContents(app) + count, err := dbmodels.CountAgentsContents(app, ids) if err == nil { data["ccount"] = count } @@ -135,19 +141,28 @@ func (p *PersonenPage) SearchRequest(app core.App, engine *templating.Engine, e data["FTS"] = true } - dbmodels.SortAgentsByName(agents) - dbmodels.SortAgentsByName(altagents) + dbmodels.Sort_Agents_Name(agents) + dbmodels.Sort_Agents_Name(altagents) data["search"] = search data["agents"] = agents data["altagents"] = altagents - bcount, err := dbmodels.CountAgentsBaende(app) + ids := []any{} + for _, a := range agents { + ids = append(ids, a.Id) + } + + for _, a := range altagents { + ids = append(ids, a.Id) + } + + bcount, err := dbmodels.CountAgentsBaende(app, ids) if err == nil { data["bcount"] = bcount } - count, err := dbmodels.CountAgentsContents(app) + count, err := dbmodels.CountAgentsContents(app, ids) if err == nil { data["ccount"] = count } diff --git a/pages/reihen.go b/pages/reihen.go index c62f082..6dcbbdf 100644 --- a/pages/reihen.go +++ b/pages/reihen.go @@ -208,7 +208,7 @@ func NewCommonReihenData(app core.App) CommonReihenData { if err != nil { app.Logger().Error("Failed to fetch places", "error", err) } - dbmodels.SortPlacesByName(places) + dbmodels.Sort_Places_Name(places) rec := []core.Record{} err = app.RecordQuery(dbmodels.ENTRIES_TABLE). diff --git a/pages/static.go b/pages/static.go index bc6be06..12fc5f0 100644 --- a/pages/static.go +++ b/pages/static.go @@ -8,11 +8,12 @@ import ( func init() { RegisterStaticPage("/datenschutz/", pagemodels.P_DATENSCHUTZ_NAME) - RegisterTextPage("/edition/kontakt/", pagemodels.P_KONTAKT_NAME) - RegisterTextPage("/edition/danksagungen/", pagemodels.P_DANK_NAME) - RegisterTextPage("/edition/literatur/", pagemodels.P_LIT_NAME) - RegisterTextPage("/edition/einfuehrung/", pagemodels.P_EINFUEHRUNG_NAME) - RegisterTextPage("/edition/dokumentation/", pagemodels.P_DOK_NAME) + RegisterTextPage("/redaktion/kontakt/", pagemodels.P_KONTAKT_NAME) + RegisterTextPage("/redaktion/danksagungen/", pagemodels.P_DANK_NAME) + RegisterTextPage("/redaktion/literatur/", pagemodels.P_LIT_NAME) + RegisterTextPage("/redaktion/einfuehrung/", pagemodels.P_EINFUEHRUNG_NAME) + RegisterTextPage("/redaktion/dokumentation/", pagemodels.P_DOK_NAME) + RegisterTextPage("/redaktion/lesekabinett/", pagemodels.P_KABINETT_NAME) } func RegisterStaticPage(url, name string) { diff --git a/views/assets/css/fonts.css b/views/assets/css/fonts.css index 55440cd..47fd50e 100644 --- a/views/assets/css/fonts.css +++ b/views/assets/css/fonts.css @@ -38,6 +38,14 @@ src: url(/assets/fonts/SourceSans3-BoldItalic.ttf) format("truetype"); } +@font-face { + font-family: "Spectral"; + font-style: normal; + font-weight: 500; + font-display: swap; + src: url(/assets/fonts/Spectral-Regular.ttf) format("truetype"); +} + @font-face { font-family: "Source Sans 3"; font-style: normal; diff --git a/views/layouts/blank/root.gohtml b/views/layouts/blank/root.gohtml index 50b57bd..a27b455 100644 --- a/views/layouts/blank/root.gohtml +++ b/views/layouts/blank/root.gohtml @@ -2,6 +2,9 @@ + {{ block "head" . }} @@ -9,27 +12,38 @@ {{ if .isDev }} + {{ else }} + {{ if .url }} + + {{ end }} {{ end }} - - + + + - + {{ block "body" . }} {{ end }} diff --git a/views/layouts/components/_menu.gohtml b/views/layouts/components/_menu.gohtml index 185e697..4a01ed0 100644 --- a/views/layouts/components/_menu.gohtml +++ b/views/layouts/components/_menu.gohtml @@ -5,10 +5,16 @@ x-data="{ openeditionmenu: window.location.pathname.startsWith('/edition/')}">
-
+
+ +
-

{{ .site.title }}

-

{{ .site.desc }}

+

+ {{ .site.title }} +

+

{{ .site.desc }}

@@ -40,7 +46,7 @@ {{ if and $model.page (HasPrefix $model.page.Path "/edition") -}} aria-current="true" {{- end }} - data-url="/edition/" + data-url="/redaktion/" class="text-slate-600 hover:text-slate-900 hover:cursor-pointer hover:bg-slate-100 !pr-2.5" :class="openeditionmenu? 'bg-slate-100' : 'closed'" @@ -57,36 +63,43 @@ class="submenu flex flex-row justify-end pt-3.5 gap-x-4 font-bold font-serif [&>a]:no-underline [&>*]:-mb-1.5 w-full pr-2.5 [&>*]:px-1.5"> Einführung Dokumentation Literatur Lesekabinett + Danksagungen Kontakt + + +
+ +
+
+
+ {{- Safe $model.texte.Abs1 -}} +
+
+ {{- Safe $model.texte.Abs2 -}} +
+
+ +
+
+
diff --git a/views/routes/edition/danksagungen/body.gohtml b/views/routes/redaktion/danksagungen/body.gohtml similarity index 100% rename from views/routes/edition/danksagungen/body.gohtml rename to views/routes/redaktion/danksagungen/body.gohtml diff --git a/views/routes/edition/danksagungen/head.gohtml b/views/routes/redaktion/danksagungen/head.gohtml similarity index 100% rename from views/routes/edition/danksagungen/head.gohtml rename to views/routes/redaktion/danksagungen/head.gohtml diff --git a/views/routes/edition/dokumentation/body.gohtml b/views/routes/redaktion/dokumentation/body.gohtml similarity index 100% rename from views/routes/edition/dokumentation/body.gohtml rename to views/routes/redaktion/dokumentation/body.gohtml diff --git a/views/routes/edition/dokumentation/head.gohtml b/views/routes/redaktion/dokumentation/head.gohtml similarity index 100% rename from views/routes/edition/dokumentation/head.gohtml rename to views/routes/redaktion/dokumentation/head.gohtml diff --git a/views/routes/edition/einfuehrung/body.gohtml b/views/routes/redaktion/einfuehrung/body.gohtml similarity index 100% rename from views/routes/edition/einfuehrung/body.gohtml rename to views/routes/redaktion/einfuehrung/body.gohtml diff --git a/views/routes/edition/einfuehrung/head.gohtml b/views/routes/redaktion/einfuehrung/head.gohtml similarity index 100% rename from views/routes/edition/einfuehrung/head.gohtml rename to views/routes/redaktion/einfuehrung/head.gohtml diff --git a/views/routes/edition/kontakt/body.gohtml b/views/routes/redaktion/kontakt/body.gohtml similarity index 100% rename from views/routes/edition/kontakt/body.gohtml rename to views/routes/redaktion/kontakt/body.gohtml diff --git a/views/routes/edition/kontakt/head.gohtml b/views/routes/redaktion/kontakt/head.gohtml similarity index 100% rename from views/routes/edition/kontakt/head.gohtml rename to views/routes/redaktion/kontakt/head.gohtml diff --git a/views/routes/redaktion/lesekabinett/body.gohtml b/views/routes/redaktion/lesekabinett/body.gohtml new file mode 100644 index 0000000..1dfc4eb --- /dev/null +++ b/views/routes/redaktion/lesekabinett/body.gohtml @@ -0,0 +1,8 @@ +
+
+ {{ if .record.Title }}

{{ .record.Title }}

{{ end }} +
+ {{ Safe .record.Text }} +
+
+
diff --git a/views/routes/edition/literatur/head.gohtml b/views/routes/redaktion/lesekabinett/head.gohtml similarity index 100% rename from views/routes/edition/literatur/head.gohtml rename to views/routes/redaktion/lesekabinett/head.gohtml diff --git a/views/routes/edition/literatur/body.gohtml b/views/routes/redaktion/literatur/body.gohtml similarity index 74% rename from views/routes/edition/literatur/body.gohtml rename to views/routes/redaktion/literatur/body.gohtml index 4650577..f1a80e9 100644 --- a/views/routes/edition/literatur/body.gohtml +++ b/views/routes/redaktion/literatur/body.gohtml @@ -2,10 +2,10 @@
-
+
{{ if .record.Title }}

{{ .record.Title }}

{{ end }} -
-
+
+
{{ Safe .record.Text }}
diff --git a/views/routes/redaktion/literatur/head.gohtml b/views/routes/redaktion/literatur/head.gohtml new file mode 100644 index 0000000..0176898 --- /dev/null +++ b/views/routes/redaktion/literatur/head.gohtml @@ -0,0 +1 @@ +{{ .site.title }} – {{ .record.Title }} diff --git a/views/routes/reihen/components/hero.gohtml b/views/routes/reihen/components/hero.gohtml index 20fed57..cf215b6 100644 --- a/views/routes/reihen/components/hero.gohtml +++ b/views/routes/reihen/components/hero.gohtml @@ -10,16 +10,16 @@
{{ Safe $model.record.Text }}
Bitte beachten Sie, dass es sich hier noch um eine öffentliche Testversion handelt. Über Rückmeldungen und Anregungen freuen wir uns [→ Kontakt] + href="/redaktion//kontakt">Kontakt]
diff --git a/views/routes/suche/beitraege/body.gohtml b/views/routes/suche/beitraege/body.gohtml index 9fb8c16..5767398 100644 --- a/views/routes/suche/beitraege/body.gohtml +++ b/views/routes/suche/beitraege/body.gohtml @@ -185,7 +185,6 @@ {{- else -}}
Kein Beitrag gefunden.
{{- end -}} -
+
{{- end -}} diff --git a/views/routes/suche/beitraege/pills.gohtml b/views/routes/suche/beitraege/pills.gohtml index 2c2c804..c4adac1 100644 --- a/views/routes/suche/beitraege/pills.gohtml +++ b/views/routes/suche/beitraege/pills.gohtml @@ -5,7 +5,9 @@ -}} {{- if $isFiltered -}} -
+
{{- if $model.filters.Agent -}} {{- end -}} {{- if $model.filters.OnlyScans -}} +
-
-
- -
+
+ ${this.renderIcon()}
${this.text}
${this.renderValue()} @@ -193,6 +192,23 @@ class FilterPill extends HTMLElement { `; } + renderIcon() { + const isBool = this.value === "true" || this.value === "false"; + if (!isBool) { + return `
+ +
+ `; + } + return ` +
+ +
+ `; + } + renderValue() { const isBool = this.value === "true" || this.value === "false"; if (isBool) return ``; @@ -713,10 +729,14 @@ class PopupImage extends HTMLElement { this._preview = null; this._description = null; this._imageURL = ""; + this._hideDLButton = false; } connectedCallback() { + this.classList.add("cursor-pointer"); + this.classList.add("select-none"); this._imageURL = this.getAttribute("data-image-url") || ""; + this._hideDLButton = this.getAttribute("data-hide-dl-button") || false; this._preview = this.querySelector("img"); this._description = this.querySelector(".image-description"); @@ -735,7 +755,6 @@ class PopupImage extends HTMLElement { } showOverlay() { - const descriptionHtml = this._description ? this._description.innerHTML : ""; this.overlay = document.createElement("div"); this.overlay.classList.add( "fixed", @@ -749,26 +768,21 @@ class PopupImage extends HTMLElement { ); this.overlay.innerHTML = ` -
-
+
+
+
- - -
Bild herunterladen
-
+ ${this.downloadButton()}
- Popup Image - -
- ${descriptionHtml} -
+ ${this.description()} +
`; @@ -788,6 +802,40 @@ class PopupImage extends HTMLElement { document.body.appendChild(this.overlay); } + descriptionImgClass() { + if (!this.description) { + return "0"; + } + return ""; + } + + description() { + if (!this._description) { + return ""; + } + + return ` +
+
+ ${this._description.innerHTML} +
+
+ `; + } + + downloadButton() { + if (this._hideDLButton) { + return ""; + } + + return ` + + +
Bild herunterladen
+
+ `; + } + hideOverlay() { this.overlay.parentNode.removeChild(this.overlay); this.overlay = null; @@ -1167,6 +1215,43 @@ class IntLink extends HTMLElement { } } +class ImageReel extends HTMLElement { + #minWidth = 176; + + constructor() { + super(); + this._images = []; + } + + connectedCallback() { + this._images = Array.from(this.querySelectorAll(".primages")); + this.calculateShownImages(); + const rObs = new ResizeObserver((__, _) => { + this.calculateShownImages(); + }); + + this._resizeObserver = rObs; + rObs.observe(this); + } + + disconnectedCallback() { + this._resizeObserver.unobserve(this); + } + + calculateShownImages() { + const c = this.getBoundingClientRect(); + console.log(c); + const fits = Math.floor(c.width / (this.#minWidth + 10)); + for (let i = 0; i < this._images.length; i++) { + if (i < fits - 1) { + this._images[i].classList.remove("hidden"); + } else { + this._images[i].classList.add("hidden"); + } + } + } +} + customElements.define(INT_LINK_ELEMENT, IntLink); customElements.define(ABBREV_TOOLTIPS_ELEMENT, AbbreviationTooltips); customElements.define(FILTER_LIST_ELEMENT, FilterList); @@ -1175,5 +1260,6 @@ customElements.define(TOOLTIP_ELEMENT, ToolTip); customElements.define(POPUP_IMAGE_ELEMENT, PopupImage); customElements.define(TABLIST_ELEMENT, Tablist); customElements.define(FILTER_PILL_ELEMENT, FilterPill); +customElements.define(IMAGE_REEL_ELEMENT, ImageReel); export { XSLTParseProcess, FilterList, ScrollButton, AbbreviationTooltips }; diff --git a/views/transform/site.css b/views/transform/site.css index 0c451b2..51287ab 100644 --- a/views/transform/site.css +++ b/views/transform/site.css @@ -242,6 +242,11 @@ @apply -indent-3.5 ml-3.5; } + #indexpage { + background-image: url("/assets/bg.jpg"); + @apply h-full w-full; + } + #searchnav > a:nth-of-type(1) { @apply ml-6; }