Implementing sorting.

This commit is contained in:
Krzysztof Płaczek
2025-08-01 19:31:43 +02:00
parent 01c3f59085
commit 1ee5fbf655
3 changed files with 138 additions and 48 deletions

View File

@@ -34,7 +34,7 @@
</form> </form>
<div x-show="advancedSearch" class="flex m-4"> <div x-show="advancedSearch" class="flex m-4">
<div class="relative w-full d-block max-w-xs mr-2"> <div class="relative w-full d-block max-w-xs mr-2">
<input x-model="username" placeholder="użytkownik" type="text" class="peer mr-2 max-w-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:outline focus:outline-sky-500 block w-full p-2.5 px-4 dark:bg-stone-900 dark:border-stone-700 dark:text-gray-100" /> <input @input.debounce="updateFilter" x-model="username" placeholder="użytkownik" type="text" class="peer mr-2 max-w-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:outline focus:outline-sky-500 block w-full p-2.5 px-4 dark:bg-stone-900 dark:border-stone-700 dark:text-gray-100" />
<button x-show="username.length" @click="username=''" type="button" class="absolute inset-y-0 end-0 flex items-center pe-3 invisible peer-valid:visible"> <button x-show="username.length" @click="username=''" type="button" class="absolute inset-y-0 end-0 flex items-center pe-3 invisible peer-valid:visible">
<svg class="w-4 h-4 text-gray-500 " xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"> <svg class="w-4 h-4 text-gray-500 " xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/> <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
@@ -42,7 +42,7 @@
</button> </button>
</div> </div>
<div class="relative w-full d-block max-w-xs mr-2"> <div class="relative w-full d-block max-w-xs mr-2">
<input x-model="title" placeholder="tytuł" type="text" class="peer mr-2 max-w-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:outline focus:outline-sky-500 block w-full p-2.5 px-4 dark:bg-stone-900 dark:border-stone-700 dark:text-gray-100" /> <input @input.debounce="updateFilter" x-model="title" placeholder="tytuł" type="text" class="peer mr-2 max-w-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:outline focus:outline-sky-500 block w-full p-2.5 px-4 dark:bg-stone-900 dark:border-stone-700 dark:text-gray-100" />
<button x-show="title.length" @click="title=''" type="button" class="absolute inset-y-0 end-0 flex items-center pe-3 invisible peer-valid:visible"> <button x-show="title.length" @click="title=''" type="button" class="absolute inset-y-0 end-0 flex items-center pe-3 invisible peer-valid:visible">
<svg class="w-4 h-4 text-gray-500 " xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"> <svg class="w-4 h-4 text-gray-500 " xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/> <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
@@ -50,7 +50,7 @@
</button> </button>
</div> </div>
<div class="relative w-full d-block max-w-xs mr-2"> <div class="relative w-full d-block max-w-xs mr-2">
<input x-model="author" placeholder="autor" type="text" class="peer mr-2 max-w-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:outline focus:outline-sky-500 block w-full p-2.5 px-4 dark:bg-stone-900 dark:border-stone-700 dark:text-gray-100" /> <input @input.debounce="updateFilter" x-model="author" placeholder="autor" type="text" class="peer mr-2 max-w-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:outline focus:outline-sky-500 block w-full p-2.5 px-4 dark:bg-stone-900 dark:border-stone-700 dark:text-gray-100" />
<button x-show="author.length" @click="author=''" type="button" class="absolute inset-y-0 end-0 flex items-center pe-3 invisible peer-valid:visible"> <button x-show="author.length" @click="author=''" type="button" class="absolute inset-y-0 end-0 flex items-center pe-3 invisible peer-valid:visible">
<svg class="w-4 h-4 text-gray-500 " xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"> <svg class="w-4 h-4 text-gray-500 " xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/> <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
@@ -58,22 +58,22 @@
</button> </button>
</div> </div>
<div class="relative w-full d-block max-w-xs mr-2"> <div class="relative w-full d-block max-w-xs mr-2">
<input x-model="publisher" placeholder="wydawca" type="text" class="peer mr-2 max-w-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:outline focus:outline-sky-500 block w-full p-2.5 px-4 dark:bg-stone-900 dark:border-stone-700 dark:text-gray-100" /> <input @input.debounce="updateFilter" x-model="publisher" placeholder="wydawca" type="text" class="peer mr-2 max-w-xs bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:outline focus:outline-sky-500 block w-full p-2.5 px-4 dark:bg-stone-900 dark:border-stone-700 dark:text-gray-100" />
<button x-show="publisher.length" @click="publisher=''" type="button" class="absolute inset-y-0 end-0 flex items-center pe-3 invisible peer-valid:visible"> <button x-show="publisher.length" @click="publisher=''" type="button" class="absolute inset-y-0 end-0 flex items-center pe-3 invisible peer-valid:visible">
<svg class="w-4 h-4 text-gray-500 " xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor"> <svg class="w-4 h-4 text-gray-500 " xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor">
<path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/> <path stroke-linecap="round" stroke-linejoin="round" d="M6 18 18 6M6 6l12 12"/>
</svg> </svg>
</button> </button>
</div> </div>
<div class=" w-full d-block max-w-xs mr-2"> <div class="d-block max-w-xs mr-2">
<label for="year-2025" class="p-2.5 inline-block" > <label for="year-2025" class="p-2.5 inline-block" >
<input x-model="year" type="checkbox" id="year-2025" value="2025" /> 2025 <input @input.debounce="updateFilter" x-model="year" type="checkbox" id="year-2025" value="2025" /> 2025
</label> </label>
<label for="year-2024" class="p-2.5 inline-block" > <label for="year-2024" class="p-2.5 inline-block" >
<input x-model="year" type="checkbox" id="year-2024" value="2024" /> 2024 <input @input.debounce="updateFilter" x-model="year" type="checkbox" id="year-2024" value="2024" /> 2024
</label> </label>
<label for="year-2023" class="p-2.5 inline-block" > <label for="year-2023" class="p-2.5 inline-block" >
<input x-model="year" type="checkbox" id="year-2023" value="2023" /> 2023 <input @input.debounce="updateFilter" x-model="year" type="checkbox" id="year-2023" value="2023" /> 2023
</label> </label>
</div> </div>
@@ -87,15 +87,15 @@
<thead> <thead>
<tr> <tr>
<th class="text-right pl-1 w-[4rem]">#</th> <th class="text-right pl-1 w-[4rem]">#</th>
<th class="text-left pl-1">Uzytkownik</th> <th class="text-left pl-1 cursor-pointer" @click="orderBy('username')">Uzytkownik</th>
<th class="text-left pl-1">Tytuł</th> <th class="text-left pl-1 cursor-pointer" @click="orderBy('title')">Tytuł</th>
<th class="text-left pl-1">Autor</th> <th class="text-left pl-1 cursor-pointer" @click="orderBy('author')">Autor</th>
<th class="text-left pl-1">Wydawca</th> <th class="text-left pl-1 cursor-pointer" @click="orderBy('publisher')">Wydawca</th>
<th class="text-right pr-4 w-[7rem]">Stron</th> <th class="text-right pr-4 w-[7rem] cursor-pointer" @click="orderBy('pages')">Stron</th>
<th class="text-left pl-1 w-[12rem]">Format</th> <th class="text-left pl-1 w-[12rem] cursor-pointer" @click="orderBy('format')">Format</th>
<th class="text-right w-[5rem]">Ocena</th> <th class="text-right w-[5rem] cursor-pointer" @click="orderBy('rating')">Ocena</th>
<th class="text-right pr-4 w-[5rem]"></th> <th class="text-right pr-4 w-[5rem] cursor-pointer" @click="orderBy('likes')"></th>
<th class="text-left pl-1 w-[5rem]">Link</th> <th class="text-left pl-1 w-[5rem] cursor-pointer">Link</th>
</tr> </tr>
</thead> </thead>
<tbody> <tbody>
@@ -117,7 +117,7 @@
<td class="pr-4 text-right w-[5rem] w-[5rem]"><a :href="item.book.pages" x-text="item.book.pages"></a></td> <td class="pr-4 text-right w-[5rem] w-[5rem]"><a :href="item.book.pages" x-text="item.book.pages"></a></td>
<td class="pl-1"><a :href="item.book.format" x-text="item.book.format"></a></td> <td class="pl-1"><a :href="item.book.format" x-text="item.book.format"></a></td>
<td class="text-right"><a :href="item.book.rating" x-text="item.book.rating"></a></td> <td class="text-right"><a :href="item.book.rating" x-text="item.book.rating"></a></td>
<td class="pr-4 text-right"><a :href="item.book.likes" x-text="item.likes"></a></td> <td class="pr-4 text-right" x-text="item.likes"></td>
<td class="pl-1 py-2"> <td class="pl-1 py-2">
<a :href="'https://www.hejto.pl/wpis/'+item.slug" target="_blank"> <a :href="'https://www.hejto.pl/wpis/'+item.slug" target="_blank">
link link

