Fixed mobile menu

This commit is contained in:
2025-08-07 19:13:08 +00:00
parent 616e073fe7
commit 35f8393a59
4 changed files with 327 additions and 20 deletions

View File

@@ -68,3 +68,22 @@ class BookCollection(Base):
# Relationships
book = relationship("Book", back_populates="book_collections")
collection = relationship("Collection", back_populates="book_collections")
class User(Base):
"""User model."""
__tablename__ = "User"
id: Mapped[int] = mapped_column(primary_key=True, nullable=False)
username: Mapped[str] = mapped_column(unique=True, nullable=False)
password: Mapped[str] = mapped_column(nullable=False)
email: Mapped[Optional[str]] = mapped_column(unique=True, nullable=True)
date_joined: Mapped[timestamp] = mapped_column(
nullable=False, server_default=func.CURRENT_TIMESTAMP()
)
last_login: Mapped[Optional[timestamp]] = mapped_column(
nullable=True, server_default=None
)
is_active: Mapped[bool] = mapped_column(nullable=False, default=True)
is_admin: Mapped[bool] = mapped_column(nullable=False, default=False)
is_superuser: Mapped[bool] = mapped_column(nullable=False, default=False)

View File

@@ -271,23 +271,6 @@ class Storage:
session.close()
return _result
# def fuzzy_search_books(self, query: str, limit: int = 30):
# """Fuzzy search for books by title, author, or tags."""
# with Session(self.engine) as session:
# books = session.execute(select(Book)).scalars().all()
#
# # Prepare a combined text field
# book_choices = {book.id: f"{book.title or ''} {book.author or ''} {book.tags or ''}"
# for book in books}
#
# # Use RapidFuzz to score
# results = process.extract(query, book_choices, scorer=fuzz.WRatio, limit=limit)
#
# # results = [(matched_text, score, book_id), ...]
# book_ids = [book_id for (_, score, book_id) in results if score > 50] # threshold
# books = [b for b in books if b.id in book_ids]
# return books
def parse_advanced_query(self, query: str) -> dict:
"""Parse a query like 'title:"dark tower" author:king tags:fantasy'"""

View File

@@ -15,7 +15,7 @@ const collections = {{ collections|collections_tojson }};
<div id="navbarMain" class="navbar-menu">
<div class="navbar-start is-flex is-flex-grow-1">
<a class="navbar-item" href="/">Home</a>
<div class="navbar-item is-flex-grow-1 px-2">
<div class="is-hidden-touch navbar-item is-flex-grow-1 px-2">
<div class="field is-grouped is-fullwidth" style="width: 100%;">
<p class="control is-expanded">
<span class="select is-small is-rounded is-link is-fullwidth">
@@ -26,7 +26,6 @@ const collections = {{ collections|collections_tojson }};
{% endif %}
{% for collection in collections %}
<option value="{{collection.id}}" class="collection_selection">
<!-- {{collection.name[:80]}} -->
{{collection.name}}
</option>
{% endfor %}
@@ -35,7 +34,7 @@ const collections = {{ collections|collections_tojson }};
</p>
</div>
</div>
<div class="navbar-item is-flex-grow-1 px-2">
<div class="is-hidden-touch navbar-item is-flex-grow-1 px-2">
<form action="/api/search" method="get" class="field has-addons is-flex-grow-1">
<div class="control is-expanded">
<input
@@ -90,5 +89,55 @@ const collections = {{ collections|collections_tojson }};
</div>
</div>
</div>
<!-- Mobile-only -->
<div class="navbar-item is-hidden-desktop">
<div class="field is-grouped is-fullwidth">
<p class="control is-expanded">
<span class="select is-small is-rounded is-link is-fullwidth">
<select id="collection_select_mobile">
<option value="" disabled selected>Select a collection</option>
{% if collections is not defined or collections|length == 0 %}
<option value="" disabled>No collections available</option>
{% endif %}
{% for collection in collections %}
<option value="{{collection.id}}" class="collection_selection">
{{collection.name}}
</option>
{% endfor %}
</select>
</span>
</p>
</div>
<form action="/api/search" method="get" class="field has-addons is-fullwidth mt-2">
<div class="control is-expanded">
<input
class="input is-small is-dark is-link is-rounded-left"
type="text"
name="search"
placeholder="Search books..." />
</div>
<div class="control">
<button
class="button is-small is-dark is-link is-rounded-right"
type="submit">
Search
</button>
</div>
</form>
</div>
</div>
</nav>
<script>
document.getElementById("collection_select")?.addEventListener("change", function () {
const value = encodeURIComponent(this.value);
window.location.href = `/api/collection/${value}`;
});
document.getElementById("collection_select_mobile")?.addEventListener("change", function () {
const value = encodeURIComponent(this.value);
window.location.href = `/api/collection/${value}`;
});
</script>