Compare commits

...

3 Commits

Author SHA1 Message Date
jolheiser 9030c27f00
fix: minor correction for non-chroma pre/code blocks
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2024-05-24 22:29:44 -05:00
jolheiser f93238ae57
feat: move search to topbar and no result indicator
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2024-05-24 21:31:35 -05:00
jolheiser fdbe918ef4
docs: update email
Signed-off-by: jolheiser <john.olheiser@gmail.com>
2024-05-24 21:08:39 -05:00
9 changed files with 60 additions and 48 deletions

View File

@ -10,7 +10,7 @@ Minimal git server
ugit allows cloning via HTTPS/SSH, but can only be pushed to via SSH. ugit allows cloning via HTTPS/SSH, but can only be pushed to via SSH.
There are no plans to directly support issues or PR workflows, although webhooks are planned and auxillary software may be created to facilitate these things. There are no plans to directly support issues or PR workflows, although webhooks are planned and auxillary software may be created to facilitate these things.
For now, if you wish to collaborate, please send me patches at [john+ugit@jolheiser.com](mailto:john+ugit@jolheiser.com). For now, if you wish to collaborate, please send me patches at [ugit@jolheiser.com](mailto:git@jolheiser.com).
Currently all HTML is allowed in markdown, ugit is intended to be run by/for a trusted user. Currently all HTML is allowed in markdown, ugit is intended to be run by/for a trusted user.

View File

@ -1,7 +1,7 @@
package html package html
type BaseContext struct { type BaseContext struct {
Title string Title string
Description string Description string
} }
@ -23,4 +23,3 @@ templ base(bc BaseContext) {
</body> </body>
</html> </html>
} }

View File

@ -3,6 +3,11 @@
color: rgb(var(--ctp-text)); color: rgb(var(--ctp-text));
} }
.markdown code,
.markdown pre {
background-color: rgb(var(--ctp-base));
}
.markdown a { .markdown a {
color: rgb(var(--ctp-blue)); color: rgb(var(--ctp-blue));
text-decoration-line: underline; text-decoration-line: underline;

View File

@ -3,10 +3,10 @@ package html
import "fmt" import "fmt"
type RepoHeaderComponentContext struct { type RepoHeaderComponentContext struct {
Name string Name string
Ref string Ref string
Description string Description string
CloneURL string CloneURL string
} }
templ repoHeaderComponent(rhcc RepoHeaderComponentContext) { templ repoHeaderComponent(rhcc RepoHeaderComponentContext) {
@ -21,10 +21,9 @@ templ repoHeaderComponent(rhcc RepoHeaderComponentContext) {
{ " - " } { " - " }
<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/log/%s", rhcc.Name, rhcc.Ref)) }>log</a> <a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/log/%s", rhcc.Name, rhcc.Ref)) }>log</a>
{ " - " } { " - " }
<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/search", rhcc.Name)) }>search</a> <form class="inline-block" action={ templ.SafeURL(fmt.Sprintf("/%s/search", rhcc.Name)) } method="get"><input class="rounded p-1 bg-mantle focus:border-lavender focus:outline-none focus:ring-0" id="search" type="text" name="q" placeholder="search"/></form>
{ " - " } { " - " }
<pre class="text-text inline select-all bg-base dark:bg-base/50 p-1 rounded">{ fmt.Sprintf("%s/%s.git", rhcc.CloneURL, rhcc.Name) }</pre> <pre class="text-text inline select-all bg-base dark:bg-base/50 p-1 rounded">{ fmt.Sprintf("%s/%s.git", rhcc.CloneURL, rhcc.Name) }</pre>
</div> </div>
<div class="text-text/80 mb-1">{ rhcc.Description }</div> <div class="text-text/80 mb-1">{ rhcc.Description }</div>
} }

View File

@ -4,7 +4,7 @@ import "fmt"
import "go.jolheiser.com/ugit/internal/git" import "go.jolheiser.com/ugit/internal/git"
type SearchContext struct { type SearchContext struct {
BaseContext BaseContext
RepoHeaderComponentContext RepoHeaderComponentContext
Results []git.GrepResult Results []git.GrepResult
} }
@ -33,10 +33,12 @@ func (s SearchContext) DedupeResults() [][]git.GrepResult {
templ RepoSearch(sc SearchContext) { templ RepoSearch(sc SearchContext) {
@base(sc.BaseContext) { @base(sc.BaseContext) {
@repoHeaderComponent(sc.RepoHeaderComponentContext) @repoHeaderComponent(sc.RepoHeaderComponentContext)
<form method="get"><label class="text-text">Search <input class="rounded p-1 mt-2 bg-mantle focus:border-lavender focus:outline-none focus:ring-0" id="search" type="text" name="q" placeholder="search"/></label></form>
for _, results := range sc.DedupeResults() { for _, results := range sc.DedupeResults() {
@repoSearchResult(sc.RepoHeaderComponentContext.Name, sc.RepoHeaderComponentContext.Ref, results) @repoSearchResult(sc.RepoHeaderComponentContext.Name, sc.RepoHeaderComponentContext.Ref, results)
} }
if len(sc.DedupeResults()) == 0 {
<p class="text-text mt-5 text-lg">No results</p>
}
} }
<script> <script>
const search = new URLSearchParams(window.location.search).get("q"); const search = new URLSearchParams(window.location.search).get("q");
@ -46,15 +48,18 @@ templ RepoSearch(sc SearchContext) {
templ repoSearchResult(repo, ref string, results []git.GrepResult) { templ repoSearchResult(repo, ref string, results []git.GrepResult) {
<div class="text-text mt-5"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, results[0].File, results[0].Line)) }>{ results[0].File }</a></div> <div class="text-text mt-5"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, results[0].File, results[0].Line)) }>{ results[0].File }</a></div>
<div class="code">@templ.Raw(results[0].Content)</div> <div class="code">
@templ.Raw(results[0].Content)
</div>
if len(results) > 1 { if len(results) > 1 {
<details class="text-text cursor-pointer"> <details class="text-text cursor-pointer">
<summary>{ fmt.Sprintf("%d ", len(results[1:])) }more</summary> <summary>{ fmt.Sprintf("%d ", len(results[1:])) }more</summary>
for _, result := range results[1:] { for _, result := range results[1:] {
<div class="text-text mt-5 ml-5"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, result.File, result.Line)) }>{ results[0].File }</a></div> <div class="text-text mt-5 ml-5"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, result.File, result.Line)) }>{ results[0].File }</a></div>
<div class="code ml-5">@templ.Raw(result.Content)</div> <div class="code ml-5">
@templ.Raw(result.Content)
</div>
} }
</details> </details>
} }
} }

