From 0e6d0ecd660e61c7165499471439526abab49d4f Mon Sep 17 00:00:00 2001 From: djuka Date: Fri, 20 Feb 2026 12:55:05 +0000 Subject: [PATCH] T15: Docs viewer sidebar layout (25%/75% grid) sa HTMX fragmentima Co-Authored-By: Claude Opus 4.6 --- TASKS/reports/T15-report.md | 50 +++++++++++++++++++++++++ TASKS/review/T15.md | 53 ++++++++++++++++++++++++++ code/internal/server/docs.go | 15 ++++++++ code/internal/server/server_test.go | 58 +++++++++++++++++++++++++++++ code/web/static/style.css | 20 ++++++++-- code/web/templates/docs-list.html | 26 ++++++++----- code/web/templates/docs-view.html | 33 +++++++++++----- 7 files changed, 233 insertions(+), 22 deletions(-) create mode 100644 TASKS/reports/T15-report.md create mode 100644 TASKS/review/T15.md diff --git a/TASKS/reports/T15-report.md b/TASKS/reports/T15-report.md new file mode 100644 index 0000000..9a6583c --- /dev/null +++ b/TASKS/reports/T15-report.md @@ -0,0 +1,50 @@ +# T15 Izveštaj: Fix — docs viewer zauzima pola ekrana + +**Agent:** coder +**Model:** Opus +**Datum:** 2026-02-20 + +--- + +## Šta je urađeno + +Docs viewer pretvoren u sidebar + content layout (25%/75% grid). + +### Izmenjeni fajlovi + +| Fajl | Izmena | +|------|--------| +| `web/static/style.css` | docs-layout grid (25%/75%), docs-sidebar, docs-main, responsive | +| `web/templates/docs-list.html` | Sidebar + content layout sa placeholder | +| `web/templates/docs-view.html` | Sidebar sa file listom + content sa breadcrumbs | +| `internal/server/docs.go` | Files polje u docsViewData, HTMX fragment detekcija | +| `internal/server/server_test.go` | 3 nova testa | + +### Layout + +``` +┌──────────────┬───────────────────────────┐ +│ Sidebar 25% │ Content 75% │ +│ File list │ Breadcrumbs + Markdown │ +│ │ │ +│ │ │ +└──────────────┴───────────────────────────┘ +``` + +- HTMX klik na fajl → swap samo content div (fragment) +- Direktan URL pristup → full page sa sidebar +- Responsive: na <700px → 1 kolona (100%) +- min-height: 80vh + +### Novi testovi — 3 PASS + +``` +TestDocsView_HasSidebarLayout PASS +TestDocsView_HTMXReturnsFragment PASS +TestDocsList_HasSidebarLayout PASS +``` + +### Ukupno projekat: 119 testova, svi prolaze + +- `go vet ./...` — čist +- `go build ./...` — prolazi diff --git a/TASKS/review/T15.md b/TASKS/review/T15.md new file mode 100644 index 0000000..e61d7a3 --- /dev/null +++ b/TASKS/review/T15.md @@ -0,0 +1,53 @@ +# T15: Fix — docs viewer zauzima pola ekrana + +**Kreirao:** planer +**Datum:** 2026-02-20 +**Agent:** coder +**Model:** Sonnet +**Zavisi od:** T12 ✅ + +--- + +## Opis + +BUG/UI: Docs viewer je premali. Treba da zauzima pola ekrana (50%ширine). + +## Izmena + +Layout kad je docs otvoren: +``` +┌──────────────────────┬──────────────────────┐ +│ │ │ +│ Lista fajlova │ Sadržaj .md fajla │ +│ (sidebar 25%) │ (content 75%) │ +│ │ │ +│ │ │ +│ │ │ +│ │ │ +└──────────────────────┴──────────────────────┘ +``` + +Ceo docs tab zauzima minimalno 50% viewport širine. +Sadržaj fajla: max-width nema ograničenja, koristi sav prostor. +Visina: min-height 80vh da ne bude stisnuto. + +## Fajlovi za izmenu + +``` +code/web/static/style.css ← širina docs containera +code/web/templates/docs.html ← ako treba layout fix +``` + +## Testovi + +- Otvori /docs → zauzima puno ekrana +- Renderovan markdown čitljiv na celoj širini +- Responsive: na manjem ekranu 100% širine + +--- + +## Pitanja + +--- + +## Odgovori diff --git a/code/internal/server/docs.go b/code/internal/server/docs.go index bedbd4d..56e0d9f 100644 --- a/code/internal/server/docs.go +++ b/code/internal/server/docs.go @@ -30,6 +30,7 @@ type docsViewData struct { Path string Breadcrumbs []breadcrumb HTML htmltpl.HTML + Files []docFile } // breadcrumb represents one segment of the navigation path. @@ -89,10 +90,24 @@ func (s *Server) handleDocsView(c *gin.Context) { // Render markdown to HTML rendered := renderMarkdown(content, relPath) + // HTMX request → return just the content fragment + if c.GetHeader("HX-Request") == "true" { + c.Header("Content-Type", "text/html; charset=utf-8") + breadcrumbHTML := `
Dokumenti` + for _, bc := range buildBreadcrumbs(relPath) { + breadcrumbHTML += ` ` + bc.Name + `` + } + breadcrumbHTML += `
` + c.String(http.StatusOK, breadcrumbHTML+rendered) + return + } + + // Full page request → return with sidebar data := docsViewData{ Path: relPath, Breadcrumbs: buildBreadcrumbs(relPath), HTML: htmltpl.HTML(rendered), + Files: scanMarkdownFiles(s.projectRoot()), } c.Header("Content-Type", "text/html; charset=utf-8") diff --git a/code/internal/server/server_test.go b/code/internal/server/server_test.go index ac1e12d..8d138f0 100644 --- a/code/internal/server/server_test.go +++ b/code/internal/server/server_test.go @@ -928,6 +928,64 @@ func TestConsoleHistory_AfterExec(t *testing.T) { } } +func TestDocsView_HasSidebarLayout(t *testing.T) { + srv := setupTestServer(t) + + req := httptest.NewRequest(http.MethodGet, "/docs/CLAUDE.md", nil) + w := httptest.NewRecorder() + srv.Router.ServeHTTP(w, req) + + body := w.Body.String() + if !containsStr(body, "docs-layout") { + t.Error("expected docs-layout class for grid layout") + } + if !containsStr(body, "docs-sidebar") { + t.Error("expected docs-sidebar class") + } + if !containsStr(body, "docs-main") { + t.Error("expected docs-main class") + } + // Sidebar should list files + if !containsStr(body, "README.md") { + t.Error("expected file list in sidebar") + } +} + +func TestDocsView_HTMXReturnsFragment(t *testing.T) { + srv := setupTestServer(t) + + req := httptest.NewRequest(http.MethodGet, "/docs/CLAUDE.md", nil) + req.Header.Set("HX-Request", "true") + w := httptest.NewRecorder() + srv.Router.ServeHTTP(w, req) + + body := w.Body.String() + // Should NOT have full page HTML + if containsStr(body, "") { + t.Error("HTMX request should return fragment, not full page") + } + // Should have breadcrumbs and content + if !containsStr(body, "Dokumenti") { + t.Error("expected breadcrumbs in fragment") + } + if !containsStr(body, "Glavni fajl") { + t.Error("expected rendered content in fragment") + } +} + +func TestDocsList_HasSidebarLayout(t *testing.T) { + srv := setupTestServer(t) + + req := httptest.NewRequest(http.MethodGet, "/docs", nil) + w := httptest.NewRecorder() + srv.Router.ServeHTTP(w, req) + + body := w.Body.String() + if !containsStr(body, "docs-layout") { + t.Error("expected docs-layout class on docs list page") + } +} + func TestRewriteLinksSimple(t *testing.T) { input := `link and ext` result := rewriteLinksSimple(input, ".") diff --git a/code/web/static/style.css b/code/web/static/style.css index 9c83ff6..e7e576e 100644 --- a/code/web/static/style.css +++ b/code/web/static/style.css @@ -349,13 +349,20 @@ body { /* Docs */ .docs-container { padding: 16px 24px; - max-width: 960px; - margin: 0 auto; + min-height: 80vh; } -.docs-container h2 { - margin-bottom: 16px; +.docs-layout { + display: grid; + grid-template-columns: 25% 1fr; + gap: 16px; + min-height: 80vh; +} + +.docs-sidebar h2 { + margin-bottom: 12px; color: #e94560; + font-size: 1.1em; } .docs-list { @@ -403,6 +410,10 @@ body { margin: 0 4px; } +.docs-main { + min-width: 0; +} + .docs-content { background: #16213e; border-radius: 8px; @@ -609,6 +620,7 @@ body { @media (max-width: 700px) { .board { grid-template-columns: repeat(2, 1fr); } #task-detail { width: 100%; right: -100%; } + .docs-layout { grid-template-columns: 1fr; } } @media (max-width: 500px) { diff --git a/code/web/templates/docs-list.html b/code/web/templates/docs-list.html index 05d85ee..79be157 100644 --- a/code/web/templates/docs-list.html +++ b/code/web/templates/docs-list.html @@ -18,16 +18,24 @@
-

Dokumentacija

-
- {{range .Files}} - - 📄 - {{.Name}} - - {{end}} +
+
+

Dokumentacija

+
+ {{range .Files}} + + 📄 + {{.Name}} + + {{end}} +
+
+
+
+

Klikni na fajl da vidiš sadržaj.

+
+
-
diff --git a/code/web/templates/docs-view.html b/code/web/templates/docs-view.html index 391ea08..98f41a1 100644 --- a/code/web/templates/docs-view.html +++ b/code/web/templates/docs-view.html @@ -18,15 +18,30 @@
-
- Dokumenti - {{range .Breadcrumbs}} - - {{.Name}} - {{end}} -
-
- {{.HTML}} +
+
+

Dokumentacija

+
+ {{range .Files}} + + 📄 + {{.Name}} + + {{end}} +
+
+
+
+
+ Dokumenti + {{range .Breadcrumbs}} + + {{.Name}} + {{end}} +
+ {{.HTML}} +
+