This repository has no description
0

Configure Feed

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

core / appview / pages / templates / layouts / fragments / topbar.html
9.9 kB 225 lines
1{{ define "layouts/fragments/topbar" }} 2 <nav class="mx-auto space-x-4 px-6 py-2"> 3 <div class="flex justify-between p-0 items-center"> 4 <div id="left-items"> 5 <a href="/" hx-boost="true" class="text-2xl no-underline hover:no-underline flex items-center gap-2"> 6 <span class="hidden sm:inline-flex">{{ template "fragments/logotypeSmall" }}</span> 7 <span class="inline-flex sm:hidden">{{ template "fragments/dolly/logo" (dict "Classes" "size-8" ) }}</span> 8 </a> 9 </div> 10 11 <div id="right-items" class="flex items-center gap-4"> 12 {{ with .LoggedInUser }} 13 <div class="flex items-center order-1 md:order-3">{{ block "newButton" . }} {{ end }}</div> 14 <div class="flex items-center order-2 md:order-4">{{ template "notifications/fragments/bell" }}</div> 15 <div class="flex items-center order-3 md:order-1">{{ block "search" . }} {{ end }}</div> 16 <div class="hidden md:block md:order-2 w-px h-6 bg-gray-200 dark:bg-gray-700 self-center"></div> 17 <div class="flex items-center order-4 md:order-5">{{ block "profileDropdown" . }} {{ end }}</div> 18 {{ else }} 19 <a href="/login">Login</a> 20 <span class="text-gray-500 dark:text-gray-400">or</span> 21 <a href="/signup" class="btn-create py-0 hover:no-underline hover:text-white flex items-center gap-2"> 22 Join now {{ i "arrow-right" "size-4" }} 23 </a> 24 {{ end }} 25 </div> 26 </div> 27 </nav> 28{{ end }} 29 30{{ define "newButton" }} 31<details class="relative inline-block text-left nav-dropdown"> 32 <summary class="btn py-0 cursor-pointer list-none flex items-center gap-2"> 33 {{ i "plus" "w-4 h-4" }} <span class="hidden md:inline">New</span> 34 </summary> 35 <div class="absolute flex flex-col right-0 mt-3 p-4 rounded w-48 bg-white dark:bg-gray-800 dark:text-white border border-gray-200 dark:border-gray-700"> 36 <a href="/repo/new" class="flex items-center gap-2"> 37 {{ i "book-plus" "w-4 h-4" }} 38 New repository 39 </a> 40 <a href="/strings/new" class="flex items-center gap-2"> 41 {{ i "line-squiggle" "w-4 h-4" }} 42 New string 43 </a> 44 </div> 45</details> 46{{ end }} 47 48{{ define "search" }} 49<div class="relative hidden md:block" id="topbar-search-container"> 50 <div id="topbar-search-box" class="relative flex items-center gap-2 px-2 pr-1.5 py-4 max-h-[30px] md:w-80 lg:w-96 border border-gray-200 dark:border-gray-700 rounded bg-white dark:bg-gray-900 focus-within:z-[51] before:content-[''] before:absolute before:inset-0 before:rounded-md before:invisible focus-within:before:visible before:ring-2 before:ring-transparent before:ring-offset-transparent before:ring-offset-1 before:pointer-events-none focus-within:before:ring-gray-300 dark:focus-within:before:ring-gray-600"> 51 {{ i "search" "size-4 text-gray-400" }} 52 <input 53 type="text" 54 id="topbar-search-input" 55 name="q" 56 placeholder="Search..." 57 autocomplete="off" 58 class="flex-1 border-none bg-transparent p-0 focus:outline-none focus:[box-shadow:none] text-sm text-gray-800 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-600 peer" 59 hx-get="/search/quick" 60 hx-trigger="input changed delay:10ms" 61 hx-target="#topbar-search-results" 62 hx-swap="innerHTML" 63 hx-indicator="#topbar-search-indicator" 64 /> 65 <kbd id="search-kbd" class="pointer-events-none flex items-center text-xs border border-gray-200 dark:border-gray-600 rounded border-b-2 px-1 font-sans leading-5 text-gray-400 dark:text-gray-500 peer-focus:hidden peer-[:not(:placeholder-shown)]:hidden"></kbd> 66 <script> 67 (function() { 68 var kbd = document.getElementById('search-kbd'); 69 if (!kbd) return; 70 var ua = navigator.userAgent; 71 var isMobile = /Mobi|Android|iPhone|iPad|iPod/i.test(ua); 72 if (isMobile) { 73 kbd.style.display = 'none'; 74 } else if (/Macintosh|Mac OS X/.test(ua)) { 75 kbd.textContent = '⌘K'; 76 } else { 77 kbd.textContent = 'Ctrl+K'; 78 } 79 })(); 80 </script> 81 <span id="topbar-search-indicator" class="shrink-0"> 82 {{ i "loader-circle" "size-4 text-gray-400 animate-spin" }} 83 </span> 84 <button 85 type="button" 86 class="hidden peer-[:not(:placeholder-shown)]:block text-gray-400 hover:text-gray-600 dark:hover:text-gray-300" 87 onclick="const i=document.getElementById('topbar-search-input');i.value='';htmx.trigger(i,'input');i.focus()" 88 >{{ i "x" "size-4" }}</button> 89 </div> 90 <div id="topbar-search-results" class="absolute w-full z-50"></div> 91</div> 92 93<button id="mobile-search-btn" class="md:hidden" type="button" data-action="open-mobile-search"> 94 {{ i "search" "size-5 text-gray-500 dark:text-gray-400" }} 95</button> 96 97<div id="mobile-search-overlay" 98 class="md:hidden fixed inset-x-0 top-0 h-dvh z-50 99 bg-white dark:bg-gray-900 100 flex flex-col 101 opacity-0 pointer-events-none 102 transition-opacity duration-150 103 pt-[env(safe-area-inset-top)]" 104 aria-hidden="true"> 105 <div class="flex items-center gap-3 px-4 py-3 border-b border-gray-200 dark:border-gray-700 shrink-0"> 106 {{ i "search" "size-4 text-gray-400 shrink-0" }} 107 <input 108 type="text" 109 id="mobile-search-input" 110 name="q" 111 placeholder="Search..." 112 autocomplete="off" 113 inputmode="search" 114 class="flex-1 min-w-0 border-none bg-transparent p-0 focus:outline-none focus:[box-shadow:none] text-[16px] text-gray-800 dark:text-gray-200 placeholder-gray-400 dark:placeholder-gray-600 peer" 115 hx-get="/search/quick/mobile" 116 hx-trigger="input changed delay:10ms" 117 hx-target="#mobile-search-results" 118 hx-swap="innerHTML" 119 hx-indicator="#mobile-search-indicator" 120 /> 121 <span id="mobile-search-indicator" class="shrink-0"> 122 {{ i "loader-circle" "size-4 text-gray-400 animate-spin" }} 123 </span> 124 <button type="button" class="p-1 -mr-1 hit-area hit-area-4" data-action="close-mobile-search"> 125 {{ i "x" "size-5 text-gray-400" }} 126 </button> 127 </div> 128 <div id="mobile-search-results" class="flex-1 flex flex-col overflow-hidden pb-[env(safe-area-inset-bottom)]"></div> 129 <div id="mobile-search-spacer" class="bg-gray-50 dark:bg-gray-800 hidden"></div> 130</div> 131<style> 132 #topbar-search-indicator, 133 #mobile-search-indicator { 134 display: none; 135 opacity: 0; 136 transition-property: opacity, display; 137 transition-duration: 150ms, 150ms; 138 transition-timing-function: ease-out; 139 transition-behavior: allow-discrete; 140 } 141 #topbar-search-indicator.htmx-request, 142 #mobile-search-indicator.htmx-request { 143 display: block; 144 opacity: 1; 145 transition-duration: 0s, 0s; 146 } 147</style> 148{{ end }} 149 150{{ define "profileDropdown" }} 151{{ $handle := resolve .Did }} 152<details class="relative inline-block text-left nav-dropdown"> 153 <summary class="cursor-pointer list-none flex items-center gap-1"> 154 {{ template "user/fragments/pic" (list .Did "size-8 md:size-6") }} 155 <span class="hidden md:inline">{{ $handle | truncateAt30 }}</span> 156 </summary> 157 <div class="absolute right-0 mt-4 rounded bg-white dark:bg-gray-800 dark:text-white border border-gray-200 dark:border-gray-700 shadow-lg z-50 text-sm" style="width: 14rem;"> 158 {{ $linkStyle := "flex items-center gap-3 px-4 py-2 hover:no-underline hover:bg-gray-50 hover:dark:bg-gray-700/50" }} 159 160 {{ $others := .Accounts | otherAccounts .Did }} 161 {{ if $others }} 162 <div class="text-sm text-gray-500 dark:text-gray-400 px-3 py-1 pt-2">Switch account</div> 163 {{ range $others }} 164 <button 165 type="button" 166 hx-post="/account/switch" 167 hx-vals='{"did": "{{ .Did }}"}' 168 hx-swap="none" 169 class="{{$linkStyle}} w-full text-left pl-3" 170 > 171 {{ template "user/fragments/pic" (list .Did "size-6") }} 172 <span class="truncate flex-1">{{ .Did | resolve }}</span> 173 </button> 174 {{ end }} 175 {{ end }} 176 177 <a href="/login?mode=add_account" class="{{$linkStyle}} pl-3"> 178 <div class="size-6 rounded-full bg-gray-100 dark:bg-gray-700 flex items-center justify-center"> 179 {{ i "plus" "size-3" }} 180 </div> 181 182 <div class="text-left flex-1 min-w-0 block truncate"> 183 Add account 184 </div> 185 </a> 186 187 <div class="border-t border-gray-200 dark:border-gray-700"> 188 <a href="/{{ $handle }}" class="{{$linkStyle}}"> 189 {{ i "user" "size-4" }} 190 Profile 191 </a> 192 <a href="/{{ $handle }}?tab=repos" class="{{$linkStyle}}"> 193 {{ i "book-marked" "size-4" }} 194 Repositories 195 </a> 196 <a href="/{{ $handle }}?tab=strings" class="{{$linkStyle}}"> 197 {{ i "line-squiggle" "size-4" }} 198 Strings 199 </a> 200 <a href="/settings" class="{{$linkStyle}}"> 201 {{ i "cog" "size-4" }} 202 Settings 203 </a> 204 <a href="#" 205 hx-post="/logout" 206 hx-swap="none" 207 class="{{$linkStyle}} text-red-400 hover:text-red-400 hover:bg-red-100 dark:hover:bg-red-700/20 pb-2"> 208 {{ i "log-out" "size-4" }} 209 Logout 210 </a> 211 </div> 212 </div> 213</details> 214 215<script> 216document.addEventListener('click', function(event) { 217 const dropdowns = document.querySelectorAll('.nav-dropdown'); 218 dropdowns.forEach(function(dropdown) { 219 if (!dropdown.contains(event.target)) { 220 dropdown.removeAttribute('open'); 221 } 222 }); 223}); 224</script> 225{{ end }}