base.html
·
524 lines
·
31.2 KB
| 1 | <!DOCTYPE html> |
| 2 | <html lang="{{.Lang}}" data-theme="{{if .Theme}}{{.Theme}}{{else}}system{{end}}" data-copied-text="{{t .Lang "common.copied"}}" data-copy-failed-text="{{t .Lang "common.copy_failed"}}" data-shortcut-unavailable="{{t .Lang "shortcuts.unavailable"}}"> |
| 3 | <head> |
| 4 | <meta charset="utf-8"> |
| 5 | <meta name="viewport" content="width=device-width, initial-scale=1"> |
| 6 | <link rel="icon" type="image/svg+xml" href="/static/favicon.svg"> |
| 7 | <title>{{if .Title}}{{.Title}} · Polar{{else}}Polar{{end}}</title> |
| 8 | <meta name="description" content="{{t .Lang "app.tagline"}}"> |
| 9 | <script> |
| 10 | (function(){ |
| 11 | try { |
| 12 | var saved = localStorage.getItem('polar_theme'); |
| 13 | if (saved && ['light','dark','system'].indexOf(saved) !== -1) { |
| 14 | document.documentElement.setAttribute('data-theme', saved); |
| 15 | } |
| 16 | var sb = localStorage.getItem('polar_sidebar'); |
| 17 | if (sb === 'collapsed') { |
| 18 | document.documentElement.setAttribute('data-sidebar', 'collapsed'); |
| 19 | } |
| 20 | } catch(e) {} |
| 21 | })(); |
| 22 | </script> |
| 23 | <style>{{inlineCSS}}</style> |
| 24 | <link rel="stylesheet" href="/static/css/app.css?v={{assetVer}}"> |
| 25 | </head> |
| 26 | <body{{if .CurrentUser}} data-current-user="{{.CurrentUser.Username}}"{{end}}{{if .Repo}} data-repo-path="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}" data-repo-can-write="{{if .CanWrite}}true{{else}}false{{end}}" data-repo-issues="{{if .Repo.EnableIssues}}true{{else}}false{{end}}" data-repo-pulls="{{if .Repo.EnablePulls}}true{{else}}false{{end}}" data-repo-releases="{{if .Repo.EnableReleases}}true{{else}}false{{end}}" data-repo-activity="{{if .Repo.EnableActivity}}true{{else}}false{{end}}"{{end}}> |
| 27 | {{sprite}} |
| 28 | {{$pageBackground := ""}} |
| 29 | {{with .ProfileUser}}{{$pageBackground = imageURL .BackgroundURL}}{{end}} |
| 30 | {{with .Repo}}{{$pageBackground = imageURL .BackgroundURL}}{{end}} |
| 31 | |
| 32 | <!-- Floating button to expand sidebar when collapsed --> |
| 33 | <button type="button" class="sidebar-expand-btn" data-toggle-sidebar title="{{t .Lang "nav.toggle_sidebar"}} (Ctrl+B)" aria-label="{{t .Lang "nav.toggle_sidebar"}}"> |
| 34 | {{icon "sidebar" "size-4"}} |
| 35 | </button> |
| 36 | |
| 37 | <div class="app-shell"> |
| 38 | <!-- Left Sidebar --> |
| 39 | <aside class="app-sidebar" aria-label="Sidebar"> |
| 40 | <div class="sidebar-inner"> |
| 41 | <div class="flex flex-col gap-2 min-w-0"> |
| 42 | <!-- Brand, Language & Collapse Sidebar --> |
| 43 | <div class="flex items-center justify-between px-3 py-2" style="padding:0.25rem 0.35rem;"> |
| 44 | <a href="/" class="font-semibold text-base tracking-tight" style="letter-spacing:-0.02em;">Polar</a> |
| 45 | <div class="flex items-center gap-1"> |
| 46 | {{if eq .Lang "en"}} |
| 47 | <a href="?lang=ru" class="btn btn-ghost btn-sm font-mono" title="{{t .Lang "nav.lang"}}">RU</a> |
| 48 | {{else}} |
| 49 | <a href="?lang=en" class="btn btn-ghost btn-sm font-mono" title="{{t .Lang "nav.lang"}}">EN</a> |
| 50 | {{end}} |
| 51 | <button type="button" class="btn btn-ghost btn-icon" style="width:1.65rem;height:1.65rem;" data-toggle-sidebar title="{{t .Lang "nav.toggle_sidebar"}} (Ctrl+B)" aria-label="{{t .Lang "nav.toggle_sidebar"}}"> |
| 52 | {{icon "sidebar" "size-4"}} |
| 53 | </button> |
| 54 | </div> |
| 55 | </div> |
| 56 | |
| 57 | <!-- Search / Command Palette Trigger --> |
| 58 | <button type="button" class="btn btn-outline w-full justify-between text-muted" style="padding:0 0.55rem;height:1.95rem;" data-open-palette=""> |
| 59 | <span class="flex items-center gap-2 text-xs"> |
| 60 | {{icon "search" "size-3.5"}} |
| 61 | <span>{{t .Lang "nav.search_placeholder"}}</span> |
| 62 | </span> |
| 63 | <kbd class="kbd">⌘K</kbd> |
| 64 | </button> |
| 65 | |
| 66 | <!-- Primary Navigation --> |
| 67 | <nav class="flex flex-col gap-1 mt-1"> |
| 68 | <a href="/" class="nav-item"> |
| 69 | <span class="flex items-center gap-2">{{icon "home" "size-4"}} {{t .Lang "nav.home"}}</span> |
| 70 | </a> |
| 71 | {{if .ExploreEnabled}} |
| 72 | <a href="/explore" class="nav-item"> |
| 73 | <span class="flex items-center gap-2">{{icon "globe" "size-4"}} {{t .Lang "nav.explore"}}</span> |
| 74 | </a> |
| 75 | {{end}} |
| 76 | {{if .CurrentUser}} |
| 77 | <a href="/settings" class="nav-item"> |
| 78 | <span class="flex items-center gap-2">{{icon "settings" "size-4"}} {{t .Lang "nav.settings"}}</span> |
| 79 | </a> |
| 80 | {{if .CurrentUser.IsAdmin}} |
| 81 | <a href="/admin" class="nav-item"> |
| 82 | <span class="flex items-center gap-2">{{icon "shield" "size-4"}} {{t .Lang "nav.admin"}}</span> |
| 83 | </a> |
| 84 | {{end}} |
| 85 | {{end}} |
| 86 | </nav> |
| 87 | |
| 88 | </div> |
| 89 | |
| 90 | <!-- Sidebar Bottom: 3-Theme Switcher + Account --> |
| 91 | <div class="flex flex-col gap-2 pt-2" style="border-top:1px solid hsl(var(--border));"> |
| 92 | <div class="segmented" role="radiogroup" aria-label="{{t .Lang "nav.theme"}}"> |
| 93 | <button type="button" class="segmented-btn {{if eq .Theme "light"}}active{{end}}" data-set-theme="light" title="{{t .Lang "theme.light"}}"> |
| 94 | {{icon "sun" "size-3.5"}} |
| 95 | <span>{{t .Lang "theme.light"}}</span> |
| 96 | </button> |
| 97 | <button type="button" class="segmented-btn {{if eq .Theme "dark"}}active{{end}}" data-set-theme="dark" title="{{t .Lang "theme.dark"}}"> |
| 98 | {{icon "moon" "size-3.5"}} |
| 99 | <span>{{t .Lang "theme.dark"}}</span> |
| 100 | </button> |
| 101 | <button type="button" class="segmented-btn {{if eq .Theme "system"}}active{{end}}" data-set-theme="system" title="{{t .Lang "theme.system"}}"> |
| 102 | {{icon "laptop" "size-3.5"}} |
| 103 | <span>{{t .Lang "theme.system"}}</span> |
| 104 | </button> |
| 105 | </div> |
| 106 | |
| 107 | {{if .CurrentUser}} |
| 108 | <div class="flex items-center justify-between gap-1" style="padding:0.15rem 0.25rem;"> |
| 109 | <a href="/{{.CurrentUser.Username}}" class="flex items-center gap-2 min-w-0 truncate text-sm font-medium"> |
| 110 | {{avatar .CurrentUser.Username .CurrentUser.AvatarURL}} |
| 111 | <span class="truncate">{{.CurrentUser.Username}}</span> |
| 112 | </a> |
| 113 | <div class="flex items-center gap-1"> |
| 114 | <form method="post" action="/logout" style="margin:0;"> |
| 115 | <input type="hidden" name="_csrf" value="{{.CSRFToken}}"> |
| 116 | <button type="submit" class="btn btn-ghost btn-icon" style="width:1.65rem;height:1.65rem;" title="{{t .Lang "nav.logout"}}" aria-label="{{t .Lang "nav.logout"}}"> |
| 117 | {{icon "log-out" "size-3.5"}} |
| 118 | </button> |
| 119 | </form> |
| 120 | </div> |
| 121 | </div> |
| 122 | {{else}} |
| 123 | <div class="flex flex-col gap-1.5"> |
| 124 | <a href="/login" class="btn btn-outline btn-sm w-full">{{t .Lang "nav.login"}}</a> |
| 125 | {{if .RegistrationEnabled}} |
| 126 | <a href="/register" class="btn btn-primary btn-sm w-full">{{t .Lang "nav.register"}}</a> |
| 127 | {{end}} |
| 128 | </div> |
| 129 | {{end}} |
| 130 | <div style="padding:0 0.35rem;"> |
| 131 | <a href="/agents" class="muted-link flex items-center gap-1.5 text-xs" style="padding:0.1rem 0;"> |
| 132 | {{icon "book-open" "size-3.5"}} |
| 133 | <span>{{t .Lang "nav.agents"}}</span> |
| 134 | </a> |
| 135 | </div> |
| 136 | </div> |
| 137 | </div> |
| 138 | </aside> |
| 139 | |
| 140 | <!-- Main Content Column --> |
| 141 | <div class="app-col{{if $pageBackground}} has-page-bg{{end}}"> |
| 142 | {{if $pageBackground}} |
| 143 | <div class="page-bg" aria-hidden="true"><img src="{{$pageBackground}}" alt=""></div> |
| 144 | {{end}} |
| 145 | |
| 146 | <!-- Mobile Topbar (only visible on small screens) --> |
| 147 | <div class="mobile-topbar"> |
| 148 | <div class="flex items-center gap-2"> |
| 149 | <button type="button" class="btn btn-ghost btn-icon" data-drawer-open aria-label="Menu"> |
| 150 | {{icon "menu" "size-4"}} |
| 151 | </button> |
| 152 | <a href="/" class="font-semibold text-base tracking-tight" style="letter-spacing:-0.02em;">Polar</a> |
| 153 | </div> |
| 154 | <div class="flex items-center gap-1.5"> |
| 155 | <button type="button" class="btn btn-ghost btn-icon" data-open-palette="" aria-label="{{t .Lang "nav.command_palette"}}"> |
| 156 | {{icon "search" "size-4"}} |
| 157 | </button> |
| 158 | {{if eq .Lang "en"}} |
| 159 | <a href="?lang=ru" class="btn btn-ghost btn-sm font-mono" title="{{t .Lang "nav.lang"}}" aria-label="{{t .Lang "nav.lang"}}">RU</a> |
| 160 | {{else}} |
| 161 | <a href="?lang=en" class="btn btn-ghost btn-sm font-mono" title="{{t .Lang "nav.lang"}}" aria-label="{{t .Lang "nav.lang"}}">EN</a> |
| 162 | {{end}} |
| 163 | {{if .CurrentUser}} |
| 164 | <a href="/new" class="btn btn-primary btn-sm">{{icon "plus" "size-3.5"}}</a> |
| 165 | {{else}} |
| 166 | <a href="/login" class="btn btn-outline btn-sm">{{t .Lang "nav.login"}}</a> |
| 167 | {{end}} |
| 168 | </div> |
| 169 | </div> |
| 170 | |
| 171 | <main class="app-main"> |
| 172 | {{if .Flash}} |
| 173 | <div class="container mb-4"> |
| 174 | <div class="card p-3 flex items-center justify-between gap-2" role="status" style="border-color:hsl(var(--primary) / 0.4);"> |
| 175 | <span class="flex items-center gap-2 text-sm">{{icon "check" "size-4"}} {{.Flash}}</span> |
| 176 | </div> |
| 177 | </div> |
| 178 | {{end}} |
| 179 | {{if .Error}} |
| 180 | <div class="container mb-4"> |
| 181 | <div class="card p-3 flex items-center justify-between gap-2" role="alert" style="border-color:hsl(var(--destructive) / 0.6);color:hsl(var(--destructive));"> |
| 182 | <span class="flex items-center gap-2 text-sm">{{icon "alert-circle" "size-4"}} {{.Error}}</span> |
| 183 | </div> |
| 184 | </div> |
| 185 | {{end}} |
| 186 | |
| 187 | {{template "content" .}} |
| 188 | </main> |
| 189 | </div> |
| 190 | </div> |
| 191 | |
| 192 | <!-- Mobile Drawer --> |
| 193 | <div id="mobile-drawer" class="mobile-drawer" aria-hidden="true"> |
| 194 | <div class="mobile-drawer-panel"> |
| 195 | <div class="flex flex-col gap-2"> |
| 196 | <div class="flex items-center justify-between" style="padding-bottom:0.5rem;border-bottom:1px solid hsl(var(--border));"> |
| 197 | <span class="font-semibold text-base tracking-tight" style="letter-spacing:-0.02em;">Polar</span> |
| 198 | <button type="button" class="btn btn-ghost btn-icon" data-drawer-close aria-label="{{t .Lang "common.close"}}"> |
| 199 | {{icon "close" "size-4"}} |
| 200 | </button> |
| 201 | </div> |
| 202 | <nav class="flex flex-col gap-1"> |
| 203 | <a href="/" class="nav-item">{{icon "home" "size-4"}} {{t .Lang "nav.home"}}</a> |
| 204 | {{if .CurrentUser}} |
| 205 | <a href="/new" class="nav-item">{{icon "plus" "size-4"}} {{t .Lang "repo.new.title"}}</a> |
| 206 | <a href="/settings" class="nav-item">{{icon "settings" "size-4"}} {{t .Lang "nav.settings"}}</a> |
| 207 | {{if .CurrentUser.IsAdmin}} |
| 208 | <a href="/admin" class="nav-item">{{icon "shield" "size-4"}} {{t .Lang "nav.admin"}}</a> |
| 209 | {{end}} |
| 210 | {{end}} |
| 211 | {{if .ExploreEnabled}} |
| 212 | <a href="/explore" class="nav-item">{{icon "globe" "size-4"}} {{t .Lang "nav.explore"}}</a> |
| 213 | {{end}} |
| 214 | </nav> |
| 215 | </div> |
| 216 | <div class="flex flex-col gap-2"> |
| 217 | <div class="segmented" role="group" aria-label="{{t .Lang "nav.lang"}}"> |
| 218 | <a href="?lang=ru" class="segmented-btn {{if eq .Lang "ru"}}active{{end}}">RU</a> |
| 219 | <a href="?lang=en" class="segmented-btn {{if eq .Lang "en"}}active{{end}}">EN</a> |
| 220 | </div> |
| 221 | <div class="segmented" role="group" aria-label="{{t .Lang "nav.theme"}}"> |
| 222 | <button type="button" class="segmented-btn {{if eq .Theme "light"}}active{{end}}" data-set-theme="light">{{t .Lang "theme.light"}}</button> |
| 223 | <button type="button" class="segmented-btn {{if eq .Theme "dark"}}active{{end}}" data-set-theme="dark">{{t .Lang "theme.dark"}}</button> |
| 224 | <button type="button" class="segmented-btn {{if eq .Theme "system"}}active{{end}}" data-set-theme="system">{{t .Lang "theme.system"}}</button> |
| 225 | </div> |
| 226 | </div> |
| 227 | </div> |
| 228 | </div> |
| 229 | |
| 230 | <!-- Command Palette (Ctrl/Cmd+K) --> |
| 231 | <div id="command-palette" class="backdrop" role="dialog" aria-modal="true" aria-label="{{t .Lang "nav.command_palette"}}" aria-hidden="true"> |
| 232 | <div class="palette-box"> |
| 233 | <div class="palette-input-wrap"> |
| 234 | {{icon "search" "size-4"}} |
| 235 | <input id="command-palette-input" type="text" class="palette-input" placeholder="{{t .Lang "palette.placeholder"}}" autocomplete="off"> |
| 236 | <kbd class="kbd">ESC</kbd> |
| 237 | </div> |
| 238 | <div class="palette-list" role="listbox"> |
| 239 | <div data-palette-group> |
| 240 | <div class="palette-group-title">{{t .Lang "palette.group.nav"}}</div> |
| 241 | <button type="button" class="palette-item" data-palette-item data-palette-href="/" data-palette-keywords="home главная домой"> |
| 242 | <span class="flex items-center gap-2">{{icon "home" "size-4"}} {{t .Lang "nav.home"}}</span> |
| 243 | <span class="flex items-center gap-1"><kbd class="kbd">g</kbd><kbd class="kbd">h</kbd></span> |
| 244 | </button> |
| 245 | {{if .ExploreEnabled}} |
| 246 | <button type="button" class="palette-item" data-palette-item data-palette-href="/explore" data-palette-keywords="explore обзор публичные"> |
| 247 | <span class="flex items-center gap-2">{{icon "globe" "size-4"}} {{t .Lang "nav.explore"}}</span> |
| 248 | <span class="flex items-center gap-1"><kbd class="kbd">g</kbd><kbd class="kbd">r</kbd></span> |
| 249 | </button> |
| 250 | {{end}} |
| 251 | <button type="button" class="palette-item" data-palette-item data-palette-href="/agents" data-palette-keywords="agents ai api guide агенты документация"> |
| 252 | <span class="flex items-center gap-2">{{icon "book-open" "size-4"}} {{t .Lang "nav.agents"}}</span> |
| 253 | </button> |
| 254 | {{if .CurrentUser}} |
| 255 | <button type="button" class="palette-item" data-palette-item data-palette-href="/new" data-palette-keywords="new create создать репозиторий"> |
| 256 | <span class="flex items-center gap-2">{{icon "plus" "size-4"}} {{t .Lang "repo.new.title"}}</span> |
| 257 | </button> |
| 258 | <button type="button" class="palette-item" data-palette-item data-palette-href="/settings" data-palette-keywords="settings tokens настройки токены"> |
| 259 | <span class="flex items-center gap-2">{{icon "settings" "size-4"}} {{t .Lang "nav.settings"}}</span> |
| 260 | </button> |
| 261 | {{if .CurrentUser.IsAdmin}} |
| 262 | <button type="button" class="palette-item" data-palette-item data-palette-href="/admin" data-palette-keywords="admin админка"> |
| 263 | <span class="flex items-center gap-2">{{icon "shield" "size-4"}} {{t .Lang "nav.admin"}}</span> |
| 264 | </button> |
| 265 | {{end}} |
| 266 | {{else}} |
| 267 | <button type="button" class="palette-item" data-palette-item data-palette-href="/login" data-palette-keywords="login войти"> |
| 268 | <span class="flex items-center gap-2">{{icon "user" "size-4"}} {{t .Lang "nav.login"}}</span> |
| 269 | </button> |
| 270 | <button type="button" class="palette-item" data-palette-item data-palette-href="/register" data-palette-keywords="register регистрация"> |
| 271 | <span class="flex items-center gap-2">{{icon "plus" "size-4"}} {{t .Lang "nav.register"}}</span> |
| 272 | </button> |
| 273 | {{end}} |
| 274 | <button type="button" class="palette-item" data-palette-item data-palette-action="toggle-sidebar" data-palette-keywords="sidebar toggle боковая панель скрыть"> |
| 275 | <span class="flex items-center gap-2">{{icon "sidebar" "size-4"}} {{t .Lang "nav.toggle_sidebar"}}</span> |
| 276 | <span class="flex items-center gap-1"><kbd class="kbd">Ctrl</kbd><kbd class="kbd">B</kbd></span> |
| 277 | </button> |
| 278 | </div> |
| 279 | |
| 280 | {{if .PaletteFiles}} |
| 281 | <div data-palette-group> |
| 282 | <div class="palette-group-title">{{t .Lang "repo.files"}} ({{.Repo.OwnerUsername}}/{{.Repo.Name}})</div> |
| 283 | {{range .PaletteFiles}} |
| 284 | <button type="button" class="palette-item" data-palette-item data-palette-href="/{{$.Repo.OwnerUsername}}/{{$.Repo.Name}}/blob/{{$.Ref}}/{{.}}" data-palette-keywords="file: {{.}}"> |
| 285 | <span class="flex items-center gap-2 font-mono text-xs">{{icon "file-code" "size-4"}} {{.}}</span> |
| 286 | </button> |
| 287 | {{end}} |
| 288 | </div> |
| 289 | {{end}} |
| 290 | |
| 291 | {{if .PaletteRepos}} |
| 292 | <div data-palette-group> |
| 293 | <div class="palette-group-title">{{t .Lang "palette.group.repos"}}</div> |
| 294 | {{range .PaletteRepos}} |
| 295 | <button type="button" class="palette-item" data-palette-item data-palette-href="/{{.OwnerUsername}}/{{.Name}}" data-palette-keywords="repo {{.OwnerUsername}}/{{.Name}} {{.Description}}"> |
| 296 | <span class="flex items-center gap-2"> |
| 297 | {{if .IsPrivate}}{{icon "lock" "size-4"}}{{else}}{{icon "git-branch" "size-4"}}{{end}} |
| 298 | <span>{{.OwnerUsername}}/<strong>{{.Name}}</strong></span> |
| 299 | </span> |
| 300 | <span class="text-xs text-muted">{{if .IsPrivate}}{{t $.Lang "repo.private"}}{{else}}{{t $.Lang "repo.public"}}{{end}}</span> |
| 301 | </button> |
| 302 | {{end}} |
| 303 | </div> |
| 304 | {{end}} |
| 305 | |
| 306 | <div data-palette-group> |
| 307 | <div class="palette-group-title">{{t .Lang "palette.group.themes"}}</div> |
| 308 | <button type="button" class="palette-item" data-palette-item data-palette-theme="light" data-palette-keywords="theme light светлая"> |
| 309 | <span class="flex items-center gap-2">{{icon "sun" "size-4"}} {{t .Lang "theme.light"}}</span> |
| 310 | </button> |
| 311 | <button type="button" class="palette-item" data-palette-item data-palette-theme="dark" data-palette-keywords="theme dark темная тёмная"> |
| 312 | <span class="flex items-center gap-2">{{icon "moon" "size-4"}} {{t .Lang "theme.dark"}}</span> |
| 313 | </button> |
| 314 | <button type="button" class="palette-item" data-palette-item data-palette-theme="system" data-palette-keywords="theme system авто системная"> |
| 315 | <span class="flex items-center gap-2">{{icon "laptop" "size-4"}} {{t .Lang "theme.system"}}</span> |
| 316 | </button> |
| 317 | </div> |
| 318 | </div> |
| 319 | </div> |
| 320 | </div> |
| 321 | |
| 322 | <!-- Keyboard Shortcuts Dialog (?) --> |
| 323 | <div id="shortcuts-dialog" class="backdrop" role="dialog" aria-modal="true" aria-label="{{t .Lang "shortcuts.title"}}" aria-hidden="true"> |
| 324 | <div class="dialog-box"> |
| 325 | <div class="card-header"> |
| 326 | <span class="font-semibold flex items-center gap-2">{{icon "keyboard" "size-4"}} {{t .Lang "shortcuts.title"}}</span> |
| 327 | <button type="button" class="btn btn-ghost btn-icon" data-dialog-close aria-label="{{t .Lang "common.close"}}"> |
| 328 | {{icon "close" "size-4"}} |
| 329 | </button> |
| 330 | </div> |
| 331 | <div class="card-body shortcuts-list"> |
| 332 | <div class="shortcuts-group-label">{{t .Lang "shortcuts.group.general"}}</div> |
| 333 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.palette"}}</span><span class="shortcut-keys"><kbd class="kbd">Ctrl</kbd><kbd class="kbd">K</kbd></span></div> |
| 334 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.shortcuts"}}</span><kbd class="kbd">?</kbd></div> |
| 335 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.context_menu"}}</span><span class="shortcut-keys"><kbd class="kbd">Shift</kbd><kbd class="kbd">F10</kbd></span></div> |
| 336 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.theme"}}</span><span class="shortcut-keys"><kbd class="kbd">Ctrl</kbd><kbd class="kbd">Shift</kbd><kbd class="kbd">L</kbd></span></div> |
| 337 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.copy_url"}}</span><kbd class="kbd">y</kbd></div> |
| 338 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.sidebar"}}</span><span class="shortcut-keys"><kbd class="kbd">Ctrl</kbd><kbd class="kbd">B</kbd></span></div> |
| 339 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.search"}}</span><kbd class="kbd">/</kbd></div> |
| 340 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.close"}}</span><kbd class="kbd">Esc</kbd></div> |
| 341 | |
| 342 | <div class="shortcuts-group-label">{{t .Lang "shortcuts.group.navigation"}}</div> |
| 343 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.home"}}</span><span class="shortcut-keys"><kbd class="kbd">g</kbd><kbd class="kbd">h</kbd></span></div> |
| 344 | <div class="shortcut-row"><span>{{t .Lang "nav.explore"}}</span><span class="shortcut-keys"><kbd class="kbd">g</kbd><kbd class="kbd">r</kbd></span></div> |
| 345 | {{if .CurrentUser}} |
| 346 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.profile"}}</span><span class="shortcut-keys"><kbd class="kbd">g</kbd><kbd class="kbd">o</kbd></span></div> |
| 347 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.new_repo"}}</span><span class="shortcut-keys"><kbd class="kbd">g</kbd><kbd class="kbd">n</kbd></span></div> |
| 348 | {{end}} |
| 349 | |
| 350 | {{if .Repo}} |
| 351 | <div class="shortcuts-group-label">{{t .Lang "shortcuts.group.repo"}}</div> |
| 352 | <div class="shortcut-row"><span>{{t .Lang "repo.tab.code"}}</span><span class="shortcut-keys"><kbd class="kbd">g</kbd><kbd class="kbd">c</kbd></span></div> |
| 353 | {{if .Repo.EnableIssues}}<div class="shortcut-row"><span>{{t .Lang "repo.tab.issues"}}</span><span class="shortcut-keys"><kbd class="kbd">g</kbd><kbd class="kbd">i</kbd></span></div>{{end}} |
| 354 | {{if .Repo.EnablePulls}}<div class="shortcut-row"><span>{{t .Lang "repo.tab.pulls"}}</span><span class="shortcut-keys"><kbd class="kbd">g</kbd><kbd class="kbd">p</kbd></span></div>{{end}} |
| 355 | {{if .Repo.EnableReleases}}<div class="shortcut-row"><span>{{t .Lang "repo.tab.releases"}}</span><span class="shortcut-keys"><kbd class="kbd">g</kbd><kbd class="kbd">l</kbd></span></div>{{end}} |
| 356 | {{if .Repo.EnableActivity}}<div class="shortcut-row"><span>{{t .Lang "repo.tab.activity"}}</span><span class="shortcut-keys"><kbd class="kbd">g</kbd><kbd class="kbd">a</kbd></span></div>{{end}} |
| 357 | <div class="shortcut-row"><span>{{t .Lang "repo.tab.branches"}}</span><span class="shortcut-keys"><kbd class="kbd">g</kbd><kbd class="kbd">b</kbd></span></div> |
| 358 | {{if .CanWrite}}<div class="shortcut-row"><span>{{t .Lang "repo.tab.settings"}}</span><span class="shortcut-keys"><kbd class="kbd">g</kbd><kbd class="kbd">s</kbd></span></div>{{end}} |
| 359 | <div class="shortcut-row"><span>{{t .Lang "shortcuts.files"}}</span><kbd class="kbd">t</kbd></div> |
| 360 | {{end}} |
| 361 | </div> |
| 362 | </div> |
| 363 | </div> |
| 364 | |
| 365 | |
| 366 | <!-- Custom Context Menu --> |
| 367 | <div id="context-menu" class="context-menu" role="menu" aria-label="{{t .Lang "contextmenu.title"}}" aria-hidden="true"> |
| 368 | <div class="context-menu-section" data-context-section="selection" hidden> |
| 369 | <div class="context-menu-label">{{t .Lang "contextmenu.selection"}}</div> |
| 370 | <button type="button" class="context-menu-item" data-context-action="copy-selection" role="menuitem"> |
| 371 | {{icon "copy" "size-3.5"}}<span>{{t .Lang "contextmenu.copy_selection"}}</span> |
| 372 | </button> |
| 373 | <button type="button" class="context-menu-item" data-context-action="search-selection" role="menuitem"> |
| 374 | {{icon "search" "size-3.5"}}<span>{{t .Lang "contextmenu.search_selection"}}</span> |
| 375 | </button> |
| 376 | </div> |
| 377 | |
| 378 | <div class="context-menu-section" data-context-section="link" hidden> |
| 379 | <div class="context-menu-label">{{t .Lang "contextmenu.link"}}</div> |
| 380 | <button type="button" class="context-menu-item" data-context-action="link-open" role="menuitem"> |
| 381 | {{icon "link" "size-3.5"}}<span>{{t .Lang "contextmenu.open_link"}}</span> |
| 382 | </button> |
| 383 | <button type="button" class="context-menu-item" data-context-action="link-copy" role="menuitem"> |
| 384 | {{icon "copy" "size-3.5"}}<span>{{t .Lang "contextmenu.copy_link"}}</span> |
| 385 | </button> |
| 386 | <button type="button" class="context-menu-item" data-context-action="link-text" role="menuitem"> |
| 387 | {{icon "file" "size-3.5"}}<span>{{t .Lang "contextmenu.copy_link_text"}}</span> |
| 388 | </button> |
| 389 | </div> |
| 390 | |
| 391 | <div class="context-menu-section" data-context-section="image" hidden> |
| 392 | <div class="context-menu-label">{{t .Lang "contextmenu.image"}}</div> |
| 393 | <button type="button" class="context-menu-item" data-context-action="image-open" role="menuitem"> |
| 394 | {{icon "image" "size-3.5"}}<span>{{t .Lang "contextmenu.open_image"}}</span> |
| 395 | </button> |
| 396 | <button type="button" class="context-menu-item" data-context-action="image-copy" role="menuitem"> |
| 397 | {{icon "copy" "size-3.5"}}<span>{{t .Lang "contextmenu.copy_image"}}</span> |
| 398 | </button> |
| 399 | <button type="button" class="context-menu-item" data-context-action="image-save" role="menuitem"> |
| 400 | {{icon "download" "size-3.5"}}<span>{{t .Lang "contextmenu.save_image"}}</span> |
| 401 | </button> |
| 402 | </div> |
| 403 | |
| 404 | {{if .Repo}} |
| 405 | <div class="context-menu-section" data-context-section="repo"> |
| 406 | <div class="context-menu-label"> |
| 407 | <span>{{t .Lang "contextmenu.repository"}}</span> |
| 408 | <span class="context-menu-meta">{{.Repo.OwnerUsername}}/{{.Repo.Name}}</span> |
| 409 | </div> |
| 410 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}" role="menuitem"> |
| 411 | {{icon "code" "size-3.5"}}<span>{{t .Lang "repo.tab.code"}}</span> |
| 412 | </a> |
| 413 | {{if .Repo.EnableIssues}} |
| 414 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/issues" role="menuitem"> |
| 415 | {{icon "issue" "size-3.5"}}<span>{{t .Lang "repo.tab.issues"}}</span> |
| 416 | </a> |
| 417 | {{end}} |
| 418 | {{if .Repo.EnablePulls}} |
| 419 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/pulls" role="menuitem"> |
| 420 | {{icon "git-pull-request" "size-3.5"}}<span>{{t .Lang "repo.tab.pulls"}}</span> |
| 421 | </a> |
| 422 | {{end}} |
| 423 | {{if .Repo.EnableReleases}} |
| 424 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/releases" role="menuitem"> |
| 425 | {{icon "tag" "size-3.5"}}<span>{{t .Lang "repo.tab.releases"}}</span> |
| 426 | </a> |
| 427 | {{end}} |
| 428 | {{if .Repo.EnableActivity}} |
| 429 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/activity" role="menuitem"> |
| 430 | {{icon "activity" "size-3.5"}}<span>{{t .Lang "repo.tab.activity"}}</span> |
| 431 | </a> |
| 432 | {{end}} |
| 433 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/branches" role="menuitem"> |
| 434 | {{icon "git-branch" "size-3.5"}}<span>{{t .Lang "repo.tab.branches"}}</span> |
| 435 | </a> |
| 436 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/commits/{{.Repo.DefaultBranch}}" role="menuitem"> |
| 437 | {{icon "history" "size-3.5"}}<span>{{t .Lang "repo.tab.commits"}}</span> |
| 438 | </a> |
| 439 | </div> |
| 440 | |
| 441 | {{if or .CanWrite (and .CurrentUser (or .Repo.EnableIssues .Repo.EnablePulls))}} |
| 442 | <div class="context-menu-section" data-context-section="repo-actions"> |
| 443 | <div class="context-menu-label">{{t .Lang "contextmenu.repo_actions"}}</div> |
| 444 | {{if .CurrentUser}}{{if .Repo.EnableIssues}} |
| 445 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/issues/new" role="menuitem"> |
| 446 | {{icon "issue" "size-3.5"}}<span>{{t .Lang "issues.new"}}</span> |
| 447 | </a> |
| 448 | {{end}}{{if .Repo.EnablePulls}} |
| 449 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/pulls/new" role="menuitem"> |
| 450 | {{icon "git-pull-request" "size-3.5"}}<span>{{t .Lang "pulls.new"}}</span> |
| 451 | </a> |
| 452 | {{end}}{{end}} |
| 453 | {{if .CanWrite}} |
| 454 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/new-file" role="menuitem"> |
| 455 | {{icon "plus" "size-3.5"}}<span>{{t .Lang "file.new_file"}}</span> |
| 456 | </a> |
| 457 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/new-folder" role="menuitem"> |
| 458 | {{icon "folder" "size-3.5"}}<span>{{t .Lang "file.new_folder"}}</span> |
| 459 | </a> |
| 460 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/upload" role="menuitem"> |
| 461 | {{icon "upload" "size-3.5"}}<span>{{t .Lang "file.upload_file"}}</span> |
| 462 | </a> |
| 463 | <a class="context-menu-item" href="/{{.Repo.OwnerUsername}}/{{.Repo.Name}}/settings" role="menuitem"> |
| 464 | {{icon "settings" "size-3.5"}}<span>{{t .Lang "repo.tab.settings"}}</span> |
| 465 | </a> |
| 466 | {{end}} |
| 467 | </div> |
| 468 | {{end}} |
| 469 | {{end}} |
| 470 | |
| 471 | <div class="context-menu-section" data-context-section="page"> |
| 472 | <div class="context-menu-label">{{t .Lang "contextmenu.page"}}</div> |
| 473 | <button type="button" class="context-menu-item" data-context-action="page-back" role="menuitem"> |
| 474 | {{icon "arrow-left" "size-3.5"}}<span>{{t .Lang "contextmenu.back"}}</span> |
| 475 | </button> |
| 476 | <button type="button" class="context-menu-item" data-context-action="page-forward" role="menuitem"> |
| 477 | {{icon "arrow-right" "size-3.5"}}<span>{{t .Lang "contextmenu.forward"}}</span> |
| 478 | </button> |
| 479 | <button type="button" class="context-menu-item" data-context-action="page-reload" role="menuitem"> |
| 480 | {{icon "history" "size-3.5"}}<span>{{t .Lang "contextmenu.reload"}}</span> |
| 481 | </button> |
| 482 | <button type="button" class="context-menu-item" data-context-action="page-copy" role="menuitem"> |
| 483 | {{icon "copy" "size-3.5"}}<span>{{t .Lang "contextmenu.copy_url"}}</span><kbd class="context-menu-kbd">y</kbd> |
| 484 | </button> |
| 485 | </div> |
| 486 | |
| 487 | <div class="context-menu-section" data-context-section="appearance"> |
| 488 | <div class="context-menu-label">{{t .Lang "contextmenu.appearance"}}</div> |
| 489 | <button type="button" class="context-menu-item" data-context-action="theme" data-theme-value="light" role="menuitemradio" aria-checked="false"> |
| 490 | {{icon "sun" "size-3.5"}}<span>{{t .Lang "theme.light"}}</span><span class="context-menu-check">{{icon "check" "size-3.5"}}</span> |
| 491 | </button> |
| 492 | <button type="button" class="context-menu-item" data-context-action="theme" data-theme-value="dark" role="menuitemradio" aria-checked="false"> |
| 493 | {{icon "moon" "size-3.5"}}<span>{{t .Lang "theme.dark"}}</span><span class="context-menu-check">{{icon "check" "size-3.5"}}</span> |
| 494 | </button> |
| 495 | <button type="button" class="context-menu-item" data-context-action="theme" data-theme-value="system" role="menuitemradio" aria-checked="false"> |
| 496 | {{icon "laptop" "size-3.5"}}<span>{{t .Lang "theme.system"}}</span><span class="context-menu-check">{{icon "check" "size-3.5"}}</span> |
| 497 | </button> |
| 498 | </div> |
| 499 | |
| 500 | <div class="context-menu-section" data-context-section="app"> |
| 501 | <div class="context-menu-label">{{t .Lang "contextmenu.app"}}</div> |
| 502 | <button type="button" class="context-menu-item" data-context-action="palette" role="menuitem"> |
| 503 | {{icon "command" "size-3.5"}}<span>{{t .Lang "shortcuts.palette"}}</span><kbd class="context-menu-kbd">Ctrl K</kbd> |
| 504 | </button> |
| 505 | <button type="button" class="context-menu-item" data-context-action="shortcuts" role="menuitem"> |
| 506 | {{icon "keyboard" "size-3.5"}}<span>{{t .Lang "shortcuts.title"}}</span><kbd class="context-menu-kbd">?</kbd> |
| 507 | </button> |
| 508 | {{if .CurrentUser}} |
| 509 | <a class="context-menu-item" href="/new" role="menuitem"> |
| 510 | {{icon "plus" "size-3.5"}}<span>{{t .Lang "repo.new.title"}}</span> |
| 511 | </a> |
| 512 | <a class="context-menu-item" href="/settings" role="menuitem"> |
| 513 | {{icon "settings" "size-3.5"}}<span>{{t .Lang "nav.settings"}}</span> |
| 514 | </a> |
| 515 | {{end}} |
| 516 | </div> |
| 517 | </div> |
| 518 | |
| 519 | <div id="toast-container" class="toast-container" aria-live="polite"></div> |
| 520 | |
| 521 | <script src="/static/js/htmx.min.js" defer></script> |
| 522 | <script src="/static/js/app.js?v={{assetVer}}" defer></script> |
| 523 | </body> |
| 524 | </html> |