Skip to content

Commit

Permalink
Feature - Gallery and list books views (#32)
Browse files Browse the repository at this point in the history
Feature - Gallery and list books views
  • Loading branch information
JSerwatka authored Jun 22, 2021
1 parent 675c237 commit 3710e66
Show file tree
Hide file tree
Showing 17 changed files with 497 additions and 3 deletions.
54 changes: 54 additions & 0 deletions clipping_manager/templates/clipping_manager/books.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
{% extends "content.html" %}
{% load i18n %}
{% load staticfiles sekizai_tags %}

{% block content %}
<div class="row mb-3 mx-auto">
<div class="input-group col-9 col-sm-10 pl-0">
<div class="input-group-prepend">
<span class="input-group-text">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16">
<path d="M11.742 10.344a6.5 6.5 0 1 0-1.397 1.398h-.001c.03.04.062.078.098.115l3.85 3.85a1 1 0 0 0 1.415-1.414l-3.85-3.85a1.007 1.007 0 0 0-.115-.1zM12 6.5a5.5 5.5 0 1 1-11 0 5.5 5.5 0 0 1 11 0z"></path>
</svg>
</span>
</div>
<input type="text" class="form-control" id="search-book" placeholder="{% trans 'Search a book or an author'%}">
</div>
<div class="col-3 col-sm-2 pr-0">
<div class="btn-group" style='float:right'>
<button data-view="gallery-view" class="btn btn-dark shadow-none" id="btn-gallery">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" style="vertical-align: -2px">
<path d="M4 2v2H2V2h2zm1 12v-2a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1zm0-5V7a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1zm0-5V2a1 1 0 0 0-1-1H2a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1zm5 10v-2a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1zm0-5V7a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1zm0-5V2a1 1 0 0 0-1-1H7a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1zM9 2v2H7V2h2zm5 0v2h-2V2h2zM4 7v2H2V7h2zm5 0v2H7V7h2zm5 0h-2v2h2V7zM4 12v2H2v-2h2zm5 0v2H7v-2h2zm5 0v2h-2v-2h2zM12 1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1h-2zm-1 6a1 1 0 0 1 1-1h2a1 1 0 0 1 1 1v2a1 1 0 0 1-1 1h-2a1 1 0 0 1-1-1V7zm1 4a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1h-2z"/>
</svg>
</button>
<button data-view="list-view" class="btn btn-light shadow-none" id="btn-list">
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" viewBox="0 0 16 16" style="vertical-align: -2px">
<path fill-rule="evenodd" d="M5 11.5a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm0-4a.5.5 0 0 1 .5-.5h9a.5.5 0 0 1 0 1h-9a.5.5 0 0 1-.5-.5zm-3 1a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2zm0 4a1 1 0 1 0 0-2 1 1 0 0 0 0 2z"/>
</svg>
</button>
</div>
</div>
</div>
<div id="book-view" class="gallery-view">
<div class="list-header">
<div></div>
<div class="header-title">{% trans "Title" %}</div>
<div class="header-author">{% trans "Author" %}</div>
<div class="header-clippings">{% trans "Clippings" %}</div>
</div>
{% for book in books %}
{% include "clipping_manager/partials/book_list_item.html" with book=book %}
{% endfor %}
</div>

{% addtoblock "js" %}
<script src="{% static 'js/components.js' %}"></script>
<script>
window.onload = function() {
booksView.searchBook();
booksView.switchView();
};
</script>
{% endaddtoblock %}

{% endblock %}
3 changes: 3 additions & 0 deletions clipping_manager/templates/clipping_manager/dashboard.html
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,9 @@ <h2>Manage Clippings</h2>
<a href="{% url 'clipping_manager:browse' %}" class="btn btn-primary">
Browse Your Clippings
</a>
<a href="{% url 'clipping_manager:books' %}" class="btn btn-primary">
Browse Your Books
</a>
<p class="mt-4">
You can import clippings from your <em>Amazon Kindle</em> or a simple text file.
</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
{% load urlparams %}

<div class="js-book-element">
<a href="{% url 'clipping_manager:browse'%}{% urlparams book=book.id content='' %}">
<div class="view-element">
<div class="book-cover">
<img src="https://i.pinimg.com/736x/8d/13/b1/8d13b15006817344608393deb8b3a9a2--old-book-cover-book-covers.jpg" alt="plain book cover">
</div>
<div class="js-book-title book-title">
{{book.title|default:_("unknown")}}
</div>
<div class="js-book-author book-author">
{{book.author_name|default:_("unknown")}}
</div>
<div class="book-clippings-count">
{{book.clippings_count}}
</div>
</div>
</a>
</div>
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<div class="mb-5">
<p class="clipping-content"><em>{{ clipping.content }}</em></p>
<p class="js-clipping-content clipping-content"><em>{{ clipping.content }}</em></p>
<span class="text-secondary">&mdash; {{ clipping.book.title }}</span>
</div>
Empty file.
11 changes: 11 additions & 0 deletions clipping_manager/templatetags/urlparams.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
from django import template
from urllib.parse import urlencode

register = template.Library()

@register.simple_tag
def urlparams(*_, **kwargs):
safe_args = {k: v for k, v in kwargs.items() if v is not None}
if safe_args:
return '?{}'.format(urlencode(safe_args))
return ''
3 changes: 2 additions & 1 deletion clipping_manager/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,12 @@

from clipping_manager.views import UploadMyClippingsFileView, RandomClippingView, RandomClippingFullscreenView, \
DashboardView, AdminStatisticsView, EmailDeliveryView, DailyEmailDeliveryView, BiweeklyEmailDeliveryView, \
WeeklyEmailDeliveryView, ClippingsBrowseView, UploadTextFileClippingsView, PersonalStatisticsView
WeeklyEmailDeliveryView, ClippingsBrowseView, UploadTextFileClippingsView, PersonalStatisticsView, BooksView

urlpatterns = [
url(r'^$', login_required(DashboardView.as_view()), name='dashboard'),
url(r'^browse/$', login_required(ClippingsBrowseView.as_view()), name='browse'),
url(r'^books/$', login_required(BooksView.as_view()), name='books'),
url(r'^upload/$', login_required(UploadMyClippingsFileView.as_view()), name='upload'),
url(r'^upload-plaintext/$', login_required(UploadTextFileClippingsView.as_view()), name='upload-plaintext'),
url(r'^email-delivery/$', login_required(EmailDeliveryView.as_view()), name='email-delivery'),
Expand Down
10 changes: 10 additions & 0 deletions clipping_manager/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,16 @@ def get_queryset(self):
return self.filter.qs.distinct()


class BooksView(ListView):
template_name = 'clipping_manager/books.html'
context_object_name = 'books'
model = Book

def get_queryset(self):
return Book.objects.for_user(self.request.user) \
.annotate(clippings_count = Count("clippings"))


class UploadMyClippingsFileView(FormView):
form_class = UploadKindleClippingsForm
template_name = 'clipping_manager/upload_kindle_clippings_file.html'
Expand Down
170 changes: 170 additions & 0 deletions static/css/main.css

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

49 changes: 49 additions & 0 deletions static/js/components.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
// ------- books.html -------
const booksView = {
// Hides books which doesn't match the search bar value
searchBook() {
const searchInput = document.querySelector('#search-book');
const books = document.querySelectorAll('.js-book-element');

function displayMatches() {
const regex = new RegExp(this.value, 'gi');

books.forEach(book => {
const title = book.querySelector('.js-book-title').textContent;
const author = book.querySelector('.js-book-author').textContent;

if (title.match(regex) || author.match(regex)) {
book.classList.remove('hidden');
}
else {
book.classList.add('hidden');
}
})
}

searchInput.addEventListener('keyup', displayMatches);
},
// Switches between the list and the gallery book view + controls buttons' colors
switchView() {
const galleryBtn = document.querySelector('#btn-gallery');
const listBtn = document.querySelector('#btn-list');
const bookView = document.querySelector('#book-view');

function viewControl() {
// Swap buttons' colors
Array.from(this.parentElement.children).forEach(btn => {
btn.classList.remove('btn-dark');
btn.classList.add('btn-light');
})

this.classList.remove('btn-light');
this.classList.add('btn-dark');

// Switch the book view
bookView.className = this.dataset.view;
}

galleryBtn.addEventListener('click', viewControl);
listBtn.addEventListener('click', viewControl);
}
}
3 changes: 2 additions & 1 deletion static/js/helper-functions.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
// ------- browse.html -------
// Highlights the searched phrase ('Content contains') in clippings
function highlightClippings(wordToHighlight) {
// If empty -> stop the function
if (!wordToHighlight) return;

// Get all clippings' text
const clippings = document.querySelectorAll('.clipping-content > em');
const clippings = document.querySelectorAll('.js-clipping-content > em');

// Highlighs searched-for phrase in each clipping (case-insensitive)
clippings.forEach((clipping) => {
Expand Down
4 changes: 4 additions & 0 deletions static/scss/_basics.scss
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,8 @@ a {

.highlight {
background: #ffc600;
}

.hidden {
display: none;
}
Loading

0 comments on commit 3710e66

Please sign in to comment.