From 7ee9c57ed15e73194a396e7491c552de07705f53 Mon Sep 17 00:00:00 2001 From: Raelon Masters Date: Sun, 31 May 2020 01:20:52 -0400 Subject: [PATCH 01/13] First push with mobi support --- config.json | 2 +- importBooks | 2 +- installer | 2 +- pyproject.toml | 2 +- requirements.txt | 1 + src/backend/lib/library.py | 55 ++++++++++++++++++++++++++------------ 6 files changed, 43 insertions(+), 21 deletions(-) diff --git a/config.json b/config.json index 71951be..28132cf 100755 --- a/config.json +++ b/config.json @@ -1 +1 @@ -{"TITLE": "pyShelf E-Book Server", "VERSION": "0.5.0", "BOOKPATH": "", "DB_HOST": "localhost", "DB_PORT": "5432", "DATABASE": "pyshelf", "USER": "pyshelf", "PASSWORD": "pyshelf", "BOOKSHELF": "data/shelf.json", "ALLOWED_HOSTS": "*", "hostname": "localhost", "webport": "8000", "wsgiport": "8001"} +{"TITLE": "pyShelf E-Book Server", "VERSION": "0.5.0", "BOOKPATH": "/home/raelon/Books", "DB_HOST": "localhost", "DB_PORT": "5432", "DATABASE": "pyshelf", "USER": "pyshelf", "PASSWORD": "pyshelf", "BOOKSHELF": "data/shelf.json", "ALLOWED_HOSTS": "*", "hostname": "localhost", "webport": "8000", "wsgiport": "8001"} diff --git a/importBooks b/importBooks index 244906d..272b643 100755 --- a/importBooks +++ b/importBooks @@ -1,4 +1,4 @@ -#!python +#!/usr/bin/env python import pathlib import sys diff --git a/installer b/installer index f6882b5..b8c112b 100755 --- a/installer +++ b/installer @@ -1,4 +1,4 @@ -#!python +#!/usr/bin/ env python import json import os import pathlib diff --git a/pyproject.toml b/pyproject.toml index eaa5fde..6caf254 100755 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,4 +7,4 @@ use_parentheses = true # NOTE: the known_third_party setting is managed by # seed-isort-config and should not be modified directly. # Any changes made to this setting will be overwritten. -known_third_party = ["backend", "bs4", "django", "interface", "prompt_toolkit", "psycopg2", "pyfiglet", "requests"] +known_third_party = ["backend", "bs4", "django", "interface", "mobi", "prompt_toolkit", "psycopg2", "pyfiglet", "requests"] diff --git a/requirements.txt b/requirements.txt index 749a3dd..89974a9 100755 --- a/requirements.txt +++ b/requirements.txt @@ -17,3 +17,4 @@ psycopg2-binary prompt_toolkit psutil pyfiglet +mobi-python diff --git a/src/backend/lib/library.py b/src/backend/lib/library.py index 6585f6d..9b0686c 100755 --- a/src/backend/lib/library.py +++ b/src/backend/lib/library.py @@ -7,6 +7,8 @@ import zipfile from bs4 import BeautifulSoup +from mobi import Mobi + from .api_hooks import DuckDuckGo from .config import Config from .storage import Storage @@ -26,8 +28,7 @@ class Catalogue: self.html_regx = re.compile(r"\.html") self.root_dir = config.root self.book_folder = config.book_path - self.book_shelf = config.book_shelf - self._book_list_expanded = None + # self.book_shelf = config.book_shelf self.books = None self.db_pointer = config.catalogue_db self.config = config @@ -56,24 +57,30 @@ class Catalogue: :returns self._book_list_expanded: json string containing all book metadata """ - self.scan_folder() # Populate file list - regx = re.compile(r"\.epub") + self.scan_folder() # Populate file list + regx = re.compile(r"\.epub|\.mobi") try: self.books = list(filter(regx.search, filter(None, self.file_list))) except TypeError as e: print(e) - self._book_list_expanded = {} - with open(self.book_shelf, "w") as f: - for book in self.books: - self._book_list_expanded[book] = self.process_book(book) - json.dump(self._book_list_expanded, f) + """ + for book in self.books: + self._book_list_expanded[book] = self.process_by_filetype(book) return self._book_list_expanded + """ + + def process_by_filetype(self, book): + if book.endswith(".epub"): + epub = self.process_epub(book) + return self.extract_metadata_epub(epub) + elif book.endswith(".mobi"): + return self.extract_metadata_mobi(book) @staticmethod - def process_book(book): + def process_epub(book): """Return dictionary of epub file contents""" - book = zipfile.ZipFile(book, "r") details = {} + book = zipfile.ZipFile(book, "r") with book as book_zip: details["files"] = [] details["path"] = book.filename @@ -86,7 +93,7 @@ class Catalogue: details["files"].append(match.string) return details - def extract_metadata(self, book): + def extract_metadata_epub(self, book): """ Return extracted metadata and cover picture book['path'] == Full path to ebook file @@ -94,7 +101,7 @@ class Catalogue: """ book_zip = zipfile.ZipFile(book["path"], "r") with book_zip as f: - content = self.extract_content(book_zip, book) + content = self.extract_content(f, book) soup = BeautifulSoup(content, "lxml") title = soup.find("dc:title") if title is None: @@ -105,13 +112,27 @@ class Catalogue: if author is not None: author = author.contents[0] try: - cover = self.extract_cover_image(book_zip, book) + cover = self.extract_cover_image(f, book) except IndexError: # cover = self.extract_cover_html(book_zip, book) cover = DuckDuckGo().image_result(title) book_details = [title, author, cover, book["path"]] return book_details + @staticmethod + def extract_metadata_mobi(book): + book = Mobi(book) + book.parse() + try: + cover_image = book.readImageRecord(0) + except KeyError: + cover_image = None + title = book.title().decode("utf-8") + author = book.author().decode( + "utf-8" + ) # TODO some files are still passing encoded data for author. + return [title, author, cover_image, book.f.name] + def extract_content(self, book_zip, book): """ Opens epub as zip file filters then stores as list any files matching opf_regx @@ -161,12 +182,12 @@ class Catalogue: Gets a list of new files via compare_shelf_current. Iterates over list and inserts new books into database. """ + # TODO Refactor metadata extraction into process_book call to more easily handle additional formats book_list = self.compare_shelf_current() db = Storage(self.config) for book in book_list: - book = self.process_book(book) - extracted = self.extract_metadata(book) - db.insert_book(extracted) + book = self.process_by_filetype(book) + db.insert_book(book) inserted = db.commit() if inserted is not True: print(inserted) From 60f7184a3a129bac7756ffd87644a795698217c6 Mon Sep 17 00:00:00 2001 From: Raelon Masters Date: Sun, 31 May 2020 13:51:25 -0400 Subject: [PATCH 02/13] Fixed improper python shebang --- makeCollections | 2 +- src/backend/lib/library.py | 11 ++++++----- src/backend/pyShelf_MakeCollections.py | 4 ++-- 3 files changed, 9 insertions(+), 8 deletions(-) diff --git a/makeCollections b/makeCollections index 4333055..0e82de7 100755 --- a/makeCollections +++ b/makeCollections @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import pathlib import sys diff --git a/src/backend/lib/library.py b/src/backend/lib/library.py index 9b0686c..320abee 100755 --- a/src/backend/lib/library.py +++ b/src/backend/lib/library.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import json import os import pathlib @@ -128,9 +128,9 @@ class Catalogue: except KeyError: cover_image = None title = book.title().decode("utf-8") - author = book.author().decode( - "utf-8" - ) # TODO some files are still passing encoded data for author. + author = book.author().decode("utf-8") + breakpoint() + # TODO some files are still passing encoded data for author. return [title, author, cover_image, book.f.name] def extract_content(self, book_zip, book): @@ -182,7 +182,8 @@ class Catalogue: Gets a list of new files via compare_shelf_current. Iterates over list and inserts new books into database. """ - # TODO Refactor metadata extraction into process_book call to more easily handle additional formats + # TODO Refactor metadata extraction into process_book \ + # call to more easily handle additional formats book_list = self.compare_shelf_current() db = Storage(self.config) for book in book_list: diff --git a/src/backend/pyShelf_MakeCollections.py b/src/backend/pyShelf_MakeCollections.py index 0f16549..139e394 100755 --- a/src/backend/pyShelf_MakeCollections.py +++ b/src/backend/pyShelf_MakeCollections.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import os import sys import time @@ -16,7 +16,7 @@ def MakeCollections(root): config = Config(root) # Get configuration settings # InitFiles(config.file_array) # Initialize file system _storage = Storage(config) - _storage.make_collections() + _storage.make_collections() _t2 = time.time() scan_time = round(_t2 - _t1) print("Collections Made.") From c12a32eb017b0100df7395e81982a96c8b38bb55 Mon Sep 17 00:00:00 2001 From: Raelon Masters Date: Sun, 31 May 2020 14:06:54 -0400 Subject: [PATCH 03/13] Fixed improper python shebang --- src/backend/pyShelf_ScanLibrary.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/pyShelf_ScanLibrary.py b/src/backend/pyShelf_ScanLibrary.py index 84b62e5..b8c5c33 100755 --- a/src/backend/pyShelf_ScanLibrary.py +++ b/src/backend/pyShelf_ScanLibrary.py @@ -1,4 +1,4 @@ -#!/usr/bin/python +#!/usr/bin/env python import os import sys import time From d740456df59f9e44b13272dc625549fe079c3bf5 Mon Sep 17 00:00:00 2001 From: Raelon Masters Date: Mon, 1 Jun 2020 09:05:28 -0400 Subject: [PATCH 04/13] Started UI Changes --- src/backend/lib/library.py | 1 - src/interface/static/css/main.css | 19 ++++++++++++------- src/interface/templates/index.html | 18 +----------------- 3 files changed, 13 insertions(+), 25 deletions(-) diff --git a/src/backend/lib/library.py b/src/backend/lib/library.py index 320abee..e85bc4f 100755 --- a/src/backend/lib/library.py +++ b/src/backend/lib/library.py @@ -28,7 +28,6 @@ class Catalogue: self.html_regx = re.compile(r"\.html") self.root_dir = config.root self.book_folder = config.book_path - # self.book_shelf = config.book_shelf self.books = None self.db_pointer = config.catalogue_db self.config = config diff --git a/src/interface/static/css/main.css b/src/interface/static/css/main.css index 060213a..c3f93d9 100755 --- a/src/interface/static/css/main.css +++ b/src/interface/static/css/main.css @@ -8,11 +8,12 @@ body { #app { display: grid; - grid-template-areas: "app_header" + grid-template-areas: + "app_header" "app_body" "app_footer"; - grid-template-rows: auto auto auto; - /*max-height: 100%;*/ + grid-template-rows: 52px auto auto; + /* max-height: 100%; */ } .clear { @@ -24,30 +25,32 @@ body { margin: 0px; display: grid; grid-template-areas: - "title slogan subhdr" - "nav_left_top nav_center_top nav_right_top"; - align-items: center; - background-color: #2b2b2b; + "title nav_left_top nav_center_top nav_right_top"; + grid-template-columns: 225px auto auto; padding: 4px 0px 4px; grid-auto-columns: auto; + background-color: #2b2b2b; } .nav_left_top { grid-area: nav_left_top; display: flex; justify-content: left; + align-items: center; } .nav_center_top { grid-area: nav_center_top; display: flex; justify-content: center; + align-items: center; } .nav_right_top { grid-area: nav_right_top; display: flex; justify-content: flex-end; + align-items: center; } .app_hdr { @@ -225,12 +228,14 @@ body { margin: 0px 5px 0px 0px; padding-top: 2px; padding-bottom: 2px; + max-height: 20px; } .nav_search { margin: 0px 5px 0px 0px; border-radius: 5px; border: 1px solid #999; + max-height: 17px; } .search {} diff --git a/src/interface/templates/index.html b/src/interface/templates/index.html index d8ea54b..6990132 100755 --- a/src/interface/templates/index.html +++ b/src/interface/templates/index.html @@ -17,28 +17,12 @@ +

