Port the web to bootstrap5

So it is responsive in phones.
This commit is contained in:
Las Zenow 2017-06-08 00:44:35 +00:00
parent 8af2ad3758
commit 6a3da59c75
40 changed files with 1131 additions and 849 deletions

View file

@ -77,14 +77,10 @@ https://gitlab.com/trantor/trantor/issues
All the matterial of this project is under WTFPL as described on the LICENSE All the matterial of this project is under WTFPL as described on the LICENSE
file with the exception of: file with the exception of:
* css/bootstrap.min.css css/bootstra-responsive.min.css js/bootstrap.min.js * css/bootstrap.bundle.min.css css/bootstrap.bundle.min.css.map js/bootstrap.bundle.min.js
img/glyphicons-halflings-white.png img/glyphicons-halflings.png js/bootstrap.bundle.min.js.map img/bootstrap-icons.svg
From the bootstrap framework: http://twitter.github.com/bootstrap/ From the bootstrap framework: https://getbootstrap.com/
* js/jquery.js
From jquery library: http://jquery.com/
* img/bright_squares.png * img/bright_squares.png
From subtlepatterns: http://subtlepatterns.com/bright-squares/ From subtlepatterns: http://subtlepatterns.com/bright-squares/
* css/FredokaOne.ttf css/PTSerif.ttf * css/FredokaOne.ttf css/PTSerif.ttf
From Google Web Fonts: http://www.google.com/webfonts From Google Web Fonts: http://www.google.com/webfonts
* js/bootstrap-tokenfield.min.js dist/css/bootstrap-tokenfield.min.css
From Bootstrap Tokenfield: https://github.com/sliptree/bootstrap-tokenfield

File diff suppressed because one or more lines are too long

View file

@ -1,5 +0,0 @@
/*!
* bootstrap-tokenfield
* https://github.com/sliptree/bootstrap-tokenfield
* Copyright 2013-2014 Sliptree and other contributors; Licensed MIT
*/@-webkit-keyframes blink{0%{border-color:#ededed}100%{border-color:#b94a48}}@-moz-keyframes blink{0%{border-color:#ededed}100%{border-color:#b94a48}}@keyframes blink{0%{border-color:#ededed}100%{border-color:#b94a48}}.tokenfield{height:auto;min-height:34px;padding-bottom:0}.tokenfield.focus{border-color:#66afe9;outline:0;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6);box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 8px rgba(102,175,233,.6)}.tokenfield .token{-webkit-box-sizing:border-box;-moz-box-sizing:border-box;box-sizing:border-box;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px;display:inline-block;border:1px solid #d9d9d9;background-color:#ededed;white-space:nowrap;margin:-1px 5px 5px 0;height:22px;vertical-align:top;cursor:default}.tokenfield .token:hover{border-color:#b9b9b9}.tokenfield .token.active{border-color:#52a8ec;border-color:rgba(82,168,236,.8)}.tokenfield .token.duplicate{border-color:#ebccd1;-webkit-animation-name:blink;animation-name:blink;-webkit-animation-duration:.1s;animation-duration:.1s;-webkit-animation-direction:normal;animation-direction:normal;-webkit-animation-timing-function:ease;animation-timing-function:ease;-webkit-animation-iteration-count:infinite;animation-iteration-count:infinite}.tokenfield .token.invalid{background:0 0;border:1px solid transparent;-webkit-border-radius:0;-moz-border-radius:0;border-radius:0;border-bottom:1px dotted #d9534f}.tokenfield .token.invalid.active{background:#ededed;border:1px solid #ededed;-webkit-border-radius:3px;-moz-border-radius:3px;border-radius:3px}.tokenfield .token .token-label{display:inline-block;overflow:hidden;text-overflow:ellipsis;padding-left:4px;vertical-align:top}.tokenfield .token .close{font-family:Arial;display:inline-block;line-height:100%;font-size:1.1em;line-height:1.49em;margin-left:5px;float:none;height:100%;vertical-align:top;padding-right:4px}.tokenfield .token-input{background:0 0;width:60px;min-width:60px;border:0;height:20px;padding:0;margin-bottom:6px;-webkit-box-shadow:none;box-shadow:none}.tokenfield .token-input:focus{border-color:transparent;outline:0;-webkit-box-shadow:none;box-shadow:none}.tokenfield.disabled{cursor:not-allowed;background-color:#eee}.tokenfield.disabled .token-input{cursor:not-allowed}.tokenfield.disabled .token:hover{cursor:not-allowed;border-color:#d9d9d9}.tokenfield.disabled .token:hover .close{cursor:not-allowed;opacity:.2;filter:alpha(opacity=20)}.has-warning .tokenfield.focus{border-color:#66512c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #c0a16b}.has-error .tokenfield.focus{border-color:#843534;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #ce8483}.has-success .tokenfield.focus{border-color:#2b542c;-webkit-box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168;box-shadow:inset 0 1px 1px rgba(0,0,0,.075),0 0 6px #67b168}.tokenfield.input-sm,.input-group-sm .tokenfield{min-height:30px;padding-bottom:0}.input-group-sm .token,.tokenfield.input-sm .token{height:20px;margin-bottom:4px}.input-group-sm .token-input,.tokenfield.input-sm .token-input{height:18px;margin-bottom:5px}.tokenfield.input-lg,.input-group-lg .tokenfield{height:auto;min-height:45px;padding-bottom:4px}.input-group-lg .token,.tokenfield.input-lg .token{height:25px}.input-group-lg .token-label,.tokenfield.input-lg .token-label{line-height:23px}.input-group-lg .token .close,.tokenfield.input-lg .token .close{line-height:1.3em}.input-group-lg .token-input,.tokenfield.input-lg .token-input{height:23px;line-height:23px;margin-bottom:6px;vertical-align:top}.tokenfield.rtl{direction:rtl;text-align:right}.tokenfield.rtl .token{margin:-1px 0 5px 5px}.tokenfield.rtl .token .token-label{padding-left:0;padding-right:4px}

16
css/bootstrap.min.css vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -10,19 +10,15 @@
font-weight: 400; font-weight: 400;
src: local('PT Serif'), local('PTSerif-Regular'), url(/css/PTSerif.ttf) format('truetype'); src: local('PT Serif'), local('PTSerif-Regular'), url(/css/PTSerif.ttf) format('truetype');
} }
h1, h2, h3, h4, h5, h6 { h1, h2, h3, h4, h5, h6, .navbar-brand, .title {
font-family: 'Fredoka One', cursive; font-family: 'Fredoka One', cursive;
} }
p, div { p, div {
font-family: 'PT Serif', serif; font-family: 'PT Serif', serif;
} }
a {
text-decoration: none;
}
body { body {
background: url(/img/bright_squares.png) repeat 0 0; background: url(/img/bright_squares.png) repeat 0 0;
} }
.centered {
text-align:center;
}
.down {
vertical-align:text-bottom;
}

1
img/bootstrap-icons.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 595 KiB

File diff suppressed because one or more lines are too long

7
js/bootstrap.bundle.min.js vendored Normal file

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

6
js/bootstrap.min.js vendored

File diff suppressed because one or more lines are too long

2
js/jquery.js vendored

File diff suppressed because one or more lines are too long

View file

@ -27,7 +27,7 @@ func deleteHandler(h handler) {
} }
book, err := h.db.GetBookID(id) book, err := h.db.GetBookID(id)
if err != nil { if err != nil {
h.sess.Notify("Book not found!", "The book with id '"+id+"' is not there", "error") h.sess.Notify("Book not found!", "The book with id '"+id+"' is not there", "danger")
continue continue
} }
err = h.db.UpdateSubmissionByBook(id, "Rejected", nil) err = h.db.UpdateSubmissionByBook(id, "Rejected", nil)
@ -124,7 +124,7 @@ func saveHandler(h handler) {
err := h.db.UpdateBook(id, book) err := h.db.UpdateBook(id, book)
if err != nil { if err != nil {
log.Error("Updating book: ", err) log.Error("Updating book: ", err)
h.sess.Notify("Can't modify book!", err.Error(), "error") h.sess.Notify("Can't modify book!", err.Error(), "danger")
} else { } else {
h.sess.Notify("Book Modified!", "", "success") h.sess.Notify("Book Modified!", "", "success")
} }

View file

@ -15,7 +15,7 @@ func listHandler(h handler) {
list, err := h.db.GetBookList(listID) list, err := h.db.GetBookList(listID)
if err != nil { if err != nil {
log.Error("Error loading list ", listID, ": ", err) log.Error("Error loading list ", listID, ": ", err)
h.sess.Notify("Something went wrong!", "Could not load the list", "error") h.sess.Notify("Something went wrong!", "Could not load the list", "danger")
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound) http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
return return
} }
@ -52,7 +52,7 @@ func listPostHandler(h handler) {
userLists, err := h.db.GetListsByUser(h.sess.User) userLists, err := h.db.GetListsByUser(h.sess.User)
if err != nil { if err != nil {
log.Error("Error loading user (", h.sess.User, ") lists: ", err) log.Error("Error loading user (", h.sess.User, ") lists: ", err)
h.sess.Notify("Something went wrong!", "Could not add book to the list", "error") h.sess.Notify("Something went wrong!", "Could not add book to the list", "danger")
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound) http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
return return
} }
@ -71,7 +71,7 @@ func listPostHandler(h handler) {
err = h.db.NewBookList(listID, listTitle, h.sess.User, []string{}) err = h.db.NewBookList(listID, listTitle, h.sess.User, []string{})
if err != nil { if err != nil {
log.Error("Error creating list ", listTitle, " by user ", h.sess.User, ": ", err) log.Error("Error creating list ", listTitle, " by user ", h.sess.User, ": ", err)
h.sess.Notify("Something went wrong!", "Could not add book to the list", "error") h.sess.Notify("Something went wrong!", "Could not add book to the list", "danger")
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound) http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
return return
} }
@ -83,7 +83,7 @@ func listPostHandler(h handler) {
err = h.db.AddBookToList(listID, bookID) err = h.db.AddBookToList(listID, bookID)
if err != nil { if err != nil {
log.Error("Error adding book ", bookID, " to list ", listTitle, "(", listID, "): ", err) log.Error("Error adding book ", bookID, " to list ", listTitle, "(", listID, "): ", err)
h.sess.Notify("Something went wrong!", "Could not add book to the list", "error") h.sess.Notify("Something went wrong!", "Could not add book to the list", "danger")
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound) http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
return return
} }
@ -96,12 +96,12 @@ func listEditPostHandler(h handler) {
list, err := h.db.GetBookList(listID) list, err := h.db.GetBookList(listID)
if err != nil || list == nil { if err != nil || list == nil {
log.Error("Error loading list ", listID, ": ", err) log.Error("Error loading list ", listID, ": ", err)
h.sess.Notify("Something went wrong!", "Could not save the list", "error") h.sess.Notify("Something went wrong!", "Could not save the list", "danger")
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound) http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
return return
} }
if h.sess.User != list.User.Username { if h.sess.User != list.User.Username {
h.sess.Notify("You are not the owner of the list!", "You can't edit it", "error") h.sess.Notify("You are not the owner of the list!", "You can't edit it", "danger")
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound) http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
return return
} }
@ -111,7 +111,7 @@ func listEditPostHandler(h handler) {
err = h.db.UpdateBookList(listID, title, description) err = h.db.UpdateBookList(listID, title, description)
if err != nil { if err != nil {
log.Error("Error editing list ", list.Title, "(", listID, "): ", err) log.Error("Error editing list ", list.Title, "(", listID, "): ", err)
h.sess.Notify("Something went wrong!", "Could not edit the list", "error") h.sess.Notify("Something went wrong!", "Could not edit the list", "danger")
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound) http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
return return
} }
@ -126,12 +126,12 @@ func listRemoveHandler(h handler) {
list, err := h.db.GetBookList(listID) list, err := h.db.GetBookList(listID)
if err != nil || list == nil { if err != nil || list == nil {
log.Error("Error loading list ", listID, ": ", err) log.Error("Error loading list ", listID, ": ", err)
h.sess.Notify("Something went wrong!", "Could not remove books from the list", "error") h.sess.Notify("Something went wrong!", "Could not remove books from the list", "danger")
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound) http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
return return
} }
if h.sess.User != list.User.Username { if h.sess.User != list.User.Username {
h.sess.Notify("You are not the owner of the list!", "You can't remove books from it", "error") h.sess.Notify("You are not the owner of the list!", "You can't remove books from it", "danger")
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound) http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
return return
} }
@ -139,7 +139,7 @@ func listRemoveHandler(h handler) {
err = h.db.DeleteBookFromList(listID, bookID) err = h.db.DeleteBookFromList(listID, bookID)
if err != nil { if err != nil {
log.Error("Error remove book ", bookID, " from list ", listID, "): ", err) log.Error("Error remove book ", bookID, " from list ", listID, "): ", err)
h.sess.Notify("Something went wrong!", "Could not remove book", "error") h.sess.Notify("Something went wrong!", "Could not remove book", "danger")
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound) http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
return return
} }

View file

