Skip to content

Commit

Permalink
Merge branch 'main' into kong
Browse files Browse the repository at this point in the history
  • Loading branch information
svera authored Jan 17, 2025
2 parents 71b1819 + da2ec98 commit 55e9c19
Show file tree
Hide file tree
Showing 18 changed files with 178 additions and 134 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

A personal documents server, Coreander indexes the documents (EPUBs and PDFs with no DRM) that it finds in the passed folder, and provides a web interface to search and access them.

![Coreander screenshot](screenshot.png)
![Coreander home](home.png)
*Coreander home*

## Features
* Single binary with all dependencies included.
Expand Down Expand Up @@ -138,3 +139,12 @@ In case both a flag and its equivalent environment variable are passed, flag tak
|`--recovery-timeout` |`RECOVERY_TIMEOUT` | Specifies the maximum time a user recovery link may last, in hours. Floating-point values are allowed. Defaults to 2 hours.
|`--upload-document-max-size` |`UPLOAD_DOCUMENT_MAX_SIZE`| Maximum document size allowed to be uploaded to the library, in megabytes. Set this to 0 to unlimit upload size. Defaults to 20 megabytes.
|`--fqdn` |`FQDN` | Domain name of the server. If Coreander is listening to a non-standard HTTP / HTTPS port, include it using a colon (e. g. example.com:3000). Defaults to `localhost`.

## Screenshots