pyShelf {{Version}}

-
-

"An elegant tool... for a more civilized age."

-
-
- - - - - Fork - - Issue - -
- From 1b54820d67fc2d2d7146ce0205ad2f786d8660a2 Mon Sep 17 00:00:00 2001 From: Raelon Masters Date: Thu, 11 Jun 2020 11:20:32 -0400 Subject: [PATCH 05/13] First push of newui --- importBooks.pstat | 0 src/interface/migrations/0005_navigation.py | 35 +++++++++ src/interface/models.py | 37 ++++++++++ src/interface/static/css/main.css | 81 +++++++++++---------- src/interface/static/js/pyshelf_ux.js | 9 ++- src/interface/templates/index.html | 70 ++++++++++-------- src/interface/templates/search.html | 81 +++++++++------------ src/interface/views.py | 25 ++++++- 8 files changed, 215 insertions(+), 123 deletions(-) create mode 100644 importBooks.pstat create mode 100644 src/interface/migrations/0005_navigation.py diff --git a/importBooks.pstat b/importBooks.pstat new file mode 100644 index 0000000..e69de29 diff --git a/src/interface/migrations/0005_navigation.py b/src/interface/migrations/0005_navigation.py new file mode 100644 index 0000000..fcae6e3 --- /dev/null +++ b/src/interface/migrations/0005_navigation.py @@ -0,0 +1,35 @@ +# Generated by Django 3.0.4 on 2020-06-10 05:07 + +from django.db import migrations, models + + +class Migration(migrations.Migration): + + dependencies = [ + ("interface", "0004_collections"), + ] + + operations = [ + migrations.CreateModel( + name="Navigation", + fields=[ + ( + "id", + models.AutoField( + auto_created=True, + primary_key=True, + serialize=False, + verbose_name="ID", + ), + ), + ("title", models.CharField(max_length=255)), + ("link", models.CharField(max_length=255, null=True)), + ("category", models.CharField(max_length=255, null=True)), + ("parent_id", models.IntegerField(null=True)), + ("alt", models.CharField(max_length=255, null=True)), + ("type", models.IntegerField(null=True)), + ("socket", models.CharField(max_length=255)), + ], + options={"db_table": "navigation",}, + ), + ] diff --git a/src/interface/models.py b/src/interface/models.py index 2f07909..a80dce3 100755 --- a/src/interface/models.py +++ b/src/interface/models.py @@ -62,3 +62,40 @@ class Collections(models.Model): except Exception as e: raise return results + + +class Navigation(models.Model): + """ + pyShelfs Navigation Database class + :param title: Link Text + :param link: Link link :) + :param category: Where in the nav tree do I belong + :param parent_id: This link is a sub link of link with id of me + :param alt: Alternate text of link + :param type: Web link, or Socket link which will be expected to act on \ + the link, and the action defined in socket + :param socket: if a Socket link define socket here + """ + + class Meta: + db_table = "navigation" + + def __str__(self): + return self.title + + title = models.CharField(max_length=255) + link = models.CharField(max_length=255, null=True) + category = models.CharField(max_length=255, null=True) + parent_id = models.IntegerField(null=True, editable=True) + alt = models.CharField(max_length=255, null=True) + type = models.IntegerField(null=True) + socket = models.CharField(max_length=255, null=False) + + def generic_search(self, query): + try: + results = Navigation.objects.annotate( + search=SearchVector("title", "parent_id", "category"), + ).filter(search=query) + except Exception as e: + raise + return results diff --git a/src/interface/static/css/main.css b/src/interface/static/css/main.css index c3f93d9..c1da0b0 100755 --- a/src/interface/static/css/main.css +++ b/src/interface/static/css/main.css @@ -1,19 +1,17 @@ body { margin: 0px; padding: 0px; - background-color: #DCDCDD; - color: #fff; + background-color: #FFF; + color: #000; overflow-x: hidden; } #app { display: grid; grid-template-areas: - "app_header" - "app_body" - "app_footer"; - grid-template-rows: 52px auto auto; - /* max-height: 100%; */ + "app_body"; + grid-template-rows: auto; + /*! max-height: 100%; */ } .clear { @@ -28,8 +26,7 @@ body { "title nav_left_top nav_center_top nav_right_top"; grid-template-columns: 225px auto auto; padding: 4px 0px 4px; - grid-auto-columns: auto; - background-color: #2b2b2b; + background-color: #2d2d2d; } .nav_left_top { @@ -55,15 +52,15 @@ body { .app_hdr { grid-area: title; - margin: 0px 0px 5px 0px; + margin: 0px 0px 0px 0px; font-family: 'Gruppo', cursive; - font-size: 36px; + font-size: 20px; text-align: start; - padding: 0px 0px 0px 5px; + padding: 0px 0px 0px 0px; } .shadow { - text-shadow: #4c5c68 -5px 3px 5px; + text-shadow: #fff -1px 0px 11px; } .app_subhdr { @@ -87,24 +84,24 @@ body { grid-area: app_body; grid-template-rows: auto; grid-template-areas: "nav_l shelf"; - grid-template-columns: 15vw 85vw; - background-color: dimgray; + grid-template-columns: 160px auto; + background-color: white; } .nav_l { display: grid; grid-area: nav_l; font-family: 'Gruppo', cursive; - font-size: 20px; - max-height: 500px; + font-size: 15px; + /*! max-height: 500px; */ overflow-y: scroll; - padding: 0px 10px; + /*! padding: 0px 10px; */ } .popover{ display: none; z-index: 100; - background-color: #000; + background-color: #cecece; /*min-width: 200px;*/ min-height: 30px; position: fixed; @@ -116,31 +113,33 @@ body { padding: 0px 10px; } .nav_l_hdr { - text-align: center; - padding: 5px; - background-color: #292f35; - border-bottom: 2px solid #000; + /*! text-align: center; */ + padding: 1px; + background-color: #9e9e9e; + border-bottom: 2px solid #dadada; + color: black; + font-weight: bold; } .nav_l_0 { - background-color: #2b2b2b; - padding: 5px; - text-align: center; - border-bottom: 1px solid #000; + background-color: #dadada; + /*! padding: 5px; */ + /*! text-align: center; */ + border-bottom: 1px solid #dadada; } .nav_l_1 { - padding: 5px; - text-align: center; - border-bottom: 1px solid #000; + /*! padding: 5px; */ + /*! text-align: center; */ + border-bottom: 1px solid #dadada; } .nav_link {} #vert-nav { list-style: None; padding: 0px; margin: 10px 0px; - border-left: 5px solid #292f35; - border-right: 5px solid #292f35; + /*! border-left: 5px solid #292f35; */ + /*! border-right: 5px solid #292f35; */ } .vert-nav-item {} @@ -224,11 +223,11 @@ body { background-color: darkgray; border-radius: 5px; border: 1px solid #999; - min-width: 110px; + /*! min-width: 110px; */ margin: 0px 5px 0px 0px; - padding-top: 2px; - padding-bottom: 2px; - max-height: 20px; + /*! padding-top: 2px; */ + /*! padding-bottom: 2px; */ + /*! max-height: 20px; */ } .nav_search { @@ -308,5 +307,13 @@ a.book_link { a.nav_link { text-decoration: none; - color: #fff; + color: #000; +} +.hidden{ + display: none; +} +.vert-nav{ + list-style: None; + padding: 0px; + margin: 0px 0px; } diff --git a/src/interface/static/js/pyshelf_ux.js b/src/interface/static/js/pyshelf_ux.js index 64374cf..8bad8e5 100755 --- a/src/interface/static/js/pyshelf_ux.js +++ b/src/interface/static/js/pyshelf_ux.js @@ -30,9 +30,9 @@ $(document).ready(function(){ $(this).removeAttr("disabled"); } }); - $('#app').css("height", max_height); - $('.nav_l').css("max-height", max_height); - $('div.shelf').css("max-height", max_height); +// $('#app').css("height", max_height); +// $('.nav_l').css("max-height", max_height); +// $('div.shelf').css("max-height", max_height); $('.nav_link').on('mouseover', function (e){ var popover_str = $(this).attr('alt'); x = $(this).offset().left @@ -51,4 +51,7 @@ $(document).ready(function(){ $('.popover').css('top', y); $('.popover').css('display','none'); }); + $('#btn_collections').on('click', function (e){ + $('.hidden.vert-nav.collections').toggle() + }); }) diff --git a/src/interface/templates/index.html b/src/interface/templates/index.html index 6990132..df05431 100755 --- a/src/interface/templates/index.html +++ b/src/interface/templates/index.html @@ -19,32 +19,50 @@
-
-
-

