Added downloading posts into json files, filtering by year.
This commit is contained in:
5
download_posts.php
Normal file
5
download_posts.php
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
<?php
|
||||||
|
|
||||||
|
file_put_contents('public/posts_2023.json',file_get_contents('https://bookmeter.xyz/api/posts?edition=2023'));
|
||||||
|
file_put_contents('public/posts_2024.json',file_get_contents('https://bookmeter.xyz/api/posts?edition=2024'));
|
||||||
|
file_put_contents('public/posts_2025.json',file_get_contents('https://bookmeter.xyz/api/posts?edition=2025'));
|
||||||
60
index.html
60
index.html
@@ -10,7 +10,7 @@
|
|||||||
}
|
}
|
||||||
</style>
|
</style>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body class="dark:text-gray-300 dark:bg-stone-950">
|
||||||
|
|
||||||
<div x-data="bookmeterList">
|
<div x-data="bookmeterList">
|
||||||
<div x-cloak>
|
<div x-cloak>
|
||||||
@@ -21,8 +21,7 @@
|
|||||||
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"/>
|
<path stroke="currentColor" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="m19 19-4-4m0-7A7 7 0 1 1 1 8a7 7 0 0 1 14 0Z"/>
|
||||||
</svg>
|
</svg>
|
||||||
</div>
|
</div>
|
||||||
<input type="text" class="peer bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:outline focus:outline-sky-500 block w-full ps-10 p-2.5 pr-8"
|
<input type="text" class="peer bg-gray-50 border border-gray-300 text-gray-900 text-sm rounded-lg focus:outline focus:outline-sky-500 block w-full ps-10 p-2.5 pr-8 dark:bg-stone-900 dark:border-stone-700 dark:text-gray-100" x-model="nameFilter" placeholder="wyszukiwarka"/>
|
||||||
x-model="nameFilter" placeholder="wyszukiwarka"/>
|
|
||||||
<button x-show="nameFilter.length" @click="nameFilter=''" type="button" class="absolute inset-y-0 end-0 flex items-center pe-3 invisible peer-valid:visible">
|
<button x-show="nameFilter.length" @click="nameFilter=''" 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"/>
|
||||||
@@ -35,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" />
|
<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" />
|
||||||
<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"/>
|
||||||
@@ -43,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" />
|
<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" />
|
||||||
<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"/>
|
||||||
@@ -51,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" />
|
<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" />
|
||||||
<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"/>
|
||||||
@@ -59,13 +58,24 @@
|
|||||||
</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" />
|
<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" />
|
||||||
<button x-show="publisher.length" @click="author=''" 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">
|
||||||
|
<label for="year-2025" class="p-2.5 inline-block" >
|
||||||
|
<input x-model="year" type="checkbox" id="year-2025" value="2025" /> 2025
|
||||||
|
</label>
|
||||||
|
<label for="year-2024" class="p-2.5 inline-block" >
|
||||||
|
<input x-model="year" type="checkbox" id="year-2024" value="2024" /> 2024
|
||||||
|
</label>
|
||||||
|
<label for="year-2023" class="p-2.5 inline-block" >
|
||||||
|
<input x-model="year" type="checkbox" id="year-2023" value="2023" /> 2023
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div class="inline-block m-2 text-blue-400 inline cursor-pointer">
|
<div class="inline-block m-2 text-blue-400 inline cursor-pointer">
|
||||||
<div @click="advancedSearch = false">proste filtrowanie</div>
|
<div @click="advancedSearch = false">proste filtrowanie</div>
|
||||||
@@ -89,47 +99,27 @@
|
|||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<template x-for="(item, key) in filteredItems" :key="item.index">
|
<template x-for="(item, key) in filteredItems" :key="item.uuid">
|
||||||
<tr class="border-b border-slate-100 m-3 w-auto hover:bg-gray-100">
|
<tr class="border-b border-slate-100 dark:border-stone-900 m-3 w-auto hover:bg-gray-100 dark:hover:bg-stone-900">
|
||||||
<td class="pl-1 text-right" x-text="filteredItems.length-key"></td>
|
<td class="pl-1 text-right" x-text="filteredItems.length-key"></td>
|
||||||
<td class="pl-1 w-3 py-2">
|
<td class="pl-1 w-3 py-2">
|
||||||
<template x-if="!advancedSearch">
|
<a @click="advancedSearch ? username=item.username : nameFilter='@'+item.username" class="cursor-pointer" x-text="item.username"></a>
|
||||||
<a @click="nameFilter='@'+item.username" class="cursor-pointer" x-text="item.username"></a>
|
|
||||||
</template>
|
|
||||||
<template x-if="advancedSearch">
|
|
||||||
<a @click="username=item.username" class="cursor-pointer" x-text="item.username"></a>
|
|
||||||
</template>
|
|
||||||
</td>
|
</td>
|
||||||
<td class="pl-1 w-12">
|
<td class="pl-1 w-12">
|
||||||
<template x-if="!advancedSearch">
|
<a @click="advancedSearch ? title=item.book.title : nameFilter=item.book.title" class="cursor-pointer" x-text="item.book.title"></a>
|
||||||
<a @click="nameFilter=item.book.title" class="cursor-pointer" x-text="item.book.title"></a>
|
|
||||||
</template>
|
|
||||||
<template x-if="advancedSearch">
|
|
||||||
<a @click="title=item.book.title" class="cursor-pointer" x-text="item.book.title"></a>
|
|
||||||
</template>
|
|
||||||
</td>
|
</td>
|
||||||
<td class="pl-1 w-8">
|
<td class="pl-1 w-8">
|
||||||
<template x-if="!advancedSearch">
|
<a @click="advancedSearch ? author=item.book.author : nameFilter=item.book.author" class="cursor-pointer" x-text="item.book.author"></a>
|
||||||
<a @click="nameFilter=item.book.author" class="cursor-pointer" x-text="item.book.author"></a>
|
|
||||||
</template>
|
|
||||||
<template x-if="advancedSearch">
|
|
||||||
<a @click="author=item.book.author" class="cursor-pointer" x-text="item.book.author"></a>
|
|
||||||
</template>
|
|
||||||
</td>
|
</td>
|
||||||
<td class="pl-1 w-8">
|
<td class="pl-1 w-8">
|
||||||
<template x-if="!advancedSearch">
|
<a @click="advancedSearch ? publisher=item.book.publisher : nameFilter=item.book.publisher" class="cursor-pointer" x-text="item.book.publisher"></a>
|
||||||
<a @click="nameFilter=item.book.publisher" class="cursor-pointer" x-text="item.book.publisher"></a>
|
|
||||||
</template>
|
|
||||||
<template x-if="advancedSearch">
|
|
||||||
<a @click="publisher=item.book.publisher" class="cursor-pointer" x-text="item.book.publisher"></a>
|
|
||||||
</template>
|
|
||||||
</td>
|
</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="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"><a :href="item.book.likes" x-text="item.likes"></a></td>
|
||||||
<td class="pl-1 py-2">
|
<td class="pl-1 py-2">
|
||||||
<a :href="'https://www.hejto.pl/wpis/'+item.slug">
|
<a :href="'https://www.hejto.pl/wpis/'+item.slug" target="_blank">
|
||||||
link
|
link
|
||||||
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4 text-gray-500 inline">
|
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" class="w-4 h-4 text-gray-500 inline">
|
||||||
<path stroke-linecap="round" stroke-linejoin="round"
|
<path stroke-linecap="round" stroke-linejoin="round"
|
||||||
|
|||||||
31
src/main.js
31
src/main.js
@@ -8,13 +8,16 @@ Alpine.plugin(persist)
|
|||||||
|
|
||||||
Alpine.data('bookmeterList', function () {
|
Alpine.data('bookmeterList', function () {
|
||||||
return {
|
return {
|
||||||
items: [],
|
items: {},
|
||||||
filteredItems: [],
|
filteredItems: [],
|
||||||
username: '',
|
username: '',
|
||||||
publisher: '',
|
publisher: '',
|
||||||
title: '',
|
title: '',
|
||||||
author: '',
|
author: '',
|
||||||
nameFilter: '',
|
nameFilter: '',
|
||||||
|
years: [2023, 2024, 2025],
|
||||||
|
year: this.$persist(['2025']).as('year-filter'),
|
||||||
|
orderBy: [],
|
||||||
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());
|
||||||
@@ -22,22 +25,29 @@ Alpine.data('bookmeterList', function () {
|
|||||||
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());
|
||||||
|
|
||||||
let qp = new URLSearchParams(window.location.search);
|
let qp = new URLSearchParams(window.location.search);
|
||||||
if(qp.get('filter')) this.nameFilter = qp.get('filter');
|
if(qp.get('filter')) this.nameFilter = qp.get('filter');
|
||||||
|
|
||||||
const res = await fetch('/posts.json')
|
const [data1, data2, data3] = await Promise.all([
|
||||||
this.items = await res.json();
|
fetch('/posts_2025.json').then(res => res.json()),
|
||||||
|
fetch('/posts_2024.json').then(res => res.json()),
|
||||||
|
fetch('/posts_2023.json').then(res => res.json())
|
||||||
|
])
|
||||||
|
|
||||||
|
|
||||||
|
this.items = [...data1, ...data2, ...data3]
|
||||||
this.updateFilter();
|
this.updateFilter();
|
||||||
},
|
},
|
||||||
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) || '-',
|
||||||
'likes_total': this.filteredItems.reduce((a, b) => a + b.likes, 0) || '-',
|
likes_total: this.filteredItems.reduce((a, b) => a + b.likes, 0) || '-',
|
||||||
'pages_avg': Math.round(this.filteredItems.reduce((a, b) => a + b.book.pages, 0)/this.filteredItems.length) || '-',
|
pages_avg: Math.round(this.filteredItems.reduce((a, b) => a + b.book.pages, 0)/this.filteredItems.length) || '-',
|
||||||
'likes_avg': Math.round(this.filteredItems.reduce((a, b) => a + b.likes, 0)/this.filteredItems.length) || '-',
|
likes_avg: Math.round(this.filteredItems.reduce((a, b) => a + b.likes, 0)/this.filteredItems.length) || '-',
|
||||||
'rating_avg': (this.filteredItems.reduce((a, b) => a + b.book.rating, 0)/this.filteredItems.length).toPrecision(2) || '-',
|
rating_avg: (this.filteredItems.reduce((a, b) => a + b.book.rating, 0)/this.filteredItems.length).toPrecision(2) || '-',
|
||||||
'formats': this.filteredItems.reduce((acc, item) => {
|
formats: this.filteredItems.reduce((acc, item) => {
|
||||||
let val = item.book.format.toLowerCase() || 'brak danych';
|
let val = item.book.format.toLowerCase() || 'brak danych';
|
||||||
acc[val] = acc[val] === undefined ? 1 : acc[val] += 1;
|
acc[val] = acc[val] === undefined ? 1 : acc[val] += 1;
|
||||||
return acc;
|
return acc;
|
||||||
@@ -46,8 +56,9 @@ Alpine.data('bookmeterList', function () {
|
|||||||
},
|
},
|
||||||
updateFilter(){
|
updateFilter(){
|
||||||
let filter = this.nameFilter.toLowerCase();
|
let filter = this.nameFilter.toLowerCase();
|
||||||
|
|
||||||
this.filteredItems = this.items.filter(i => {
|
this.filteredItems = this.items.filter(i => {
|
||||||
|
return this.year.includes(i.created_at.substring(0,4))
|
||||||
|
}).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())) &&
|
||||||
|
|||||||
Reference in New Issue
Block a user