@ -43,7 +43,7 @@ func submissionCommentHandler(h handler) {
err := h.db.UpdateSubmissionComment(submissionID, bookID, comment) err := h.db.UpdateSubmissionComment(submissionID, bookID, comment)
if err != nil { if err != nil {
log.Error("Adding comment (submission: ", submissionID, ", book: ", bookID, ") <", comment, ">: ", err) log.Error("Adding comment (submission: ", submissionID, ", book: ", bookID, ") <", comment, ">: ", err)
h.sess.Notify("Error adding a comment!", "Can't add the comment rigt now. Try again later or report it to the site admins", "error") h.sess.Notify("Error adding a comment!", "Can't add the comment rigt now. Try again later or report it to the site admins", "danger")
} else { } else {
h.sess.Notify("Comment added!", "", "success") h.sess.Notify("Comment added!", "", "success")
} }
@ -131,17 +131,17 @@ func storeHandler(h handler) {
} }
book, err := h.db.GetBookID(id) book, err := h.db.GetBookID(id)
if err != nil { if err != nil {
h.sess.Notify("Book not found!", "The book with id '"+id+"' is not there", "error") h.sess.Notify("Book not found!", "The book with id '"+id+"' is not there", "danger")
continue continue
} }
if err != nil { if err != nil {
h.sess.Notify("An error ocurred!", err.Error(), "error") h.sess.Notify("An error ocurred!", err.Error(), "danger")
log.Error("Error getting book for storing '", book.Title, "': ", err.Error()) log.Error("Error getting book for storing '", book.Title, "': ", err.Error())
continue continue
} }
err = h.db.ActiveBook(id) err = h.db.ActiveBook(id)
if err != nil { if err != nil {
h.sess.Notify("An error ocurred!", err.Error(), "error") h.sess.Notify("An error ocurred!", err.Error(), "danger")
log.Error("Error storing book '", book.Title, "': ", err.Error()) log.Error("Error storing book '", book.Title, "': ", err.Error())
continue continue
} }

View file

