@@ -44,6 +44,14 @@ Currently pyShelf will recursively scan your collection, extract and store some
Django has been implemented to power the frontend experience, and web based database maintenance. The first steps of which are included in this commit. Also the book database has been switched over to reflect this. A properly configured web server is required for hosting the frontend, configuration of which is outside of the scope of this readme. Running via the Django test server might be possible, albeit not recomended.
+## New in 0.2.0
+* UI
+ * The UI has moved closer to what I have envisioned for this project, however more features and changes will be coming as needed to both the form and function.
+* UX
+ * Results have now been limited to 20 per page. Currently this is hardcoded in however in the future it will be user definable.
+ * Previous page & next page buttons have been implemented, and are working.
+
+
## In Progress
* UI/UX tweaks, including making the book display responsive. and not so ugly.
diff --git a/config.json b/config.json
index af20934..f89c692 100644
--- a/config.json
+++ b/config.json
@@ -1,6 +1,6 @@
{
"TITLE": "pyShelf E-Book Server",
- "VERSION": "0.1.0",
+ "VERSION": "0.2.0",
"BOOKPATH": "books/",
"DATABASE": "src/db.sqlite3",
"BOOKSHELF": "data/shelf.json"
diff --git a/docs/html/HTML/GTAGSROOT b/docs/html/HTML/GTAGSROOT
index dc5ede3..3da86ee 100755
--- a/docs/html/HTML/GTAGSROOT
+++ b/docs/html/HTML/GTAGSROOT
@@ -1 +1 @@
-/home/raelon/Projects/pyShelf/app
+/home/raelon/Projects/pyShelf
diff --git a/docs/html/HTML/index.html b/docs/html/HTML/index.html
index c06841c..1fc2c79 100755
--- a/docs/html/HTML/index.html
+++ b/docs/html/HTML/index.html
@@ -1,16 +1,16 @@
-pyShelf Open Source Ebook Server-0.1.0
+pyShelf Open Source Ebook Server-0.2.0
-
pyShelf Open Source Ebook Server-0.1.0
+
pyShelf Open Source Ebook Server-0.2.0
-Last updated Sun Nov 10 01:10:53 EST 2019
+Last updated Fri Nov 29 22:17:44 EST 2019
Powered by GLOBAL-6.6.3.
diff --git a/docs/html/HTML/mains.html b/docs/html/HTML/mains.html
index c06841c..1fc2c79 100755
--- a/docs/html/HTML/mains.html
+++ b/docs/html/HTML/mains.html
@@ -1,16 +1,16 @@
-pyShelf Open Source Ebook Server-0.1.0
+pyShelf Open Source Ebook Server-0.2.0
-
pyShelf Open Source Ebook Server-0.1.0
+
pyShelf Open Source Ebook Server-0.2.0
-Last updated Sun Nov 10 01:10:53 EST 2019
+Last updated Fri Nov 29 22:17:44 EST 2019
Powered by GLOBAL-6.6.3.
diff --git a/docs/html/HTML/rebuild.sh b/docs/html/HTML/rebuild.sh
old mode 100755
new mode 100644
index 26ccd6c..dbc9d71
--- a/docs/html/HTML/rebuild.sh
+++ b/docs/html/HTML/rebuild.sh
@@ -5,4 +5,4 @@
# Usage:
# % sh rebuild.sh
#
-cd /home/raelon/Projects/pyShelf/app && GTAGSCONF=':skip=HTML/,HTML.pub/,tags,TAGS,ID,y.tab.c,y.tab.h,gtags.files,cscope.files,cscope.out,cscope.po.out,cscope.in.out,SCCS/,RCS/,CVS/,CVSROOT/,{arch}/,autom4te.cache/,*.orig,*.rej,*.bak,*~,#*#,*.swp,*.tmp,*_flymake.*,*_flymake,*.o,*.a,*.so,*.lo,*.zip,*.gz,*.bz2,*.xz,*.lzh,*.Z,*.tgz,*.min.js,*min.css:langmap=c\:.c.h,yacc\:.y,asm\:.s.S,java\:.java,cpp\:.c++.cc.hh.cpp.cxx.hxx.hpp.C.H,php\:.php.php3.phtml:' htags -g -s -a -n -v -w -t 'pyShelf Open Source Ebook Server-0.1.0' /home/raelon/Projects/pyShelf/docs/html
+cd /home/raelon/Projects/pyShelf && GTAGSCONF=':langmap=c\:.c.h,yacc\:.y,asm\:.s.S,java\:.java,cpp\:.c++.cc.hh.cpp.cxx.hxx.hpp.C.H,php\:.php.php3.phtml:skip=HTML/,HTML.pub/,tags,TAGS,ID,y.tab.c,y.tab.h,gtags.files,cscope.files,cscope.out,cscope.po.out,cscope.in.out,SCCS/,RCS/,CVS/,CVSROOT/,{arch}/,autom4te.cache/,*.orig,*.rej,*.bak,*~,#*#,*.swp,*.tmp,*_flymake.*,*_flymake,*.o,*.a,*.so,*.lo,*.zip,*.gz,*.bz2,*.xz,*.lzh,*.Z,*.tgz,*.min.js,*min.css:' htags -g -s -a -n -v -w -t 'pyShelf Open Source Ebook Server-0.2.0' /home/raelon/Projects/pyShelf/docs/html
diff --git a/docs/html/index.hhc b/docs/html/index.hhc
index 96007e5..a1f54eb 100755
--- a/docs/html/index.hhc
+++ b/docs/html/index.hhc
@@ -4,169 +4,6 @@
@@ -47,7 +47,7 @@ $(function() {
-Generated on Sun Nov 10 2019 01:10:53 for pyShelf Open Source Ebook Server by
+Generated on Fri Nov 29 2019 22:17:44 for pyShelf Open Source Ebook Server by 1.8.16
diff --git a/docs/html/menudata.js b/docs/html/menudata.js
index 25e7273..bdab70c 100755
--- a/docs/html/menudata.js
+++ b/docs/html/menudata.js
@@ -21,13 +21,4 @@ with this program; if not, write to the Free Software Foundation, Inc.,
for the JavaScript code in this file
*/
var menudata={children:[
-{text:"Main Page",url:"index.html"},
-{text:"Classes",url:"annotated.html",children:[
-{text:"Class List",url:"annotated.html"},
-{text:"Class Index",url:"classes.html"},
-{text:"Class Hierarchy",url:"hierarchy.html"},
-{text:"Class Members",url:"functions.html",children:[
-{text:"All",url:"functions.html"},
-{text:"Functions",url:"functions_func.html"}]}]},
-{text:"Files",url:"files.html",children:[
-{text:"File List",url:"files.html"}]}]}
+{text:"Main Page",url:"index.html"}]}
diff --git a/docs/warn.log b/docs/warn.log
index 63e674e..9ceb12d 100755
--- a/docs/warn.log
+++ b/docs/warn.log
@@ -1,62 +1,2 @@
-/home/raelon/Projects/pyShelf/app/config.py:3: warning: Member __init__(self) (function) of class app::config::Config is not documented.
-/home/raelon/Projects/pyShelf/app/config.py:4: warning: Member book_path (variable) of class app::config::Config is not documented.
-/home/raelon/Projects/pyShelf/app/config.py:5: warning: Member TITLE (variable) of class app::config::Config is not documented.
-/home/raelon/Projects/pyShelf/app/config.py:6: warning: Member book_shelf (variable) of class app::config::Config is not documented.
-/home/raelon/Projects/pyShelf/app/config.py:8: warning: Member catalogue_db (variable) of class app::config::Config is not documented.
-/home/raelon/Projects/pyShelf/app/config.py:9: warning: Member file_array (variable) of class app::config::Config is not documented.
-/home/raelon/Projects/pyShelf/app/config.py:13: warning: Member auto_scan (variable) of class app::config::Config is not documented.
-/home/raelon/Projects/pyShelf/app/lib/api_hooks.py:11: warning: Member __init__(self) (function) of class app::lib::api_hooks::DuckDuckGo is not documented.
-/home/raelon/Projects/pyShelf/app/lib/api_hooks.py:12: warning: Member url (variable) of class app::lib::api_hooks::DuckDuckGo is not documented.
-/home/raelon/Projects/pyShelf/app/lib/api_hooks.py:14: warning: return type of member app.lib.api_hooks.DuckDuckGo.image_result is not documented
-/home/raelon/Projects/pyShelf/app/lib/display.py:17: warning: Member dimensions (variable) of class app::lib::display::Frontend is not documented.
-/home/raelon/Projects/pyShelf/app/lib/display.py:18: warning: Member TITLE (variable) of class app::lib::display::Frontend is not documented.
-/home/raelon/Projects/pyShelf/app/lib/display.py:53: warning: return type of member app.lib.display.Frontend.app_body is not documented
-/home/raelon/Projects/pyShelf/app/lib/display.py:74: warning: return type of member app.lib.display.Frontend.app_footer is not documented
-/home/raelon/Projects/pyShelf/app/lib/display.py:38: warning: return type of member app.lib.display.Frontend.app_Headers is not documented
-/home/raelon/Projects/pyShelf/app/lib/display.py:91: warning: return type of member app.lib.display.Frontend.compile is not documented
-/home/raelon/Projects/pyShelf/app/lib/display.py:20: warning: return type of member app.lib.display.Frontend.html_Headers is not documented
-/home/raelon/Projects/pyShelf/app/lib/library.py:21: warning: Member __init__(self) (function) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:27: warning: Member scan_folder(self, folder=config.book_path) (function) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:101: warning: Member extract_content(self, book_zip, book) (function) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:109: warning: Member extract_cover_html(self, book_zip, book) (function) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:117: warning: Member extract_cover_image(self, book_zip, book) (function) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:126: warning: Member compare_shelf_current(self) (function) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:139: warning: Member import_books(self, list=None) (function) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:22: warning: Member file_list (variable) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:23: warning: Member opf_regx (variable) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:24: warning: Member cover_regx (variable) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:25: warning: Member html_regx (variable) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:53: warning: Member books (variable) of class app::lib::library::Catalogue is not documented.
-/home/raelon/Projects/pyShelf/app/lib/library.py:78: warning: return type of member app.lib.library.Catalogue.extract_metadata is not documented
-/home/raelon/Projects/pyShelf/app/lib/library.py:43: warning: return type of member app.lib.library.Catalogue.filter_books is not documented
-/home/raelon/Projects/pyShelf/app/lib/library.py:61: warning: return type of member app.lib.library.Catalogue.process_book is not documented
-/home/raelon/Projects/pyShelf/app/lib/library.py:36: warning: return type of member app.lib.library.Catalogue.scan_book is not documented
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:77: warning: Member books_per_page (variable) of class app::lib::pyShelf::BookDisplay is not documented.
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:78: warning: Member current_page (variable) of class app::lib::pyShelf::BookDisplay is not documented.
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:79: warning: Member thumbnail_size (variable) of class app::lib::pyShelf::BookDisplay is not documented.
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:80: warning: Member thumbnail_scale (variable) of class app::lib::pyShelf::BookDisplay is not documented.
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:81: warning: Member total_pages (variable) of class app::lib::pyShelf::BookDisplay is not documented.
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:99: warning: return type of member app.lib.pyShelf.BookDisplay.booksPerPage is not documented
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:83: warning: return type of member app.lib.pyShelf.BookDisplay.nextPage is not documented
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:91: warning: return type of member app.lib.pyShelf.BookDisplay.previousPage is not documented
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:117: warning: Member __init__(self) (function) of class app::lib::pyShelf::BookServer is not documented.
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:118: warning: Member server_address (variable) of class app::lib::pyShelf::BookServer is not documented.
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:119: warning: Member handler (variable) of class app::lib::pyShelf::BookServer is not documented.
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:120: warning: Member httpd (variable) of class app::lib::pyShelf::BookServer is not documented.
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:143: warning: return type of member app.lib.pyShelf.BookServer.close is not documented
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:122: warning: return type of member app.lib.pyShelf.BookServer.close_prompt is not documented
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:131: warning: return type of member app.lib.pyShelf.BookServer.run is not documented
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:17: warning: Member __init__(self, file_array) (function) of class app::lib::pyShelf::InitFiles is not documented.
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:24: warning: return type of member app.lib.pyShelf.InitFiles.CreateFile is not documented
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:34: warning: Member do_GET(self) (function) of class app::lib::pyShelf::RequestHandler is not documented.
-/home/raelon/Projects/pyShelf/app/lib/pyShelf.py:37: warning: Member path (variable) of class app::lib::pyShelf::RequestHandler is not documented.
-/home/raelon/Projects/pyShelf/app/lib/storage.py:14: warning: Member __init__(self) (function) of class app::lib::storage::Storage is not documented.
-/home/raelon/Projects/pyShelf/app/lib/storage.py:60: warning: Member book_paths_list(self) (function) of class app::lib::storage::Storage is not documented.
-/home/raelon/Projects/pyShelf/app/lib/storage.py:67: warning: Member commit(self) (function) of class app::lib::storage::Storage is not documented.
-/home/raelon/Projects/pyShelf/app/lib/storage.py:71: warning: Member close(self) (function) of class app::lib::storage::Storage is not documented.
-/home/raelon/Projects/pyShelf/app/lib/storage.py:15: warning: Member db_file (variable) of class app::lib::storage::Storage is not documented.
-/home/raelon/Projects/pyShelf/app/lib/storage.py:22: warning: Member db (variable) of class app::lib::storage::Storage is not documented.
-/home/raelon/Projects/pyShelf/app/lib/storage.py:23: warning: Member cursor (variable) of class app::lib::storage::Storage is not documented.
-/home/raelon/Projects/pyShelf/app/lib/storage.py:28: warning: return type of member app.lib.storage.Storage.create_tables is not documented
-/home/raelon/Projects/pyShelf/app/lib/storage.py:19: warning: return type of member app.lib.storage.Storage.database is not documented
-/home/raelon/Projects/pyShelf/app/lib/storage.py:39: warning: return type of member app.lib.storage.Storage.insert_book is not documented
+warning: source app is not a readable file or directory... skipping.
+error: Cannot find directory app/. Check the value of the INPUT tag in the configuration file.
diff --git a/doxygen.conf b/doxygen.conf
index 6ead1ad..740efd9 100644
--- a/doxygen.conf
+++ b/doxygen.conf
@@ -38,7 +38,7 @@ PROJECT_NAME = "pyShelf Open Source Ebook Server"
# could be handy for archiving the generated documentation or if some version
# control system is used.
-PROJECT_NUMBER = 0.1.0
+PROJECT_NUMBER = 0.2.0
# Using the PROJECT_BRIEF tag one can provide an optional one line description
# for a project that appears at the top of each page and should give viewer a
diff --git a/src/frontend/urls.py b/src/frontend/urls.py
index 924328a..4d47ec2 100755
--- a/src/frontend/urls.py
+++ b/src/frontend/urls.py
@@ -21,8 +21,9 @@ from interface import views
urlpatterns = [
path("admin/", admin.site.urls),
path("", views.index, name="index"),
- # path('', views.download, name="download")
- path("", views.download, name="download"),
+ path("download/", views.download, name="download"),
+ path("prev_page/", views.prev_page, name="prev_page"),
+ path("next_page/", views.next_page, name="next_page"),
]
if settings.DEBUG:
import debug_toolbar
diff --git a/src/interface/migrations/0001_initial.py b/src/interface/migrations/0001_initial.py
new file mode 100644
index 0000000..f9155d6
--- /dev/null
+++ b/src/interface/migrations/0001_initial.py
@@ -0,0 +1,30 @@
+# Generated by Django 2.2.7 on 2019-11-28 19:24
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+ initial = True
+
+ dependencies = [
+ ]
+
+ operations = [
+ migrations.CreateModel(
+ name='Books',
+ fields=[
+ ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+ ('title', models.CharField(max_length=255)),
+ ('author', models.CharField(max_length=255, null=True)),
+ ('categories', models.CharField(max_length=255, null=True)),
+ ('cover', models.BinaryField(editable=True, null=True)),
+ ('pages', models.IntegerField(null=True)),
+ ('progress', models.IntegerField(null=True)),
+ ('file_name', models.CharField(max_length=255)),
+ ],
+ options={
+ 'db_table': 'books',
+ },
+ ),
+ ]
diff --git a/src/interface/models.py b/src/interface/models.py
deleted file mode 100755
index b2f5951..0000000
--- a/src/interface/models.py
+++ /dev/null
@@ -1,34 +0,0 @@
-from django.db import models
-
-# Create your models here.
-
-
-class Books(models.Model):
- """
- pyShelfs Book Database class
- :param title: Book title
- :param author: Author
- :param categories: Categories <-- Not implemented
- :param cover: Cover image BinaryField
- :param pages: # of pages <-- Not implemented
- :param progress: Reader percentage <-- Not implented
- :param file_name: Path to book
- """
-
- class Meta:
- db_table = "books"
-
- def __str__(self):
- return self.title
-
- title = models.CharField(max_length=255)
- author = models.CharField(max_length=255, null=True)
- categories = models.CharField(max_length=255, null=True)
- cover = models.BinaryField(null=True, editable=True)
- pages = models.IntegerField(null=True)
- progress = models.IntegerField(null=True)
- file_name = models.CharField(max_length=255, null=False)
-
- def get_absolute_url(self):
- """Returns the url to access a particular instance of MyModelName."""
- return reverse("model-detail-view", args=[str(self.id)])
diff --git a/src/interface/static/css/main.css b/src/interface/static/css/main.css
index 75874c4..07cdfc2 100755
--- a/src/interface/static/css/main.css
+++ b/src/interface/static/css/main.css
@@ -1,61 +1,142 @@
body{
- margin: 0px 10px 0px 10px;
+ margin: 0px;
padding: 0px;
background-color: #DCDCDD;
- color: #46494C
+ color: #fff;
+ overflow: hidden;
}
#app{
display: grid;
grid-template-areas: "app_header"
"app_body"
"app_footer";
- grid-template-rows: 5vh 90vh 5vh;
- max-height: 100%
+ grid-template-rows: auto 84vh auto;
+ max-height: 100%;
+}
+.clear{
+ clear: both;
}
.app_header{
grid-area: app_header;
+ margin: 0px;
display: grid;
- grid-template-areas: "title slogan";
+ grid-template-areas:
+ "title slogan subhdr"
+ "nav_left_top nav_center_top nav_right_top";
align-items: center;
+ background-color: #2b2b2b;
+ padding: 4px 0px 4px;
+ grid-auto-columns: auto;
+}
+.nav_left_top{
+ grid-area: nav_left_top;
+ display: flex;
+ justify-content: left;
+}
+.nav_center_top{
+ grid-area: nav_center_top;
+ display: flex;
+ justify-content: center;
+}
+.nav_right_top{
+ grid-area: nav_right_top;
+ display: flex;
+ justify-content: right;
}
.app_hdr{
grid-area: title;
- margin: 0;
- font-family: 'Audiowide', cursive;
- font-size: 25px;
+ margin: 0px 0px 5px 0px;
+ font-family: 'Gruppo', cursive;
+ font-size: 36px;
text-align: start;
+ padding: 0px 0px 0px 5px;
}
.shadow{
text-shadow: #4c5c68 -5px 3px 5px;
}
.app_subhdr{
- grid-area: slogan;
- margin: 0;
- font-family: 'Audiowide', cursive;
+ grid-area: subhdr;
+ margin: 0px 5px;
+ font-family: 'Gruppo', cursive;
font-size: 18px;
- text-shadow: #4c5c68 -5px 3px 5px;
text-align: end;
}
+.app_slogan{
+ grid-area: slogan;
+ margin: 0;
+ font-size: 18px;
+ font-family: 'Gruppo', cursive;
+ text-align: center;
+}
.app_body{
display: grid;
grid-area: app_body;
- grid-template-rows: 5vh auto;
- grid-template-areas: "nav_top"
- "shelf";
+ grid-template-rows: auto;
+ grid-template-areas: "shelf";
justify-items: center;
+ overflow-y: scroll;
+ background-color: dimgray;
}
.app_footer{
grid-area: app_footer;
- position: fixed;
- bottom: 0px;
+ min-width: 100%;
+ background-color: #2b2b2b;
+ margin: 0px;
}
.nav_top{
- grid-area: nav_top
+ grid-area: nav_top;
+ display: grid;
+ grid-template-areas: "left center right";
+ grid-template-columns: auto auto auto;
+}
+.navbar{
+ list-style-type: none;
+}
+.left_align{
+display: flex;
+justify-content: left;
+}
+.center_align{
+display: flex;
+justify-content:center;
+}
+.right_align{
+display: flex;
+justify-content: right;
+}
+.top{
+
+}
+.inline{
+
+}
+.inline_txt{
+
+}
+.button{
+
+}
+.nav_button{
+ background-color:darkgray;
+ border-radius: 5px;
+ border: 1px solid #999;
+ min-width: 110px;
+ margin: 0px 5px 0px 0px;
+ padding-top: 2px;
+ padding-bottom: 2px;
+}
+.nav_search{
+ margin: 0px 5px 0px 0px;
+ border-radius: 5px;
+ border: 1px solid #999;
+}
+.search{
+
}
.shelf{
grid-area: shelf;
margin: 0px 0px;
- padding: 0px;
+ padding: 10px 0px 10px;
list-style-type: none;
}
.shelf_contents{
@@ -80,6 +161,7 @@ body{
font-family: 'Audiowide', cursive;
font-size: 25px;
padding: 0;
+ margin: 0px;
}
.shelf_item{
background-color: burlywood;
@@ -95,3 +177,7 @@ body{
a.book_link{
text-decoration: none;
}
+a.nav_link{
+ text-decoration: none;
+ color: #fff;
+}
diff --git a/src/interface/static/img/gpl-125x28.png b/src/interface/static/img/gpl-125x28.png
new file mode 100644
index 0000000..2dab05f
Binary files /dev/null and b/src/interface/static/img/gpl-125x28.png differ
diff --git a/src/interface/static/img/gpl-150x33.png b/src/interface/static/img/gpl-150x33.png
new file mode 100644
index 0000000..c38be55
Binary files /dev/null and b/src/interface/static/img/gpl-150x33.png differ
diff --git a/src/interface/static/img/gpl-175x39.png b/src/interface/static/img/gpl-175x39.png
new file mode 100644
index 0000000..9925fc2
Binary files /dev/null and b/src/interface/static/img/gpl-175x39.png differ
diff --git a/src/interface/static/img/gpl.png b/src/interface/static/img/gpl.png
new file mode 100644
index 0000000..7bc4297
Binary files /dev/null and b/src/interface/static/img/gpl.png differ
diff --git a/src/interface/static/img/open-source-150x25.png b/src/interface/static/img/open-source-150x25.png
new file mode 100644
index 0000000..329333c
Binary files /dev/null and b/src/interface/static/img/open-source-150x25.png differ
diff --git a/src/interface/static/img/open-source-175x29.png b/src/interface/static/img/open-source-175x29.png
new file mode 100644
index 0000000..33382f3
Binary files /dev/null and b/src/interface/static/img/open-source-175x29.png differ
diff --git a/src/interface/static/img/open-source-200x33.png b/src/interface/static/img/open-source-200x33.png
new file mode 100644
index 0000000..5361bd6
Binary files /dev/null and b/src/interface/static/img/open-source-200x33.png differ
diff --git a/src/interface/static/img/open-source.png b/src/interface/static/img/open-source.png
new file mode 100644
index 0000000..e6f37a1
Binary files /dev/null and b/src/interface/static/img/open-source.png differ
diff --git a/src/interface/static/img/pyShelf_frontend_0_1_0.png b/src/interface/static/img/pyShelf_frontend_0_1_0.png
index 4c89425..9fd1ddc 100644
Binary files a/src/interface/static/img/pyShelf_frontend_0_1_0.png and b/src/interface/static/img/pyShelf_frontend_0_1_0.png differ
diff --git a/src/interface/static/img/pyShelf_frontend_0_1_0_thumb.png b/src/interface/static/img/pyShelf_frontend_0_1_0_thumb.png
new file mode 100644
index 0000000..492329c
Binary files /dev/null and b/src/interface/static/img/pyShelf_frontend_0_1_0_thumb.png differ
diff --git a/src/interface/static/js/jquery-3.4.1.min.js b/src/interface/static/js/jquery-3.4.1.min.js
new file mode 100644
index 0000000..a1c07fd
--- /dev/null
+++ b/src/interface/static/js/jquery-3.4.1.min.js
@@ -0,0 +1,2 @@
+/*! jQuery v3.4.1 | (c) JS Foundation and other contributors | jquery.org/license */
+!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],E=C.document,r=Object.getPrototypeOf,s=t.slice,g=t.concat,u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType},x=function(e){return null!=e&&e===e.window},c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.4.1",k=function(e,t){return new k.fn.init(e,t)},p=/^[\s\uFEFF\xA0]+|[\s\uFEFF\xA0]+$/g;function d(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp($),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+$),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\([\\da-f]{1,6}"+M+"?|("+M+")|.)","ig"),ne=function(e,t,n){var r="0x"+t-65536;return r!=r||n?t:r<0?String.fromCharCode(r+65536):String.fromCharCode(r>>10|55296,1023&r|56320)},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(m.childNodes),m.childNodes),t[m.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&((e?e.ownerDocument||e:m)!==C&&T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!A[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&U.test(t)){(s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=k),o=(l=h(t)).length;while(o--)l[o]="#"+s+" "+xe(l[o]);c=l.join(","),f=ee.test(t)&&ye(e.parentNode)||e}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){A(t,!0)}finally{s===k&&e.removeAttribute("id")}}}return g(t.replace(B,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[k]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e.namespaceURI,n=(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:m;return r!==C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),m!==C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=k,!C.getElementsByName||!C.getElementsByName(k).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+k+"-]").length||v.push("~="),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+k+"+*").length||v.push(".#.+[+~]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",$)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},D=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)===(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e===C||e.ownerDocument===m&&y(m,e)?-1:t===C||t.ownerDocument===m&&y(m,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e===C?-1:t===C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]===m?-1:s[r]===m?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if((e.ownerDocument||e)!==C&&T(e),d.matchesSelector&&E&&!A[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){A(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=p[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&p(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?k.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?k.grep(e,function(e){return e===n!==r}):"string"!=typeof n?k.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(k.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||q,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:L.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof k?t[0]:t,k.merge(this,k.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),D.test(r[1])&&k.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(k):k.makeArray(e,this)}).prototype=k.fn,q=k(E);var H=/^(?:parents|prev(?:Until|All))/,O={children:!0,contents:!0,next:!0,prev:!0};function P(e,t){while((e=e[t])&&1!==e.nodeType);return e}k.fn.extend({has:function(e){var t=k(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i,ge={option:[1,""],thead:[1,"