forked from tangled.org/core
this repo has no description

appview: pages/blob: toggle render for markdown files

Also sets up a pages/markup package with extensible rendering for future markup languages that we may support.
We may also want an interface or something for markup.RenderMarkdown (maybe just markup.Render), but don't have to bother with that now.

Changed files
+67 -9
appview
pages
state
+2 -1
appview/pages/funcmap.go
···
"time"
"github.com/dustin/go-humanize"
)
func funcMap() template.FuncMap {
···
return v.Slice(start, end).Interface()
},
"markdown": func(text string) template.HTML {
-
return template.HTML(renderMarkdown(text))
},
"isNil": func(t any) bool {
// returns false for other "zero" values
···
"time"
"github.com/dustin/go-humanize"
+
"tangled.sh/tangled.sh/core/appview/pages/markup"
)
func funcMap() template.FuncMap {
···
return v.Slice(start, end).Interface()
},
"markdown": func(text string) template.HTML {
+
return template.HTML(markup.RenderMarkdown(text))
},
"isNil": func(t any) bool {
// returns false for other "zero" values
+3 -2
appview/pages/markdown.go appview/pages/markup/markdown.go
···
-
package pages
import (
"bytes"
···
"github.com/yuin/goldmark/parser"
)
-
func renderMarkdown(source string) string {
md := goldmark.New(
goldmark.WithExtensions(extension.GFM),
goldmark.WithParserOptions(
···
+
// Package markup is an umbrella package for all markups and their renderers.
+
package markup
import (
"bytes"
···
"github.com/yuin/goldmark/parser"
)
+
func RenderMarkdown(source string) string {
md := goldmark.New(
goldmark.WithExtensions(extension.GFM),
goldmark.WithParserOptions(
+26
appview/pages/markup/readme.go
···
···
+
package markup
+
+
import "strings"
+
+
type Format string
+
+
const (
+
FormatMarkdown Format = "markdown"
+
FormatText Format = "text"
+
)
+
+
var FileTypes map[Format][]string = map[Format][]string{
+
FormatMarkdown: []string{".md", ".markdown", ".mdown", ".mkdn", ".mkd"},
+
}
+
+
func GetFormat(filename string) Format {
+
for format, extensions := range FileTypes {
+
for _, extension := range extensions {
+
if strings.HasSuffix(filename, extension) {
+
return format
+
}
+
}
+
}
+
// default format
+
return FormatText
+
}
+15 -5
appview/pages/pages.go
···
"github.com/microcosm-cc/bluemonday"
"tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
"tangled.sh/tangled.sh/core/appview/state/userutil"
"tangled.sh/tangled.sh/core/types"
)
···
ext := filepath.Ext(params.ReadmeFileName)
switch ext {
case ".md", ".markdown", ".mdown", ".mkdn", ".mkd":
-
htmlString = renderMarkdown(params.Readme)
params.Raw = false
params.HTMLReadme = template.HTML(bluemonday.UGCPolicy().Sanitize(htmlString))
default:
···
}
type RepoBlobParams struct {
-
LoggedInUser *auth.User
-
RepoInfo RepoInfo
-
Active string
-
BreadCrumbs [][]string
types.RepoBlobResponse
}
···
b := style.Builder()
b.Add(chroma.LiteralString, "noitalic")
style, _ = b.Build()
if params.Lines < 5000 {
c := params.Contents
···
"github.com/microcosm-cc/bluemonday"
"tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
+
"tangled.sh/tangled.sh/core/appview/pages/markup"
"tangled.sh/tangled.sh/core/appview/state/userutil"
"tangled.sh/tangled.sh/core/types"
)
···
ext := filepath.Ext(params.ReadmeFileName)
switch ext {
case ".md", ".markdown", ".mdown", ".mkdn", ".mkd":
+
htmlString = markup.RenderMarkdown(params.Readme)
params.Raw = false
params.HTMLReadme = template.HTML(bluemonday.UGCPolicy().Sanitize(htmlString))
default:
···
}
type RepoBlobParams struct {
+
LoggedInUser *auth.User
+
RepoInfo RepoInfo
+
Active string
+
BreadCrumbs [][]string
+
ShowRendered bool
+
RenderedContents template.HTML
types.RepoBlobResponse
}
···
b := style.Builder()
b.Add(chroma.LiteralString, "noitalic")
style, _ = b.Build()
+
+
if params.ShowRendered {
+
switch markup.GetFormat(params.Path) {
+
case markup.FormatMarkdown:
+
params.RenderedContents = template.HTML(markup.RenderMarkdown(params.Contents))
+
}
+
}
if params.Lines < 5000 {
c := params.Contents
+10 -1
appview/pages/templates/repo/blob.html
···
<span>{{ byteFmt .SizeHint }}</span>
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
<a href="/{{ .RepoInfo.FullName }}/blob/{{ .Ref }}/raw/{{ .Path }}">view raw</a>
</div>
</div>
</div>
···
</p>
{{ else }}
<div class="overflow-auto relative">
-
<div class="whitespace-pre peer-target:bg-yellow-200 dark:peer-target:bg-yellow-900">{{ $.Contents | escapeHtml }}</div>
</div>
{{ end }}
{{ end }}
···
<span>{{ byteFmt .SizeHint }}</span>
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
<a href="/{{ .RepoInfo.FullName }}/blob/{{ .Ref }}/raw/{{ .Path }}">view raw</a>
+
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
+
<a
+
href="/{{ .RepoInfo.FullName }}/blob/{{ .Ref }}/{{ .Path }}?code={{ .ShowRendered }}"
+
hx-boost="true"
+
>view {{ if .ShowRendered }}code{{ else }}rendered{{ end }}</a>
</div>
</div>
</div>
···
</p>
{{ else }}
<div class="overflow-auto relative">
+
{{ if .ShowRendered }}
+
<div id="blob-contents" class="prose dark:prose-invert p-6">{{ .RenderedContents }}</div>
+
{{ else }}
+
<div id="blob-contents" class="whitespace-pre peer-target:bg-yellow-200 dark:peer-target:bg-yellow-900">{{ $.Contents | escapeHtml }}</div>
+
{{ end }}
</div>
{{ end }}
{{ end }}
+11
appview/state/repo.go
···
"tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
"tangled.sh/tangled.sh/core/appview/pages"
"tangled.sh/tangled.sh/core/types"
comatproto "github.com/bluesky-social/indigo/api/atproto"
···
}
}
user := s.auth.GetUser(r)
s.pages.RepoBlob(w, pages.RepoBlobParams{
LoggedInUser: user,
RepoInfo: f.RepoInfo(s, user),
RepoBlobResponse: result,
BreadCrumbs: breadcrumbs,
})
return
}
···
"tangled.sh/tangled.sh/core/appview/auth"
"tangled.sh/tangled.sh/core/appview/db"
"tangled.sh/tangled.sh/core/appview/pages"
+
"tangled.sh/tangled.sh/core/appview/pages/markup"
"tangled.sh/tangled.sh/core/types"
comatproto "github.com/bluesky-social/indigo/api/atproto"
···
}
}
+
var showRendered = false
+
if markup.GetFormat(result.Path) == markup.FormatMarkdown {
+
showRendered = true
+
}
+
+
if r.URL.Query().Get("code") == "true" {
+
showRendered = false
+
}
+
user := s.auth.GetUser(r)
s.pages.RepoBlob(w, pages.RepoBlobParams{
LoggedInUser: user,
RepoInfo: f.RepoInfo(s, user),
RepoBlobResponse: result,
BreadCrumbs: breadcrumbs,
+
ShowRendered: showRendered,
})
return
}