Add sticky chart and sticky search, see badlogic/heissepreise#89

This commit is contained in:
Christian Tschugg 2023-06-24 16:19:40 +02:00
parent d85311c4b5
commit 94a8eb2b1c
6 changed files with 99 additions and 11 deletions

View File

@ -11,6 +11,8 @@ class Settings extends Model {
this[store] = stores[store].defaultChecked;
});
this.onlyAvailable = true;
this.stickyChart = true;
this.stickySearch = false;
let settings = localStorage.getItem("settings");
if (settings) {

View File

@ -38,6 +38,8 @@ class SettingsView extends View {
</select>
</div>
<custom-checkbox x-id="onlyAvailable" x-state x-change label="Nur verfügbare Produkte anzeigen" checked></custom-checkbox>
<custom-checkbox x-id="stickyChart" x-state x-change label="Diagramm immer anzeigen (wenn verfügbar)" checked></custom-checkbox>
<custom-checkbox x-id="stickySearch" x-state x-change label="Suche immer anzeigen (wenn verfügbar)"></custom-checkbox>
</div>
`;
this.setupEventHandlers();

View File

@ -2,10 +2,6 @@
@tailwind components;
@tailwind utilities;
*.hidden {
display: none !important;
}
/* Product table */
thead > tr {
@apply bg-primary text-white text-left hidden md:table-row uppercase text-sm;
@ -208,6 +204,38 @@ thead > tr {
font-weight: 900 !important;
}
.hidden {
*.hidden,
.hidden,
.toggle--hidden {
display: none !important;
}
.wrapper {
position: relative;
text-align: center;
width: 100%;
display: flex;
justify-content: center;
align-items: center;
margin: 0 auto;
gap: 0.5em;
z-index: 1;
}
.wrapper--search label {
cursor: pointer;
}
.wrapper--search abbr {
text-decoration: none;
}
.wrapper--sticky {
flex-direction: column;
position: sticky;
top: 4em;
z-index: 1;
padding: 1em;
}
.toggle:not(:checked) ~ .wrapper--sticky,
.toggle:not(:checked) ~ .wrapper--sticky * {
display: none;
}

View File

@ -14,8 +14,8 @@ class ItemsChart extends View {
this.unitPrice = false;
this.innerHTML = /*html*/ `
<div class="bg-stone-200 p-4 mx-auto md:rounded-none md:mb-0 rounded-xl mb-4">
<div class="w-full h-[calc(100vh*0.50)] md:h-[calc(100vh*0.60)] lg:h-[calc(100vh*0.60)]" style="position: relative;">
<div class="bg-stone-200 p-4 mx-auto md:rounded-none md:mb-0 rounded-xl mb-4w ${settings.stickyChart ? "sticky top-0" : ""}">
<div class="w-full h-[calc(100vh*0.50)] md:h-[calc(100vh*0.60)] lg:h-[calc(100vh*0.60)]" style="position: relative;">
<canvas x-id="canvas" class="bg-white rounded-lg"></canvas>
<div x-id="noData" class="hidden flex items-center justify-center h-full">Keine Daten ausgewählt</div>
</div>

View File

@ -24,7 +24,20 @@ class ItemsFilter extends View {
const placeholder = this.hasAttribute("placeholder") ? this.getAttribute("placeholder") : "Produkte suchen... (min. 3 Zeichen)";
this.innerHTML = /*html*/ `
${
settings.stickySearch
? `
<div class="wrapper wrapper--search">
<input x-id="query" x-state x-input-debounce class="rounded-lg px-2 py-1 w-full" type="text" placeholder="${placeholder}" />
<label for="filter-toggle-search"><abbr title="Filter anzeigen/ausblenden">🎚</abbr></label>
</div>
<input class="toggle toggle--hidden" type="checkbox" id="filter-toggle-search" />
<div class="wrapper wrapper--sticky">
`
: `
<input x-id="query" x-state x-input-debounce class="rounded-lg px-2 py-1 w-full" type="text" placeholder="${placeholder}" />
`
}
<div x-id="sqlError" class="hidden mt-4 p-4">
</div>
@ -88,9 +101,21 @@ class ItemsFilter extends View {
)
.join("")}
</div>
${
settings.stickySearch
? `
</div>
`
: ""
}
`;
this.classList.add("items-filter");
if (settings.stickySearch) {
this.classList.add("sticky");
this.style = "top: -1px;z-index:20;";
}
const elements = this.elements;
elements.query.addEventListener("input", () => {
@ -132,9 +157,11 @@ class ItemsFilter extends View {
});
this.setupEventHandlers();
this.setupStickyChart();
this.addEventListener("x-change", () => {
this.filter();
this.observe();
});
}
@ -161,6 +188,35 @@ class ItemsFilter extends View {
}
}
setupStickyChart() {
if (!settings.stickySearch) return;
this.observer = new IntersectionObserver(
(entries) => {
for (const entry of entries) {
const clientRect = entry.target.getBoundingClientRect();
console.log(entry.target, entry.intersectionRatio);
if (entry.intersectionRatio < 0.999 && clientRect.top + clientRect.height < window.innerHeight) {
// Fix Edge issue
entry.target.classList.add("wrapper--pinned");
} else {
entry.target.classList.remove("wrapper--pinned");
}
}
},
{
rootMargin: "0px",
threshold: 0.999,
}
);
this.observe();
}
observe() {
if (this.observer == null) return;
this.observer.unobserve(this);
this.observer.observe(this);
}
filter() {
if (!this.model) return;

View File

@ -479,13 +479,13 @@
"code": "32"
},
{
"id": "schweinefleisch-spezialitaten",
"url": "https://www.roksh.at/hofer/angebot/schweinefleisch-spezialitaten",
"id": "faschiertes",
"url": "https://www.roksh.at/hofer/angebot/faschiertes",
"code": "32"
},
{
"id": "faschiertes",
"url": "https://www.roksh.at/hofer/angebot/faschiertes",
"id": "schweinefleisch-spezialitaten",
"url": "https://www.roksh.at/hofer/angebot/schweinefleisch-spezialitaten",
"code": "32"
},
{