Monorepo for Tangled
0

Configure Feed

Select the types of activity you want to include in your feed.

appview/repo/search: improve ui/ux

- use an `<input>` instead of a `<button>`
- add support for `?q=%s` in `repo/search`
- show empty state message with query examples
- consistent `search-code` icon accross `repo/search` and `repo`
overview to distinguish from global search

resolves
[TAN-534](https://linear.app/tangled/issue/TAN-534/reposearch-nitpicks-and-reworks)

Signed-off-by: eti <eti@eti.tf>

authored by

eti and committed by
Tangled
(Jun 29, 2026, 11:21 PM +0300) 3d339179 7baee08a

+44 -9
+1
appview/pages/pages.go
··· 943 943 } 944 944 945 945 type RepoSearchResultsFragmentParams struct { 946 + Query string 946 947 Results []SearchResult 947 948 ErrorMsg string 948 949 }
+17
appview/pages/templates/repo/fragments/searchResults.html
··· 5 5 {{ i "circle-alert" "size-4" }} 6 6 <span>{{ .ErrorMsg }}</span> 7 7 </div> 8 + {{ else if not .Query }} 9 + {{ template "searchEmptyState" }} 8 10 {{ else }} 9 11 {{ range .Results }} 10 12 {{ template "resultCard" . }} ··· 15 17 {{ end }} 16 18 {{ end }} 17 19 </div> 20 + {{ end }} 21 + 22 + {{ define "searchEmptyState" }} 23 + {{ $code := "px-1 py-0.5 bg-gray-100 dark:bg-gray-700 rounded text-xs font-mono" }} 24 + <div class="flex flex-col items-center text-center gap-3 p-12 border border-gray-200 dark:border-gray-700 rounded"> 25 + <span class="text-gray-400 dark:text-gray-500">{{ i "search-code" "size-8" }}</span> 26 + <p class="text-base text-gray-500 dark:text-gray-400">Enter a search term above to find files or code in this repository.</p> 27 + <p class="text-sm text-gray-500 dark:text-gray-400 max-w-md"> 28 + Type any text to match file contents, or narrow your search with 29 + <code class="{{ $code }}">lang:go</code>, 30 + <code class="{{ $code }}">file:readme</code>, 31 + <code class="{{ $code }}">sym:functionName</code>, or 32 + <code class="{{ $code }}">case:yes</code>. 33 + </p> 34 + </div> 18 35 {{ end }} 19 36 20 37 {{ define "resultCard" }}
+21 -6
appview/pages/templates/repo/index.html
··· 12 12 {{ if .Languages }} 13 13 {{ block "repoLanguages" . }}{{ end }} 14 14 {{ end }} 15 - <div class="flex items-center justify-between pb-5"> 15 + <div class="flex flex-wrap items-center justify-between gap-3 pb-5"> 16 16 {{ block "branchSelector" . }}{{ end }} 17 + <form id="search-form" class="relative flex items-center h-[32px] order-last w-full md:order-none md:w-64" method="GET" action="/{{ .RepoInfo.FullName }}/search"> 18 + <span class="absolute left-2 top-1/2 -translate-y-1/2 text-gray-400 pointer-events-none"> 19 + {{ i "search-code" "w-4 h-4" }} 20 + </span> 21 + <input 22 + id="search-q" 23 + class="w-full h-full py-1 pl-8 pr-8 peer" 24 + type="search" 25 + name="q" 26 + placeholder="Find files or code..." 27 + > 28 + <button 29 + type="button" 30 + onclick="const i=document.getElementById('search-q');i.value='';i.focus();" 31 + class="absolute right-2 top-1/2 -translate-y-1/2 text-gray-400 hover:text-gray-600 dark:hover:text-gray-300 hidden peer-[:not(:placeholder-shown)]:block" 32 + > 33 + {{ i "x" "w-4 h-4" }} 34 + </button> 35 + </form> 17 36 <div class="flex items-center gap-3"> 18 37 <a href="/{{ .RepoInfo.FullName }}/commits/{{ .Ref | urlquery }}" class="inline-flex md:hidden items-center text-sm gap-1 font-bold"> 19 38 {{ i "git-commit-horizontal" "w-4" "h-4" }} {{ scaleFmt .TotalCommits }} ··· 23 42 </a> 24 43 <a href="/{{ .RepoInfo.FullName }}/tags" class="inline-flex md:hidden items-center text-sm gap-1 font-bold"> 25 44 {{ i "tags" "w-4" "h-4" }} {{ scaleFmt (len .Tags) }} 26 - </a> 27 - <a href="/{{ .RepoInfo.FullName }}/search" class="btn"> 28 - {{ i "search" "size-4" }} 29 45 </a> 30 46 {{ template "repo/fragments/cloneDropdown" . }} 31 47 </div> ··· 68 84 {{ end }} 69 85 70 86 {{ define "branchSelector" }} 71 - <div class="flex gap-2 items-center justify-between w-full"> 87 + <div class="flex gap-2 items-center justify-between flex-1 min-w-0"> 72 88 <div class="flex gap-2 items-stretch"> 73 89 <select 74 90 onchange="window.location.href = '/{{ .RepoInfo.FullName }}/tree/' + encodeURIComponent(this.value)" ··· 365 381 {{ template "repo/fragments/readme" . }} 366 382 {{- end -}} 367 383 {{ end }} 368 -
+3 -2
appview/pages/templates/repo/search.html
··· 16 16 <input 17 17 type="text" 18 18 name="q" 19 - value="" 19 + value="{{ .FilterQuery }}" 20 20 placeholder="Find files or code" 21 21 hx-get="" 22 - hx-trigger="input changed delay:100ms from:input" 22 + hx-trigger="{{ if .FilterQuery }}load, {{ end }}input changed delay:100ms from:input" 23 23 hx-target="#repo-files" 24 24 hx-swap="outerHTML" 25 + autofocus 25 26 class="font-mono flex-1 py-1 pl-8 pr-2 peer" 26 27 > 27 28 </div>
+2 -1
appview/repo/filesearch.go
··· 23 23 if err := rp.pages.RepoSearchPage(w, pages.RepoSearchParams{ 24 24 BaseParams: pages.BaseParamsFromContext(r.Context()), 25 25 RepoInfo: rp.repoResolver.GetRepoInfo(r, rp.oauth.GetMultiAccountUser(r)), 26 - FilterQuery: "", 26 + FilterQuery: r.URL.Query().Get("q"), 27 27 }); err != nil { 28 28 rp.logger.Error("failed to render", "err", err) 29 29 } ··· 39 39 q := r.URL.Query().Get("q") 40 40 41 41 var params pages.RepoSearchResultsFragmentParams 42 + params.Query = q 42 43 defer func() { 43 44 if err := rp.pages.RepoSearchResultsFragment(w, params); err != nil { 44 45 l.Error("failed to render", "err", err)