+2
-1
appview/pages/funcmap.go
+2
-1
appview/pages/funcmap.go
···
13
13
"time"
14
14
15
15
"github.com/dustin/go-humanize"
16
+
"tangled.sh/tangled.sh/core/appview/pages/markup"
16
17
)
17
18
18
19
func funcMap() template.FuncMap {
···
137
138
return v.Slice(start, end).Interface()
138
139
},
139
140
"markdown": func(text string) template.HTML {
140
-
return template.HTML(renderMarkdown(text))
141
+
return template.HTML(markup.RenderMarkdown(text))
141
142
},
142
143
"isNil": func(t any) bool {
143
144
// returns false for other "zero" values
+3
-2
appview/pages/markdown.go
appview/pages/markup/markdown.go
+3
-2
appview/pages/markdown.go
appview/pages/markup/markdown.go
···
1
-
package pages
1
+
// Package markup is an umbrella package for all markups and their renderers.
2
+
package markup
2
3
3
4
import (
4
5
"bytes"
···
8
9
"github.com/yuin/goldmark/parser"
9
10
)
10
11
11
-
func renderMarkdown(source string) string {
12
+
func RenderMarkdown(source string) string {
12
13
md := goldmark.New(
13
14
goldmark.WithExtensions(extension.GFM),
14
15
goldmark.WithParserOptions(
+26
appview/pages/markup/readme.go
+26
appview/pages/markup/readme.go
···
1
+
package markup
2
+
3
+
import "strings"
4
+
5
+
type Format string
6
+
7
+
const (
8
+
FormatMarkdown Format = "markdown"
9
+
FormatText Format = "text"
10
+
)
11
+
12
+
var FileTypes map[Format][]string = map[Format][]string{
13
+
FormatMarkdown: []string{".md", ".markdown", ".mdown", ".mkdn", ".mkd"},
14
+
}
15
+
16
+
func GetFormat(filename string) Format {
17
+
for format, extensions := range FileTypes {
18
+
for _, extension := range extensions {
19
+
if strings.HasSuffix(filename, extension) {
20
+
return format
21
+
}
22
+
}
23
+
}
24
+
// default format
25
+
return FormatText
26
+
}
+15
-5
appview/pages/pages.go
+15
-5
appview/pages/pages.go
···
24
24
"github.com/microcosm-cc/bluemonday"
25
25
"tangled.sh/tangled.sh/core/appview/auth"
26
26
"tangled.sh/tangled.sh/core/appview/db"
27
+
"tangled.sh/tangled.sh/core/appview/pages/markup"
27
28
"tangled.sh/tangled.sh/core/appview/state/userutil"
28
29
"tangled.sh/tangled.sh/core/types"
29
30
)
···
350
351
ext := filepath.Ext(params.ReadmeFileName)
351
352
switch ext {
352
353
case ".md", ".markdown", ".mdown", ".mkdn", ".mkd":
353
-
htmlString = renderMarkdown(params.Readme)
354
+
htmlString = markup.RenderMarkdown(params.Readme)
354
355
params.Raw = false
355
356
params.HTMLReadme = template.HTML(bluemonday.UGCPolicy().Sanitize(htmlString))
356
357
default:
···
446
447
}
447
448
448
449
type RepoBlobParams struct {
449
-
LoggedInUser *auth.User
450
-
RepoInfo RepoInfo
451
-
Active string
452
-
BreadCrumbs [][]string
450
+
LoggedInUser *auth.User
451
+
RepoInfo RepoInfo
452
+
Active string
453
+
BreadCrumbs [][]string
454
+
ShowRendered bool
455
+
RenderedContents template.HTML
453
456
types.RepoBlobResponse
454
457
}
455
458
···
458
461
b := style.Builder()
459
462
b.Add(chroma.LiteralString, "noitalic")
460
463
style, _ = b.Build()
464
+
465
+
if params.ShowRendered {
466
+
switch markup.GetFormat(params.Path) {
467
+
case markup.FormatMarkdown:
468
+
params.RenderedContents = template.HTML(markup.RenderMarkdown(params.Contents))
469
+
}
470
+
}
461
471
462
472
if params.Lines < 5000 {
463
473
c := params.Contents
+10
-1
appview/pages/templates/repo/blob.html
+10
-1
appview/pages/templates/repo/blob.html
···
43
43
<span>{{ byteFmt .SizeHint }}</span>
44
44
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
45
45
<a href="/{{ .RepoInfo.FullName }}/blob/{{ .Ref }}/raw/{{ .Path }}">view raw</a>
46
+
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
47
+
<a
48
+
href="/{{ .RepoInfo.FullName }}/blob/{{ .Ref }}/{{ .Path }}?code={{ .ShowRendered }}"
49
+
hx-boost="true"
50
+
>view {{ if .ShowRendered }}code{{ else }}rendered{{ end }}</a>
46
51
</div>
47
52
</div>
48
53
</div>
···
52
57
</p>
53
58
{{ else }}
54
59
<div class="overflow-auto relative">
55
-
<div class="whitespace-pre peer-target:bg-yellow-200 dark:peer-target:bg-yellow-900">{{ $.Contents | escapeHtml }}</div>
60
+
{{ if .ShowRendered }}
61
+
<div id="blob-contents" class="prose dark:prose-invert p-6">{{ .RenderedContents }}</div>
62
+
{{ else }}
63
+
<div id="blob-contents" class="whitespace-pre peer-target:bg-yellow-200 dark:peer-target:bg-yellow-900">{{ $.Contents | escapeHtml }}</div>
64
+
{{ end }}
56
65
</div>
57
66
{{ end }}
58
67
{{ end }}
+11
appview/state/repo.go
+11
appview/state/repo.go
···
25
25
"tangled.sh/tangled.sh/core/appview/auth"
26
26
"tangled.sh/tangled.sh/core/appview/db"
27
27
"tangled.sh/tangled.sh/core/appview/pages"
28
+
"tangled.sh/tangled.sh/core/appview/pages/markup"
28
29
"tangled.sh/tangled.sh/core/types"
29
30
30
31
comatproto "github.com/bluesky-social/indigo/api/atproto"
···
453
454
}
454
455
}
455
456
457
+
var showRendered = false
458
+
if markup.GetFormat(result.Path) == markup.FormatMarkdown {
459
+
showRendered = true
460
+
}
461
+
462
+
if r.URL.Query().Get("code") == "true" {
463
+
showRendered = false
464
+
}
465
+
456
466
user := s.auth.GetUser(r)
457
467
s.pages.RepoBlob(w, pages.RepoBlobParams{
458
468
LoggedInUser: user,
459
469
RepoInfo: f.RepoInfo(s, user),
460
470
RepoBlobResponse: result,
461
471
BreadCrumbs: breadcrumbs,
472
+
ShowRendered: showRendered,
462
473
})
463
474
return
464
475
}