pyShelf {{Version}}

-
- - - -
@@ -59,18 +77,6 @@
-
diff --git a/src/interface/templates/search.html b/src/interface/templates/search.html index 2ca7c70..821e7f7 100755 --- a/src/interface/templates/search.html +++ b/src/interface/templates/search.html @@ -16,48 +16,44 @@
-
-
-

pyShelf {{Version}}

-
-
-

"An elegant tool... for a more civilized age."

-
-
- - - - - Fork - -Issue - -
- - - - -
+
-
diff --git a/src/interface/views.py b/src/interface/views.py index 590bb39..5c922e8 100755 --- a/src/interface/views.py +++ b/src/interface/views.py @@ -9,7 +9,7 @@ from django.http import JsonResponse from django.shortcuts import HttpResponse, render # render_to_response from django.utils.text import slugify -from .models import Books, Collections +from .models import Books, Collections, Navigation config = Config(Path("../")) @@ -26,7 +26,8 @@ def index(request): "Books": book_set(20, _set), "Set": str(_set), "Version": config.VERSION, - "LeftNav": menu("collections"), + "LeftNavCollections": menu("collections"), + "LeftNavMenu0": menu("nav_l_0"), }, ) @@ -190,7 +191,21 @@ def hr_name(book): return "{0}{1}".format(slugify(book.title), os.path.splitext(book.file_name)[1]) -def menu(which, _set=1): +def format_list(list_in): + formated_list, formated_list_key, x = [], [], 0 + for i in list_in: + if i.id not in formated_list_key: + if x % 2 == 0: + c = 0 + else: + c = 1 + if x <= 10: + x += 1 + else: + x = 0 + + +def menu(which, _set=1, parent=None): if which == "collections": collection_list = Collections.objects.all() collections, collection_key, x = [], [], 0 @@ -217,3 +232,7 @@ def menu(which, _set=1): ) collection_key.append(i.collection) return collections + elif which == "nav_lvl_0": + navigation_list = Navigation.objects.all() + breakpoint() + return navigation_list From 9fdd7e25a0d8d728352a7f5aa20bf73269797759 Mon Sep 17 00:00:00 2001 From: Raelon Masters Date: Fri, 12 Jun 2020 12:54:12 -0400 Subject: [PATCH 06/13] Changed layout from grid to single column --- src/interface/static/css/main.css | 30 ++++++++++++++------------ src/interface/templates/index.html | 33 ++++++++++++++++++----------- src/interface/templates/search.html | 14 ++++++------ src/interface/views.py | 4 ++++ 4 files changed, 49 insertions(+), 32 deletions(-) diff --git a/src/interface/static/css/main.css b/src/interface/static/css/main.css index c1da0b0..e824537 100755 --- a/src/interface/static/css/main.css +++ b/src/interface/static/css/main.css @@ -94,8 +94,9 @@ body { font-family: 'Gruppo', cursive; font-size: 15px; /*! max-height: 500px; */ - overflow-y: scroll; + overflow-y: auto; /*! padding: 0px 10px; */ + margin: 0px; } .popover{ @@ -114,7 +115,7 @@ body { } .nav_l_hdr { /*! text-align: center; */ - padding: 1px; + padding: 0px 5px; background-color: #9e9e9e; border-bottom: 2px solid #dadada; color: black; @@ -126,18 +127,20 @@ body { /*! padding: 5px; */ /*! text-align: center; */ border-bottom: 1px solid #dadada; + padding: 0px 0px 0px 10px; } .nav_l_1 { /*! padding: 5px; */ /*! text-align: center; */ border-bottom: 1px solid #dadada; + padding: 0px 0px 0px 10px; } .nav_link {} #vert-nav { list-style: None; padding: 0px; - margin: 10px 0px; + margin: 0px; /*! border-left: 5px solid #292f35; */ /*! border-right: 5px solid #292f35; */ } @@ -277,11 +280,9 @@ p { } #book_shelf { - display: grid; - grid-template-columns: 21% 21% 21% 21%; list-style-type: none; font-family: 'Audiowide', cursive; - font-size: 25px; + font-size: 15px; padding: 0; margin: 0px; min-width: 99vw; @@ -289,22 +290,24 @@ p { .shelf_item { display: grid; - background-color: burlywood; + grid-template-columns: 100px auto; + grid-template-areas: "thumb details"; margin: 0 10px 10px 10px; - max-width: 20vw; - max-height: 70vh; - text-align: center; } .book_thumb { - width: 20vw; - height: 70vh; + grid-area: thumb; + width: 100px; } a.book_link { text-decoration: none; } - +.book_details {} +.book_details_list {grid-area: details;list-style-type: none;} +.book_title {} +.book_author {} +.book_controls {} a.nav_link { text-decoration: none; color: #000; @@ -317,3 +320,4 @@ a.nav_link { padding: 0px; margin: 0px 0px; } +.btn {cursor:pointer} diff --git a/src/interface/templates/index.html b/src/interface/templates/index.html index df05431..888a2ac 100755 --- a/src/interface/templates/index.html +++ b/src/interface/templates/index.html @@ -27,18 +27,18 @@

pyShelf {{Version}}

- +