forked from tangled.org/core
Monorepo for Tangled — https://tangled.org

appview/pages: improve grid layout in directory listings

unifies layouts in repo-index and repo-tree.

Signed-off-by: oppiliappan <me@oppi.li>

oppi.li 87d9107d 23e971e6

verified
Changed files
+101 -115
appview
+1 -1
appview/pages/funcmap.go
···
if v.Len() == 0 {
return nil
}
-
return v.Slice(0, min(n, v.Len()-1)).Interface()
},
"markdown": func(text string) template.HTML {
···
if v.Len() == 0 {
return nil
}
+
return v.Slice(0, min(n, v.Len())).Interface()
},
"markdown": func(text string) template.HTML {
+1 -2
appview/pages/pages.go
···
RepoInfo repoinfo.RepoInfo
Active string
BreadCrumbs [][]string
-
BaseTreeLink string
-
BaseBlobLink string
types.RepoTreeResponse
}
···
RepoInfo repoinfo.RepoInfo
Active string
BreadCrumbs [][]string
+
TreePath string
types.RepoTreeResponse
}
+27 -47
appview/pages/templates/repo/index.html
···
{{ end }}
{{ define "fileTree" }}
-
<div
-
id="file-tree"
-
class="col-span-1 pr-2 md:border-r md:border-gray-200 dark:md:border-gray-700"
-
>
-
{{ $containerstyle := "py-1" }}
-
{{ $linkstyle := "no-underline hover:underline dark:text-white" }}
-
{{ range .Files }}
-
{{ if not .IsFile }}
-
<div class="{{ $containerstyle }}">
-
<div class="flex justify-between items-center">
-
<a
-
href="/{{ $.RepoInfo.FullName }}/tree/{{ $.Ref | urlquery }}/{{ .Name }}"
-
class="{{ $linkstyle }}"
-
>
-
<div class="flex items-center gap-2">
-
{{ i "folder" "size-4 fill-current" }}
-
{{ .Name }}
-
</div>
-
</a>
-
{{ if .LastCommit }}
-
<span class="text-xs text-gray-500 dark:text-gray-400">{{ template "repo/fragments/time" .LastCommit.When }}</span>
-
{{ end }}
-
</div>
-
</div>
-
{{ end }}
-
{{ end }}
-
-
{{ range .Files }}
-
{{ if .IsFile }}
-
<div class="{{ $containerstyle }}">
-
<div class="flex justify-between items-center">
-
<a
-
href="/{{ $.RepoInfo.FullName }}/blob/{{ $.Ref | urlquery }}/{{ .Name }}"
-
class="{{ $linkstyle }}"
-
>
-
<div class="flex items-center gap-2">
-
{{ i "file" "size-4" }}{{ .Name }}
-
</div>
-
</a>
-
{{ if .LastCommit }}
-
<span class="text-xs text-gray-500 dark:text-gray-400">{{ template "repo/fragments/time" .LastCommit.When }}</span>
-
{{ end }}
-
</div>
-
</div>
-
{{ end }}
-
{{ end }}
-
</div>
{{ end }}
{{ define "rightInfo" }}
···
{{ end }}
{{ define "fileTree" }}
+
<div id="file-tree" class="col-span-1 pr-2 md:border-r md:border-gray-200 dark:md:border-gray-700" >
+
{{ $linkstyle := "no-underline hover:underline dark:text-white" }}
+
{{ range .Files }}
+
<div class="grid grid-cols-2 gap-4 items-center py-1">
+
<div class="col-span-1">
+
{{ $link := printf "/%s/%s/%s/%s" $.RepoInfo.FullName "tree" (urlquery $.Ref) .Name }}
+
{{ $icon := "folder" }}
+
{{ $iconStyle := "size-4 fill-current" }}
+
{{ if .IsFile }}
+
{{ $link = printf "/%s/%s/%s/%s" $.RepoInfo.FullName "blob" (urlquery $.Ref) .Name }}
+
{{ $icon = "file" }}
+
{{ $iconStyle = "size-4" }}
+
{{ end }}
+
<a href="{{ $link }}" class="{{ $linkstyle }}">
+
<div class="flex items-center gap-2">
+
{{ i $icon $iconStyle }}{{ .Name }}
+
</div>
+
</a>
+
</div>
+
<div class="text-xs col-span-1 text-right">
+
{{ with .LastCommit }}
+
<a href="/{{ $.RepoInfo.FullName }}/commit/{{ .Hash }}" class="text-gray-500 dark:text-gray-400">{{ template "repo/fragments/time" .When }}</a>
+
{{ end }}
+
</div>
+
</div>
+
{{ end }}
+
</div>
{{ end }}
{{ define "rightInfo" }}
+26 -34
appview/pages/templates/repo/tree.html
···
{{define "repoContent"}}
<main>
<div class="tree">
-
{{ $containerstyle := "py-1" }}
{{ $linkstyle := "no-underline hover:underline" }}
<div class="pb-2 mb-3 text-base border-b border-gray-200 dark:border-gray-700">
···
</div>
{{ range .Files }}
-
{{ if not .IsFile }}
-
<div class="{{ $containerstyle }}">
-
<div class="flex justify-between items-center">
-
<a href="/{{ $.BaseTreeLink }}/{{ .Name }}" class="{{ $linkstyle }}">
-
<div class="flex items-center gap-2">
-
{{ i "folder" "size-4 fill-current" }}{{ .Name }}
-
</div>
-
</a>
-
{{ if .LastCommit}}
-
<div class="flex items-end gap-2">
-
<span class="text text-gray-500 dark:text-gray-400 mr-6">{{ .LastCommit.Message }}</span>
-
<span class="text-xs text-gray-500 dark:text-gray-400">{{ template "repo/fragments/time" .LastCommit.When }}</span>
</div>
-
{{ end }}
</div>
-
</div>
-
{{ end }}
-
{{ end }}
-
{{ range .Files }}
-
{{ if .IsFile }}
-
<div class="{{ $containerstyle }}">
-
<div class="flex justify-between items-center">
-
<a href="/{{ $.BaseBlobLink }}/{{ .Name }}" class="{{ $linkstyle }}">
-
<div class="flex items-center gap-2">
-
{{ i "file" "size-4" }}{{ .Name }}
-
</div>
-
</a>
-
{{ if .LastCommit}}
-
<div class="flex items-end gap-2">
-
<span class="text text-gray-500 dark:text-gray-400 mr-6">{{ .LastCommit.Message }}</span>
-
<span class="text-xs text-gray-500 dark:text-gray-400">{{ template "repo/fragments/time" .LastCommit.When }}</span>
-
</div>
-
{{ end }}
</div>
-
</div>
{{ end }}
-
{{ end }}
</div>
</main>
{{end}}
···
{{define "repoContent"}}
<main>
<div class="tree">
{{ $linkstyle := "no-underline hover:underline" }}
<div class="pb-2 mb-3 text-base border-b border-gray-200 dark:border-gray-700">
···
</div>
{{ range .Files }}
+
<div class="grid grid-cols-12 gap-4 items-center py-1">
+
<div class="col-span-6 md:col-span-3">
+
{{ $link := printf "/%s/%s/%s/%s/%s" $.RepoInfo.FullName "tree" (urlquery $.Ref) $.TreePath .Name }}
+
{{ $icon := "folder" }}
+
{{ $iconStyle := "size-4 fill-current" }}
+
+
{{ if .IsFile }}
+
{{ $icon = "file" }}
+
{{ $iconStyle = "size-4" }}
+
{{ end }}
+
<a href="{{ $link }}" class="{{ $linkstyle }}">
+
<div class="flex items-center gap-2">
+
{{ i $icon $iconStyle }}{{ .Name }}
</div>
+
</a>
</div>
+
<div class="col-span-0 md:col-span-7 hidden md:block overflow-hidden">
+
{{ with .LastCommit }}
+
<a href="/{{ $.RepoInfo.FullName }}/commit/{{ .Hash }}" class="text-gray-500 dark:text-gray-400 block truncate">{{ .Message }}</a>
+
{{ end }}
+
</div>
+
+
<div class="col-span-6 md:col-span-2 text-right">
+
{{ with .LastCommit }}
+
<a href="/{{ $.RepoInfo.FullName }}/commit/{{ .Hash }}" class="text-gray-500 dark:text-gray-400">{{ template "repo/fragments/time" .When }}</a>
+
{{ end }}
</div>
+
</div>
{{ end }}
+
</div>
</main>
{{end}}
+3 -3
appview/pages/templates/user/repos.html
···
{{ end }}
{{ define "content" }}
-
<div class="grid grid-cols-1 md:grid-cols-8 gap-4">
-
<div class="md:col-span-2 order-1 md:order-1">
{{ template "user/fragments/profileCard" .Card }}
</div>
-
<div id="all-repos" class="md:col-span-6 order-2 md:order-2">
{{ block "ownRepos" . }}{{ end }}
</div>
</div>
···
{{ end }}
{{ define "content" }}
+
<div class="grid grid-cols-1 md:grid-cols-11 gap-4">
+
<div class="md:col-span-3 order-1 md:order-1">
{{ template "user/fragments/profileCard" .Card }}
</div>
+
<div id="all-repos" class="md:col-span-8 order-2 md:order-2">
{{ block "ownRepos" . }}{{ end }}
</div>
</div>
+2
appview/repo/index.go
···
tagMap[hash] = append(tagMap[hash], branch.Name)
}
slices.SortFunc(result.Branches, func(a, b types.Branch) int {
if a.Name == result.Ref {
return -1
···
tagMap[hash] = append(tagMap[hash], branch.Name)
}
+
sortFiles(result.Files)
+
slices.SortFunc(result.Branches, func(a, b types.Branch) int {
if a.Name == result.Ref {
return -1
+7 -28
appview/repo/repo.go
···
"log"
"net/http"
"net/url"
-
"path"
"slices"
-
"sort"
"strconv"
"strings"
"time"
···
// redirects tree paths trying to access a blob; in this case the result.Files is unpopulated,
// so we can safely redirect to the "parent" (which is the same file).
-
if len(result.Files) == 0 && result.Parent == treePath {
http.Redirect(w, r, fmt.Sprintf("/%s/blob/%s/%s", f.OwnerSlashRepo(), ref, result.Parent), http.StatusFound)
return
}
···
}
}
-
baseTreeLink := path.Join(f.OwnerSlashRepo(), "tree", ref, treePath)
-
baseBlobLink := path.Join(f.OwnerSlashRepo(), "blob", ref, treePath)
rp.pages.RepoTree(w, pages.RepoTreeParams{
LoggedInUser: user,
BreadCrumbs: breadcrumbs,
-
BaseTreeLink: baseTreeLink,
-
BaseBlobLink: baseBlobLink,
RepoInfo: f.RepoInfo(user),
RepoTreeResponse: result,
})
-
return
}
func (rp *Repo) RepoTags(w http.ResponseWriter, r *http.Request) {
···
return
}
-
slices.SortFunc(result.Branches, func(a, b types.Branch) int {
-
if a.IsDefault {
-
return -1
-
}
-
if b.IsDefault {
-
return 1
-
}
-
if a.Commit != nil && b.Commit != nil {
-
if a.Commit.Committer.When.Before(b.Commit.Committer.When) {
-
return 1
-
} else {
-
return -1
-
}
-
}
-
return strings.Compare(a.Name, b.Name) * -1
-
})
user := rp.oauth.GetUser(r)
rp.pages.RepoBranches(w, pages.RepoBranchesParams{
···
RepoInfo: f.RepoInfo(user),
RepoBranchesResponse: *result,
})
-
return
}
func (rp *Repo) RepoBlob(w http.ResponseWriter, r *http.Request) {
···
return
}
branches := result.Branches
-
sort.Slice(branches, func(i int, j int) bool {
-
return branches[i].Commit.Committer.When.After(branches[j].Commit.Committer.When)
-
})
var defaultBranch string
for _, b := range branches {
···
"log"
"net/http"
"net/url"
"slices"
"strconv"
"strings"
"time"
···
// redirects tree paths trying to access a blob; in this case the result.Files is unpopulated,
// so we can safely redirect to the "parent" (which is the same file).
+
unescapedTreePath, _ := url.PathUnescape(treePath)
+
if len(result.Files) == 0 && result.Parent == unescapedTreePath {
http.Redirect(w, r, fmt.Sprintf("/%s/blob/%s/%s", f.OwnerSlashRepo(), ref, result.Parent), http.StatusFound)
return
}
···
}
}
+
sortFiles(result.Files)
rp.pages.RepoTree(w, pages.RepoTreeParams{
LoggedInUser: user,
BreadCrumbs: breadcrumbs,
+
TreePath: treePath,
RepoInfo: f.RepoInfo(user),
RepoTreeResponse: result,
})
}
func (rp *Repo) RepoTags(w http.ResponseWriter, r *http.Request) {
···
return
}
+
sortBranches(result.Branches)
user := rp.oauth.GetUser(r)
rp.pages.RepoBranches(w, pages.RepoBranchesParams{
···
RepoInfo: f.RepoInfo(user),
RepoBranchesResponse: *result,
})
}
func (rp *Repo) RepoBlob(w http.ResponseWriter, r *http.Request) {
···
return
}
branches := result.Branches
+
+
sortBranches(branches)
var defaultBranch string
for _, b := range branches {
+34
appview/repo/repo_util.go
···
"crypto/rand"
"fmt"
"math/big"
"tangled.sh/tangled.sh/core/appview/db"
"tangled.sh/tangled.sh/core/appview/pages/repoinfo"
"github.com/go-git/go-git/v5/plumbing/object"
)
func uniqueEmails(commits []*object.Commit) []string {
emails := make(map[string]struct{})
···
"crypto/rand"
"fmt"
"math/big"
+
"slices"
+
"sort"
+
"strings"
"tangled.sh/tangled.sh/core/appview/db"
"tangled.sh/tangled.sh/core/appview/pages/repoinfo"
+
"tangled.sh/tangled.sh/core/types"
"github.com/go-git/go-git/v5/plumbing/object"
)
+
+
func sortFiles(files []types.NiceTree) {
+
sort.Slice(files, func(i, j int) bool {
+
iIsFile := files[i].IsFile
+
jIsFile := files[j].IsFile
+
if iIsFile != jIsFile {
+
return !iIsFile
+
}
+
return files[i].Name < files[j].Name
+
})
+
}
+
+
func sortBranches(branches []types.Branch) {
+
slices.SortFunc(branches, func(a, b types.Branch) int {
+
if a.IsDefault {
+
return -1
+
}
+
if b.IsDefault {
+
return 1
+
}
+
if a.Commit != nil && b.Commit != nil {
+
if a.Commit.Committer.When.Before(b.Commit.Committer.When) {
+
return 1
+
} else {
+
return -1
+
}
+
}
+
return strings.Compare(a.Name, b.Name)
+
})
+
}
func uniqueEmails(commits []*object.Commit) []string {
emails := make(map[string]struct{})