From 6b65d9cd15d4068c1dd2d2f391740decd052f680 Mon Sep 17 00:00:00 2001 From: Francisco Penedo Alvarez Date: Fri, 20 Mar 2026 23:43:14 +0100 Subject: [PATCH] Improve mobile responsiveness and user experience --- docs/frontend-plan.md | 109 ++++++++++++++---- src/hxbooks/static/style.css | 75 ++++++++++++ src/hxbooks/templates/book/detail.html.j2 | 39 +++++++ src/hxbooks/templates/book/list.html.j2 | 2 +- .../templates/components/book_card.html.j2 | 42 +++++-- .../templates/components/header.html.j2 | 44 ++++--- .../components/reading_status.html.j2 | 30 +++-- .../components/user_book_vars.html.j2 | 6 + .../components/wishlist_status.html.j2 | 6 +- 9 files changed, 278 insertions(+), 75 deletions(-) create mode 100644 src/hxbooks/templates/components/user_book_vars.html.j2 diff --git a/docs/frontend-plan.md b/docs/frontend-plan.md index 5ed9754..79ffb59 100644 --- a/docs/frontend-plan.md +++ b/docs/frontend-plan.md @@ -1,8 +1,53 @@ # Frontend Rebuild Plan - Phase 1: Pure HTML Responsive Design **Created**: March 17, 2026 +**Completed**: March 20, 2026 +**Status**: ✅ **PHASE 1 COMPLETE** **Phase**: 1 of 3 (Pure HTML → HTMX → JavaScript Components) +## ✅ Phase 1 Completion Summary + +**Phase 1 has been successfully completed** with all core objectives achieved and several enhancements beyond the original scope. + +### 🎯 Major Achievements + +**✅ Complete Responsive Redesign** +- Mobile-first responsive layout with 768px breakpoint +- JavaScript completely eliminated (HTML + CSS only approach) +- Component-based template architecture ready for HTMX integration +- Clean URL structure with search state persistence + +**✅ Enhanced User Experience** +- User-specific status badges on book cards (reading, rating, wishlist) +- Expandable mobile status bar using CSS-only approach +- Fixed Bootstrap mobile dropdown positioning issues +- Optimized book card sizing and layout for better screen utilization + +**✅ Technical Improvements** +- Pydantic 2.x server-side validation with proper error handling +- Shared template component system (`user_book_vars.html.j2`) +- Jinja2 import/export pattern for DRY template variables +- Individual form handling to avoid nested HTML form issues + +**✅ Code Quality Enhancements** +- Eliminated code duplication across template components +- Proper Jinja2 scoping with `{% import %}` and `with context` +- Component isolation ready for HTMX partial updates +- Clean separation between presentation and business logic + +### 📱 Mobile Responsiveness Achievements +- **Header**: Fixed user selector dropdown floating properly on mobile +- **Book Details**: Expandable status component that collapses on mobile, stays expanded on desktop +- **Book Cards**: Status badges properly positioned, optimized card sizing +- **Forms**: All forms work seamlessly across device sizes + +### 🛠️ Technical Architecture Delivered +- Component-based templates in `src/hxbooks/templates/components/` +- Shared variables system for user book data across components +- Bootstrap 5.3 + custom CSS responsive framework +- Server-side validation with Pydantic schemas +- Clean URL routing with search state preservation + ## Overview Rebuild HXBooks frontend with mobile-first responsive design using pure HTML and Bootstrap. Create clean, component-based template structure that will be HTMX-ready for Phase 2. @@ -179,42 +224,58 @@ templates/ - Accessibility features (deferred) - Alternative view formats (table, detailed list) -## Verification Checklist +## ✅ Verification Checklist - COMPLETED ### Responsive Behavior -- [ ] Sidebar collapses to hamburger on mobile (< 768px) -- [ ] Card grid adapts to screen width -- [ ] Forms are usable on mobile devices -- [ ] Header user selector works on all devices +- [x] Sidebar collapses to hamburger on mobile (< 768px) +- [x] Card grid adapts to screen width (optimized with better sizing) +- [x] Forms are usable on mobile devices +- [x] Header user selector works on all devices (fixed dropdown positioning) ### Search Functionality -- [ ] URL persistence for all search parameters -- [ ] Saved searches load correctly from sidebar -- [ ] Search results display in responsive card grid -- [ ] Navigation between search and details preserves context +- [x] URL persistence for all search parameters +- [x] Saved searches load correctly from sidebar +- [x] Search results display in responsive card grid +- [x] Navigation between search and details preserves context ### Book Management -- [ ] Create new book workflow functions -- [ ] ISBN import modal works -- [ ] Book details editing with validation -- [ ] Accept/Discard/Delete actions work correctly +- [x] Create new book workflow functions +- [x] ISBN import modal works +- [x] Book details editing with validation (Pydantic integration) +- [x] Accept/Discard/Delete actions work correctly ### User Context -- [ ] User selector dropdown updates context -- [ ] Reading status reflects selected user -- [ ] Wishlist data shows for correct user -- [ ] User-specific actions function properly +- [x] User selector dropdown updates context +- [x] Reading status reflects selected user +- [x] Wishlist data shows for correct user +- [x] User-specific actions function properly ### Form Validation -- [ ] HTML5 validation prevents submission of invalid data -- [ ] Server-side Pydantic validation shows errors -- [ ] Error messages display clearly -- [ ] Form state preserved after validation errors +- [x] HTML5 validation prevents submission of invalid data +- [x] Server-side Pydantic validation shows errors +- [x] Error messages display clearly +- [x] Form state preserved after validation errors + +### ✨ Additional Features Delivered +- [x] **Status badges on book cards** - Reading status, ratings, and wishlist indicators +- [x] **Mobile expandable status component** - CSS-only solution for book details +- [x] **Shared template variables** - DRY approach with proper Jinja2 imports +- [x] **JavaScript elimination** - Pure HTML+CSS approach achieved +- [x] **Enhanced mobile UX** - Fixed dropdown issues, optimized layouts +- [x] **Code quality improvements** - Component refactoring and template organization --- -**Next Phase Preview**: Phase 2 will enhance these components with HTMX for: +## 🚀 Phase 2 Preparation + +**Ready for Phase 2**: The component-based architecture and clean URL structure are now ready for HTMX enhancement: - Partial page updates (search results, form submissions) -- Inline editing capabilities +- Inline editing capabilities - Progressive enhancement of user interactions -- Dynamic form validation and feedback \ No newline at end of file +- Dynamic form validation and feedback + +**Key Files Ready for HTMX Integration:** +- All components in `src/hxbooks/templates/components/` +- Clean separation between data and presentation +- Atomic components designed for independent updates +- URL-based state management compatible with HTMX navigation \ No newline at end of file diff --git a/src/hxbooks/static/style.css b/src/hxbooks/static/style.css index 36667c7..deb847a 100644 --- a/src/hxbooks/static/style.css +++ b/src/hxbooks/static/style.css @@ -26,6 +26,25 @@ padding: 0; } +/* Mobile Navbar Dropdown Fix */ +@media (max-width: 768px) { + .navbar .dropdown.position-static { + position: static !important; + } + + .navbar .dropdown-menu.mobile-dropdown { + position: fixed !important; + top: 60px !important; + right: 15px !important; + left: auto !important; + transform: none !important; + margin-top: 0 !important; + box-shadow: 0 0.5rem 1rem rgba(0, 0, 0, 0.15) !important; + z-index: 1050 !important; + max-width: 250px; + } +} + .sidebar { position: sticky; top: 0; @@ -66,6 +85,10 @@ position: absolute; top: 0.5rem; right: 0.5rem; + display: flex; + flex-direction: column; + gap: 0.25rem; + align-items: flex-end; } .book-card-footer { @@ -135,6 +158,58 @@ } } +/* User Status Mobile Component */ +.status-toggle-checkbox { + display: none; +} + +.user-status-card { + background: white; + border: 1px solid #dee2e6; + border-radius: 0.375rem; + overflow: hidden; +} + +.status-bar { + display: block; + padding: 0.75rem 1rem; + background: #f8f9fa; + border-bottom: 1px solid #dee2e6; + cursor: pointer; + margin: 0; + transition: background-color 0.2s; +} + +.status-bar:hover { + background: #e9ecef; +} + +.expand-arrow { + font-size: 0.875rem; + transition: transform 0.2s; +} + +.expandable-content { + max-height: 0; + overflow: hidden; + transition: max-height 0.3s ease; +} + +.status-toggle-checkbox:checked~.user-status-card .expandable-content { + max-height: 2000px; +} + +.status-toggle-checkbox:checked~.user-status-card .expand-arrow { + transform: rotate(180deg); +} + +/* Hide mobile status component on desktop */ +@media (min-width: 992px) { + .user-status-card { + display: none; + } +} + /* Utility Classes */ .text-truncate-2 { display: -webkit-box; diff --git a/src/hxbooks/templates/book/detail.html.j2 b/src/hxbooks/templates/book/detail.html.j2 index 5a62687..a6587ea 100644 --- a/src/hxbooks/templates/book/detail.html.j2 +++ b/src/hxbooks/templates/book/detail.html.j2 @@ -18,6 +18,45 @@ {% block content %}
+ + {% if session.get('viewing_as_user') %} + {% import 'components/user_book_vars.html.j2' as vars with context %} +
+ +
+ + +
+
+ {% include 'components/reading_status.html.j2' %} + {% include 'components/wishlist_status.html.j2' %} +
+
+
+
+ {% endif %}
diff --git a/src/hxbooks/templates/book/list.html.j2 b/src/hxbooks/templates/book/list.html.j2 index f6b6236..f51f8d8 100644 --- a/src/hxbooks/templates/book/list.html.j2 +++ b/src/hxbooks/templates/book/list.html.j2 @@ -33,7 +33,7 @@ {% if books %} -
+
{% for book in books %}
{% include 'components/book_card.html.j2' %} diff --git a/src/hxbooks/templates/components/book_card.html.j2 b/src/hxbooks/templates/components/book_card.html.j2 index 1b5ddd4..bcb8bdc 100644 --- a/src/hxbooks/templates/components/book_card.html.j2 +++ b/src/hxbooks/templates/components/book_card.html.j2 @@ -4,36 +4,54 @@
📖
- +
- {% if session.get('viewing_as_user') %} - - + {% if g.viewing_user %} + {% import 'components/user_book_vars.html.j2' as vars with context %} + + + {% if vars.current_reading %} + ▶️ Reading + {% elif vars.user_readings | selectattr('dropped', 'true') | list %} + ⏸ Dropped + {% elif vars.completed_readings %} + ✓ Completed + {% endif %} + + + {% if vars.latest_rated_reading and vars.latest_rated_reading.rating %} + {{ vars.latest_rated_reading.rating }} ⭐ + {% endif %} + + + {% if vars.user_wishlist %} + 💖 Wishlist + {% endif %} {% endif %}
- +
{{ book.title }}
- + {% if book.authors %}

by {{ book.authors | join(', ') }}

{% endif %} - - {% if book.description %} + + {# {% if book.description %}

{{ book.description }}

- {% endif %} - + {% endif %} #} +
{% if book.first_published %} {{ book.first_published }} {% endif %} - + {% if book.genres %}
{% for genre in book.genres[:2] %} @@ -46,7 +64,7 @@ {% endif %}
- +