1diff --git a/pkg/config/config.go b/pkg/config/config.go
2index 6ac6d0560dddf90e88fdce766d2a0261d5a4ab2c..3759b7cc65b14ec93b21b2e862e20b57248ca111 100644
3--- a/pkg/config/config.go
4+++ b/pkg/config/config.go
5@@ -42,6 +42,7 @@ Name string
6 Path string
7 Description string
8 Public bool
9+ About string
10 }
11
12 // ConfigurationRepository represents the configuration repository (as in
13@@ -214,6 +215,10 @@ case "public":
14 if err := setBool(d, &repository.Public); err != nil {
15 return err
16 }
17+ case "about":
18+ if err := setString(d, &repository.About); err != nil {
19+ return err
20+ }
21 }
22 }
23
24@@ -249,6 +254,7 @@ Path: path,
25 Name: filepath.Base(path),
26 Description: "",
27 Public: false,
28+ About: "README.md",
29 }
30 }
31
32diff --git a/pkg/config/config_test.go b/pkg/config/config_test.go
33index 2d779c53ce9aee562d0e7d57e354b7470aa534de..8c1d27ebe8586e356314e45e6a5742766928b443 100644
34--- a/pkg/config/config_test.go
35+++ b/pkg/config/config_test.go
36@@ -53,6 +53,7 @@ Name: "cerrado.git",
37 Path: "/srv/git/cerrado.git",
38 Description: "",
39 Public: false,
40+ About: "README.md",
41 },
42 },
43 },
44@@ -64,6 +65,7 @@ repository /srv/git/cerrado.git {
45 name cerrado
46 description "Single person forge"
47 public true
48+ about readme.txt
49 }`,
50 expectedConfig: &configuration{
51 Scan: defaultScan(),
52@@ -74,6 +76,7 @@ Name: "cerrado",
53 Path: "/srv/git/cerrado.git",
54 Description: "Single person forge",
55 Public: true,
56+ About: "readme.txt",
57 },
58 },
59 },
60@@ -111,6 +114,7 @@ repository /srv/git/cerrado.git {
61 name cerrado
62 description "Single person forge"
63 public true
64+ about readme.txt
65 }`,
66 expectedConfig: &configuration{
67 Scan: &scan{
68@@ -124,12 +128,14 @@ Name: "linux.git",
69 Path: "/srv/git/linux.git",
70 Description: "",
71 Public: false,
72+ About: "README.md",
73 },
74 {
75 Name: "cerrado",
76 Path: "/srv/git/cerrado.git",
77 Description: "Single person forge",
78 Public: true,
79+ About: "readme.txt",
80 },
81 },
82 },
83diff --git a/pkg/handler/git/handler.go b/pkg/handler/git/handler.go
84index 899f61ee30eab7f322c42d25636de59791763221..25505ba4c8ebfc520f69f9e21b87eef41752cd66 100644
85--- a/pkg/handler/git/handler.go
86+++ b/pkg/handler/git/handler.go
87@@ -33,6 +33,7 @@ ListCommits(name string, ref string, count int) ([]*object.Commit, error)
88 GetHead(name string) (*plumbing.Reference, error)
89 GetTree(name, ref, path string) (*object.Tree, error)
90 GetFileContent(name, ref, path string) (string, error)
91+ GetAbout(name string) (string, error)
92 ListTags(name string) ([]*plumbing.Reference, error)
93 ListBranches(name string) ([]*plumbing.Reference, error)
94 }
95@@ -126,10 +127,28 @@ ref, err := g.gitService.GetHead(name)
96 if err != nil {
97 return err
98 }
99+
100+ file, err := g.gitService.GetAbout(name)
101+ if err != nil {
102+ return err
103+ }
104+
105+ extensions := parser.CommonExtensions | parser.AutoHeadingIDs | parser.NoEmptyLineBeforeBlock
106+ p := parser.NewWithExtensions(extensions)
107+ doc := p.Parse([]byte(file))
108+
109+ htmlFlag := markdownhtml.CommonFlags | markdownhtml.HrefTargetBlank
110+ opts := markdownhtml.RendererOptions{Flags: htmlFlag}
111+ renderer := markdownhtml.NewRenderer(opts)
112+
113+ bs := markdown.Render(doc, renderer)
114+
115 gitList := &templates.GitItemPage{
116- Name: name,
117- Ref: ref.Name().Short(),
118- GitItemBase: &templates.GitItemAboutPage{},
119+ Name: name,
120+ Ref: ref.Name().Short(),
121+ GitItemBase: &templates.GitItemAboutPage{
122+ About: bs,
123+ },
124 }
125 templates.WritePageTemplate(w, gitList)
126 return nil
127diff --git a/pkg/service/git.go b/pkg/service/git.go
128index 2165abef8acdfbe13d4831c7e6e0c2556678b004..6bb6e9ebb7739ae025c124766ac402d19c429aad 100644
129--- a/pkg/service/git.go
130+++ b/pkg/service/git.go
131@@ -128,6 +128,24 @@
132 return repo.FileContent(path)
133 }
134
135+func (g *GitService) GetAbout(name string) (string, error) {
136+ r := g.configRepo.GetByName(name)
137+ if r == nil {
138+ return "", RepositoryNotFoundErr
139+ }
140+
141+ repo, err := git.OpenRepository(r.Path)
142+ if err != nil {
143+ return "", err
144+ }
145+ err = repo.SetRef("")
146+ if err != nil {
147+ return "", err
148+ }
149+
150+ return repo.FileContent(r.About)
151+}
152+
153 func (g *GitService) ListTags(name string) ([]*plumbing.Reference, error) {
154 r := g.configRepo.GetByName(name)
155 if r == nil {
156diff --git a/scss/main.scss b/scss/main.scss
157index 107a4c8231a96c66e05ffc6cc91dda311568a367..c438a906e17ffab32f1ce85550253e1b7ea74847 100644
158--- a/scss/main.scss
159+++ b/scss/main.scss
160@@ -60,6 +60,12 @@ end: right,
161 center: center,
162 )
163 ),
164+ "margin": (
165+ responsive: true,
166+ property: margin,
167+ class: m,
168+ values: map-merge($spacers, (auto: auto))
169+ ),
170 "margin-end": (
171 responsive: true,
172 property: margin-right,
173@@ -110,6 +116,11 @@ margin: 0.5rem 0;
174 }
175
176 .code-view {
177+ display: grid;
178+ overflow-x: auto;
179+}
180+
181+pre {
182 display: grid;
183 overflow-x: auto;
184 }
185diff --git a/templates/gititemabout.qtpl b/templates/gititemabout.qtpl
186index abda2fb2476cf828c66e19736aea6e857feac0fd..da9c2e963053111c905671375f028ebf95b1123b 100644
187--- a/templates/gititemabout.qtpl
188+++ b/templates/gititemabout.qtpl
189@@ -1,10 +1,13 @@
190 {% code
191 type GitItemAboutPage struct {
192+ About []byte
193 }
194 %}
195
196 {% func (g *GitItemAboutPage) Nav(name, ref string) %}{%= GitItemNav(name, ref, Readme) %}{% endfunc %}
197
198 {% func (g *GitItemAboutPage) GitContent(name, ref string) %}
199-<h4>About</h4>
200+<div class="m-2">
201+{%z= g.About %}
202+</div>
203 {% endfunc %}
204diff --git a/templates/gititemabout.qtpl.go b/templates/gititemabout.qtpl.go
205index cd49d2fa25928890cb2a8e6ccda5d5057f1144e0..e1c1db423a94f90e4a9fb1d3563acfbdca7c9698 100644
206--- a/templates/gititemabout.qtpl.go
207+++ b/templates/gititemabout.qtpl.go
208@@ -19,72 +19,79 @@ )
209
210 //line gititemabout.qtpl:2
211 type GitItemAboutPage struct {
212+ About []byte
213 }
214
215-//line gititemabout.qtpl:6
216+//line gititemabout.qtpl:7
217 func (g *GitItemAboutPage) StreamNav(qw422016 *qt422016.Writer, name, ref string) {
218-//line gititemabout.qtpl:6
219+//line gititemabout.qtpl:7
220 StreamGitItemNav(qw422016, name, ref, Readme)
221-//line gititemabout.qtpl:6
222+//line gititemabout.qtpl:7
223 }
224
225-//line gititemabout.qtpl:6
226+//line gititemabout.qtpl:7
227 func (g *GitItemAboutPage) WriteNav(qq422016 qtio422016.Writer, name, ref string) {
228-//line gititemabout.qtpl:6
229+//line gititemabout.qtpl:7
230 qw422016 := qt422016.AcquireWriter(qq422016)
231-//line gititemabout.qtpl:6
232+//line gititemabout.qtpl:7
233 g.StreamNav(qw422016, name, ref)
234-//line gititemabout.qtpl:6
235+//line gititemabout.qtpl:7
236 qt422016.ReleaseWriter(qw422016)
237-//line gititemabout.qtpl:6
238+//line gititemabout.qtpl:7
239 }
240
241-//line gititemabout.qtpl:6
242+//line gititemabout.qtpl:7
243 func (g *GitItemAboutPage) Nav(name, ref string) string {
244-//line gititemabout.qtpl:6
245+//line gititemabout.qtpl:7
246 qb422016 := qt422016.AcquireByteBuffer()
247-//line gititemabout.qtpl:6
248+//line gititemabout.qtpl:7
249 g.WriteNav(qb422016, name, ref)
250-//line gititemabout.qtpl:6
251+//line gititemabout.qtpl:7
252 qs422016 := string(qb422016.B)
253-//line gititemabout.qtpl:6
254+//line gititemabout.qtpl:7
255 qt422016.ReleaseByteBuffer(qb422016)
256-//line gititemabout.qtpl:6
257+//line gititemabout.qtpl:7
258 return qs422016
259-//line gititemabout.qtpl:6
260+//line gititemabout.qtpl:7
261 }
262
263-//line gititemabout.qtpl:8
264+//line gititemabout.qtpl:9
265 func (g *GitItemAboutPage) StreamGitContent(qw422016 *qt422016.Writer, name, ref string) {
266-//line gititemabout.qtpl:8
267+//line gititemabout.qtpl:9
268+ qw422016.N().S(`
269+<div class="m-2">
270+`)
271+//line gititemabout.qtpl:11
272+ qw422016.N().Z(g.About)
273+//line gititemabout.qtpl:11
274 qw422016.N().S(`
275-<h4>About</h4>
276+</div>
277 `)
278-//line gititemabout.qtpl:10
279+//line gititemabout.qtpl:13
280 }
281
282-//line gititemabout.qtpl:10
283+//line gititemabout.qtpl:13
284 func (g *GitItemAboutPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
285-//line gititemabout.qtpl:10
286+//line gititemabout.qtpl:13
287 qw422016 := qt422016.AcquireWriter(qq422016)
288-//line gititemabout.qtpl:10
289+//line gititemabout.qtpl:13
290 g.StreamGitContent(qw422016, name, ref)
291-//line gititemabout.qtpl:10
292+//line gititemabout.qtpl:13
293 qt422016.ReleaseWriter(qw422016)
294-//line gititemabout.qtpl:10
295+//line gititemabout.qtpl:13
296 }
297
298-//line gititemabout.qtpl:10
299+//line gititemabout.qtpl:13
300 func (g *GitItemAboutPage) GitContent(name, ref string) string {
301-//line gititemabout.qtpl:10
302+//line gititemabout.qtpl:13
303 qb422016 := qt422016.AcquireByteBuffer()
304-//line gititemabout.qtpl:10
305+//line gititemabout.qtpl:13
306 g.WriteGitContent(qb422016, name, ref)
307-//line gititemabout.qtpl:10
308+//line gititemabout.qtpl:13
309 qs422016 := string(qb422016.B)
310-//line gititemabout.qtpl:10
311+//line gititemabout.qtpl:13
312 qt422016.ReleaseByteBuffer(qb422016)
313-//line gititemabout.qtpl:10
314+//line gititemabout.qtpl:13
315 return qs422016
316-//line gititemabout.qtpl:10
317+//line gititemabout.qtpl:13
318 }
319diff --git a/templates/gititemlog.qtpl b/templates/gititemlog.qtpl
320index a28e7ad52cbd51c2cb6509b3f008116b61e7d8be..3588d32403566a2b260c68d8d50c2b176671ad22 100644
321--- a/templates/gititemlog.qtpl
322+++ b/templates/gititemlog.qtpl
323@@ -12,6 +12,7 @@ {% func (g *GitItemLogPage) GitContent(name, ref string) %}
324 <div class="event-list">
325 {% for _, c := range g.Commits %}
326 <div class="row event">
327+
328 <div class="col-xxl-2">
329 {%s TimeFormat(c.Committer.When) %}
330 </div>
331diff --git a/templates/gititemlog.qtpl.go b/templates/gititemlog.qtpl.go
332index 76c24329c241285809f56a6a9014e1e4274d47bb..b950d1550a22169e8ca085849ca1ddad5dfb4aea 100644
333--- a/templates/gititemlog.qtpl.go
334+++ b/templates/gititemlog.qtpl.go
335@@ -69,64 +69,65 @@ for _, c := range g.Commits {
336 //line gititemlog.qtpl:13
337 qw422016.N().S(`
338 <div class="row event">
339+
340 <div class="col-xxl-2">
341 `)
342-//line gititemlog.qtpl:16
343+//line gititemlog.qtpl:17
344 qw422016.E().S(TimeFormat(c.Committer.When))
345-//line gititemlog.qtpl:16
346+//line gititemlog.qtpl:17
347 qw422016.N().S(`
348 </div>
349 <div class="col-xxl-7 code-view">
350 <pre>`)
351-//line gititemlog.qtpl:19
352+//line gititemlog.qtpl:20
353 qw422016.E().S(c.Message)
354-//line gititemlog.qtpl:19
355+//line gititemlog.qtpl:20
356 qw422016.N().S(`</pre>
357 </div>
358 <div class="col-xxl-3">
359 <small>`)
360-//line gititemlog.qtpl:22
361+//line gititemlog.qtpl:23
362 qw422016.E().S(c.Committer.Name)
363-//line gititemlog.qtpl:22
364+//line gititemlog.qtpl:23
365 qw422016.N().S(` <`)
366-//line gititemlog.qtpl:22
367+//line gititemlog.qtpl:23
368 qw422016.E().S(c.Committer.Email)
369-//line gititemlog.qtpl:22
370+//line gititemlog.qtpl:23
371 qw422016.N().S(`></small>
372 </div>
373 </div>
374 `)
375-//line gititemlog.qtpl:25
376+//line gititemlog.qtpl:26
377 }
378-//line gititemlog.qtpl:25
379+//line gititemlog.qtpl:26
380 qw422016.N().S(`
381 </div>
382 `)
383-//line gititemlog.qtpl:27
384+//line gititemlog.qtpl:28
385 }
386
387-//line gititemlog.qtpl:27
388+//line gititemlog.qtpl:28
389 func (g *GitItemLogPage) WriteGitContent(qq422016 qtio422016.Writer, name, ref string) {
390-//line gititemlog.qtpl:27
391+//line gititemlog.qtpl:28
392 qw422016 := qt422016.AcquireWriter(qq422016)
393-//line gititemlog.qtpl:27
394+//line gititemlog.qtpl:28
395 g.StreamGitContent(qw422016, name, ref)
396-//line gititemlog.qtpl:27
397+//line gititemlog.qtpl:28
398 qt422016.ReleaseWriter(qw422016)
399-//line gititemlog.qtpl:27
400+//line gititemlog.qtpl:28
401 }
402
403-//line gititemlog.qtpl:27
404+//line gititemlog.qtpl:28
405 func (g *GitItemLogPage) GitContent(name, ref string) string {
406-//line gititemlog.qtpl:27
407+//line gititemlog.qtpl:28
408 qb422016 := qt422016.AcquireByteBuffer()
409-//line gititemlog.qtpl:27
410+//line gititemlog.qtpl:28
411 g.WriteGitContent(qb422016, name, ref)
412-//line gititemlog.qtpl:27
413+//line gititemlog.qtpl:28
414 qs422016 := string(qb422016.B)
415-//line gititemlog.qtpl:27
416+//line gititemlog.qtpl:28
417 qt422016.ReleaseByteBuffer(qb422016)
418-//line gititemlog.qtpl:27
419+//line gititemlog.qtpl:28
420 return qs422016
421-//line gititemlog.qtpl:27
422+//line gititemlog.qtpl:28
423 }