mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2026-02-04 02:25:30 +00:00
+ /baende endpoint fixes
This commit is contained in:
@@ -240,10 +240,12 @@ func (p *BaendePage) buildResultData(app core.App, ma pagemodels.IApp, e *core.R
|
||||
|
||||
// Validate sort field - whitelist approach for security
|
||||
validSorts := map[string]bool{
|
||||
"title": true,
|
||||
"alm": true,
|
||||
"year": true,
|
||||
"signatur": true,
|
||||
"title": true,
|
||||
"alm": true,
|
||||
"year": true,
|
||||
"signatur": true,
|
||||
"responsibility": true,
|
||||
"place": true,
|
||||
}
|
||||
if !validSorts[sort] {
|
||||
sort = "title" // default
|
||||
@@ -325,6 +327,10 @@ func (p *BaendePage) buildResultData(app core.App, ma pagemodels.IApp, e *core.R
|
||||
dbmodels.Sort_Entries_Year_Title(filteredEntries)
|
||||
case "signatur":
|
||||
dbmodels.Sort_Entries_Signatur(filteredEntries, itemsMap)
|
||||
case "responsibility":
|
||||
dbmodels.Sort_Entries_Responsibility_Title(filteredEntries)
|
||||
case "place":
|
||||
dbmodels.Sort_Entries_Place_Title(filteredEntries)
|
||||
default: // "title"
|
||||
dbmodels.Sort_Entries_Title_Year(filteredEntries)
|
||||
}
|
||||
|
||||
@@ -113,3 +113,51 @@ func Sort_Entries_Signatur(entries []*Entry, itemsMap map[string][]*Item) {
|
||||
return collator.CompareString(iLowestSig, jLowestSig)
|
||||
})
|
||||
}
|
||||
|
||||
// Sort_Entries_Responsibility_Title sorts entries by responsibility statement, then preferred title.
|
||||
// Empty responsibility statements sort last.
|
||||
func Sort_Entries_Responsibility_Title(entries []*Entry) {
|
||||
collator := collate.New(language.German)
|
||||
slices.SortFunc(entries, func(i, j *Entry) int {
|
||||
iResp := i.ResponsibilityStmt()
|
||||
jResp := j.ResponsibilityStmt()
|
||||
|
||||
if iResp == "" && jResp == "" {
|
||||
return collator.CompareString(i.PreferredTitle(), j.PreferredTitle())
|
||||
}
|
||||
if iResp == "" {
|
||||
return 1
|
||||
}
|
||||
if jResp == "" {
|
||||
return -1
|
||||
}
|
||||
if iResp == jResp {
|
||||
return collator.CompareString(i.PreferredTitle(), j.PreferredTitle())
|
||||
}
|
||||
return collator.CompareString(iResp, jResp)
|
||||
})
|
||||
}
|
||||
|
||||
// Sort_Entries_Place_Title sorts entries by place statement, then preferred title.
|
||||
// Empty place statements sort last.
|
||||
func Sort_Entries_Place_Title(entries []*Entry) {
|
||||
collator := collate.New(language.German)
|
||||
slices.SortFunc(entries, func(i, j *Entry) int {
|
||||
iPlace := i.PlaceStmt()
|
||||
jPlace := j.PlaceStmt()
|
||||
|
||||
if iPlace == "" && jPlace == "" {
|
||||
return collator.CompareString(i.PreferredTitle(), j.PreferredTitle())
|
||||
}
|
||||
if iPlace == "" {
|
||||
return 1
|
||||
}
|
||||
if jPlace == "" {
|
||||
return -1
|
||||
}
|
||||
if iPlace == jPlace {
|
||||
return collator.CompareString(i.PreferredTitle(), j.PreferredTitle())
|
||||
}
|
||||
return collator.CompareString(iPlace, jPlace)
|
||||
})
|
||||
}
|
||||
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -125,8 +125,8 @@ class="container-normal font-sans mt-10">
|
||||
Alphabet
|
||||
<i class="ri-arrow-down-s-line transform origin-center transition-transform" :class="{ 'rotate-180': alphabetOpen }"></i>
|
||||
</summary>
|
||||
<div class="absolute left-0 mt-2 w-12 z-10 bg-white rounded-md shadow-lg border border-gray-200">
|
||||
<div class="p-2 flex flex-col gap-1 text-sm text-gray-700">
|
||||
<div class="absolute left-0 mt-2 z-10 bg-white rounded-md shadow-lg border border-gray-200">
|
||||
<div class="p-2 grid grid-cols-13 gap-1 text-sm text-gray-700 w-[26rem]">
|
||||
{{- range $_, $ch := $model.letters -}}
|
||||
<a href="/baende/?letter={{ $ch }}&sort={{ $model.sort_field }}&order={{ $model.sort_order }}"
|
||||
hx-get="/baende/results/?letter={{ $ch }}&sort={{ $model.sort_field }}&order={{ $model.sort_order }}"
|
||||
@@ -134,33 +134,26 @@ class="container-normal font-sans mt-10">
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="body"
|
||||
hx-push-url="/baende/?letter={{ $ch }}&sort={{ $model.sort_field }}&order={{ $model.sort_order }}"
|
||||
@click="offset = 0; hasMore = true; alphabetOpen = false; selectedLetter = '{{ $ch }}'"
|
||||
@click="offset = 0; hasMore = true; alphabetOpen = false; selectedLetter = '{{ $ch }}'; search = ''"
|
||||
:class="selectedLetter === '{{ $ch }}' ? 'bg-stone-200 font-bold' : ''"
|
||||
class="text-center py-1 px-2 rounded hover:bg-gray-100 no-underline transition-colors">
|
||||
{{ $ch }}
|
||||
</a>
|
||||
{{- end -}}
|
||||
<!-- Clear filter option -->
|
||||
<a href="/baende/?sort={{ $model.sort_field }}&order={{ $model.sort_order }}"
|
||||
hx-get="/baende/results/?sort={{ $model.sort_field }}&order={{ $model.sort_order }}"
|
||||
hx-target="#baenderesults"
|
||||
hx-swap="outerHTML"
|
||||
hx-indicator="body"
|
||||
hx-push-url="/baende/?sort={{ $model.sort_field }}&order={{ $model.sort_order }}"
|
||||
@click="offset = 0; hasMore = true; alphabetOpen = false; selectedLetter = ''"
|
||||
class="text-center py-1 px-2 rounded hover:bg-gray-100 no-underline transition-colors border-t mt-1">
|
||||
@click="offset = 0; hasMore = true; alphabetOpen = false; selectedLetter = ''; search = ''"
|
||||
class="text-center py-1 px-2 rounded hover:bg-gray-100 no-underline transition-colors col-span-13 border-t mt-1">
|
||||
Alle
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right side group: Spalten menu and count/button -->
|
||||
<div class="flex items-end gap-4">
|
||||
|
||||
|
||||
|
||||
<!-- Spalten toggle -->
|
||||
<div class="relative" x-data="{ open: false }">
|
||||
@@ -173,13 +166,16 @@ class="container-normal font-sans mt-10">
|
||||
<div class="p-4 flex flex-col gap-2 text-sm text-gray-700">
|
||||
<label class="inline-flex items-center gap-2"><input type="checkbox" data-col="appearance" checked /> Erscheinung</label>
|
||||
<label class="inline-flex items-center gap-2"><input type="checkbox" data-col="year" /> Jahr</label>
|
||||
<label class="inline-flex items-center gap-2"><input type="checkbox" data-col="language" /> Sprachen</label>
|
||||
<label class="inline-flex items-center gap-2"><input type="checkbox" data-col="extent" checked /> Umfang / Maße</label>
|
||||
<label class="inline-flex items-center gap-2"><input type="checkbox" data-col="signatures" checked /> Signaturen</label>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Right side group: count/button -->
|
||||
<div class="flex items-end gap-4 ml-auto">
|
||||
|
||||
<!-- Count and New button -->
|
||||
<div class="flex items-center gap-3">
|
||||
@@ -202,6 +198,11 @@ class="container-normal font-sans mt-10">
|
||||
<div id="baenderesults" class="mt-2" data-next-offset="{{ $model.next_offset }}">
|
||||
{{ template "_baende_table" $model }}
|
||||
|
||||
<!-- Bottom count -->
|
||||
<div id="baende-count-bottom" class="mt-4 flex justify-center text-base font-semibold font-sans text-gray-600 whitespace-nowrap">
|
||||
{{ if $model.current_count }}{{ $model.current_count }} / {{ end }}{{ if $model.total_count }}{{ $model.total_count }}{{ else }}{{ len $model.result.Entries }}{{ end }} Bände
|
||||
</div>
|
||||
|
||||
<!-- Load More Button -->
|
||||
<div class="mt-6 flex justify-center" x-show="hasMore">
|
||||
<button
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
{{ $model := . }}
|
||||
|
||||
<div class="mt-6 overflow-x-auto">
|
||||
<div class="mt-6 overflow-x-auto overflow-y-visible">
|
||||
<table class="min-w-full text-sm font-sans baende-text">
|
||||
<thead class="text-left text-gray-600 border-b">
|
||||
<tr>
|
||||
<th class="py-2 pr-4 pl-2 whitespace-nowrap w-[10rem]"
|
||||
<th class="py-2 pr-4 pl-2 whitespace-nowrap w-[10rem] align-bottom"
|
||||
:aria-sort="sortField === 'alm' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'">
|
||||
<button type="button"
|
||||
class="flex w-full items-center justify-between gap-1 text-left text-sm"
|
||||
@@ -19,7 +19,7 @@
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</th>
|
||||
<th class="py-2 pr-4 whitespace-nowrap w-[44rem]"
|
||||
<th class="py-2 pr-4 whitespace-nowrap w-[44rem] align-bottom"
|
||||
:aria-sort="sortField === 'title' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'">
|
||||
<button type="button"
|
||||
class="flex w-full items-center justify-between gap-1 text-left text-sm"
|
||||
@@ -34,8 +34,35 @@
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</th>
|
||||
<th class="py-2 pr-4 whitespace-nowrap col-appearance w-[18rem]">Erscheinung</th>
|
||||
<th class="py-2 pr-4 whitespace-nowrap col-year hidden"
|
||||
<th class="py-2 pr-4 whitespace-nowrap col-appearance w-[18rem] align-bottom">
|
||||
<div class="flex flex-col items-start gap-0.5 h-full justify-end">
|
||||
<button type="button"
|
||||
class="flex w-full items-center justify-between gap-1 text-left text-sm leading-tight"
|
||||
@click="changeSort('responsibility')">
|
||||
<span class="font-semibold tracking-wide">Herausgeber</span>
|
||||
<i class="text-xs opacity-70 transition-colors"
|
||||
:class="{
|
||||
'ri-arrow-up-line text-blue-600': sortField === 'responsibility' && sortOrder === 'asc',
|
||||
'ri-arrow-down-line text-blue-600': sortField === 'responsibility' && sortOrder === 'desc',
|
||||
'ri-arrow-up-down-line text-gray-400': sortField !== 'responsibility'
|
||||
}"
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
<button type="button"
|
||||
class="flex w-full items-center justify-between gap-1 text-left text-sm leading-tight"
|
||||
@click="changeSort('place')">
|
||||
<span class="font-semibold tracking-wide">Ortsangabe</span>
|
||||
<i class="text-xs opacity-70 transition-colors"
|
||||
:class="{
|
||||
'ri-arrow-up-line text-blue-600': sortField === 'place' && sortOrder === 'asc',
|
||||
'ri-arrow-down-line text-blue-600': sortField === 'place' && sortOrder === 'desc',
|
||||
'ri-arrow-up-down-line text-gray-400': sortField !== 'place'
|
||||
}"
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</div>
|
||||
</th>
|
||||
<th class="py-2 pr-4 whitespace-nowrap col-year hidden align-bottom"
|
||||
:aria-sort="sortField === 'year' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'">
|
||||
<button type="button"
|
||||
class="flex w-full items-center justify-between gap-1 text-left text-sm"
|
||||
@@ -50,9 +77,13 @@
|
||||
aria-hidden="true"></i>
|
||||
</button>
|
||||
</th>
|
||||
<th class="py-2 pr-4 whitespace-nowrap col-language hidden">Sprachen</th>
|
||||
<th class="py-2 pr-4 whitespace-nowrap col-extent w-[18rem]">Umfang / Maße</th>
|
||||
<th class="py-2 pr-4 whitespace-nowrap col-signatures"
|
||||
<th class="py-2 pr-4 whitespace-nowrap col-extent w-[18rem] align-bottom">
|
||||
<div class="flex flex-col items-start gap-0.5 leading-tight">
|
||||
<span class="font-semibold tracking-wide">Umfang / Maße</span>
|
||||
<span class="font-semibold tracking-wide">Sprache</span>
|
||||
</div>
|
||||
</th>
|
||||
<th class="py-2 pr-4 whitespace-nowrap col-signatures align-bottom"
|
||||
:aria-sort="sortField === 'signatur' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'">
|
||||
<button type="button"
|
||||
class="flex w-full items-center justify-between gap-1 text-left text-sm"
|
||||
@@ -86,22 +117,22 @@
|
||||
{{- end -}}
|
||||
<div class="flex flex-wrap items-center gap-1.5 pt-1">
|
||||
<tool-tip position="top" class="inline">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}" onclick="event.stopPropagation();" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<i class="ri-eye-line"></i>
|
||||
</a>
|
||||
<div class="data-tip">Ansehen</div>
|
||||
</tool-tip>
|
||||
{{- if (IsAdminOrEditor $model.request.user) -}}
|
||||
<tool-tip position="top" class="inline">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}/edit" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}/edit" onclick="event.stopPropagation();" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<i class="ri-edit-line"></i>
|
||||
</a>
|
||||
<div class="data-tip">Bearbeiten</div>
|
||||
</tool-tip>
|
||||
<form method="POST" action="/almanach/{{ $entry.MusenalmID }}/edit/delete" class="inline" onsubmit="return confirm('Band wirklich löschen?');">
|
||||
<form method="POST" action="/almanach/{{ $entry.MusenalmID }}/edit/delete" class="inline" onsubmit="event.stopPropagation(); return confirm('Band wirklich löschen?');">
|
||||
<input type="hidden" name="csrf_token" value="{{ $model.csrf_token }}" />
|
||||
<tool-tip position="top" class="inline">
|
||||
<button type="submit" class="inline-flex items-center gap-1 rounded-xs bg-red-50 px-2 py-1 text-xs font-semibold text-red-700 hover:bg-red-100 hover:text-red-900">
|
||||
<button type="submit" onclick="event.stopPropagation();" class="inline-flex items-center gap-1 rounded-xs bg-red-50 px-2 py-1 text-xs font-semibold text-red-700 hover:bg-red-100 hover:text-red-900">
|
||||
<i class="ri-delete-bin-line"></i>
|
||||
</button>
|
||||
<div class="data-tip">Löschen</div>
|
||||
@@ -112,7 +143,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-2 pr-4">
|
||||
<div class="font-semibold text-slate-900 text-base leading-snug">
|
||||
<div class="font-semibold text-slate-900 text-base leading-snug inline-flex items-center gap-1">
|
||||
{{- if $entry.PreferredTitle -}}
|
||||
{{ $entry.PreferredTitle }}
|
||||
{{- else if ne $entry.Year 0 -}}
|
||||
@@ -120,8 +151,8 @@
|
||||
{{- else -}}
|
||||
[o.J.]
|
||||
{{- end -}}
|
||||
<tool-tip position="top" class="inline">
|
||||
<i class="status-icon ml-1 align-middle {{- if eq $entry.EditState "Edited" }} ri-checkbox-circle-line{{- else if eq $entry.EditState "Seen" }} ri-information-line{{- else if eq $entry.EditState "Review" }} ri-search-line{{- else if eq $entry.EditState "ToDo" }} ri-list-check{{- else }} ri-forbid-2-line{{- end }}" data-status="{{ $entry.EditState }}"></i>
|
||||
<tool-tip position="top" class="inline-flex items-center">
|
||||
<i class="status-icon {{- if eq $entry.EditState "Edited" }} ri-checkbox-circle-line{{- else if eq $entry.EditState "Seen" }} ri-information-line{{- else if eq $entry.EditState "Review" }} ri-search-line{{- else if eq $entry.EditState "ToDo" }} ri-list-check{{- else }} ri-forbid-2-line{{- end }}" data-status="{{ $entry.EditState }}"></i>
|
||||
<div class="data-tip">
|
||||
{{- if eq $entry.EditState "Unknown" -}}
|
||||
Gesucht
|
||||
@@ -190,21 +221,24 @@
|
||||
{{ $entry.Year }}
|
||||
{{- end -}}
|
||||
</td>
|
||||
<td class="py-2 pr-4 col-language hidden">
|
||||
{{- if $entry.Language -}}
|
||||
{{- range $i, $lang := $entry.Language -}}
|
||||
{{- if $i }}, {{ end -}}{{ LanguageNameGerman $lang }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
</td>
|
||||
<td class="py-2 pr-4 col-extent">
|
||||
{{- if or $entry.Extent $entry.Dimensions -}}
|
||||
{{- if or $entry.Extent $entry.Dimensions $entry.Language -}}
|
||||
<div class="flex flex-col gap-1 text-sm text-gray-700">
|
||||
{{- if $entry.Extent -}}
|
||||
<div><span class="font-semibold text-gray-500 block">Struktur</span>{{ $entry.Extent }}</div>
|
||||
<div>{{ $entry.Extent }}</div>
|
||||
{{- end -}}
|
||||
{{- if $entry.Dimensions -}}
|
||||
<div><span class="font-semibold text-gray-500">Maße:</span> {{ $entry.Dimensions }}</div>
|
||||
<div>{{ $entry.Dimensions }}</div>
|
||||
{{- end -}}
|
||||
{{- if or $entry.Extent $entry.Dimensions -}}
|
||||
<div class="h-1"></div>
|
||||
{{- end -}}
|
||||
{{- if $entry.Language -}}
|
||||
<div class="flex flex-wrap gap-1.5 pt-0.5">
|
||||
{{- range $i, $lang := $entry.Language -}}
|
||||
<span class="inline-flex items-center rounded-xs border border-slate-200 bg-white px-2 py-0.5 text-xs font-semibold text-slate-700">{{ LanguageNameGerman $lang }}</span>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
@@ -214,12 +248,12 @@
|
||||
{{- if $items -}}
|
||||
<div class="flex flex-col gap-2 text-sm text-gray-700">
|
||||
{{- range $_, $item := $items -}}
|
||||
<div class="inline-flex flex-col items-center justify-center rounded-xs border border-slate-200 bg-white text-xs">
|
||||
<div class="inline-flex flex-col items-center justify-center rounded-xs border border-slate-200 bg-white text-sm">
|
||||
{{- if $item.Identifier -}}
|
||||
<div class="px-2 py-1 font-semibold text-slate-900 text-center">{{ $item.Identifier }}</div>
|
||||
{{- end -}}
|
||||
{{- if $item.Media -}}
|
||||
<div class="w-full border-t border-slate-200 px-2 py-1 text-gray-600 text-center leading-snug">
|
||||
<div class="w-full border-t border-slate-200 px-2 py-1 text-gray-600 text-center leading-snug text-sm">
|
||||
{{- range $i, $media := $item.Media -}}{{- if $i }}, {{ end -}}{{ $media }}{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
|
||||
@@ -9,22 +9,22 @@
|
||||
{{- end -}}
|
||||
<div class="flex flex-wrap items-center gap-1.5 pt-2">
|
||||
<tool-tip position="top" class="inline">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}" onclick="event.stopPropagation();" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<i class="ri-eye-line"></i>
|
||||
</a>
|
||||
<div class="data-tip">Ansehen</div>
|
||||
</tool-tip>
|
||||
{{- if $result.IsAdmin -}}
|
||||
<tool-tip position="top" class="inline">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}/edit" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}/edit" onclick="event.stopPropagation();" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<i class="ri-edit-line"></i>
|
||||
</a>
|
||||
<div class="data-tip">Bearbeiten</div>
|
||||
</tool-tip>
|
||||
<form method="POST" action="/almanach/{{ $entry.MusenalmID }}/edit/delete" class="inline" onsubmit="return confirm('Band wirklich löschen?');">
|
||||
<form method="POST" action="/almanach/{{ $entry.MusenalmID }}/edit/delete" class="inline" onsubmit="event.stopPropagation(); return confirm('Band wirklich löschen?');">
|
||||
<input type="hidden" name="csrf_token" value="{{ $result.CSRFToken }}" />
|
||||
<tool-tip position="top" class="inline">
|
||||
<button type="submit" class="inline-flex items-center gap-1 rounded-xs bg-red-50 px-2 py-1 text-xs font-semibold text-red-700 hover:bg-red-100 hover:text-red-900">
|
||||
<button type="submit" onclick="event.stopPropagation();" class="inline-flex items-center gap-1 rounded-xs bg-red-50 px-2 py-1 text-xs font-semibold text-red-700 hover:bg-red-100 hover:text-red-900">
|
||||
<i class="ri-delete-bin-line"></i>
|
||||
|
||||
</button>
|
||||
@@ -35,6 +35,7 @@
|
||||
<tool-tip position="top" class="inline">
|
||||
<button
|
||||
type="button"
|
||||
onclick="event.stopPropagation();"
|
||||
class="inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900"
|
||||
hx-get="/baende/row/{{ $entry.MusenalmID }}"
|
||||
hx-target="closest tr"
|
||||
@@ -50,7 +51,7 @@
|
||||
<td class="py-2 pr-4 pl-2" colspan="6">
|
||||
<div class="rounded-md border border-slate-200 bg-white shadow-sm p-3 text-base">
|
||||
<div class="flex items-start justify-between gap-4 mb-3">
|
||||
<div class="font-sans text-base font-semibold text-slate-900 inline-flex items-center">
|
||||
<div class="font-sans text-base font-semibold text-slate-900 inline-flex items-center gap-1">
|
||||
{{- if $entry.PreferredTitle -}}
|
||||
{{ $entry.PreferredTitle }}
|
||||
{{- else if ne $entry.Year 0 -}}
|
||||
@@ -59,7 +60,7 @@
|
||||
[o.J.]
|
||||
{{- end -}}
|
||||
<tool-tip position="top" class="inline-flex items-center">
|
||||
<i class="status-icon ml-1 {{- if eq $entry.EditState "Edited" }} ri-checkbox-circle-line{{- else if eq $entry.EditState "Seen" }} ri-information-line{{- else if eq $entry.EditState "Review" }} ri-search-line{{- else if eq $entry.EditState "ToDo" }} ri-list-check{{- else }} ri-forbid-2-line{{- end }}" data-status="{{ $entry.EditState }}"></i>
|
||||
<i class="status-icon {{- if eq $entry.EditState "Edited" }} ri-checkbox-circle-line{{- else if eq $entry.EditState "Seen" }} ri-information-line{{- else if eq $entry.EditState "Review" }} ri-search-line{{- else if eq $entry.EditState "ToDo" }} ri-list-check{{- else }} ri-forbid-2-line{{- end }}" data-status="{{ $entry.EditState }}"></i>
|
||||
<div class="data-tip">
|
||||
{{- if eq $entry.EditState "Unknown" -}}
|
||||
Gesucht
|
||||
@@ -78,7 +79,7 @@
|
||||
</tool-tip>
|
||||
</div>
|
||||
</div>
|
||||
<div class="grid grid-cols-1 lg:grid-cols-[1fr_18rem] gap-6 text-base font-sans text-gray-700">
|
||||
<div class="grid grid-cols-1 lg:grid-cols-[1fr_18rem] gap-6 text-base font-sans text-gray-700 baende-details-card">
|
||||
<div class="flex flex-col gap-3">
|
||||
{{- if or $entry.TitleStmt $entry.SubtitleStmt $entry.VariantTitle $entry.ParallelTitle $entry.IncipitStmt -}}
|
||||
<div>
|
||||
@@ -105,7 +106,7 @@
|
||||
{{- if $entry.Annotation -}}
|
||||
<div>
|
||||
<div class="text-xs uppercase tracking-wide text-gray-500">Annotation</div>
|
||||
<div>{{ $entry.Annotation }}</div>
|
||||
<div class="annotation-content">{{- Safe (ReplaceSlashParen $entry.Annotation) -}}</div>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- if $result.SeriesRels -}}
|
||||
@@ -162,7 +163,7 @@
|
||||
{{- if $entry.Comment -}}
|
||||
<div>
|
||||
<div class="text-xs uppercase tracking-wide text-gray-500">Kommentar</div>
|
||||
<div>{{ $entry.Comment }}</div>
|
||||
<div class="annotation-content">{{- Safe (ReplaceSlashParen $entry.Comment) -}}</div>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- if ne $entry.Year 0 -}}
|
||||
@@ -206,33 +207,62 @@
|
||||
{{- if $result.Items -}}
|
||||
<div>
|
||||
<div class="text-xs uppercase tracking-wide text-gray-500">Exemplare</div>
|
||||
<div class="flex flex-col gap-2">
|
||||
<div class="grid grid-cols-1 gap-4">
|
||||
{{- range $_, $item := $result.Items -}}
|
||||
<div class="rounded-md border border-slate-200 bg-white px-3 py-2 shadow-sm">
|
||||
<div class="flex items-start gap-3">
|
||||
<div class="inline-flex flex-col items-center justify-center rounded-xs border border-slate-200 bg-white text-xs min-w-[6rem]">
|
||||
{{- if $item.Identifier -}}
|
||||
<div class="px-2 py-1 font-semibold text-slate-900 text-center">{{ $item.Identifier }}</div>
|
||||
{{- end -}}
|
||||
{{- if $item.Media -}}
|
||||
<div class="w-full border-t border-slate-200 px-2 py-1 text-gray-600 text-center leading-snug">
|
||||
<div class="rounded-sm border border-slate-200 bg-white">
|
||||
<div class="divide-y divide-slate-200 text-sm text-gray-700">
|
||||
{{- if $item.Identifier -}}
|
||||
<div class="grid grid-cols-[5rem_1fr] items-center gap-3 px-3 py-1.5">
|
||||
<span class="text-xs uppercase tracking-wide text-gray-500 whitespace-nowrap">Signatur</span>
|
||||
<span class="font-semibold text-slate-900">{{ $item.Identifier }}</span>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- if $item.Media -}}
|
||||
<div class="grid grid-cols-[5rem_1fr] items-center gap-3 px-3 py-1.5">
|
||||
<span class="text-xs uppercase tracking-wide text-gray-500 whitespace-nowrap">Status</span>
|
||||
<span class="font-medium text-slate-800">
|
||||
{{- range $i, $media := $item.Media -}}{{- if $i }}, {{ end -}}{{ $media }}{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
<div class="flex-1">
|
||||
{{- if or $item.Location $item.Owner -}}
|
||||
<div class="text-sm text-gray-600">
|
||||
{{- if $item.Location -}}<span>{{ $item.Location }}</span>{{- end -}}
|
||||
{{- if $item.Owner -}}<span class="ml-2">{{ $item.Owner }}</span>{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
</span>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- if $item.Location -}}
|
||||
<div class="grid grid-cols-[5rem_1fr] items-center gap-3 px-3 py-1.5">
|
||||
<span class="text-xs uppercase tracking-wide text-gray-500 whitespace-nowrap">Standort</span>
|
||||
<span class="font-medium text-slate-800">{{ $item.Location }}</span>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- if $item.Owner -}}
|
||||
<div class="grid grid-cols-[5rem_1fr] items-center gap-3 px-3 py-1.5">
|
||||
<span class="text-xs uppercase tracking-wide text-gray-500 whitespace-nowrap">Träger</span>
|
||||
<span class="font-medium text-slate-800">{{ $item.Owner }}</span>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- if $item.Condition -}}
|
||||
<div class="grid grid-cols-[5rem_1fr] items-center gap-3 px-3 py-1.5">
|
||||
<span class="text-xs uppercase tracking-wide text-gray-500 whitespace-nowrap">Zustand</span>
|
||||
<span class="font-medium text-slate-800">{{ $item.Condition }}</span>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- if $item.Annotation -}}
|
||||
<div class="grid grid-cols-[5rem_1fr] items-center gap-3 px-3 py-1.5">
|
||||
<span class="text-xs uppercase tracking-wide text-gray-500 whitespace-nowrap">Anmerkung</span>
|
||||
<span class="text-slate-700 annotation-content annotation-small">{{- Safe (ReplaceSlashParen $item.Annotation) -}}</span>
|
||||
</div>
|
||||
{{- end -}}
|
||||
{{- if $item.Uri -}}
|
||||
<div class="grid grid-cols-[5rem_1fr] items-center gap-3 px-3 py-1.5">
|
||||
<span class="text-xs uppercase tracking-wide text-gray-500 whitespace-nowrap">URI</span>
|
||||
<a href="{{ $item.Uri }}" class="text-slate-700 hover:text-slate-900 underline underline-offset-2" target="_blank" rel="noopener">Link öffnen</a>
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- if or $item.Location $item.Owner -}}
|
||||
{{- if or $item.Location $item.Owner $item.Condition $item.Annotation $item.Uri -}}
|
||||
<div class="sr-only">
|
||||
{{- if $item.Location -}}<span>{{ $item.Location }}</span>{{- end -}}
|
||||
{{- if $item.Owner -}}<span class="ml-2">{{ $item.Owner }}</span>{{- end -}}
|
||||
{{- if $item.Condition -}}<span class="ml-2">{{ $item.Condition }}</span>{{- end -}}
|
||||
{{- if $item.Annotation -}}<span class="ml-2">{{ $item.Annotation }}</span>{{- end -}}
|
||||
{{- if $item.Uri -}}<span class="ml-2">{{ $item.Uri }}</span>{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
@@ -245,4 +275,3 @@
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
|
||||
|
||||
@@ -15,22 +15,22 @@
|
||||
{{- end -}}
|
||||
<div class="flex flex-wrap items-center gap-1.5 pt-1">
|
||||
<tool-tip position="top" class="inline">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}" onclick="event.stopPropagation();" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<i class="ri-eye-line"></i>
|
||||
</a>
|
||||
<div class="data-tip">Ansehen</div>
|
||||
</tool-tip>
|
||||
{{- if (IsAdminOrEditor $model.request.user) -}}
|
||||
<tool-tip position="top" class="inline">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}/edit" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}/edit" onclick="event.stopPropagation();" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<i class="ri-edit-line"></i>
|
||||
</a>
|
||||
<div class="data-tip">Bearbeiten</div>
|
||||
</tool-tip>
|
||||
<form method="POST" action="/almanach/{{ $entry.MusenalmID }}/edit/delete" class="inline" onsubmit="return confirm('Band wirklich löschen?');">
|
||||
<form method="POST" action="/almanach/{{ $entry.MusenalmID }}/edit/delete" class="inline" onsubmit="event.stopPropagation(); return confirm('Band wirklich löschen?');">
|
||||
<input type="hidden" name="csrf_token" value="{{ $model.csrf_token }}" />
|
||||
<tool-tip position="top" class="inline">
|
||||
<button type="submit" class="inline-flex items-center gap-1 rounded-xs bg-red-50 px-2 py-1 text-xs font-semibold text-red-700 hover:bg-red-100 hover:text-red-900">
|
||||
<button type="submit" onclick="event.stopPropagation();" class="inline-flex items-center gap-1 rounded-xs bg-red-50 px-2 py-1 text-xs font-semibold text-red-700 hover:bg-red-100 hover:text-red-900">
|
||||
<i class="ri-delete-bin-line"></i>
|
||||
</button>
|
||||
<div class="data-tip">Löschen</div>
|
||||
@@ -41,7 +41,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-2 pr-4">
|
||||
<div class="font-semibold text-slate-900 text-base leading-snug">
|
||||
<div class="font-semibold text-slate-900 text-base leading-snug inline-flex items-center gap-1">
|
||||
{{- if $entry.PreferredTitle -}}
|
||||
{{ $entry.PreferredTitle }}
|
||||
{{- else if ne $entry.Year 0 -}}
|
||||
@@ -49,8 +49,8 @@
|
||||
{{- else -}}
|
||||
[o.J.]
|
||||
{{- end -}}
|
||||
<tool-tip position="top" class="inline">
|
||||
<i class="status-icon ml-1 align-middle {{- if eq $entry.EditState "Edited" }} ri-checkbox-circle-line{{- else if eq $entry.EditState "Seen" }} ri-information-line{{- else if eq $entry.EditState "Review" }} ri-search-line{{- else if eq $entry.EditState "ToDo" }} ri-list-check{{- else }} ri-forbid-2-line{{- end }}" data-status="{{ $entry.EditState }}"></i>
|
||||
<tool-tip position="top" class="inline-flex items-center">
|
||||
<i class="status-icon {{- if eq $entry.EditState "Edited" }} ri-checkbox-circle-line{{- else if eq $entry.EditState "Seen" }} ri-information-line{{- else if eq $entry.EditState "Review" }} ri-search-line{{- else if eq $entry.EditState "ToDo" }} ri-list-check{{- else }} ri-forbid-2-line{{- end }}" data-status="{{ $entry.EditState }}"></i>
|
||||
<div class="data-tip">
|
||||
{{- if eq $entry.EditState "Unknown" -}}
|
||||
Gesucht
|
||||
@@ -119,21 +119,24 @@
|
||||
{{ $entry.Year }}
|
||||
{{- end -}}
|
||||
</td>
|
||||
<td class="py-2 pr-4 col-language hidden">
|
||||
{{- if $entry.Language -}}
|
||||
{{- range $i, $lang := $entry.Language -}}
|
||||
{{- if $i }}, {{ end -}}{{ LanguageNameGerman $lang }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
</td>
|
||||
<td class="py-2 pr-4 col-extent">
|
||||
{{- if or $entry.Extent $entry.Dimensions -}}
|
||||
{{- if or $entry.Extent $entry.Dimensions $entry.Language -}}
|
||||
<div class="flex flex-col gap-1 text-sm text-gray-700">
|
||||
{{- if $entry.Extent -}}
|
||||
<div><span class="font-semibold text-gray-500 block">Struktur</span>{{ $entry.Extent }}</div>
|
||||
<div>{{ $entry.Extent }}</div>
|
||||
{{- end -}}
|
||||
{{- if $entry.Dimensions -}}
|
||||
<div><span class="font-semibold text-gray-500">Maße:</span> {{ $entry.Dimensions }}</div>
|
||||
<div>{{ $entry.Dimensions }}</div>
|
||||
{{- end -}}
|
||||
{{- if or $entry.Extent $entry.Dimensions -}}
|
||||
<div class="h-1"></div>
|
||||
{{- end -}}
|
||||
{{- if $entry.Language -}}
|
||||
<div class="flex flex-wrap gap-1.5 pt-0.5">
|
||||
{{- range $i, $lang := $entry.Language -}}
|
||||
<span class="inline-flex items-center rounded-xs border border-slate-200 bg-white px-2 py-0.5 text-xs font-semibold text-slate-700">{{ LanguageNameGerman $lang }}</span>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
@@ -143,12 +146,12 @@
|
||||
{{- if $items -}}
|
||||
<div class="flex flex-col gap-2 text-sm text-gray-700">
|
||||
{{- range $_, $item := $items -}}
|
||||
<div class="inline-flex flex-col items-center justify-center rounded-xs border border-slate-200 bg-white text-xs">
|
||||
<div class="inline-flex flex-col items-center justify-center rounded-xs border border-slate-200 bg-white text-sm">
|
||||
{{- if $item.Identifier -}}
|
||||
<div class="px-2 py-1 font-semibold text-slate-900 text-center">{{ $item.Identifier }}</div>
|
||||
{{- end -}}
|
||||
{{- if $item.Media -}}
|
||||
<div class="w-full border-t border-slate-200 px-2 py-1 text-gray-600 text-center leading-snug">
|
||||
<div class="w-full border-t border-slate-200 px-2 py-1 text-gray-600 text-center leading-snug text-sm">
|
||||
{{- range $i, $media := $item.Media -}}{{- if $i }}, {{ end -}}{{ $media }}{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
|
||||
@@ -17,6 +17,10 @@
|
||||
|
||||
{{ template "_baende_table" $model }}
|
||||
|
||||
<div id="baende-count-bottom" class="mt-4 flex justify-center text-base font-semibold font-sans text-gray-600 whitespace-nowrap">
|
||||
{{ if $model.current_count }}{{ $model.current_count }} / {{ end }}{{ if $model.total_count }}{{ $model.total_count }}{{ else }}{{ len $model.result.Entries }}{{ end }} Bände
|
||||
</div>
|
||||
|
||||
<!-- Load More Button -->
|
||||
<div class="mt-6 flex justify-center" x-show="hasMore">
|
||||
<button
|
||||
|
||||
@@ -15,22 +15,22 @@
|
||||
{{- end -}}
|
||||
<div class="flex flex-wrap items-center gap-1.5 pt-1">
|
||||
<tool-tip position="top" class="inline">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}" onclick="event.stopPropagation();" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<i class="ri-eye-line"></i>
|
||||
</a>
|
||||
<div class="data-tip">Ansehen</div>
|
||||
</tool-tip>
|
||||
{{- if .is_admin -}}
|
||||
<tool-tip position="top" class="inline">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}/edit" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<a href="/almanach/{{ $entry.MusenalmID }}/edit" onclick="event.stopPropagation();" class="no-underline inline-flex items-center gap-1 rounded-xs bg-stone-100 px-2 py-1 text-xs font-semibold text-slate-700 hover:bg-stone-200 hover:text-slate-900">
|
||||
<i class="ri-edit-line"></i>
|
||||
</a>
|
||||
<div class="data-tip">Bearbeiten</div>
|
||||
</tool-tip>
|
||||
<form method="POST" action="/almanach/{{ $entry.MusenalmID }}/edit/delete" class="inline" onsubmit="return confirm('Band wirklich löschen?');">
|
||||
<form method="POST" action="/almanach/{{ $entry.MusenalmID }}/edit/delete" class="inline" onsubmit="event.stopPropagation(); return confirm('Band wirklich löschen?');">
|
||||
<input type="hidden" name="csrf_token" value="{{ $model.csrf_token }}" />
|
||||
<tool-tip position="top" class="inline">
|
||||
<button type="submit" class="inline-flex items-center gap-1 rounded-xs bg-red-50 px-2 py-1 text-xs font-semibold text-red-700 hover:bg-red-100 hover:text-red-900">
|
||||
<button type="submit" onclick="event.stopPropagation();" class="inline-flex items-center gap-1 rounded-xs bg-red-50 px-2 py-1 text-xs font-semibold text-red-700 hover:bg-red-100 hover:text-red-900">
|
||||
<i class="ri-delete-bin-line"></i>
|
||||
</button>
|
||||
<div class="data-tip">Löschen</div>
|
||||
@@ -41,7 +41,7 @@
|
||||
</div>
|
||||
</td>
|
||||
<td class="py-2 pr-4">
|
||||
<div class="font-semibold text-slate-900 text-base leading-snug">
|
||||
<div class="font-semibold text-slate-900 text-base leading-snug inline-flex items-center gap-1">
|
||||
{{- if $entry.PreferredTitle -}}
|
||||
{{ $entry.PreferredTitle }}
|
||||
{{- else if ne $entry.Year 0 -}}
|
||||
@@ -49,8 +49,8 @@
|
||||
{{- else -}}
|
||||
[o.J.]
|
||||
{{- end -}}
|
||||
<tool-tip position="top" class="inline">
|
||||
<i class="status-icon ml-1 align-middle {{- if eq $entry.EditState "Edited" }} ri-checkbox-circle-line{{- else if eq $entry.EditState "Seen" }} ri-information-line{{- else if eq $entry.EditState "Review" }} ri-search-line{{- else if eq $entry.EditState "ToDo" }} ri-list-check{{- else }} ri-forbid-2-line{{- end }}" data-status="{{ $entry.EditState }}"></i>
|
||||
<tool-tip position="top" class="inline-flex items-center">
|
||||
<i class="status-icon {{- if eq $entry.EditState "Edited" }} ri-checkbox-circle-line{{- else if eq $entry.EditState "Seen" }} ri-information-line{{- else if eq $entry.EditState "Review" }} ri-search-line{{- else if eq $entry.EditState "ToDo" }} ri-list-check{{- else }} ri-forbid-2-line{{- end }}" data-status="{{ $entry.EditState }}"></i>
|
||||
<div class="data-tip">
|
||||
{{- if eq $entry.EditState "Unknown" -}}
|
||||
Gesucht
|
||||
@@ -119,21 +119,24 @@
|
||||
{{ $entry.Year }}
|
||||
{{- end -}}
|
||||
</td>
|
||||
<td class="py-2 pr-4 col-language hidden">
|
||||
{{- if $entry.Language -}}
|
||||
{{- range $i, $lang := $entry.Language -}}
|
||||
{{- if $i }}, {{ end -}}{{ LanguageNameGerman $lang }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
</td>
|
||||
<td class="py-2 pr-4 col-extent">
|
||||
{{- if or $entry.Extent $entry.Dimensions -}}
|
||||
{{- if or $entry.Extent $entry.Dimensions $entry.Language -}}
|
||||
<div class="flex flex-col gap-1 text-sm text-gray-700">
|
||||
{{- if $entry.Extent -}}
|
||||
<div><span class="font-semibold text-gray-500 block">Struktur</span>{{ $entry.Extent }}</div>
|
||||
<div>{{ $entry.Extent }}</div>
|
||||
{{- end -}}
|
||||
{{- if $entry.Dimensions -}}
|
||||
<div><span class="font-semibold text-gray-500">Maße:</span> {{ $entry.Dimensions }}</div>
|
||||
<div>{{ $entry.Dimensions }}</div>
|
||||
{{- end -}}
|
||||
{{- if or $entry.Extent $entry.Dimensions -}}
|
||||
<div class="h-1"></div>
|
||||
{{- end -}}
|
||||
{{- if $entry.Language -}}
|
||||
<div class="flex flex-wrap gap-1.5 pt-0.5">
|
||||
{{- range $i, $lang := $entry.Language -}}
|
||||
<span class="inline-flex items-center rounded-xs border border-slate-200 bg-white px-2 py-0.5 text-xs font-semibold text-slate-700">{{ LanguageNameGerman $lang }}</span>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
@@ -143,12 +146,12 @@
|
||||
{{- if $items -}}
|
||||
<div class="flex flex-col gap-2 text-sm text-gray-700">
|
||||
{{- range $_, $item := $items -}}
|
||||
<div class="inline-flex flex-col items-center justify-center rounded-xs border border-slate-200 bg-white text-xs">
|
||||
<div class="inline-flex flex-col items-center justify-center rounded-xs border border-slate-200 bg-white text-sm">
|
||||
{{- if $item.Identifier -}}
|
||||
<div class="px-2 py-1 font-semibold text-slate-900 text-center">{{ $item.Identifier }}</div>
|
||||
{{- end -}}
|
||||
{{- if $item.Media -}}
|
||||
<div class="w-full border-t border-slate-200 px-2 py-1 text-gray-600 text-center leading-snug">
|
||||
<div class="w-full border-t border-slate-200 px-2 py-1 text-gray-600 text-center leading-snug text-sm">
|
||||
{{- range $i, $media := $item.Media -}}{{- if $i }}, {{ end -}}{{ $media }}{{- end -}}
|
||||
</div>
|
||||
{{- end -}}
|
||||
|
||||
@@ -300,6 +300,15 @@
|
||||
@apply font-serif;
|
||||
}
|
||||
|
||||
/* Card view (baende details) should use sans annotations */
|
||||
.baende-details-card .annotation-content {
|
||||
@apply font-sans text-base;
|
||||
}
|
||||
|
||||
.baende-details-card .annotation-small {
|
||||
@apply text-sm;
|
||||
}
|
||||
|
||||
/* Headings - bold with spacing, same font size */
|
||||
.annotation-content h1 {
|
||||
@apply font-bold mt-2 mb-1 leading-normal;
|
||||
|
||||
@@ -81,7 +81,7 @@ export class ToolTip extends HTMLElement {
|
||||
"tooltip-box",
|
||||
"opacity-0",
|
||||
"hidden",
|
||||
"absolute",
|
||||
"fixed",
|
||||
"px-2",
|
||||
"py-1",
|
||||
"text-sm",
|
||||
@@ -89,7 +89,7 @@ export class ToolTip extends HTMLElement {
|
||||
"bg-gray-900",
|
||||
"rounded",
|
||||
"shadow",
|
||||
"z-10",
|
||||
"z-50",
|
||||
"whitespace-nowrap",
|
||||
"transition-all",
|
||||
"duration-200",
|
||||
@@ -169,6 +169,7 @@ export class ToolTip extends HTMLElement {
|
||||
clearTimeout(this._hideTimeout);
|
||||
clearTimeout(this._hiddenTimeout);
|
||||
this._tooltipBox.classList.remove("hidden");
|
||||
this._updatePosition();
|
||||
setTimeout(() => {
|
||||
this._tooltipBox.classList.remove("opacity-0");
|
||||
this._tooltipBox.classList.add("opacity-100");
|
||||
@@ -186,61 +187,40 @@ export class ToolTip extends HTMLElement {
|
||||
}
|
||||
|
||||
_updatePosition() {
|
||||
this._tooltipBox.classList.remove(
|
||||
"bottom-full",
|
||||
"left-1/2",
|
||||
"-translate-x-1/2",
|
||||
"mb-2", // top
|
||||
"top-full",
|
||||
"mt-2", // bottom
|
||||
"right-full",
|
||||
"-translate-y-1/2",
|
||||
"mr-2",
|
||||
"top-1/2", // left
|
||||
"left-full",
|
||||
"ml-2", // right
|
||||
);
|
||||
const anchorRect = this.getBoundingClientRect();
|
||||
const tipRect = this._tooltipBox.getBoundingClientRect();
|
||||
const gap = 6;
|
||||
|
||||
let top = 0;
|
||||
let left = 0;
|
||||
const pos = this.getAttribute("position") || "top";
|
||||
|
||||
switch (pos) {
|
||||
case "bottom":
|
||||
this._tooltipBox.classList.add(
|
||||
"top-full",
|
||||
"left-1/2",
|
||||
"transform",
|
||||
"-translate-x-1/2",
|
||||
"mt-0.5",
|
||||
);
|
||||
top = anchorRect.bottom + gap;
|
||||
left = anchorRect.left + (anchorRect.width - tipRect.width) / 2;
|
||||
break;
|
||||
case "left":
|
||||
this._tooltipBox.classList.add(
|
||||
"right-full",
|
||||
"top-1/2",
|
||||
"transform",
|
||||
"-translate-y-1/2",
|
||||
"mr-0.5",
|
||||
);
|
||||
top = anchorRect.top + (anchorRect.height - tipRect.height) / 2;
|
||||
left = anchorRect.left - tipRect.width - gap;
|
||||
break;
|
||||
case "right":
|
||||
this._tooltipBox.classList.add(
|
||||
"left-full",
|
||||
"top-1/2",
|
||||
"transform",
|
||||
"-translate-y-1/2",
|
||||
"ml-0.5",
|
||||
);
|
||||
top = anchorRect.top + (anchorRect.height - tipRect.height) / 2;
|
||||
left = anchorRect.right + gap;
|
||||
break;
|
||||
case "top":
|
||||
default:
|
||||
// top as default
|
||||
this._tooltipBox.classList.add(
|
||||
"bottom-full",
|
||||
"left-1/2",
|
||||
"transform",
|
||||
"-translate-x-1/2",
|
||||
"mb-0.5",
|
||||
);
|
||||
top = anchorRect.top - tipRect.height - gap;
|
||||
left = anchorRect.left + (anchorRect.width - tipRect.width) / 2;
|
||||
}
|
||||
|
||||
const padding = 4;
|
||||
const maxLeft = window.innerWidth - tipRect.width - padding;
|
||||
const maxTop = window.innerHeight - tipRect.height - padding;
|
||||
left = Math.max(padding, Math.min(left, maxLeft));
|
||||
top = Math.max(padding, Math.min(top, maxTop));
|
||||
|
||||
this._tooltipBox.style.left = `${left}px`;
|
||||
this._tooltipBox.style.top = `${top}px`;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user