From f9f314cdad707c07b3b9d88131eb2cf70a179dbd Mon Sep 17 00:00:00 2001 From: vanadium23 Date: Sun, 27 Apr 2025 17:36:53 +0300 Subject: [PATCH 1/2] wip on progress view --- internal/controller/http/web/books.go | 32 +++++++++++++++++++++----- internal/controller/http/web/router.go | 2 +- internal/sync/progress.go | 4 ++++ 3 files changed, 31 insertions(+), 7 deletions(-) diff --git a/internal/controller/http/web/books.go b/internal/controller/http/web/books.go index 02e23b9..67bb023 100644 --- a/internal/controller/http/web/books.go +++ b/internal/controller/http/web/books.go @@ -9,17 +9,19 @@ import ( "github.com/vanadium23/kompanion/internal/entity" "github.com/vanadium23/kompanion/internal/library" "github.com/vanadium23/kompanion/internal/stats" + syncpkg "github.com/vanadium23/kompanion/internal/sync" "github.com/vanadium23/kompanion/pkg/logger" ) type booksRoutes struct { - shelf library.Shelf - stats stats.ReadingStats - logger logger.Interface + shelf library.Shelf + stats stats.ReadingStats + progress syncpkg.Progress + logger logger.Interface } -func newBooksRoutes(handler *gin.RouterGroup, shelf library.Shelf, stats stats.ReadingStats, l logger.Interface) { - r := &booksRoutes{shelf: shelf, stats: stats, logger: l} +func newBooksRoutes(handler *gin.RouterGroup, shelf library.Shelf, stats stats.ReadingStats, progress syncpkg.Progress, l logger.Interface) { + r := &booksRoutes{shelf: shelf, stats: stats, progress: progress, logger: l} handler.GET("/", r.listBooks) handler.POST("/upload", r.uploadBook) @@ -44,8 +46,26 @@ func (r *booksRoutes) listBooks(c *gin.Context) { return } + // Fetch progress for each book + type BookWithProgress struct { + entity.Book + Progress float64 + } + booksWithProgress := make([]BookWithProgress, len(books.Books)) + for i, book := range books.Books { + progress, err := r.progress.Fetch(c.Request.Context(), book.DocumentID) + if err != nil { + r.logger.Error(err, "failed to fetch progress for book %s", book.ID) + progress = entity.Progress{} + } + booksWithProgress[i] = BookWithProgress{ + Book: book, + Progress: progress.Percentage * 100, + } + } + c.HTML(200, "books", passStandartContext(c, gin.H{ - "books": books.Books, + "books": booksWithProgress, "pagination": gin.H{ "currentPage": page, "perPage": perPage, diff --git a/internal/controller/http/web/router.go b/internal/controller/http/web/router.go index 8a27ca2..8986721 100644 --- a/internal/controller/http/web/router.go +++ b/internal/controller/http/web/router.go @@ -81,7 +81,7 @@ func NewRouter( // Product pages bookGroup := handler.Group("/books") bookGroup.Use(authMiddleware(a)) - newBooksRoutes(bookGroup, shelf, stats, l) + newBooksRoutes(bookGroup, shelf, stats, p, l) // Stats pages statsGroup := handler.Group("/stats") diff --git a/internal/sync/progress.go b/internal/sync/progress.go index 94fd6b6..0f86f7a 100644 --- a/internal/sync/progress.go +++ b/internal/sync/progress.go @@ -42,6 +42,10 @@ func (uc *ProgressSyncUseCase) Fetch(ctx context.Context, bookID string) (entity return entity.Progress{}, nil } + if len(doc) == 0 { + return entity.Progress{}, nil + } + last := doc[0] // rewrite koreader device with our authed device last.Device = last.AuthDeviceName From c05ab04bbaf187b638a680d52290aca1a663b45a Mon Sep 17 00:00:00 2001 From: vanadium23 Date: Mon, 28 Apr 2025 17:24:37 +0300 Subject: [PATCH 2/2] web: add progress to main books --- .cursorrules | 20 ++++++++++ .gitignore | 2 + Makefile | 9 ++++- internal/controller/http/web/books.go | 4 +- internal/controller/http/web/router.go | 27 +++++++++++++ web/static/static.css | 54 ++++++++------------------ web/templates/books.html | 42 ++++++++++++-------- web/templates/layouts/master.html | 2 +- 8 files changed, 100 insertions(+), 60 deletions(-) create mode 100644 .cursorrules diff --git a/.cursorrules b/.cursorrules new file mode 100644 index 0000000..61b5640 --- /dev/null +++ b/.cursorrules @@ -0,0 +1,20 @@ +DO NOT GIVE ME HIGH LEVEL SHIT, IF I ASK FOR FIX OR EXPLANATION, I WANT ACTUAL CODE OR EXPLANATION! I DON'T WANT "Here's how you can blablabla" +- Be casual unless otherwise specified +- Be terse +- Suggest solutions that I didn't think about-anticipate my needs +- Treat me as an expert +- Be accurate and thorough +- Give the answer immediately. Provide detailed explanations and restate my query in your own words if necessary after giving the answer +- Value good arguments over authorities, the source is irrelevant +- Consider new technologies and contrarian ideas, not just the conventional wisdom +- You may use high levels of speculation or prediction, just flag it for me +- No moral lectures +- Discuss safety only when it's crucial and non-obvious +- If your content policy is an issue, provide the closest acceptable response and explain the content policy issue afterward +- Cite sources whenever possible at the end, not inline +- No need to mention your knowledge cutoff +- No need to disclose you're an AI +- Please respect my formatting preferences when you provide code. +- Please respect all code comments, they're usually there for a reason. Remove them ONLY if they're completely irrelevant after a code change. if unsure, do not remove the comment. +- Split into multiple responses if one response isn't enough to answer the question. +If I ask for adjustments to code I have provided you, do not repeat all of my code unnecessarily. Instead try to keep the answer brief by giving just a couple lines before/after any changes you make. Multiple code blocks are ok. \ No newline at end of file diff --git a/.gitignore b/.gitignore index 95450a4..34a9465 100644 --- a/.gitignore +++ b/.gitignore @@ -28,3 +28,5 @@ go.work data/ bin/ release/ + +docker-compose-local.yml diff --git a/Makefile b/Makefile index c2b3540..f7bf8ea 100644 --- a/Makefile +++ b/Makefile @@ -1,5 +1,10 @@ -include .env.example -export +ifneq (,$(wildcard ./.env)) + include .env + export +else + include .env.example + export +endif LOCAL_BIN:=$(CURDIR)/bin PATH:=$(LOCAL_BIN):$(PATH) diff --git a/internal/controller/http/web/books.go b/internal/controller/http/web/books.go index 67bb023..e9aae9a 100644 --- a/internal/controller/http/web/books.go +++ b/internal/controller/http/web/books.go @@ -49,7 +49,7 @@ func (r *booksRoutes) listBooks(c *gin.Context) { // Fetch progress for each book type BookWithProgress struct { entity.Book - Progress float64 + Progress int } booksWithProgress := make([]BookWithProgress, len(books.Books)) for i, book := range books.Books { @@ -60,7 +60,7 @@ func (r *booksRoutes) listBooks(c *gin.Context) { } booksWithProgress[i] = BookWithProgress{ Book: book, - Progress: progress.Percentage * 100, + Progress: int(progress.Percentage * 100), } } diff --git a/internal/controller/http/web/router.go b/internal/controller/http/web/router.go index 8986721..a8df3de 100644 --- a/internal/controller/http/web/router.go +++ b/internal/controller/http/web/router.go @@ -5,8 +5,10 @@ import ( "fmt" "html/template" "io/fs" + "math" "net/http" "path/filepath" + "strings" "time" "github.com/foolin/goview" @@ -64,6 +66,7 @@ func NewRouter( "Version": func() string { return template.HTMLEscapeString(version) }, + "generateProgressBar": generateProgressBar, } gv := ginview.New(config) gv.SetFileHandler(embeddedFH) @@ -114,6 +117,30 @@ func formatDuration(seconds int) string { return fmt.Sprintf("%ds", secs) } +func generateProgressBar(percentage int, totalLength int) string { + if percentage < 0 { + percentage = 0 + } + numEquals := int(math.Round(float64(percentage) * float64(totalLength) / 100.0)) + if numEquals > totalLength { + numEquals = totalLength + } + if numEquals < 0 { + numEquals = 0 + } + + numDots := totalLength - numEquals + + var sb strings.Builder + sb.Grow(totalLength + 2) + sb.WriteString("[") + sb.WriteString(strings.Repeat("▓", numEquals)) + sb.WriteString(strings.Repeat("░", numDots)) + sb.WriteString("]") + + return sb.String() +} + // https://github.com/foolin/goview/issues/25#issuecomment-876889943 func embeddedFH(config goview.Config, tmpl string) (string, error) { path := filepath.Join(config.Root, tmpl) diff --git a/web/static/static.css b/web/static/static.css index c9bed32..72b6a16 100644 --- a/web/static/static.css +++ b/web/static/static.css @@ -1,5 +1,3 @@ - - .edit-book-article { display: flex; flex-direction: row; @@ -19,50 +17,30 @@ height: auto; } - - /* books */ -.book-grid { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(200px, 1fr)); - gap: 20px; - padding: 20px; -} - -.book-item { +.book-card { display: flex; - flex-direction: column; - align-items: center; - text-align: center; + align-items: flex-start; + gap: 1rem; + border: var(--border-thickness) solid var(--text-color); + padding: 1rem; + margin-bottom: 1.5rem; } -.book-item .cover { - width: 100%; - height: 300px; - /* Фиксированная высота для всех обложек */ - display: flex; - align-items: center; - justify-content: center; - background-color: #f0f0f0; - /* Цвет фона для обложек, если изображение отсутствует */ +/* Container for the book cover image */ +.book-cover { + flex-shrink: 0; + width: 10rem; } -.book-item img { +/* Style the actual image */ +.book-cover img { + display: block; width: 100%; - height: 100%; - object-fit: cover; - /* Обеспечиваем, чтобы изображение полностью занимало контейнер */ + height: auto; } .book-info { - margin-top: 10px; -} - -.book-title { - font-weight: bold; + flex-grow: 1; + margin-top: 0; } - -.book-author { - font-style: italic; - color: #555; -} \ No newline at end of file diff --git a/web/templates/books.html b/web/templates/books.html index 82d08c7..3eb6322 100644 --- a/web/templates/books.html +++ b/web/templates/books.html @@ -6,21 +6,27 @@
- + -
+
{{ range .books }} -
- -
+ + +
+

+ + {{.Title}} + +

+

{{.Author}}

+

{{ generateProgressBar .Progress 15 }} // {{ .Progress }}%

+
{{ end }}
@@ -30,11 +36,11 @@ {{ if .hasPrev }} Previous {{ end }} - + {{ if .hasNext }} Next {{ end }} - + diff --git a/web/templates/layouts/master.html b/web/templates/layouts/master.html index f5a280c..20a88e1 100644 --- a/web/templates/layouts/master.html +++ b/web/templates/layouts/master.html @@ -16,7 +16,7 @@
- + {{ if .isAuthenticated }}
KOmpanionKOmpanion> Books > Statistics