Signed-off-by: oppiliappan me@oppi.li
+10
-55
appview/pages/pages.go
+10
-55
appview/pages/pages.go
···
744
func (r RepoTreeParams) TreeStats() RepoTreeStats {
745
numFolders, numFiles := 0, 0
746
for _, f := range r.Files {
747
-
if !f.IsFile {
748
numFolders += 1
749
-
} else if f.IsFile {
750
numFiles += 1
751
}
752
}
···
817
}
818
819
type RepoBlobParams struct {
820
-
LoggedInUser *oauth.User
821
-
RepoInfo repoinfo.RepoInfo
822
-
Active string
823
-
Unsupported bool
824
-
IsImage bool
825
-
IsVideo bool
826
-
ContentSrc string
827
-
BreadCrumbs [][]string
828
-
ShowRendered bool
829
-
RenderToggle bool
830
-
RenderedContents template.HTML
831
*tangled.RepoBlob_Output
832
-
// Computed fields for template compatibility
833
-
Contents string
834
-
Lines int
835
-
SizeHint uint64
836
-
IsBinary bool
837
}
838
839
func (p *Pages) RepoBlob(w io.Writer, params RepoBlobParams) error {
840
-
var style *chroma.Style = styles.Get("catpuccin-latte")
841
-
842
-
if params.ShowRendered {
843
-
switch markup.GetFormat(params.Path) {
844
-
case markup.FormatMarkdown:
845
-
p.rctx.RepoInfo = params.RepoInfo
846
-
p.rctx.RendererType = markup.RendererTypeRepoMarkdown
847
-
htmlString := p.rctx.RenderMarkdown(params.Contents)
848
-
sanitized := p.rctx.SanitizeDefault(htmlString)
849
-
params.RenderedContents = template.HTML(sanitized)
850
-
}
851
-
}
852
-
853
-
c := params.Contents
854
-
formatter := chromahtml.New(
855
-
chromahtml.InlineCode(false),
856
-
chromahtml.WithLineNumbers(true),
857
-
chromahtml.WithLinkableLineNumbers(true, "L"),
858
-
chromahtml.Standalone(false),
859
-
chromahtml.WithClasses(true),
860
-
)
861
-
862
-
lexer := lexers.Get(filepath.Base(params.Path))
863
-
if lexer == nil {
864
-
lexer = lexers.Fallback
865
-
}
866
-
867
-
iterator, err := lexer.Tokenise(nil, c)
868
-
if err != nil {
869
-
return fmt.Errorf("chroma tokenize: %w", err)
870
-
}
871
-
872
-
var code bytes.Buffer
873
-
err = formatter.Format(&code, style, iterator)
874
-
if err != nil {
875
-
return fmt.Errorf("chroma format: %w", err)
876
}
877
878
-
params.Contents = code.String()
879
params.Active = "overview"
880
return p.executeRepo("repo/blob", w, params)
881
}
···
744
func (r RepoTreeParams) TreeStats() RepoTreeStats {
745
numFolders, numFiles := 0, 0
746
for _, f := range r.Files {
747
+
if !f.IsFile() {
748
numFolders += 1
749
+
} else if f.IsFile() {
750
numFiles += 1
751
}
752
}
···
817
}
818
819
type RepoBlobParams struct {
820
+
LoggedInUser *oauth.User
821
+
RepoInfo repoinfo.RepoInfo
822
+
Active string
823
+
BreadCrumbs [][]string
824
+
BlobView models.BlobView
825
*tangled.RepoBlob_Output
826
}
827
828
func (p *Pages) RepoBlob(w io.Writer, params RepoBlobParams) error {
829
+
switch params.BlobView.ContentType {
830
+
case models.BlobContentTypeMarkup:
831
+
p.rctx.RepoInfo = params.RepoInfo
832
}
833
834
params.Active = "overview"
835
return p.executeRepo("repo/blob", w, params)
836
}
+62
-39
appview/pages/templates/repo/blob.html
+62
-39
appview/pages/templates/repo/blob.html
···
11
{{ end }}
12
13
{{ define "repoContent" }}
14
-
{{ $lines := split .Contents }}
15
-
{{ $tot_lines := len $lines }}
16
-
{{ $tot_chars := len (printf "%d" $tot_lines) }}
17
-
{{ $code_number_style := "text-gray-400 dark:text-gray-500 left-0 bg-white dark:bg-gray-800 text-right mr-6 select-none inline-block w-12" }}
18
{{ $linkstyle := "no-underline hover:underline" }}
19
<div class="pb-2 mb-3 text-base border-b border-gray-200 dark:border-gray-700">
20
<div class="flex flex-col md:flex-row md:justify-between gap-2">
···
36
</div>
37
<div id="file-info" class="text-gray-500 dark:text-gray-400 text-xs md:text-sm flex flex-wrap items-center gap-1 md:gap-0">
38
<span>at <a href="/{{ .RepoInfo.FullName }}/tree/{{ .Ref }}">{{ .Ref }}</a></span>
39
-
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
40
-
<span>{{ .Lines }} lines</span>
41
-
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
42
-
<span>{{ byteFmt .SizeHint }}</span>
43
-
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
44
-
<a href="/{{ .RepoInfo.FullName }}/raw/{{ .Ref }}/{{ .Path }}">view raw</a>
45
-
{{ if .RenderToggle }}
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>
51
{{ end }}
52
</div>
53
</div>
54
</div>
55
-
{{ if and .IsBinary .Unsupported }}
56
-
<p class="text-center text-gray-400 dark:text-gray-500">
57
-
Previews are not supported for this file type.
58
-
</p>
59
-
{{ else if .IsBinary }}
60
-
<div class="text-center">
61
-
{{ if .IsImage }}
62
-
<img src="{{ .ContentSrc }}"
63
-
alt="{{ .Path }}"
64
-
class="max-w-full h-auto mx-auto border border-gray-200 dark:border-gray-700 rounded" />
65
-
{{ else if .IsVideo }}
66
-
<video controls class="max-w-full h-auto mx-auto border border-gray-200 dark:border-gray-700 rounded">
67
-
<source src="{{ .ContentSrc }}">
68
-
Your browser does not support the video tag.
69
-
</video>
70
-
{{ end }}
71
-
</div>
72
-
{{ else }}
73
-
<div class="overflow-auto relative">
74
-
{{ if .ShowRendered }}
75
-
<div id="blob-contents" class="prose dark:prose-invert">{{ .RenderedContents }}</div>
76
{{ else }}
77
-
<div id="blob-contents" class="whitespace-pre peer-target:bg-yellow-200 dark:peer-target:bg-yellow-900">{{ $.Contents | escapeHtml }}</div>
78
{{ end }}
79
-
</div>
80
{{ end }}
81
{{ template "fragments/multiline-select" }}
82
{{ end }}
···
11
{{ end }}
12
13
{{ define "repoContent" }}
14
{{ $linkstyle := "no-underline hover:underline" }}
15
<div class="pb-2 mb-3 text-base border-b border-gray-200 dark:border-gray-700">
16
<div class="flex flex-col md:flex-row md:justify-between gap-2">
···
32
</div>
33
<div id="file-info" class="text-gray-500 dark:text-gray-400 text-xs md:text-sm flex flex-wrap items-center gap-1 md:gap-0">
34
<span>at <a href="/{{ .RepoInfo.FullName }}/tree/{{ .Ref }}">{{ .Ref }}</a></span>
35
+
36
+
{{ if .BlobView.ShowingText }}
37
+
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
38
+
<span>{{ .Lines }} lines</span>
39
+
{{ end }}
40
+
41
+
{{ if .BlobView.SizeHint }}
42
+
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
43
+
<span>{{ byteFmt .BlobView.SizeHint }}</span>
44
+
{{ end }}
45
+
46
+
{{ if .BlobView.HasRawView }}
47
+
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
48
+
<a href="/{{ .RepoInfo.FullName }}/raw/{{ .Ref }}/{{ .Path }}">view raw</a>
49
+
{{ end }}
50
+
51
+
{{ if .BlobView.ShowToggle }}
52
+
<span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span>
53
+
<a href="/{{ .RepoInfo.FullName }}/blob/{{ .Ref }}/{{ .Path }}?code={{ .BlobView.ShowingRendered }}" hx-boost="true">
54
+
view {{ if .BlobView.ShowingRendered }}code{{ else }}rendered{{ end }}
55
+
</a>
56
{{ end }}
57
</div>
58
</div>
59
</div>
60
+
{{ if .BlobView.IsUnsupported }}
61
+
<p class="text-center text-gray-400 dark:text-gray-500">
62
+
Previews are not supported for this file type.
63
+
</p>
64
+
{{ else if .BlobView.ContentType.IsSubmodule }}
65
+
<p class="text-center text-gray-400 dark:text-gray-500">
66
+
This directory is a git submodule of <a href="{{ .BlobView.ContentSrc }}">{{ .BlobView.ContentSrc }}</a>.
67
+
</p>
68
+
{{ else if .BlobView.ContentType.IsImage }}
69
+
<div class="text-center">
70
+
<img src="{{ .BlobView.ContentSrc }}"
71
+
alt="{{ .Path }}"
72
+
class="max-w-full h-auto mx-auto border border-gray-200 dark:border-gray-700 rounded" />
73
+
</div>
74
+
{{ else if .BlobView.ContentType.IsVideo }}
75
+
<div class="text-center">
76
+
<video controls class="max-w-full h-auto mx-auto border border-gray-200 dark:border-gray-700 rounded">
77
+
<source src="{{ .BlobView.ContentSrc }}">
78
+
Your browser does not support the video tag.
79
+
</video>
80
+
</div>
81
+
{{ else if .BlobView.ContentType.IsSvg }}
82
+
<div class="overflow-auto relative">
83
+
{{ if .BlobView.ShowingRendered }}
84
+
<div class="text-center">
85
+
<img src="{{ .BlobView.ContentSrc }}"
86
+
alt="{{ .Path }}"
87
+
class="max-w-full h-auto mx-auto border border-gray-200 dark:border-gray-700 rounded" />
88
+
</div>
89
{{ else }}
90
+
<div id="blob-contents" class="whitespace-pre peer-target:bg-yellow-200 dark:peer-target:bg-yellow-900">{{ code .BlobView.Contents .Path | escapeHtml }}</div>
91
{{ end }}
92
+
</div>
93
+
{{ else if .BlobView.ContentType.IsMarkup }}
94
+
<div class="overflow-auto relative">
95
+
{{ if .BlobView.ShowingRendered }}
96
+
<div id="blob-contents" class="prose dark:prose-invert">{{ .BlobView.Contents | readme }}</div>
97
+
{{ else }}
98
+
<div id="blob-contents" class="whitespace-pre peer-target:bg-yellow-200 dark:peer-target:bg-yellow-900">{{ code .BlobView.Contents .Path | escapeHtml }}</div>
99
+
{{ end }}
100
+
</div>
101
+
{{ else if .BlobView.ContentType.IsCode }}
102
+
<div id="blob-contents" class="whitespace-pre peer-target:bg-yellow-200 dark:peer-target:bg-yellow-900">{{ code .BlobView.Contents .Path | escapeHtml }}</div>
103
{{ end }}
104
{{ template "fragments/multiline-select" }}
105
{{ end }}