mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2025-10-29 01:05:32 +00:00
Lesekabinett & Startseite
This commit is contained in:
@@ -1,8 +1,6 @@
|
|||||||
package dbmodels
|
package dbmodels
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"slices"
|
|
||||||
|
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"golang.org/x/text/collate"
|
"golang.org/x/text/collate"
|
||||||
@@ -12,17 +10,6 @@ import (
|
|||||||
type AgentsEntries map[string][]*REntriesAgents
|
type AgentsEntries map[string][]*REntriesAgents
|
||||||
type AgentsContents map[string][]*RContentsAgents
|
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) {
|
func FTS5SearchAgents(app core.App, query string) ([]*Agent, error) {
|
||||||
a := []*Agent{}
|
a := []*Agent{}
|
||||||
q := NormalizeQuery(query)
|
q := NormalizeQuery(query)
|
||||||
@@ -216,13 +203,6 @@ func AgentsForLetter(app core.App, letter string) ([]*Agent, error) {
|
|||||||
return agents, nil
|
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) {
|
func BasicSearchAgents(app core.App, query string) ([]*Agent, []*Agent, error) {
|
||||||
agents, err := TitleSearchAgents(app, query)
|
agents, err := TitleSearchAgents(app, query)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -297,10 +277,11 @@ type AgentCount struct {
|
|||||||
ID string `db:"id"`
|
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{}
|
couns := []AgentCount{}
|
||||||
err := app.RecordQuery(RelationTableName(ENTRIES_TABLE, AGENTS_TABLE)).
|
err := app.RecordQuery(RelationTableName(ENTRIES_TABLE, AGENTS_TABLE)).
|
||||||
Select("count(*) as count, " + AGENTS_TABLE + " as id").
|
Select("count(*) as count, " + AGENTS_TABLE + " as id").
|
||||||
|
Where(dbx.HashExp{ID_FIELD: ids}).
|
||||||
GroupBy(AGENTS_TABLE).
|
GroupBy(AGENTS_TABLE).
|
||||||
All(&couns)
|
All(&couns)
|
||||||
|
|
||||||
@@ -316,7 +297,7 @@ func CountAgentsBaende(app core.App) (map[string]int, error) {
|
|||||||
return ret, nil
|
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{}
|
couns := []AgentCount{}
|
||||||
err := app.RecordQuery(RelationTableName(CONTENTS_TABLE, AGENTS_TABLE)).
|
err := app.RecordQuery(RelationTableName(CONTENTS_TABLE, AGENTS_TABLE)).
|
||||||
Select("count(*) as count, " + AGENTS_TABLE + " as id").
|
Select("count(*) as count, " + AGENTS_TABLE + " as id").
|
||||||
|
|||||||
@@ -3,16 +3,30 @@ package dbmodels
|
|||||||
import (
|
import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"regexp"
|
"regexp"
|
||||||
"sort"
|
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"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 {
|
type CollectionInfo struct {
|
||||||
Collection *Content
|
Annotation string
|
||||||
Singles []int
|
Collection int
|
||||||
Recorded bool
|
Obj []string
|
||||||
|
INr []int
|
||||||
|
Obj_Unsure []string
|
||||||
|
INr_Unsure []int
|
||||||
|
|
||||||
|
ObjRanges []Range[string]
|
||||||
|
INrRanges []Range[int]
|
||||||
|
Recorded bool
|
||||||
}
|
}
|
||||||
|
|
||||||
func (ci CollectionInfo) String() string {
|
func (ci CollectionInfo) String() string {
|
||||||
@@ -20,107 +34,296 @@ func (ci CollectionInfo) String() string {
|
|||||||
return string(marshalled)
|
return string(marshalled)
|
||||||
}
|
}
|
||||||
|
|
||||||
// parseAnnotation detects "nicht erfasst" references (Recorded=false),
|
func (ci CollectionInfo) ShortString() string {
|
||||||
// then finds all "INr" references (both single values and ranges).
|
s := strings.Builder{}
|
||||||
// Ranges like "100-105" are fully expanded to singles. Duplicates are removed.
|
s.WriteString(strconv.Itoa(ci.Collection))
|
||||||
// Any references not in `inos` are ignored.
|
s.WriteString(": ")
|
||||||
func ParseAnnotation(c *Content, annotation string, inos []int) CollectionInfo {
|
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{
|
ci := CollectionInfo{
|
||||||
|
Annotation: annotation,
|
||||||
Collection: c,
|
Collection: c,
|
||||||
Singles: []int{},
|
Recorded: true,
|
||||||
Recorded: true, // Default
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// 1) Detect phrases like "nicht erfasst", "nicht aufgenommen", etc.
|
split := strings.Split(annotation, "/)")
|
||||||
notRecordedPatterns := []string{"erfasst", "aufgenommen", "verzeichnet", "registriert"}
|
|
||||||
lowerAnn := strings.ToLower(annotation)
|
inomap := make(map[int]bool)
|
||||||
if strings.Contains(lowerAnn, "nicht") {
|
for _, i := range inos {
|
||||||
for _, kw := range notRecordedPatterns {
|
inomap[i] = true
|
||||||
if strings.Contains(lowerAnn, kw) {
|
}
|
||||||
ci.Recorded = false
|
|
||||||
break
|
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
|
for _, s := range split {
|
||||||
singlesMap := make(map[int]struct{})
|
l := strings.ToLower(s)
|
||||||
|
|
||||||
// 2) Regex that matches "INr" plus the numeric portion (including dash / punctuation).
|
// TODO: before this, we may cut the annotation into /) pieces
|
||||||
re := regexp.MustCompile(`(?i)\bINr[.:]?\s+([\d,\-\s–—;/.]+)`)
|
notRecordedPatterns := []string{"erfasst", "aufgenommen", "verzeichnet", "registriert"}
|
||||||
matches := re.FindAllStringSubmatch(annotation, -1)
|
if strings.Contains(l, "nicht") {
|
||||||
|
for _, kw := range notRecordedPatterns {
|
||||||
// Regex to unify different dash characters into a simple '-'
|
if strings.Contains(l, kw) {
|
||||||
dashRegex := regexp.MustCompile(`[–—−‒]`)
|
ci.Recorded = false
|
||||||
|
break
|
||||||
// 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{}{}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
return ci
|
||||||
numericChunk := m[1]
|
}
|
||||||
|
|
||||||
// Replace typographic dashes with ASCII hyphen
|
func findINrRangesSingles(matches [][]string) ([]Range[int], []int) {
|
||||||
numericChunk = dashRegex.ReplaceAllString(numericChunk, "-")
|
ranges := make([]Range[int], 0)
|
||||||
|
singles := make([]int, 0)
|
||||||
|
|
||||||
// Also unify semicolons or slashes to commas
|
for _, match := range matches {
|
||||||
extraDelims := regexp.MustCompile(`[;/]+`)
|
chunk := match[1]
|
||||||
numericChunk = extraDelims.ReplaceAllString(numericChunk, ",")
|
normalized := dashRegex.ReplaceAllString(chunk, "-")
|
||||||
|
// WARNING: Replacing the OBj and INr delimiter ; with a comma here.
|
||||||
// Now split on commas
|
// It's a problem if the Obj was left out: INr 323345-323398; 23-53
|
||||||
parts := strings.Split(numericChunk, ",")
|
// 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 {
|
for _, p := range parts {
|
||||||
p = strings.TrimSpace(p)
|
p = strings.TrimSpace(p)
|
||||||
if p == "" {
|
if p == "" {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
// If we see a hyphen, treat it as a range
|
|
||||||
if strings.Contains(p, "-") {
|
rangeParts := strings.Split(p, "-")
|
||||||
rangeParts := strings.SplitN(p, "-", 2)
|
if len(rangeParts) == 2 {
|
||||||
if len(rangeParts) == 2 {
|
// INFO: we have a range, most prob
|
||||||
fromStr := strings.TrimSpace(rangeParts[0])
|
fromStr := strings.TrimSpace(rangeParts[0])
|
||||||
toStr := strings.TrimSpace(rangeParts[1])
|
toStr := strings.TrimSpace(rangeParts[1])
|
||||||
if fromVal, errFrom := strconv.Atoi(fromStr); errFrom == nil {
|
if fromVal, errFrom := strconv.Atoi(fromStr); errFrom == nil {
|
||||||
if toVal, errTo := strconv.Atoi(toStr); errTo == nil {
|
if toVal, errTo := strconv.Atoi(toStr); errTo == nil {
|
||||||
expandRange(fromVal, toVal)
|
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 {
|
continue
|
||||||
// Single integer reference
|
}
|
||||||
if val, err := strconv.Atoi(p); err == nil {
|
|
||||||
if inList(val, inos) {
|
rangeParts = strings.Split(p, " u")
|
||||||
singlesMap[val] = struct{}{}
|
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
|
return ranges, singles
|
||||||
for s := range singlesMap {
|
|
||||||
ci.Singles = append(ci.Singles, s)
|
|
||||||
}
|
|
||||||
sort.Ints(ci.Singles)
|
|
||||||
|
|
||||||
return ci
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// inList checks membership in `inos`
|
func findONrRangesSingles(matches [][]string) ([]Range[string], []string) {
|
||||||
func inList(x int, list []int) bool {
|
ranges := make([]Range[string], 0)
|
||||||
for _, item := range list {
|
singles := make([]string, 0)
|
||||||
if item == x {
|
|
||||||
return true
|
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
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +0,0 @@
|
|||||||
package dbmodels
|
|
||||||
|
|
||||||
type FieldMetaData struct {
|
|
||||||
MetaData MetaData `json:",omitempty" db:"edit_fielddata"`
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
})
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
}
|
|
||||||
@@ -12,6 +12,8 @@ import (
|
|||||||
// - any id or multiple IDs (of an indexed field)
|
// - any id or multiple IDs (of an indexed field)
|
||||||
// 3. Naming convention: <TableName>_<FilteredField>[s]
|
// 3. Naming convention: <TableName>_<FilteredField>[s]
|
||||||
// For scanning, with an Iter_ prefix, yields single row results
|
// 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) {
|
func REntriesAgents_Agent(app core.App, id string) ([]*REntriesAgents, error) {
|
||||||
return TableByFields[*REntriesAgents](
|
return TableByFields[*REntriesAgents](
|
||||||
|
|||||||
@@ -1,10 +1,6 @@
|
|||||||
package dbmodels
|
package dbmodels
|
||||||
|
|
||||||
import (
|
import ()
|
||||||
"iter"
|
|
||||||
|
|
||||||
"github.com/pocketbase/pocketbase/core"
|
|
||||||
)
|
|
||||||
|
|
||||||
// INFO: Iterator queries to be reused
|
// INFO: Iterator queries to be reused
|
||||||
// Rules
|
// Rules
|
||||||
@@ -15,23 +11,24 @@ import (
|
|||||||
// 3. Naming convention: Iter_<TableName>_<FilteredField>[s]
|
// 3. Naming convention: Iter_<TableName>_<FilteredField>[s]
|
||||||
|
|
||||||
// BUG: this is not working as expected, see Iter_TableByField in queryhelpers.go
|
// 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 {
|
// func Iter_REntriesAgents_Agent(app core.App, id string) (iter.Seq2[*REntriesAgents, error], error) {
|
||||||
return nil, err
|
// innerIterator, err := Iter_TableByField[REntriesAgents](
|
||||||
}
|
// app,
|
||||||
|
// RelationTableName(ENTRIES_TABLE, AGENTS_TABLE),
|
||||||
return func(yield func(*REntriesAgents, error) bool) {
|
// AGENTS_TABLE,
|
||||||
for item, err := range innerIterator {
|
// id,
|
||||||
if !yield(item, err) {
|
// )
|
||||||
return
|
//
|
||||||
}
|
// if err != nil {
|
||||||
}
|
// return nil, err
|
||||||
}, nil
|
// }
|
||||||
}
|
//
|
||||||
|
// return func(yield func(*REntriesAgents, error) bool) {
|
||||||
|
// for item, err := range innerIterator {
|
||||||
|
// if !yield(item, err) {
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// }, nil
|
||||||
|
// }
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
package dbmodels
|
package dbmodels
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"iter"
|
|
||||||
"reflect"
|
"reflect"
|
||||||
|
|
||||||
"github.com/pocketbase/dbx"
|
"github.com/pocketbase/dbx"
|
||||||
@@ -10,100 +9,50 @@ import (
|
|||||||
|
|
||||||
// INFO: These functions are very abstract interfaces to the DB that help w querying
|
// 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 (
|
const (
|
||||||
QUERY_PARTITION_SIZE = 1200
|
QUERY_PARTITION_SIZE = 1200
|
||||||
)
|
)
|
||||||
|
|
||||||
func Iter_TableByField[T interface{}](app core.App, table, field string, value interface{}) (iter.Seq2[*T, error], error) {
|
// BUG: this is not working, throws an exception
|
||||||
rows, err := app.RecordQuery(table).
|
// github.com/pocketbase/pocketbase/apis.NewRouter.panicRecover.func3.1()
|
||||||
Where(dbx.HashExp{field: value}).
|
//
|
||||||
Rows()
|
// func Iter_TableByField[T interface{}](app core.App, table, field string, value interface{}) (iter.Seq2[*T, error], error) {
|
||||||
if err != nil {
|
// rows, err := app.RecordQuery(table).
|
||||||
return nil, err
|
// Where(dbx.HashExp{field: value}).
|
||||||
}
|
// Rows()
|
||||||
|
// if err != nil {
|
||||||
return func(yield func(*T, error) bool) {
|
// return nil, err
|
||||||
for rows.Next() {
|
// }
|
||||||
var item T
|
//
|
||||||
err := rows.ScanStruct(&item)
|
// return func(yield func(*T, error) bool) {
|
||||||
if !yield(&item, err) {
|
// for rows.Next() {
|
||||||
return
|
// var item T
|
||||||
}
|
// err := rows.ScanStruct(&item)
|
||||||
}
|
// if !yield(&item, err) {
|
||||||
}, nil
|
// return
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
func Iter_TableByID[T interface{}](app core.App, table, id interface{}) (iter.Seq2[*T, error], error) {
|
// }, nil
|
||||||
rows, err := app.RecordQuery(table).
|
// }
|
||||||
Where(dbx.HashExp{ID_FIELD: id}).
|
//
|
||||||
Rows()
|
// func Iter_TableByID[T interface{}](app core.App, table, id interface{}) (iter.Seq2[*T, error], error) {
|
||||||
if err != nil {
|
// rows, err := app.RecordQuery(table).
|
||||||
return nil, err
|
// Where(dbx.HashExp{ID_FIELD: id}).
|
||||||
}
|
// Rows()
|
||||||
|
// if err != nil {
|
||||||
return func(yield func(*T, error) bool) {
|
// return nil, err
|
||||||
for rows.Next() {
|
// }
|
||||||
var item T
|
//
|
||||||
rows.Scan(&item)
|
// return func(yield func(*T, error) bool) {
|
||||||
if !yield(&item, nil) {
|
// for rows.Next() {
|
||||||
return
|
// var item T
|
||||||
}
|
// rows.Scan(&item)
|
||||||
}
|
// if !yield(&item, nil) {
|
||||||
}, nil
|
// return
|
||||||
}
|
// }
|
||||||
|
// }
|
||||||
|
// }, nil
|
||||||
|
// }
|
||||||
|
|
||||||
func TableByField[T interface{}](app core.App, table, field string, value string) (T, error) {
|
func TableByField[T interface{}](app core.App, table, field string, value string) (T, error) {
|
||||||
var ret T
|
var ret T
|
||||||
|
|||||||
@@ -8,6 +8,8 @@ import (
|
|||||||
"golang.org/x/text/language"
|
"golang.org/x/text/language"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// INFO: Functions that implement sorting of which sqlite is not capable of.
|
||||||
|
|
||||||
func Sort_Series_Title(series []*Series) {
|
func Sort_Series_Title(series []*Series) {
|
||||||
collator := collate.New(language.German)
|
collator := collate.New(language.German)
|
||||||
slices.SortFunc(series, func(i, j *Series) int {
|
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())
|
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())
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import (
|
|||||||
_ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_einfuehrung"
|
_ "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_index"
|
||||||
_ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_kontakt"
|
_ "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_literatur"
|
||||||
_ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_reihen"
|
_ "github.com/Theodor-Springmann-Stiftung/musenalm/pages/migrations_reihen"
|
||||||
"github.com/pocketbase/pocketbase/plugins/migratecmd"
|
"github.com/pocketbase/pocketbase/plugins/migratecmd"
|
||||||
|
|||||||
@@ -43,6 +43,12 @@ func (b *IndexBilder) SetBild(bild *filesystem.File) {
|
|||||||
b.Set(F_IMAGE, bild)
|
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 {
|
func (b *IndexBilder) Vorschau() string {
|
||||||
return b.GetString(F_PREVIEW)
|
return b.GetString(F_PREVIEW)
|
||||||
}
|
}
|
||||||
@@ -51,6 +57,12 @@ func (b *IndexBilder) SetVorschau(vorschau *filesystem.File) {
|
|||||||
b.Set(F_PREVIEW, vorschau)
|
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 {
|
type IndexTexte struct {
|
||||||
core.BaseRecordProxy
|
core.BaseRecordProxy
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
package pagemodels
|
package pagemodels
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
P_KABINETT_NAME = "lesekabinett"
|
||||||
P_BEITRAG_NAME = "beitrag"
|
P_BEITRAG_NAME = "beitrag"
|
||||||
P_DATENSCHUTZ_NAME = "datenschutz"
|
P_DATENSCHUTZ_NAME = "datenschutz"
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,14 +1,14 @@
|
|||||||
package pages
|
package pages
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"net/http"
|
"time"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/Theodor-Springmann-Stiftung/musenalm/app"
|
"github.com/Theodor-Springmann-Stiftung/musenalm/app"
|
||||||
"github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels"
|
"github.com/Theodor-Springmann-Stiftung/musenalm/pagemodels"
|
||||||
"github.com/Theodor-Springmann-Stiftung/musenalm/templating"
|
"github.com/Theodor-Springmann-Stiftung/musenalm/templating"
|
||||||
"github.com/pocketbase/pocketbase/core"
|
"github.com/pocketbase/pocketbase/core"
|
||||||
"github.com/pocketbase/pocketbase/tools/router"
|
"github.com/pocketbase/pocketbase/tools/router"
|
||||||
|
"math/rand"
|
||||||
)
|
)
|
||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
@@ -27,12 +27,36 @@ type IndexPage struct {
|
|||||||
// TODO:
|
// TODO:
|
||||||
func (p *IndexPage) Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error {
|
func (p *IndexPage) Setup(router *router.Router[*core.RequestEvent], app core.App, engine *templating.Engine) error {
|
||||||
router.GET("/{$}", func(e *core.RequestEvent) error {
|
router.GET("/{$}", func(e *core.RequestEvent) error {
|
||||||
var builder strings.Builder
|
bilder := []*pagemodels.IndexBilder{}
|
||||||
err := engine.Render(&builder, "/", nil, "blank")
|
err := app.RecordQuery(pagemodels.GeneratePageTableName(pagemodels.P_INDEX_NAME, pagemodels.T_INDEX_BILDER)).
|
||||||
|
All(&bilder)
|
||||||
if err != nil {
|
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
|
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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
63
pages/migrations_lesekabinett/1739220544_kabinett.go
Normal file
63
pages/migrations_lesekabinett/1739220544_kabinett.go
Normal file
@@ -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 = `<h1>Texte zum Almanachwesen</h1>
|
||||||
|
<p><em>Joseph Franz von Ratschky:</em> Vorbericht. in: Wiener Musenalmanach. 1779, S. 3-6. [↓<a href="/assets/Lesekabinett/ratschky_in_wiener_1779.pdf" target="_blank" rel="noopener">Download</a>]</p>
|
||||||
|
<p><em>Gottfried August Bürger:</em> Nothgedrungene Nachrede. in: Göttinger Musenalmanach. 1782, S. 184-192. [↓<a href="/assets/Lesekabinett/buerger_in_goettinger_1782.pdf" target="_blank" rel="noopener">Download</a>]</p>
|
||||||
|
<p><em>Christian Cay Lorenz Hirschfeld: </em>An die Leser. in: Gartenkalender. 1783, S. 272. [↓<a href="/assets/Lesekabinett/hirschfeld_in_gartenkalender_1783.pdf" target="_blank" rel="noopener">Download</a>]</p>
|
||||||
|
<p><em>Johann Heinrich Voß:</em> Ankündigung. in: Hamburger Musenalmanach. 1784, S. 222ff. [↓<a href="/assets/Lesekabinett/voss_in_hamburger_1784.pdf" target="_blank" rel="noopener">Download</a>]</p>
|
||||||
|
<p><em>Gotthold Friedrich Stäudlin: </em>Nachrede. in: Schwäbischer Musenalmanach. 1786 [o. S.]. [↓<a href="/assets/Lesekabinett/staeudlin_in_schwaebischer_1786.pdf" target="_blank" rel="noopener">Download</a>]</p>
|
||||||
|
<p><em>Gottfried August Bürger:</em> Fürbitte eines ans peinliche Kreuz der Verlegenheit genagelten Herausgebers eines Musenalmanachs. in: Göttinger Musenalmanach. 1789, S. 104. [↓<a href="/assets/Lesekabinett/buerger_in_goettinger_1789.pdf" target="_blank" rel="noopener">Download</a>]</p>
|
||||||
|
<p><em>Anonymus: </em>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. [↓<a href="/assets/Lesekabinett/anonymus.pdf" target="_blank" rel="noopener">Download</a>]</p>
|
||||||
|
<p><em>Stephan Schütze:</em> Die Neujahrsversammlung. Ein dramatischer Prolog. in: Taschenbuch der Liebe und Freundschaft gewidmet. 1813, S. 1-20. [↓<a href="/assets/Lesekabinett/schuetze_in_taschenbuch_1813.pdf" target="_blank" rel="noopener">Download</a>]</p>
|
||||||
|
<p><em>N. B. E.: </em>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. [↓<em><a href="/assets/Lesekabinett/nbe_in_hermes_1820.pdf" target="_blank" rel="noopener">Download</a>]</em></p>
|
||||||
|
<p><em>Ferdinand Johannes Wit:</em> Die Almanachomanie. in: Politisches Taschenbuch. 1831, S. 102-111. [↓<a href="/assets/Lesekabinett/wit_in_politaschenbuch_1831.pdf" target="_blank" rel="noopener">Download</a>]</p>
|
||||||
|
<p><em>August Wilhelm Schlegel:</em> Recept. in: Deutscher Musenalmanach (Chamisso, Schwab, Gaudy). 1836, S. 18. [↓<a href="/assets/Lesekabinett/schlegel_in_deutscher_1836.pdf" target="_blank" rel="noopener">Download</a>]</p>
|
||||||
|
<p><em>Robert Eduard Prutz:</em> 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. [↓<a href="/assets/Lesekabinett/prutz_in_musenalmanache_1854.pdf" target="_blank" rel="noopener">Download</a>]</p>
|
||||||
|
<h1>Allotria und Kuriosa</h1>
|
||||||
|
<p><em>Anonymus:</em> 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. [↓<a href="/assets/Lesekabinett/allatroia_anonymus_wochenblatt_1794.pdf" target="_blank" rel="noopener">Download</a>]</p>`
|
||||||
|
|
||||||
|
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
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ import (
|
|||||||
"github.com/pocketbase/pocketbase/tools/router"
|
"github.com/pocketbase/pocketbase/tools/router"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
// INFO: V0 of these
|
||||||
const (
|
const (
|
||||||
URL_PERSONEN = "/personen/"
|
URL_PERSONEN = "/personen/"
|
||||||
PARAM_FILTER = "filter"
|
PARAM_FILTER = "filter"
|
||||||
@@ -86,17 +87,22 @@ func (p *PersonenPage) FilterRequest(app core.App, engine *templating.Engine, e
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return engine.Response404(e, err, data)
|
return engine.Response404(e, err, data)
|
||||||
}
|
}
|
||||||
dbmodels.SortAgentsByName(agents)
|
dbmodels.Sort_Agents_Name(agents)
|
||||||
data["agents"] = agents
|
data["agents"] = agents
|
||||||
data["filter"] = filter
|
data["filter"] = filter
|
||||||
data["letter"] = letter
|
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 {
|
if err == nil {
|
||||||
data["bcount"] = bcount
|
data["bcount"] = bcount
|
||||||
}
|
}
|
||||||
|
|
||||||
count, err := dbmodels.CountAgentsContents(app)
|
count, err := dbmodels.CountAgentsContents(app, ids)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
data["ccount"] = count
|
data["ccount"] = count
|
||||||
}
|
}
|
||||||
@@ -135,19 +141,28 @@ func (p *PersonenPage) SearchRequest(app core.App, engine *templating.Engine, e
|
|||||||
data["FTS"] = true
|
data["FTS"] = true
|
||||||
}
|
}
|
||||||
|
|
||||||
dbmodels.SortAgentsByName(agents)
|
dbmodels.Sort_Agents_Name(agents)
|
||||||
dbmodels.SortAgentsByName(altagents)
|
dbmodels.Sort_Agents_Name(altagents)
|
||||||
|
|
||||||
data["search"] = search
|
data["search"] = search
|
||||||
data["agents"] = agents
|
data["agents"] = agents
|
||||||
data["altagents"] = altagents
|
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 {
|
if err == nil {
|
||||||
data["bcount"] = bcount
|
data["bcount"] = bcount
|
||||||
}
|
}
|
||||||
|
|
||||||
count, err := dbmodels.CountAgentsContents(app)
|
count, err := dbmodels.CountAgentsContents(app, ids)
|
||||||
if err == nil {
|
if err == nil {
|
||||||
data["ccount"] = count
|
data["ccount"] = count
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,7 +208,7 @@ func NewCommonReihenData(app core.App) CommonReihenData {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
app.Logger().Error("Failed to fetch places", "error", err)
|
app.Logger().Error("Failed to fetch places", "error", err)
|
||||||
}
|
}
|
||||||
dbmodels.SortPlacesByName(places)
|
dbmodels.Sort_Places_Name(places)
|
||||||
|
|
||||||
rec := []core.Record{}
|
rec := []core.Record{}
|
||||||
err = app.RecordQuery(dbmodels.ENTRIES_TABLE).
|
err = app.RecordQuery(dbmodels.ENTRIES_TABLE).
|
||||||
|
|||||||
@@ -8,11 +8,12 @@ import (
|
|||||||
|
|
||||||
func init() {
|
func init() {
|
||||||
RegisterStaticPage("/datenschutz/", pagemodels.P_DATENSCHUTZ_NAME)
|
RegisterStaticPage("/datenschutz/", pagemodels.P_DATENSCHUTZ_NAME)
|
||||||
RegisterTextPage("/edition/kontakt/", pagemodels.P_KONTAKT_NAME)
|
RegisterTextPage("/redaktion/kontakt/", pagemodels.P_KONTAKT_NAME)
|
||||||
RegisterTextPage("/edition/danksagungen/", pagemodels.P_DANK_NAME)
|
RegisterTextPage("/redaktion/danksagungen/", pagemodels.P_DANK_NAME)
|
||||||
RegisterTextPage("/edition/literatur/", pagemodels.P_LIT_NAME)
|
RegisterTextPage("/redaktion/literatur/", pagemodels.P_LIT_NAME)
|
||||||
RegisterTextPage("/edition/einfuehrung/", pagemodels.P_EINFUEHRUNG_NAME)
|
RegisterTextPage("/redaktion/einfuehrung/", pagemodels.P_EINFUEHRUNG_NAME)
|
||||||
RegisterTextPage("/edition/dokumentation/", pagemodels.P_DOK_NAME)
|
RegisterTextPage("/redaktion/dokumentation/", pagemodels.P_DOK_NAME)
|
||||||
|
RegisterTextPage("/redaktion/lesekabinett/", pagemodels.P_KABINETT_NAME)
|
||||||
}
|
}
|
||||||
|
|
||||||
func RegisterStaticPage(url, name string) {
|
func RegisterStaticPage(url, name string) {
|
||||||
|
|||||||
@@ -38,6 +38,14 @@
|
|||||||
src: url(/assets/fonts/SourceSans3-BoldItalic.ttf) format("truetype");
|
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-face {
|
||||||
font-family: "Source Sans 3";
|
font-family: "Source Sans 3";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
|||||||
@@ -2,6 +2,9 @@
|
|||||||
<html class="w-full h-full" {{ if .lang }}lang="{{ .lang }}"{{ end }}>
|
<html class="w-full h-full" {{ if .lang }}lang="{{ .lang }}"{{ end }}>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
|
<meta
|
||||||
|
name="htmx-config"
|
||||||
|
content='{"defaultSwapStyle":"outerHTML", "scrollBehavior": "instant"}' />
|
||||||
|
|
||||||
{{ block "head" . }}
|
{{ block "head" . }}
|
||||||
<!-- Default Head elements -->
|
<!-- Default Head elements -->
|
||||||
@@ -9,27 +12,38 @@
|
|||||||
|
|
||||||
{{ if .isDev }}
|
{{ if .isDev }}
|
||||||
<link rel="icon" href="/assets/logo/dev_favicon.png" />
|
<link rel="icon" href="/assets/logo/dev_favicon.png" />
|
||||||
|
<meta name="robots" content="noindex" />
|
||||||
{{ else }}
|
{{ else }}
|
||||||
|
{{ if .url }}
|
||||||
|
<link rel="canonical" href="{{ .url }}" />
|
||||||
|
{{ end }}
|
||||||
<link rel="icon" href="/assets/logo/favicon.png" />
|
<link rel="icon" href="/assets/logo/favicon.png" />
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|
||||||
|
|
||||||
<link href="/assets/css/remixicon.css" rel="stylesheet" />
|
|
||||||
<script src="/assets/js/alpine.min.js" defer></script>
|
<script src="/assets/js/alpine.min.js" defer></script>
|
||||||
<script src="/assets/js/htmx.min.js" defer></script>
|
<script src="/assets/js/htmx.min.js" defer></script>
|
||||||
<script src="/assets/js/htmx-response-targets.js" defer></script>
|
<script src="/assets/js/htmx-response-targets.js" defer></script>
|
||||||
<script src="/assets/js/client-side-templates.js" defer></script>
|
<script src="/assets/js/mark.min.js" defer></script>
|
||||||
|
|
||||||
|
<script type="module" src="/assets/scripts.js"></script>
|
||||||
|
<link href="/assets/css/remixicon.css" rel="stylesheet" />
|
||||||
<link rel="stylesheet" type="text/css" href="/assets/css/fonts.css" />
|
<link rel="stylesheet" type="text/css" href="/assets/css/fonts.css" />
|
||||||
<link rel="stylesheet" type="text/css" href="/assets/style.css" />
|
<link rel="stylesheet" type="text/css" href="/assets/style.css" />
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
import { setup } from "/assets/scripts.js";
|
document.body.addEventListener("htmx:responseError", function (event) {
|
||||||
setup();
|
const config = event.detail.requestConfig;
|
||||||
|
if (config.boosted) {
|
||||||
|
document.body.innerHTML = event.detail.xhr.responseText;
|
||||||
|
const newUrl = event.detail.xhr.responseURL || config.url;
|
||||||
|
window.history.pushState(null, "", newUrl);
|
||||||
|
}
|
||||||
|
});
|
||||||
</script>
|
</script>
|
||||||
</head>
|
</head>
|
||||||
|
|
||||||
<body class="w-full" hx-ext="response-targets" hx-boost="true">
|
<body class="w-full h-full min-h-full" hx-ext="response-targets" hx-boost="true">
|
||||||
{{ block "body" . }}
|
{{ block "body" . }}
|
||||||
<!-- Default app body... -->
|
<!-- Default app body... -->
|
||||||
{{ end }}
|
{{ end }}
|
||||||
|
|||||||
@@ -5,10 +5,16 @@
|
|||||||
x-data="{ openeditionmenu: window.location.pathname.startsWith('/edition/')}">
|
x-data="{ openeditionmenu: window.location.pathname.startsWith('/edition/')}">
|
||||||
<div class="flex flex-row justify-between">
|
<div class="flex flex-row justify-between">
|
||||||
<div class="flex flex-row gap-x-3">
|
<div class="flex flex-row gap-x-3">
|
||||||
<div class="grow-0"><img class="h-14 w-14 border" src="/assets/favicon.png" /></div>
|
<div class="grow-0">
|
||||||
|
<a href="/" class="no-underline"
|
||||||
|
><img class="h-14 w-14 border" src="/assets/favicon.png"
|
||||||
|
/></a>
|
||||||
|
</div>
|
||||||
<div class="flex flex-col">
|
<div class="flex flex-col">
|
||||||
<h1 class="font-bold text-2xl tracking-wide">{{ .site.title }}</h1>
|
<h1 class="font-bold text-2xl tracking-wide">
|
||||||
<h2 class="italic">{{ .site.desc }}</h2>
|
<a href="/" class="no-underline text-slate-800">{{ .site.title }}</a>
|
||||||
|
</h1>
|
||||||
|
<h2 class="italic text-slate-800">{{ .site.desc }}</h2>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@@ -40,7 +46,7 @@
|
|||||||
{{ if and $model.page (HasPrefix $model.page.Path "/edition") -}}
|
{{ if and $model.page (HasPrefix $model.page.Path "/edition") -}}
|
||||||
aria-current="true"
|
aria-current="true"
|
||||||
{{- end }}
|
{{- end }}
|
||||||
data-url="/edition/"
|
data-url="/redaktion/"
|
||||||
class="text-slate-600 hover:text-slate-900 hover:cursor-pointer hover:bg-slate-100
|
class="text-slate-600 hover:text-slate-900 hover:cursor-pointer hover:bg-slate-100
|
||||||
!pr-2.5"
|
!pr-2.5"
|
||||||
:class="openeditionmenu? 'bg-slate-100' : 'closed'"
|
: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
|
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">
|
[&>a]:no-underline [&>*]:-mb-1.5 w-full pr-2.5 [&>*]:px-1.5">
|
||||||
<a
|
<a
|
||||||
href="/edition/einfuehrung/"
|
href="/redaktion/einfuehrung/"
|
||||||
{{ if and $model.page (HasPrefix $model.page.Path "/edition/einfuehrung") -}}
|
{{ if and $model.page (HasPrefix $model.page.Path "/redaktion/einfuehrung") -}}
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
>Einführung</a
|
>Einführung</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="/edition/dokumentation/"
|
href="/redaktion/dokumentation/"
|
||||||
{{ if and $model.page (HasPrefix $model.page.Path "/edition/dokumentation") -}}
|
{{ if and $model.page (HasPrefix $model.page.Path "/redaktion/dokumentation") -}}
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
>Dokumentation</a
|
>Dokumentation</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="/edition/literatur/"
|
href="/redaktion/literatur/"
|
||||||
{{ if and $model.page (HasPrefix $model.page.Path "/edition/literatur") -}}
|
{{ if and $model.page (HasPrefix $model.page.Path "/redaktion/literatur") -}}
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
>Literatur</a
|
>Literatur</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="/edition/danksagungen/"
|
href="/redaktion/lesekabinett/"
|
||||||
{{ if and $model.page (HasPrefix $model.page.Path "/edition/danksagungen") -}}
|
{{ if and $model.page (HasPrefix $model.page.Path "/redaktion/lesekabinett") -}}
|
||||||
|
aria-current="page"
|
||||||
|
{{- end -}}
|
||||||
|
>Lesekabinett</a
|
||||||
|
>
|
||||||
|
<a
|
||||||
|
href="/redaktion/danksagungen/"
|
||||||
|
{{ if and $model.page (HasPrefix $model.page.Path "/redaktion/danksagungen") -}}
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
>Danksagungen</a
|
>Danksagungen</a
|
||||||
>
|
>
|
||||||
<a
|
<a
|
||||||
href="/edition/kontakt/"
|
href="/redaktion/kontakt/"
|
||||||
{{ if and $model.page (HasPrefix $model.page.Path "/edition/kontakt") -}}
|
{{ if and $model.page (HasPrefix $model.page.Path "/redaktion/kontakt") -}}
|
||||||
aria-current="page"
|
aria-current="page"
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
>Kontakt</a
|
>Kontakt</a
|
||||||
|
|||||||
Binary file not shown.
BIN
views/public/Lesekabinett/anonymus.pdf
Normal file
BIN
views/public/Lesekabinett/anonymus.pdf
Normal file
Binary file not shown.
39
views/public/Lesekabinett/beschreibungen.txt
Normal file
39
views/public/Lesekabinett/beschreibungen.txt
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
Joseph Franz von Ratschky: Vorbericht. in: Wiener Musenalmanach. 1779, S. 3-6.
|
||||||
|
ratschky_in_wiener_1779.pdf
|
||||||
|
|
||||||
|
Gottfried August Bürger: Nothgedrungene Nachrede. in: Göttinger Musenalmanach. 1782, S. 184-192.
|
||||||
|
buerger_in_goettinger_1782.pdf
|
||||||
|
|
||||||
|
Christian Cay Lorenz Hirschfeld: An die Leser. in: Gartenkalender. 1783, S. 272.
|
||||||
|
hirschfeld_in_gartenkalender_1783.pdf
|
||||||
|
|
||||||
|
Johann Heinrich Voß: Ankündigung. in: Hamburger Musenalmanach. 1784, S. 222ff.
|
||||||
|
voss_in_hamburger_1784.pdf
|
||||||
|
|
||||||
|
Gotthold Friedrich Stäudlin: Nachrede. in: Schwäbischer Musenalmanach. 1786 [o. S.].
|
||||||
|
staeudlin_in_schwaebischer_1786.pdf
|
||||||
|
|
||||||
|
Gottfried August Bürger: Fürbitte eines ans peinliche Kreuz der Verlegenheit genagelten Herausgebers eines Musenalmanachs. in: Göttinger Musenalmanach. 1789, S. 104.
|
||||||
|
buerger_in_goettinger_1789.pdf
|
||||||
|
|
||||||
|
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.
|
||||||
|
anonymus.pdf
|
||||||
|
|
||||||
|
Stephan Schütze: Die Neujahrsversammlung. Ein dramatischer Prolog. in: Taschenbuch der Liebe und Freundschaft gewidmet. 1813, S. 1-20.
|
||||||
|
schuetze_in_taschenbuch_1813.pdf
|
||||||
|
|
||||||
|
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.
|
||||||
|
nbe_in_hermes_1820.pdf
|
||||||
|
|
||||||
|
Ferdinand Johannes Wit: Die Almanachomanie. in: Politisches Taschenbuch. 1831, S. 102-111.
|
||||||
|
wit_in_politaschenbuch_1831.pdf
|
||||||
|
|
||||||
|
August Wilhelm Schlegel: Recept. in: Deutscher Musenalmanach (Chamisso, Schwab, Gaudy). 1836, S. 18.
|
||||||
|
schlegel_in_deutscher_1836.pdf
|
||||||
|
|
||||||
|
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.
|
||||||
|
prutz_in_musenalmanache.pdf
|
||||||
|
|
||||||
|
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.
|
||||||
|
allatroia_anonymus_wochenblatt_1794.pdf
|
||||||
|
Allatroia
|
||||||
BIN
views/public/Lesekabinett/buerger_in_goettinger_1782.pdf
Normal file
BIN
views/public/Lesekabinett/buerger_in_goettinger_1782.pdf
Normal file
Binary file not shown.
BIN
views/public/Lesekabinett/buerger_in_goettinger_1789.pdf
Normal file
BIN
views/public/Lesekabinett/buerger_in_goettinger_1789.pdf
Normal file
Binary file not shown.
BIN
views/public/Lesekabinett/hirschfeld_in_gartenkalender_1783.pdf
Normal file
BIN
views/public/Lesekabinett/hirschfeld_in_gartenkalender_1783.pdf
Normal file
Binary file not shown.
BIN
views/public/Lesekabinett/nbe_in_hermes_1820.pdf
Normal file
BIN
views/public/Lesekabinett/nbe_in_hermes_1820.pdf
Normal file
Binary file not shown.
BIN
views/public/Lesekabinett/prutz_in_musenalmanache_1854.pdf
Normal file
BIN
views/public/Lesekabinett/prutz_in_musenalmanache_1854.pdf
Normal file
Binary file not shown.
BIN
views/public/Lesekabinett/ratschky_in_wiener_1779.pdf
Normal file
BIN
views/public/Lesekabinett/ratschky_in_wiener_1779.pdf
Normal file
Binary file not shown.
BIN
views/public/Lesekabinett/schlegel_in_deutscher_1836.pdf
Normal file
BIN
views/public/Lesekabinett/schlegel_in_deutscher_1836.pdf
Normal file
Binary file not shown.
BIN
views/public/Lesekabinett/schuetze_in_taschenbuch_1813.pdf
Normal file
BIN
views/public/Lesekabinett/schuetze_in_taschenbuch_1813.pdf
Normal file
Binary file not shown.
BIN
views/public/Lesekabinett/staeudlin_in_schwaebischer_1786.pdf
Normal file
BIN
views/public/Lesekabinett/staeudlin_in_schwaebischer_1786.pdf
Normal file
Binary file not shown.
BIN
views/public/Lesekabinett/voss_in_hamburger_1784.pdf
Normal file
BIN
views/public/Lesekabinett/voss_in_hamburger_1784.pdf
Normal file
Binary file not shown.
BIN
views/public/Lesekabinett/wit_in_politaschenbuch_1831.pdf
Normal file
BIN
views/public/Lesekabinett/wit_in_politaschenbuch_1831.pdf
Normal file
Binary file not shown.
@@ -38,6 +38,14 @@
|
|||||||
src: url(/assets/fonts/SourceSans3-BoldItalic.ttf) format("truetype");
|
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-face {
|
||||||
font-family: "Source Sans 3";
|
font-family: "Source Sans 3";
|
||||||
font-style: normal;
|
font-style: normal;
|
||||||
|
|||||||
BIN
views/public/fonts/Spectral-Regular.ttf
Normal file
BIN
views/public/fonts/Spectral-Regular.ttf
Normal file
Binary file not shown.
BIN
views/public/musen.png
Normal file
BIN
views/public/musen.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 249 KiB |
@@ -1 +1,53 @@
|
|||||||
Hello from the root remplate!
|
{{- $model := . -}}
|
||||||
|
<div id="intropageroot">
|
||||||
|
<image-reel class="hidden lg:block max-w-full my-8 mx-12 relative" id="imagecontainer">
|
||||||
|
<div class="overflow-hidden flex flex-row justify-between">
|
||||||
|
{{- range $i, $img := $model.bilder -}}
|
||||||
|
<div class="shrink-0 shadow-lg primages overflow-hidden w-[200px]">
|
||||||
|
<popup-image
|
||||||
|
data-image-url="{{- $img.BildPath -}}"
|
||||||
|
aria-role="button"
|
||||||
|
tabindex="0"
|
||||||
|
data-hide-dl-button="true">
|
||||||
|
<img
|
||||||
|
class="shadow h-full scale-[1.3]"
|
||||||
|
src="{{ $img.VorschauPath }}?thumb=500x0"
|
||||||
|
alt="musen" />
|
||||||
|
<div class="image-description hidden">
|
||||||
|
{{- Safe $img.Beschreibung -}}
|
||||||
|
</div>
|
||||||
|
</popup-image>
|
||||||
|
</div>
|
||||||
|
{{- end -}}
|
||||||
|
</div>
|
||||||
|
</image-reel>
|
||||||
|
|
||||||
|
<div class="w-full min-h-full mt-8">
|
||||||
|
<div class="text-center relative max-w-screen-xl mx-auto" data-="">
|
||||||
|
<img
|
||||||
|
src="/assets/musen.png"
|
||||||
|
class="max-w-[28rem] mx-auto lg:absolute left-2/3 top-2"
|
||||||
|
alt="Bild von aufsteigenden Musen" />
|
||||||
|
<a href="/reihen" class="block no-underline !font-[Spectral] small-caps text-slate-700">
|
||||||
|
<h1 class="text-2xl lg:text-4xl pt-8 lg:!pt-52 !font-[Spectral]">Willkommen auf der</h1>
|
||||||
|
<h1 class="text-4xl lg:text-8xl !font-[Spectral]">Musenalm</h1>
|
||||||
|
<h2 class="text-2xl lg:text-4xl !font-[Spectral]">Bibliographie deutscher Almanache</h2>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
<div class="mt-8 lg:text-lg font-medium lg:w-9/12 xl:w-7/12 mx-auto px-4 lg:px-0">
|
||||||
|
<div class="lg:flex gap-x-12 starttext font-serif hyphens-auto indented">
|
||||||
|
<div class="lg:w-2/3">
|
||||||
|
{{- Safe $model.texte.Abs1 -}}
|
||||||
|
</div>
|
||||||
|
<div class="lg:mt-36 lg:w-1/3">
|
||||||
|
{{- Safe $model.texte.Abs2 -}}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="text-center mt-8 startlinks font-serif text-xl" data-="">
|
||||||
|
<a href="/redaktion/einfuehrung" class="">Einleitung</a>
|
||||||
|
<div class="inline px-1">|</div>
|
||||||
|
<a href="/reihen" class="font-bold">Alle Bände<i class="ri-arrow-right-double-line"></i></a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|||||||
8
views/routes/redaktion/lesekabinett/body.gohtml
Normal file
8
views/routes/redaktion/lesekabinett/body.gohtml
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
<div class="container-normal relative">
|
||||||
|
<div class="text indented">
|
||||||
|
{{ if .record.Title }}<h1 class="mb-12">{{ .record.Title }}</h1>{{ end }}
|
||||||
|
<div class="text">
|
||||||
|
{{ Safe .record.Text }}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -2,10 +2,10 @@
|
|||||||
|
|
||||||
|
|
||||||
<div class="container-normal relative">
|
<div class="container-normal relative">
|
||||||
<div class="text indented">
|
<div class="text ">
|
||||||
{{ if .record.Title }}<h1 class="mb-12">{{ .record.Title }}</h1>{{ end }}
|
{{ if .record.Title }}<h1 class="mb-12">{{ .record.Title }}</h1>{{ end }}
|
||||||
<div class="flex flex-row gap-x-6 justify-between">
|
<div class="flex flex-row gap-x-6 justify-between ">
|
||||||
<div class="jumptext grow shrink-0">
|
<div class="grow shrink-0 text indented">
|
||||||
{{ Safe .record.Text }}
|
{{ Safe .record.Text }}
|
||||||
</div>
|
</div>
|
||||||
<div>
|
<div>
|
||||||
1
views/routes/redaktion/literatur/head.gohtml
Normal file
1
views/routes/redaktion/literatur/head.gohtml
Normal file
@@ -0,0 +1 @@
|
|||||||
|
<title>{{ .site.title }} – {{ .record.Title }}</title>
|
||||||
@@ -10,16 +10,16 @@
|
|||||||
<div class="px-8">
|
<div class="px-8">
|
||||||
{{ Safe $model.record.Text }}
|
{{ Safe $model.record.Text }}
|
||||||
<div class="pt-3">
|
<div class="pt-3">
|
||||||
<a href="/edition/einfuehrung">Einführung</i></a>
|
<a href="/redaktion/einfuehrung">Einführung</i></a>
|
||||||
<i class="ri-seedling-line px-1.5"></i>
|
<i class="ri-seedling-line px-1.5"></i>
|
||||||
<a href="/edition/dokumentation">Dokumentation </a>
|
<a href="/redaktion/dokumentation">Dokumentation </a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="mt-4 py-2 px-3 rounded bg-orange-100 border border-orange-200
|
<div class="mt-4 py-2 px-3 rounded bg-orange-100 border border-orange-200
|
||||||
text-orange-950 font-sans font-bold">
|
text-orange-950 font-sans font-bold">
|
||||||
Bitte beachten Sie, dass es sich hier noch um eine öffentliche Testversion
|
Bitte beachten Sie, dass es sich hier noch um eine öffentliche Testversion
|
||||||
handelt. Über Rückmeldungen und Anregungen freuen wir uns [→ <a
|
handelt. Über Rückmeldungen und Anregungen freuen wir uns [→ <a
|
||||||
href="/edition//kontakt">Kontakt</a>]
|
href="/redaktion//kontakt">Kontakt</a>]
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -185,7 +185,6 @@
|
|||||||
{{- else -}}
|
{{- else -}}
|
||||||
<div class="mt-4">Kein Beitrag gefunden.</div>
|
<div class="mt-4">Kein Beitrag gefunden.</div>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
</div>
|
|
||||||
|
|
||||||
<script type="module">
|
<script type="module">
|
||||||
let elements = document.querySelectorAll('.search-text');
|
let elements = document.querySelectorAll('.search-text');
|
||||||
@@ -197,5 +196,6 @@
|
|||||||
});
|
});
|
||||||
}, 200);
|
}, 200);
|
||||||
</script>
|
</script>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
|
|||||||
@@ -5,7 +5,9 @@
|
|||||||
-}}
|
-}}
|
||||||
|
|
||||||
{{- if $isFiltered -}}
|
{{- if $isFiltered -}}
|
||||||
<div class="flex flex-row gap-x-3" id="searchpills">
|
<div
|
||||||
|
class="flex flex-row gap-x-3 bg-orange-100 items-center py-1 justify-between"
|
||||||
|
id="searchpills">
|
||||||
{{- if $model.filters.Agent -}}
|
{{- if $model.filters.Agent -}}
|
||||||
<filter-pill
|
<filter-pill
|
||||||
data-queryparam="agentfilter"
|
data-queryparam="agentfilter"
|
||||||
@@ -28,6 +30,7 @@
|
|||||||
</filter-pill>
|
</filter-pill>
|
||||||
{{- end -}}
|
{{- end -}}
|
||||||
{{- if $model.filters.OnlyScans -}}
|
{{- if $model.filters.OnlyScans -}}
|
||||||
|
<div class="grow"></div>
|
||||||
<filter-pill
|
<filter-pill
|
||||||
data-queryparam="onlyscans"
|
data-queryparam="onlyscans"
|
||||||
data-value="{{ $model.filters.OnlyScans }}"
|
data-value="{{ $model.filters.OnlyScans }}"
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ const INT_LINK_ELEMENT = "int-link";
|
|||||||
const POPUP_IMAGE_ELEMENT = "popup-image";
|
const POPUP_IMAGE_ELEMENT = "popup-image";
|
||||||
const TABLIST_ELEMENT = "tab-list";
|
const TABLIST_ELEMENT = "tab-list";
|
||||||
const FILTER_PILL_ELEMENT = "filter-pill";
|
const FILTER_PILL_ELEMENT = "filter-pill";
|
||||||
|
const IMAGE_REEL_ELEMENT = "image-reel";
|
||||||
|
|
||||||
class XSLTParseProcess {
|
class XSLTParseProcess {
|
||||||
#processors;
|
#processors;
|
||||||
@@ -180,10 +181,8 @@ class FilterPill extends HTMLElement {
|
|||||||
render() {
|
render() {
|
||||||
this.innerHTML = `
|
this.innerHTML = `
|
||||||
<a href="${this.getURL()}" class="!no-underline block text-base" hx-target="#searchresults" hx-select="#searchresults" hx-swap="outerHTML show:window:top">
|
<a href="${this.getURL()}" class="!no-underline block text-base" hx-target="#searchresults" hx-select="#searchresults" hx-swap="outerHTML show:window:top">
|
||||||
<div class="flex flex-row filter-pill rounded-lg bg-orange-100 hover:saturate-50 px-2.5 mt-2">
|
<div class="flex flex-row filter-pill rounded-lg bg-orange-100 hover:saturate-50 px-2.5">
|
||||||
<div href="${this.getURL()}" class="filter-pill-close no-underline font-bold mr-1 text-orange-900 hover:text-orange-800">
|
${this.renderIcon()}
|
||||||
<i class="ri-close-circle-line"></i>
|
|
||||||
</div>
|
|
||||||
<div class="flex flex-row filter-pill-label-value !items-baseline text-slate-700">
|
<div class="flex flex-row filter-pill-label-value !items-baseline text-slate-700">
|
||||||
<div class="filter-pill-label font-bold mr-1.5 align-baseline">${this.text}</div>
|
<div class="filter-pill-label font-bold mr-1.5 align-baseline">${this.text}</div>
|
||||||
${this.renderValue()}
|
${this.renderValue()}
|
||||||
@@ -193,6 +192,23 @@ class FilterPill extends HTMLElement {
|
|||||||
`;
|
`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
renderIcon() {
|
||||||
|
const isBool = this.value === "true" || this.value === "false";
|
||||||
|
if (!isBool) {
|
||||||
|
return `<div
|
||||||
|
href="${this.getURL()}"
|
||||||
|
class="filter-pill-close no-underline font-bold mr-1 text-orange-900 hover:text-orange-800">
|
||||||
|
<i class="ri-arrow-left-s-line"></i>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
return `
|
||||||
|
<div href="${this.getURL()}" class="filter-pill-close no-underline font-bold mr-1 text-orange-900 hover:text-orange-800">
|
||||||
|
<i class="ri-close-circle-line"></i>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
renderValue() {
|
renderValue() {
|
||||||
const isBool = this.value === "true" || this.value === "false";
|
const isBool = this.value === "true" || this.value === "false";
|
||||||
if (isBool) return ``;
|
if (isBool) return ``;
|
||||||
@@ -713,10 +729,14 @@ class PopupImage extends HTMLElement {
|
|||||||
this._preview = null;
|
this._preview = null;
|
||||||
this._description = null;
|
this._description = null;
|
||||||
this._imageURL = "";
|
this._imageURL = "";
|
||||||
|
this._hideDLButton = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
connectedCallback() {
|
connectedCallback() {
|
||||||
|
this.classList.add("cursor-pointer");
|
||||||
|
this.classList.add("select-none");
|
||||||
this._imageURL = this.getAttribute("data-image-url") || "";
|
this._imageURL = this.getAttribute("data-image-url") || "";
|
||||||
|
this._hideDLButton = this.getAttribute("data-hide-dl-button") || false;
|
||||||
this._preview = this.querySelector("img");
|
this._preview = this.querySelector("img");
|
||||||
this._description = this.querySelector(".image-description");
|
this._description = this.querySelector(".image-description");
|
||||||
|
|
||||||
@@ -735,7 +755,6 @@ class PopupImage extends HTMLElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
showOverlay() {
|
showOverlay() {
|
||||||
const descriptionHtml = this._description ? this._description.innerHTML : "";
|
|
||||||
this.overlay = document.createElement("div");
|
this.overlay = document.createElement("div");
|
||||||
this.overlay.classList.add(
|
this.overlay.classList.add(
|
||||||
"fixed",
|
"fixed",
|
||||||
@@ -749,26 +768,21 @@ class PopupImage extends HTMLElement {
|
|||||||
);
|
);
|
||||||
|
|
||||||
this.overlay.innerHTML = `
|
this.overlay.innerHTML = `
|
||||||
<div class="relative w-max max-w-dvw max-h-dvh shadow-lg flex flex-col items-center gap-4">
|
<div class="relative w-max max-w-dvw max-h-dvh shadow-lg flex flex-col items-center justify-center gap-4">
|
||||||
<div class="absolute -right-16 top-0 text-white text-4xl flex flex-col">
|
<div>
|
||||||
|
<div class="absolute -right-16 text-white text-4xl flex flex-col">
|
||||||
<button class="hover:text-gray-300 cursor-pointer focus:outline-none" aria-label="Close popup">
|
<button class="hover:text-gray-300 cursor-pointer focus:outline-none" aria-label="Close popup">
|
||||||
<i class="ri-close-fill text-4xl"></i>
|
<i class="ri-close-fill text-4xl"></i>
|
||||||
</button>
|
</button>
|
||||||
<tool-tip position="right">
|
${this.downloadButton()}
|
||||||
<a href="${this._imageURL}" target="_blank" class="text-white no-underline hover:text-gray-300"><i class="ri-file-download-line"></i></a>
|
|
||||||
<div class="data-tip">Bild herunterladen</div>
|
|
||||||
</tool-tip>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<img
|
<img
|
||||||
src="${this._imageURL}"
|
src="${this._imageURL}"
|
||||||
alt="Popup Image"
|
alt="Popup Image"
|
||||||
class="full max-h-[90vh] max-w-[80vw] object-contain"
|
class="full max-h-[80vh] max-w-[80vw] object-contain block relative ${this.descriptionImgClass()}"
|
||||||
/>
|
/>
|
||||||
|
${this.description()}
|
||||||
<div class="text-center text-gray-700 description-content">
|
</div>
|
||||||
${descriptionHtml}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
`;
|
`;
|
||||||
|
|
||||||
@@ -788,6 +802,40 @@ class PopupImage extends HTMLElement {
|
|||||||
document.body.appendChild(this.overlay);
|
document.body.appendChild(this.overlay);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
descriptionImgClass() {
|
||||||
|
if (!this.description) {
|
||||||
|
return "0";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
description() {
|
||||||
|
if (!this._description) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<div class="font-serif text-left description-content mt-3 text-slate-900 ">
|
||||||
|
<div class="max-w-[80ch] hyphens-auto px-6 py-2 bg-stone-50 shadow-lg">
|
||||||
|
${this._description.innerHTML}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
downloadButton() {
|
||||||
|
if (this._hideDLButton) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
||||||
|
return `
|
||||||
|
<tool-tip position="right">
|
||||||
|
<a href="${this._imageURL}" target="_blank" class="text-white no-underline hover:text-gray-300"><i class="ri-file-download-line"></i></a>
|
||||||
|
<div class="data-tip">Bild herunterladen</div>
|
||||||
|
</tool-tip>
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
hideOverlay() {
|
hideOverlay() {
|
||||||
this.overlay.parentNode.removeChild(this.overlay);
|
this.overlay.parentNode.removeChild(this.overlay);
|
||||||
this.overlay = null;
|
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(INT_LINK_ELEMENT, IntLink);
|
||||||
customElements.define(ABBREV_TOOLTIPS_ELEMENT, AbbreviationTooltips);
|
customElements.define(ABBREV_TOOLTIPS_ELEMENT, AbbreviationTooltips);
|
||||||
customElements.define(FILTER_LIST_ELEMENT, FilterList);
|
customElements.define(FILTER_LIST_ELEMENT, FilterList);
|
||||||
@@ -1175,5 +1260,6 @@ customElements.define(TOOLTIP_ELEMENT, ToolTip);
|
|||||||
customElements.define(POPUP_IMAGE_ELEMENT, PopupImage);
|
customElements.define(POPUP_IMAGE_ELEMENT, PopupImage);
|
||||||
customElements.define(TABLIST_ELEMENT, Tablist);
|
customElements.define(TABLIST_ELEMENT, Tablist);
|
||||||
customElements.define(FILTER_PILL_ELEMENT, FilterPill);
|
customElements.define(FILTER_PILL_ELEMENT, FilterPill);
|
||||||
|
customElements.define(IMAGE_REEL_ELEMENT, ImageReel);
|
||||||
|
|
||||||
export { XSLTParseProcess, FilterList, ScrollButton, AbbreviationTooltips };
|
export { XSLTParseProcess, FilterList, ScrollButton, AbbreviationTooltips };
|
||||||
|
|||||||
@@ -242,6 +242,11 @@
|
|||||||
@apply -indent-3.5 ml-3.5;
|
@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) {
|
#searchnav > a:nth-of-type(1) {
|
||||||
@apply ml-6;
|
@apply ml-6;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user