forked from tangled.org/core
Monorepo for Tangled

appview: blob: view raw file

Also improves the file/tree metadata.

anirudh.fi b742fca8 66ebd7d3

verified
Changed files
+74 -24
appview
pages
templates
state
+11 -7
appview/pages/templates/repo/blob.html
··· 17 17 {{ $tot_chars := len (printf "%d" $tot_lines) }} 18 18 {{ $code_number_style := "text-gray-400 left-0 bg-white text-right mr-6 select-none inline-block w-12" }} 19 19 {{ $linkstyle := "no-underline hover:underline" }} 20 - <div class="pb-2 text-base"> 21 - <div class="flex justify-between"> 22 - <div id="breadcrumbs"> 20 + <div class="pb-2 mb-3 text-base border-b border-gray-200"> 21 + <div class="flex flex-col md:flex-row md:justify-between gap-2"> 22 + <div id="breadcrumbs" class="overflow-x-auto whitespace-nowrap"> 23 23 {{ range $idx, $value := .BreadCrumbs }} 24 24 {{ if ne $idx (sub (len $.BreadCrumbs) 1) }} 25 25 <a ··· 35 35 {{ end }} 36 36 {{ end }} 37 37 </div> 38 - <div id="file-info" class="text-gray-500 text-xs"> 39 - {{ .Lines }} lines 40 - <span class="select-none px-2 [&:before]:content-['·']"></span> 41 - {{ byteFmt .SizeHint }} 38 + <div id="file-info" class="text-gray-500 text-xs md:text-sm flex flex-wrap items-center gap-1 md:gap-0"> 39 + <span>at <a href="/{{ .RepoInfo.FullName }}/tree/{{ .Ref }}">{{ .Ref }}</a></span> 40 + <span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span> 41 + <span>{{ .Lines }} lines</span> 42 + <span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span> 43 + <span>{{ byteFmt .SizeHint }}</span> 44 + <span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span> 45 + <a href="/{{ .RepoInfo.FullName }}/blob/raw/{{ .Ref }}/{{ .Path }}">view raw</a> 42 46 </div> 43 47 </div> 44 48 </div>
+18 -17
appview/pages/templates/repo/tree.html
··· 17 17 {{ $containerstyle := "py-1" }} 18 18 {{ $linkstyle := "no-underline hover:underline" }} 19 19 20 - <div class="pb-2 text-base"> 20 + <div class="pb-2 mb-3 text-base border-b border-gray-200"> 21 21 <div class="flex justify-between"> 22 22 <div id="breadcrumbs"> 23 23 {{ range .BreadCrumbs }} 24 24 <a href="{{ index . 1}}" class="text-bold text-gray-500 {{ $linkstyle }}">{{ index . 0 }}</a> / 25 25 {{ end }} 26 26 </div> 27 - <div id="dir-info"> 28 - <span class="text-gray-500 text-xs"> 29 - {{ $stats := .TreeStats }} 27 + <div id="dir-info" class="text-gray-500 text-xs md:text-sm flex flex-wrap items-center gap-1 md:gap-0"> 28 + {{ $stats := .TreeStats }} 30 29 31 - {{ if eq $stats.NumFolders 1 }} 32 - {{ $stats.NumFolders }} folder 33 - <span class="px-1 select-none">·</span> 34 - {{ else if gt $stats.NumFolders 1 }} 35 - {{ $stats.NumFolders }} folders 36 - <span class="px-1 select-none">·</span> 37 - {{ end }} 30 + <span>at <a href="/{{ $.RepoInfo.FullName }}/tree/{{ $.Ref }}">{{ $.Ref }}</a></span> 31 + <span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span> 32 + {{ if eq $stats.NumFolders 1 }} 33 + <span>{{ $stats.NumFolders }} folder</span> 34 + <span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span> 35 + {{ else if gt $stats.NumFolders 1 }} 36 + <span>{{ $stats.NumFolders }} folders</span> 37 + <span class="select-none px-1 md:px-2 [&:before]:content-['·']"></span> 38 + {{ end }} 39 + 40 + {{ if eq $stats.NumFiles 1 }} 41 + <span>{{ $stats.NumFiles }} file</span> 42 + {{ else if gt $stats.NumFiles 1 }} 43 + <span>{{ $stats.NumFiles }} files</span> 44 + {{ end }} 38 45 39 - {{ if eq $stats.NumFiles 1 }} 40 - {{ $stats.NumFiles }} file 41 - {{ else if gt $stats.NumFiles 1 }} 42 - {{ $stats.NumFiles }} files 43 - {{ end }} 44 - </span> 45 46 </div> 46 47 </div> 47 48 </div>
+44
appview/state/repo.go
··· 460 460 return 461 461 } 462 462 463 + func (s *State) RepoBlobRaw(w http.ResponseWriter, r *http.Request) { 464 + f, err := fullyResolvedRepo(r) 465 + if err != nil { 466 + log.Println("failed to get repo and knot", err) 467 + return 468 + } 469 + 470 + ref := chi.URLParam(r, "ref") 471 + filePath := chi.URLParam(r, "*") 472 + 473 + protocol := "http" 474 + if !s.config.Dev { 475 + protocol = "https" 476 + } 477 + resp, err := http.Get(fmt.Sprintf("%s://%s/%s/%s/blob/%s/%s", protocol, f.Knot, f.OwnerDid(), f.RepoName, ref, filePath)) 478 + if err != nil { 479 + log.Println("failed to reach knotserver", err) 480 + return 481 + } 482 + 483 + body, err := io.ReadAll(resp.Body) 484 + if err != nil { 485 + log.Printf("Error reading response body: %v", err) 486 + return 487 + } 488 + 489 + var result types.RepoBlobResponse 490 + err = json.Unmarshal(body, &result) 491 + if err != nil { 492 + log.Println("failed to parse response:", err) 493 + return 494 + } 495 + 496 + if result.IsBinary { 497 + w.Header().Set("Content-Type", "application/octet-stream") 498 + w.Write(body) 499 + return 500 + } 501 + 502 + w.Header().Set("Content-Type", "text/plain") 503 + w.Write([]byte(result.Contents)) 504 + return 505 + } 506 + 463 507 func (s *State) AddCollaborator(w http.ResponseWriter, r *http.Request) { 464 508 f, err := fullyResolvedRepo(r) 465 509 if err != nil {
+1
appview/state/router.go
··· 63 63 r.Get("/branches", s.RepoBranches) 64 64 r.Get("/tags", s.RepoTags) 65 65 r.Get("/blob/{ref}/*", s.RepoBlob) 66 + r.Get("/blob/{ref}/raw/*", s.RepoBlobRaw) 66 67 67 68 r.Route("/issues", func(r chi.Router) { 68 69 r.Get("/", s.RepoIssues)