![Search results](search-results.png)
*Search results*
![Document detail in dark mode](doc-detail.png)
*Document detail in dark mode*
![Reading interface](reading.png)
*Reading interface*
Binary file added doc-detail.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added home.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 2 additions & 2 deletions internal/index/bleve_read.go
Original file line number Diff line number Diff line change
Expand Up @@ -269,7 +269,7 @@ func (b *BleveIndexer) SameSubjects(slugID string, quantity int) ([]Document, er
typeQuery.SetField("Type")
bq.AddMust(typeQuery)

res := make([]Document, quantity)
res := make([]Document, 0, quantity)
for i := 0; i < quantity; i++ {
doc, err := b.runQuery(bq, 1)
if err != nil {
Expand All @@ -278,7 +278,7 @@ func (b *BleveIndexer) SameSubjects(slugID string, quantity int) ([]Document, er
if len(doc) == 0 {
return res, nil
}
res[i] = doc[0]
res = append(res, doc[0])
for _, slug := range doc[0].AuthorsSlugs {
qa := bleve.NewTermQuery(slug)
qa.SetField("AuthorsSlugs")
Expand Down
2 changes: 1 addition & 1 deletion internal/webserver/controller/user/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import (
func (u *Controller) Create(c *fiber.Ctx) error {
role, _ := strconv.Atoi(c.FormValue("role"))
user := model.User{
Name: c.FormValue("name"),
Name: strings.TrimSpace(c.FormValue("name")),
Username: strings.ToLower(c.FormValue("username")),
Email: c.FormValue("email"),
SendToEmail: c.FormValue("send-to-email"),
Expand Down
4 changes: 2 additions & 2 deletions internal/webserver/controller/user/update.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (u *Controller) Update(c *fiber.Ctx) error {
}

func (u *Controller) updateUserData(c *fiber.Ctx, user *model.User, session model.Session) error {
user.Name = c.FormValue("name")
user.Name = strings.TrimSpace(c.FormValue("name"))
user.Username = strings.ToLower(c.FormValue("username"))
user.Email = c.FormValue("email")
user.SendToEmail = c.FormValue("send-to-email")
Expand Down Expand Up @@ -120,7 +120,7 @@ func (u *Controller) validate(c *fiber.Ctx, user *model.User, session model.Sess
func (u *Controller) usernameExists(c *fiber.Ctx, session model.Session) (bool, error) {
user, err := u.repository.FindByUsername(c.FormValue("username"))
if err != nil {
return true, fiber.ErrInternalServerError
return true, err
}
if user != nil && (session.Role == model.RoleAdmin && user.Uuid == c.FormValue("id")) {
return false, nil
Expand Down
16 changes: 16 additions & 0 deletions internal/webserver/embedded/css/display.css
Original file line number Diff line number Diff line change
Expand Up @@ -121,3 +121,19 @@ a.collapse-control.collapsed:after {
.datetime::first-letter {
text-transform: capitalize;
}

.zoomable {
overflow: hidden;
}

.zoomable img {
transition: all .3s ease;
}

.zoomable img:hover {
transform: scale(1.1);
}

.zoomable + .card-img-overlay {
bottom: auto !important;
}
3 changes: 2 additions & 1 deletion internal/webserver/embedded/js/cover.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@
document.querySelectorAll(".cover").forEach(function(elem) {
elem.addEventListener("error", () => {
elem.onerror = null
const coverTitleId = elem.getAttribute("data-cover-title-id")
elem.parentNode.children[0].srcset = elem.src
elem.parentNode.parentNode.children[1].classList.remove('d-none')
document.getElementById(coverTitleId).classList.remove('d-none')
})
})
3 changes: 3 additions & 0 deletions internal/webserver/embedded/js/reader.js
Original file line number Diff line number Diff line change
Expand Up @@ -107,8 +107,11 @@ class Reader {
}
async open(file) {
this.view = document.createElement('foliate-view')
const storage = window.localStorage
const slug = document.getElementById('slug').value
document.body.append(this.view)
await this.view.open(file)
await this.view.init({lastLocation: storage.getItem(slug)})
this.view.addEventListener('load', this.#onLoad.bind(this))
this.view.addEventListener('relocate', this.#onRelocate.bind(this))

Expand Down
116 changes: 60 additions & 56 deletions internal/webserver/embedded/views/layout.html
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@

<body class="d-flex flex-column h-100" hx-ext="response-targets">
<header>
<nav class="navbar navbar-expand-md fixed-top {{if .HomeNavbar}}navbar-home{{end}}">
<nav class="navbar navbar-expand-lg fixed-top {{if .HomeNavbar}}navbar-home{{end}}">
<div class="container d-flex justify-content-end">
{{if not .HomeNavbar}}
<span class="navbar-brand mb-0 h1">
Expand All @@ -45,63 +45,49 @@
data-bs-target="#offcanvasNavbar" aria-controls="offcanvasNavbar">
<span class="navbar-toggler-icon"></span>
</button>
<div class="offcanvas offcanvas-end" tabindex="-1" id="offcanvasNavbar"
<div class="offcanvas-lg offcanvas-end" tabindex="-1" id="offcanvasNavbar"
aria-labelledby="offcanvasNavbarLabel">
<div class="offcanvas-header">
<h5 class="offcanvas-title" id="offcanvasNavbarLabel">Coreander</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" aria-label="Close"></button>
<h5 class="offcanvas-title" id="offcanvasNavbarLabel">
<img src="/images/coreander-logo-small.png" alt="Logo" width="32" height="32" class="d-inline-block align-text-middle">
{{.Session.Name}}
</h5>
<button type="button" class="btn-close" data-bs-dismiss="offcanvas" data-bs-target="#offcanvasNavbar" aria-label="Close"></button>
</div>
<div class="offcanvas-body">
<ul class="navbar-nav justify-content-end flex-grow-1 pe-3 text-start">
{{if and (.Session) (ne .Session.Name "")}}
<li class="nav-item dropdown">
<button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
{{.Session.Name}}
</button>
<ul class="dropdown-menu">
<li>
{{if eq .Session.Role 2}}
<a class="dropdown-item" href="/users">
<i class="bi-person-fill"></i>

{{t .Lang "Users"}}
</a>
{{else}}
<a class="dropdown-item" href="/users/{{.Session.Username}}">
<i class="bi-person-fill"></i>
<li class="p-2">
{{if eq .Session.Role 2}}
<a href="/users" class="link-underline link-underline-opacity-0">
<i class="bi-person-fill"></i>

{{t .Lang "Update your profile"}}
</a>
{{end}}
</li>
<li>
<a class="dropdown-item" href="/highlights">
<i class="bi-star-fill"></i>
{{t .Lang "Users"}}
</a>
{{else}}
<a href="/users/{{.Session.Username}}" class="link-underline link-underline-opacity-0">
<i class="bi-person-fill"></i>

{{t .Lang "Highlights"}}
</a>
</li>
{{if eq .Session.Role 2}}
<li>
<a class="dropdown-item" href="/upload">
<i class="bi-cloud-upload-fill"></i>
{{t .Lang "Update your profile"}}
</a>
{{end}}
</li>
<li class="p-2">
<a href="/highlights" class="link-underline link-underline-opacity-0">
<i class="bi-star-fill"></i>

{{t .Lang "Upload document"}}
</a>
</li>
{{end}}
<li>
<hr class="dropdown-divider">
</li>
<li>
<a class="dropdown-item" href="/sessions" hx-delete="/sessions">
<i class="bi-box-arrow-right"></i>
{{t .Lang "Highlights"}}
</a>
</li>
{{if eq .Session.Role 2}}
<li class="p-2">
<a href="/upload" class="link-underline link-underline-opacity-0">
<i class="bi-cloud-upload-fill"></i>

{{t .Lang "Logout"}}
</a>
</li>
</ul>
{{t .Lang "Upload document"}}
</a>
</li>
{{end}}
{{else if not .DisableLoginLink}}
<li class="p-2">
<a href="/sessions/new">{{t .Lang "Login"}}</a>
Expand All @@ -111,17 +97,35 @@ <h5 class="offcanvas-title" id="offcanvasNavbarLabel">Coreander</h5>
{{$lang := .Lang}}
{{$URLPath := .URLPath}}
{{$queryString := .QueryString}}
{{range $i, $currentLang := .SupportedLanguages}}
{{if eq $lang $currentLang}}
<li class="p-2">{{uppercase $currentLang}}</li>
{{else if eq $queryString ""}}
<li class="p-2"><a href="{{$URLPath}}?l={{$currentLang}}">{{uppercase $currentLang}}</a></li>
{{else}}
<li class="p-2"><a href="{{$URLPath}}?{{$queryString}}&l={{$currentLang}}">{{uppercase $currentLang}}</a></li>
<li class="nav-item dropdown">
<button class="btn dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false">
<i class="bi-globe"></i>
</button>
<ul class="dropdown-menu">
{{range $i, $currentLang := .SupportedLanguages}}
{{if eq $lang $currentLang}}
<li class="dropdown-item">{{uppercase $currentLang}}</li>
{{else if eq $queryString ""}}
<li class="dropdown-item"><a href="{{$URLPath}}?l={{$currentLang}}">{{uppercase $currentLang}}</a></li>
{{else}}
<li class="dropdown-item"><a href="{{$URLPath}}?{{$queryString}}&l={{$currentLang}}">{{uppercase $currentLang}}</a></li>
{{end}}
{{end}}
{{end}}
</ul>
</li>
<li class="nav-item dropdown">
{{template "partials/color-mode-toggle" dict "Lang" $lang}}
</li>
{{if and (.Session) (ne .Session.Name "")}}
<hr class="d-lg-none">
{{template "partials/color-mode-toggle" dict "Lang" $lang}}
<li class="p-2">
<a href="/sessions" hx-delete="/sessions" class="link-underline link-underline-opacity-0">
<i class="bi-box-arrow-right"></i>

{{t .Lang "Logout"}}
</a>
</li>
{{end}}
</ul>
</div>
</div>
Expand Down
Loading

0 comments on commit 55e9c19

Please sign in to comment.