Files
LibraryAPI/library_service/templates/books.html

301 lines
11 KiB
HTML

{% extends "base.html" %}{% block content %}
<style>
.range-double {
height: 0;
pointer-events: none;
appearance: none;
-webkit-appearance: none;
}
.range-double::-webkit-slider-thumb {
-webkit-appearance: none;
appearance: none;
width: 8px;
height: 8px;
border-radius: 100%;
background: #4b5563;
border: 1px solid #ffffff;
box-shadow: 0 0 0 1px #4b5563;
cursor: pointer;
pointer-events: auto;
}
.range-double::-moz-range-thumb {
width: 8px;
height: 8px;
border-radius: 100%;
background: #4b5563;
border: 1px solid #ffffff;
box-shadow: 0 0 0 1px #4b5563;
cursor: pointer;
pointer-events: auto;
}
.range-double::-moz-range-track {
background: transparent;
}
</style>
<div class="container mx-auto p-4 flex flex-col md:flex-row gap-6">
<aside class="w-full md:w-1/4">
<div
id="admin-actions"
class="hidden bg-white px-4 py-2 rounded-lg shadow-md mb-6"
>
<a
href="/author/create"
class="w-full flex justify-center items-center px-4 py-2 my-2 bg-green-600 text-white font-medium rounded-lg hover:bg-green-700 transition"
>
<svg
class="w-5 h-5 mr-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Добавить автора
</a>
<a
href="/genre/create"
class="w-full flex justify-center items-center px-4 py-2 my-2 bg-green-600 text-white font-medium rounded-lg hover:bg-green-700 transition"
>
<svg
class="w-5 h-5 mr-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Добавить жанр
</a>
<a
href="/book/create"
class="w-full flex justify-center items-center px-4 py-2 my-2 bg-green-600 text-white font-medium rounded-lg hover:bg-green-700 transition"
>
<svg
class="w-5 h-5 mr-2"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 4v16m8-8H4"
/>
</svg>
Добавить книгу
</a>
</div>
<div class="bg-white p-4 rounded-lg shadow-md mb-6">
<h2 class="text-xl font-bold mb-4">Поиск</h2>
<div class="relative">
<input
type="text"
id="book-search-input"
placeholder="Название книги..."
class="w-full border rounded-lg pl-10 pr-4 py-2 focus:outline-none focus:ring-2 focus:ring-gray-400 transition"
/>
<svg
class="absolute left-3 top-2.5 h-5 w-5 text-gray-400"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"
></path>
</svg>
</div>
</div>
<div
x-data="pagesSlider(0, 2000, 10)"
class="bg-white p-4 rounded-lg shadow-md mb-6"
>
<h2 class="text-xl font-bold mb-4">Страниц</h2>
<div class="flex justify-between text-xs text-gray-500 mb-2">
<span>От: <span id="pages-min-value" x-text="minValue"></span></span>
<span>До: <span id="pages-max-value" x-text="maxValue"></span></span>
</div>
<div class="relative mt-4 mb-6">
<div class="absolute top-1/2 -translate-y-1/2 w-full h-1 bg-gray-200 rounded-full"></div>
<div
id="pages-range-progress"
class="absolute top-1/2 -translate-y-1/2 h-1 bg-gray-600 rounded-full"
:style="{ left: leftPercent + '%', right: rightPercent + '%' }"
></div>
<input
id="pages-min"
type="range"
:min="min"
:max="max"
x-model.number="minValue"
@input="onMinInput()"
class="range-double absolute top-0 left-0 w-full bg-transparent appearance-none pointer-events-none"
/>
<input
id="pages-max"
type="range"
:min="min"
:max="max"
x-model.number="maxValue"
@input="onMaxInput()"
class="range-double absolute top-0 left-0 w-full bg-transparent appearance-none pointer-events-none"
/>
</div>
</div>
<div class="bg-white p-4 rounded-lg shadow-md mb-6">
<h2 class="text-xl font-bold mb-4">Авторы</h2>
<div
id="selected-authors-container"
class="flex flex-wrap gap-2 mb-2 min-h-[0px]"
></div>
<div class="relative">
<input
type="text"
id="author-search-input"
placeholder="Поиск автора..."
class="w-full border rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-1 focus:ring-gray-400"
autocomplete="off"
/>
<div
id="author-dropdown"
class="hidden absolute z-50 w-full bg-white border border-gray-200 rounded-lg shadow-lg max-h-48 overflow-y-auto mt-1"
></div>
</div>
</div>
<div class="bg-white p-4 rounded-lg shadow-md mb-6">
<h2 class="text-xl font-bold mb-4">Жанры</h2>
<ul
id="genres-list"
class="space-y-2 max-h-60 overflow-y-auto text-sm text-gray-700"
></ul>
</div>
<button
id="apply-filters-btn"
class="w-full bg-gray-600 text-white font-bold py-2 px-4 rounded-lg hover:bg-gray-700 transition mb-2"
>
Применить
</button>
<button
id="reset-filters-btn"
class="w-full bg-white text-gray-600 border border-gray-300 font-bold py-2 px-4 rounded-lg hover:bg-gray-50 transition"
>
Сбросить
</button>
</aside>
<main class="w-full md:w-3/4">
<div id="books-container" class="grid grid-cols-1 gap-4"></div>
<div id="pagination-container"></div>
</main>
</div>
<template id="book-card-template">
<div
class="bg-white p-4 rounded-lg shadow-md mb-4 hover:shadow-lg transition-shadow duration-200 cursor-pointer book-card"
>
<div class="flex items-start">
<div class="flex-1">
<div class="flex justify-between items-center gap-2 mb-1">
<h3
class="book-title text-lg font-bold text-gray-900 hover:text-gray-400 transition-colors"
></h3>
<span
class="book-status inline-flex items-center px-2 py-0.5 rounded-full text-xs font-medium"
></span>
</div>
<p class="text-sm text-gray-600 mb-2">
<span class="font-medium">Авторы:</span>
<span class="book-authors"></span>
</p>
<p class="book-page-count text-sm text-gray-600 mb-2 hidden">
<span class="font-medium">Страниц:</span>
<span class="page-count-value"></span>
</p>
<p
class="book-desc text-gray-700 text-sm mb-2 line-clamp-3"
></p>
<div class="book-genres flex flex-wrap gap-1"></div>
</div>
</div>
</div>
</template>
<template id="genre-badge-template">
<span
class="inline-block bg-gray-100 text-gray-600 text-xs px-2 py-1 rounded-full"
></span>
</template>
<template id="empty-state-template">
<div class="bg-white p-8 rounded-lg shadow-md text-center">
<svg
class="mx-auto h-12 w-12 text-gray-400 mb-4"
fill="none"
stroke="currentColor"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M12 6.253v13m0-13C10.832 5.477 9.246 5 7.5 5S4.168 5.477 3 6.253v13C4.168 18.477 5.754 18 7.5 18s3.332.477 4.5 1.253m0-13C13.168 5.477 14.754 5 16.5 5c1.747 0 3.332.477 4.5 1.253v13C19.832 18.477 18.247 18 16.5 18c-1.746 0-3.332.477-4.5 1.253"
></path>
</svg>
<h3 class="text-lg font-medium text-gray-900 mb-2">Книги не найдены</h3>
<p class="text-gray-500">
Попробуйте изменить параметры поиска или фильтры
</p>
</div>
</template>
{% endblock %} {% block scripts %}
<script src="/static/page/books.js"></script>
<script>
document.addEventListener('alpine:init', () => {
Alpine.data('pagesSlider', (min, max, gap) => ({
min,
max,
gap,
minValue: min,
maxValue: max,
// проценты для заливки
get leftPercent() {
return (this.minValue - this.min) * 100 / (this.max - this.min);
},
get rightPercent() {
return 100 - (this.maxValue - this.min) * 100 / (this.max - this.min);
},
onMinInput() {
if (this.maxValue - this.minValue < this.gap) {
this.minValue = this.maxValue - this.gap;
}
},
onMaxInput() {
if (this.maxValue - this.minValue < this.gap) {
this.maxValue = this.minValue + this.gap;
}
}
}));
});
</script>
{% endblock %}