View File

@@ -583,29 +583,30 @@ video {
inset-inline-start: 0px; inset-inline-start: 0px;
} }
.m-2 {
margin: 0.5rem;
}
.m-3 { .m-3 {
margin: 0.75rem; margin: 0.75rem;
} }
.mx-auto { .m-4 {
margin-left: auto; margin: 1rem;
margin-right: auto;
} }
.my-2 { .mr-2 {
margin-top: 0.5rem; margin-right: 0.5rem;
margin-bottom: 0.5rem;
}
.my-4 {
margin-top: 1rem;
margin-bottom: 1rem;
} }
.block { .block {
display: block; display: block;
} }
.inline-block {
display: inline-block;
}
.inline { .inline {
display: inline; display: inline;
} }
@@ -622,18 +623,10 @@ video {
height: 1rem; height: 1rem;
} }
.w-1 {
width: 0.25rem;
}
.w-12 { .w-12 {
width: 3rem; width: 3rem;
} }
.w-2 {
width: 0.5rem;
}
.w-3 { .w-3 {
width: 0.75rem; width: 0.75rem;
} }
@@ -646,6 +639,22 @@ video {
width: 2rem; width: 2rem;
} }
.w-\[12rem\] {
width: 12rem;
}
.w-\[4rem\] {
width: 4rem;
}
.w-\[5rem\] {
width: 5rem;
}
.w-\[7rem\] {
width: 7rem;
}
.w-auto { .w-auto {
width: auto; width: auto;
} }
@@ -654,8 +663,20 @@ video {
width: 100%; width: 100%;
} }
.max-w-lg { .max-w-md {
max-width: 32rem; max-width: 28rem;
}
.max-w-xs {
max-width: 20rem;
}
.table-fixed {
table-layout: fixed;
}
.cursor-pointer {
cursor: pointer;
} }
.items-center { .items-center {
@@ -693,6 +714,11 @@ video {
padding: 0.625rem; padding: 0.625rem;
} }
.px-4 {
padding-left: 1rem;
padding-right: 1rem;
}
.py-2 { .py-2 {
padding-top: 0.5rem; padding-top: 0.5rem;
padding-bottom: 0.5rem; padding-bottom: 0.5rem;
@@ -739,6 +765,11 @@ video {
line-height: 1.25rem; line-height: 1.25rem;
} }
.text-blue-400 {
--tw-text-opacity: 1;
color: rgb(96 165 250 / var(--tw-text-opacity, 1));
}
.text-gray-500 { .text-gray-500 {
--tw-text-opacity: 1; --tw-text-opacity: 1;
color: rgb(107 114 128 / var(--tw-text-opacity, 1)); color: rgb(107 114 128 / var(--tw-text-opacity, 1));
@@ -757,6 +788,11 @@ video {
display: none; display: none;
} }
.hover\:bg-gray-100:hover {
--tw-bg-opacity: 1;
background-color: rgb(243 244 246 / var(--tw-bg-opacity, 1));
}
.focus\:outline:focus { .focus\:outline:focus {
outline-style: solid; outline-style: solid;
} }
@@ -767,4 +803,41 @@ video {
.peer:valid ~ .peer-valid\:visible { .peer:valid ~ .peer-valid\:visible {
visibility: visible; visibility: visible;
}
@media (prefers-color-scheme: dark) {
.dark\:border-stone-700 {
--tw-border-opacity: 1;
border-color: rgb(68 64 60 / var(--tw-border-opacity, 1));
}
.dark\:border-stone-900 {
--tw-border-opacity: 1;
border-color: rgb(28 25 23 / var(--tw-border-opacity, 1));
}
.dark\:bg-stone-900 {
--tw-bg-opacity: 1;
background-color: rgb(28 25 23 / var(--tw-bg-opacity, 1));
}
.dark\:bg-stone-950 {
--tw-bg-opacity: 1;
background-color: rgb(12 10 9 / var(--tw-bg-opacity, 1));
}
.dark\:text-gray-100 {
--tw-text-opacity: 1;
color: rgb(243 244 246 / var(--tw-text-opacity, 1));
}
.dark\:text-gray-300 {
--tw-text-opacity: 1;
color: rgb(209 213 219 / var(--tw-text-opacity, 1));
}
.dark\:hover\:bg-stone-900:hover {
--tw-bg-opacity: 1;
background-color: rgb(28 25 23 / var(--tw-bg-opacity, 1));
}
} }

View File

@@ -17,14 +17,14 @@ Alpine.data('bookmeterList', function () {
nameFilter: '', nameFilter: '',
years: [2023, 2024, 2025], years: [2023, 2024, 2025],
year: this.$persist(['2025']).as('year-filter'), year: this.$persist(['2025']).as('year-filter'),
orderBy: [], orderColumn: ['order', 1],
advancedSearch: this.$persist(0).as('advanced-search'), advancedSearch: this.$persist(0).as('advanced-search'),
async init() { async init() {
this.$watch('nameFilter', () => this.updateFilter()); this.$watch('nameFilter', () => this.updateFilter());
this.$watch('username', () => this.updateFilter()); // this.$watch('username', () => this.updateFilter());
this.$watch('title', () => this.updateFilter()); // this.$watch('title', () => this.updateFilter());
this.$watch('author', () => this.updateFilter()); // this.$watch('author', () => this.updateFilter());
this.$watch('publisher', () => this.updateFilter()); // this.$watch('publisher', () => this.updateFilter());
this.$watch('year', () => this.updateFilter()); this.$watch('year', () => this.updateFilter());
let qp = new URLSearchParams(window.location.search); let qp = new URLSearchParams(window.location.search);
@@ -36,10 +36,14 @@ Alpine.data('bookmeterList', function () {
fetch('/posts_2023.json').then(res => res.json()) fetch('/posts_2023.json').then(res => res.json())
]) ])
this.items = [...data1, ...data2, ...data3] this.items = [...data1, ...data2, ...data3]
this.updateFilter(); this.updateFilter();
}, },
orderBy(property) {
let direction = (this.orderColumn[0] === property) ? this.orderColumn[1] * -1 : 1;
this.orderColumn = [property, direction];
this.sort();
},
stats(){ stats(){
return { return {
pages_total: this.filteredItems.reduce((a, b) => a + b.book.pages, 0) || '-', pages_total: this.filteredItems.reduce((a, b) => a + b.book.pages, 0) || '-',
@@ -54,11 +58,23 @@ Alpine.data('bookmeterList', function () {
}, {}) }, {})
}; };
}, },
sort() {
let sortFunction = ({
username: (a,b) => ((a.username < b.username) ? -1 : (a.username > b.username) ? 1 : 0) * this.orderColumn[1],
title: (a,b) => ((a.book.title < b.book.title) ? -1 : (a.book.title > b.book.title) ? 1 : 0) * this.orderColumn[1],
author: (a,b) => ((a.book.author < b.book.author) ? -1 : (a.book.author > b.book.author) ? 1 : 0) * this.orderColumn[1],
publisher: (a,b) => ((a.book.publisher < b.book.publisher) ? -1 : (a.book.publisher > b.book.publisher) ? 1 : 0) * this.orderColumn[1],
pages: (a,b) => ((a.book.pages < b.book.pages) ? -1 : (a.book.pages > b.book.pages) ? 1 : 0) * this.orderColumn[1],
format: (a,b) => ((a.book.format < b.book.format) ? -1 : (a.book.format > b.book.format) ? 1 : 0) * this.orderColumn[1],
rating: (a,b) => ((a.book.rating < b.book.rating) ? -1 : (a.book.rating > b.book.rating) ? 1 : 0) * this.orderColumn[1],
likes: (a,b) => ((a.likes < b.likes) ? -1 : (a.likes > b.likes) ? 1 : 0) * this.orderColumn[1],
})[this.orderColumn[0]];
this.filteredItems = this.filteredItems.sort(sortFunction);
},
updateFilter(){ updateFilter(){
let filter = this.nameFilter.toLowerCase(); let filter = this.nameFilter.toLowerCase();
this.filteredItems = this.items.filter(i => { this.filteredItems = this.items.filter(i => this.year.includes(i.created_at.substring(0,4)))
return this.year.includes(i.created_at.substring(0,4)) .filter(i => {
}).filter(i => {
if(this.advancedSearch) { if(this.advancedSearch) {
return ( return (
(!this.username || i.username.toLowerCase().includes(this.username.toLowerCase())) && (!this.username || i.username.toLowerCase().includes(this.username.toLowerCase())) &&
@@ -73,6 +89,7 @@ Alpine.data('bookmeterList', function () {
return false; return false;
} }
}); });
this.sort();
this.updateURL(); this.updateURL();
}, },