cerrado @ 349a3d1ff36a436261b1b65b870f8f262f06584f

feat: Add bare bones project list
  1diff --git a/main.go b/main.go
  2index d2452e8a5766b22174b55f2ffbdcd2bc2149a954..0ba2dbc9553dcab2cbb3b5c0b3172c79c7dda650 100644
  3--- a/main.go
  4+++ b/main.go
  5@@ -1,25 +1,17 @@
  6 package main
  7 
  8 import (
  9-	"bytes"
 10 	"context"
 11-	"encoding/json"
 12 	"flag"
 13-	"io/fs"
 14 	"log/slog"
 15 	"net/http"
 16 	"os"
 17 	"os/signal"
 18 	"time"
 19 
 20-	"github.com/alecthomas/chroma/v2/formatters/html"
 21-	"github.com/alecthomas/chroma/v2/lexers"
 22-	"github.com/alecthomas/chroma/v2/styles"
 23-
 24-	"git.gabrielgio.me/cerrado/pkg/config"
 25+	"git.gabrielgio.me/cerrado/pkg/handler"
 26+	"git.gabrielgio.me/cerrado/pkg/service"
 27 	"git.gabrielgio.me/cerrado/pkg/worker"
 28-	"git.gabrielgio.me/cerrado/static"
 29-	"git.gabrielgio.me/cerrado/templates"
 30 )
 31 
 32 func main() {
 33@@ -41,57 +33,20 @@ 	flag.Parse()
 34 
 35 	mux := http.NewServeMux()
 36 
 37-	staticFs, err := fs.Sub(static.Static, ".")
 38+	staticHandler, err := handler.NewStaticHander("/static/")
 39 	if err != nil {
 40 		return err
 41 	}
 42 
 43-	mux.Handle("/static/", http.StripPrefix("/static/", http.FileServer(http.FS(staticFs))))
 44-	mux.HandleFunc("/", func(w http.ResponseWriter, _ *http.Request) {
 45-		slog.Info("Handling index")
 46+	// services
 47+	gitService := service.NewGitService()
 48 
 49-		f, err := os.Open(*configPath)
 50-		if err != nil {
 51-			slog.Error("Error openning config file json", "error", err, "path", *configPath)
 52-			return
 53-		}
 54+	//handlers
 55+	gitHandler := handler.NewGitHandler(gitService)
 56 
 57-		c, err := config.Parse(f)
 58-		if err != nil {
 59-			slog.Error("Error parsing config", "error", err, "path", *configPath)
 60-			return
 61-		}
 62-
 63-		b, err := json.MarshalIndent(c, "", "	")
 64-		if err != nil {
 65-			slog.Error("Error parsing json", "error", err)
 66-			return
 67-		}
 68-
 69-		lexer := lexers.Get("json")
 70-		style := styles.Get("monokailight")
 71-		formatter := html.New(
 72-			html.WithLineNumbers(true),
 73-		)
 74-		iterator, err := lexer.Tokenise(nil, string(b))
 75-		if err != nil {
 76-			slog.Error("Error tokenise", "error", err)
 77-			return
 78-		}
 79-
 80-		var code bytes.Buffer
 81-		err = formatter.Format(&code, style, iterator)
 82-		if err != nil {
 83-			slog.Error("Error format", "error", err)
 84-			return
 85-		}
 86-
 87-		hello := &templates.HelloPage{
 88-			Body: code.String(),
 89-		}
 90-
 91-		templates.WritePageTemplate(w, hello)
 92-	})
 93+	mux.Handle("/static/", staticHandler)
 94+	mux.HandleFunc("/config", handler.ConfigFile(*configPath))
 95+	mux.HandleFunc("/", gitHandler.List)
 96 	serverTask := worker.NewServerTask(&http.Server{Handler: mux, Addr: "0.0.0.0:8080"})
 97 
 98 	pool := worker.NewTaskPool()
 99diff --git a/pkg/handler/git.go b/pkg/handler/git.go
100new file mode 100644
101index 0000000000000000000000000000000000000000..5b0912187f278158f0ab3ff7287a1a2f06e0e6df
102--- /dev/null
103+++ b/pkg/handler/git.go
104@@ -0,0 +1,21 @@
105+package handler
106+
107+import (
108+	"net/http"
109+
110+	"git.gabrielgio.me/cerrado/pkg/service"
111+	"git.gabrielgio.me/cerrado/templates"
112+)
113+
114+type GitHandler struct {
115+	gitService *service.GitService
116+}
117+
118+func NewGitHandler(gitService *service.GitService) *GitHandler {
119+	return &GitHandler{gitService}
120+}
121+
122+func (g *GitHandler) List(w http.ResponseWriter, _ *http.Request) {
123+	gitList := &templates.GitListPage{g.gitService.ListRepositories()}
124+	templates.WritePageTemplate(w, gitList)
125+}
126diff --git a/pkg/handler/static.go b/pkg/handler/static.go
127new file mode 100644
128index 0000000000000000000000000000000000000000..9f312f41f09ef14dad4649bfaa0b76d61f8abb5e
129--- /dev/null
130+++ b/pkg/handler/static.go
131@@ -0,0 +1,18 @@
132+package handler
133+
134+import (
135+	"io/fs"
136+	"net/http"
137+
138+	"git.gabrielgio.me/cerrado/static"
139+)
140+
141+func NewStaticHander(prefix string) (http.Handler, error) {
142+	staticFs, err := fs.Sub(static.Static, ".")
143+	if err != nil {
144+		return nil, err
145+	}
146+
147+	handler := http.StripPrefix(prefix, http.FileServer(http.FS(staticFs)))
148+	return handler, nil
149+}
150diff --git a/pkg/handler/status.go b/pkg/handler/status.go
151new file mode 100644
152index 0000000000000000000000000000000000000000..2a84a7e0e00ce79a7236eda6e444c6c3220209b9
153--- /dev/null
154+++ b/pkg/handler/status.go
155@@ -0,0 +1,62 @@
156+package handler
157+
158+import (
159+	"bytes"
160+	"encoding/json"
161+	"log/slog"
162+	"net/http"
163+	"os"
164+
165+	"github.com/alecthomas/chroma/v2/formatters/html"
166+	"github.com/alecthomas/chroma/v2/lexers"
167+	"github.com/alecthomas/chroma/v2/styles"
168+
169+	"git.gabrielgio.me/cerrado/pkg/config"
170+	"git.gabrielgio.me/cerrado/templates"
171+)
172+
173+func ConfigFile(configPath string) func(http.ResponseWriter, *http.Request) {
174+	return func(w http.ResponseWriter, _ *http.Request) {
175+		f, err := os.Open(configPath)
176+		if err != nil {
177+			slog.Error("Error openning config file json", "error", err, "path", configPath)
178+			return
179+		}
180+
181+		c, err := config.Parse(f)
182+		if err != nil {
183+			slog.Error("Error parsing config", "error", err, "path", configPath)
184+			return
185+		}
186+
187+		b, err := json.MarshalIndent(c, "", "	")
188+		if err != nil {
189+			slog.Error("Error parsing json", "error", err)
190+			return
191+		}
192+
193+		lexer := lexers.Get("json")
194+		style := styles.Get("monokailight")
195+		formatter := html.New(
196+			html.WithLineNumbers(true),
197+		)
198+		iterator, err := lexer.Tokenise(nil, string(b))
199+		if err != nil {
200+			slog.Error("Error tokenise", "error", err)
201+			return
202+		}
203+
204+		var code bytes.Buffer
205+		err = formatter.Format(&code, style, iterator)
206+		if err != nil {
207+			slog.Error("Error format", "error", err)
208+			return
209+		}
210+
211+		hello := &templates.HelloPage{
212+			Body: code.String(),
213+		}
214+
215+		templates.WritePageTemplate(w, hello)
216+	}
217+}
218diff --git a/pkg/service/git.go b/pkg/service/git.go
219new file mode 100644
220index 0000000000000000000000000000000000000000..0415ceeee803e69b7e73d69b5875edd6321cfffd
221--- /dev/null
222+++ b/pkg/service/git.go
223@@ -0,0 +1,30 @@
224+package service
225+
226+import "fmt"
227+
228+type (
229+	GitService struct{}
230+	Repository struct {
231+		Name        string
232+		Title       string
233+		Description string
234+	}
235+)
236+
237+func NewGitService() *GitService {
238+	return &GitService{}
239+}
240+
241+func (g *GitService) ListRepositories() []*Repository {
242+	repos := make([]*Repository, 10)
243+
244+	for i := range 10 {
245+		repos[i] = &Repository{
246+			Name:        fmt.Sprintf("repository-%d", i),
247+			Title:       fmt.Sprintf("Repository %d", i),
248+			Description: fmt.Sprintf("This is a description for repository %d", i),
249+		}
250+	}
251+
252+	return repos
253+}
254diff --git a/scss/main.scss b/scss/main.scss
255index 7273c9f36be42a2a85fa8774639400a13bb7668a..eb8a6fe7dc52e09b62850258544a966c374925d2 100644
256--- a/scss/main.scss
257+++ b/scss/main.scss
258@@ -1,4 +1,9 @@
259+//$card-border-width: 0;
260+$card-border-radius: 0;
261+$card-cap-padding-y: 0;
262+$card-cap-padding-x: 0;
263 
264+// basic functionality
265 @import "bootstrap/scss/_functions.scss";
266 @import "bootstrap/scss/_variables.scss";
267 @import "bootstrap/scss/_variables-dark.scss";
268@@ -6,14 +11,16 @@ @import "bootstrap/scss/_maps.scss";
269 @import "bootstrap/scss/_mixins.scss";
270 @import "bootstrap/scss/_utilities.scss";
271 
272-
273+// added component
274 @import "bootstrap/scss/_root.scss";
275 @import "bootstrap/scss/_containers.scss";
276 @import "bootstrap/scss/_nav.scss";
277 @import "bootstrap/scss/_navbar.scss";
278+@import "bootstrap/scss/_card.scss";
279+@import "bootstrap/scss/_grid.scss";
280 
281 
282 body {
283     font-family: $font-family-monospace;
284-
285+    margin: 0;
286 }
287diff --git a/templates/gitlist.qtpl b/templates/gitlist.qtpl
288new file mode 100644
289index 0000000000000000000000000000000000000000..10a89da1a91734e006f2ef7e191ae51bc269ec01
290--- /dev/null
291+++ b/templates/gitlist.qtpl
292@@ -0,0 +1,34 @@
293+{% import "git.gabrielgio.me/cerrado/pkg/service" %}
294+{% import "git.gabrielgio.me/cerrado/pkg/u" %}
295+
296+
297+{% code
298+type GitListPage struct {
299+    Respositories []*service.Repository
300+}
301+%}
302+
303+{% func (p *GitListPage) Title() %}Git | List{% endfunc %}
304+
305+{% func (p *GitListPage) Content() %}
306+{% for _, c := range u.ChunkBy(p.Respositories, 3) %}
307+<div class="row">
308+  {% for _, r := range c %}
309+  <div class="col-md-4 g-0">
310+    <div class="card">
311+      <div class="card-header">
312+        {%s r.Title %}
313+      </div>
314+      <div class="card-body">
315+        <p class="card-text">{%s r.Description %}</p>
316+        <a href="/{%s r.Name %}" class="btn btn-primary">go to repository</a>
317+      </div>
318+    </div>
319+  </div>
320+  {% endfor %}
321+</div>
322+{% endfor %}
323+{% endfunc %}
324+
325+{% func (p *GitListPage) Script() %}
326+{% endfunc %}
327diff --git a/templates/gitlist.qtpl.go b/templates/gitlist.qtpl.go
328new file mode 100644
329index 0000000000000000000000000000000000000000..b02eeadf929a41ad4b3621deb6f5b7cb34be5454
330--- /dev/null
331+++ b/templates/gitlist.qtpl.go
332@@ -0,0 +1,175 @@
333+// Code generated by qtc from "gitlist.qtpl". DO NOT EDIT.
334+// See https://github.com/valyala/quicktemplate for details.
335+
336+//line gitlist.qtpl:1
337+package templates
338+
339+//line gitlist.qtpl:1
340+import "git.gabrielgio.me/cerrado/pkg/service"
341+
342+//line gitlist.qtpl:2
343+import "git.gabrielgio.me/cerrado/pkg/u"
344+
345+//line gitlist.qtpl:5
346+import (
347+	qtio422016 "io"
348+
349+	qt422016 "github.com/valyala/quicktemplate"
350+)
351+
352+//line gitlist.qtpl:5
353+var (
354+	_ = qtio422016.Copy
355+	_ = qt422016.AcquireByteBuffer
356+)
357+
358+//line gitlist.qtpl:6
359+type GitListPage struct {
360+	Respositories []*service.Repository
361+}
362+
363+//line gitlist.qtpl:11
364+func (p *GitListPage) StreamTitle(qw422016 *qt422016.Writer) {
365+//line gitlist.qtpl:11
366+	qw422016.N().S(`Git | List`)
367+//line gitlist.qtpl:11
368+}
369+
370+//line gitlist.qtpl:11
371+func (p *GitListPage) WriteTitle(qq422016 qtio422016.Writer) {
372+//line gitlist.qtpl:11
373+	qw422016 := qt422016.AcquireWriter(qq422016)
374+//line gitlist.qtpl:11
375+	p.StreamTitle(qw422016)
376+//line gitlist.qtpl:11
377+	qt422016.ReleaseWriter(qw422016)
378+//line gitlist.qtpl:11
379+}
380+
381+//line gitlist.qtpl:11
382+func (p *GitListPage) Title() string {
383+//line gitlist.qtpl:11
384+	qb422016 := qt422016.AcquireByteBuffer()
385+//line gitlist.qtpl:11
386+	p.WriteTitle(qb422016)
387+//line gitlist.qtpl:11
388+	qs422016 := string(qb422016.B)
389+//line gitlist.qtpl:11
390+	qt422016.ReleaseByteBuffer(qb422016)
391+//line gitlist.qtpl:11
392+	return qs422016
393+//line gitlist.qtpl:11
394+}
395+
396+//line gitlist.qtpl:13
397+func (p *GitListPage) StreamContent(qw422016 *qt422016.Writer) {
398+//line gitlist.qtpl:13
399+	qw422016.N().S(`
400+`)
401+//line gitlist.qtpl:14
402+	for _, c := range u.ChunkBy(p.Respositories, 3) {
403+//line gitlist.qtpl:14
404+		qw422016.N().S(`
405+<div class="row">
406+  `)
407+//line gitlist.qtpl:16
408+		for _, r := range c {
409+//line gitlist.qtpl:16
410+			qw422016.N().S(`
411+  <div class="col-md-4 g-0">
412+    <div class="card">
413+      <div class="card-header">
414+        `)
415+//line gitlist.qtpl:20
416+			qw422016.E().S(r.Title)
417+//line gitlist.qtpl:20
418+			qw422016.N().S(`
419+      </div>
420+      <div class="card-body">
421+        <p class="card-text">`)
422+//line gitlist.qtpl:23
423+			qw422016.E().S(r.Description)
424+//line gitlist.qtpl:23
425+			qw422016.N().S(`</p>
426+        <a href="/`)
427+//line gitlist.qtpl:24
428+			qw422016.E().S(r.Name)
429+//line gitlist.qtpl:24
430+			qw422016.N().S(`" class="btn btn-primary">go to repository</a>
431+      </div>
432+    </div>
433+  </div>
434+  `)
435+//line gitlist.qtpl:28
436+		}
437+//line gitlist.qtpl:28
438+		qw422016.N().S(`
439+</div>
440+`)
441+//line gitlist.qtpl:30
442+	}
443+//line gitlist.qtpl:30
444+	qw422016.N().S(`
445+`)
446+//line gitlist.qtpl:31
447+}
448+
449+//line gitlist.qtpl:31
450+func (p *GitListPage) WriteContent(qq422016 qtio422016.Writer) {
451+//line gitlist.qtpl:31
452+	qw422016 := qt422016.AcquireWriter(qq422016)
453+//line gitlist.qtpl:31
454+	p.StreamContent(qw422016)
455+//line gitlist.qtpl:31
456+	qt422016.ReleaseWriter(qw422016)
457+//line gitlist.qtpl:31
458+}
459+
460+//line gitlist.qtpl:31
461+func (p *GitListPage) Content() string {
462+//line gitlist.qtpl:31
463+	qb422016 := qt422016.AcquireByteBuffer()
464+//line gitlist.qtpl:31
465+	p.WriteContent(qb422016)
466+//line gitlist.qtpl:31
467+	qs422016 := string(qb422016.B)
468+//line gitlist.qtpl:31
469+	qt422016.ReleaseByteBuffer(qb422016)
470+//line gitlist.qtpl:31
471+	return qs422016
472+//line gitlist.qtpl:31
473+}
474+
475+//line gitlist.qtpl:33
476+func (p *GitListPage) StreamScript(qw422016 *qt422016.Writer) {
477+//line gitlist.qtpl:33
478+	qw422016.N().S(`
479+`)
480+//line gitlist.qtpl:34
481+}
482+
483+//line gitlist.qtpl:34
484+func (p *GitListPage) WriteScript(qq422016 qtio422016.Writer) {
485+//line gitlist.qtpl:34
486+	qw422016 := qt422016.AcquireWriter(qq422016)
487+//line gitlist.qtpl:34
488+	p.StreamScript(qw422016)
489+//line gitlist.qtpl:34
490+	qt422016.ReleaseWriter(qw422016)
491+//line gitlist.qtpl:34
492+}
493+
494+//line gitlist.qtpl:34
495+func (p *GitListPage) Script() string {
496+//line gitlist.qtpl:34
497+	qb422016 := qt422016.AcquireByteBuffer()
498+//line gitlist.qtpl:34
499+	p.WriteScript(qb422016)
500+//line gitlist.qtpl:34
501+	qs422016 := string(qb422016.B)
502+//line gitlist.qtpl:34
503+	qt422016.ReleaseByteBuffer(qb422016)
504+//line gitlist.qtpl:34
505+	return qs422016
506+//line gitlist.qtpl:34
507+}
508diff --git a/templates/helloworld.qtpl b/templates/helloworld.qtpl
509index 66287eac78fadb51d34da5420d2700ff4b4bb511..45c5595820b5fc751efd9f83275cb86da2d11ddc 100644
510--- a/templates/helloworld.qtpl
511+++ b/templates/helloworld.qtpl
512@@ -7,8 +7,6 @@
513 {% func (p *HelloPage) Title() %}Hello{% endfunc %}
514 
515 {% func (p *HelloPage) Content() %}
516-HelloWorld
517-
518 {%s= p.Body %}
519 {% endfunc %}
520 
521diff --git a/templates/helloworld.qtpl.go b/templates/helloworld.qtpl.go
522index a12455fe6c09e8027a97fd8b4a1fe30179553928..61c8f75a74d772c57fd5124d9966cfdbcba1f45c 100644
523--- a/templates/helloworld.qtpl.go
524+++ b/templates/helloworld.qtpl.go
525@@ -59,73 +59,71 @@ //line helloworld.qtpl:9
526 func (p *HelloPage) StreamContent(qw422016 *qt422016.Writer) {
527 //line helloworld.qtpl:9
528 	qw422016.N().S(`
529-HelloWorld
530-
531 `)
532-//line helloworld.qtpl:12
533+//line helloworld.qtpl:10
534 	qw422016.N().S(p.Body)
535-//line helloworld.qtpl:12
536+//line helloworld.qtpl:10
537 	qw422016.N().S(`
538 `)
539-//line helloworld.qtpl:13
540+//line helloworld.qtpl:11
541 }
542 
543-//line helloworld.qtpl:13
544+//line helloworld.qtpl:11
545 func (p *HelloPage) WriteContent(qq422016 qtio422016.Writer) {
546-//line helloworld.qtpl:13
547+//line helloworld.qtpl:11
548 	qw422016 := qt422016.AcquireWriter(qq422016)
549-//line helloworld.qtpl:13
550+//line helloworld.qtpl:11
551 	p.StreamContent(qw422016)
552-//line helloworld.qtpl:13
553+//line helloworld.qtpl:11
554 	qt422016.ReleaseWriter(qw422016)
555-//line helloworld.qtpl:13
556+//line helloworld.qtpl:11
557 }
558 
559-//line helloworld.qtpl:13
560+//line helloworld.qtpl:11
561 func (p *HelloPage) Content() string {
562-//line helloworld.qtpl:13
563+//line helloworld.qtpl:11
564 	qb422016 := qt422016.AcquireByteBuffer()
565-//line helloworld.qtpl:13
566+//line helloworld.qtpl:11
567 	p.WriteContent(qb422016)
568-//line helloworld.qtpl:13
569+//line helloworld.qtpl:11
570 	qs422016 := string(qb422016.B)
571-//line helloworld.qtpl:13
572+//line helloworld.qtpl:11
573 	qt422016.ReleaseByteBuffer(qb422016)
574-//line helloworld.qtpl:13
575+//line helloworld.qtpl:11
576 	return qs422016
577-//line helloworld.qtpl:13
578+//line helloworld.qtpl:11
579 }
580 
581-//line helloworld.qtpl:15
582+//line helloworld.qtpl:13
583 func (p *HelloPage) StreamScript(qw422016 *qt422016.Writer) {
584-//line helloworld.qtpl:15
585+//line helloworld.qtpl:13
586 	qw422016.N().S(`
587 `)
588-//line helloworld.qtpl:16
589+//line helloworld.qtpl:14
590 }
591 
592-//line helloworld.qtpl:16
593+//line helloworld.qtpl:14
594 func (p *HelloPage) WriteScript(qq422016 qtio422016.Writer) {
595-//line helloworld.qtpl:16
596+//line helloworld.qtpl:14
597 	qw422016 := qt422016.AcquireWriter(qq422016)
598-//line helloworld.qtpl:16
599+//line helloworld.qtpl:14
600 	p.StreamScript(qw422016)
601-//line helloworld.qtpl:16
602+//line helloworld.qtpl:14
603 	qt422016.ReleaseWriter(qw422016)
604-//line helloworld.qtpl:16
605+//line helloworld.qtpl:14
606 }
607 
608-//line helloworld.qtpl:16
609+//line helloworld.qtpl:14
610 func (p *HelloPage) Script() string {
611-//line helloworld.qtpl:16
612+//line helloworld.qtpl:14
613 	qb422016 := qt422016.AcquireByteBuffer()
614-//line helloworld.qtpl:16
615+//line helloworld.qtpl:14
616 	p.WriteScript(qb422016)
617-//line helloworld.qtpl:16
618+//line helloworld.qtpl:14
619 	qs422016 := string(qb422016.B)
620-//line helloworld.qtpl:16
621+//line helloworld.qtpl:14
622 	qt422016.ReleaseByteBuffer(qb422016)
623-//line helloworld.qtpl:16
624+//line helloworld.qtpl:14
625 	return qs422016
626-//line helloworld.qtpl:16
627+//line helloworld.qtpl:14
628 }