@ -23,6 +23,7 @@ var tmpl_funcs = map[string]interface{}{
"strings_join": stringsJoin, "strings_join": stringsJoin,
"download_url": downloadUrl, "download_url": downloadUrl,
"size2mb": size2mb, "size2mb": size2mb,
"mul": mul,
} }
type Status struct { type Status struct {
@ -114,6 +115,10 @@ func size2mb(size int) float32 {
return float32(size) / (1024.0 * 1024.0) return float32(size) / (1024.0 * 1024.0)
} }
func mul(a, b int) int {
return a * b
}
type DevTemplateExecutor struct { type DevTemplateExecutor struct {
assetsPath string assetsPath string
tpe string tpe string

View file

@ -92,7 +92,7 @@ func uploadPostHandler(h handler) {
const _2M int64 = (1 << 20) * 2 const _2M int64 = (1 << 20) * 2
if h.ro { if h.ro {
h.sess.Notify("Upload failed!", "The library is in Read Only mode, no books can be uploaded", "error") h.sess.Notify("Upload failed!", "The library is in Read Only mode, no books can be uploaded", "danger")
uploadHandler(h) uploadHandler(h)
return return
} }
@ -109,13 +109,13 @@ func uploadPostHandler(h handler) {
submission := database.Submission{ submission := database.Submission{
SubmissionID: submissionID, SubmissionID: submissionID,
Filename: f.Filename, Filename: f.Filename,
Status: "Waiting to be processed", Status: "Waiting to be processed, reload the page in few minutes",
} }
file, err := f.Open() file, err := f.Open()
if err != nil { if err != nil {
log.Error("Can not open uploaded file ", f.Filename, ": ", err) log.Error("Can not open uploaded file ", f.Filename, ": ", err)
h.sess.Notify("Upload problem!", "There was a problem with book "+f.Filename, "error") h.sess.Notify("Upload problem!", "There was a problem with book "+f.Filename, "danger")
submission.Status = "It was not possible to read the book" submission.Status = "It was not possible to read the book"
h.db.AddSubmission(submission, h.sess.User) h.db.AddSubmission(submission, h.sess.User)
continue continue

View file

@ -30,7 +30,7 @@ func loginPostHandler(h handler) {
h.sess.Notify("Successful login!", "Welcome "+user, "success") h.sess.Notify("Successful login!", "Welcome "+user, "success")
} else { } else {
log.Warn("User ", user, " bad user or password") log.Warn("User ", user, " bad user or password")
h.sess.Notify("Invalid login!", "user or password invalid", "error") h.sess.Notify("Invalid login!", "user or password invalid", "danger")
} }
h.sess.Save(h.w, h.r) h.sess.Save(h.w, h.r)
http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound) http.Redirect(h.w, h.r, h.r.Referer(), http.StatusFound)
@ -40,16 +40,16 @@ func createUserHandler(h handler) {
pass := h.r.FormValue("pass") pass := h.r.FormValue("pass")
confirmPass := h.r.FormValue("confirmPass") confirmPass := h.r.FormValue("confirmPass")
if pass != confirmPass { if pass != confirmPass {
h.sess.Notify("Registration error!", "Passwords don't match", "error") h.sess.Notify("Registration error!", "Passwords don't match", "danger")
} else if pass == "" { } else if pass == "" {
h.sess.Notify("Registration error!", "The password can't be empty", "error") h.sess.Notify("Registration error!", "The password can't be empty", "danger")
} else { } else {
user := strings.TrimSpace(h.r.FormValue("user")) user := strings.TrimSpace(h.r.FormValue("user"))
err := h.db.AddUser(user, pass) err := h.db.AddUser(user, pass)
if err == nil { if err == nil {
h.sess.Notify("Account created!", "Welcome "+user+". Now you can login", "success") h.sess.Notify("Account created!", "Welcome "+user+". Now you can login", "success")
} else { } else {
h.sess.Notify("Registration error!", err.Error(), "error") h.sess.Notify("Registration error!", err.Error(), "danger")
} }
} }
h.sess.Save(h.w, h.r) h.sess.Save(h.w, h.r)
@ -91,14 +91,14 @@ func settingsHandler(h handler) {
pass2 := h.r.FormValue("password2") pass2 := h.r.FormValue("password2")
switch { switch {
case !h.db.ValidPassword(h.sess.User, current_pass): case !h.db.ValidPassword(h.sess.User, current_pass):
h.sess.Notify("Password error!", "The current password given don't match with the user password. Try again", "error") h.sess.Notify("Password error!", "The current password given don't match with the user password. Try again", "danger")
case pass1 != pass2: case pass1 != pass2:
h.sess.Notify("Passwords don't match!", "The new password and the confirmation password don't match. Try again", "error") h.sess.Notify("Passwords don't match!", "The new password and the confirmation password don't match. Try again", "danger")
default: default:
err := h.db.SetPassword(h.sess.User, pass1) err := h.db.SetPassword(h.sess.User, pass1)
if err != nil { if err != nil {
log.Warn("Can't update password for user ", h.sess.User, ": ", err) log.Warn("Can't update password for user ", h.sess.User, ": ", err)
h.sess.Notify("Password error!", "An error has ocurred updating the password in the database. Sorry.", "error") h.sess.Notify("Password error!", "An error has ocurred updating the password in the database. Sorry.", "danger")
} else { } else {
h.sess.Notify("Password updated!", "Your new password is correctly set.", "success") h.sess.Notify("Password updated!", "Your new password is correctly set.", "success")
} }
@ -167,14 +167,14 @@ func userAdminPostHandler(h handler) {
if password != "" { if password != "" {
err := h.db.SetPassword(username, password) err := h.db.SetPassword(username, password)
if err != nil { if err != nil {
h.sess.Notify("An error ocurred!", err.Error(), "error") h.sess.Notify("An error ocurred!", err.Error(), "danger")
} else { } else {
h.sess.Notify("Password updated!", "", "success") h.sess.Notify("Password updated!", "", "success")
} }
} else if role != "" { } else if role != "" {
err := h.db.SetRole(username, role) err := h.db.SetRole(username, role)
if err != nil { if err != nil {
h.sess.Notify("An error ocurred!", err.Error(), "error") h.sess.Notify("An error ocurred!", err.Error(), "danger")
} else { } else {
h.sess.Notify("Role updated!", "", "success") h.sess.Notify("Role updated!", "", "success")
} }
@ -194,11 +194,11 @@ func addUserHandler(h handler) {
role := h.r.FormValue("role") role := h.r.FormValue("role")
err := h.db.AddUser(username, password) err := h.db.AddUser(username, password)
if err != nil { if err != nil {
h.sess.Notify("An error ocurred!", err.Error(), "error") h.sess.Notify("An error ocurred!", err.Error(), "danger")
} else { } else {
err := h.db.SetRole(username, role) err := h.db.SetRole(username, role)
if err != nil { if err != nil {
h.sess.Notify("An error ocurred!", err.Error(), "error") h.sess.Notify("An error ocurred!", err.Error(), "danger")
} else { } else {
h.sess.Notify("User created!", "", "success") h.sess.Notify("User created!", "", "success")
} }

View file

@ -1,7 +1,7 @@
{{template "header.html" .S}} {{template "header.html" .S}}
<div class="row"> <div class="row justify-content-center">
<div class="span10 offset1"> <div class="col-sm-10">
<h4>Page not found</h4> <h4>Page not found</h4>
<p> <p>
The requested page don't exist. The requested page don't exist.

View file

@ -17,7 +17,7 @@
<h4>Donations</h4> <h4>Donations</h4>
<p>If you feel like donate some bitcoins we'll gladly accept them. You can request one bitcoin key for you or use our public bitcoin key:</p> <p>If you feel like donate some bitcoins we'll gladly accept them. You can request one bitcoin key for you or use our public bitcoin key:</p>
<p class="centered text-success">1JioYbSYDH4JQYbhF7tX2kGUVZc2vzvugx <br /> <p class="text-center text-success">1JioYbSYDH4JQYbhF7tX2kGUVZc2vzvugx <br />
<img src="/img/bitcoin.png" alt="1JioYbSYDH4JQYbhF7tX2kGUVZc2vzvugx" /> <img src="/img/bitcoin.png" alt="1JioYbSYDH4JQYbhF7tX2kGUVZc2vzvugx" />
</p> </p>

View file

@ -5,111 +5,165 @@
{{with .Book}} {{with .Book}}
<script> <script>
function delBook(){ function delBook(){
var div = document.getElementById('delete'); const div = document.getElementById('delete');
div.innerHTML = div.classList.remove("visually-hidden");
'<div class="alert alert-error fade in"> \ }
<a class="close" data-dismiss="alert">×</a> \ function closeAlert() {
<h4 class="alert-heading">Do you really want to delete it?</h4> \ const div = document.getElementById('delete');
<p>Remove a book is permanent, you won\'t be able to get it back</p> \ div.classList.add("visually-hidden");
<a class="btn btn-danger" href="/delete/{{.ID}}/">Remove it</a> \
<a class="btn" href="#" data-dismiss="alert">Cancel</a> \
</div>';
} }
</script> </script>
<div id="delete"></div> <div id="delete" class="alert alert-danger fade visually-hidden show" role="alert">
<div class="row">
<div class="col-11">
<h4 class="alert-heading">Do you really want to delete it?</h4>
<p>Remove a book is permanent, you won't be able to get it back</p>
<a class="btn btn-danger" href="/delete/{{.ID}}/">Remove it</a>
<a class="btn" href="#" onClick="closeAlert();">Cancel</a>
</div>
<div class="col-1 justify-content-end">
<button type="button" class="btn-close" onClick="closeAlert();"></button>
</div>
</div>
</div>
<header class="row"> <header class="row justify-content-end">
<div class="span8 offset4">
<h1>{{.Title}} <h1>{{.Title}}
{{if not .Active}} {{if not .Active}}
<span class="label label-warning">waiting for moderation</span> <span class="badge label-warning text-dark">waiting for moderation</span>
{{end}} {{end}}
</h1> </h1>
</div>
</header> </header>
<div class="row"> <div class="row">
{{if .Cover}} {{if .Cover}}
<div class="span4"> <div class="col-sm-4 text-center">
<img src="/cover/{{.ID}}/big/{{.Title}}.jpg" alt="{{.Title}}" class="pull-right" /> <img src="/cover/{{.ID}}/big/{{.Title}}.jpg" alt="{{.Title}}" class="float-sm-end img-fluid" />
</div> </div>
{{end}} {{end}}
<div class="span8"> <div class="col-sm-8">
<div class="row"><p></p></div> <div class="row">
<div class="row"> <div class="col-md-8">
<div class="span5"> <dl class="row">
<dl class="dl-horizontal"> {{if .Authors}}
{{if .Authors}}<dt>Authors</dt> <dd>{{range .Authors}}<a href="/search/?q=author:{{.}}">{{.}}</a>, {{end}}</dd>{{end}} <dt class="col-sm-3 text-sm-end">Authors</dt>
{{if .Publisher}}<dt>Publisher</dt> <dd><a href="/search/?q=publisher:{{.Publisher}}">{{.Publisher}}</a></dd>{{end}} <dd class="col-sm-9 text-start">{{range .Authors}}<a href="/search/?q=author:{{.}}">{{.}}</a>, {{end}}</dd>
{{if .Tags}}<dt>Tags</dt> <dd>{{range .Tags}}<a href="/search/?q=tag:{{.}}">{{.}}</a>, {{end}}</dd>{{end}} {{end}}
{{if .Isbn}}<dt>ISBN</dt> <dd>{{.Isbn}}</dd>{{end}} {{if .Publisher}}
{{if .Date}}<dt>Date</dt> <dd>{{.Date}}</dd>{{end}} <dt class="col-sm-3 text-sm-end">Publisher</dt>
{{if .FileSize}}<dt>Size</dt> <dd>{{printf "%.2f" (size2mb .FileSize)}} MB</dd>{{end}} <dd class="col-sm-9 text-start"><a href="/search/?q=publisher:{{.Publisher}}">{{.Publisher}}</a></dd>
{{if .Lang}}<dt>Lang</dt> <dd><a href="/search/?q=lang:{{.Lang}}">{{.Lang}}</a> </dd>{{end}} {{end}}
</dl> {{if .Tags}}
</div> <dt class="col-sm-3 text-sm-end">Tags</dt>
<div class="span3"> <dd class="col-sm-9 text-start">{{range .Tags}}<a href="/search/?q=tag:{{.}}">{{.}}</a>, {{end}}</dd>
<div class="row"> {{end}}
<div class="btn-group pull-right"> {{if .Isbn}}
<a href="{{download_url .}}" class="btn btn-large btn-inverse"><i class="icon-download-alt icon-white"></i> download</a> <dt class="col-sm-3 text-sm-end">ISBN</dt>
<a href="/read/{{.ID}}" class="btn btn-large btn-warning"><i class="icon-eye-open icon-white"></i> read it!</a> <dd class="col-sm-9 text-start">{{.Isbn}}</dd>
{{end}}
{{if .Date}}
<dt class="col-sm-3 text-sm-end">Date</dt>
<dd class="col-sm-9 text-start">{{.Date}}</dd>
{{end}}
{{if .FileSize}}
<dt class="col-sm-3 text-sm-end">Size</dt>
<dd class="col-sm-9 text-start">{{printf "%.2f" (size2mb .FileSize)}} MB</dd>
{{end}}
{{if .Lang}}
<dt class="col-sm-3 text-sm-end">Lang</dt>
<dd class="col-sm-9 text-start"><a href="/search/?q=lang:{{.Lang}}">{{.Lang}}</a> </dd>
{{end}}
</dl>
</div>
<div class="col-md-4">
<div class="btn-group d-flex justify-content-end">
<a href="{{download_url .}}" class="btn btn-dark btn-sm">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#file-earmark-arrow-down"/>
</svg>
download
</a>
<a href="/read/{{.ID}}" class="btn btn-warning btn-sm">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#eyeglasses"/>
</svg>
read it!
</a>
</div> </div>
<div class="pull-right"> <div class="text-end">
<small>Downloaded: {{$downloadCounter}} times</small> <small>Downloaded: {{$downloadCounter}} times</small>
</div> </div>
</div> {{if eq $role "admin" "moderator"}}
{{if eq $role "admin" "moderator"}} <div class="row"><p></p></div>
<div class="row"><p></p></div> <div class="btn-group d-flex justify-content-end">
<div class="row"> <a href="/edit/{{.ID}}" class="btn btn-primary btn-sm">
<div class="btn-group pull-right"> <svg class="bi" width="1em" height="1em" fill="currentColor">
<a href="/edit/{{.ID}}" class="btn btn-primary"><i class="icon-pencil"></i> Edit</a> <use xlink:href="/img/bootstrap-icons.svg#pencil"/>
<a href="#" onClick="delBook();" class="btn btn-danger"><i class="icon-trash"></i> Delete</a> </svg>
</div> edit
</div> </a>
{{end}} <a href="#" onClick="delBook();" class="btn btn-danger btn-sm">
</div> <svg class="bi" width="1em" height="1em" fill="currentColor">
</div> <use xlink:href="/img/bootstrap-icons.svg#trash"/>
</svg>
delete
</a>
</div>
{{end}}
</div>
</div>
{{end}} {{end}}
<div class="row"> <div class="row">
<div class="span8">
{{range .Description}} {{range .Description}}
<p>{{.}}</p> <p>{{.}}</p>
{{end}} {{end}}
</div> </div>
</div> </div>
</div>
</div> </div>
{{if .Lists}} {{if .Lists}}
<br /> <br />
<div class="row"> <div class="row justify-content-center">
<div class="span10 offset1"> <div class="col-10">
<h4>Book in lists:</h4> <h4>Book in lists:</h4>
<ul class="nav nav-tabs nav-stacked"> <ul class="nav flex-column">
{{range .Lists}} {{range .Lists}}
<li><a href="/list/{{.ListID}}">{{.Title}} ({{len .Books}}) <li class="nav-item">
<span class="pull-right">By {{.User.Username}}</span></a> <a class="nav-link" href="/list/{{.ListID}}">
</li> <div class="row">
{{end}} <div class="col">{{.Title}} ({{len .Books}})</div>
</ul> <div class="col text-end">By {{.User.Username}}</div>
</div> </div>
</a>
</li>
{{end}}
</ul>
</div>
</div> </div>
{{else}} {{else}}
<br /> <br />
{{end}} {{end}}
<br />
{{if .S.User}} {{if .S.User}}
<div class="row"> <form method="POST" action="/list/">
<h5 class="offset1 span2">Add book to a list:</h5> <div class="row g-3 align-items-start">
<form class="form-inline" method="POST" action="/list/"> <h6 class="col-sm-2 text-sm-end col-form-label">Add book to a list:</h6>
<input type="hidden" id="book_id" name="book_id" value="{{.Book.ID}}"> <input type="hidden" id="book_id" name="book_id" value="{{.Book.ID}}">
<div class="input-append"> <div class="col-sm-5">
<input type="text" data-provide="typeahead" data-source='["{{strings_join .UserLists}}"]' data-items="4" id="list" name="list" autocomplete="off"> <div class="input-group">
<button type="submit" class="btn btn-primary">Add</button> <input class="form-control" list="bookListOptions" id="list" name="list" placeholder="Write a name of a list to create or add">
<datalist id="bookListOptions">
{{range .UserLists}}
<option value="{{.}}">
{{end}}
</datalist>
<button type="submit" class="btn btn-primary">Add</button>
</div>
</div> </div>
</form> </div>
</div> </form>
{{end}} {{end}}
{{template "footer.html" .S}} {{template "footer.html" .S}}

View file

@ -1,25 +1,39 @@
{{range .}} {{range .}}
<div class="row"> <div class="card mb-3">
<div class="span1"> <div class="row g-0">
<p class="pull-right"><a href="/book/{{.ID}}" title="{{.Description}}">{{if .Cover}}<img class="img-rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" />{{end}}</a></p> <div class="col-md-1 d-flex align-items-center justify-content-center">
</div> <a href="/book/{{.ID}}" title="{{.Description}}">
<div class="span10 well"> {{if .Cover}}<img class="rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" />{{end}}
<div class="row"> </a>
<div class="span7">
<p>
<span class="muted">[{{if .Lang}}{{.Lang}}{{end}}]</span>
<a href="/book/{{.ID}}" title="{{.Description}}"><strong>{{.Title}}</strong></a>
<span class="muted">{{if .Publisher}}{{.Publisher}}{{end}}</span><br />
{{range .Authors}}{{.}}, {{end}}
</p>
</div>
<div class="span3">
<div class="btn-group pull-right">
<a href="{{download_url .}}" class="btn btn-inverse"><i class="icon-download-alt icon-white"></i> download</a>
<a href="/read/{{.ID}}" class="btn btn-warning"><i class="icon-eye-open icon-white"></i> read it!</a>
</div>
</div>
</div>
</div>
</div> </div>
<div class="col-md-11">
<div class="card-body">
<p class="card-title">
<span class="text-muted">[{{if .Lang}}{{.Lang}}{{end}}]</span>
<a href="/book/{{.ID}}" title="{{.Description}}"><strong>{{.Title}}</strong></a>
<span class="text-muted">{{if .Publisher}}{{.Publisher}}{{end}}</span>
</p>
<div class="card-text row">
<p class="col-9">{{range .Authors}}{{.}}, {{end}}</p>
<div class="col-3">
<div class="btn-group d-flex justify-content-end">
<a href="{{download_url .}}" class="btn btn-dark btn-sm">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#file-earmark-arrow-down"/>
</svg>
download
</a>
<a href="/read/{{.ID}}" class="btn btn-warning btn-sm">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#eyeglasses"/>
</svg>
read it!
</a>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
{{end}} {{end}}

View file

@ -2,35 +2,70 @@
<h4>Dashboard</h4> <h4>Dashboard</h4>
<div class="row"> <div class="row justify-content-center">
<div class="span8 offset2"> <div class="col-sm-8">
<ul class="nav nav-tabs nav-stacked"> <ul class="nav flex-column">
{{if eq .S.Role "admin" "moderator"}} {{if eq .S.Role "admin" "moderator"}}
<li><a href="/submission/moderate/"><i class="icon-book"></i> Moderate submissions</a></li> <li class="nav-item">
{{if eq .S.Role "admin"}} <a class="nav-link" href="/submission/moderate/">
<li><a href="/news/edit"><i class="icon-certificate"></i> Edit news</a></li> <svg class="bi" width="1em" height="1em" fill="currentColor">
{{end}} <use xlink:href="/img/bootstrap-icons.svg#journal-check"/>
<li class="divider"></li> </svg>
{{end}} Moderate submissions
<li><a href="/submission/"><i class="icon-folder-open"></i> Submissions</a></li> </a>
<li><a href="/settings/"><i class="icon-wrench"></i> Settings</a></li> </li>
<li class="divider"></li> {{if eq .S.Role "admin"}}
<li><a href="/logout/"><i class="icon-off"></i> Log Out</a></li> <li class="nav-item">
</ul> <a class="nav-link" href="/news/edit">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#newspaper"/>
</svg>
Edit news
</a>
</li>
{{end}}
{{end}}
<li class="nav-item">
<a class="nav-link" href="/submission/">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#journal-arrow-up"/>
</svg>
Submissions
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/settings/">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#gear"/>
</svg>
Settings
</a>
</li>
<li class="nav-item">
<a class="nav-link" href="/logout/">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#power"/>
</svg>
Log Out
</a>
</li>
</ul>
</div> </div>
</div> </div>
{{if .Lists}} {{if .Lists}}
<br /> <br />
<h4>My book lists</h4> <h4>My book lists</h4>
<div class="row"> <div class="row justify-content-center">
<div class="span8 offset2"> <div class="col-8">
<ul class="nav nav-tabs nav-stacked"> <ul class="nav flex-column">
{{range .Lists}} {{range .Lists}}
<li><a href="/list/{{.ListID}}">{{.Title}} ({{len .Books}})</a></li> <li class="nav-item">
{{end}} <a class="nav-link" href="/list/{{.ListID}}">{{.Title}} ({{len .Books}})</a>
</li>
{{end}}
</ul> </ul>
</div> </div>
</div> </div>
{{end}} {{end}}

View file

@ -1,90 +1,113 @@
{{template "header.html" .S}} {{template "header.html" .S}}
<!-- TODO: tokenfield -->
{{$submissionID := .SubmissionID}} {{$submissionID := .SubmissionID}}
{{with .Book}} {{with .Book}}
<div class="row"> <div class="row">
{{if .Cover}} {{if .Cover}}
<div class="span4"> <div class="d-none d-sm-block col-sm-4">
<img src="/cover/{{.ID}}/big/{{.Title}}.jpg" alt="{{.Title}}" class="pull-right" /> <img src="/cover/{{.ID}}/big/{{.Title}}.jpg" alt="{{.Title}}" class="img-fluid float-end" />
</div> </div>
{{end}} {{end}}
<div class="span8"> <div class="col-sm-8">
<form class="form-horizontal" method="POST" <form method="POST"
{{if $submissionID}} {{if $submissionID}}
action="/submission/{{$submissionID}}/save/{{.ID}}"> action="/submission/{{$submissionID}}/save/{{.ID}}">
{{else}} {{else}}
action="/save/{{.ID}}"> action="/save/{{.ID}}">
{{end}} {{end}}
<fieldset> <div class="row g-3 align-items-center">
<div class="control-group"> <div class="col-sm-2 text-sm-end">
<label class="control-label" for="title">Title</label> <label class="col-form-label" for="title">Title</label>
<div class="controls"> </div>
<input class="input-xlarge" type="text" id="title" value="{{.Title}}" name="title"> <div class="col-sm-10">
</div> <input class="form-control" type="text" id="title" value="{{.Title}}" name="title">
</div> </div>
</fieldset> </div>
<fieldset> <br />
<div class="control-group"> <div class="row g-3 align-items-center">
<label class="control-label" for="author">Author</label> <div class="col-sm-2 text-sm-end">
<div class="controls"> <label class="col-form-label" for="author">Author</label>
{{range .Authors}} </div>
<input class="input-xlarge" type="text" id="author" value="{{.}}" name="author"> <div class="col-sm-10">
{{end}} <div class="row">
<input class="input-xlarge" type="text" id="author" placeholder="Add author" name="author"> {{range .Authors}}
</div> <div class="col-sm-6">
</div> <input class="form-control" type="text" id="author" value="{{.}}" name="author">
<div class="control-group"> </div>
<label class="control-label" for="publisher">Publisher</label> {{end}}
<div class="controls"> <div class="col-sm-6">
<input class="input-xlarge" type="text" id="publisher" value="{{.Publisher}}" name="publisher"> <input class="form-control" type="text" id="author" placeholder="Add author" name="author">
</div> </div>
</div> </div>
<div class="control-group"> </div>
<label class="control-label" for="tags">Tags</label> </div>
<div class="controls"> <br />
<input class="input-xlarge" type="text" id="tags" value="{{range .Tags}}{{.}},{{end}}" name="tags" placeholder="Add tag and hit enter"> <div class="row g-3 align-items-center">
</div> <div class="col-sm-2 text-sm-end">
</div> <label class="col-form-label" for="publisher">Publisher</label>
<div class="control-group"> </div>
<label class="control-label" for="tags">ISBN</label> <div class="col-sm-10">
<div class="controls"> <input class="form-control" type="text" id="publisher" value="{{.Publisher}}" name="publisher">
<input class="input-xlarge" type="text" id="isbn" value="{{.Isbn}}" name="isbn"> </div>
</div> </div>
</div> <br />
<div class="control-group"> <div class="row g-3 align-items-center">
<label class="control-label" for="date">Date</label> <div class="col-sm-2 text-sm-end">
<div class="controls"> <label class="col-form-label" for="tags">Tags</label>
<input class="input-xlarge" type="text" id="date" value="{{.Date}}" name="date"> </div>
</div> <div class="col-sm-10">
</div> <input class="form-control" type="text" id="tags" value="{{range .Tags}}{{.}},{{end}}" name="tags" placeholder="Add tag and hit enter">
<div class="control-group"> </div>
<label class="control-label" for="lang">Lang</label> </div>
<div class="controls"> <br />
<input class="input-xlarge" type="text" id="langs" value="{{.Lang}}" name="lang"> <div class="row g-3 align-items-center">
</div> <div class="col-sm-2 text-sm-end">
</div> <label class="col-form-label" for="tags">ISBN</label>
</fieldset> </div>
<fieldset> <div class="col-sm-10">
<div class="control-group"> <input class="form-control" type="text" id="isbn" value="{{.Isbn}}" name="isbn">
<label class="control-label" for="description">Description</label> </div>
<div class="controls"> </div>
<textarea class="input-xlarge" id="description" rows="5" name="description">{{.Description}}</textarea> <br />
</div> <div class="row g-3 align-items-center">
</div> <div class="col-sm-2 text-sm-end">
<div class="form-actions"> <label class="col-form-label" for="date">Date</label>
<button type="submit" class="btn btn-primary">Save</button> </div>
<a href="/book/{{.ID}}" class="btn">Cancel</a> <div class="col-sm-10">
</div> <input class="form-control" type="text" id="date" value="{{.Date}}" name="date">
</fieldset> </div>
</div>
<br />
<div class="row g-3 align-items-center">
<div class="col-sm-2 text-sm-end">
<label class="col-form-label" for="lang">Lang</label>
</div>
<div class="col-sm-10">
<input class="form-control" type="text" id="langs" value="{{.Lang}}" name="lang">
</div>
</div>
<br />
<div class="row g-3 align-items-center">
<div class="col-sm-2 text-sm-end">
<label class="col-form-label" for="description">Description</label>
</div>
<div class="col-sm-10">
<textarea class="form-control" id="description" rows="5" name="description">{{.Description}}</textarea>
</div>
</div>
<br />
<div class="form-actions">
<button type="submit" class="btn btn-primary">Save</button>
<a href="/book/{{.ID}}" class="btn">Cancel</a>
</div>
</form> </form>
</div> </div>
</div> </div>
{{end}} {{end}}
<script src="/js/bootstrap-tokenfield.min.js"></script> <!-- TODO: tokenfield -->
<script>
$('#tags').tokenfield();
</script>
{{template "footer.html" .S}} {{template "footer.html" .S}}

View file

@ -2,8 +2,8 @@
<h4>Add News:</h4> <h4>Add News:</h4>
<form method="POST" action="/news/edit"> <form method="POST" action="/news/edit">
<textarea class="field span10" name="text" rows="3"></textarea> <br /> <textarea class="col-12" name="text" rows="3"></textarea> <br />
<button type="submit" class="btn">Add</button> <button type="submit" class="btn btn-primary">Add</button>
</form> </form>
{{template "footer.html" .S}} {{template "footer.html" .S}}

View file

@ -1,21 +1,24 @@
</div> <!-- container open in index.html --> </div> <!-- container open in index.html -->
<footer class="container footer"> </main>
<footer>
<div class="container">
<hr /> <hr />
<div class="row"> <div class="row">
<div class="span6"> <div class="col">
<p><small>Chief Librarian: Las Zenow &lt;zenow@riseup.net&gt;<br /> <p><small>Chief Librarian: Las Zenow &lt;zenow@riseup.net&gt;<br />
Fork the source code from <a href="https://gitlab.com/trantor">gitlab</a></small>.</p> Fork the source code from <a href="https://gitlab.com/trantor">gitlab</a></small>.</p>
</div> </div>
{{if not .IsOnion}} {{if not .IsOnion}}
<div class="span6"> <div class="col">
<p class="pull-right"><small>This is a mirror of the <a href="https://www.torproject.org/">Tor</a> onion service:<br /> <p class="d-flex justify-content-end"><small>This is a mirror of the <a href="https://www.torproject.org/">Tor</a> onion service:<br />
<a href="http://kx5thpx2olielkihfyo4jgjqfb7zx7wxr3sd4xzt26ochei4m6f7tayd.onion/">http://kx5thpx2olielkihfyo4jgjqfb7zx7wxr3sd4xzt26ochei4m6f7tayd.onion</a></small></p> <a href="http://kx5thpx2olielkihfyo4jgjqfb7zx7wxr3sd4xzt26ochei4m6f7tayd.onion/">http://kx5thpx2olielkihfyo4jgjqfb7zx7wxr3sd4xzt26ochei4m6f7tayd.onion</a></small></p>
</div> </div>
{{end}} {{end}}
</div> </div>
</div> <!-- container -->
</footer> </footer>
<!-- Placed at the end of the document so the pages load faster --> <!-- Placed at the end of the document so the pages load faster -->
<script src="/js/bootstrap.min.js"></script> <script src="/js/bootstrap.bundle.min.js"></script>
</body> </body>
</html> </html>

View file

@ -1,106 +1,155 @@
<!DOCTYPE HTML> <!DOCTYPE HTML>
<html lang="en"> <html lang="en">
<head> <head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<link href="/img/favicon.ico" rel="icon" type="image/x-icon" /> <link href="/img/favicon.ico" rel="icon" type="image/x-icon" />
<link href="/css/bootstrap.min.css" rel="stylesheet"> <link href="/css/bootstrap.min.css" rel="stylesheet">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link href="/css/bootstrap-responsive.min.css" rel="stylesheet">
<link href="/css/bootstrap-tokenfield.min.css" rel="stylesheet">
<link href="/css/custom.css" rel="stylesheet"> <link href="/css/custom.css" rel="stylesheet">
<link rel="alternate" type="application/rss+xml" title="{{.Title}}" href="/search/?fmt=rss&q={{.Search}}" /> <link rel="alternate" type="application/rss+xml" title="{{.Title}}" href="/search/?fmt=rss&q={{.Search}}" />
<title>{{.Title}}</title> <title>{{.Title}}</title>
<script src="/js/jquery.js"></script>
</head> </head>
<body> <body>
<header>
<!-- login screen --> <!-- login screen -->
<form class="form-horizontal modal hide" id="login" method="POST" action="/login/" enctype="application/x-www-form-urlencoded"> <div class="modal fade" id="loginModal" tabindex="-1" aria-labelledby="loginModalLabel" aria-hidden="true">
<div class="modal-header"> <div class="modal-dialog">
<a type="button" class="close" data-dismiss="modal">×</a> <div class="modal-content">
<h3>Log In</h3> <div class="modal-header">
<small><a href="/login/">Or create an account -></a></small> <h5 class="modal-title" id="loginModalLabel">Log In</h5>
</div> <button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
<div class="modal-body">
<fieldset>
<div class="control-group">
<div class="controls">
<div class="input-prepend">
<div class="add-on"><i class="icon-user"></i></div>
<input type="text" placeholder="Username" size="16" name="user" autofocus="autofocus">
</div> </div>
<div class="d-flex justify-content-end">
<small><a href="/login/">Or create an account -></a></small>&nbsp;
</div> </div>
</div> <form id="login" method="POST" action="/login/" enctype="application/x-www-form-urlencoded">
<div class="control-group"> <div class="modal-body">
<div class="controls"> <div class="input-group mb-3">
<div class="input-prepend"> <span class="input-group-text" id="user">
<div class="add-on"><i class="icon-lock"></i></div> <svg class="bi" width="1.5em" height="1.5em" fill="currentColor">
<input type="password" placeholder="Password" size="16" name="pass"> <use xlink:href="/img/bootstrap-icons.svg#person-fill"/>
</div> </svg>
</div> </span>
</div> <input type="text" class="form-control" placeholder="Username" name="user" autofocus="autofocus" aria-label="Username" aria-describedby="user">
</fieldset> </div>
</div> <div class="input-group mb-3">
<div class="modal-footer"> <span class="input-group-text" id="pass">
<fieldset> <svg class="bi" width="1.5em" height="1.5em" fill="currentColor">
<a href="#" class="btn" data-dismiss="modal">Cancel</a> <use xlink:href="/img/bootstrap-icons.svg#key-fill"/>
<input class="btn btn-primary" type="submit" name="submit" value="Log In"/> </svg>
</fieldset> </span>
</div> <input type="password" class="form-control" placeholder="Password" name="pass" aria-label="Password" aria-describedby="pass">
</form> </div>
</div>
<div class="modal-footer">
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
<input class="btn btn-primary" type="submit" name="submit" value="Log In"/>
</div>
</form>
</div> <!-- modal-content -->
</div> <!-- modal-dialog -->
</div> <!-- modal -->
<div class="navbar navbar-inverse"> <nav class="navbar navbar-expand-md navbar-dark bg-dark">
<div class="navbar-inner"> <div class="container-fluid">
<div class="container"> <a class="navbar-brand" href="/">Imperial Library</a>
<a class="brand" href="/">Imperial Library</a> <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<div class="nav-collapse"> <span class="navbar-toggler-icon"></span>
<ul class="nav"> </button>
<li {{if .Home}}class="active"{{end}}><a href="/">Home</a></li> <div class="collapse navbar-collapse" id="navbarSupportedContent">
<li {{if .About}}class="active"{{end}}><a href="/about/">About</a></li> <ul class="navbar-nav me-auto">
<li {{if .News}}class="active"{{end}}><a href="/news/">News</a></li> <li class="nav-item"><a class="nav-link {{if .Home}}active{{end}}" href="/">Home</a></li>
<li {{if .Upload}}class="active"{{end}}><a href="/upload/">Upload</a></li> <li class="nav-item"><a class="nav-link {{if .About}}active{{end}}" href="/about/">About</a></li>
<li><a href="/forum/">Forum</a></li> <li class="nav-item"><a class="nav-link {{if .News}}active{{end}}" href="/news/">News</a></li>
</ul> <li class="nav-item"><a class="nav-link {{if .Upload}}active{{end}}" href="/upload/">Upload</a></li>
<li class="nav-item"><a class="nav-link" href="/forum/">Forum</a></li>
</ul>
<ul class="nav pull-right"> <ul class="navbar-nav justify-content-end">
<li class="divider-vertical"></li> <li class="nav-item"><a class="nav-link {{if .Help}}active{{end}}" href="/help/">Help</a></li>
{{if .User}} </ul>
<li class="dropdown"> <form class="d-flex" action="/search/">
<a href="/dashboard/" class="dropdown-toggle" data-toggle="dropdown"> <input type="search" class="form-control" name="q" {{if .Search}}value="{{.Search}}"{{else}}placeholder="Search"{{end}} />
<i class="icon-user icon-white"></i> {{.User}}<b class="caret"></b> </form>
</a> <ul class="navbar-nav">
<ul class="dropdown-menu"> {{if .User}}
<li><a href="/dashboard/"><i class="icon-tasks"></i> Dashboard</a></li> <li class="nav-item dropdown">
{{if eq .Role "admin" "moderator"}} <a class="nav-link dropdown-toggle" href="/dashboard/" id="navbarScrollingDropdown" role="button" data-bs-toggle="dropdown" aria-expanded="false">
<li><a href="/submission/moderate/"><i class="icon-book"></i> Moderate submissions</a></li> {{.User}}
{{if eq .Role "admin"}} </a>
<li><a href="/news/edit"><i class="icon-certificate"></i> Edit news</a></li> <ul class="dropdown-menu dropdown-menu-dark dropdown-menu-end" aria-labelledby="navbarScrollingDropdown">
<li><a href="/admin/users/"><i class="icon-user"></i> Users admin</a></li> <li><a href="/dashboard/" class="dropdown-item">
{{end}} <svg class="bi" width="1em" height="1em" fill="currentColor">
<li class="divider"></li> <use xlink:href="/img/bootstrap-icons.svg#card-list"/>
{{end}} </svg>
<li><a href="/submission/"><i class="icon-folder-open"></i> Submissions</a></li> Dashboard
<li><a href="/settings/"><i class="icon-wrench"></i> Settings</a></li> </a></li>
<li class="divider"></li> {{if eq .Role "admin" "moderator"}}
<li><a href="/logout/"><i class="icon-off"></i> Log Out</a></li> <li><a href="/submission/moderate/" class="dropdown-item">
</ul> <svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#journal-check"/>
</svg>
Moderate submissions
</a></li>
{{if eq .Role "admin"}}
<li><a href="/news/edit" class="dropdown-item">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#newspaper"/>
</svg>
Edit news
</a></li>
<li><a href="/admin/users/" class="dropdown-item">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#people"/>
</svg>
Users admin
</a></li>
{{end}}
<li><hr class="dropdown-divider"></li>
{{end}}
<li><a href="/submission/" class="dropdown-item">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#journal-arrow-up"/>
</svg>
Submissions
</a></li>
<li><a href="/settings/" class="dropdown-item">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#gear"/>
</svg>
Settings
</a></li>
<li><hr class="dropdown-divider"></li>
<li><a href="/logout/" class="dropdown-item">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#power"/>
</svg>
Log Out
</a></li>
</ul>
</li>
{{else}}
<li class="nav-item">
<a class="nav-link" data-toggle="modal" href="/login/#login" data-bs-toggle="modal" data-bs-target="#loginModal">
<small>Login/SignUp</small>
</a>
</li> </li>
{{else}} {{end}}
<li><a data-toggle="modal" href="/login/#login"><i class="icon-user icon-white"></i> <small>Login/SignUp</small></a></li> </ul>
{{end}} </div><!--/.nav-collapse -->
</ul> </div><!--/.nav-container-fluid-->
</div><!--/.nav-collapse --> </nav>
<form class="navbar-search pull-right" action="/search/"> </header>
<input type="search" class="search-query span3" name="q" {{if .Search}}value="{{.Search}}"{{else}}placeholder="Search"{{end}} />
</form> <main>
<ul class="nav pull-right"> <div class="container">
<li {{if .Help}}class="active"{{end}}><a href="/help/">Help</a></li> <br />
</ul>
</div>
</div>
</div>
<div class="container">
{{range .Notif}} {{range .Notif}}
<div class="alert alert-{{.Type}}"> <div class="alert alert-{{.Type}} alert-dismissible fade show" role="alert">
<button class="close" data-dismiss="alert">×</button> <strong>{{.Title}}</strong> {{.Msg}}
<strong>{{.Title}}</strong> {{.Msg}} <button type="button" class="btn-close" data-bs-dismiss="alert" aria-label="Close"></button>
</div> </div>
{{end}} {{end}}

View file

@ -1,80 +1,43 @@
{{template "header.html" .S}} {{template "header.html" .S}}
{{range .News}} {{range .News}}
<div class="row"> <div class="row justify-content-center">
<div class="offset2 span8 alert alert-info"> <div class="col-sm-10 alert alert-info">
<a href="/news/"><strong>News!</strong></a> {{.Text}} <a href="/news/"><strong>News!</strong></a> {{.Text}}
</div> </div>
</div> </div>
{{end}} {{end}}
<div class="row"> <div class="row">
<p class="centered">There are {{.Count}} books on the library.</p> <p class="text-center">There are {{.Count}} books on the library.</p>
</div> </div>
<div class="row"> <div class="row">
<h4>Last books added: <div class="col">
<span class="pull-right"> <h4>Last books added:</h4>
<small>(<a href="/search/?q=">more</a>)</small> </div>
<a href="/search/?fmt=rss&q="><img src="/img/feed.png"/></a> <div class="col text-end title">
</span> <small>(<a href="/search/?q=">more</a>)</small>
</h4> <a href="/search/?fmt=rss&q="><img src="/img/feed.png"/></a>
</div>
</div> </div>
<ul class="row thumbnails"> <div class="row">
{{with .Books}} {{with .Books}}
{{range .}} {{range .}}
<li class="span2"> <div class="col-sm-2">
<div class="thumbnail centered" style="border:none;"> <div class="thumbnail text-center" style="border:none;">
<a href="/book/{{.ID}}" title="{{.Description}}"> <a href="/book/{{.ID}}" title="{{.Description}}">
{{if .Cover}}<div class="down"><img class="img-rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" /></div>{{end}} {{if .Cover}}<div class="down"><img class="rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" /></div>{{end}}
<p><strong>{{.Title}}</strong></p> <p><strong>{{.Title}}</strong></p>
</a> </a>
</div> </div>
</li> </div>
{{end}} {{end}}
{{end}} {{end}}
</ul>
<!--
<div class="row">
<h4>Most visited books:</h4>
</div> </div>
<ul class="row thumbnails">
{{with .VisitedBooks}}
{{range .}}
<li class="span2">
<div class="thumbnail centered" style="border:none;">
<a href="/book/{{.ID}}" title="{{.Description}}">
{{if .Cover}}<div class="down"><img class="img-rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" /></div>{{end}}
<p><strong>{{.Title}}</strong></p>
</a>
</div>
</li>
{{end}}
{{end}}
</ul>
<div class="row"> <div class="row">
<h4>Most downloaded books:</h4> <p class="text-center">{{range .Tags}}<a class="badge bg-secondary" href="/search/?q=tag:{{.}}">{{.}}</a> {{end}}</p>
</div>
<ul class="row thumbnails">
{{with .DownloadedBooks}}
{{range .}}
<li class="span2">
<div class="thumbnail centered" style="border:none;">
<a href="/book/{{.ID}}" title="{{.Description}}">
{{if .Cover}}<div class="down"><img class="img-rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" /></div>{{end}}
<p><strong>{{.Title}}</strong></p>
</a>
</div>
</li>
{{end}}
{{end}}
</ul>
-->
<div class="row">
<p class="centered">{{range .Tags}}<a class="label" href="/search/?q=tag:{{.}}">{{.}}</a> {{end}}</p>
</div> </div>
{{template "footer.html" .S}} {{template "footer.html" .S}}

View file

@ -1,11 +1,16 @@
{{template "header.html" .S}} {{template "header.html" .S}}
<div class="row"> <div class="row">
<h4 class="span10">{{.List.Title}} <a href="/list/{{.List.ListID}}?fmt=rss"><img src="/img/feed.png"/></a></h4> <h4 class="col-sm-10">{{.List.Title}} <a href="/list/{{.List.ListID}}?fmt=rss"><img src="/img/feed.png"/></a></h4>
<p class="span2 pull-right"> <p class="col-sm-2 text-end">
{{if eq .S.User .List.User.Username}} {{if eq .S.User .List.User.Username}}
<a href="/list/{{.List.ListID}}/edit" class="btn btn-primary"><i class="icon-pencil"></i> Edit</a> <a href="/list/{{.List.ListID}}/edit" class="btn btn-primary">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#pencil"/>
</svg>
Edit
</a>
{{else}} {{else}}
By {{.List.User.Username}} By {{.List.User.Username}}
{{end}} {{end}}

View file

@ -1,54 +1,56 @@
{{template "header.html" .S}} {{template "header.html" .S}}
{{with .List}} {{with .List}}
<form class="form-horizontal" method="POST" action="/list/{{.ListID}}"> <form method="POST" action="/list/{{.ListID}}">
<fieldset> <div class="mb-3">
<div class="control-group"> <label class="form-label" for="title">Title</label>
<label class="control-label" for="title">Title</label> <input class="form-control" type="text" id="title" value="{{.Title}}" name="title">
<div class="controls">
<input class="input-xlarge" type="text" id="title" value="{{.Title}}" name="title">
</div>
</div> </div>
</fieldset> <div class="mb-3">
<fieldset> <label class="form-label" for="description">Description</label>
<div class="control-group"> <textarea class="form-control" id="description" rows="5" name="description">{{range .Description}}{{.}}{{end}}</textarea>
<label class="control-label" for="description">Description</label>
<div class="controls">
<textarea class="input-xlarge" id="description" rows="5" name="description">{{range .Description}}{{.}}
{{end}}</textarea>
</div>
</div> </div>
<div class="form-actions"> <div class="text-end">
<button type="submit" class="btn btn-primary">Save</button> <button type="submit" class="btn btn-primary">Save</button>
<a href="/list/{{.ListID}}" class="btn">Cancel</a> <a href="/list/{{.ListID}}" class="btn btn-secondary">Cancel</a>
</div> </div>
</fieldset>
</form> </form>
{{end}} {{end}}
<br />
{{$listID := .List.ListID}} {{$listID := .List.ListID}}
{{range .List.Books}} {{range .List.Books}}
<div class="row"> <div class="card mb-3">
<div class="span1"> <div class="row g-0">
<p class="pull-right"><a href="/book/{{.ID}}">{{if .Cover}}<img class="img-rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" />{{end}}</a></p> <div class="col-md-1 d-flex align-items-center justify-content-center">
</div> <a href="/book/{{.ID}}" title="{{.Description}}">
<div class="span10 well"> {{if .Cover}}<img class="rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" />{{end}}
<div class="row"> </a>
<div class="span7">
<p>
<span class="muted">[{{if .Lang}}{{.Lang}}{{end}}]</span>
<a href="/book/{{.ID}}"><strong>{{.Title}}</strong></a>
<span class="muted">{{if .Publisher}}{{.Publisher}}{{end}}</span><br />
{{range .Authors}}{{.}}, {{end}}
</p>
</div>
<div class="span3">
<div class="pull-right">
<a href="/list/{{$listID}}/remove/{{.ID}}" class="btn btn-danger"><i class="icon-remove"></i> remove</a>
</div>
</div>
</div> </div>
<div class="col-md-11">
<div class="card-body">
<p class="card-title">
<span class="text-muted">[{{if .Lang}}{{.Lang}}{{end}}]</span>
<a href="/book/{{.ID}}" title="{{.Description}}"><strong>{{.Title}}</strong></a>
<span class="text-muted">{{if .Publisher}}{{.Publisher}}{{end}}</span>
</p>
<div class="card-text row">
<p class="col-9">{{range .Authors}}{{.}}, {{end}}</p>
<div class="col-3">
<div class="btn-group d-flex justify-content-end">
<a href="/list/{{$listID}}/remove/{{.ID}}" class="btn btn-danger">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#trash"/>
</svg>
remove
</a>
</div>
</div>
</div>
</div>
</div> </div>
</div>
</div> </div>
{{end}} {{end}}

View file

@ -21,46 +21,67 @@ function checkPasswordMatch() {
} }
</script> </script>
<div class="offset1 span4"> <div class="row justify-content-center">
<div class="col-sm-4">
<h3>Log In</h3> <h3>Log In</h3>
<form id="login" method="POST" action="/login/" enctype="application/x-www-form-urlencoded"> <form id="login" method="POST" action="/login/" enctype="application/x-www-form-urlencoded">
<div class="input-prepend"> <div class="input-group mb-3">
<div class="add-on"><i class="icon-user"></i></div> <span class="input-group-text" id="user">
<input type="text" placeholder="Username" size="16" name="user" autofocus="autofocus"> <svg class="bi" width="1.5em" height="1.5em" fill="currentColor">
</div> <use xlink:href="/img/bootstrap-icons.svg#person-fill"/>
<div class="input-prepend"> </svg>
<div class="add-on"><i class="icon-lock"></i></div> </span>
<input type="password" placeholder="Password" size="16" name="pass"> <input type="text" class="form-control" placeholder="Username" name="user" autofocus="autofocus" aria-label="Username" aria-describedby="user">
</div> </div>
<input class="btn btn-primary" type="submit" name="submit" value="Log In"/> <div class="input-group mb-3">
<span class="input-group-text" id="pass">
<svg class="bi" width="1.5em" height="1.5em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#key-fill"/>
</svg>
</span>
<input type="password" class="form-control" placeholder="Password" name="pass" aria-label="Password" aria-describedby="pass">
</div>
<input class="btn btn-primary" type="submit" name="submit" value="Log In"/>
</form> </form>
</div> </div>
<div class="span2"> <div class="col-sm-2">
<br /> <br />
<br /> <br />
<h3 class="centered">Or</h3> <h3 class="centered">Or</h3>
<br />
<br />
</div> </div>
<div class="span4"> <div class="col-sm-4">
<h3>Create an Account</h3> <h3>Create an Account</h3>
<form id="login" method="POST" action="/create_user/" enctype="application/x-www-form-urlencoded"> <form id="login" method="POST" action="/create_user/" enctype="application/x-www-form-urlencoded">
<div class="input-prepend"> <div class="input-group mb-3">
<div class="add-on"><i class="icon-user"></i></div> <span class="input-group-text" id="user">
<input type="text" placeholder="Username" size="16" name="user"> <svg class="bi" width="1.5em" height="1.5em" fill="currentColor">
</div> <use xlink:href="/img/bootstrap-icons.svg#person-fill"/>
<div class="input-prepend"> </svg>
<div class="add-on"><i class="icon-lock"></i></div> </span>
<input type="password" placeholder="Password" size="16" name="pass" id="pass"> <input type="text" class="form-control" placeholder="Username" name="user" autofocus="autofocus" aria-label="Username" aria-describedby="user">
</div> </div>
<div class="control-group" id="passCheck"> <div class="input-group mb-3">
<div class="controls input-prepend"> <span class="input-group-text" id="pass">
<div class="add-on"><i class="icon-lock"></i></div> <svg class="bi" width="1.5em" height="1.5em" fill="currentColor">
<input type="password" placeholder="Confirm password" size="16" name="confirmPass" id="confirmPass"> <use xlink:href="/img/bootstrap-icons.svg#key-fill"/>
</div> </svg>
<span id="passCheckHelp" class="help-inline"></span> </span>
</div> <input type="password" class="form-control" placeholder="Password" name="pass" aria-label="Password" aria-describedby="pass" id="pass">
<input class="btn btn-primary" type="submit" name="submit" value="Create"/> </div>
<div class="input-group mb-3">
<span class="input-group-text" id="pass">
<svg class="bi" width="1.5em" height="1.5em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#key-fill"/>
</svg>
</span>
<input type="password" class="form-control" placeholder="Confirm password" name="confirmPass" aria-label="Password" aria-describedby="confirmPass" id="confirmPass">
</div>
<input class="btn btn-primary" type="submit" name="submit" value="Create" />
</form> </form>
</div> </div>
</div>
{{template "footer.html" .S}} {{template "footer.html" .S}}

View file

@ -1,15 +1,16 @@
{{template "header.html" .S}} {{template "header.html" .S}}
<h4>News: <div class="row">
<a href="/news/?fmt=rss" class="pull-right"><img src="/img/feed.png"/></a> <h4 class="col">News:</h4>
</h4> <a href="/news/?fmt=rss" class="col text-end"><img src="/img/feed.png"/></a>
<dl class="dl-horizontal">
{{range .News}}
<div class="well well-small">
<dt>{{.Date}}</dt>
<dd>{{.Text}}</dd>
</div> </div>
<dl>
{{range .News}}
<div class="row">
<dt class="col-sm-2 text-sm-end">{{.Date}}</dt>
<dd class="col-sm-10">{{.Text}}</dd>
</div>
{{end}} {{end}}
</dl> </dl>

View file

@ -3,68 +3,80 @@
<div class="row"> <div class="row">
<div class="span4">
{{range .Chapters}}
{{range .In}}
<ul id="bookMenu" class="nav nav-list hidden-phone">
{{end}}
<li {{if .Active}}class="active"{{end}}><a href="{{.Link}}">{{.Label}}</a></li>
{{range .Out}}
</ul>
{{end}}
{{end}}
{{if .Chapters}}
</ul>
{{end}}
</div>
<div class="span8">
<script type="text/javascript"> {{if .Chapters}}
function resizeIframe() { <div class="col-md-4">
var contentHeight = $("#bookContent").contents().find("html").height(); <nav id="index" class="navbar navbar-expand-md navbar-light bg-light flex-column">
$("#bookContent").height(ContentHeight); <div class="row">
} <div class="col d-flex justify-content-start">
</script> <a class="navbar-brand" href="#">Index</a>
</div>
<div class="d-block d-md-none col d-flex justify-content-end">
<button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#indexContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation">
<span class="navbar-toggler-icon"></span>
</button>
</div>
</div>
<div class="collapse navbar-collapse" id="indexContent">
{{range .Chapters}}
{{range .In}}
<nav class="nav nav-pills flex-column">
{{end}}
<a class="nav-link ms-{{mul 2 .Depth}}{{if .Active}} active{{end}}" href="{{.Link}}">{{.Label}}</a>
{{range .Out}}
</nav>
{{end}}
{{end}}
</div>
</nav>
</div>
{{end}}
<ul class="pager"> <div class="col">
{{if .Prev}} <script type="text/javascript">
<li class="previous"> function resizeIframe() {
<a href="{{.Prev}}">&larr; Prev</a> var contentHeight = $("#bookContent").contents().find("html").height();
</li> $("#bookContent").height(ContentHeight);
{{end}} }
{{if .Book.Active}} </script>
<li class="">
<a href="{{.Back}}">Back</a> {{if not .Book.Active}}
</li> <div class="text-center">
{{else}} <p class="badge bg-warning">waiting for moderation</p>
<span class="label label-warning">waiting for moderation</span> </div>
{{end}} {{end}}
{{if .Next}} <nav class="d-flex justify-content-center" arial-label="Book navigation">
<li class="next"> <ul class="pagination">
<a href="{{.Next}}">Next &rarr;</a> <li class="page-item {{if not .Prev}}disabled{{end}}">
</li> <a class="page-link" href="{{.Prev}}">&larr; Prev</a>
{{end}} </li>
</ul> <li class="page-item">
<a class="page-link" href="{{.Back}}">Back</a>
<iframe id="bookContent" onload="resizeIframe();" style="width: 100%; height: 1080px; border: 0;" scrolling="auto" src="{{.Content}}" seamless="seamless" sandbox="allow-same-origin" frameborder=0></iframe> </li>
<li class="page-item {{if not .Next}}disabled{{end}}">
<ul class="pager"> <a class="page-link" href="{{.Next}}">Next &rarr;</a>
{{if .Prev}} </li>
<li class="previous"> </ul>
<a href="{{.Prev}}">&larr; Prev</a> </nav>
</li>
{{end}} <iframe id="bookContent" onload="resizeIframe();" style="width: 100%; height: 1080px; border: 0;" scrolling="auto" src="{{.Content}}" seamless="seamless" sandbox="allow-same-origin" frameborder=0></iframe>
<li class="">
<a href="{{.Back}}">Back</a> <nav class="d-flex justify-content-center" arial-label="Book navigation">
</li> <ul class="pagination">
{{if .Next}} <li class="page-item {{if not .Prev}}disabled{{end}}">
<li class="next"> <a class="page-link" href="{{.Prev}}">&larr; Prev</a>
<a href="{{.Next}}">Next &rarr;</a> </li>
</li> <li class="page-item">
{{end}} <a class="page-link" href="{{.Back}}">Back</a>
</ul> </li>
<li class="page-item {{if not .Next}}disabled{{end}}">
</div> <a class="page-link" href="{{.Next}}">Next &rarr;</a>
</li>
</ul>
</nav>
</div>
</div> </div>

View file

@ -1,45 +1,50 @@
{{template "header.html" .S}} {{template "header.html" .S}}
<ul class="pager"> <p class="text-center">Found {{.Found}} books <a href="{{.S.FullURL}}&fmt=rss"><img src="/img/feed.png"/></a> <br />
{{if .Prev}} <nav class="d-flex justify-content-center" arial-label="Book search page navigation">
<li class="previous"> <ul class="pagination">
<a href="{{.Prev}}">&larr; Prev</a> <li class="page-item {{if not .Prev}}disabled{{end}}">
</li> <a class="page-link" href="{{.Prev}}">&larr; Prev</a>
{{else}} </li>
<div class="span1"></div> <li class="page-item disabled">
{{end}} <a class="page-link" href="#">Page {{.Page}}</a>
<p class="centered span9">Found {{.Found}} books. Page {{.Page}} <a href="{{.S.FullURL}}&fmt=rss"><img src="/img/feed.png"/></a> <br /> </li>
{{if .Next}} <li class="page-item {{if not .Next}}disabled{{end}}">
<li class="next"> <a class="page-link" href="{{.Next}}">Next &rarr;</a>
<a href="{{.Next}}">Next &rarr;</a> </li>
</li> </ul>
{{end}} </nav>
</ul>
{{template "book_list.html" .Books}} {{template "book_list.html" .Books}}
<ul class="pager"> <nav class="d-flex justify-content-center" arial-label="Book search page navigation">
{{if .Prev}} <ul class="pagination">
<li class="previous"> <li class="page-item {{if not .Prev}}disabled{{end}}">
<a href="{{.Prev}}">&larr; Prev</a> <a class="page-link" href="{{.Prev}}">&larr; Prev</a>
</li> </li>
{{else}} <li class="page-item disabled">
<div class="span1"></div> <a class="page-link" href="#">Page {{.Page}}</a>
{{end}} </li>
<form class="form-inline span9 centered"> <li class="page-item {{if not .Next}}disabled{{end}}">
<label>Books per page: </label> <a class="page-link" href="{{.Next}}">Next &rarr;</a>
<div class="input-append" action="/search/"> </li>
<input class="span1" name="num" type="text" value="{{.ItemsPage}}" /> </ul>
<button type="submit" class="btn">Ok</button> </nav>
</div>
<input class="hidden span1" name="q" type="text" value="{{.S.Search}}" /> <form class="d-flex justify-content-center" action="/search/">
<div class="row g-3 align-items-center">
<div class="col-auto">
<label for="inputNum" class="col-form-label">Books per page: </label>
</div>
<div class="col-auto">
<input name="num" size="3" type="text" value="{{.ItemsPage}}" id="inputNum" class="form-control" />
</div>
<div class="col-auto">
<button type="submit" class="btn btn-primary">Ok</button>
</div>
</div>
<input name="q" type="hidden" value="{{.S.Search}}" />
</form> </form>
{{if .Next}}
<li class="next">
<a href="{{.Next}}">Next &rarr;</a>
</li>
{{end}}
</ul>
{{template "footer.html" .S}} {{template "footer.html" .S}}

View file

@ -1,51 +1,36 @@
{{template "header.html" .S}} {{template "header.html" .S}}
<script> <script>
$(document).ready(function () {
$("#passCheck").keyup(checkPasswordMatch);
});
function checkPasswordMatch() { function checkPasswordMatch() {
var password = $("#password1").val(); var password = document.forms["passwordChange"]["password1"].value;
var confirmPassword = $("#password2").val(); var confirmPassword = document.forms["passwordChange"]["password2"].value;
if (password != confirmPassword) { if (password != confirmPassword) {
$("#passCheck").removeClass("success"); document.getElementById("password2").classList.remove("is-valid");
$("#passCheck").addClass("error"); document.getElementById("password2").classList.add("is-invalid");
$("#passCheckHelp").html("Passwords don't match!");
} else { } else {
$("#passCheck").removeClass("error"); document.getElementById("password2").classList.remove("is-invalid");
$("#passCheck").addClass("success"); document.getElementById("password2").classList.add("is-valid");
$("#passCheckHelp").html("");
} }
} }
</script> </script>
<h2>Settings</h2> <h2>Settings</h2>
<form class="form-horizontal" method="POST" action="/settings/"> <form name="passwordChange" method="POST" action="/settings/">
<legend>Change your pasword</legend> <legend>Change your pasword</legend>
<div class="control-group"> <div class="mb-3">
<label class="control-label" for="currpass">Current password:</label> <label class="form-label" for="currpass">Current password:</label>
<div class="controls"> <input class="form-control" type="password" name="currpass" id="currpass" /><br />
<input type="password" name="currpass" id="currpass" /><br />
</div>
</div> </div>
<div class="control-group" id="passCheck"> <div class="mb-3">
<label class="control-label" for="password1">New password:</label> <label class="form-label" for="password1">New password:</label>
<div class="controls"> <input class="form-control" type="password" name="password1" id="password1" onchange="checkPasswordMatch()" />
<input type="password" name="password1" id="password1" /> <label class="form-label" for="password2">Confirm password:</label>
</div> <input class="form-control" type="password" name="password2" id="password2" onchange="checkPasswordMatch()" />
<label class="control-label" for="password2">Confirm password:</label> <div class="invalid-feedback">Passwords don't match!</div>
<div class="controls">
<input type="password" name="password2" id="password2" />
</div>
<div id="passCheckHelp" class="controls text-error"></div>
</div> </div>
<div class="control-group"> <button type="submit" class="btn btn-primary">Change password</button>
<div class="controls">
<button type="submit" class="btn">Change password</button>
</div>
</div> </div>
</form> </form>

View file

@ -5,6 +5,7 @@
<ul> <ul>
<li>Check if the book is already in the library, please remove the books that are already in the library in a better or similar edition/quality. You can click on the title or the authors to search for similar books in the library.</li> <li>Check if the book is already in the library, please remove the books that are already in the library in a better or similar edition/quality. You can click on the title or the authors to search for similar books in the library.</li>
<li>Edit if needed the title, authors, publisher, ...</li> <li>Edit if needed the title, authors, publisher, ...</li>
<li>Take into account that your submission might be waiting to process, reload this page in few minutes to see it already processed</li>
</ul> </ul>
<p>Thank you for your submission.</p> <p>Thank you for your submission.</p>
</div> </div>
@ -13,66 +14,97 @@
{{$submissionID := .SubmissionID}} {{$submissionID := .SubmissionID}}
{{range .Submissions}} {{range .Submissions}}
<div class="row"> <div class="row">
<div class="row"> <p>
<div class="span9"> <b>{{.Filename}}</b>
<p><b>{{.Filename}}</b> {{if not .Book}}
{{if not .Book}} <span class="badge bg-danger">
<span class="label label-important"> {{else if .Book.Active}}
{{else if .Book.Active}} <span class="badge bg-success">
<span class="label label-success"> {{else}}
{{else}} <span class="badge bg-warning">
<span class="label label-warning"> {{end}}
{{end}} {{.Status}}</span>
{{.Status}}</span></p> </p>
</div>
</div>
{{with .Book}}
{{if .}}
<div class="span1">
<p class="pull-right"><a href="/book/{{.ID}}">{{if .Cover}}<img class="img-rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" />{{end}}</a></p>
</div>
<div class="span10 well">
<div class="row">
<div class="span7">
<p>
<span class="muted">[{{if .Lang}}{{.Lang}}{{end}}]</span>
<a href="/search/?q=title:{{.Title}}"><strong>{{.Title}}</strong></a><br />
{{if .Authors}}<strong>Authors:</strong> {{range .Authors}}<a href="/search/?q=author:{{.}}">{{.}}</a>, {{end}}<br />{{end}}
{{if .Publisher}}<strong>Publisher:</strong> <a href="/search/?q=publisher:{{.Publisher}}">{{.Publisher}}</a><br />{{end}}
{{if .Tags}}<strong>Tags:</strong> {{range .Tags}}<a href="/search/?q=tag:{{.}}">{{.}}</a>, {{end}}<br />{{end}}
{{if .Isbn}}<strong>ISBN:</strong> {{.Isbn}}<br />{{end}}
{{if .Date}}<strong>Date:</strong> {{.Date}}<br />{{end}}
{{.Description}}
</p>
</div>
<div class="span3">
{{if and .ID (not .Active)}}
<div class="row btn-group pull-right">
{{if eq $role "admin" "moderator"}}
<a href="/store/{{.ID}}/" class="btn btn-success"><i class="icon-ok"></i> Save</a>
{{end}}
<a href="/submission/{{$submissionID}}/edit/{{.ID}}" class="btn btn-primary"><i class="icon-pencil"></i> Edit</a>
<a href="/submission/{{$submissionID}}/delete/{{.ID}}/" class="btn btn-danger"><i class="icon-remove"></i> Delete</a>
</div>
<div class="row"><p></p></div>
{{end}}
<div class="row btn-group pull-right">
<a href="{{download_url .}}" class="btn btn-inverse"><i class="icon-download-alt icon-white"></i> download</a>
<a href="/read/{{.ID}}" class="btn btn-warning"><i class="icon-eye-open icon-white"></i> read it!</a>
</div>
</div>
</div>
</div>
{{end}}
{{end}}
</div> </div>
{{if .Book}} {{$comment := .Comment}}
<form class="row form-inline" method="POST" action="/submission/{{$submissionID}}/comment/{{.Book.ID}}"> {{with .Book}}
<textarea class="span11" id="comment" rows="2" name="comment" placeholder="Comments about this book submission. Is it a better version than an existing one in the library?">{{.Comment}}</textarea> {{if .}}
<button type="submit" class="btn btn-primary">Send comment</button> <div class="card mb-3">
</form> <div class="row g-0">
<div class="col-md-1 d-flex align-items-center justify-content-center">
<a href="/book/{{.ID}}" title="{{.Description}}">
{{if .Cover}}<img class="rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" />{{end}}
</a>
</div>
<div class="col-md-11">
<div class="card-body">
<p class="card-title">
<a href="/search/?q=title:{{.Title}}"><strong>{{.Title}}</strong></a>
</p>
<div class="card-text row">
<p class="col-md-8">
{{if .Authors}}<strong>Authors:</strong> {{range .Authors}}<a href="/search/?q=author:{{.}}">{{.}}</a>, {{end}}<br />{{end}}
{{if .Publisher}}<strong>Publisher:</strong> <a href="/search/?q=publisher:{{.Publisher}}">{{.Publisher}}</a><br />{{end}}
{{if .Tags}}<strong>Tags:</strong> {{range .Tags}}<a href="/search/?q=tag:{{.}}">{{.}}</a>, {{end}}<br />{{end}}
{{if .Isbn}}<strong>ISBN:</strong> {{.Isbn}}<br />{{end}}
{{if .Date}}<strong>Date:</strong> {{.Date}}<br />{{end}}
{{if .Lang}}<strong>Lang:</strong> <a href="/search/?q=lang:{{.Lang}}">{{.Lang}}</a> <br />{{end}}
</p>
<div class="col-md-4">
{{if and .ID (not .Active)}}
<div class="btn-group d-flex justify-content-end">
{{if eq $role "admin" "moderator"}}
<a href="/store/{{.ID}}/" class="btn btn-success">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#check"/>
</svg>
save
</a>
{{end}}
<a href="/submission/{{$submissionID}}/edit/{{.ID}}" class="btn btn-primary">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#pencil"/>
</svg>
edit
</a>
<a href="/submission/{{$submissionID}}/delete/{{.ID}}/" class="btn btn-danger">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#trash"/>
</svg>
delete
</a>
</div>
{{end}}
<div class="btn-group d-flex justify-content-end">
<a href="{{download_url .}}" class="btn btn-dark btn-sm">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#file-earmark-arrow-down"/>
</svg>
download
</a>
<a href="/read/{{.ID}}" class="btn btn-warning btn-sm">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#eyeglasses"/>
</svg>
read it!
</a>
</div>
</div>
</div>
<p>{{.Description}}</p>
{{if not .Active}}
<form method="POST" action="/submission/{{$submissionID}}/comment/{{.ID}}">
<textarea class="form-control" id="comment" rows="2" name="comment" placeholder="Comments about this book submission. Is it a better version than an existing one in the library?">{{$comment}}</textarea>
<button type="submit" class="btn btn-primary">Update comment</button>
</form>
{{end}}
</div>
</div>
</div>
</div>
{{end}}
{{end}} {{end}}
{{end}} {{end}}

View file

@ -1,89 +1,153 @@
{{template "header.html" .S}} {{template "header.html" .S}}
<form class="centered" action="/submission/moderate/"> <form action="/submission/moderate/">
<input type="search" class="search-query span8" name="q" {{if .Search}}value="{{.Search}}"{{else}}placeholder="Search"{{end}} /> <div class="row justify-content-center">
<input type="search" class="col-sm-8" name="q" {{if .Search}}value="{{.Search}}"{{else}}placeholder="Search"{{end}} />
</div>
</form> </form>
<br />
{{if .Books}} {{if .Books}}
<div class="centered btn-group"> <div class="btn-group">
<a href="/store/{{range .Books}}{{.B.ID}}/{{end}}" class="btn btn-large btn-success"><i class="icon-ok"></i> Save All</a> <a href="/store/{{range .Books}}{{.B.ID}}/{{end}}" class="btn btn-lg btn-success">
<a href="/delete/{{range .Books}}{{.B.ID}}/{{end}}" class="btn btn-large btn-danger"><i class="icon-remove"></i> Delete All</a> <svg class="bi" width="1.5em" height="1.5em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#check-all"/>
</svg>
Save All
</a>
<a href="/delete/{{range .Books}}{{.B.ID}}/{{end}}" class="btn btn-lg btn-danger">
<svg class="bi" width="1.5em" height="1.5em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#trash-fill"/>
</svg>
Delete All
</a>
</div> </div>
{{end}} {{end}}
<p class="centered">Found {{.Found}} books.<br /></p>
<ul class="pager"> <p class="text-center">Found {{.Found}} books.<br /></p>
{{if .Prev}} <nav class="d-flex justify-content-center" arial-label="Book moderate page navigation">
<li class="previous"> <ul class="pagination">
<a href="{{.Prev}}">&larr; Prev</a> <li class="page-item {{if not .Prev}}disabled{{end}}">
</li> <a class="page-link" href="{{.Prev}}">&larr; Prev</a>
{{end}} </li>
{{if .Next}} <li class="page-item disabled">
<li class="next"> <a class="page-link" href="#">Page {{.Page}}</a>
<a href="{{.Next}}">Next &rarr;</a> </li>
</li> <li class="page-item {{if not .Next}}disabled{{end}}">
{{end}} <a class="page-link" href="{{.Next}}">Next &rarr;</a>
</ul> </li>
</ul>
</nav>
{{range .Books}} {{range .Books}}
{{$titleFound := .TitleFound}} {{$titleFound := .TitleFound}}
{{$authorFound := .AuthorFound}} {{$authorFound := .AuthorFound}}
{{with .B}} {{with .B}}
<div class="row"> <div class="card mb-3">
<div class="span1"> <div class="row g-0">
<p class="pull-right">{{if .Cover}}<img src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" />{{end}}</p> <div class="col-md-1 d-flex align-items-center justify-content-center">
</div> <a href="/book/{{.ID}}" title="{{.Description}}">
<div class="span9"> {{if .Cover}}<img class="rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" />{{end}}
<p><a href="/search/?q=title:{{.Title}}"><strong>{{.Title}}</strong></a> <!--<small>({{$titleFound}})</small>--><br /> </a>
{{if .Authors}}<strong>Authors:</strong> {{range .Authors}}<a href="/search/?q=author:{{.}}">{{.}}</a>, {{end}} <!--<small>({{$authorFound}})</small>--><br />{{end}}
{{if .Publisher}}<strong>Publisher:</strong> <a href="/search/?q=publisher:{{.Publisher}}">{{.Publisher}}</a><br />{{end}}
{{if .Tags}}<strong>Tags:</strong> {{range .Tags}}<a href="/search/?q=tag:{{.}}">{{.}}</a>, {{end}}<br />{{end}}
{{if .Isbn}}<strong>ISBN:</strong> {{.Isbn}}<br />{{end}}
{{if .Date}}<strong>Date:</strong> {{.Date}}<br />{{end}}
{{if .Lang}}<strong>Lang:</strong> <a href="/search/?q=lang:{{.Lang}}">{{.Lang}}</a> <br />{{end}}
{{.Description}}
</p>
</div>
<div class="span2">
<div class="row btn-group pull-right">
<a href="/store/{{.ID}}/" class="btn btn-success"><i class="icon-ok"></i> Save</a>
<a href="/edit/{{.ID}}" class="btn btn-primary"><i class="icon-pencil"></i> Edit</a>
<a href="/delete/{{.ID}}/" class="btn btn-danger"><i class="icon-remove"></i> Delete</a>
</div>
<div class="row"><p></p></div>
<div class="row btn-group pull-right">
<a href="{{download_url .}}" class="btn btn-inverse"><i class="icon-download-alt icon-white"></i> download</a>
<a href="/read/{{.ID}}" class="btn btn-warning"><i class="icon-eye-open icon-white"></i> read it!</a>
</div> </div>
<div class="col-md-11">
<div class="card-body">
<p class="card-title">
<a href="/search/?q=title:{{.Title}}"><strong>{{.Title}}</strong></a> <!--<small>({{$titleFound}})</small>-->
</p>
<div class="card-text row">
<p class="col-md-8">
{{if .Authors}}<strong>Authors:</strong> {{range .Authors}}<a href="/search/?q=author:{{.}}">{{.}}</a>, {{end}} <!--<small>({{$authorFound}})</small>--><br />{{end}}
{{if .Publisher}}<strong>Publisher:</strong> <a href="/search/?q=publisher:{{.Publisher}}">{{.Publisher}}</a><br />{{end}}
{{if .Tags}}<strong>Tags:</strong> {{range .Tags}}<a href="/search/?q=tag:{{.}}">{{.}}</a>, {{end}}<br />{{end}}
{{if .Isbn}}<strong>ISBN:</strong> {{.Isbn}}<br />{{end}}
{{if .Date}}<strong>Date:</strong> {{.Date}}<br />{{end}}
{{if .Lang}}<strong>Lang:</strong> <a href="/search/?q=lang:{{.Lang}}">{{.Lang}}</a> <br />{{end}}
</p>
<div class="col-md-4">
<div class="btn-group d-flex justify-content-end">
<a href="/store/{{.ID}}/" class="btn btn-success">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#check"/>
</svg>
save
</a>
<a href="/edit/{{.ID}}" class="btn btn-primary">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#pencil"/>
</svg>
edit
</a>
<a href="/delete/{{.ID}}/" class="btn btn-danger">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#trash"/>
</svg>
delete
</a>
</div>
<div class="btn-group d-flex justify-content-end">
<a href="{{download_url .}}" class="btn btn-dark btn-sm">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#file-earmark-arrow-down"/>
</svg>
download
</a>
<a href="/read/{{.ID}}" class="btn btn-warning btn-sm">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#eyeglasses"/>
</svg>
read it!
</a>
</div>
</div>
</div>
<p>{{.Description}}</p>
</div>
</div> </div>
</div>
</div> </div>
{{end}} {{end}}
{{if .Comment}} {{if .Comment}}
<div class="row"> <div class="row">
<div class="span1"> <div class="col-md-1">
<b>Comment:</b> <b>Comment:</b>
</div> </div>
<div class="span10 well"> <div class="col-md-11">
<p>{{.Comment}}</p> <p>{{.Comment}}</p>
</div> </div>
</div> </div>
<br />
{{end}} {{end}}
{{end}} {{end}}
<ul class="pager">
{{if .Prev}} <nav class="d-flex justify-content-center" arial-label="Book moderate page navigation">
<li class="previous"> <ul class="pagination">
<a href="{{.Prev}}">&larr; Prev</a> <li class="page-item {{if not .Prev}}disabled{{end}}">
</li> <a class="page-link" href="{{.Prev}}">&larr; Prev</a>
{{end}} </li>
{{if .Next}} <li class="page-item disabled">
<li class="next"> <a class="page-link" href="#">Page {{.Page}}</a>
<a href="{{.Next}}">Next &rarr;</a> </li>
</li> <li class="page-item {{if not .Next}}disabled{{end}}">
{{end}} <a class="page-link" href="{{.Next}}">Next &rarr;</a>
</ul> </li>
</ul>
</nav>
{{if .Books}} {{if .Books}}
<div class="centered btn-group"> <div class="btn-group">
<a href="/store/{{range .Books}}{{.B.ID}}/{{end}}" class="btn btn-large btn-success"><i class="icon-ok"></i> Save All</a> <a href="/store/{{range .Books}}{{.B.ID}}/{{end}}" class="btn btn-lg btn-success">
<a href="/delete/{{range .Books}}{{.B.ID}}/{{end}}" class="btn btn-large btn-danger"><i class="icon-remove"></i> Delete All</a> <svg class="bi" width="1.5em" height="1.5em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#check-all"/>
</svg>
Save All
</a>
<a href="/delete/{{range .Books}}{{.B.ID}}/{{end}}" class="btn btn-lg btn-danger">
<svg class="bi" width="1.5em" height="1.5em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#trash-fill"/>
</svg>
Delete All
</a>
</div> </div>
{{end}} {{end}}

View file

@ -7,70 +7,98 @@
{{$role := .S.Role}} {{$role := .S.Role}}
{{range .Submissions}} {{range .Submissions}}
<div class="row"> <div class="row">
<div class="row"> <p>
<div class="span9"> <b>{{.Filename}}</b>
<p><b>{{.Filename}}</b> {{if not .Book}}
{{if not .Book}} <span class="badge bg-danger">
<span class="label label-important"> {{else if .Book.Active}}
{{else if .Book.Active}} <span class="badge bg-success">
<span class="label label-success"> {{else}}
{{else}} <span class="badge bg-warning">
<span class="label label-warning"> {{end}}
{{end}} {{.Status}}</span>
{{.Status}}</span></p> </p>
</div>
<div class="span3">
<h6 class="pull-right"><a href="/submission/{{.SubmissionID}}">Submission {{.SubmissionID}}</a></h6>
</div>
</div>
{{$submissionID := .SubmissionID}}
{{with .Book}}
{{if .}}
<div class="span1">
<p class="pull-right"><a href="/book/{{.ID}}">{{if .Cover}}<img class="img-rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" />{{end}}</a></p>
</div>
<div class="span10 well">
<div class="row">
<div class="span7">
<p>
<span class="muted">[{{if .Lang}}{{.Lang}}{{end}}]</span>
<a href="/search/?q=title:{{.Title}}"><strong>{{.Title}}</strong></a><br />
{{if .Authors}}<strong>Authors:</strong> {{range .Authors}}<a href="/search/?q=author:{{.}}">{{.}}</a>, {{end}}<br />{{end}}
{{if .Publisher}}<strong>Publisher:</strong> <a href="/search/?q=publisher:{{.Publisher}}">{{.Publisher}}</a><br />{{end}}
{{if .Tags}}<strong>Tags:</strong> {{range .Tags}}<a href="/search/?q=tag:{{.}}">{{.}}</a>, {{end}}<br />{{end}}
{{if .Isbn}}<strong>ISBN:</strong> {{.Isbn}}<br />{{end}}
{{if .Date}}<strong>Date:</strong> {{.Date}}<br />{{end}}
{{.Description}}
</p>
</div>
<div class="span3">
{{if and .ID (not .Active)}}
<div class="row btn-group pull-right">
{{if eq $role "admin" "moderator"}}
<a href="/store/{{.ID}}/" class="btn btn-success"><i class="icon-ok"></i> Save</a>
{{end}}
<a href="/submission/{{$submissionID}}/edit/{{.ID}}" class="btn btn-primary"><i class="icon-pencil"></i> Edit</a>
<a href="/submission/{{$submissionID}}/delete/{{.ID}}/" class="btn btn-danger"><i class="icon-remove"></i> Delete</a>
</div>
<div class="row"><p></p></div>
{{end}}
<div class="row btn-group pull-right">
<a href="{{download_url .}}" class="btn btn-inverse"><i class="icon-download-alt icon-white"></i> download</a>
<a href="/read/{{.ID}}" class="btn btn-warning"><i class="icon-eye-open icon-white"></i> read it!</a>
</div>
</div>
</div>
</div>
{{end}}
{{end}}
</div> </div>
{{if .Book}} {{$comment := .Comment}}
<form class="row form-inline" method="POST" action="/submission/{{.SubmissionID}}/comment/{{.Book.ID}}"> {{$submissionID := .SubmissionID}}
<textarea class="span11" id="comment" rows="2" name="comment" placeholder="Comments about this book submission. Is it a better version than an existing one in the library?">{{.Comment}}</textarea> {{with .Book}}
<button type="submit" class="btn btn-primary">Send comment</button> {{if .}}
</form> <div class="card mb-3">
<div class="row g-0">
<div class="col-md-1 d-flex align-items-center justify-content-center">
<a href="/book/{{.ID}}" title="{{.Description}}">
{{if .Cover}}<img class="rounded" src="/cover/{{.ID}}/small/{{.Title}}.jpg" alt="{{.Title}}" />{{end}}
</a>
</div>
<div class="col-md-11">
<div class="card-body">
<p class="card-title">
<a href="/search/?q=title:{{.Title}}"><strong>{{.Title}}</strong></a>
</p>
<div class="card-text row">
<p class="col-md-8">
{{if .Authors}}<strong>Authors:</strong> {{range .Authors}}<a href="/search/?q=author:{{.}}">{{.}}</a>, {{end}}<br />{{end}}
{{if .Publisher}}<strong>Publisher:</strong> <a href="/search/?q=publisher:{{.Publisher}}">{{.Publisher}}</a><br />{{end}}
{{if .Tags}}<strong>Tags:</strong> {{range .Tags}}<a href="/search/?q=tag:{{.}}">{{.}}</a>, {{end}}<br />{{end}}
{{if .Isbn}}<strong>ISBN:</strong> {{.Isbn}}<br />{{end}}
{{if .Date}}<strong>Date:</strong> {{.Date}}<br />{{end}}
{{if .Lang}}<strong>Lang:</strong> <a href="/search/?q=lang:{{.Lang}}">{{.Lang}}</a> <br />{{end}}
</p>
<div class="col-md-4">
{{if and .ID (not .Active)}}
<div class="btn-group d-flex justify-content-end">
{{if eq $role "admin" "moderator"}}
<a href="/store/{{.ID}}/" class="btn btn-success">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#check"/>
</svg>
save
</a>
{{end}}
<a href="/submission/{{$submissionID}}/edit/{{.ID}}" class="btn btn-primary">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#pencil"/>
</svg>
edit
</a>
<a href="/submission/{{$submissionID}}/delete/{{.ID}}/" class="btn btn-danger">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#trash"/>
</svg>
delete
</a>
</div>
{{end}}
<div class="btn-group d-flex justify-content-end">
<a href="{{download_url .}}" class="btn btn-dark btn-sm">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#file-earmark-arrow-down"/>
</svg>
download
</a>
<a href="/read/{{.ID}}" class="btn btn-warning btn-sm">
<svg class="bi" width="1em" height="1em" fill="currentColor">
<use xlink:href="/img/bootstrap-icons.svg#eyeglasses"/>
</svg>
read it!
</a>
</div>
</div>
</div>
<p>{{.Description}}</p>
{{if not .Active}}
<form method="POST" action="/submission/{{$submissionID}}/comment/{{.ID}}">
<textarea class="form-control" id="comment" rows="2" name="comment" placeholder="Comments about this book submission. Is it a better version than an existing one in the library?">{{$comment}}</textarea>
<button type="submit" class="btn btn-primary">Update comment</button>
</form>
{{end}}
</div>
</div>
</div>
</div>
{{end}}
{{end}} {{end}}
{{end}} {{end}}

View file

@ -2,10 +2,14 @@
<p>Upload your epubs to help the library.</p> <p>Upload your epubs to help the library.</p>
<form class="well form-inline" method="POST" enctype="multipart/form-data"> <div class="row justify-content-center">
<input accept="application/epub+zip" type="file" name="epub" multiple="multiple" /> <form class="col-sm-11" method="POST" enctype="multipart/form-data">
<button type="submit" class="btn">Submit</button> <div class="input-group mb-3">
</form> <input accept="application/epub+zip" type="file" name="epub" multiple="multiple" />
<button type="submit" class="btn btn-outline-secondary">Upload</button>
</div>
</form>
</div>
<p>The uploaded books will be reviewed by the librarians and included if they comply our quality standards. Do not upload epubs converted from PDFs or any book that is not pleasant to read.</p> <p>The uploaded books will be reviewed by the librarians and included if they comply our quality standards. Do not upload epubs converted from PDFs or any book that is not pleasant to read.</p>

View file

@ -1,8 +1,33 @@
{{template "header.html" .S}} {{template "header.html" .S}}
<h4>Add user:</h4>
<form class="row" method="POST" action="/admin/users/add/">
<div class="col-6 col-md-3">
<label class="col-form-label" for="username">Username</label>
<input class="form-control" type="text" id="username" name="username">
</div>
<div class="col-6 col-md-3">
<label class="col-form-label" for="role">Role</label>
<input class="form-control" type="text" id="role" name="role" value="moderator">
</div>
<div class="col-6 col-md-3">
<label class="col-form-label" for="password">Password</label>
<input class="form-control" type="password" id="password" name="password">
</div>
<div class="col-6 col-md-3">
<br />
<button type="submit" class="btn btn-primary" id="submit">Create</button>
</div>
</form>
<br />
<h4>Users:</h4> <h4>Users:</h4>
<table class="table table-hover"> <div class="table-responsive-md">
<table class="table">
<thead> <thead>
<th>username</th> <th>username</th>
<th>role</th> <th>role</th>
@ -13,16 +38,24 @@
{{range .Users}} {{range .Users}}
<tr> <tr>
<td>{{.Username}}</td> <td>{{.Username}}</td>
<td><form class="row form-inline" method="POST" action="/admin/users/"> <td><form class="row" method="POST" action="/admin/users/">
<input type="hidden" id="username" name="username" value="{{.Username}}"> <input type="hidden" id="username" name="username" value="{{.Username}}">
<div class="col">
<input type="text" id="role" name="role" value="{{.Role}}"> <input type="text" id="role" name="role" value="{{.Role}}">
</div>
<div class="col">
<button type="submit" class="btn btn-primary">Update</button> <button type="submit" class="btn btn-primary">Update</button>
</div>
</form> </form>
</td> </td>
<td><form class="row form-inline" method="POST" action="/admin/users/"> <td><form class="row form-inline" method="POST" action="/admin/users/">
<input type="hidden" id="username" name="username" value="{{.Username}}"> <input type="hidden" id="username" name="username" value="{{.Username}}">
<input type="password" id="password" name="password" placeholder="password"> <div class="col">
<button type="submit" class="btn btn-primary">Update</button> <input type="password" id="password" name="password" placeholder="password">
</div>
<div class="col">
<button type="submit" class="btn btn-primary">Update</button>
</div>
</form> </form>
</td> </td>
<td>{{.LastLogin.Format "2006-01-02"}}</td> <td>{{.LastLogin.Format "2006-01-02"}}</td>
@ -30,33 +63,6 @@
{{end}} {{end}}
</tbody> </tbody>
</table> </table>
</div>
<h4>Add user:</h4>
<form class="form-horizontal" method="POST" action="/admin/users/add/">
<div class="control-group">
<label class="control-label" for="username">Username</label>
<div class="controls">
<input type="text" id="username" name="username">
</div>
</div>
<div class="control-group">
<label class="control-label" for="role">Role</label>
<div class="controls">
<input type="text" id="role" name="role" value="moderator">
</div>
</div>
<div class="control-group">
<label class="control-label" for="password">Password</label>
<div class="controls">
<input type="password" id="password" name="password">
</div>
</div>
<div class="form-actions">
<button type="submit" class="btn btn-primary">Submit</button>
</div>
</form>
{{template "footer.html" .S}} {{template "footer.html" .S}}