mirror of
https://github.com/Theodor-Springmann-Stiftung/musenalm.git
synced 2026-02-04 02:25:30 +00:00
349 lines
16 KiB
Plaintext
349 lines
16 KiB
Plaintext
{{ $model := . }}
|
|
|
|
<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] align-bottom"
|
|
:aria-sort="sortField === 'alm' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'">
|
|
<div class="flex flex-col items-start gap-0.5 leading-tight">
|
|
<button type="button"
|
|
class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm"
|
|
@click="changeSort('alm')">
|
|
<span class="font-semibold tracking-wide">Alm-Nr</span>
|
|
<i class="text-xs opacity-70 transition-colors"
|
|
:class="{
|
|
'ri-arrow-up-line text-blue-600': sortField === 'alm' && sortOrder === 'asc',
|
|
'ri-arrow-down-line text-blue-600': sortField === 'alm' && sortOrder === 'desc',
|
|
'ri-arrow-up-down-line text-gray-400': sortField !== 'alm'
|
|
}"
|
|
aria-hidden="true"></i>
|
|
</button>
|
|
<span class="font-semibold tracking-wide">Nachweis</span>
|
|
</div>
|
|
</th>
|
|
<th class="py-2 pr-4 whitespace-nowrap w-[44rem] align-bottom col-title"
|
|
:aria-sort="sortField === 'title' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'">
|
|
<button type="button"
|
|
class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm"
|
|
@click="changeSort('title')">
|
|
<span class="font-semibold tracking-wide">Titel</span>
|
|
<i class="text-xs opacity-70 transition-colors"
|
|
:class="{
|
|
'ri-arrow-up-line text-blue-600': sortField === 'title' && sortOrder === 'asc',
|
|
'ri-arrow-down-line text-blue-600': sortField === 'title' && sortOrder === 'desc',
|
|
'ri-arrow-up-down-line text-gray-400': sortField !== 'title'
|
|
}"
|
|
aria-hidden="true"></i>
|
|
</button>
|
|
</th>
|
|
<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="baende-sort-button 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="baende-sort-button 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="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm"
|
|
@click="changeSort('year')">
|
|
<span class="font-semibold tracking-wide">Jahr</span>
|
|
<i class="text-xs opacity-70 transition-colors"
|
|
:class="{
|
|
'ri-arrow-up-line text-blue-600': sortField === 'year' && sortOrder === 'asc',
|
|
'ri-arrow-down-line text-blue-600': sortField === 'year' && sortOrder === 'desc',
|
|
'ri-arrow-up-down-line text-gray-400': sortField !== 'year'
|
|
}"
|
|
aria-hidden="true"></i>
|
|
</button>
|
|
</th>
|
|
<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="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm"
|
|
@click="changeSort('signatur')">
|
|
<span class="font-semibold tracking-wide">Signaturen</span>
|
|
<i class="text-xs opacity-70 transition-colors"
|
|
:class="{
|
|
'ri-arrow-up-line text-blue-600': sortField === 'signatur' && sortOrder === 'asc',
|
|
'ri-arrow-down-line text-blue-600': sortField === 'signatur' && sortOrder === 'desc',
|
|
'ri-arrow-up-down-line text-gray-400': sortField !== 'signatur'
|
|
}"
|
|
aria-hidden="true"></i>
|
|
</button>
|
|
</th>
|
|
<th class="py-2 pr-4 whitespace-nowrap col-modified hidden align-bottom w-[11.25rem]"
|
|
:aria-sort="sortField === 'updated' ? (sortOrder === 'asc' ? 'ascending' : 'descending') : 'none'">
|
|
<div class="flex flex-col items-start gap-0.5 leading-tight">
|
|
<button type="button"
|
|
class="baende-sort-button flex w-full items-center justify-between gap-1 text-left text-sm"
|
|
@click="changeSort('updated')">
|
|
<span class="font-semibold tracking-wide">Bearbeitet am</span>
|
|
<i class="text-xs opacity-70 transition-colors"
|
|
:class="{
|
|
'ri-arrow-up-line text-blue-600': sortField === 'updated' && sortOrder === 'asc',
|
|
'ri-arrow-down-line text-blue-600': sortField === 'updated' && sortOrder === 'desc',
|
|
'ri-arrow-up-down-line text-gray-400': sortField !== 'updated'
|
|
}"
|
|
aria-hidden="true"></i>
|
|
</button>
|
|
<span class="font-semibold tracking-wide">Benutzer</span>
|
|
</div>
|
|
</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody id="baende-tbody">
|
|
{{- if not (len $model.result.Entries) -}}
|
|
<tr>
|
|
<td colspan="7" class="py-6 text-center text-sm text-gray-500">
|
|
Keine Bände gefunden.
|
|
</td>
|
|
</tr>
|
|
{{- end -}}
|
|
{{- range $_, $entry := $model.result.Entries -}}
|
|
<tr class="border-b align-top cursor-pointer transition-colors odd:bg-white even:bg-stone-50/60 hover:bg-stone-100"
|
|
data-role="baende-row"
|
|
data-entry-id="{{ $entry.MusenalmID }}"
|
|
hx-get="/baende/details/{{ $entry.MusenalmID }}"
|
|
hx-target="this"
|
|
hx-swap="outerHTML"
|
|
>
|
|
<td class="py-2 pr-4 pl-2 whitespace-nowrap w-[10rem]">
|
|
<div class="flex flex-col gap-1">
|
|
<span class="inline-flex items-center rounded-xs bg-stone-100 px-2.5 py-0.5 text-xs font-semibold text-slate-700">Alm {{ $entry.MusenalmID }}</span>
|
|
{{- if $entry.References -}}
|
|
<span class="inline-flex items-center rounded-xs bg-stone-100 px-2.5 py-0.5 text-xs text-slate-700 max-w-[10rem] whitespace-normal break-words" title="{{ $entry.References }}">{{ $entry.References }}</span>
|
|
{{- end -}}
|
|
<div class="flex flex-wrap items-center gap-1.5 pt-1">
|
|
<tool-tip position="top" class="inline">
|
|
<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" 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="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" 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>
|
|
</tool-tip>
|
|
</form>
|
|
{{- end -}}
|
|
</div>
|
|
</div>
|
|
</td>
|
|
<td class="py-2 pr-4 col-title">
|
|
<div class="font-semibold text-slate-900 text-base leading-snug">
|
|
{{- if $entry.PreferredTitle -}}
|
|
<span class="inline">{{ $entry.PreferredTitle }}</span>
|
|
{{- else if ne $entry.Year 0 -}}
|
|
<span class="inline">{{ $entry.Year }}</span>
|
|
{{- else -}}
|
|
<span class="inline">[o.J.]</span>
|
|
{{- end -}}
|
|
<tool-tip position="top" class="inline-block align-middle ml-1">
|
|
<i class="status-icon 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>
|
|
<div class="data-tip">
|
|
{{- if eq $entry.EditState "Unknown" -}}
|
|
Gesucht
|
|
{{- else if eq $entry.EditState "ToDo" -}}
|
|
Zu erledigen
|
|
{{- else if eq $entry.EditState "Review" -}}
|
|
Überprüfen
|
|
{{- else if eq $entry.EditState "Seen" -}}
|
|
Autopsiert
|
|
{{- else if eq $entry.EditState "Edited" -}}
|
|
Vollständig Erfasst
|
|
{{- else -}}
|
|
{{ $entry.EditState }}
|
|
{{- end -}}
|
|
</div>
|
|
</tool-tip>
|
|
</div>
|
|
{{- if $entry.TitleStmt -}}
|
|
<div class="text-gray-700 text-base mt-1 leading-snug">
|
|
{{ $entry.TitleStmt }}
|
|
</div>
|
|
{{- end -}}
|
|
{{- if or $entry.SubtitleStmt $entry.VariantTitle $entry.ParallelTitle $entry.IncipitStmt -}}
|
|
<div class="flex flex-col gap-1 text-sm text-gray-700 mt-1">
|
|
{{- if $entry.SubtitleStmt -}}
|
|
<div><span class="font-semibold text-gray-500">Untertitel:</span> {{ $entry.SubtitleStmt }}</div>
|
|
{{- end -}}
|
|
{{- if $entry.VariantTitle -}}
|
|
<div><span class="font-semibold text-gray-500">Varianten:</span> {{ $entry.VariantTitle }}</div>
|
|
{{- end -}}
|
|
{{- if $entry.ParallelTitle -}}
|
|
<div><span class="font-semibold text-gray-500">Parallel:</span> {{ $entry.ParallelTitle }}</div>
|
|
{{- end -}}
|
|
{{- if $entry.IncipitStmt -}}
|
|
<div><span class="font-semibold text-gray-500">Incipit:</span> {{ $entry.IncipitStmt }}</div>
|
|
{{- end -}}
|
|
</div>
|
|
{{- end -}}
|
|
</td>
|
|
<td class="py-2 pr-4 col-appearance">
|
|
{{- if or $entry.ResponsibilityStmt $entry.PublicationStmt $entry.PlaceStmt -}}
|
|
<div class="flex flex-col gap-2 text-sm text-gray-700">
|
|
{{- if and $entry.ResponsibilityStmt (not (eq $entry.ResponsibilityStmt "unbezeichnet")) -}}
|
|
<div>
|
|
<div class="text-xs font-semibold text-gray-500">Herausgaberangabe</div>
|
|
<div>{{ $entry.ResponsibilityStmt }}</div>
|
|
</div>
|
|
{{- end -}}
|
|
{{- if $entry.PublicationStmt -}}
|
|
<div>
|
|
<div class="text-xs font-semibold text-gray-500">Publikationsangabe</div>
|
|
<div>{{ $entry.PublicationStmt }}</div>
|
|
</div>
|
|
{{- end -}}
|
|
{{- if $entry.PlaceStmt -}}
|
|
<div>
|
|
<div class="text-xs font-semibold text-gray-500">Ortsangabe</div>
|
|
<div>{{ $entry.PlaceStmt }}</div>
|
|
</div>
|
|
{{- end -}}
|
|
</div>
|
|
{{- end -}}
|
|
</td>
|
|
<td class="py-2 pr-4 whitespace-nowrap col-year hidden">
|
|
{{- if ne $entry.Year 0 -}}
|
|
{{ $entry.Year }}
|
|
{{- end -}}
|
|
</td>
|
|
<td class="py-2 pr-4 col-extent">
|
|
{{- if or $entry.Extent $entry.Dimensions $entry.Language -}}
|
|
<div class="flex flex-col gap-1 text-sm text-gray-700">
|
|
{{- if $entry.Extent -}}
|
|
<div>{{ $entry.Extent }}</div>
|
|
{{- end -}}
|
|
{{- if $entry.Dimensions -}}
|
|
<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 -}}
|
|
</td>
|
|
<td class="py-2 pr-4 col-signatures">
|
|
{{- $items := index $model.result.Items $entry.Id -}}
|
|
{{- 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-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 text-sm">
|
|
{{- range $i, $media := $item.Media -}}{{- if $i }}, {{ end -}}{{ $media }}{{- end -}}
|
|
</div>
|
|
{{- end -}}
|
|
</div>
|
|
{{- end -}}
|
|
</div>
|
|
{{- end -}}
|
|
</td>
|
|
<td class="py-2 pr-4 col-modified hidden w-[11.25rem]">
|
|
<div class="flex flex-col gap-1 text-sm text-gray-700">
|
|
{{- if $entry.Updated -}}
|
|
<div class="tabular-nums">{{ GermanShortDateTime $entry.Updated }}</div>
|
|
{{- end -}}
|
|
{{- $editor := $entry.Editor -}}
|
|
{{- if $editor -}}
|
|
{{- $user := index $model.result.Users $editor -}}
|
|
{{- if $user -}}
|
|
<div class="font-semibold text-slate-900">{{ $user.Name }}</div>
|
|
{{- end -}}
|
|
{{- end -}}
|
|
</div>
|
|
</td>
|
|
</tr>
|
|
{{- end -}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
|
|
<script>
|
|
(() => {
|
|
const toggleRoot = document.querySelector('[data-role="baende-column-toggle"]');
|
|
if (toggleRoot) {
|
|
const storageKey = "baende-columns";
|
|
let saved = null;
|
|
try {
|
|
saved = JSON.parse(localStorage.getItem(storageKey) || "null");
|
|
} catch {
|
|
saved = null;
|
|
}
|
|
const checkboxes = toggleRoot.querySelectorAll('input[type="checkbox"][data-col]');
|
|
checkboxes.forEach((checkbox) => {
|
|
const col = checkbox.getAttribute("data-col");
|
|
if (saved && typeof saved[col] === "boolean") {
|
|
checkbox.checked = saved[col];
|
|
}
|
|
const setColumn = (visible) => {
|
|
document.querySelectorAll(`.col-${col}`).forEach((el) => {
|
|
el.classList.toggle("hidden", !visible);
|
|
});
|
|
};
|
|
setColumn(checkbox.checked);
|
|
checkbox.addEventListener("change", (event) => {
|
|
setColumn(event.target.checked);
|
|
const nextState = {};
|
|
checkboxes.forEach((cb) => {
|
|
const key = cb.getAttribute("data-col");
|
|
nextState[key] = cb.checked;
|
|
});
|
|
localStorage.setItem(storageKey, JSON.stringify(nextState));
|
|
});
|
|
});
|
|
}
|
|
})();
|
|
</script>
|