View File

@ -63,16 +63,7 @@ func RepoSearch(sc SearchContext) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <form method=\"get\"><label class=\"text-text\">") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var3 := `Search `
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<input class=\"rounded p-1 mt-2 bg-mantle focus:border-lavender focus:outline-none focus:ring-0\" id=\"search\" type=\"text\" name=\"q\" placeholder=\"search\"></label></form>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -82,6 +73,25 @@ func RepoSearch(sc SearchContext) templ.Component {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
if len(sc.DedupeResults()) == 0 {
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<p class=\"text-text mt-5 text-lg\">")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
templ_7745c5c3_Var3 := `No results`
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var3)
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</p>")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
}
if !templ_7745c5c3_IsBuffer { if !templ_7745c5c3_IsBuffer {
_, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer) _, templ_7745c5c3_Err = io.Copy(templ_7745c5c3_W, templ_7745c5c3_Buffer)
} }
@ -143,7 +153,7 @@ func repoSearchResult(repo, ref string, results []git.GrepResult) templ.Componen
var templ_7745c5c3_Var7 string var templ_7745c5c3_Var7 string
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File) templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 47, Col: 230} return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 49, Col: 230}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -169,7 +179,7 @@ func repoSearchResult(repo, ref string, results []git.GrepResult) templ.Componen
var templ_7745c5c3_Var8 string var templ_7745c5c3_Var8 string
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d ", len(results[1:]))) templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d ", len(results[1:])))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 51, Col: 50} return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 55, Col: 50}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
@ -201,7 +211,7 @@ func repoSearchResult(repo, ref string, results []git.GrepResult) templ.Componen
var templ_7745c5c3_Var11 string var templ_7745c5c3_Var11 string
templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File) templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 53, Col: 230} return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 57, Col: 230}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {

View File

@ -166,7 +166,7 @@ func repoHeaderComponent(rhcc RepoHeaderComponentContext) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(" <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("<form class=\"inline-block\" action=\"")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -175,25 +175,16 @@ func repoHeaderComponent(rhcc RepoHeaderComponentContext) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\">") _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("\" method=\"get\"><input class=\"rounded p-1 bg-mantle focus:border-lavender focus:outline-none focus:ring-0\" id=\"search\" type=\"text\" name=\"q\" placeholder=\"search\"></form>")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
templ_7745c5c3_Var15 := `search` var templ_7745c5c3_Var15 string
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ_7745c5c3_Var15) templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(" - ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString("</a> ")
if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err
}
var templ_7745c5c3_Var16 string
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(" - ")
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 24, Col: 9} return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 24, Col: 9}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -201,12 +192,12 @@ func repoHeaderComponent(rhcc RepoHeaderComponentContext) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var17 string var templ_7745c5c3_Var16 string
templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s/%s.git", rhcc.CloneURL, rhcc.Name)) templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s/%s.git", rhcc.CloneURL, rhcc.Name))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 25, Col: 131} return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 25, Col: 131}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
@ -214,12 +205,12 @@ func repoHeaderComponent(rhcc RepoHeaderComponentContext) templ.Component {
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }
var templ_7745c5c3_Var18 string var templ_7745c5c3_Var17 string
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(rhcc.Description) templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinStringErrs(rhcc.Description)
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 27, Col: 50} return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 27, Col: 50}
} }
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17))
if templ_7745c5c3_Err != nil { if templ_7745c5c3_Err != nil {
return templ_7745c5c3_Err return templ_7745c5c3_Err
} }

File diff suppressed because one or more lines are too long

View File

@ -71,6 +71,9 @@ func (rh repoHandler) repoTree(ref, path string) http.HandlerFunc {
func (rh repoHandler) repoFile(w http.ResponseWriter, r *http.Request, repo *git.Repo, ref, path string) error { func (rh repoHandler) repoFile(w http.ResponseWriter, r *http.Request, repo *git.Repo, ref, path string) error {
content, err := repo.FileContent(ref, path) content, err := repo.FileContent(ref, path)
if err != nil { if err != nil {
if errors.Is(err, object.ErrFileNotFound) {
return httperr.Status(err, http.StatusNotFound)
}
return httperr.Error(err) return httperr.Error(err)
} }