Abschluss einfache Inhaltsuche

This commit is contained in:
Simon Martens
2025-03-01 04:48:47 +01:00
parent 8bc1fdb79c
commit 64c24480ca
8 changed files with 226 additions and 18 deletions

View File

@@ -67,6 +67,39 @@ func (p *BeitraegeFilterParameters) FieldSetBeitraege() []dbmodels.FTS5QueryRequ
return ret return ret
} }
func (p BeitraegeFilterParameters) ToQueryParams() string {
r := ""
if p.Agent != "" {
r += "&" + FILTER_PARAM_BEIAEGE_AGENT + "=" + p.Agent
}
if p.Type != "" {
r += "&" + FILTER_PARAM_BEIAEGE_TYPE + "=" + p.Type
}
if p.Year != "" {
r += "&" + FILTER_PARAM_BEIAEGE_YEAR + "=" + p.Year
}
if p.OnlyScans {
r += "&" + FILTER_PARAM_BEIAEGE_ONLYSCANS + "=on"
}
return r
}
func (p BeitraegeFilterParameters) ToQueryParamsWOScans() string {
r := ""
if p.Agent != "" {
r += "&" + FILTER_PARAM_BEIAEGE_AGENT + "=" + p.Agent
}
if p.Type != "" {
r += "&" + FILTER_PARAM_BEIAEGE_TYPE + "=" + p.Type
}
if p.Year != "" {
r += "&" + FILTER_PARAM_BEIAEGE_YEAR + "=" + p.Year
}
return r
}
type SearchResultBeitraege struct { type SearchResultBeitraege struct {
Queries []dbmodels.FTS5QueryRequest Queries []dbmodels.FTS5QueryRequest

View File

@@ -21,14 +21,12 @@
{{ end }} {{ end }}
<script type="module" src="/assets/scripts.js"></script>
<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 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 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" />

View File

@@ -140,14 +140,15 @@
{{- template "_fieldscript" -}} {{- template "_fieldscript" -}}
{{- if $model.parameters.IsBeitraegeSearch -}} {{- if $model.parameters.IsBeitraegeSearch -}}
<div class="cotents" id="searchresult"> <div class="cotents" id="searchresults">
{{- if $model.result.Hits -}} {{- if $model.result.Hits -}}
{{ template "_filterlist" $model }} {{ template "_filterlist" $model }}
{{- end -}} {{- end -}}
<div class="container-normal"> <div class="container-normal" id="subresults">
{{ template "tablehead" $model }} {{ template "tablehead" $model }}
{{ template "pills" $model }}
{{- if $model.result.Hits -}} {{- if $model.result.Hits -}}
<div class="mt-8" id="almanachcontents"> <div class="mt-8" id="almanachcontents">
{{- range $_, $hit := $model.result.Hits -}} {{- range $_, $hit := $model.result.Hits -}}

View File

@@ -0,0 +1,38 @@
{{ $model := . }}
{{- $isFiltered := or $model.filters.Agent $model.filters.Year $model.filters.Type
$model.filters.OnlyScans
-}}
{{- if $isFiltered -}}
<div class="flex flex-row gap-x-3" id="searchpills">
{{- if $model.filters.Agent -}}
<filter-pill
data-queryparam="agentfilter"
data-value="{{ $model.filters.Agent }}"
data-text="Person">
</filter-pill>
{{- end -}}
{{- if $model.filters.Year -}}
<filter-pill
data-queryparam="yearfilter"
data-value="{{ $model.filters.Year }}"
data-text="Jahr">
</filter-pill>
{{- end -}}
{{- if $model.filters.Type -}}
<filter-pill
data-queryparam="typefilter"
data-value="{{ $model.filters.Type }}"
data-text="Typ">
</filter-pill>
{{- end -}}
{{- if $model.filters.OnlyScans -}}
<filter-pill
data-queryparam="onlyscans"
data-value="{{ $model.filters.OnlyScans }}"
data-text="Nur Digitalisate">
</filter-pill>
{{- end -}}
</div>
{{- end -}}

View File

@@ -63,11 +63,12 @@
id="onlyscans" id="onlyscans"
name="onlyscans" name="onlyscans"
autocomplete="off" autocomplete="off"
hx-get="{{- $model.parameters.ToQueryParamsBeitraege -}}" hx-get="{{- $model.parameters.ToQueryParamsBeitraege -}} {{- $model.filters.ToQueryParamsWOScans -}}"
trigger="change" trigger="change"
hx-push-url="true" hx-push-url="true"
hx-select="main" hx-select="#searchresults"
hx-target="main" hx-target="#searchresults"
hx-swap="outerHTML"
{{ if $model.filters.OnlyScans -}}checked{{- end -}} /> {{ if $model.filters.OnlyScans -}}checked{{- end -}} />
<label <label
@@ -82,11 +83,12 @@
name="sort" name="sort"
id="sort" id="sort"
autocomplete="off" autocomplete="off"
hx-get="{{- $model.parameters.ToQueryParamsBeitraege -}}" hx-get="{{- $model.parameters.ToQueryParamsBeitraege -}}{{- $model.filters.ToQueryParams -}}"
trigger="change" trigger="change"
hx-push-url="true" hx-push-url="true"
hx-select="main" hx-select="#subresults"
hx-target="main"> hx-target="#subresults"
hx-swap="outerHTML show:window:top">
<option <option
value="year" value="year"
{{ if eq $model.parameters.Sort "year" -}} {{ if eq $model.parameters.Sort "year" -}}

View File

@@ -3,21 +3,24 @@
{{- $isFiltered := or $model.filters.Agent $model.filters.Year $model.filters.Type -}} {{- $isFiltered := or $model.filters.Agent $model.filters.Year $model.filters.Type -}}
<div class="container-oversize " x-data="{ filters: '{{- $isFiltered -}}' }"> <div class="container-oversize ">
<button <button
class="w-full flex flex-row bg-slate-100 py-3 border-2 border-slate-100 hover:border-slate-900 class="w-full flex flex-row bg-slate-100 py-3 border-2 border-slate-100 hover:border-slate-900
cursor-pointer box-content hover:[&>_h2]:font-slate-900 select-none" cursor-pointer box-content hover:[&>_h2]:font-slate-900 select-none"
@click="filters = !filters"> id="filterlistbtn">
<h2 class="text-2xl text-stone-700 px-32"> <h2 class="text-2xl text-stone-700 px-32">
Filter Filter
<i class="ri-arrow-right-s-line" x-show="!filters"></i> <i class="ri-arrow-right-s-line show-closed"></i>
<i class="ri-arrow-down-s-line" x-show="filters"></i> <i class="ri-arrow-down-s-line show-opened"></i>
</h2> </h2>
</button> </button>
<div <div
class="flex flex-row px-24 justify-between bg-slate-100 py-12 border-t-4 border-stone-50" class="flex flex-row px-24 justify-between bg-slate-100 py-12 border-t-4 border-stone-50 {{ if
id="searchfilter" $isFiltered
x-show="filters"> }}
hidden
{{ end }}"
id="searchfilter">
<div class="w-[30%] grow-0 shrink-0"> <div class="w-[30%] grow-0 shrink-0">
<filter-list <filter-list
class="" class=""
@@ -48,6 +51,30 @@
</div> </div>
<script type="module"> <script type="module">
let button = document.getElementById("filterlistbtn");
let filter = document.getElementById("searchfilter");
if (button && filter) {
toggleFilter();
if (button && filter) {
button.addEventListener("click", () => {
toggleFilter();
});
}
function toggleFilter() {
if (filter.classList.contains("hidden")) {
filter.classList.remove("hidden");
button.querySelector(".show-closed").classList.add("hidden");
button.querySelector(".show-opened").classList.remove("hidden");
} else {
filter.classList.add("hidden");
button.querySelector(".show-closed").classList.remove("hidden");
button.querySelector(".show-opened").classList.add("hidden");
}
}
}
let agentList = document.getElementById("agent-list"); let agentList = document.getElementById("agent-list");
if (agentList) { if (agentList) {
agentList.items = {{ $model.result.AgentsList }}; agentList.items = {{ $model.result.AgentsList }};

View File

@@ -17,6 +17,7 @@ const ABBREV_TOOLTIPS_ELEMENT = "abbrev-tooltips";
const INT_LINK_ELEMENT = "int-link"; 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";
class XSLTParseProcess { class XSLTParseProcess {
#processors; #processors;
@@ -107,6 +108,100 @@ function setup_templates() {
}); });
} }
class FilterPill extends HTMLElement {
constructor() {
super();
this._value = "";
this.render();
}
static get observedAttributes() {
return ["data-text", "data-queryparam", "data-value"];
}
set value(value) {
this.setAttribute("data-value", value);
}
get value() {
return this.getAttribute("data-value") || "";
}
set text(value) {
this.setAttribute("data-text", value);
}
get text() {
return this.getAttribute("data-text") || "";
}
set queryparam(value) {
this.setAttribute("data-queryparam", value);
}
get queryparam() {
return this.getAttribute("data-queryparam") || "";
}
connectedCallback() {
this._filter = this.text;
this._queryparam = this.queryparam;
this.render();
htmx.process(this);
}
attributeChangedCallback(name, oldValue, newValue) {
if (oldValue !== newValue) {
if (name === "data-text") {
this._filter = newValue;
}
if (name === "data-queryparam") {
this._queryparam = newValue;
}
if (name === "data-value") {
this._value = newValue;
}
this.render();
}
}
getURL() {
if (this._queryparam) {
let url = new URL(window.location);
let params = new URLSearchParams(url.search);
params.delete(this._queryparam);
params.delete("page");
url.search = params.toString();
return url.toString();
}
return "#";
}
render() {
this.innerHTML = `
<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-100 px-2.5 mt-2">
<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>
<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>
${this.renderValue()}
</div>
</div>
</a>
`;
}
renderValue() {
const isBool = this.value === "true" || this.value === "false";
if (isBool) return ``;
return `
<div class="filter-pill-value">${this.value}</div>
`;
}
}
class FilterList extends HTMLElement { class FilterList extends HTMLElement {
#hiddenlist = false; #hiddenlist = false;
#activequery = ""; #activequery = "";
@@ -318,6 +413,7 @@ class FilterList extends HTMLElement {
let url = new URL(window.location); let url = new URL(window.location);
let params = new URLSearchParams(url.search); let params = new URLSearchParams(url.search);
params.set(this._queryparam, this.getHREF(item)); params.set(this._queryparam, this.getHREF(item));
params.delete("page");
url.search = params.toString(); url.search = params.toString();
return url.toString(); return url.toString();
} }
@@ -1018,5 +1114,6 @@ customElements.define(SCROLL_BUTTON_ELEMENT, ScrollButton);
customElements.define(TOOLTIP_ELEMENT, ToolTip); 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);
export { XSLTParseProcess, FilterList, ScrollButton, AbbreviationTooltips }; export { XSLTParseProcess, FilterList, ScrollButton, AbbreviationTooltips };

View File

@@ -312,6 +312,18 @@
@apply border shadow-inner; @apply border shadow-inner;
} }
#searchpills {
@apply flex flex-row gap-x-2.5;
}
#searchpills filter-pill .filter-pill {
@appply px-2.5 rounded-lg bg-orange-300;
}
#searchresults .filter-list-item[aria-current="page"] {
@apply text-orange-800 border-orange-900 bg-orange-100 pointer-events-none;
}
#persontype a { #persontype a {
@apply px-1.5 border-b-[5px] border-transparent hover:border-zinc-200 no-underline font-serif mx-2.5; @apply px-1.5 border-b-[5px] border-transparent hover:border-zinc-200 no-underline font-serif mx-2.5;
} }