Mirror of https://git.jolheiser.com/ugit

Compare changes

Choose any two refs to compare.

+3 -2
README.md
··· 9 9 10 10 ยตgit allows cloning via HTTPS/SSH, but can only be pushed to via SSH. 11 11 12 - 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. 13 - If you wish to collaborate, please send me patches via [git-pr](https://pr.jolheiser.com/repos/ugit). 12 + There are no plans to directly support issues or PR workflows. 13 + If you wish to collaborate, please send me patches via [github](https://github.com/jolheiser/ugit) or [tangled](https://tangled.org/@jolheiser.com/ugit). 14 + For issue/bug-tracking, I recommend [git-bug](https://github.com/git-bug/git-bug). 14 15 15 16 Currently all HTML is allowed in markdown, ยตgit is intended to be run by/for a trusted user. 16 17
-2
cmd/ugitd/args.go
··· 18 18 Profile profileArgs 19 19 Log logArgs 20 20 ShowPrivate bool 21 - TUI bool 22 21 } 23 22 24 23 type sshArgs struct { ··· 115 114 fs.StringVar(&c.Meta.Description, "meta.description", c.Meta.Description, "App description") 116 115 fs.StringVar(&c.Profile.Username, "profile.username", c.Profile.Username, "Username for index page") 117 116 fs.StringVar(&c.Profile.Email, "profile.email", c.Profile.Email, "Email for index page") 118 - fs.BoolVar(&c.TUI, "tui", c.TUI, "Run the TUI interface directly") 119 117 fs.Func("profile.links", "Link(s) for index page", func(s string) error { 120 118 parts := strings.SplitN(s, ",", 2) 121 119 if len(parts) != 2 {
+5 -14
cmd/ugitd/main.go
··· 20 20 "go.jolheiser.com/ugit/internal/git" 21 21 "go.jolheiser.com/ugit/internal/http" 22 22 "go.jolheiser.com/ugit/internal/ssh" 23 - "go.jolheiser.com/ugit/internal/tui" 24 23 ) 25 24 26 25 func main() { ··· 39 38 args.RepoDir, err = filepath.Abs(args.RepoDir) 40 39 if err != nil { 41 40 panic(err) 42 - } 43 - 44 - // Run TUI mode if requested 45 - if args.TUI { 46 - if err := tui.Run(args.RepoDir); err != nil { 47 - panic(err) 48 - } 49 - return 50 41 } 51 42 52 43 slog.SetLogLoggerLevel(args.Log.Level) ··· 152 143 if err != nil { 153 144 return err 154 145 } 155 - fi.WriteString("#!/usr/bin/env bash\n") 156 - fi.WriteString(fmt.Sprintf("%s pre-receive-hook\n", bin)) 157 - fi.WriteString(fmt.Sprintf(`for hook in %s.d/*; do 146 + fmt.Fprintln(fi, "#!/usr/bin/env bash") 147 + fmt.Fprintf(fi, "%s pre-receive-hook\n", bin) 148 + fmt.Fprintf(fi, `for hook in %s.d/*; do 158 149 test -x "${hook}" && test -f "${hook}" || continue 159 150 "${hook}" 160 - done`, fp)) 151 + done`, fp) 161 152 fi.Close() 162 153 163 154 return os.Chmod(fp, 0o755) ··· 171 162 172 163 opts := make([]*packp.Option, 0) 173 164 if pushCount, err := strconv.Atoi(os.Getenv("GIT_PUSH_OPTION_COUNT")); err == nil { 174 - for idx := 0; idx < pushCount; idx++ { 165 + for idx := range pushCount { 175 166 opt := os.Getenv(fmt.Sprintf("GIT_PUSH_OPTION_%d", idx)) 176 167 kv := strings.SplitN(opt, "=", 2) 177 168 if len(kv) == 2 {
+7 -7
flake.lock
··· 2 2 "nodes": { 3 3 "nixpkgs": { 4 4 "locked": { 5 - "lastModified": 1736241350, 6 - "narHash": "sha256-CHd7yhaDigUuJyDeX0SADbTM9FXfiWaeNyY34FL1wQU=", 5 + "lastModified": 1755205935, 6 + "narHash": "sha256-EQ6qHuJWguaoBZyxdqsgJqyEdS77k+2CnlKrfFxlkRY=", 7 7 "owner": "nixos", 8 8 "repo": "nixpkgs", 9 - "rev": "8c9fd3e564728e90829ee7dbac6edc972971cd0f", 9 + "rev": "c5e2e42c112de623adfd662b3e51f0805bf9ff83", 10 10 "type": "github" 11 11 }, 12 12 "original": { ··· 30 30 ] 31 31 }, 32 32 "locked": { 33 - "lastModified": 1695841587, 34 - "narHash": "sha256-fgiZd5AV+hi8Ne0bJ8SyAx5nppseW4aXJQEIDSr0VNA=", 33 + "lastModified": 1753803577, 34 + "narHash": "sha256-sE5IgsHacXmfsWJjVVPvb7Aa6oHElt+nfP6+3Pqa414=", 35 35 "ref": "refs/heads/main", 36 - "rev": "afca060674b20e0ccecde2d6fe88c887790219a5", 37 - "revCount": 1, 36 + "rev": "4ce9431cbb4e9e5dceadfbc413fbd34e7305fe8e", 37 + "revCount": 3, 38 38 "type": "git", 39 39 "url": "https://git.jolheiser.com/tailwind-ctp" 40 40 },
+4 -4
flake.nix
··· 34 34 tctpl = forAllSystems (system: tailwind-ctp-lsp.packages.${system}.default); 35 35 in 36 36 { 37 - packages = forAllSystems (system: import ./nix { pkgs = import nixpkgs { inherit system; }; }); 37 + packages = forAllSystems (system: import ./nix { pkgs = nixpkgs.legacyPackages.${system}; }); 38 38 devShells = forAllSystems ( 39 39 system: 40 40 let 41 - pkgs = import nixpkgs { inherit system; }; 41 + pkgs = nixpkgs.legacyPackages.${system}; 42 42 in 43 43 { 44 44 default = pkgs.mkShell { ··· 47 47 gopls 48 48 air 49 49 tctp.${system} 50 - tctpl.${system} 51 - vscode-langservers-extracted 50 + #tctpl.${system} 51 + #vscode-langservers-extracted 52 52 ]; 53 53 }; 54 54 }
+64 -48
go.mod
··· 1 1 module go.jolheiser.com/ugit 2 2 3 - go 1.23.1 4 - 5 - toolchain go1.23.3 3 + go 1.24.0 6 4 7 5 require ( 6 + github.com/a-h/templ v0.3.960 8 7 github.com/alecthomas/assert/v2 v2.11.0 9 - github.com/alecthomas/chroma/v2 v2.15.0 10 - github.com/charmbracelet/bubbles v0.21.0 11 - github.com/charmbracelet/bubbletea v1.3.5 12 - github.com/charmbracelet/lipgloss v1.1.0 13 - github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c 14 - github.com/charmbracelet/wish v1.4.4 8 + github.com/alecthomas/chroma/v2 v2.20.0 9 + github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309 10 + github.com/charmbracelet/wish v1.4.7 15 11 github.com/dustin/go-humanize v1.0.1 16 - github.com/go-chi/chi/v5 v5.2.0 12 + github.com/go-chi/chi/v5 v5.2.3 17 13 github.com/go-chi/httplog/v2 v2.1.1 18 - github.com/go-git/go-billy/v5 v5.6.1 19 - github.com/go-git/go-git/v5 v5.13.1 14 + github.com/go-git/go-billy/v5 v5.6.2 15 + github.com/go-git/go-git/v5 v5.16.3 20 16 github.com/peterbourgon/ff/v3 v3.4.0 21 - github.com/yuin/goldmark v1.7.8 22 - github.com/yuin/goldmark-emoji v1.0.4 17 + github.com/yuin/goldmark v1.7.13 18 + github.com/yuin/goldmark-emoji v1.0.6 23 19 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc 24 - golang.org/x/net v0.34.0 25 - maragu.dev/gomponents v1.0.0 20 + golang.org/x/net v0.46.0 26 21 ) 27 22 28 23 require ( 29 - dario.cat/mergo v1.0.1 // indirect 24 + dario.cat/mergo v1.0.2 // indirect 30 25 github.com/Microsoft/go-winio v0.6.2 // indirect 31 - github.com/ProtonMail/go-crypto v1.1.4 // indirect 32 - github.com/alecthomas/repr v0.4.0 // indirect 26 + github.com/ProtonMail/go-crypto v1.3.0 // indirect 27 + github.com/a-h/parse v0.0.0-20250122154542-74294addb73e // indirect 28 + github.com/alecthomas/repr v0.5.1 // indirect 29 + github.com/andybalholm/brotli v1.1.0 // indirect 33 30 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be // indirect 34 - github.com/atotto/clipboard v0.1.4 // indirect 35 31 github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect 36 - github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect 37 - github.com/charmbracelet/keygen v0.5.1 // indirect 38 - github.com/charmbracelet/log v0.4.0 // indirect 39 - github.com/charmbracelet/x/ansi v0.8.0 // indirect 40 - github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect 41 - github.com/charmbracelet/x/conpty v0.1.0 // indirect 42 - github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5 // indirect 43 - github.com/charmbracelet/x/input v0.2.0 // indirect 32 + github.com/cenkalti/backoff/v4 v4.3.0 // indirect 33 + github.com/charmbracelet/bubbletea v1.3.10 // indirect 34 + github.com/charmbracelet/colorprofile v0.3.2 // indirect 35 + github.com/charmbracelet/keygen v0.5.4 // indirect 36 + github.com/charmbracelet/lipgloss v1.1.0 // indirect 37 + github.com/charmbracelet/log v0.4.2 // indirect 38 + github.com/charmbracelet/x/ansi v0.10.2 // indirect 39 + github.com/charmbracelet/x/cellbuf v0.0.13 // indirect 40 + github.com/charmbracelet/x/conpty v0.1.1 // indirect 41 + github.com/charmbracelet/x/errors v0.0.0-20251030181443-0cf22f8402df // indirect 44 42 github.com/charmbracelet/x/term v0.2.1 // indirect 45 - github.com/charmbracelet/x/termios v0.1.0 // indirect 46 - github.com/cloudflare/circl v1.5.0 // indirect 43 + github.com/charmbracelet/x/termios v0.1.1 // indirect 44 + github.com/cli/browser v1.3.0 // indirect 45 + github.com/clipperhouse/stringish v0.1.1 // indirect 46 + github.com/clipperhouse/uax29/v2 v2.3.0 // indirect 47 + github.com/cloudflare/circl v1.6.1 // indirect 47 48 github.com/creack/pty v1.1.24 // indirect 48 - github.com/cyphar/filepath-securejoin v0.3.6 // indirect 49 + github.com/cyphar/filepath-securejoin v0.5.0 // indirect 49 50 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect 50 - github.com/dlclark/regexp2 v1.11.4 // indirect 51 + github.com/dlclark/regexp2 v1.11.5 // indirect 51 52 github.com/emirpasic/gods v1.18.1 // indirect 52 53 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect 54 + github.com/fatih/color v1.16.0 // indirect 55 + github.com/fsnotify/fsnotify v1.7.0 // indirect 53 56 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect 54 - github.com/go-logfmt/logfmt v0.6.0 // indirect 57 + github.com/go-logfmt/logfmt v0.6.1 // indirect 55 58 github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 // indirect 56 59 github.com/hexops/gotextdiff v1.0.3 // indirect 57 60 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 // indirect 58 - github.com/kevinburke/ssh_config v1.2.0 // indirect 59 - github.com/lucasb-eyer/go-colorful v1.2.0 // indirect 61 + github.com/kevinburke/ssh_config v1.4.0 // indirect 62 + github.com/klauspost/cpuid/v2 v2.3.0 // indirect 63 + github.com/lucasb-eyer/go-colorful v1.3.0 // indirect 64 + github.com/mattn/go-colorable v0.1.13 // indirect 60 65 github.com/mattn/go-isatty v0.0.20 // indirect 61 66 github.com/mattn/go-localereader v0.0.1 // indirect 62 - github.com/mattn/go-runewidth v0.0.16 // indirect 63 - github.com/mmcloughlin/avo v0.6.0 // indirect 67 + github.com/mattn/go-runewidth v0.0.19 // indirect 64 68 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect 65 69 github.com/muesli/cancelreader v0.2.2 // indirect 66 70 github.com/muesli/termenv v0.16.0 // indirect 67 - github.com/pjbgf/sha1cd v0.3.1 // indirect 71 + github.com/natefinch/atomic v1.0.1 // indirect 72 + github.com/pjbgf/sha1cd v0.5.0 // indirect 68 73 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect 69 74 github.com/rivo/uniseg v0.4.7 // indirect 70 - github.com/sahilm/fuzzy v0.1.1 // indirect 71 - github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 // indirect 72 - github.com/skeema/knownhosts v1.3.0 // indirect 75 + github.com/sergi/go-diff v1.4.0 // indirect 76 + github.com/skeema/knownhosts v1.3.2 // indirect 73 77 github.com/xanzy/ssh-agent v0.3.3 // indirect 74 78 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect 75 - golang.org/x/crypto v0.32.0 // indirect 76 - golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 // indirect 77 - golang.org/x/mod v0.22.0 // indirect 78 - golang.org/x/sync v0.13.0 // indirect 79 - golang.org/x/sys v0.32.0 // indirect 80 - golang.org/x/text v0.21.0 // indirect 81 - golang.org/x/tools v0.29.0 // indirect 79 + golang.org/x/crypto v0.43.0 // indirect 80 + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 // indirect 81 + golang.org/x/mod v0.29.0 // indirect 82 + golang.org/x/sync v0.17.0 // indirect 83 + golang.org/x/sys v0.37.0 // indirect 84 + golang.org/x/text v0.30.0 // indirect 85 + golang.org/x/tools v0.38.0 // indirect 82 86 gopkg.in/warnings.v0 v0.1.2 // indirect 83 87 gopkg.in/yaml.v2 v2.4.0 // indirect 84 88 ) 89 + 90 + tool ( 91 + github.com/a-h/templ/cmd/templ 92 + go.jolheiser.com/ugit/assets 93 + go.jolheiser.com/ugit/cmd/ugitd 94 + go.jolheiser.com/ugit/internal/git 95 + go.jolheiser.com/ugit/internal/html 96 + go.jolheiser.com/ugit/internal/html/markup 97 + go.jolheiser.com/ugit/internal/http 98 + go.jolheiser.com/ugit/internal/http/httperr 99 + go.jolheiser.com/ugit/internal/ssh 100 + )
+1 -1
go.mod.sri
··· 1 - sha256-L87PnM43gHrDcsRr3wnkB4e1Th2S0LsSwkXuebAFH44= 1 + sha256-OPdD57zqvRzzk8o7xyxGoqUCT+KNtBI/+1isQXkhWOw=
+110 -104
go.sum
··· 1 - dario.cat/mergo v1.0.1 h1:Ra4+bf83h2ztPIQYNP99R6m+Y7KfnARDfID+a+vLl4s= 2 - dario.cat/mergo v1.0.1/go.mod h1:uNxQE+84aUszobStD9th8a29P2fMDhsBdgRYvZOxGmk= 1 + dario.cat/mergo v1.0.2 h1:85+piFYR1tMbRrLcDwR18y4UKJ3aH1Tbzi24VRW1TK8= 2 + dario.cat/mergo v1.0.2/go.mod h1:E/hbnu0NxMFBjpMIE34DRGLWqDy0g5FuKDhCb31ngxA= 3 3 github.com/Microsoft/go-winio v0.5.2/go.mod h1:WpS1mjBmmwHBEWmogvA2mj8546UReBk4v8QkMxJ6pZY= 4 4 github.com/Microsoft/go-winio v0.6.2 h1:F2VQgta7ecxGYO8k3ZZz3RS8fVIXVxONVUPlNERoyfY= 5 5 github.com/Microsoft/go-winio v0.6.2/go.mod h1:yd8OoFMLzJbo9gZq8j5qaps8bJ9aShtEA8Ipt1oGCvU= 6 - github.com/ProtonMail/go-crypto v1.1.4 h1:G5U5asvD5N/6/36oIw3k2bOfBn5XVcZrb7PBjzzKKoE= 7 - github.com/ProtonMail/go-crypto v1.1.4/go.mod h1:rA3QumHc/FZ8pAHreoekgiAbzpNsfQAosU5td4SnOrE= 6 + github.com/ProtonMail/go-crypto v1.3.0 h1:ILq8+Sf5If5DCpHQp4PbZdS1J7HDFRXz/+xKBiRGFrw= 7 + github.com/ProtonMail/go-crypto v1.3.0/go.mod h1:9whxjD8Rbs29b4XWbB8irEcE8KHMqaR2e7GWU1R+/PE= 8 + github.com/a-h/parse v0.0.0-20250122154542-74294addb73e h1:HjVbSQHy+dnlS6C3XajZ69NYAb5jbGNfHanvm1+iYlo= 9 + github.com/a-h/parse v0.0.0-20250122154542-74294addb73e/go.mod h1:3mnrkvGpurZ4ZrTDbYU84xhwXW2TjTKShSwjRi2ihfQ= 10 + github.com/a-h/templ v0.3.960 h1:trshEpGa8clF5cdI39iY4ZrZG8Z/QixyzEyUnA7feTM= 11 + github.com/a-h/templ v0.3.960/go.mod h1:oCZcnKRf5jjsGpf2yELzQfodLphd2mwecwG4Crk5HBo= 8 12 github.com/alecthomas/assert/v2 v2.11.0 h1:2Q9r3ki8+JYXvGsDyBXwH3LcJ+WK5D0gc5E8vS6K3D0= 9 13 github.com/alecthomas/assert/v2 v2.11.0/go.mod h1:Bze95FyfUr7x34QZrjL+XP+0qgp/zg8yS+TtBj1WA3k= 10 14 github.com/alecthomas/chroma/v2 v2.2.0/go.mod h1:vf4zrexSH54oEjJ7EdB65tGNHmH3pGZmVkgTP5RHvAs= 11 - github.com/alecthomas/chroma/v2 v2.15.0 h1:LxXTQHFoYrstG2nnV9y2X5O94sOBzf0CIUpSTbpxvMc= 12 - github.com/alecthomas/chroma/v2 v2.15.0/go.mod h1:gUhVLrPDXPtp/f+L1jo9xepo9gL4eLwRuGAunSZMkio= 15 + github.com/alecthomas/chroma/v2 v2.20.0 h1:sfIHpxPyR07/Oylvmcai3X/exDlE8+FA820NTz+9sGw= 16 + github.com/alecthomas/chroma/v2 v2.20.0/go.mod h1:e7tViK0xh/Nf4BYHl00ycY6rV7b8iXBksI9E359yNmA= 13 17 github.com/alecthomas/repr v0.0.0-20220113201626-b1b626ac65ae/go.mod h1:2kn6fqh/zIyPLmm3ugklbEi5hg5wS435eygvNfaDQL8= 14 - github.com/alecthomas/repr v0.4.0 h1:GhI2A8MACjfegCPVq9f1FLvIBS+DrQ2KQBFZP1iFzXc= 15 - github.com/alecthomas/repr v0.4.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= 18 + github.com/alecthomas/repr v0.5.1 h1:E3G4t2QbHTSNpPKBgMTln5KLkZHLOcU7r37J4pXBuIg= 19 + github.com/alecthomas/repr v0.5.1/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4= 20 + github.com/andybalholm/brotli v1.1.0 h1:eLKJA0d02Lf0mVpIDgYnqXcUn0GqVmEFny3VuID1U3M= 21 + github.com/andybalholm/brotli v1.1.0/go.mod h1:sms7XGricyQI9K10gOSf56VKKWS4oLer58Q+mhRPtnY= 16 22 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be h1:9AeTilPcZAjCFIImctFaOjnTIavg87rW78vTPkQqLI8= 17 23 github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= 18 24 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5 h1:0CwZNZbxp69SHPdPJAN/hZIm0C4OItdklCFmMRWYpio= 19 25 github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= 20 - github.com/atotto/clipboard v0.1.4 h1:EH0zSVneZPSuFR11BlR9YppQTVDbh5+16AmcJi4g1z4= 21 - github.com/atotto/clipboard v0.1.4/go.mod h1:ZY9tmq7sm5xIbd9bOK4onWV4S6X0u6GY7Vn0Yu86PYI= 22 26 github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= 23 27 github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= 24 - github.com/aymanbagabas/go-udiff v0.2.0 h1:TK0fH4MteXUDspT88n8CKzvK0X9O2xu9yQjWpi6yML8= 25 - github.com/aymanbagabas/go-udiff v0.2.0/go.mod h1:RE4Ex0qsGkTAJoQdQQCA0uG+nAzJO/pI/QwceO5fgrA= 26 - github.com/charmbracelet/bubbles v0.21.0 h1:9TdC97SdRVg/1aaXNVWfFH3nnLAwOXr8Fn6u6mfQdFs= 27 - github.com/charmbracelet/bubbles v0.21.0/go.mod h1:HF+v6QUR4HkEpz62dx7ym2xc71/KBHg+zKwJtMw+qtg= 28 - github.com/charmbracelet/bubbletea v1.3.5 h1:JAMNLTbqMOhSwoELIr0qyP4VidFq72/6E9j7HHmRKQc= 29 - github.com/charmbracelet/bubbletea v1.3.5/go.mod h1:TkCnmH+aBd4LrXhXcqrKiYwRs7qyQx5rBgH5fVY3v54= 30 - github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= 31 - github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= 32 - github.com/charmbracelet/keygen v0.5.1 h1:zBkkYPtmKDVTw+cwUyY6ZwGDhRxXkEp0Oxs9sqMLqxI= 33 - github.com/charmbracelet/keygen v0.5.1/go.mod h1:zznJVmK/GWB6dAtjluqn2qsttiCBhA5MZSiwb80fcHw= 28 + github.com/cenkalti/backoff/v4 v4.3.0 h1:MyRJ/UdXutAwSAT+s3wNd7MfTIcy71VQueUuFK343L8= 29 + github.com/cenkalti/backoff/v4 v4.3.0/go.mod h1:Y3VNntkOUPxTVeUxJ/G5vcM//AlwfmyYozVcomhLiZE= 30 + github.com/charmbracelet/bubbletea v1.3.10 h1:otUDHWMMzQSB0Pkc87rm691KZ3SWa4KUlvF9nRvCICw= 31 + github.com/charmbracelet/bubbletea v1.3.10/go.mod h1:ORQfo0fk8U+po9VaNvnV95UPWA1BitP1E0N6xJPlHr4= 32 + github.com/charmbracelet/colorprofile v0.3.2 h1:9J27WdztfJQVAQKX2WOlSSRB+5gaKqqITmrvb1uTIiI= 33 + github.com/charmbracelet/colorprofile v0.3.2/go.mod h1:mTD5XzNeWHj8oqHb+S1bssQb7vIHbepiebQ2kPKVKbI= 34 + github.com/charmbracelet/keygen v0.5.4 h1:XQYgf6UEaTGgQSSmiPpIQ78WfseNQp4Pz8N/c1OsrdA= 35 + github.com/charmbracelet/keygen v0.5.4/go.mod h1:t4oBRr41bvK7FaJsAaAQhhkUuHslzFXVjOBwA55CZNM= 34 36 github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= 35 37 github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= 36 - github.com/charmbracelet/log v0.4.0 h1:G9bQAcx8rWA2T3pWvx7YtPTPwgqpk7D68BX21IRW8ZM= 37 - github.com/charmbracelet/log v0.4.0/go.mod h1:63bXt/djrizTec0l11H20t8FDSvA4CRZJ1KH22MdptM= 38 - github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c h1:treQxMBdI2PaD4eOYfFux8stfCkUxhuUxaqGcxKqVpI= 39 - github.com/charmbracelet/ssh v0.0.0-20241211182756-4fe22b0f1b7c/go.mod h1:CY1xbl2z+ZeBmNWItKZyxx0zgDgnhmR57+DTsHOobJ4= 40 - github.com/charmbracelet/wish v1.4.4 h1:wtfoAMkf8Db9zi+9Lme2f7XKMxL6BqfgDWbqcTUHLaU= 41 - github.com/charmbracelet/wish v1.4.4/go.mod h1:XB8v51UxIFMRlUod9lLaAgOsj/wpe+qW9HjsoYIiNMo= 42 - github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE= 43 - github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q= 44 - github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= 45 - github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= 46 - github.com/charmbracelet/x/conpty v0.1.0 h1:4zc8KaIcbiL4mghEON8D72agYtSeIgq8FSThSPQIb+U= 47 - github.com/charmbracelet/x/conpty v0.1.0/go.mod h1:rMFsDJoDwVmiYM10aD4bH2XiRgwI7NYJtQgl5yskjEQ= 48 - github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5 h1:Hx72S6S4jAfrrWE3pv9IbudVdUV4htBgkOX800o17Bk= 49 - github.com/charmbracelet/x/errors v0.0.0-20250107110353-48b574af22a5/go.mod h1:2P0UgXMEa6TsToMSuFqKFQR+fZTO9CNGUNokkPatT/0= 50 - github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91 h1:payRxjMjKgx2PaCWLZ4p3ro9y97+TVLZNaRZgJwSVDQ= 51 - github.com/charmbracelet/x/exp/golden v0.0.0-20241011142426-46044092ad91/go.mod h1:wDlXFlCrmJ8J+swcL/MnGUuYnqgQdW9rhSD61oNMb6U= 52 - github.com/charmbracelet/x/input v0.2.0 h1:1Sv+y/flcqUfUH2PXNIDKDIdT2G8smOnGOgawqhwy8A= 53 - github.com/charmbracelet/x/input v0.2.0/go.mod h1:KUSFIS6uQymtnr5lHVSOK9j8RvwTD4YHnWnzJUYnd/M= 38 + github.com/charmbracelet/log v0.4.2 h1:hYt8Qj6a8yLnvR+h7MwsJv/XvmBJXiueUcI3cIxsyig= 39 + github.com/charmbracelet/log v0.4.2/go.mod h1:qifHGX/tc7eluv2R6pWIpyHDDrrb/AG71Pf2ysQu5nw= 40 + github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309 h1:dCVbCRRtg9+tsfiTXTp0WupDlHruAXyp+YoxGVofHHc= 41 + github.com/charmbracelet/ssh v0.0.0-20250826160808-ebfa259c7309/go.mod h1:R9cISUs5kAH4Cq/rguNbSwcR+slE5Dfm8FEs//uoIGE= 42 + github.com/charmbracelet/wish v1.4.7 h1:O+jdLac3s6GaqkOHHSwezejNK04vl6VjO1A+hl8J8Yc= 43 + github.com/charmbracelet/wish v1.4.7/go.mod h1:OBZ8vC62JC5cvbxJLh+bIWtG7Ctmct+ewziuUWK+G14= 44 + github.com/charmbracelet/x/ansi v0.10.2 h1:ith2ArZS0CJG30cIUfID1LXN7ZFXRCww6RUvAPA+Pzw= 45 + github.com/charmbracelet/x/ansi v0.10.2/go.mod h1:HbLdJjQH4UH4AqA2HpRWuWNluRE6zxJH/yteYEYCFa8= 46 + github.com/charmbracelet/x/cellbuf v0.0.13 h1:/KBBKHuVRbq1lYx5BzEHBAFBP8VcQzJejZ/IA3iR28k= 47 + github.com/charmbracelet/x/cellbuf v0.0.13/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= 48 + github.com/charmbracelet/x/conpty v0.1.1 h1:s1bUxjoi7EpqiXysVtC+a8RrvPPNcNvAjfi4jxsAuEs= 49 + github.com/charmbracelet/x/conpty v0.1.1/go.mod h1:OmtR77VODEFbiTzGE9G1XiRJAga6011PIm4u5fTNZpk= 50 + github.com/charmbracelet/x/errors v0.0.0-20251030181443-0cf22f8402df h1:6zTS1yAzaSDINNXDQRtayOHL4Zde4LVmnbjRPdxV84g= 51 + github.com/charmbracelet/x/errors v0.0.0-20251030181443-0cf22f8402df/go.mod h1:O2BTD/aMVQDmrvqroIO3fB6zXUuU07ZpVt21QTmZjRg= 54 52 github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= 55 53 github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= 56 - github.com/charmbracelet/x/termios v0.1.0 h1:y4rjAHeFksBAfGbkRDmVinMg7x7DELIGAFbdNvxg97k= 57 - github.com/charmbracelet/x/termios v0.1.0/go.mod h1:H/EVv/KRnrYjz+fCYa9bsKdqF3S8ouDK0AZEbG7r+/U= 58 - github.com/cloudflare/circl v1.5.0 h1:hxIWksrX6XN5a1L2TI/h53AGPhNHoUBo+TD1ms9+pys= 59 - github.com/cloudflare/circl v1.5.0/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= 54 + github.com/charmbracelet/x/termios v0.1.1 h1:o3Q2bT8eqzGnGPOYheoYS8eEleT5ZVNYNy8JawjaNZY= 55 + github.com/charmbracelet/x/termios v0.1.1/go.mod h1:rB7fnv1TgOPOyyKRJ9o+AsTU/vK5WHJ2ivHeut/Pcwo= 56 + github.com/cli/browser v1.3.0 h1:LejqCrpWr+1pRqmEPDGnTZOjsMe7sehifLynZJuqJpo= 57 + github.com/cli/browser v1.3.0/go.mod h1:HH8s+fOAxjhQoBUAsKuPCbqUuxZDhQ2/aD+SzsEfBTk= 58 + github.com/clipperhouse/stringish v0.1.1 h1:+NSqMOr3GR6k1FdRhhnXrLfztGzuG+VuFDfatpWHKCs= 59 + github.com/clipperhouse/stringish v0.1.1/go.mod h1:v/WhFtE1q0ovMta2+m+UbpZ+2/HEXNWYXQgCt4hdOzA= 60 + github.com/clipperhouse/uax29/v2 v2.3.0 h1:SNdx9DVUqMoBuBoW3iLOj4FQv3dN5mDtuqwuhIGpJy4= 61 + github.com/clipperhouse/uax29/v2 v2.3.0/go.mod h1:Wn1g7MK6OoeDT0vL+Q0SQLDz/KpfsVRgg6W7ihQeh4g= 62 + github.com/cloudflare/circl v1.6.1 h1:zqIqSPIndyBh1bjLVVDHMPpVKqp8Su/V+6MeDzzQBQ0= 63 + github.com/cloudflare/circl v1.6.1/go.mod h1:uddAzsPgqdMAYatqJ0lsjX1oECcQLIlRpzZh3pJrofs= 60 64 github.com/creack/pty v1.1.24 h1:bJrF4RRfyJnbTJqzRLHzcGaZK1NeM5kTC9jGgovnR1s= 61 65 github.com/creack/pty v1.1.24/go.mod h1:08sCNb52WyoAwi2QDyzUCTgcvVFhUzewun7wtTfvcwE= 62 - github.com/cyphar/filepath-securejoin v0.3.6 h1:4d9N5ykBnSp5Xn2JkhocYDkOpURL/18CYMpo6xB9uWM= 63 - github.com/cyphar/filepath-securejoin v0.3.6/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= 66 + github.com/cyphar/filepath-securejoin v0.5.0 h1:hIAhkRBMQ8nIeuVwcAoymp7MY4oherZdAxD+m0u9zaw= 67 + github.com/cyphar/filepath-securejoin v0.5.0/go.mod h1:Sdj7gXlvMcPZsbhwhQ33GguGLDGQL7h7bg04C/+u9jI= 64 68 github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 65 69 github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 66 70 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc h1:U9qPSI2PIWSS1VwoXQT9A3Wy9MM3WgvqSxFWenqJduM= 67 71 github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= 68 72 github.com/dlclark/regexp2 v1.4.0/go.mod h1:2pZnwuY/m+8K6iRw6wQdMtk+rH5tNGR1i55kozfMjCc= 69 73 github.com/dlclark/regexp2 v1.7.0/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= 70 - github.com/dlclark/regexp2 v1.11.4 h1:rPYF9/LECdNymJufQKmri9gV604RvvABwgOA8un7yAo= 71 - github.com/dlclark/regexp2 v1.11.4/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= 74 + github.com/dlclark/regexp2 v1.11.5 h1:Q/sSnsKerHeCkc/jSTNq1oCm7KiVgUMZRDUoRu0JQZQ= 75 + github.com/dlclark/regexp2 v1.11.5/go.mod h1:DHkYz0B9wPfa6wondMfaivmHpzrQ3v9q8cnmRbL6yW8= 72 76 github.com/dustin/go-humanize v1.0.1 h1:GzkhY7T5VNhEkwH0PVJgjz+fX1rhBrR7pRT3mDkpeCY= 73 77 github.com/dustin/go-humanize v1.0.1/go.mod h1:Mu1zIs6XwVuF/gI1OepvI0qD18qycQx+mFykh5fBlto= 74 - github.com/elazarl/goproxy v1.2.3 h1:xwIyKHbaP5yfT6O9KIeYJR5549MXRQkoQMRXGztz8YQ= 75 - github.com/elazarl/goproxy v1.2.3/go.mod h1:YfEbZtqP4AetfO6d40vWchF3znWX7C7Vd6ZMfdL8z64= 78 + github.com/elazarl/goproxy v1.7.2 h1:Y2o6urb7Eule09PjlhQRGNsqRfPmYI3KKQLFpCAV3+o= 79 + github.com/elazarl/goproxy v1.7.2/go.mod h1:82vkLNir0ALaW14Rc399OTTjyNREgmdL2cVoIbS6XaE= 76 80 github.com/emirpasic/gods v1.18.1 h1:FXtiHYKDGKCW2KzwZKx0iC0PQmdlorYgdFG9jPXJ1Bc= 77 81 github.com/emirpasic/gods v1.18.1/go.mod h1:8tpGGwCnJ5H4r6BWwaV6OrWmMoPhUl5jm/FMNAnJvWQ= 78 82 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= 79 83 github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= 84 + github.com/fatih/color v1.16.0 h1:zmkK9Ngbjj+K0yRhTVONQh1p/HknKYSlNT+vZCzyokM= 85 + github.com/fatih/color v1.16.0/go.mod h1:fL2Sau1YI5c0pdGEVCbKQbLXB6edEj1ZgiY4NijnWvE= 86 + github.com/fsnotify/fsnotify v1.7.0 h1:8JEhPFa5W2WU7YfeZzPNqzMP6Lwt7L2715Ggo0nosvA= 87 + github.com/fsnotify/fsnotify v1.7.0/go.mod h1:40Bi/Hjc2AVfZrqy+aj+yEI+/bRxZnMJyTJwOpGvigM= 80 88 github.com/gliderlabs/ssh v0.3.8 h1:a4YXD1V7xMF9g5nTkdfnja3Sxy1PVDCj1Zg4Wb8vY6c= 81 89 github.com/gliderlabs/ssh v0.3.8/go.mod h1:xYoytBv1sV0aL3CavoDuJIQNURXkkfPA/wxQ1pL1fAU= 82 - github.com/go-chi/chi/v5 v5.2.0 h1:Aj1EtB0qR2Rdo2dG4O94RIU35w2lvQSj6BRA4+qwFL0= 83 - github.com/go-chi/chi/v5 v5.2.0/go.mod h1:DslCQbL2OYiznFReuXYUmQ2hGd1aDpCnlMNITLSKoi8= 90 + github.com/go-chi/chi/v5 v5.2.3 h1:WQIt9uxdsAbgIYgid+BpYc+liqQZGMHRaUwp0JUcvdE= 91 + github.com/go-chi/chi/v5 v5.2.3/go.mod h1:L2yAIGWB3H+phAw1NxKwWM+7eUH/lU8pOMm5hHcoops= 84 92 github.com/go-chi/httplog/v2 v2.1.1 h1:ojojiu4PIaoeJ/qAO4GWUxJqvYUTobeo7zmuHQJAxRk= 85 93 github.com/go-chi/httplog/v2 v2.1.1/go.mod h1:/XXdxicJsp4BA5fapgIC3VuTD+z0Z/VzukoB3VDc1YE= 86 94 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 h1:+zs/tPmkDkHx3U66DAb0lQFJrpS6731Oaa12ikc+DiI= 87 95 github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376/go.mod h1:an3vInlBmSxCcxctByoQdvwPiA7DTK7jaaFDBTtu0ic= 88 - github.com/go-git/go-billy/v5 v5.6.1 h1:u+dcrgaguSSkbjzHwelEjc0Yj300NUevrrPphk/SoRA= 89 - github.com/go-git/go-billy/v5 v5.6.1/go.mod h1:0AsLr1z2+Uksi4NlElmMblP5rPcDZNRCD8ujZCRR2BE= 96 + github.com/go-git/go-billy/v5 v5.6.2 h1:6Q86EsPXMa7c3YZ3aLAQsMA0VlWmy43r6FHqa/UNbRM= 97 + github.com/go-git/go-billy/v5 v5.6.2/go.mod h1:rcFC2rAsp/erv7CMz9GczHcuD0D32fWzH+MJAU+jaUU= 90 98 github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399 h1:eMje31YglSBqCdIqdhKBW8lokaMrL3uTkpGYlE2OOT4= 91 99 github.com/go-git/go-git-fixtures/v4 v4.3.2-0.20231010084843-55a94097c399/go.mod h1:1OCfN199q1Jm3HZlxleg+Dw/mwps2Wbk9frAWm+4FII= 92 - github.com/go-git/go-git/v5 v5.13.1 h1:DAQ9APonnlvSWpvolXWIuV6Q6zXy2wHbN4cVlNR5Q+M= 93 - github.com/go-git/go-git/v5 v5.13.1/go.mod h1:qryJB4cSBoq3FRoBRf5A77joojuBcmPJ0qu3XXXVixc= 94 - github.com/go-logfmt/logfmt v0.6.0 h1:wGYYu3uicYdqXVgoYbvnkrPVXkuLM1p1ifugDMEdRi4= 95 - github.com/go-logfmt/logfmt v0.6.0/go.mod h1:WYhtIu8zTZfxdn5+rREduYbwxfcBr/Vr6KEVveWlfTs= 100 + github.com/go-git/go-git/v5 v5.16.3 h1:Z8BtvxZ09bYm/yYNgPKCzgWtaRqDTgIKRgIRHBfU6Z8= 101 + github.com/go-git/go-git/v5 v5.16.3/go.mod h1:4Ge4alE/5gPs30F2H1esi2gPd69R0C39lolkucHBOp8= 102 + github.com/go-logfmt/logfmt v0.6.1 h1:4hvbpePJKnIzH1B+8OR/JPbTx37NktoI9LE2QZBBkvE= 103 + github.com/go-logfmt/logfmt v0.6.1/go.mod h1:EV2pOAQoZaT1ZXZbqDl5hrymndi4SY9ED9/z6CO0XAk= 96 104 github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8 h1:f+oWsMOmNPc8JmEHVZIycC7hBoQxHH9pNKQORJNozsQ= 97 105 github.com/golang/groupcache v0.0.0-20241129210726-2c02b8208cf8/go.mod h1:wcDNUvekVysuuOpQKo3191zZyTpiI6se1N1ULghS0sw= 98 - github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= 99 - github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= 106 + github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= 107 + github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= 100 108 github.com/hexops/gotextdiff v1.0.3 h1:gitA9+qJrrTCsiCl7+kh75nPqQt1cx4ZkudSTLoUqJM= 101 109 github.com/hexops/gotextdiff v1.0.3/go.mod h1:pSWU5MAI3yDq+fZBTazCSJysOMbxWL1BSow5/V2vxeg= 102 110 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99 h1:BQSFePA1RWJOlocH6Fxy8MmwDt+yVQYULKfN0RoTN8A= 103 111 github.com/jbenet/go-context v0.0.0-20150711004518-d14ea06fba99/go.mod h1:1lJo3i6rXxKeerYnT8Nvf0QmHCRC1n8sfWVwXF2Frvo= 104 - github.com/kevinburke/ssh_config v1.2.0 h1:x584FjTGwHzMwvHx18PXxbBVzfnxogHaAReU4gf13a4= 105 - github.com/kevinburke/ssh_config v1.2.0/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= 112 + github.com/kevinburke/ssh_config v1.4.0 h1:6xxtP5bZ2E4NF5tuQulISpTO2z8XbtH8cg1PWkxoFkQ= 113 + github.com/kevinburke/ssh_config v1.4.0/go.mod h1:q2RIzfka+BXARoNexmF9gkxEX7DmvbW9P4hIVx2Kg4M= 114 + github.com/klauspost/cpuid/v2 v2.3.0 h1:S4CRMLnYUhGeDFDqkGriYKdfoFlDnMtqTiI/sFzhA9Y= 115 + github.com/klauspost/cpuid/v2 v2.3.0/go.mod h1:hqwkgyIinND0mEev00jJYCxPNVRVXFQeu1XKlok6oO0= 106 116 github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= 107 117 github.com/kr/pretty v0.3.1 h1:flRD4NNwYAUpkphVc1HcthR4KEIFJ65n8Mw5qdRn3LE= 108 118 github.com/kr/pretty v0.3.1/go.mod h1:hoEshYVHaxMs3cyo3Yncou5ZscifuDolrwPKZanG3xk= ··· 110 120 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= 111 121 github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY= 112 122 github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE= 113 - github.com/kylelemons/godebug v1.1.0 h1:RPNrshWIDI6G2gRW9EHilWtl7Z6Sb1BR0xunSBf0SNc= 114 - github.com/kylelemons/godebug v1.1.0/go.mod h1:9/0rRGxNHcop5bhtWyNeEfOS8JIWk580+fNqagV/RAw= 115 - github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= 116 - github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 123 + github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= 124 + github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= 125 + github.com/mattn/go-colorable v0.1.13 h1:fFA4WZxdEF4tXPZVKMLwD8oUnCTTo08duU7wxecdEvA= 126 + github.com/mattn/go-colorable v0.1.13/go.mod h1:7S9/ev0klgBDR4GtXTXX8a3vIGJpMovkB8vQcUbaXHg= 127 + github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= 117 128 github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= 118 129 github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= 119 130 github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= 120 131 github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= 121 - github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= 122 - github.com/mattn/go-runewidth v0.0.16/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= 123 - github.com/mmcloughlin/avo v0.6.0 h1:QH6FU8SKoTLaVs80GA8TJuLNkUYl4VokHKlPhVDg4YY= 124 - github.com/mmcloughlin/avo v0.6.0/go.mod h1:8CoAGaCSYXtCPR+8y18Y9aB/kxb8JSS6FRI7mSkvD+8= 132 + github.com/mattn/go-runewidth v0.0.19 h1:v++JhqYnZuu5jSKrk9RbgF5v4CGUjqRfBm05byFGLdw= 133 + github.com/mattn/go-runewidth v0.0.19/go.mod h1:XBkDxAl56ILZc9knddidhrOlY5R/pDhgLpndooCuJAs= 125 134 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= 126 135 github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= 127 136 github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= 128 137 github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= 129 138 github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= 130 139 github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= 140 + github.com/natefinch/atomic v1.0.1 h1:ZPYKxkqQOx3KZ+RsbnP/YsgvxWQPGxjC0oBt2AhwV0A= 141 + github.com/natefinch/atomic v1.0.1/go.mod h1:N/D/ELrljoqDyT3rZrsUmtsuzvHkeB/wWjHV22AZRbM= 131 142 github.com/onsi/gomega v1.34.1 h1:EUMJIKUjM8sKjYbtxQI9A4z2o+rruxnzNvpknOXie6k= 132 143 github.com/onsi/gomega v1.34.1/go.mod h1:kU1QgUvBDLXBJq618Xvm2LUX6rSAfRaFRTcdOeDLwwY= 133 144 github.com/peterbourgon/ff/v3 v3.4.0 h1:QBvM/rizZM1cB0p0lGMdmR7HxZeI/ZrBWB4DqLkMUBc= 134 145 github.com/peterbourgon/ff/v3 v3.4.0/go.mod h1:zjJVUhx+twciwfDl0zBcFzl4dW8axCRyXE/eKY9RztQ= 135 - github.com/pjbgf/sha1cd v0.3.1 h1:Dh2GYdpJnO84lIw0LJwTFXjcNbasP/bklicSznyAaPI= 136 - github.com/pjbgf/sha1cd v0.3.1/go.mod h1:Y8t7jSB/dEI/lQE04A1HVKteqjj9bX5O4+Cex0TCu8s= 146 + github.com/pjbgf/sha1cd v0.5.0 h1:a+UkboSi1znleCDUNT3M5YxjOnN1fz2FhN48FlwCxs0= 147 + github.com/pjbgf/sha1cd v0.5.0/go.mod h1:lhpGlyHLpQZoxMv8HcgXvZEhcGs0PG/vsZnEJ7H0iCM= 137 148 github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= 138 149 github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= 139 150 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 140 151 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 h1:Jamvg5psRIccs7FGNTlIRMkT8wgtp5eCXdBlqhYGL6U= 141 152 github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= 142 - github.com/rivo/uniseg v0.2.0/go.mod h1:J6wj4VEh+S6ZtnVlnTBMWIodfgj8LQOQFoIToxlJtxc= 143 153 github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= 144 154 github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= 145 - github.com/rogpeppe/go-internal v1.12.0 h1:exVL4IDcn6na9z1rAb56Vxr+CgyK3nn3O+epU5NdKM8= 146 - github.com/rogpeppe/go-internal v1.12.0/go.mod h1:E+RYuTGaKKdloAfM02xzb0FW3Paa99yedzYV+kq4uf4= 147 - github.com/sahilm/fuzzy v0.1.1 h1:ceu5RHF8DGgoi+/dR5PsECjCDH1BE3Fnmpo7aVXOdRA= 148 - github.com/sahilm/fuzzy v0.1.1/go.mod h1:VFvziUEIMCrT6A6tw2RFIXPXXmzXbOsSHF0DOI8ZK9Y= 149 - github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3 h1:n661drycOFuPLCN3Uc8sB6B/s6Z4t2xvBgU1htSHuq8= 150 - github.com/sergi/go-diff v1.3.2-0.20230802210424-5b0b94c5c0d3/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= 155 + github.com/rogpeppe/go-internal v1.14.1 h1:UQB4HGPB6osV0SQTLymcB4TgvyWu6ZyliaW0tI/otEQ= 156 + github.com/rogpeppe/go-internal v1.14.1/go.mod h1:MaRKkUm5W0goXpeCfT7UZI6fk/L7L7so1lCWt35ZSgc= 157 + github.com/sergi/go-diff v1.4.0 h1:n/SP9D5ad1fORl+llWyN+D6qoUETXNZARKjyY2/KVCw= 158 + github.com/sergi/go-diff v1.4.0/go.mod h1:A0bzQcvG0E7Rwjx0REVgAGH58e96+X0MeOfepqsbeW4= 151 159 github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= 152 - github.com/skeema/knownhosts v1.3.0 h1:AM+y0rI04VksttfwjkSTNQorvGqmwATnvnAHpSgc0LY= 153 - github.com/skeema/knownhosts v1.3.0/go.mod h1:sPINvnADmT/qYH1kfv+ePMmOBTH6Tbl7b5LvTDjFK7M= 160 + github.com/skeema/knownhosts v1.3.2 h1:EDL9mgf4NzwMXCTfaxSD/o/a5fxDw/xL9nkU28JjdBg= 161 + github.com/skeema/knownhosts v1.3.2/go.mod h1:bEg3iQAuw+jyiw+484wwFJoKSLwcfd7fqRy+N0QTiow= 154 162 github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= 155 163 github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= 156 164 github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= ··· 162 170 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= 163 171 github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= 164 172 github.com/yuin/goldmark v1.4.15/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= 165 - github.com/yuin/goldmark v1.7.1/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= 166 - github.com/yuin/goldmark v1.7.8 h1:iERMLn0/QJeHFhxSt3p6PeN9mGnvIKSpG9YYorDMnic= 167 - github.com/yuin/goldmark v1.7.8/go.mod h1:uzxRWxtg69N339t3louHJ7+O03ezfj6PlliRlaOzY1E= 168 - github.com/yuin/goldmark-emoji v1.0.4 h1:vCwMkPZSNefSUnOW2ZKRUjBSD5Ok3W78IXhGxxAEF90= 169 - github.com/yuin/goldmark-emoji v1.0.4/go.mod h1:tTkZEbwu5wkPmgTcitqddVxY9osFZiavD+r4AzQrh1U= 173 + github.com/yuin/goldmark v1.7.13 h1:GPddIs617DnBLFFVJFgpo1aBfe/4xcvMc3SB5t/D0pA= 174 + github.com/yuin/goldmark v1.7.13/go.mod h1:ip/1k0VRfGynBgxOz0yCqHrbZXhcjxyuS66Brc7iBKg= 175 + github.com/yuin/goldmark-emoji v1.0.6 h1:QWfF2FYaXwL74tfGOW5izeiZepUDroDJfWubQI9HTHs= 176 + github.com/yuin/goldmark-emoji v1.0.6/go.mod h1:ukxJDKFpdFb5x0a5HqbdlcKtebh086iJpI31LTKmWuA= 170 177 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc h1:+IAOyRda+RLrxa1WC7umKOZRsGq4QrFFMYApOeHzQwQ= 171 178 github.com/yuin/goldmark-highlighting/v2 v2.0.0-20230729083705-37449abec8cc/go.mod h1:ovIvrum6DQJA4QsJSovrkC4saKHQVs7TvcaeO8AIl5I= 172 179 golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= 173 - golang.org/x/crypto v0.32.0 h1:euUpcYgM8WcP71gNpTqQCn6rC2t6ULUPiOzfWaXVVfc= 174 - golang.org/x/crypto v0.32.0/go.mod h1:ZnnJkOaASj8g0AjIduWNlq2NRxL0PlBrbKVyZ6V/Ugc= 175 - golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8 h1:yqrTHse8TCMW1M1ZCP+VAR/l0kKxwaAIqN/il7x4voA= 176 - golang.org/x/exp v0.0.0-20250106191152-7588d65b2ba8/go.mod h1:tujkw807nyEEAamNbDrEGzRav+ilXA7PCRAd6xsmwiU= 177 - golang.org/x/mod v0.22.0 h1:D4nJWe9zXqHOmWqj4VMOJhvzj7bEZg4wEYa759z1pH4= 178 - golang.org/x/mod v0.22.0/go.mod h1:6SkKJ3Xj0I0BrPOZoBy3bdMptDDU9oJrpohJ3eWZ1fY= 180 + golang.org/x/crypto v0.43.0 h1:dduJYIi3A3KOfdGOHX8AVZ/jGiyPa3IbBozJ5kNuE04= 181 + golang.org/x/crypto v0.43.0/go.mod h1:BFbav4mRNlXJL4wNeejLpWxB7wMbc79PdRGhWKncxR0= 182 + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546 h1:mgKeJMpvi0yx/sU5GsxQ7p6s2wtOnGAHZWCHUM4KGzY= 183 + golang.org/x/exp v0.0.0-20251023183803-a4bb9ffd2546/go.mod h1:j/pmGrbnkbPtQfxEe5D0VQhZC6qKbfKifgD0oM7sR70= 184 + golang.org/x/mod v0.29.0 h1:HV8lRxZC4l2cr3Zq1LvtOsi/ThTgWnUk/y64QSs8GwA= 185 + golang.org/x/mod v0.29.0/go.mod h1:NyhrlYXJ2H4eJiRy/WDBO6HMqZQ6q9nk4JzS3NuCK+w= 179 186 golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= 180 - golang.org/x/net v0.34.0 h1:Mb7Mrk043xzHgnRM88suvJFwzVrRfHEHJEl5/71CKw0= 181 - golang.org/x/net v0.34.0/go.mod h1:di0qlW3YNM5oh6GqDGQr92MyTozJPmybPK4Ev/Gm31k= 182 - golang.org/x/sync v0.13.0 h1:AauUjRAJ9OSnvULf/ARrrVywoJDy0YS2AwQ98I37610= 183 - golang.org/x/sync v0.13.0/go.mod h1:1dzgHSNfp02xaA81J2MS99Qcpr2w7fw1gpm99rleRqA= 187 + golang.org/x/net v0.46.0 h1:giFlY12I07fugqwPuWJi68oOnpfqFnJIJzaIIm2JVV4= 188 + golang.org/x/net v0.46.0/go.mod h1:Q9BGdFy1y4nkUwiLvT5qtyhAnEHgnQ/zd8PfU6nc210= 189 + golang.org/x/sync v0.17.0 h1:l60nONMj9l5drqw6jlhIELNv9I0A4OFgRsG9k2oT9Ug= 190 + golang.org/x/sync v0.17.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= 184 191 golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 185 192 golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= 186 193 golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= ··· 188 195 golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 189 196 golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 190 197 golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 198 + golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 191 199 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= 192 - golang.org/x/sys v0.32.0 h1:s77OFDvIQeibCmezSnk/q6iAfkdiQaJi4VzroCFrN20= 193 - golang.org/x/sys v0.32.0/go.mod h1:BJP2sWEmIv4KK5OTEluFJCKSidICx8ciO85XgH3Ak8k= 200 + golang.org/x/sys v0.37.0 h1:fdNQudmxPjkdUTPnLn5mdQv7Zwvbvpaxqs831goi9kQ= 201 + golang.org/x/sys v0.37.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= 194 202 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= 195 - golang.org/x/term v0.28.0 h1:/Ts8HFuMR2E6IP/jlo7QVLZHggjKQbhu/7H0LJFr3Gg= 196 - golang.org/x/term v0.28.0/go.mod h1:Sw/lC2IAUZ92udQNf3WodGtn4k/XoLyZoh8v/8uiwek= 203 + golang.org/x/term v0.36.0 h1:zMPR+aF8gfksFprF/Nc/rd1wRS1EI6nDBGyWAvDzx2Q= 204 + golang.org/x/term v0.36.0/go.mod h1:Qu394IJq6V6dCBRgwqshf3mPF85AqzYEzofzRdZkWss= 197 205 golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= 198 - golang.org/x/text v0.21.0 h1:zyQAAkrwaneQ066sspRyJaG9VNi/YJ1NfzcGB3hZ/qo= 199 - golang.org/x/text v0.21.0/go.mod h1:4IBbMaMmOPCJ8SecivzSH54+73PCFmPWxNTLm+vZkEQ= 206 + golang.org/x/text v0.30.0 h1:yznKA/E9zq54KzlzBEAWn1NXSQ8DIp/NYMy88xJjl4k= 207 + golang.org/x/text v0.30.0/go.mod h1:yDdHFIX9t+tORqspjENWgzaCVXgk0yYnYuSZ8UzzBVM= 200 208 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= 201 - golang.org/x/tools v0.29.0 h1:Xx0h3TtM9rzQpQuR4dKLrdglAmCEN5Oi+P74JdhdzXE= 202 - golang.org/x/tools v0.29.0/go.mod h1:KMQVMRsVxU6nHCFXrBPhDB8XncLNLM0lIy/F14RP588= 209 + golang.org/x/tools v0.38.0 h1:Hx2Xv8hISq8Lm16jvBZ2VQf+RLmbd7wVUsALibYI/IQ= 210 + golang.org/x/tools v0.38.0/go.mod h1:yEsQ/d/YK8cjh0L6rZlY8tgtlKiBNTL14pGDJPJpYQs= 203 211 gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 204 212 gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= 205 213 gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk= ··· 212 220 gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 213 221 gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= 214 222 gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= 215 - maragu.dev/gomponents v1.0.0 h1:eeLScjq4PqP1l+r5z/GC+xXZhLHXa6RWUWGW7gSfLh4= 216 - maragu.dev/gomponents v1.0.0/go.mod h1:oEDahza2gZoXDoDHhw8jBNgH+3UR5ni7Ur648HORydM=
+2 -2
internal/git/grep.go
··· 18 18 19 19 // Grep performs a naive "code search" via git grep 20 20 func (r Repo) Grep(search string) ([]GrepResult, error) { 21 - if strings.HasPrefix(search, "=") { 22 - search = regexp.QuoteMeta(strings.TrimPrefix(search, "=")) 21 + if after, ok := strings.CutPrefix(search, "="); ok { 22 + search = regexp.QuoteMeta(after) 23 23 } 24 24 re, err := regexp.Compile(search) 25 25 if err != nil {
+4 -3
internal/git/meta.go
··· 53 53 54 54 // UnmarshalJSON implements [json.Unmarshaler] 55 55 func (t *TagSet) UnmarshalJSON(b []byte) error { 56 + if *t == nil { 57 + ts := make(TagSet) 58 + t = &ts 59 + } 56 60 var s []string 57 61 if err := json.Unmarshal(b, &s); err != nil { 58 62 return err 59 - } 60 - if *t == nil { 61 - *t = make(TagSet) 62 63 } 63 64 for _, ss := range s { 64 65 t.Add(ss)
-61
internal/git/repo_utils.go
··· 1 - package git 2 - 3 - import ( 4 - "errors" 5 - "io/fs" 6 - "os" 7 - "path/filepath" 8 - "strings" 9 - ) 10 - 11 - // ListRepos returns all directory entries in the given directory 12 - func ListRepos(dir string) ([]fs.DirEntry, error) { 13 - entries, err := os.ReadDir(dir) 14 - if err != nil { 15 - if errors.Is(err, fs.ErrNotExist) { 16 - return []fs.DirEntry{}, nil 17 - } 18 - return nil, err 19 - } 20 - return entries, nil 21 - } 22 - 23 - // DeleteRepo deletes a git repository from the filesystem 24 - func DeleteRepo(repoPath string) error { 25 - return os.RemoveAll(repoPath) 26 - } 27 - 28 - // RenameRepo renames a git repository 29 - func RenameRepo(repoDir, oldName, newName string) error { 30 - if !filepath.IsAbs(repoDir) { 31 - return errors.New("repository directory must be an absolute path") 32 - } 33 - 34 - if !filepath.IsAbs(oldName) && !filepath.IsAbs(newName) { 35 - oldPath := filepath.Join(repoDir, oldName) 36 - if !strings.HasSuffix(oldPath, ".git") { 37 - oldPath += ".git" 38 - } 39 - 40 - newPath := filepath.Join(repoDir, newName) 41 - if !strings.HasSuffix(newPath, ".git") { 42 - newPath += ".git" 43 - } 44 - 45 - return os.Rename(oldPath, newPath) 46 - } 47 - 48 - return errors.New("repository names should not be absolute paths") 49 - } 50 - 51 - // RepoPathExists checks if a path exists 52 - func RepoPathExists(path string) (bool, error) { 53 - _, err := os.Stat(path) 54 - if err == nil { 55 - return true, nil 56 - } 57 - if errors.Is(err, fs.ErrNotExist) { 58 - return false, nil 59 - } 60 - return false, err 61 - }
-38
internal/html/base.go
··· 1 - package html 2 - 3 - import ( 4 - . "maragu.dev/gomponents" 5 - . "maragu.dev/gomponents/components" 6 - . "maragu.dev/gomponents/html" 7 - ) 8 - 9 - type BaseContext struct { 10 - Title string 11 - Description string 12 - } 13 - 14 - func base(bc BaseContext, children ...Node) Node { 15 - return HTML5(HTML5Props{ 16 - Title: bc.Title, 17 - Description: bc.Description, 18 - Head: []Node{ 19 - Link(Rel("icon"), Href("/_/favicon.svg")), 20 - Link(Rel("stylesheet"), Href("/_/tailwind.css")), 21 - ogp("title", bc.Title), 22 - ogp("description", bc.Description), 23 - Meta(Name("forge"), Content("ugit")), 24 - Meta(Name("keywords"), Content("git,forge,ugit")), 25 - }, 26 - Body: []Node{ 27 - Class("latte dark:mocha bg-base/50 dark:bg-base/95 max-w-7xl mx-5 sm:mx-auto my-10"), 28 - H2(Class("text-text text-xl mb-3"), 29 - A(Class("text-text text-xl mb-3"), Href("/"), Text("Home")), 30 - ), 31 - Group(children), 32 - }, 33 - }) 34 - } 35 - 36 - func ogp(property, content string) Node { 37 - return El("meta", Attr("property", "og:"+property), Attr("content", content)) 38 - }
+27
internal/html/base.templ
··· 1 + package html 2 + 3 + type BaseContext struct { 4 + Title string 5 + Description string 6 + } 7 + 8 + templ base(bc BaseContext) { 9 + <!DOCTYPE html> 10 + <html> 11 + <head> 12 + <meta charset="UTF-8"/> 13 + <meta name="viewport" content="width=device-width, initial-scale=1.0"/> 14 + <title>{ bc.Title }</title> 15 + <link rel="icon" href="/_/favicon.svg"/> 16 + <link rel="stylesheet" href="/_/tailwind.css"/> 17 + <meta property="og:title" content={ bc.Title }/> 18 + <meta property="og:description" content={ bc.Description }/> 19 + </head> 20 + <body class="latte dark:mocha bg-base/50 dark:bg-base/95 max-w-7xl mx-5 sm:mx-auto my-10"> 21 + <h2 class="text-text text-xl mb-3"> 22 + <a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href="/">Home</a> 23 + </h2> 24 + { children... } 25 + </body> 26 + </html> 27 + }
+92
internal/html/base_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + type BaseContext struct { 12 + Title string 13 + Description string 14 + } 15 + 16 + func base(bc BaseContext) templ.Component { 17 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 18 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 19 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 20 + return templ_7745c5c3_CtxErr 21 + } 22 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 23 + if !templ_7745c5c3_IsBuffer { 24 + defer func() { 25 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 26 + if templ_7745c5c3_Err == nil { 27 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 28 + } 29 + }() 30 + } 31 + ctx = templ.InitializeContext(ctx) 32 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 33 + if templ_7745c5c3_Var1 == nil { 34 + templ_7745c5c3_Var1 = templ.NopComponent 35 + } 36 + ctx = templ.ClearChildren(ctx) 37 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<!doctype html><html><head><meta charset=\"UTF-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1.0\"><title>") 38 + if templ_7745c5c3_Err != nil { 39 + return templ_7745c5c3_Err 40 + } 41 + var templ_7745c5c3_Var2 string 42 + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(bc.Title) 43 + if templ_7745c5c3_Err != nil { 44 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `base.templ`, Line: 14, Col: 20} 45 + } 46 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) 47 + if templ_7745c5c3_Err != nil { 48 + return templ_7745c5c3_Err 49 + } 50 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</title><link rel=\"icon\" href=\"/_/favicon.svg\"><link rel=\"stylesheet\" href=\"/_/tailwind.css\"><meta property=\"og:title\" content=\"") 51 + if templ_7745c5c3_Err != nil { 52 + return templ_7745c5c3_Err 53 + } 54 + var templ_7745c5c3_Var3 string 55 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(bc.Title) 56 + if templ_7745c5c3_Err != nil { 57 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `base.templ`, Line: 17, Col: 47} 58 + } 59 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 60 + if templ_7745c5c3_Err != nil { 61 + return templ_7745c5c3_Err 62 + } 63 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"><meta property=\"og:description\" content=\"") 64 + if templ_7745c5c3_Err != nil { 65 + return templ_7745c5c3_Err 66 + } 67 + var templ_7745c5c3_Var4 string 68 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(bc.Description) 69 + if templ_7745c5c3_Err != nil { 70 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `base.templ`, Line: 18, Col: 59} 71 + } 72 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 73 + if templ_7745c5c3_Err != nil { 74 + return templ_7745c5c3_Err 75 + } 76 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\"></head><body class=\"latte dark:mocha bg-base/50 dark:bg-base/95 max-w-7xl mx-5 sm:mx-auto my-10\"><h2 class=\"text-text text-xl mb-3\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"/\">Home</a></h2>") 77 + if templ_7745c5c3_Err != nil { 78 + return templ_7745c5c3_Err 79 + } 80 + templ_7745c5c3_Err = templ_7745c5c3_Var1.Render(ctx, templ_7745c5c3_Buffer) 81 + if templ_7745c5c3_Err != nil { 82 + return templ_7745c5c3_Err 83 + } 84 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</body></html>") 85 + if templ_7745c5c3_Err != nil { 86 + return templ_7745c5c3_Err 87 + } 88 + return nil 89 + }) 90 + } 91 + 92 + var _ = templruntime.GeneratedTemplate
+2 -1
internal/html/generate.go
··· 26 26 otherCSS string 27 27 ) 28 28 29 + //go:generate go tool templ generate 29 30 //go:generate go run generate.go 30 31 func main() { 31 32 if err := tailwind(); err != nil { ··· 72 73 defer styles.Close() 73 74 74 75 var buf bytes.Buffer 75 - cmd := exec.Command("tailwind-ctp", "-i", tmp.Name(), "--minify") 76 + cmd := exec.Command("tailwind-ctp_3", "-i", tmp.Name(), "--minify") 76 77 cmd.Stdout = &buf 77 78 if err := cmd.Run(); err != nil { 78 79 return err
-105
internal/html/index.go
··· 1 - package html 2 - 3 - import ( 4 - "fmt" 5 - 6 - "github.com/dustin/go-humanize" 7 - "go.jolheiser.com/ugit/assets" 8 - "go.jolheiser.com/ugit/internal/git" 9 - . "maragu.dev/gomponents" 10 - . "maragu.dev/gomponents/html" 11 - ) 12 - 13 - type IndexContext struct { 14 - BaseContext 15 - Profile IndexProfile 16 - Repos []*git.Repo 17 - } 18 - 19 - type IndexProfile struct { 20 - Username string 21 - Email string 22 - Links []IndexLink 23 - } 24 - 25 - type IndexLink struct { 26 - Name string 27 - URL string 28 - } 29 - 30 - func lastCommitTime(repo *git.Repo, human bool) string { 31 - c, err := repo.LastCommit() 32 - if err != nil { 33 - return "" 34 - } 35 - if human { 36 - return humanize.Time(c.When) 37 - } 38 - return c.When.Format("01/02/2006 03:04:05 PM") 39 - } 40 - 41 - func lastCommit(repo *git.Repo) *git.Commit { 42 - c, err := repo.LastCommit() 43 - if err != nil { 44 - return nil 45 - } 46 - return &c 47 - } 48 - 49 - func IndexTemplate(ic IndexContext) Node { 50 - return base(ic.BaseContext, []Node{ 51 - Header( 52 - H1(Class("text-text text-xl font-bold"), Text(ic.Title)), 53 - H2(Class("text-subtext1 text-lg"), Text(ic.Description)), 54 - ), 55 - Main(Class("mt-5"), 56 - Div(Class("grid grid-cols-1 sm:grid-cols-8"), 57 - If(ic.Profile.Username != "", 58 - Div(Class("text-mauve"), Text("@"+ic.Profile.Username)), 59 - ), 60 - If(ic.Profile.Email != "", Group([]Node{ 61 - Div(Class("text-mauve col-span-2"), 62 - Div(Class("w-5 h-5 stroke-mauve inline-block mr-1 align-middle"), Raw(string(assets.EmailIcon))), 63 - A(Class("underline decoration-mauve/50 decoration-dashed hover:decoration-solid"), Href("mailto:"+ic.Profile.Email), Text(ic.Profile.Email)), 64 - ), 65 - }), 66 - ), 67 - ), 68 - Div(Class("grid grid-cols-1 sm:grid-cols-8"), 69 - Map(ic.Profile.Links, func(link IndexLink) Node { 70 - return Div(Class("text-mauve"), 71 - Div(Class("w-5 h-5 stroke-mauve inline-block mr-1 align-middle"), 72 - Raw(string(assets.LinkIcon)), 73 - ), 74 - A(Class("underline decoration-mauve/50 decoration-dashed hover:decoration-solid"), Rel("me"), Href(link.URL), Text(link.Name)), 75 - ) 76 - }), 77 - ), 78 - Div(Class("grid sm:grid-cols-10 gap-2 mt-5"), 79 - Map(ic.Repos, func(repo *git.Repo) Node { 80 - commit := lastCommit(repo) 81 - return Group([]Node{ 82 - Div(Class("sm:col-span-2 text-blue dark:text-lavender"), 83 - A(Class("underline decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid"), Href("/"+repo.Name()), Text(repo.Name())), 84 - ), 85 - Div(Class("sm:col-span-3 text-subtext0"), Text(repo.Meta.Description)), 86 - Div(Class("sm:col-span-3 text-subtext0"), 87 - If(commit != nil, 88 - Div(Title(commit.Message), 89 - A(Class("underline text-blue dark:text-lavender decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/commit/%s", repo.Name(), commit.SHA)), Text(commit.Short())), 90 - Text(": "+commit.Summary()), 91 - ), 92 - ), 93 - ), 94 - Div(Class("sm:col-span-1 text-subtext0"), 95 - Map(repo.Meta.Tags.Slice(), func(tag string) Node { 96 - return A(Class("rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block"), Href("?tag="+tag), Text(tag)) 97 - }), 98 - ), 99 - Div(Class("sm:col-span-1 text-text/80 mb-4 sm:mb-0"), Title(lastCommitTime(repo, false)), Text(lastCommitTime(repo, true))), 100 - }) 101 - }), 102 - ), 103 - ), 104 - }...) 105 - }
+99
internal/html/index.templ
··· 1 + package html 2 + 3 + import ( 4 + "fmt" 5 + "github.com/dustin/go-humanize" 6 + "go.jolheiser.com/ugit/assets" 7 + "go.jolheiser.com/ugit/internal/git" 8 + ) 9 + 10 + type IndexContext struct { 11 + BaseContext 12 + Profile IndexProfile 13 + Repos []*git.Repo 14 + } 15 + 16 + type IndexProfile struct { 17 + Username string 18 + Email string 19 + Links []IndexLink 20 + } 21 + 22 + type IndexLink struct { 23 + Name string 24 + URL string 25 + } 26 + 27 + func lastCommitTime(repo *git.Repo, human bool) string { 28 + c, err := repo.LastCommit() 29 + if err != nil { 30 + return "" 31 + } 32 + if human { 33 + return humanize.Time(c.When) 34 + } 35 + return c.When.Format("01/02/2006 03:04:05 PM") 36 + } 37 + 38 + func lastCommit(repo *git.Repo) *git.Commit { 39 + c, err := repo.LastCommit() 40 + if err != nil { 41 + return nil 42 + } 43 + return &c 44 + } 45 + 46 + templ Index(ic IndexContext) { 47 + @base(ic.BaseContext) { 48 + <header> 49 + <h1 class="text-text text-xl font-bold">{ ic.Title }</h1> 50 + <h2 class="text-subtext1 text-lg">{ ic.Description }</h2> 51 + </header> 52 + <main class="mt-5"> 53 + <div class="grid grid-cols-1 sm:grid-cols-8"> 54 + if ic.Profile.Username != "" { 55 + <div class="text-mauve">{ `@` + ic.Profile.Username }</div> 56 + } 57 + if ic.Profile.Email != "" { 58 + <div class="text-mauve col-span-2"> 59 + <div class="w-5 h-5 stroke-mauve inline-block mr-1 align-middle"> 60 + @templ.Raw(string(assets.EmailIcon)) 61 + </div> 62 + <a class="underline decoration-mauve/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL("mailto:" + ic.Profile.Email) }>{ ic.Profile.Email }</a> 63 + </div> 64 + } 65 + </div> 66 + <div class="grid grid-cols-1 sm:grid-cols-8"> 67 + for _, link := range ic.Profile.Links { 68 + <div class="text-mauve"> 69 + <div class="w-5 h-5 stroke-mauve inline-block mr-1 align-middle"> 70 + @templ.Raw(string(assets.LinkIcon)) 71 + </div> 72 + <a class="underline decoration-mauve/50 decoration-dashed hover:decoration-solid" rel="me" href={ templ.SafeURL(link.URL) }>{ link.Name }</a> 73 + </div> 74 + } 75 + </div> 76 + <div class="grid sm:grid-cols-10 gap-2 mt-5"> 77 + for _, repo := range ic.Repos { 78 + {{ commit := lastCommit(repo) }} 79 + <div class="sm:col-span-2 text-blue dark:text-lavender"><a class="underline decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid" href={ templ.URL("/" + repo.Name()) }>{ repo.Name() }</a></div> 80 + <div class="sm:col-span-3 text-subtext0">{ repo.Meta.Description }</div> 81 + <div class="sm:col-span-3 text-subtext0"> 82 + if commit != nil { 83 + <div title={ commit.Message }> 84 + <a class="underline text-blue dark:text-lavender decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid" href={ fmt.Sprintf("/%s/commit/%s", repo.Name(), commit.SHA) }>{ commit.Short() }</a> 85 + { ": " + commit.Summary() } 86 + </div> 87 + } 88 + </div> 89 + <div class="sm:col-span-1 text-subtext0"> 90 + for _, tag := range repo.Meta.Tags.Slice() { 91 + <a href={ templ.SafeURL("?tag=" + tag) } class="rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block">{ tag }</a> 92 + } 93 + </div> 94 + <div class="sm:col-span-1 text-text/80 mb-4 sm:mb-0" title={ lastCommitTime(repo, false) }>{ lastCommitTime(repo, true) }</div> 95 + } 96 + </div> 97 + </main> 98 + } 99 + }
+408
internal/html/index_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + import ( 12 + "fmt" 13 + "github.com/dustin/go-humanize" 14 + "go.jolheiser.com/ugit/assets" 15 + "go.jolheiser.com/ugit/internal/git" 16 + ) 17 + 18 + type IndexContext struct { 19 + BaseContext 20 + Profile IndexProfile 21 + Repos []*git.Repo 22 + } 23 + 24 + type IndexProfile struct { 25 + Username string 26 + Email string 27 + Links []IndexLink 28 + } 29 + 30 + type IndexLink struct { 31 + Name string 32 + URL string 33 + } 34 + 35 + func lastCommitTime(repo *git.Repo, human bool) string { 36 + c, err := repo.LastCommit() 37 + if err != nil { 38 + return "" 39 + } 40 + if human { 41 + return humanize.Time(c.When) 42 + } 43 + return c.When.Format("01/02/2006 03:04:05 PM") 44 + } 45 + 46 + func lastCommit(repo *git.Repo) *git.Commit { 47 + c, err := repo.LastCommit() 48 + if err != nil { 49 + return nil 50 + } 51 + return &c 52 + } 53 + 54 + func Index(ic IndexContext) templ.Component { 55 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 56 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 57 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 58 + return templ_7745c5c3_CtxErr 59 + } 60 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 61 + if !templ_7745c5c3_IsBuffer { 62 + defer func() { 63 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 64 + if templ_7745c5c3_Err == nil { 65 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 66 + } 67 + }() 68 + } 69 + ctx = templ.InitializeContext(ctx) 70 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 71 + if templ_7745c5c3_Var1 == nil { 72 + templ_7745c5c3_Var1 = templ.NopComponent 73 + } 74 + ctx = templ.ClearChildren(ctx) 75 + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 76 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 77 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 78 + if !templ_7745c5c3_IsBuffer { 79 + defer func() { 80 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 81 + if templ_7745c5c3_Err == nil { 82 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 83 + } 84 + }() 85 + } 86 + ctx = templ.InitializeContext(ctx) 87 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<header><h1 class=\"text-text text-xl font-bold\">") 88 + if templ_7745c5c3_Err != nil { 89 + return templ_7745c5c3_Err 90 + } 91 + var templ_7745c5c3_Var3 string 92 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Title) 93 + if templ_7745c5c3_Err != nil { 94 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 49, Col: 53} 95 + } 96 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 97 + if templ_7745c5c3_Err != nil { 98 + return templ_7745c5c3_Err 99 + } 100 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</h1><h2 class=\"text-subtext1 text-lg\">") 101 + if templ_7745c5c3_Err != nil { 102 + return templ_7745c5c3_Err 103 + } 104 + var templ_7745c5c3_Var4 string 105 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Description) 106 + if templ_7745c5c3_Err != nil { 107 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 50, Col: 53} 108 + } 109 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 110 + if templ_7745c5c3_Err != nil { 111 + return templ_7745c5c3_Err 112 + } 113 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</h2></header><main class=\"mt-5\"><div class=\"grid grid-cols-1 sm:grid-cols-8\">") 114 + if templ_7745c5c3_Err != nil { 115 + return templ_7745c5c3_Err 116 + } 117 + if ic.Profile.Username != "" { 118 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"text-mauve\">") 119 + if templ_7745c5c3_Err != nil { 120 + return templ_7745c5c3_Err 121 + } 122 + var templ_7745c5c3_Var5 string 123 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(`@` + ic.Profile.Username) 124 + if templ_7745c5c3_Err != nil { 125 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 55, Col: 56} 126 + } 127 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 128 + if templ_7745c5c3_Err != nil { 129 + return templ_7745c5c3_Err 130 + } 131 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</div>") 132 + if templ_7745c5c3_Err != nil { 133 + return templ_7745c5c3_Err 134 + } 135 + } 136 + if ic.Profile.Email != "" { 137 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div class=\"text-mauve col-span-2\"><div class=\"w-5 h-5 stroke-mauve inline-block mr-1 align-middle\">") 138 + if templ_7745c5c3_Err != nil { 139 + return templ_7745c5c3_Err 140 + } 141 + templ_7745c5c3_Err = templ.Raw(string(assets.EmailIcon)).Render(ctx, templ_7745c5c3_Buffer) 142 + if templ_7745c5c3_Err != nil { 143 + return templ_7745c5c3_Err 144 + } 145 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div><a class=\"underline decoration-mauve/50 decoration-dashed hover:decoration-solid\" href=\"") 146 + if templ_7745c5c3_Err != nil { 147 + return templ_7745c5c3_Err 148 + } 149 + var templ_7745c5c3_Var6 templ.SafeURL 150 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("mailto:" + ic.Profile.Email)) 151 + if templ_7745c5c3_Err != nil { 152 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 62, Col: 138} 153 + } 154 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 155 + if templ_7745c5c3_Err != nil { 156 + return templ_7745c5c3_Err 157 + } 158 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\">") 159 + if templ_7745c5c3_Err != nil { 160 + return templ_7745c5c3_Err 161 + } 162 + var templ_7745c5c3_Var7 string 163 + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(ic.Profile.Email) 164 + if templ_7745c5c3_Err != nil { 165 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 62, Col: 159} 166 + } 167 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 168 + if templ_7745c5c3_Err != nil { 169 + return templ_7745c5c3_Err 170 + } 171 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</a></div>") 172 + if templ_7745c5c3_Err != nil { 173 + return templ_7745c5c3_Err 174 + } 175 + } 176 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</div><div class=\"grid grid-cols-1 sm:grid-cols-8\">") 177 + if templ_7745c5c3_Err != nil { 178 + return templ_7745c5c3_Err 179 + } 180 + for _, link := range ic.Profile.Links { 181 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"text-mauve\"><div class=\"w-5 h-5 stroke-mauve inline-block mr-1 align-middle\">") 182 + if templ_7745c5c3_Err != nil { 183 + return templ_7745c5c3_Err 184 + } 185 + templ_7745c5c3_Err = templ.Raw(string(assets.LinkIcon)).Render(ctx, templ_7745c5c3_Buffer) 186 + if templ_7745c5c3_Err != nil { 187 + return templ_7745c5c3_Err 188 + } 189 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div><a class=\"underline decoration-mauve/50 decoration-dashed hover:decoration-solid\" rel=\"me\" href=\"") 190 + if templ_7745c5c3_Err != nil { 191 + return templ_7745c5c3_Err 192 + } 193 + var templ_7745c5c3_Var8 templ.SafeURL 194 + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(link.URL)) 195 + if templ_7745c5c3_Err != nil { 196 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 72, Col: 127} 197 + } 198 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 199 + if templ_7745c5c3_Err != nil { 200 + return templ_7745c5c3_Err 201 + } 202 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">") 203 + if templ_7745c5c3_Err != nil { 204 + return templ_7745c5c3_Err 205 + } 206 + var templ_7745c5c3_Var9 string 207 + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(link.Name) 208 + if templ_7745c5c3_Err != nil { 209 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 72, Col: 141} 210 + } 211 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) 212 + if templ_7745c5c3_Err != nil { 213 + return templ_7745c5c3_Err 214 + } 215 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</a></div>") 216 + if templ_7745c5c3_Err != nil { 217 + return templ_7745c5c3_Err 218 + } 219 + } 220 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</div><div class=\"grid sm:grid-cols-10 gap-2 mt-5\">") 221 + if templ_7745c5c3_Err != nil { 222 + return templ_7745c5c3_Err 223 + } 224 + for _, repo := range ic.Repos { 225 + commit := lastCommit(repo) 226 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<div class=\"sm:col-span-2 text-blue dark:text-lavender\"><a class=\"underline decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid\" href=\"") 227 + if templ_7745c5c3_Err != nil { 228 + return templ_7745c5c3_Err 229 + } 230 + var templ_7745c5c3_Var10 templ.SafeURL 231 + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(templ.URL("/" + repo.Name())) 232 + if templ_7745c5c3_Err != nil { 233 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 79, Col: 205} 234 + } 235 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) 236 + if templ_7745c5c3_Err != nil { 237 + return templ_7745c5c3_Err 238 + } 239 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "\">") 240 + if templ_7745c5c3_Err != nil { 241 + return templ_7745c5c3_Err 242 + } 243 + var templ_7745c5c3_Var11 string 244 + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(repo.Name()) 245 + if templ_7745c5c3_Err != nil { 246 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 79, Col: 221} 247 + } 248 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 249 + if templ_7745c5c3_Err != nil { 250 + return templ_7745c5c3_Err 251 + } 252 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</a></div><div class=\"sm:col-span-3 text-subtext0\">") 253 + if templ_7745c5c3_Err != nil { 254 + return templ_7745c5c3_Err 255 + } 256 + var templ_7745c5c3_Var12 string 257 + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(repo.Meta.Description) 258 + if templ_7745c5c3_Err != nil { 259 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 80, Col: 69} 260 + } 261 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) 262 + if templ_7745c5c3_Err != nil { 263 + return templ_7745c5c3_Err 264 + } 265 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</div><div class=\"sm:col-span-3 text-subtext0\">") 266 + if templ_7745c5c3_Err != nil { 267 + return templ_7745c5c3_Err 268 + } 269 + if commit != nil { 270 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "<div title=\"") 271 + if templ_7745c5c3_Err != nil { 272 + return templ_7745c5c3_Err 273 + } 274 + var templ_7745c5c3_Var13 string 275 + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Message) 276 + if templ_7745c5c3_Err != nil { 277 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 83, Col: 34} 278 + } 279 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) 280 + if templ_7745c5c3_Err != nil { 281 + return templ_7745c5c3_Err 282 + } 283 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "\"><a class=\"underline text-blue dark:text-lavender decoration-blue/50 dark:decoration-lavender/50 decoration-dashed hover:decoration-solid\" href=\"") 284 + if templ_7745c5c3_Err != nil { 285 + return templ_7745c5c3_Err 286 + } 287 + var templ_7745c5c3_Var14 templ.SafeURL 288 + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinURLErrs(fmt.Sprintf("/%s/commit/%s", repo.Name(), commit.SHA)) 289 + if templ_7745c5c3_Err != nil { 290 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 84, Col: 206} 291 + } 292 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) 293 + if templ_7745c5c3_Err != nil { 294 + return templ_7745c5c3_Err 295 + } 296 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\">") 297 + if templ_7745c5c3_Err != nil { 298 + return templ_7745c5c3_Err 299 + } 300 + var templ_7745c5c3_Var15 string 301 + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Short()) 302 + if templ_7745c5c3_Err != nil { 303 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 84, Col: 225} 304 + } 305 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) 306 + if templ_7745c5c3_Err != nil { 307 + return templ_7745c5c3_Err 308 + } 309 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "</a> ") 310 + if templ_7745c5c3_Err != nil { 311 + return templ_7745c5c3_Err 312 + } 313 + var templ_7745c5c3_Var16 string 314 + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(": " + commit.Summary()) 315 + if templ_7745c5c3_Err != nil { 316 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 85, Col: 33} 317 + } 318 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) 319 + if templ_7745c5c3_Err != nil { 320 + return templ_7745c5c3_Err 321 + } 322 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</div>") 323 + if templ_7745c5c3_Err != nil { 324 + return templ_7745c5c3_Err 325 + } 326 + } 327 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</div><div class=\"sm:col-span-1 text-subtext0\">") 328 + if templ_7745c5c3_Err != nil { 329 + return templ_7745c5c3_Err 330 + } 331 + for _, tag := range repo.Meta.Tags.Slice() { 332 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<a href=\"") 333 + if templ_7745c5c3_Err != nil { 334 + return templ_7745c5c3_Err 335 + } 336 + var templ_7745c5c3_Var17 templ.SafeURL 337 + templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("?tag=" + tag)) 338 + if templ_7745c5c3_Err != nil { 339 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 91, Col: 45} 340 + } 341 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) 342 + if templ_7745c5c3_Err != nil { 343 + return templ_7745c5c3_Err 344 + } 345 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\" class=\"rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block\">") 346 + if templ_7745c5c3_Err != nil { 347 + return templ_7745c5c3_Err 348 + } 349 + var templ_7745c5c3_Var18 string 350 + templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(tag) 351 + if templ_7745c5c3_Err != nil { 352 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 91, Col: 141} 353 + } 354 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) 355 + if templ_7745c5c3_Err != nil { 356 + return templ_7745c5c3_Err 357 + } 358 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</a>") 359 + if templ_7745c5c3_Err != nil { 360 + return templ_7745c5c3_Err 361 + } 362 + } 363 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "</div><div class=\"sm:col-span-1 text-text/80 mb-4 sm:mb-0\" title=\"") 364 + if templ_7745c5c3_Err != nil { 365 + return templ_7745c5c3_Err 366 + } 367 + var templ_7745c5c3_Var19 string 368 + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommitTime(repo, false)) 369 + if templ_7745c5c3_Err != nil { 370 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 94, Col: 93} 371 + } 372 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) 373 + if templ_7745c5c3_Err != nil { 374 + return templ_7745c5c3_Err 375 + } 376 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "\">") 377 + if templ_7745c5c3_Err != nil { 378 + return templ_7745c5c3_Err 379 + } 380 + var templ_7745c5c3_Var20 string 381 + templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(lastCommitTime(repo, true)) 382 + if templ_7745c5c3_Err != nil { 383 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `index.templ`, Line: 94, Col: 124} 384 + } 385 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) 386 + if templ_7745c5c3_Err != nil { 387 + return templ_7745c5c3_Err 388 + } 389 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "</div>") 390 + if templ_7745c5c3_Err != nil { 391 + return templ_7745c5c3_Err 392 + } 393 + } 394 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</div></main>") 395 + if templ_7745c5c3_Err != nil { 396 + return templ_7745c5c3_Err 397 + } 398 + return nil 399 + }) 400 + templ_7745c5c3_Err = base(ic.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 401 + if templ_7745c5c3_Err != nil { 402 + return templ_7745c5c3_Err 403 + } 404 + return nil 405 + }) 406 + } 407 + 408 + var _ = templruntime.GeneratedTemplate
-17
internal/html/readme.go
··· 1 - package html 2 - 3 - import ( 4 - . "maragu.dev/gomponents" 5 - . "maragu.dev/gomponents/html" 6 - ) 7 - 8 - type ReadmeComponentContext struct { 9 - Markdown string 10 - } 11 - 12 - func readmeComponent(rcc ReadmeComponentContext) Node { 13 - if rcc.Markdown == "" { 14 - return nil 15 - } 16 - return Div(Class("bg-base dark:bg-base/50 p-5 mt-5 rounded markdown"), Raw(rcc.Markdown)) 17 - }
+13
internal/html/readme.templ
··· 1 + package html 2 + 3 + type ReadmeComponentContext struct { 4 + Markdown string 5 + } 6 + 7 + templ readmeComponent(rcc ReadmeComponentContext) { 8 + if rcc.Markdown != "" { 9 + <div class="bg-base dark:bg-base/50 p-5 mt-5 rounded markdown"> 10 + @templ.Raw(rcc.Markdown) 11 + </div> 12 + } 13 + }
+54
internal/html/readme_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + type ReadmeComponentContext struct { 12 + Markdown string 13 + } 14 + 15 + func readmeComponent(rcc ReadmeComponentContext) templ.Component { 16 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 17 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 18 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 19 + return templ_7745c5c3_CtxErr 20 + } 21 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 22 + if !templ_7745c5c3_IsBuffer { 23 + defer func() { 24 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 25 + if templ_7745c5c3_Err == nil { 26 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 27 + } 28 + }() 29 + } 30 + ctx = templ.InitializeContext(ctx) 31 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 32 + if templ_7745c5c3_Var1 == nil { 33 + templ_7745c5c3_Var1 = templ.NopComponent 34 + } 35 + ctx = templ.ClearChildren(ctx) 36 + if rcc.Markdown != "" { 37 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"bg-base dark:bg-base/50 p-5 mt-5 rounded markdown\">") 38 + if templ_7745c5c3_Err != nil { 39 + return templ_7745c5c3_Err 40 + } 41 + templ_7745c5c3_Err = templ.Raw(rcc.Markdown).Render(ctx, templ_7745c5c3_Buffer) 42 + if templ_7745c5c3_Err != nil { 43 + return templ_7745c5c3_Err 44 + } 45 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</div>") 46 + if templ_7745c5c3_Err != nil { 47 + return templ_7745c5c3_Err 48 + } 49 + } 50 + return nil 51 + }) 52 + } 53 + 54 + var _ = templruntime.GeneratedTemplate
-44
internal/html/repo.go
··· 1 - package html 2 - 3 - import ( 4 - "fmt" 5 - 6 - . "maragu.dev/gomponents" 7 - . "maragu.dev/gomponents/html" 8 - ) 9 - 10 - type RepoHeaderComponentContext struct { 11 - Name string 12 - Ref string 13 - Description string 14 - CloneURL string 15 - Tags []string 16 - } 17 - 18 - func repoHeaderComponent(rhcc RepoHeaderComponentContext) Node { 19 - return Group([]Node{ 20 - Div(Class("mb-1 text-text"), 21 - A(Class("text-lg underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href("/"+rhcc.Name), Text(rhcc.Name)), 22 - If(rhcc.Ref != "", Group([]Node{ 23 - Text(" "), 24 - A(Class("text-text/80 text-sm underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/", rhcc.Name, rhcc.Ref)), Text("@"+rhcc.Ref)), 25 - })), 26 - Text(" - "), 27 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/refs", rhcc.Name)), Text("refs")), 28 - Text(" - "), 29 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/log/%s", rhcc.Name, rhcc.Ref)), Text("log")), 30 - Text(" - "), 31 - Form(Class("inline-block"), Action(fmt.Sprintf("/%s/search", rhcc.Name)), Method("get"), 32 - Input(Class("rounded p-1 bg-mantle focus:border-lavender focus:outline-none focus:ring-0"), ID("search"), Type("text"), Name("q"), Placeholder("search")), 33 - ), 34 - Text(" - "), 35 - Pre(Class("text-text inline select-all bg-base dark:bg-base/50 p-1 rounded"), Textf("%s/%s.git", rhcc.CloneURL, rhcc.Name)), 36 - ), 37 - Div(Class("text-subtext0 mb-1"), 38 - Map(rhcc.Tags, func(tag string) Node { 39 - return Span(Class("rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block"), Text(tag)) 40 - }), 41 - ), 42 - Div(Class("text-text/80 mb-1"), Text(rhcc.Description)), 43 - }) 44 - }
+35
internal/html/repo.templ
··· 1 + package html 2 + 3 + import "fmt" 4 + 5 + type RepoHeaderComponentContext struct { 6 + Name string 7 + Ref string 8 + Description string 9 + CloneURL string 10 + Tags []string 11 + } 12 + 13 + templ repoHeaderComponent(rhcc RepoHeaderComponentContext) { 14 + <div class="mb-1 text-text"> 15 + <a class="text-lg underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL("/" + rhcc.Name) }>{ rhcc.Name }</a> 16 + if rhcc.Ref != "" { 17 + { " " } 18 + <a class="text-text/80 text-sm underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rhcc.Name, rhcc.Ref)) }>{ "@" + rhcc.Ref }</a> 19 + } 20 + { " - " } 21 + <a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/refs", rhcc.Name)) }>refs</a> 22 + { " - " } 23 + <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> 24 + { " - " } 25 + <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> 26 + { " - " } 27 + <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> 28 + </div> 29 + <div class="text-subtext0 mb-1"> 30 + for _, tag := range rhcc.Tags { 31 + <span class="rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block">{ tag }</span> 32 + } 33 + </div> 34 + <div class="text-text/80 mb-1">{ rhcc.Description }</div> 35 + }
-57
internal/html/repo_breadcrumb.go
··· 1 - package html 2 - 3 - import ( 4 - "fmt" 5 - "path" 6 - "strings" 7 - 8 - . "maragu.dev/gomponents" 9 - . "maragu.dev/gomponents/html" 10 - ) 11 - 12 - type RepoBreadcrumbComponentContext struct { 13 - Repo string 14 - Ref string 15 - Path string 16 - } 17 - 18 - type breadcrumb struct { 19 - label string 20 - href string 21 - end bool 22 - } 23 - 24 - func (r RepoBreadcrumbComponentContext) crumbs() []breadcrumb { 25 - parts := strings.Split(r.Path, "/") 26 - breadcrumbs := []breadcrumb{ 27 - { 28 - label: r.Repo, 29 - href: fmt.Sprintf("/%s/tree/%s/", r.Repo, r.Ref), 30 - }, 31 - } 32 - for idx, part := range parts { 33 - breadcrumbs = append(breadcrumbs, breadcrumb{ 34 - label: part, 35 - href: path.Join(breadcrumbs[idx].href, part), 36 - }) 37 - } 38 - breadcrumbs[len(breadcrumbs)-1].end = true 39 - return breadcrumbs 40 - } 41 - 42 - func repoBreadcrumbComponent(rbcc RepoBreadcrumbComponentContext) Node { 43 - if rbcc.Path == "" { 44 - return nil 45 - } 46 - return Div(Class("inline-block text-text"), 47 - Map(rbcc.crumbs(), func(crumb breadcrumb) Node { 48 - if crumb.end { 49 - return Span(Text(crumb.label)) 50 - } 51 - return Group([]Node{ 52 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(crumb.href), Text(crumb.label)), 53 - Text(" / "), 54 - }) 55 - }), 56 - ) 57 - }
+52
internal/html/repo_breadcrumb.templ
··· 1 + package html 2 + 3 + import ( 4 + "fmt" 5 + "path" 6 + "strings" 7 + ) 8 + 9 + type RepoBreadcrumbComponentContext struct { 10 + Repo string 11 + Ref string 12 + Path string 13 + } 14 + 15 + type breadcrumb struct { 16 + label string 17 + href string 18 + end bool 19 + } 20 + 21 + func (r RepoBreadcrumbComponentContext) crumbs() []breadcrumb { 22 + parts := strings.Split(r.Path, "/") 23 + breadcrumbs := []breadcrumb{ 24 + { 25 + label: r.Repo, 26 + href: fmt.Sprintf("/%s/tree/%s/", r.Repo, r.Ref), 27 + }, 28 + } 29 + for idx, part := range parts { 30 + breadcrumbs = append(breadcrumbs, breadcrumb{ 31 + label: part, 32 + href: path.Join(breadcrumbs[idx].href, part), 33 + }) 34 + } 35 + breadcrumbs[len(breadcrumbs)-1].end = true 36 + return breadcrumbs 37 + } 38 + 39 + templ repoBreadcrumbComponent(rbcc RepoBreadcrumbComponentContext) { 40 + if rbcc.Path != "" { 41 + <div class="inline-block text-text"> 42 + for _, crumb := range rbcc.crumbs() { 43 + if crumb.end { 44 + <span>{ crumb.label }</span> 45 + } else { 46 + <a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(crumb.href) }>{ crumb.label }</a> 47 + { " / " } 48 + } 49 + } 50 + </div> 51 + } 52 + }
+143
internal/html/repo_breadcrumb_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + import ( 12 + "fmt" 13 + "path" 14 + "strings" 15 + ) 16 + 17 + type RepoBreadcrumbComponentContext struct { 18 + Repo string 19 + Ref string 20 + Path string 21 + } 22 + 23 + type breadcrumb struct { 24 + label string 25 + href string 26 + end bool 27 + } 28 + 29 + func (r RepoBreadcrumbComponentContext) crumbs() []breadcrumb { 30 + parts := strings.Split(r.Path, "/") 31 + breadcrumbs := []breadcrumb{ 32 + { 33 + label: r.Repo, 34 + href: fmt.Sprintf("/%s/tree/%s/", r.Repo, r.Ref), 35 + }, 36 + } 37 + for idx, part := range parts { 38 + breadcrumbs = append(breadcrumbs, breadcrumb{ 39 + label: part, 40 + href: path.Join(breadcrumbs[idx].href, part), 41 + }) 42 + } 43 + breadcrumbs[len(breadcrumbs)-1].end = true 44 + return breadcrumbs 45 + } 46 + 47 + func repoBreadcrumbComponent(rbcc RepoBreadcrumbComponentContext) templ.Component { 48 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 49 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 50 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 51 + return templ_7745c5c3_CtxErr 52 + } 53 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 54 + if !templ_7745c5c3_IsBuffer { 55 + defer func() { 56 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 57 + if templ_7745c5c3_Err == nil { 58 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 59 + } 60 + }() 61 + } 62 + ctx = templ.InitializeContext(ctx) 63 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 64 + if templ_7745c5c3_Var1 == nil { 65 + templ_7745c5c3_Var1 = templ.NopComponent 66 + } 67 + ctx = templ.ClearChildren(ctx) 68 + if rbcc.Path != "" { 69 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"inline-block text-text\">") 70 + if templ_7745c5c3_Err != nil { 71 + return templ_7745c5c3_Err 72 + } 73 + for _, crumb := range rbcc.crumbs() { 74 + if crumb.end { 75 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<span>") 76 + if templ_7745c5c3_Err != nil { 77 + return templ_7745c5c3_Err 78 + } 79 + var templ_7745c5c3_Var2 string 80 + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(crumb.label) 81 + if templ_7745c5c3_Err != nil { 82 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_breadcrumb.templ`, Line: 44, Col: 24} 83 + } 84 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) 85 + if templ_7745c5c3_Err != nil { 86 + return templ_7745c5c3_Err 87 + } 88 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</span>") 89 + if templ_7745c5c3_Err != nil { 90 + return templ_7745c5c3_Err 91 + } 92 + } else { 93 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 94 + if templ_7745c5c3_Err != nil { 95 + return templ_7745c5c3_Err 96 + } 97 + var templ_7745c5c3_Var3 templ.SafeURL 98 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(crumb.href)) 99 + if templ_7745c5c3_Err != nil { 100 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_breadcrumb.templ`, Line: 46, Col: 118} 101 + } 102 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 103 + if templ_7745c5c3_Err != nil { 104 + return templ_7745c5c3_Err 105 + } 106 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">") 107 + if templ_7745c5c3_Err != nil { 108 + return templ_7745c5c3_Err 109 + } 110 + var templ_7745c5c3_Var4 string 111 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(crumb.label) 112 + if templ_7745c5c3_Err != nil { 113 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_breadcrumb.templ`, Line: 46, Col: 134} 114 + } 115 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 116 + if templ_7745c5c3_Err != nil { 117 + return templ_7745c5c3_Err 118 + } 119 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a> ") 120 + if templ_7745c5c3_Err != nil { 121 + return templ_7745c5c3_Err 122 + } 123 + var templ_7745c5c3_Var5 string 124 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(" / ") 125 + if templ_7745c5c3_Err != nil { 126 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_breadcrumb.templ`, Line: 47, Col: 12} 127 + } 128 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 129 + if templ_7745c5c3_Err != nil { 130 + return templ_7745c5c3_Err 131 + } 132 + } 133 + } 134 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>") 135 + if templ_7745c5c3_Err != nil { 136 + return templ_7745c5c3_Err 137 + } 138 + } 139 + return nil 140 + }) 141 + } 142 + 143 + var _ = templruntime.GeneratedTemplate
-72
internal/html/repo_commit.go
··· 1 - package html 2 - 3 - import ( 4 - "fmt" 5 - 6 - "github.com/dustin/go-humanize" 7 - "go.jolheiser.com/ugit/internal/git" 8 - . "maragu.dev/gomponents" 9 - . "maragu.dev/gomponents/html" 10 - ) 11 - 12 - type RepoCommitContext struct { 13 - BaseContext 14 - RepoHeaderComponentContext 15 - Commit git.Commit 16 - } 17 - 18 - func RepoCommitTemplate(rcc RepoCommitContext) Node { 19 - return base(rcc.BaseContext, []Node{ 20 - repoHeaderComponent(rcc.RepoHeaderComponentContext), 21 - Div(Class("text-text mt-5"), 22 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)), Text("tree")), 23 - Text(" "), 24 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/log/%s", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)), Text("log")), 25 - Text(" "), 26 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/commit/%s.patch", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)), Text("patch")), 27 - ), 28 - Div(Class("text-text whitespace-pre mt-5 p-3 bg-base rounded"), Text(rcc.Commit.Message)), 29 - If(rcc.Commit.Signature != "", 30 - Details(Class("text-text whitespace-pre"), 31 - Summary(Class("cursor-pointer"), Text("Signature")), 32 - Div(Class("p-3 bg-base rounded"), 33 - Code(Text(rcc.Commit.Signature)), 34 - ), 35 - ), 36 - ), 37 - Div(Class("text-text mt-3"), 38 - Div( 39 - Text(rcc.Commit.Author), 40 - Text(" "), 41 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("mailto:%s", rcc.Commit.Email)), Text(fmt.Sprintf("<%s>", rcc.Commit.Email))), 42 - ), 43 - Div(Title(rcc.Commit.When.Format("01/02/2006 03:04:05 PM")), Text(humanize.Time(rcc.Commit.When))), 44 - ), 45 - Details(Class("text-text mt-5"), 46 - Summary(Class("cursor-pointer"), Textf("%d changed files, %d additions(+), %d deletions(-)", rcc.Commit.Stats.Changed, rcc.Commit.Stats.Additions, rcc.Commit.Stats.Deletions)), 47 - Div(Class("p-3 bg-base rounded"), 48 - Map(rcc.Commit.Files, func(file git.CommitFile) Node { 49 - return A(Class("block underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href("#"+file.Path()), Text(file.Path())) 50 - }), 51 - ), 52 - ), 53 - Map(rcc.Commit.Files, func(file git.CommitFile) Node { 54 - return Group([]Node{ 55 - Div(Class("text-text mt-5"), ID(file.Path()), 56 - Span(Class("text-text/80"), Title(file.Action), Text(string(file.Action[0]))), 57 - Text(" "), 58 - If(file.From.Path != "", 59 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.From.Commit, file.From.Path)), Text(file.From.Path)), 60 - ), 61 - If(file.From.Path != "" && file.To.Path != "", Text(" โ†’ ")), 62 - If(file.To.Path != "", 63 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.To.Commit, file.To.Path)), Text(file.To.Path)), 64 - ), 65 - ), 66 - Div(Class("code"), 67 - Raw(file.Patch), 68 - ), 69 - }) 70 - }), 71 - }...) 72 - }
+55
internal/html/repo_commit.templ
··· 1 + package html 2 + 3 + import "fmt" 4 + import "github.com/dustin/go-humanize" 5 + import "go.jolheiser.com/ugit/internal/git" 6 + 7 + type RepoCommitContext struct { 8 + BaseContext 9 + RepoHeaderComponentContext 10 + Commit git.Commit 11 + } 12 + 13 + templ RepoCommit(rcc RepoCommitContext) { 14 + @base(rcc.BaseContext) { 15 + @repoHeaderComponent(rcc.RepoHeaderComponentContext) 16 + <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/", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)) }>tree</a>{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/log/%s", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)) }>log</a>{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/commit/%s.patch", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA)) }>patch</a></div> 17 + <div class="text-text whitespace-pre mt-5 p-3 bg-base rounded">{ rcc.Commit.Message }</div> 18 + if rcc.Commit.Signature != "" { 19 + <details class="text-text whitespace-pre"> 20 + <summary class="cursor-pointer">Signature</summary> 21 + <div class="p-3 bg-base rounded"><code>{ rcc.Commit.Signature }</code></div> 22 + </details> 23 + } 24 + <div class="text-text mt-3"> 25 + <div>{ rcc.Commit.Author }{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("mailto:%s", rcc.Commit.Email)) }>{ fmt.Sprintf("<%s>", rcc.Commit.Email) }</a></div> 26 + <div title={ rcc.Commit.When.Format("01/02/2006 03:04:05 PM") }>{ humanize.Time(rcc.Commit.When) }</div> 27 + </div> 28 + <details class="text-text mt-5"> 29 + <summary class="cursor-pointer">{ fmt.Sprintf("%d changed files, %d additions(+), %d deletions(-)", rcc.Commit.Stats.Changed, rcc.Commit.Stats.Additions, rcc.Commit.Stats.Deletions) }</summary> 30 + <div class="p-3 bg-base rounded"> 31 + for _, file := range rcc.Commit.Files { 32 + <a class="block underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ "#" + file.Path() }>{ file.Path() }</a> 33 + } 34 + </div> 35 + </details> 36 + for _, file := range rcc.Commit.Files { 37 + <div class="text-text mt-5" id={ file.Path() }> 38 + <span class="text-text/80" title={ file.Action }>{ string(file.Action[0]) }</span> 39 + { " " } 40 + if file.From.Path != "" { 41 + <a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.From.Commit, file.From.Path)) }>{ file.From.Path }</a> 42 + } 43 + if file.From.Path != "" && file.To.Path != "" { 44 + { " -> " } 45 + } 46 + if file.To.Path != "" { 47 + <a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.To.Commit, file.To.Path)) }>{ file.To.Path }</a> 48 + } 49 + </div> 50 + <div class="code"> 51 + @templ.Raw(file.Patch) 52 + </div> 53 + } 54 + } 55 + }
+445
internal/html/repo_commit_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + import "fmt" 12 + import "github.com/dustin/go-humanize" 13 + import "go.jolheiser.com/ugit/internal/git" 14 + 15 + type RepoCommitContext struct { 16 + BaseContext 17 + RepoHeaderComponentContext 18 + Commit git.Commit 19 + } 20 + 21 + func RepoCommit(rcc RepoCommitContext) templ.Component { 22 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 23 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 24 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 25 + return templ_7745c5c3_CtxErr 26 + } 27 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 28 + if !templ_7745c5c3_IsBuffer { 29 + defer func() { 30 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 31 + if templ_7745c5c3_Err == nil { 32 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 33 + } 34 + }() 35 + } 36 + ctx = templ.InitializeContext(ctx) 37 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 38 + if templ_7745c5c3_Var1 == nil { 39 + templ_7745c5c3_Var1 = templ.NopComponent 40 + } 41 + ctx = templ.ClearChildren(ctx) 42 + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 43 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 44 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 45 + if !templ_7745c5c3_IsBuffer { 46 + defer func() { 47 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 48 + if templ_7745c5c3_Err == nil { 49 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 50 + } 51 + }() 52 + } 53 + ctx = templ.InitializeContext(ctx) 54 + templ_7745c5c3_Err = repoHeaderComponent(rcc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 55 + if templ_7745c5c3_Err != nil { 56 + return templ_7745c5c3_Err 57 + } 58 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " <div class=\"text-text mt-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 59 + if templ_7745c5c3_Err != nil { 60 + return templ_7745c5c3_Err 61 + } 62 + var templ_7745c5c3_Var3 templ.SafeURL 63 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA))) 64 + if templ_7745c5c3_Err != nil { 65 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 213} 66 + } 67 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 68 + if templ_7745c5c3_Err != nil { 69 + return templ_7745c5c3_Err 70 + } 71 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\">tree</a>") 72 + if templ_7745c5c3_Err != nil { 73 + return templ_7745c5c3_Err 74 + } 75 + var templ_7745c5c3_Var4 string 76 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 77 + if templ_7745c5c3_Err != nil { 78 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 229} 79 + } 80 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 81 + if templ_7745c5c3_Err != nil { 82 + return templ_7745c5c3_Err 83 + } 84 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 85 + if templ_7745c5c3_Err != nil { 86 + return templ_7745c5c3_Err 87 + } 88 + var templ_7745c5c3_Var5 templ.SafeURL 89 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/log/%s", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA))) 90 + if templ_7745c5c3_Err != nil { 91 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 412} 92 + } 93 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 94 + if templ_7745c5c3_Err != nil { 95 + return templ_7745c5c3_Err 96 + } 97 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\">log</a>") 98 + if templ_7745c5c3_Err != nil { 99 + return templ_7745c5c3_Err 100 + } 101 + var templ_7745c5c3_Var6 string 102 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 103 + if templ_7745c5c3_Err != nil { 104 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 427} 105 + } 106 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 107 + if templ_7745c5c3_Err != nil { 108 + return templ_7745c5c3_Err 109 + } 110 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 111 + if templ_7745c5c3_Err != nil { 112 + return templ_7745c5c3_Err 113 + } 114 + var templ_7745c5c3_Var7 templ.SafeURL 115 + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/commit/%s.patch", rcc.RepoHeaderComponentContext.Name, rcc.Commit.SHA))) 116 + if templ_7745c5c3_Err != nil { 117 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 16, Col: 619} 118 + } 119 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 120 + if templ_7745c5c3_Err != nil { 121 + return templ_7745c5c3_Err 122 + } 123 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\">patch</a></div><div class=\"text-text whitespace-pre mt-5 p-3 bg-base rounded\">") 124 + if templ_7745c5c3_Err != nil { 125 + return templ_7745c5c3_Err 126 + } 127 + var templ_7745c5c3_Var8 string 128 + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Message) 129 + if templ_7745c5c3_Err != nil { 130 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 17, Col: 85} 131 + } 132 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 133 + if templ_7745c5c3_Err != nil { 134 + return templ_7745c5c3_Err 135 + } 136 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>") 137 + if templ_7745c5c3_Err != nil { 138 + return templ_7745c5c3_Err 139 + } 140 + if rcc.Commit.Signature != "" { 141 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<details class=\"text-text whitespace-pre\"><summary class=\"cursor-pointer\">Signature</summary><div class=\"p-3 bg-base rounded\"><code>") 142 + if templ_7745c5c3_Err != nil { 143 + return templ_7745c5c3_Err 144 + } 145 + var templ_7745c5c3_Var9 string 146 + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Signature) 147 + if templ_7745c5c3_Err != nil { 148 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 21, Col: 65} 149 + } 150 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) 151 + if templ_7745c5c3_Err != nil { 152 + return templ_7745c5c3_Err 153 + } 154 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</code></div></details>") 155 + if templ_7745c5c3_Err != nil { 156 + return templ_7745c5c3_Err 157 + } 158 + } 159 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, " <div class=\"text-text mt-3\"><div>") 160 + if templ_7745c5c3_Err != nil { 161 + return templ_7745c5c3_Err 162 + } 163 + var templ_7745c5c3_Var10 string 164 + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.Author) 165 + if templ_7745c5c3_Err != nil { 166 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 27} 167 + } 168 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) 169 + if templ_7745c5c3_Err != nil { 170 + return templ_7745c5c3_Err 171 + } 172 + var templ_7745c5c3_Var11 string 173 + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 174 + if templ_7745c5c3_Err != nil { 175 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 34} 176 + } 177 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 178 + if templ_7745c5c3_Err != nil { 179 + return templ_7745c5c3_Err 180 + } 181 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 182 + if templ_7745c5c3_Err != nil { 183 + return templ_7745c5c3_Err 184 + } 185 + var templ_7745c5c3_Var12 templ.SafeURL 186 + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("mailto:%s", rcc.Commit.Email))) 187 + if templ_7745c5c3_Err != nil { 188 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 181} 189 + } 190 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) 191 + if templ_7745c5c3_Err != nil { 192 + return templ_7745c5c3_Err 193 + } 194 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\">") 195 + if templ_7745c5c3_Err != nil { 196 + return templ_7745c5c3_Err 197 + } 198 + var templ_7745c5c3_Var13 string 199 + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("<%s>", rcc.Commit.Email)) 200 + if templ_7745c5c3_Err != nil { 201 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 25, Col: 223} 202 + } 203 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) 204 + if templ_7745c5c3_Err != nil { 205 + return templ_7745c5c3_Err 206 + } 207 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</a></div><div title=\"") 208 + if templ_7745c5c3_Err != nil { 209 + return templ_7745c5c3_Err 210 + } 211 + var templ_7745c5c3_Var14 string 212 + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(rcc.Commit.When.Format("01/02/2006 03:04:05 PM")) 213 + if templ_7745c5c3_Err != nil { 214 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 26, Col: 64} 215 + } 216 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) 217 + if templ_7745c5c3_Err != nil { 218 + return templ_7745c5c3_Err 219 + } 220 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "\">") 221 + if templ_7745c5c3_Err != nil { 222 + return templ_7745c5c3_Err 223 + } 224 + var templ_7745c5c3_Var15 string 225 + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(humanize.Time(rcc.Commit.When)) 226 + if templ_7745c5c3_Err != nil { 227 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 26, Col: 99} 228 + } 229 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) 230 + if templ_7745c5c3_Err != nil { 231 + return templ_7745c5c3_Err 232 + } 233 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</div></div><details class=\"text-text mt-5\"><summary class=\"cursor-pointer\">") 234 + if templ_7745c5c3_Err != nil { 235 + return templ_7745c5c3_Err 236 + } 237 + var templ_7745c5c3_Var16 string 238 + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d changed files, %d additions(+), %d deletions(-)", rcc.Commit.Stats.Changed, rcc.Commit.Stats.Additions, rcc.Commit.Stats.Deletions)) 239 + if templ_7745c5c3_Err != nil { 240 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 29, Col: 184} 241 + } 242 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) 243 + if templ_7745c5c3_Err != nil { 244 + return templ_7745c5c3_Err 245 + } 246 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</summary><div class=\"p-3 bg-base rounded\">") 247 + if templ_7745c5c3_Err != nil { 248 + return templ_7745c5c3_Err 249 + } 250 + for _, file := range rcc.Commit.Files { 251 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "<a class=\"block underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 252 + if templ_7745c5c3_Err != nil { 253 + return templ_7745c5c3_Err 254 + } 255 + var templ_7745c5c3_Var17 templ.SafeURL 256 + templ_7745c5c3_Var17, templ_7745c5c3_Err = templ.JoinURLErrs("#" + file.Path()) 257 + if templ_7745c5c3_Err != nil { 258 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 32, Col: 116} 259 + } 260 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var17)) 261 + if templ_7745c5c3_Err != nil { 262 + return templ_7745c5c3_Err 263 + } 264 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "\">") 265 + if templ_7745c5c3_Err != nil { 266 + return templ_7745c5c3_Err 267 + } 268 + var templ_7745c5c3_Var18 string 269 + templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(file.Path()) 270 + if templ_7745c5c3_Err != nil { 271 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 32, Col: 132} 272 + } 273 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18)) 274 + if templ_7745c5c3_Err != nil { 275 + return templ_7745c5c3_Err 276 + } 277 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "</a>") 278 + if templ_7745c5c3_Err != nil { 279 + return templ_7745c5c3_Err 280 + } 281 + } 282 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</div></details> ") 283 + if templ_7745c5c3_Err != nil { 284 + return templ_7745c5c3_Err 285 + } 286 + for _, file := range rcc.Commit.Files { 287 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<div class=\"text-text mt-5\" id=\"") 288 + if templ_7745c5c3_Err != nil { 289 + return templ_7745c5c3_Err 290 + } 291 + var templ_7745c5c3_Var19 string 292 + templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(file.Path()) 293 + if templ_7745c5c3_Err != nil { 294 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 37, Col: 47} 295 + } 296 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19)) 297 + if templ_7745c5c3_Err != nil { 298 + return templ_7745c5c3_Err 299 + } 300 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "\"><span class=\"text-text/80\" title=\"") 301 + if templ_7745c5c3_Err != nil { 302 + return templ_7745c5c3_Err 303 + } 304 + var templ_7745c5c3_Var20 string 305 + templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(file.Action) 306 + if templ_7745c5c3_Err != nil { 307 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 38, Col: 50} 308 + } 309 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20)) 310 + if templ_7745c5c3_Err != nil { 311 + return templ_7745c5c3_Err 312 + } 313 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\">") 314 + if templ_7745c5c3_Err != nil { 315 + return templ_7745c5c3_Err 316 + } 317 + var templ_7745c5c3_Var21 string 318 + templ_7745c5c3_Var21, templ_7745c5c3_Err = templ.JoinStringErrs(string(file.Action[0])) 319 + if templ_7745c5c3_Err != nil { 320 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 38, Col: 77} 321 + } 322 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var21)) 323 + if templ_7745c5c3_Err != nil { 324 + return templ_7745c5c3_Err 325 + } 326 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "</span> ") 327 + if templ_7745c5c3_Err != nil { 328 + return templ_7745c5c3_Err 329 + } 330 + var templ_7745c5c3_Var22 string 331 + templ_7745c5c3_Var22, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 332 + if templ_7745c5c3_Err != nil { 333 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 39, Col: 9} 334 + } 335 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var22)) 336 + if templ_7745c5c3_Err != nil { 337 + return templ_7745c5c3_Err 338 + } 339 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, " ") 340 + if templ_7745c5c3_Err != nil { 341 + return templ_7745c5c3_Err 342 + } 343 + if file.From.Path != "" { 344 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 345 + if templ_7745c5c3_Err != nil { 346 + return templ_7745c5c3_Err 347 + } 348 + var templ_7745c5c3_Var23 templ.SafeURL 349 + templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.From.Commit, file.From.Path))) 350 + if templ_7745c5c3_Err != nil { 351 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 41, Col: 208} 352 + } 353 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23)) 354 + if templ_7745c5c3_Err != nil { 355 + return templ_7745c5c3_Err 356 + } 357 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "\">") 358 + if templ_7745c5c3_Err != nil { 359 + return templ_7745c5c3_Err 360 + } 361 + var templ_7745c5c3_Var24 string 362 + templ_7745c5c3_Var24, templ_7745c5c3_Err = templ.JoinStringErrs(file.From.Path) 363 + if templ_7745c5c3_Err != nil { 364 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 41, Col: 227} 365 + } 366 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var24)) 367 + if templ_7745c5c3_Err != nil { 368 + return templ_7745c5c3_Err 369 + } 370 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "</a> ") 371 + if templ_7745c5c3_Err != nil { 372 + return templ_7745c5c3_Err 373 + } 374 + } 375 + if file.From.Path != "" && file.To.Path != "" { 376 + var templ_7745c5c3_Var25 string 377 + templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(" -> ") 378 + if templ_7745c5c3_Err != nil { 379 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 44, Col: 13} 380 + } 381 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25)) 382 + if templ_7745c5c3_Err != nil { 383 + return templ_7745c5c3_Err 384 + } 385 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, " ") 386 + if templ_7745c5c3_Err != nil { 387 + return templ_7745c5c3_Err 388 + } 389 + } 390 + if file.To.Path != "" { 391 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 392 + if templ_7745c5c3_Err != nil { 393 + return templ_7745c5c3_Err 394 + } 395 + var templ_7745c5c3_Var26 templ.SafeURL 396 + templ_7745c5c3_Var26, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rcc.RepoHeaderComponentContext.Name, file.To.Commit, file.To.Path))) 397 + if templ_7745c5c3_Err != nil { 398 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 47, Col: 204} 399 + } 400 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var26)) 401 + if templ_7745c5c3_Err != nil { 402 + return templ_7745c5c3_Err 403 + } 404 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "\">") 405 + if templ_7745c5c3_Err != nil { 406 + return templ_7745c5c3_Err 407 + } 408 + var templ_7745c5c3_Var27 string 409 + templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(file.To.Path) 410 + if templ_7745c5c3_Err != nil { 411 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_commit.templ`, Line: 47, Col: 221} 412 + } 413 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27)) 414 + if templ_7745c5c3_Err != nil { 415 + return templ_7745c5c3_Err 416 + } 417 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "</a>") 418 + if templ_7745c5c3_Err != nil { 419 + return templ_7745c5c3_Err 420 + } 421 + } 422 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</div><div class=\"code\">") 423 + if templ_7745c5c3_Err != nil { 424 + return templ_7745c5c3_Err 425 + } 426 + templ_7745c5c3_Err = templ.Raw(file.Patch).Render(ctx, templ_7745c5c3_Buffer) 427 + if templ_7745c5c3_Err != nil { 428 + return templ_7745c5c3_Err 429 + } 430 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "</div>") 431 + if templ_7745c5c3_Err != nil { 432 + return templ_7745c5c3_Err 433 + } 434 + } 435 + return nil 436 + }) 437 + templ_7745c5c3_Err = base(rcc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 438 + if templ_7745c5c3_Err != nil { 439 + return templ_7745c5c3_Err 440 + } 441 + return nil 442 + }) 443 + } 444 + 445 + var _ = templruntime.GeneratedTemplate
-40
internal/html/repo_file.go
··· 1 - package html 2 - 3 - import ( 4 - _ "embed" 5 - "fmt" 6 - 7 - . "maragu.dev/gomponents" 8 - . "maragu.dev/gomponents/html" 9 - ) 10 - 11 - type RepoFileContext struct { 12 - BaseContext 13 - RepoHeaderComponentContext 14 - RepoBreadcrumbComponentContext 15 - Code string 16 - Commit string 17 - Path string 18 - } 19 - 20 - //go:embed repo_file.js 21 - var repoFileJS string 22 - 23 - func RepoFileTemplate(rfc RepoFileContext) Node { 24 - permalink := fmt.Sprintf("/%s/tree/%s/%s", rfc.RepoBreadcrumbComponentContext.Repo, rfc.Commit, rfc.Path) 25 - return base(rfc.BaseContext, []Node{ 26 - repoHeaderComponent(rfc.RepoHeaderComponentContext), 27 - Div(Class("mt-2 text-text"), 28 - repoBreadcrumbComponent(rfc.RepoBreadcrumbComponentContext), 29 - Text(" - "), 30 - A(Class("text-text underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href("?raw"), Text("raw")), 31 - Text(" - "), 32 - A(Class("text-text underline decoration-text/50 decoration-dashed hover:decoration-solid"), ID("permalink"), Data("permalink", permalink), Href(permalink), Text("permalink")), 33 - Div(Class("code relative"), 34 - Raw(rfc.Code), 35 - Button(ID("copy"), Class("absolute top-0 right-0 rounded bg-base hover:bg-surface0")), 36 - ), 37 - ), 38 - Script(Raw(repoFileJS)), 39 - }...) 40 - }
-70
internal/html/repo_file.js
··· 1 - const lineRe = /#L(\d+)(?:-L(\d+))?/g 2 - const $lineLines = document.querySelectorAll(".chroma .lntable .lnt"); 3 - const $codeLines = document.querySelectorAll(".chroma .lntable .line"); 4 - const $copyButton = document.getElementById('copy'); 5 - const $permalink = document.getElementById('permalink'); 6 - const $copyIcon = "๐Ÿ“‹"; 7 - const $copiedIcon = "โœ…"; 8 - let $code = "" 9 - for (let codeLine of $codeLines) $code += codeLine.innerText; 10 - let start = 0; 11 - let end = 0; 12 - const results = [...location.hash.matchAll(lineRe)]; 13 - if (0 in results) { 14 - start = results[0][1] !== undefined ? parseInt(results[0][1]) : 0; 15 - end = results[0][2] !== undefined ? parseInt(results[0][2]) : 0; 16 - } 17 - if (start !== 0) { 18 - deactivateLines(); 19 - activateLines(start, end); 20 - let anchor = `#${start}`; 21 - if (end !== 0) anchor += `-${end}`; 22 - if (anchor !== "") $permalink.href = $permalink.dataset.permalink + anchor; 23 - $lineLines[start - 1].scrollIntoView(true); 24 - } 25 - for (let line of $lineLines) { 26 - line.addEventListener("click", (event) => { 27 - event.preventDefault(); 28 - deactivateLines(); 29 - const n = parseInt(line.id.substring(1)); 30 - let anchor = ""; 31 - if (event.shiftKey) { 32 - end = n; 33 - anchor = `#L${start}-L${end}`; 34 - } else if (start === n) { 35 - start = 0; 36 - end = 0; 37 - } else { 38 - start = n; 39 - end = 0; 40 - anchor = `#L${start}`; 41 - } 42 - history.replaceState(null, null, window.location.pathname + anchor); 43 - $permalink.href = $permalink.dataset.permalink + anchor; 44 - if (start !== 0) activateLines(start, end); 45 - }); 46 - } 47 - if (navigator.clipboard && navigator.clipboard.writeText) { 48 - $copyButton.innerText = $copyIcon; 49 - $copyButton.classList.remove("hidden"); 50 - } 51 - $copyButton.addEventListener("click", () => { 52 - navigator.clipboard.writeText($code); 53 - $copyButton.innerText = $copiedIcon; 54 - setTimeout(() => { 55 - $copyButton.innerText = $copyIcon; 56 - }, 1000); 57 - }); 58 - 59 - function activateLines(start, end) { 60 - if (end < start) end = start; 61 - for (let idx = start - 1; idx < end; idx++) { 62 - $codeLines[idx].classList.add("active"); 63 - } 64 - } 65 - 66 - function deactivateLines() { 67 - for (let code of $codeLines) { 68 - code.classList.remove("active"); 69 - } 70 - }
+111
internal/html/repo_file.templ
··· 1 + package html 2 + 3 + import "fmt" 4 + 5 + type RepoFileContext struct { 6 + BaseContext 7 + RepoHeaderComponentContext 8 + RepoBreadcrumbComponentContext 9 + Code string 10 + Commit string 11 + Path string 12 + } 13 + 14 + func (rfc RepoFileContext) Permalink() string { 15 + return fmt.Sprintf("/%s/tree/%s/%s", rfc.RepoBreadcrumbComponentContext.Repo, rfc.Commit, rfc.Path) 16 + } 17 + 18 + templ RepoFile(rfc RepoFileContext) { 19 + @base(rfc.BaseContext) { 20 + @repoHeaderComponent(rfc.RepoHeaderComponentContext) 21 + <div class="mt-2 text-text"> 22 + @repoBreadcrumbComponent(rfc.RepoBreadcrumbComponentContext) 23 + { " - " } 24 + <a class="text-text underline decoration-text/50 decoration-dashed hover:decoration-solid" href="?raw">raw</a> 25 + { " - " } 26 + <a class="text-text underline decoration-text/50 decoration-dashed hover:decoration-solid" id="permalink" data-permalink={ rfc.Permalink() } href={ rfc.Permalink() }>permalink</a> 27 + <div class="code relative"> 28 + @templ.Raw(rfc.Code) 29 + <button id="copy" class="absolute top-0 right-0 rounded bg-base hover:bg-surface0"></button> 30 + </div> 31 + </div> 32 + } 33 + <script> 34 + const lineRe = /#L(\d+)(?:-L(\d+))?/g 35 + const $lineLines = document.querySelectorAll(".chroma .lntable .lnt"); 36 + const $codeLines = document.querySelectorAll(".chroma .lntable .line"); 37 + const $copyButton = document.getElementById('copy'); 38 + const $permalink = document.getElementById('permalink'); 39 + const $copyIcon = "๐Ÿ“‹"; 40 + const $copiedIcon = "โœ…"; 41 + let $code = "" 42 + for (let codeLine of $codeLines) $code += codeLine.innerText; 43 + let start = 0; 44 + let end = 0; 45 + 46 + const results = [...location.hash.matchAll(lineRe)]; 47 + if (0 in results) { 48 + start = results[0][1] !== undefined ? parseInt(results[0][1]) : 0; 49 + end = results[0][2] !== undefined ? parseInt(results[0][2]) : 0; 50 + } 51 + if (start !== 0) { 52 + deactivateLines(); 53 + activateLines(start, end); 54 + let anchor = `#${start}`; 55 + if (end !== 0) anchor += `-${end}`; 56 + if (anchor !== "") $permalink.href = $permalink.dataset.permalink + anchor; 57 + $lineLines[start-1].scrollIntoView(true); 58 + } 59 + 60 + for (let line of $lineLines) { 61 + line.addEventListener("click", (event) => { 62 + event.preventDefault(); 63 + deactivateLines(); 64 + const n = parseInt(line.id.substring(1)); 65 + let anchor = ""; 66 + if (event.shiftKey) { 67 + end = n; 68 + anchor = `#L${start}-L${end}`; 69 + } else if (start === n) { 70 + start = 0; 71 + end = 0; 72 + } else { 73 + start = n; 74 + end = 0; 75 + anchor = `#L${start}`; 76 + } 77 + history.replaceState(null, null, window.location.pathname + anchor); 78 + $permalink.href = $permalink.dataset.permalink + anchor; 79 + if (start !== 0) activateLines(start, end); 80 + }); 81 + } 82 + 83 + if (navigator.clipboard && navigator.clipboard.writeText) { 84 + $copyButton.innerText = $copyIcon; 85 + $copyButton.classList.remove("hidden"); 86 + } 87 + $copyButton.addEventListener("click", () => { 88 + navigator.clipboard.writeText($code); 89 + $copyButton.innerText = $copiedIcon; 90 + setTimeout(() => { 91 + $copyButton.innerText = $copyIcon; 92 + }, 1000); 93 + }); 94 + 95 + function activateLines(start, end) { 96 + if (end < start) end = start; 97 + for (let idx = start - 1; idx < end; idx++) { 98 + $codeLines[idx].classList.add("active"); 99 + } 100 + } 101 + 102 + function deactivateLines() { 103 + for (let code of $codeLines) { 104 + code.classList.remove("active"); 105 + } 106 + } 107 + 108 + 109 + 110 + </script> 111 + }
+145
internal/html/repo_file_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + import "fmt" 12 + 13 + type RepoFileContext struct { 14 + BaseContext 15 + RepoHeaderComponentContext 16 + RepoBreadcrumbComponentContext 17 + Code string 18 + Commit string 19 + Path string 20 + } 21 + 22 + func (rfc RepoFileContext) Permalink() string { 23 + return fmt.Sprintf("/%s/tree/%s/%s", rfc.RepoBreadcrumbComponentContext.Repo, rfc.Commit, rfc.Path) 24 + } 25 + 26 + func RepoFile(rfc RepoFileContext) templ.Component { 27 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 28 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 29 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 30 + return templ_7745c5c3_CtxErr 31 + } 32 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 33 + if !templ_7745c5c3_IsBuffer { 34 + defer func() { 35 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 36 + if templ_7745c5c3_Err == nil { 37 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 38 + } 39 + }() 40 + } 41 + ctx = templ.InitializeContext(ctx) 42 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 43 + if templ_7745c5c3_Var1 == nil { 44 + templ_7745c5c3_Var1 = templ.NopComponent 45 + } 46 + ctx = templ.ClearChildren(ctx) 47 + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 48 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 49 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 50 + if !templ_7745c5c3_IsBuffer { 51 + defer func() { 52 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 53 + if templ_7745c5c3_Err == nil { 54 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 55 + } 56 + }() 57 + } 58 + ctx = templ.InitializeContext(ctx) 59 + templ_7745c5c3_Err = repoHeaderComponent(rfc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 60 + if templ_7745c5c3_Err != nil { 61 + return templ_7745c5c3_Err 62 + } 63 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " <div class=\"mt-2 text-text\">") 64 + if templ_7745c5c3_Err != nil { 65 + return templ_7745c5c3_Err 66 + } 67 + templ_7745c5c3_Err = repoBreadcrumbComponent(rfc.RepoBreadcrumbComponentContext).Render(ctx, templ_7745c5c3_Buffer) 68 + if templ_7745c5c3_Err != nil { 69 + return templ_7745c5c3_Err 70 + } 71 + var templ_7745c5c3_Var3 string 72 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 73 + if templ_7745c5c3_Err != nil { 74 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 23, Col: 10} 75 + } 76 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 77 + if templ_7745c5c3_Err != nil { 78 + return templ_7745c5c3_Err 79 + } 80 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " <a class=\"text-text underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"?raw\">raw</a> ") 81 + if templ_7745c5c3_Err != nil { 82 + return templ_7745c5c3_Err 83 + } 84 + var templ_7745c5c3_Var4 string 85 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 86 + if templ_7745c5c3_Err != nil { 87 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 25, Col: 10} 88 + } 89 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 90 + if templ_7745c5c3_Err != nil { 91 + return templ_7745c5c3_Err 92 + } 93 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " <a class=\"text-text underline decoration-text/50 decoration-dashed hover:decoration-solid\" id=\"permalink\" data-permalink=\"") 94 + if templ_7745c5c3_Err != nil { 95 + return templ_7745c5c3_Err 96 + } 97 + var templ_7745c5c3_Var5 string 98 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(rfc.Permalink()) 99 + if templ_7745c5c3_Err != nil { 100 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 26, Col: 141} 101 + } 102 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 103 + if templ_7745c5c3_Err != nil { 104 + return templ_7745c5c3_Err 105 + } 106 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\" href=\"") 107 + if templ_7745c5c3_Err != nil { 108 + return templ_7745c5c3_Err 109 + } 110 + var templ_7745c5c3_Var6 templ.SafeURL 111 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinURLErrs(rfc.Permalink()) 112 + if templ_7745c5c3_Err != nil { 113 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_file.templ`, Line: 26, Col: 166} 114 + } 115 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 116 + if templ_7745c5c3_Err != nil { 117 + return templ_7745c5c3_Err 118 + } 119 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">permalink</a><div class=\"code relative\">") 120 + if templ_7745c5c3_Err != nil { 121 + return templ_7745c5c3_Err 122 + } 123 + templ_7745c5c3_Err = templ.Raw(rfc.Code).Render(ctx, templ_7745c5c3_Buffer) 124 + if templ_7745c5c3_Err != nil { 125 + return templ_7745c5c3_Err 126 + } 127 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<button id=\"copy\" class=\"absolute top-0 right-0 rounded bg-base hover:bg-surface0\"></button></div></div>") 128 + if templ_7745c5c3_Err != nil { 129 + return templ_7745c5c3_Err 130 + } 131 + return nil 132 + }) 133 + templ_7745c5c3_Err = base(rfc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 134 + if templ_7745c5c3_Err != nil { 135 + return templ_7745c5c3_Err 136 + } 137 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<script>\n\t\tconst lineRe = /#L(\\d+)(?:-L(\\d+))?/g\n\t\tconst $lineLines = document.querySelectorAll(\".chroma .lntable .lnt\");\n\t\tconst $codeLines = document.querySelectorAll(\".chroma .lntable .line\");\n\t\tconst $copyButton = document.getElementById('copy');\n\t\tconst $permalink = document.getElementById('permalink');\n\t\tconst $copyIcon = \"๐Ÿ“‹\";\n\t\tconst $copiedIcon = \"โœ…\";\n\t\tlet $code = \"\"\n\t\tfor (let codeLine of $codeLines) $code += codeLine.innerText;\n\t\tlet start = 0;\n\t\tlet end = 0;\n\n\t\tconst results = [...location.hash.matchAll(lineRe)];\t\t\n\t\tif (0 in results) {\n\t\t\tstart = results[0][1] !== undefined ? parseInt(results[0][1]) : 0;\n\t\t\tend = results[0][2] !== undefined ? parseInt(results[0][2]) : 0;\n\t\t}\n\t\tif (start !== 0) {\n\t\t\tdeactivateLines();\n\t\t\tactivateLines(start, end);\n\t\t\tlet anchor = `#${start}`;\n if (end !== 0) anchor += `-${end}`;\n if (anchor !== \"\") $permalink.href = $permalink.dataset.permalink + anchor;\n\t\t\t$lineLines[start-1].scrollIntoView(true);\n\t\t}\n\n\t\tfor (let line of $lineLines) {\n\t\t\tline.addEventListener(\"click\", (event) => {\n\t\t\t\tevent.preventDefault();\n\t\t\t\tdeactivateLines();\n\t\t\t\tconst n = parseInt(line.id.substring(1));\n\t\t\t\tlet anchor = \"\";\n\t\t\t\tif (event.shiftKey) {\n\t\t\t\t\tend = n;\n\t\t\t\t\tanchor = `#L${start}-L${end}`;\n\t\t\t\t} else if (start === n) {\n\t\t\t\t\tstart = 0;\n\t\t\t\t\tend = 0;\n\t\t\t\t} else {\n\t\t\t\t\tstart = n;\n\t\t\t\t\tend = 0;\n\t\t\t\t\tanchor = `#L${start}`;\n\t\t\t\t}\n\t\t\t\thistory.replaceState(null, null, window.location.pathname + anchor);\n\t\t\t\t$permalink.href = $permalink.dataset.permalink + anchor;\n\t\t\t\tif (start !== 0) activateLines(start, end);\n\t\t\t});\n\t\t}\n\n\t\tif (navigator.clipboard && navigator.clipboard.writeText) {\n\t\t\t$copyButton.innerText = $copyIcon;\n\t\t\t$copyButton.classList.remove(\"hidden\");\n }\n\t\t$copyButton.addEventListener(\"click\", () => {\n navigator.clipboard.writeText($code);\n\t\t\t$copyButton.innerText = $copiedIcon;\n\t\t\tsetTimeout(() => {\n\t\t\t\t$copyButton.innerText = $copyIcon;\n\t\t\t}, 1000);\n });\n\n\t\tfunction activateLines(start, end) {\n\t\t\tif (end < start) end = start;\n\t\t\tfor (let idx = start - 1; idx < end; idx++) {\n\t\t\t\t$codeLines[idx].classList.add(\"active\");\n\t\t\t}\n\t\t}\n\n\t\tfunction deactivateLines() {\n\t\t\tfor (let code of $codeLines) {\n\t\t\t\tcode.classList.remove(\"active\");\n\t\t\t}\n\t\t}\n\n\t\t\n\t\t\n\t</script>") 138 + if templ_7745c5c3_Err != nil { 139 + return templ_7745c5c3_Err 140 + } 141 + return nil 142 + }) 143 + } 144 + 145 + var _ = templruntime.GeneratedTemplate
-52
internal/html/repo_log.go
··· 1 - package html 2 - 3 - import ( 4 - "fmt" 5 - 6 - "github.com/dustin/go-humanize" 7 - "go.jolheiser.com/ugit/internal/git" 8 - . "maragu.dev/gomponents" 9 - . "maragu.dev/gomponents/html" 10 - ) 11 - 12 - type RepoLogContext struct { 13 - BaseContext 14 - RepoHeaderComponentContext 15 - Commits []git.Commit 16 - } 17 - 18 - func RepoLogTemplate(rlc RepoLogContext) Node { 19 - return base(rlc.BaseContext, []Node{ 20 - repoHeaderComponent(rlc.RepoHeaderComponentContext), 21 - Div(Class("grid sm:grid-cols-8 gap-1 text-text mt-5"), 22 - Map(rlc.Commits, func(commit git.Commit) Node { 23 - return Group([]Node{ 24 - Div(Class("sm:col-span-5"), 25 - Div( 26 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/commit/%s", rlc.RepoHeaderComponentContext.Name, commit.SHA)), Text(commit.Short())), 27 - ), 28 - Div(Class("whitespace-pre"), 29 - If(commit.Details() != "", 30 - Details( 31 - Summary(Class("cursor-pointer"), Text(commit.Summary())), 32 - Div(Class("p-3 bg-base rounded"), Text(commit.Details())), 33 - ), 34 - ), 35 - If(commit.Details() == "", 36 - Text(commit.Message), 37 - ), 38 - ), 39 - ), 40 - Div(Class("sm:col-span-3 mb-4"), 41 - Div( 42 - Text(commit.Author), 43 - Text(" "), 44 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("mailto:%s", commit.Email)), Textf("<%s>", commit.Email)), 45 - ), 46 - Div(Title(commit.When.Format("01/02/2006 03:04:05 PM")), Text(humanize.Time(commit.When))), 47 - ), 48 - }) 49 - }), 50 - ), 51 - }...) 52 - }
+38
internal/html/repo_log.templ
··· 1 + package html 2 + 3 + import "fmt" 4 + import "github.com/dustin/go-humanize" 5 + import "go.jolheiser.com/ugit/internal/git" 6 + 7 + type RepoLogContext struct { 8 + BaseContext 9 + RepoHeaderComponentContext 10 + Commits []git.Commit 11 + } 12 + 13 + templ RepoLog(rlc RepoLogContext) { 14 + @base(rlc.BaseContext) { 15 + @repoHeaderComponent(rlc.RepoHeaderComponentContext) 16 + <div class="grid sm:grid-cols-8 gap-1 text-text mt-5"> 17 + for _, commit := range rlc.Commits { 18 + <div class="sm:col-span-5"> 19 + <div><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/commit/%s", rlc.RepoHeaderComponentContext.Name, commit.SHA)) }>{ commit.Short() }</a></div> 20 + <div class="whitespace-pre"> 21 + if commit.Details() != "" { 22 + <details> 23 + <summary class="cursor-pointer">{ commit.Summary() }</summary> 24 + <div class="p-3 bg-base rounded">{ commit.Details() }</div> 25 + </details> 26 + } else { 27 + { commit.Message } 28 + } 29 + </div> 30 + </div> 31 + <div class="sm:col-span-3 mb-4"> 32 + <div>{ commit.Author }{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("mailto:%s", commit.Email)) }>{ fmt.Sprintf("<%s>", commit.Email) }</a></div> 33 + <div title={ commit.When.Format("01/02/2006 03:04:05 PM") }>{ humanize.Time(commit.When) }</div> 34 + </div> 35 + } 36 + </div> 37 + } 38 + }
+228
internal/html/repo_log_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + import "fmt" 12 + import "github.com/dustin/go-humanize" 13 + import "go.jolheiser.com/ugit/internal/git" 14 + 15 + type RepoLogContext struct { 16 + BaseContext 17 + RepoHeaderComponentContext 18 + Commits []git.Commit 19 + } 20 + 21 + func RepoLog(rlc RepoLogContext) templ.Component { 22 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 23 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 24 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 25 + return templ_7745c5c3_CtxErr 26 + } 27 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 28 + if !templ_7745c5c3_IsBuffer { 29 + defer func() { 30 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 31 + if templ_7745c5c3_Err == nil { 32 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 33 + } 34 + }() 35 + } 36 + ctx = templ.InitializeContext(ctx) 37 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 38 + if templ_7745c5c3_Var1 == nil { 39 + templ_7745c5c3_Var1 = templ.NopComponent 40 + } 41 + ctx = templ.ClearChildren(ctx) 42 + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 43 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 44 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 45 + if !templ_7745c5c3_IsBuffer { 46 + defer func() { 47 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 48 + if templ_7745c5c3_Err == nil { 49 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 50 + } 51 + }() 52 + } 53 + ctx = templ.InitializeContext(ctx) 54 + templ_7745c5c3_Err = repoHeaderComponent(rlc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 55 + if templ_7745c5c3_Err != nil { 56 + return templ_7745c5c3_Err 57 + } 58 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " <div class=\"grid sm:grid-cols-8 gap-1 text-text mt-5\">") 59 + if templ_7745c5c3_Err != nil { 60 + return templ_7745c5c3_Err 61 + } 62 + for _, commit := range rlc.Commits { 63 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<div class=\"sm:col-span-5\"><div><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 64 + if templ_7745c5c3_Err != nil { 65 + return templ_7745c5c3_Err 66 + } 67 + var templ_7745c5c3_Var3 templ.SafeURL 68 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/commit/%s", rlc.RepoHeaderComponentContext.Name, commit.SHA))) 69 + if templ_7745c5c3_Err != nil { 70 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 19, Col: 190} 71 + } 72 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 73 + if templ_7745c5c3_Err != nil { 74 + return templ_7745c5c3_Err 75 + } 76 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\">") 77 + if templ_7745c5c3_Err != nil { 78 + return templ_7745c5c3_Err 79 + } 80 + var templ_7745c5c3_Var4 string 81 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Short()) 82 + if templ_7745c5c3_Err != nil { 83 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 19, Col: 209} 84 + } 85 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 86 + if templ_7745c5c3_Err != nil { 87 + return templ_7745c5c3_Err 88 + } 89 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</a></div><div class=\"whitespace-pre\">") 90 + if templ_7745c5c3_Err != nil { 91 + return templ_7745c5c3_Err 92 + } 93 + if commit.Details() != "" { 94 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<details><summary class=\"cursor-pointer\">") 95 + if templ_7745c5c3_Err != nil { 96 + return templ_7745c5c3_Err 97 + } 98 + var templ_7745c5c3_Var5 string 99 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Summary()) 100 + if templ_7745c5c3_Err != nil { 101 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 23, Col: 58} 102 + } 103 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 104 + if templ_7745c5c3_Err != nil { 105 + return templ_7745c5c3_Err 106 + } 107 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</summary><div class=\"p-3 bg-base rounded\">") 108 + if templ_7745c5c3_Err != nil { 109 + return templ_7745c5c3_Err 110 + } 111 + var templ_7745c5c3_Var6 string 112 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Details()) 113 + if templ_7745c5c3_Err != nil { 114 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 24, Col: 59} 115 + } 116 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 117 + if templ_7745c5c3_Err != nil { 118 + return templ_7745c5c3_Err 119 + } 120 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div></details>") 121 + if templ_7745c5c3_Err != nil { 122 + return templ_7745c5c3_Err 123 + } 124 + } else { 125 + var templ_7745c5c3_Var7 string 126 + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Message) 127 + if templ_7745c5c3_Err != nil { 128 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 27, Col: 23} 129 + } 130 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 131 + if templ_7745c5c3_Err != nil { 132 + return templ_7745c5c3_Err 133 + } 134 + } 135 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div></div><div class=\"sm:col-span-3 mb-4\"><div>") 136 + if templ_7745c5c3_Err != nil { 137 + return templ_7745c5c3_Err 138 + } 139 + var templ_7745c5c3_Var8 string 140 + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(commit.Author) 141 + if templ_7745c5c3_Err != nil { 142 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 25} 143 + } 144 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 145 + if templ_7745c5c3_Err != nil { 146 + return templ_7745c5c3_Err 147 + } 148 + var templ_7745c5c3_Var9 string 149 + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 150 + if templ_7745c5c3_Err != nil { 151 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 32} 152 + } 153 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) 154 + if templ_7745c5c3_Err != nil { 155 + return templ_7745c5c3_Err 156 + } 157 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 158 + if templ_7745c5c3_Err != nil { 159 + return templ_7745c5c3_Err 160 + } 161 + var templ_7745c5c3_Var10 templ.SafeURL 162 + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("mailto:%s", commit.Email))) 163 + if templ_7745c5c3_Err != nil { 164 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 175} 165 + } 166 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) 167 + if templ_7745c5c3_Err != nil { 168 + return templ_7745c5c3_Err 169 + } 170 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">") 171 + if templ_7745c5c3_Err != nil { 172 + return templ_7745c5c3_Err 173 + } 174 + var templ_7745c5c3_Var11 string 175 + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("<%s>", commit.Email)) 176 + if templ_7745c5c3_Err != nil { 177 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 32, Col: 213} 178 + } 179 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 180 + if templ_7745c5c3_Err != nil { 181 + return templ_7745c5c3_Err 182 + } 183 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</a></div><div title=\"") 184 + if templ_7745c5c3_Err != nil { 185 + return templ_7745c5c3_Err 186 + } 187 + var templ_7745c5c3_Var12 string 188 + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(commit.When.Format("01/02/2006 03:04:05 PM")) 189 + if templ_7745c5c3_Err != nil { 190 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 33, Col: 62} 191 + } 192 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) 193 + if templ_7745c5c3_Err != nil { 194 + return templ_7745c5c3_Err 195 + } 196 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\">") 197 + if templ_7745c5c3_Err != nil { 198 + return templ_7745c5c3_Err 199 + } 200 + var templ_7745c5c3_Var13 string 201 + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(humanize.Time(commit.When)) 202 + if templ_7745c5c3_Err != nil { 203 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_log.templ`, Line: 33, Col: 93} 204 + } 205 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) 206 + if templ_7745c5c3_Err != nil { 207 + return templ_7745c5c3_Err 208 + } 209 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div></div>") 210 + if templ_7745c5c3_Err != nil { 211 + return templ_7745c5c3_Err 212 + } 213 + } 214 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</div>") 215 + if templ_7745c5c3_Err != nil { 216 + return templ_7745c5c3_Err 217 + } 218 + return nil 219 + }) 220 + templ_7745c5c3_Err = base(rlc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 221 + if templ_7745c5c3_Err != nil { 222 + return templ_7745c5c3_Err 223 + } 224 + return nil 225 + }) 226 + } 227 + 228 + var _ = templruntime.GeneratedTemplate
-61
internal/html/repo_refs.go
··· 1 - package html 2 - 3 - import ( 4 - "fmt" 5 - 6 - "go.jolheiser.com/ugit/internal/git" 7 - . "maragu.dev/gomponents" 8 - . "maragu.dev/gomponents/html" 9 - ) 10 - 11 - type RepoRefsContext struct { 12 - BaseContext 13 - RepoHeaderComponentContext 14 - Branches []string 15 - Tags []git.Tag 16 - } 17 - 18 - func RepoRefsTemplate(rrc RepoRefsContext) Node { 19 - return base(rrc.BaseContext, []Node{ 20 - repoHeaderComponent(rrc.RepoHeaderComponentContext), 21 - If(len(rrc.Branches) > 0, Group([]Node{ 22 - H3(Class("text-text text-lg mt-5"), Text("Branches")), 23 - Div(Class("text-text grid grid-cols-4 sm:grid-cols-8"), 24 - Map(rrc.Branches, func(branch string) Node { 25 - return Group([]Node{ 26 - Div(Class("col-span-2 sm:col-span-1 font-bold"), Text(branch)), 27 - Div(Class("col-span-2 sm:col-span-7"), 28 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, branch)), Text("tree")), 29 - Text(" "), 30 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, branch)), Text("log")), 31 - ), 32 - }) 33 - }), 34 - ), 35 - })), 36 - If(len(rrc.Tags) > 0, Group([]Node{ 37 - H3(Class("text-text text-lg mt-5"), Text("Tags")), 38 - Div(Class("text-text grid grid-cols-8"), 39 - Map(rrc.Tags, func(tag git.Tag) Node { 40 - return Group([]Node{ 41 - Div(Class("col-span-1 font-bold"), Text(tag.Name)), 42 - Div(Class("col-span-7"), 43 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, tag.Name)), Text("tree")), 44 - Text(" "), 45 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, tag.Name)), Text("log")), 46 - ), 47 - If(tag.Signature != "", 48 - Details(Class("col-span-8 whitespace-pre"), 49 - Summary(Class("cursor-pointer"), Text("Signature")), 50 - Code(Text(tag.Signature)), 51 - ), 52 - ), 53 - If(tag.Annotation != "", 54 - Div(Class("col-span-8 mb-3"), Text(tag.Annotation)), 55 - ), 56 - }) 57 - }), 58 - ), 59 - })), 60 - }...) 61 - }
+41
internal/html/repo_refs.templ
··· 1 + package html 2 + 3 + import "fmt" 4 + import "go.jolheiser.com/ugit/internal/git" 5 + 6 + type RepoRefsContext struct { 7 + BaseContext 8 + RepoHeaderComponentContext 9 + Branches []string 10 + Tags []git.Tag 11 + } 12 + 13 + templ RepoRefs(rrc RepoRefsContext) { 14 + @base(rrc.BaseContext) { 15 + @repoHeaderComponent(rrc.RepoHeaderComponentContext) 16 + if len(rrc.Branches) > 0 { 17 + <h3 class="text-text text-lg mt-5">Branches</h3> 18 + <div class="text-text grid grid-cols-4 sm:grid-cols-8"> 19 + for _, branch := range rrc.Branches { 20 + <div class="col-span-2 sm:col-span-1 font-bold">{ branch }</div> 21 + <div class="col-span-2 sm:col-span-7"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, branch)) }>tree</a>{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, branch)) }>log</a></div> 22 + } 23 + </div> 24 + } 25 + if len(rrc.Tags) > 0 { 26 + <h3 class="text-text text-lg mt-5">Tags</h3> 27 + <div class="text-text grid grid-cols-8"> 28 + for _, tag := range rrc.Tags { 29 + <div class="col-span-1 font-bold">{ tag.Name }</div> 30 + <div class="col-span-7"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, tag.Name)) }>tree</a>{ " " }<a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, tag.Name)) }>log</a></div> 31 + if tag.Signature != "" { 32 + <details class="col-span-8 whitespace-pre"><summary class="cursor-pointer">Signature</summary><code>{ tag.Signature }</code></details> 33 + } 34 + if tag.Annotation != "" { 35 + <div class="col-span-8 mb-3">{ tag.Annotation }</div> 36 + } 37 + } 38 + </div> 39 + } 40 + } 41 + }
+254
internal/html/repo_refs_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + import "fmt" 12 + import "go.jolheiser.com/ugit/internal/git" 13 + 14 + type RepoRefsContext struct { 15 + BaseContext 16 + RepoHeaderComponentContext 17 + Branches []string 18 + Tags []git.Tag 19 + } 20 + 21 + func RepoRefs(rrc RepoRefsContext) templ.Component { 22 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 23 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 24 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 25 + return templ_7745c5c3_CtxErr 26 + } 27 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 28 + if !templ_7745c5c3_IsBuffer { 29 + defer func() { 30 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 31 + if templ_7745c5c3_Err == nil { 32 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 33 + } 34 + }() 35 + } 36 + ctx = templ.InitializeContext(ctx) 37 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 38 + if templ_7745c5c3_Var1 == nil { 39 + templ_7745c5c3_Var1 = templ.NopComponent 40 + } 41 + ctx = templ.ClearChildren(ctx) 42 + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 43 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 44 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 45 + if !templ_7745c5c3_IsBuffer { 46 + defer func() { 47 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 48 + if templ_7745c5c3_Err == nil { 49 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 50 + } 51 + }() 52 + } 53 + ctx = templ.InitializeContext(ctx) 54 + templ_7745c5c3_Err = repoHeaderComponent(rrc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 55 + if templ_7745c5c3_Err != nil { 56 + return templ_7745c5c3_Err 57 + } 58 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") 59 + if templ_7745c5c3_Err != nil { 60 + return templ_7745c5c3_Err 61 + } 62 + if len(rrc.Branches) > 0 { 63 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<h3 class=\"text-text text-lg mt-5\">Branches</h3><div class=\"text-text grid grid-cols-4 sm:grid-cols-8\">") 64 + if templ_7745c5c3_Err != nil { 65 + return templ_7745c5c3_Err 66 + } 67 + for _, branch := range rrc.Branches { 68 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<div class=\"col-span-2 sm:col-span-1 font-bold\">") 69 + if templ_7745c5c3_Err != nil { 70 + return templ_7745c5c3_Err 71 + } 72 + var templ_7745c5c3_Var3 string 73 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(branch) 74 + if templ_7745c5c3_Err != nil { 75 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 20, Col: 61} 76 + } 77 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 78 + if templ_7745c5c3_Err != nil { 79 + return templ_7745c5c3_Err 80 + } 81 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "</div><div class=\"col-span-2 sm:col-span-7\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 82 + if templ_7745c5c3_Err != nil { 83 + return templ_7745c5c3_Err 84 + } 85 + var templ_7745c5c3_Var4 templ.SafeURL 86 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, branch))) 87 + if templ_7745c5c3_Err != nil { 88 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 21, Col: 218} 89 + } 90 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 91 + if templ_7745c5c3_Err != nil { 92 + return templ_7745c5c3_Err 93 + } 94 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">tree</a>") 95 + if templ_7745c5c3_Err != nil { 96 + return templ_7745c5c3_Err 97 + } 98 + var templ_7745c5c3_Var5 string 99 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 100 + if templ_7745c5c3_Err != nil { 101 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 21, Col: 234} 102 + } 103 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 104 + if templ_7745c5c3_Err != nil { 105 + return templ_7745c5c3_Err 106 + } 107 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 108 + if templ_7745c5c3_Err != nil { 109 + return templ_7745c5c3_Err 110 + } 111 + var templ_7745c5c3_Var6 templ.SafeURL 112 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, branch))) 113 + if templ_7745c5c3_Err != nil { 114 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 21, Col: 409} 115 + } 116 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 117 + if templ_7745c5c3_Err != nil { 118 + return templ_7745c5c3_Err 119 + } 120 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "\">log</a></div>") 121 + if templ_7745c5c3_Err != nil { 122 + return templ_7745c5c3_Err 123 + } 124 + } 125 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div>") 126 + if templ_7745c5c3_Err != nil { 127 + return templ_7745c5c3_Err 128 + } 129 + } 130 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " ") 131 + if templ_7745c5c3_Err != nil { 132 + return templ_7745c5c3_Err 133 + } 134 + if len(rrc.Tags) > 0 { 135 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<h3 class=\"text-text text-lg mt-5\">Tags</h3><div class=\"text-text grid grid-cols-8\">") 136 + if templ_7745c5c3_Err != nil { 137 + return templ_7745c5c3_Err 138 + } 139 + for _, tag := range rrc.Tags { 140 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<div class=\"col-span-1 font-bold\">") 141 + if templ_7745c5c3_Err != nil { 142 + return templ_7745c5c3_Err 143 + } 144 + var templ_7745c5c3_Var7 string 145 + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Name) 146 + if templ_7745c5c3_Err != nil { 147 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 29, Col: 49} 148 + } 149 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 150 + if templ_7745c5c3_Err != nil { 151 + return templ_7745c5c3_Err 152 + } 153 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div><div class=\"col-span-7\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 154 + if templ_7745c5c3_Err != nil { 155 + return templ_7745c5c3_Err 156 + } 157 + var templ_7745c5c3_Var8 templ.SafeURL 158 + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rrc.RepoHeaderComponentContext.Name, tag.Name))) 159 + if templ_7745c5c3_Err != nil { 160 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 30, Col: 206} 161 + } 162 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 163 + if templ_7745c5c3_Err != nil { 164 + return templ_7745c5c3_Err 165 + } 166 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "\">tree</a>") 167 + if templ_7745c5c3_Err != nil { 168 + return templ_7745c5c3_Err 169 + } 170 + var templ_7745c5c3_Var9 string 171 + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 172 + if templ_7745c5c3_Err != nil { 173 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 30, Col: 222} 174 + } 175 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) 176 + if templ_7745c5c3_Err != nil { 177 + return templ_7745c5c3_Err 178 + } 179 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 180 + if templ_7745c5c3_Err != nil { 181 + return templ_7745c5c3_Err 182 + } 183 + var templ_7745c5c3_Var10 templ.SafeURL 184 + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/log/%s", rrc.RepoHeaderComponentContext.Name, tag.Name))) 185 + if templ_7745c5c3_Err != nil { 186 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 30, Col: 399} 187 + } 188 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) 189 + if templ_7745c5c3_Err != nil { 190 + return templ_7745c5c3_Err 191 + } 192 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "\">log</a></div>") 193 + if templ_7745c5c3_Err != nil { 194 + return templ_7745c5c3_Err 195 + } 196 + if tag.Signature != "" { 197 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<details class=\"col-span-8 whitespace-pre\"><summary class=\"cursor-pointer\">Signature</summary><code>") 198 + if templ_7745c5c3_Err != nil { 199 + return templ_7745c5c3_Err 200 + } 201 + var templ_7745c5c3_Var11 string 202 + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Signature) 203 + if templ_7745c5c3_Err != nil { 204 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 32, Col: 121} 205 + } 206 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 207 + if templ_7745c5c3_Err != nil { 208 + return templ_7745c5c3_Err 209 + } 210 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</code></details>") 211 + if templ_7745c5c3_Err != nil { 212 + return templ_7745c5c3_Err 213 + } 214 + } 215 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, " ") 216 + if templ_7745c5c3_Err != nil { 217 + return templ_7745c5c3_Err 218 + } 219 + if tag.Annotation != "" { 220 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<div class=\"col-span-8 mb-3\">") 221 + if templ_7745c5c3_Err != nil { 222 + return templ_7745c5c3_Err 223 + } 224 + var templ_7745c5c3_Var12 string 225 + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(tag.Annotation) 226 + if templ_7745c5c3_Err != nil { 227 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_refs.templ`, Line: 35, Col: 51} 228 + } 229 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) 230 + if templ_7745c5c3_Err != nil { 231 + return templ_7745c5c3_Err 232 + } 233 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</div>") 234 + if templ_7745c5c3_Err != nil { 235 + return templ_7745c5c3_Err 236 + } 237 + } 238 + } 239 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "</div>") 240 + if templ_7745c5c3_Err != nil { 241 + return templ_7745c5c3_Err 242 + } 243 + } 244 + return nil 245 + }) 246 + templ_7745c5c3_Err = base(rrc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 247 + if templ_7745c5c3_Err != nil { 248 + return templ_7745c5c3_Err 249 + } 250 + return nil 251 + }) 252 + } 253 + 254 + var _ = templruntime.GeneratedTemplate
-78
internal/html/repo_search.go
··· 1 - package html 2 - 3 - import ( 4 - _ "embed" 5 - "fmt" 6 - 7 - "go.jolheiser.com/ugit/internal/git" 8 - . "maragu.dev/gomponents" 9 - . "maragu.dev/gomponents/html" 10 - ) 11 - 12 - type SearchContext struct { 13 - BaseContext 14 - RepoHeaderComponentContext 15 - Results []git.GrepResult 16 - } 17 - 18 - func (s SearchContext) DedupeResults() [][]git.GrepResult { 19 - var ( 20 - results [][]git.GrepResult 21 - currentFile string 22 - ) 23 - var idx int 24 - for _, result := range s.Results { 25 - if result.File == currentFile { 26 - results[idx-1] = append(results[idx-1], result) 27 - continue 28 - } 29 - results = append(results, []git.GrepResult{result}) 30 - currentFile = result.File 31 - idx++ 32 - } 33 - 34 - return results 35 - } 36 - 37 - //go:embed repo_search.js 38 - var repoSearchJS string 39 - 40 - func repoSearchResult(repo, ref string, results []git.GrepResult) Node { 41 - return Group([]Node{ 42 - Div(Class("text-text mt-5"), 43 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, results[0].File, results[0].Line)), Text(results[0].File)), 44 - ), 45 - Div(Class("code"), 46 - Raw(results[0].Content), 47 - ), 48 - If(len(results) > 1, 49 - Details(Class("text-text cursor-pointer"), 50 - Summary(Textf("%d more", len(results[1:]))), 51 - Map(results[1:], func(result git.GrepResult) Node { 52 - return Group([]Node{ 53 - Div(Class("text-text mt-5 ml-5"), 54 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, result.File, result.Line)), Text(results[0].File)), 55 - ), 56 - Div(Class("code ml-5"), 57 - Raw(result.Content), 58 - ), 59 - }) 60 - }), 61 - ), 62 - ), 63 - }) 64 - } 65 - 66 - func RepoSearchTemplate(sc SearchContext) Node { 67 - dedupeResults := sc.DedupeResults() 68 - return base(sc.BaseContext, []Node{ 69 - repoHeaderComponent(sc.RepoHeaderComponentContext), 70 - Map(dedupeResults, func(results []git.GrepResult) Node { 71 - return repoSearchResult(sc.RepoHeaderComponentContext.Name, sc.RepoHeaderComponentContext.Ref, results) 72 - }), 73 - If(len(dedupeResults) == 0, 74 - P(Class("text-text mt-5 text-lg"), Text("No results")), 75 - ), 76 - Script(Raw(repoSearchJS)), 77 - }...) 78 - }
-2
internal/html/repo_search.js
··· 1 - const search = new URLSearchParams(window.location.search).get("q"); 2 - if (search !== "") document.querySelector("#search").value = search;
+63
internal/html/repo_search.templ
··· 1 + package html 2 + 3 + import "fmt" 4 + import "go.jolheiser.com/ugit/internal/git" 5 + 6 + type SearchContext struct { 7 + BaseContext 8 + RepoHeaderComponentContext 9 + Results []git.GrepResult 10 + } 11 + 12 + func (s SearchContext) DedupeResults() [][]git.GrepResult { 13 + var ( 14 + results [][]git.GrepResult 15 + currentFile string 16 + ) 17 + var idx int 18 + for _, result := range s.Results { 19 + if result.File == currentFile { 20 + results[idx-1] = append(results[idx-1], result) 21 + continue 22 + } 23 + results = append(results, []git.GrepResult{result}) 24 + currentFile = result.File 25 + idx++ 26 + } 27 + 28 + return results 29 + } 30 + 31 + templ RepoSearch(sc SearchContext) { 32 + @base(sc.BaseContext) { 33 + @repoHeaderComponent(sc.RepoHeaderComponentContext) 34 + for _, results := range sc.DedupeResults() { 35 + @repoSearchResult(sc.RepoHeaderComponentContext.Name, sc.RepoHeaderComponentContext.Ref, results) 36 + } 37 + if len(sc.DedupeResults()) == 0 { 38 + <p class="text-text mt-5 text-lg">No results</p> 39 + } 40 + } 41 + <script> 42 + const search = new URLSearchParams(window.location.search).get("q"); 43 + if (search !== "") document.querySelector("#search").value = search; 44 + </script> 45 + } 46 + 47 + templ repoSearchResult(repo, ref string, results []git.GrepResult) { 48 + <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> 49 + <div class="code"> 50 + @templ.Raw(results[0].Content) 51 + </div> 52 + if len(results) > 1 { 53 + <details class="text-text cursor-pointer"> 54 + <summary>{ fmt.Sprintf("%d ", len(results[1:])) }more</summary> 55 + for _, result := range results[1:] { 56 + <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> 57 + <div class="code ml-5"> 58 + @templ.Raw(result.Content) 59 + </div> 60 + } 61 + </details> 62 + } 63 + }
+232
internal/html/repo_search_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + import "fmt" 12 + import "go.jolheiser.com/ugit/internal/git" 13 + 14 + type SearchContext struct { 15 + BaseContext 16 + RepoHeaderComponentContext 17 + Results []git.GrepResult 18 + } 19 + 20 + func (s SearchContext) DedupeResults() [][]git.GrepResult { 21 + var ( 22 + results [][]git.GrepResult 23 + currentFile string 24 + ) 25 + var idx int 26 + for _, result := range s.Results { 27 + if result.File == currentFile { 28 + results[idx-1] = append(results[idx-1], result) 29 + continue 30 + } 31 + results = append(results, []git.GrepResult{result}) 32 + currentFile = result.File 33 + idx++ 34 + } 35 + 36 + return results 37 + } 38 + 39 + func RepoSearch(sc SearchContext) templ.Component { 40 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 41 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 42 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 43 + return templ_7745c5c3_CtxErr 44 + } 45 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 46 + if !templ_7745c5c3_IsBuffer { 47 + defer func() { 48 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 49 + if templ_7745c5c3_Err == nil { 50 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 51 + } 52 + }() 53 + } 54 + ctx = templ.InitializeContext(ctx) 55 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 56 + if templ_7745c5c3_Var1 == nil { 57 + templ_7745c5c3_Var1 = templ.NopComponent 58 + } 59 + ctx = templ.ClearChildren(ctx) 60 + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 61 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 62 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 63 + if !templ_7745c5c3_IsBuffer { 64 + defer func() { 65 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 66 + if templ_7745c5c3_Err == nil { 67 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 68 + } 69 + }() 70 + } 71 + ctx = templ.InitializeContext(ctx) 72 + templ_7745c5c3_Err = repoHeaderComponent(sc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 73 + if templ_7745c5c3_Err != nil { 74 + return templ_7745c5c3_Err 75 + } 76 + for _, results := range sc.DedupeResults() { 77 + templ_7745c5c3_Err = repoSearchResult(sc.RepoHeaderComponentContext.Name, sc.RepoHeaderComponentContext.Ref, results).Render(ctx, templ_7745c5c3_Buffer) 78 + if templ_7745c5c3_Err != nil { 79 + return templ_7745c5c3_Err 80 + } 81 + } 82 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") 83 + if templ_7745c5c3_Err != nil { 84 + return templ_7745c5c3_Err 85 + } 86 + if len(sc.DedupeResults()) == 0 { 87 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "<p class=\"text-text mt-5 text-lg\">No results</p>") 88 + if templ_7745c5c3_Err != nil { 89 + return templ_7745c5c3_Err 90 + } 91 + } 92 + return nil 93 + }) 94 + templ_7745c5c3_Err = base(sc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 95 + if templ_7745c5c3_Err != nil { 96 + return templ_7745c5c3_Err 97 + } 98 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "<script>\n\t\tconst search = new URLSearchParams(window.location.search).get(\"q\");\n\t\tif (search !== \"\") document.querySelector(\"#search\").value = search;\n\t</script>") 99 + if templ_7745c5c3_Err != nil { 100 + return templ_7745c5c3_Err 101 + } 102 + return nil 103 + }) 104 + } 105 + 106 + func repoSearchResult(repo, ref string, results []git.GrepResult) templ.Component { 107 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 108 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 109 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 110 + return templ_7745c5c3_CtxErr 111 + } 112 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 113 + if !templ_7745c5c3_IsBuffer { 114 + defer func() { 115 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 116 + if templ_7745c5c3_Err == nil { 117 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 118 + } 119 + }() 120 + } 121 + ctx = templ.InitializeContext(ctx) 122 + templ_7745c5c3_Var3 := templ.GetChildren(ctx) 123 + if templ_7745c5c3_Var3 == nil { 124 + templ_7745c5c3_Var3 = templ.NopComponent 125 + } 126 + ctx = templ.ClearChildren(ctx) 127 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"text-text mt-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 128 + if templ_7745c5c3_Err != nil { 129 + return templ_7745c5c3_Err 130 + } 131 + var templ_7745c5c3_Var4 templ.SafeURL 132 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, results[0].File, results[0].Line))) 133 + if templ_7745c5c3_Err != nil { 134 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 48, Col: 210} 135 + } 136 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 137 + if templ_7745c5c3_Err != nil { 138 + return templ_7745c5c3_Err 139 + } 140 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">") 141 + if templ_7745c5c3_Err != nil { 142 + return templ_7745c5c3_Err 143 + } 144 + var templ_7745c5c3_Var5 string 145 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File) 146 + if templ_7745c5c3_Err != nil { 147 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 48, Col: 230} 148 + } 149 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 150 + if templ_7745c5c3_Err != nil { 151 + return templ_7745c5c3_Err 152 + } 153 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a></div><div class=\"code\">") 154 + if templ_7745c5c3_Err != nil { 155 + return templ_7745c5c3_Err 156 + } 157 + templ_7745c5c3_Err = templ.Raw(results[0].Content).Render(ctx, templ_7745c5c3_Buffer) 158 + if templ_7745c5c3_Err != nil { 159 + return templ_7745c5c3_Err 160 + } 161 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>") 162 + if templ_7745c5c3_Err != nil { 163 + return templ_7745c5c3_Err 164 + } 165 + if len(results) > 1 { 166 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "<details class=\"text-text cursor-pointer\"><summary>") 167 + if templ_7745c5c3_Err != nil { 168 + return templ_7745c5c3_Err 169 + } 170 + var templ_7745c5c3_Var6 string 171 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%d ", len(results[1:]))) 172 + if templ_7745c5c3_Err != nil { 173 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 54, Col: 50} 174 + } 175 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 176 + if templ_7745c5c3_Err != nil { 177 + return templ_7745c5c3_Err 178 + } 179 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "more</summary> ") 180 + if templ_7745c5c3_Err != nil { 181 + return templ_7745c5c3_Err 182 + } 183 + for _, result := range results[1:] { 184 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "<div class=\"text-text mt-5 ml-5\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 185 + if templ_7745c5c3_Err != nil { 186 + return templ_7745c5c3_Err 187 + } 188 + var templ_7745c5c3_Var7 templ.SafeURL 189 + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s#L%d", repo, ref, result.File, result.Line))) 190 + if templ_7745c5c3_Err != nil { 191 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 56, Col: 210} 192 + } 193 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 194 + if templ_7745c5c3_Err != nil { 195 + return templ_7745c5c3_Err 196 + } 197 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "\">") 198 + if templ_7745c5c3_Err != nil { 199 + return templ_7745c5c3_Err 200 + } 201 + var templ_7745c5c3_Var8 string 202 + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(results[0].File) 203 + if templ_7745c5c3_Err != nil { 204 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_search.templ`, Line: 56, Col: 230} 205 + } 206 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 207 + if templ_7745c5c3_Err != nil { 208 + return templ_7745c5c3_Err 209 + } 210 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</a></div><div class=\"code ml-5\">") 211 + if templ_7745c5c3_Err != nil { 212 + return templ_7745c5c3_Err 213 + } 214 + templ_7745c5c3_Err = templ.Raw(result.Content).Render(ctx, templ_7745c5c3_Buffer) 215 + if templ_7745c5c3_Err != nil { 216 + return templ_7745c5c3_Err 217 + } 218 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</div>") 219 + if templ_7745c5c3_Err != nil { 220 + return templ_7745c5c3_Err 221 + } 222 + } 223 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</details>") 224 + if templ_7745c5c3_Err != nil { 225 + return templ_7745c5c3_Err 226 + } 227 + } 228 + return nil 229 + }) 230 + } 231 + 232 + var _ = templruntime.GeneratedTemplate
+257
internal/html/repo_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + import "fmt" 12 + 13 + type RepoHeaderComponentContext struct { 14 + Name string 15 + Ref string 16 + Description string 17 + CloneURL string 18 + Tags []string 19 + } 20 + 21 + func repoHeaderComponent(rhcc RepoHeaderComponentContext) templ.Component { 22 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 23 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 24 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 25 + return templ_7745c5c3_CtxErr 26 + } 27 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 28 + if !templ_7745c5c3_IsBuffer { 29 + defer func() { 30 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 31 + if templ_7745c5c3_Err == nil { 32 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 33 + } 34 + }() 35 + } 36 + ctx = templ.InitializeContext(ctx) 37 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 38 + if templ_7745c5c3_Var1 == nil { 39 + templ_7745c5c3_Var1 = templ.NopComponent 40 + } 41 + ctx = templ.ClearChildren(ctx) 42 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<div class=\"mb-1 text-text\"><a class=\"text-lg underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 43 + if templ_7745c5c3_Err != nil { 44 + return templ_7745c5c3_Err 45 + } 46 + var templ_7745c5c3_Var2 templ.SafeURL 47 + templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL("/" + rhcc.Name)) 48 + if templ_7745c5c3_Err != nil { 49 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 15, Col: 128} 50 + } 51 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2)) 52 + if templ_7745c5c3_Err != nil { 53 + return templ_7745c5c3_Err 54 + } 55 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\">") 56 + if templ_7745c5c3_Err != nil { 57 + return templ_7745c5c3_Err 58 + } 59 + var templ_7745c5c3_Var3 string 60 + templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(rhcc.Name) 61 + if templ_7745c5c3_Err != nil { 62 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 15, Col: 142} 63 + } 64 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3)) 65 + if templ_7745c5c3_Err != nil { 66 + return templ_7745c5c3_Err 67 + } 68 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</a> ") 69 + if templ_7745c5c3_Err != nil { 70 + return templ_7745c5c3_Err 71 + } 72 + if rhcc.Ref != "" { 73 + var templ_7745c5c3_Var4 string 74 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(" ") 75 + if templ_7745c5c3_Err != nil { 76 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 17, Col: 8} 77 + } 78 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 79 + if templ_7745c5c3_Err != nil { 80 + return templ_7745c5c3_Err 81 + } 82 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, " <a class=\"text-text/80 text-sm underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 83 + if templ_7745c5c3_Err != nil { 84 + return templ_7745c5c3_Err 85 + } 86 + var templ_7745c5c3_Var5 templ.SafeURL 87 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/", rhcc.Name, rhcc.Ref))) 88 + if templ_7745c5c3_Err != nil { 89 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 18, Col: 175} 90 + } 91 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 92 + if templ_7745c5c3_Err != nil { 93 + return templ_7745c5c3_Err 94 + } 95 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\">") 96 + if templ_7745c5c3_Err != nil { 97 + return templ_7745c5c3_Err 98 + } 99 + var templ_7745c5c3_Var6 string 100 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs("@" + rhcc.Ref) 101 + if templ_7745c5c3_Err != nil { 102 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 18, Col: 194} 103 + } 104 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 105 + if templ_7745c5c3_Err != nil { 106 + return templ_7745c5c3_Err 107 + } 108 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "</a> ") 109 + if templ_7745c5c3_Err != nil { 110 + return templ_7745c5c3_Err 111 + } 112 + } 113 + var templ_7745c5c3_Var7 string 114 + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 115 + if templ_7745c5c3_Err != nil { 116 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 20, Col: 9} 117 + } 118 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 119 + if templ_7745c5c3_Err != nil { 120 + return templ_7745c5c3_Err 121 + } 122 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, " <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 123 + if templ_7745c5c3_Err != nil { 124 + return templ_7745c5c3_Err 125 + } 126 + var templ_7745c5c3_Var8 templ.SafeURL 127 + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/refs", rhcc.Name))) 128 + if templ_7745c5c3_Err != nil { 129 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 21, Col: 139} 130 + } 131 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 132 + if templ_7745c5c3_Err != nil { 133 + return templ_7745c5c3_Err 134 + } 135 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "\">refs</a> ") 136 + if templ_7745c5c3_Err != nil { 137 + return templ_7745c5c3_Err 138 + } 139 + var templ_7745c5c3_Var9 string 140 + templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 141 + if templ_7745c5c3_Err != nil { 142 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 22, Col: 9} 143 + } 144 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9)) 145 + if templ_7745c5c3_Err != nil { 146 + return templ_7745c5c3_Err 147 + } 148 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, " <a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 149 + if templ_7745c5c3_Err != nil { 150 + return templ_7745c5c3_Err 151 + } 152 + var templ_7745c5c3_Var10 templ.SafeURL 153 + templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/log/%s", rhcc.Name, rhcc.Ref))) 154 + if templ_7745c5c3_Err != nil { 155 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 23, Col: 151} 156 + } 157 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10)) 158 + if templ_7745c5c3_Err != nil { 159 + return templ_7745c5c3_Err 160 + } 161 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">log</a> ") 162 + if templ_7745c5c3_Err != nil { 163 + return templ_7745c5c3_Err 164 + } 165 + var templ_7745c5c3_Var11 string 166 + templ_7745c5c3_Var11, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 167 + if templ_7745c5c3_Err != nil { 168 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 24, Col: 9} 169 + } 170 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var11)) 171 + if templ_7745c5c3_Err != nil { 172 + return templ_7745c5c3_Err 173 + } 174 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "<form class=\"inline-block\" action=\"") 175 + if templ_7745c5c3_Err != nil { 176 + return templ_7745c5c3_Err 177 + } 178 + var templ_7745c5c3_Var12 templ.SafeURL 179 + templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/search", rhcc.Name))) 180 + if templ_7745c5c3_Err != nil { 181 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 25, Col: 89} 182 + } 183 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12)) 184 + if templ_7745c5c3_Err != nil { 185 + return templ_7745c5c3_Err 186 + } 187 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "\" 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>") 188 + if templ_7745c5c3_Err != nil { 189 + return templ_7745c5c3_Err 190 + } 191 + var templ_7745c5c3_Var13 string 192 + templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinStringErrs(" - ") 193 + if templ_7745c5c3_Err != nil { 194 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 26, Col: 9} 195 + } 196 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13)) 197 + if templ_7745c5c3_Err != nil { 198 + return templ_7745c5c3_Err 199 + } 200 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "<pre class=\"text-text inline select-all bg-base dark:bg-base/50 p-1 rounded\">") 201 + if templ_7745c5c3_Err != nil { 202 + return templ_7745c5c3_Err 203 + } 204 + var templ_7745c5c3_Var14 string 205 + templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(fmt.Sprintf("%s/%s.git", rhcc.CloneURL, rhcc.Name)) 206 + if templ_7745c5c3_Err != nil { 207 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 27, Col: 131} 208 + } 209 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14)) 210 + if templ_7745c5c3_Err != nil { 211 + return templ_7745c5c3_Err 212 + } 213 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "</pre></div><div class=\"text-subtext0 mb-1\">") 214 + if templ_7745c5c3_Err != nil { 215 + return templ_7745c5c3_Err 216 + } 217 + for _, tag := range rhcc.Tags { 218 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "<span class=\"rounded border-rosewater border-solid border pb-0.5 px-1 mr-1 mb-1 inline-block\">") 219 + if templ_7745c5c3_Err != nil { 220 + return templ_7745c5c3_Err 221 + } 222 + var templ_7745c5c3_Var15 string 223 + templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(tag) 224 + if templ_7745c5c3_Err != nil { 225 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 31, Col: 102} 226 + } 227 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15)) 228 + if templ_7745c5c3_Err != nil { 229 + return templ_7745c5c3_Err 230 + } 231 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "</span>") 232 + if templ_7745c5c3_Err != nil { 233 + return templ_7745c5c3_Err 234 + } 235 + } 236 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</div><div class=\"text-text/80 mb-1\">") 237 + if templ_7745c5c3_Err != nil { 238 + return templ_7745c5c3_Err 239 + } 240 + var templ_7745c5c3_Var16 string 241 + templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(rhcc.Description) 242 + if templ_7745c5c3_Err != nil { 243 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo.templ`, Line: 34, Col: 50} 244 + } 245 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16)) 246 + if templ_7745c5c3_Err != nil { 247 + return templ_7745c5c3_Err 248 + } 249 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "</div>") 250 + if templ_7745c5c3_Err != nil { 251 + return templ_7745c5c3_Err 252 + } 253 + return nil 254 + }) 255 + } 256 + 257 + var _ = templruntime.GeneratedTemplate
-61
internal/html/repo_tree.go
··· 1 - package html 2 - 3 - import ( 4 - "fmt" 5 - 6 - "go.jolheiser.com/ugit/internal/git" 7 - . "maragu.dev/gomponents" 8 - . "maragu.dev/gomponents/html" 9 - ) 10 - 11 - type RepoTreeContext struct { 12 - BaseContext 13 - RepoHeaderComponentContext 14 - RepoBreadcrumbComponentContext 15 - RepoTreeComponentContext 16 - ReadmeComponentContext 17 - Description string 18 - } 19 - 20 - type RepoTreeComponentContext struct { 21 - Repo string 22 - Ref string 23 - Tree []git.FileInfo 24 - Back string 25 - } 26 - 27 - func slashDir(name string, isDir bool) string { 28 - if isDir { 29 - return name + "/" 30 - } 31 - return name 32 - } 33 - 34 - func repoTreeComponent(rtcc RepoTreeComponentContext) Node { 35 - return Div(Class("grid grid-cols-3 sm:grid-cols-8 text-text py-5 rounded px-5 gap-x-3 gap-y-1 bg-base dark:bg-base/50"), 36 - If(rtcc.Back != "", Group([]Node{ 37 - Div(Class("col-span-2")), 38 - Div(Class("sm:col-span-6"), 39 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, rtcc.Back)), Text("..")), 40 - ), 41 - })), 42 - Map(rtcc.Tree, func(fi git.FileInfo) Node { 43 - return Group([]Node{ 44 - Div(Class("sm:col-span-1 break-keep"), Text(fi.Mode)), 45 - Div(Class("sm:col-span-1 text-right"), Text(fi.Size)), 46 - Div(Class("sm:col-span-6 overflow-hidden text-ellipsis"), 47 - A(Class("underline decoration-text/50 decoration-dashed hover:decoration-solid"), Href(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, fi.Path)), Text(slashDir(fi.Name(), fi.IsDir))), 48 - ), 49 - }) 50 - }), 51 - ) 52 - } 53 - 54 - func RepoTreeTemplate(rtc RepoTreeContext) Node { 55 - return base(rtc.BaseContext, []Node{ 56 - repoHeaderComponent(rtc.RepoHeaderComponentContext), 57 - repoBreadcrumbComponent(rtc.RepoBreadcrumbComponentContext), 58 - repoTreeComponent(rtc.RepoTreeComponentContext), 59 - readmeComponent(rtc.ReadmeComponentContext), 60 - }...) 61 - }
+51
internal/html/repo_tree.templ
··· 1 + package html 2 + 3 + import ( 4 + "fmt" 5 + "go.jolheiser.com/ugit/internal/git" 6 + ) 7 + 8 + type RepoTreeContext struct { 9 + BaseContext 10 + RepoHeaderComponentContext 11 + RepoBreadcrumbComponentContext 12 + RepoTreeComponentContext 13 + ReadmeComponentContext 14 + } 15 + 16 + templ RepoTree(rtc RepoTreeContext) { 17 + @base(rtc.BaseContext) { 18 + @repoHeaderComponent(rtc.RepoHeaderComponentContext) 19 + @repoBreadcrumbComponent(rtc.RepoBreadcrumbComponentContext) 20 + @repoTreeComponent(rtc.RepoTreeComponentContext) 21 + @readmeComponent(rtc.ReadmeComponentContext) 22 + } 23 + } 24 + 25 + type RepoTreeComponentContext struct { 26 + Repo string 27 + Ref string 28 + Tree []git.FileInfo 29 + Back string 30 + } 31 + 32 + func slashDir(name string, isDir bool) string { 33 + if isDir { 34 + return name + "/" 35 + } 36 + return name 37 + } 38 + 39 + templ repoTreeComponent(rtcc RepoTreeComponentContext) { 40 + <div class="grid grid-cols-3 sm:grid-cols-8 text-text py-5 rounded px-5 gap-x-3 gap-y-1 bg-base dark:bg-base/50"> 41 + if rtcc.Back != "" { 42 + <div class="col-span-2"></div> 43 + <div class="sm:col-span-6"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, rtcc.Back)) }>..</a></div> 44 + } 45 + for _, fi := range rtcc.Tree { 46 + <div class="sm:col-span-1 break-keep">{ fi.Mode }</div> 47 + <div class="sm:col-span-1 text-right">{ fi.Size }</div> 48 + <div class="sm:col-span-6 overflow-hidden text-ellipsis"><a class="underline decoration-text/50 decoration-dashed hover:decoration-solid" href={ templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, fi.Path)) }>{ slashDir(fi.Name(), fi.IsDir) }</a></div> 49 + } 50 + </div> 51 + }
+219
internal/html/repo_tree_templ.go
··· 1 + // Code generated by templ - DO NOT EDIT. 2 + 3 + // templ: version: v0.3.924 4 + package html 5 + 6 + //lint:file-ignore SA4006 This context is only used if a nested component is present. 7 + 8 + import "github.com/a-h/templ" 9 + import templruntime "github.com/a-h/templ/runtime" 10 + 11 + import ( 12 + "fmt" 13 + "go.jolheiser.com/ugit/internal/git" 14 + ) 15 + 16 + type RepoTreeContext struct { 17 + BaseContext 18 + RepoHeaderComponentContext 19 + RepoBreadcrumbComponentContext 20 + RepoTreeComponentContext 21 + ReadmeComponentContext 22 + } 23 + 24 + func RepoTree(rtc RepoTreeContext) templ.Component { 25 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 26 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 27 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 28 + return templ_7745c5c3_CtxErr 29 + } 30 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 31 + if !templ_7745c5c3_IsBuffer { 32 + defer func() { 33 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 34 + if templ_7745c5c3_Err == nil { 35 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 36 + } 37 + }() 38 + } 39 + ctx = templ.InitializeContext(ctx) 40 + templ_7745c5c3_Var1 := templ.GetChildren(ctx) 41 + if templ_7745c5c3_Var1 == nil { 42 + templ_7745c5c3_Var1 = templ.NopComponent 43 + } 44 + ctx = templ.ClearChildren(ctx) 45 + templ_7745c5c3_Var2 := templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 46 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 47 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 48 + if !templ_7745c5c3_IsBuffer { 49 + defer func() { 50 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 51 + if templ_7745c5c3_Err == nil { 52 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 53 + } 54 + }() 55 + } 56 + ctx = templ.InitializeContext(ctx) 57 + templ_7745c5c3_Err = repoHeaderComponent(rtc.RepoHeaderComponentContext).Render(ctx, templ_7745c5c3_Buffer) 58 + if templ_7745c5c3_Err != nil { 59 + return templ_7745c5c3_Err 60 + } 61 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, " ") 62 + if templ_7745c5c3_Err != nil { 63 + return templ_7745c5c3_Err 64 + } 65 + templ_7745c5c3_Err = repoBreadcrumbComponent(rtc.RepoBreadcrumbComponentContext).Render(ctx, templ_7745c5c3_Buffer) 66 + if templ_7745c5c3_Err != nil { 67 + return templ_7745c5c3_Err 68 + } 69 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, " ") 70 + if templ_7745c5c3_Err != nil { 71 + return templ_7745c5c3_Err 72 + } 73 + templ_7745c5c3_Err = repoTreeComponent(rtc.RepoTreeComponentContext).Render(ctx, templ_7745c5c3_Buffer) 74 + if templ_7745c5c3_Err != nil { 75 + return templ_7745c5c3_Err 76 + } 77 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, " ") 78 + if templ_7745c5c3_Err != nil { 79 + return templ_7745c5c3_Err 80 + } 81 + templ_7745c5c3_Err = readmeComponent(rtc.ReadmeComponentContext).Render(ctx, templ_7745c5c3_Buffer) 82 + if templ_7745c5c3_Err != nil { 83 + return templ_7745c5c3_Err 84 + } 85 + return nil 86 + }) 87 + templ_7745c5c3_Err = base(rtc.BaseContext).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer) 88 + if templ_7745c5c3_Err != nil { 89 + return templ_7745c5c3_Err 90 + } 91 + return nil 92 + }) 93 + } 94 + 95 + type RepoTreeComponentContext struct { 96 + Repo string 97 + Ref string 98 + Tree []git.FileInfo 99 + Back string 100 + } 101 + 102 + func slashDir(name string, isDir bool) string { 103 + if isDir { 104 + return name + "/" 105 + } 106 + return name 107 + } 108 + 109 + func repoTreeComponent(rtcc RepoTreeComponentContext) templ.Component { 110 + return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) { 111 + templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context 112 + if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil { 113 + return templ_7745c5c3_CtxErr 114 + } 115 + templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W) 116 + if !templ_7745c5c3_IsBuffer { 117 + defer func() { 118 + templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer) 119 + if templ_7745c5c3_Err == nil { 120 + templ_7745c5c3_Err = templ_7745c5c3_BufErr 121 + } 122 + }() 123 + } 124 + ctx = templ.InitializeContext(ctx) 125 + templ_7745c5c3_Var3 := templ.GetChildren(ctx) 126 + if templ_7745c5c3_Var3 == nil { 127 + templ_7745c5c3_Var3 = templ.NopComponent 128 + } 129 + ctx = templ.ClearChildren(ctx) 130 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "<div class=\"grid grid-cols-3 sm:grid-cols-8 text-text py-5 rounded px-5 gap-x-3 gap-y-1 bg-base dark:bg-base/50\">") 131 + if templ_7745c5c3_Err != nil { 132 + return templ_7745c5c3_Err 133 + } 134 + if rtcc.Back != "" { 135 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "<div class=\"col-span-2\"></div><div class=\"sm:col-span-6\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 136 + if templ_7745c5c3_Err != nil { 137 + return templ_7745c5c3_Err 138 + } 139 + var templ_7745c5c3_Var4 templ.SafeURL 140 + templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, rtcc.Back))) 141 + if templ_7745c5c3_Err != nil { 142 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 43, Col: 194} 143 + } 144 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4)) 145 + if templ_7745c5c3_Err != nil { 146 + return templ_7745c5c3_Err 147 + } 148 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "\">..</a></div>") 149 + if templ_7745c5c3_Err != nil { 150 + return templ_7745c5c3_Err 151 + } 152 + } 153 + for _, fi := range rtcc.Tree { 154 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "<div class=\"sm:col-span-1 break-keep\">") 155 + if templ_7745c5c3_Err != nil { 156 + return templ_7745c5c3_Err 157 + } 158 + var templ_7745c5c3_Var5 string 159 + templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Mode) 160 + if templ_7745c5c3_Err != nil { 161 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 46, Col: 50} 162 + } 163 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5)) 164 + if templ_7745c5c3_Err != nil { 165 + return templ_7745c5c3_Err 166 + } 167 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div><div class=\"sm:col-span-1 text-right\">") 168 + if templ_7745c5c3_Err != nil { 169 + return templ_7745c5c3_Err 170 + } 171 + var templ_7745c5c3_Var6 string 172 + templ_7745c5c3_Var6, templ_7745c5c3_Err = templ.JoinStringErrs(fi.Size) 173 + if templ_7745c5c3_Err != nil { 174 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 47, Col: 50} 175 + } 176 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var6)) 177 + if templ_7745c5c3_Err != nil { 178 + return templ_7745c5c3_Err 179 + } 180 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "</div><div class=\"sm:col-span-6 overflow-hidden text-ellipsis\"><a class=\"underline decoration-text/50 decoration-dashed hover:decoration-solid\" href=\"") 181 + if templ_7745c5c3_Err != nil { 182 + return templ_7745c5c3_Err 183 + } 184 + var templ_7745c5c3_Var7 templ.SafeURL 185 + templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinURLErrs(templ.SafeURL(fmt.Sprintf("/%s/tree/%s/%s", rtcc.Repo, rtcc.Ref, fi.Path))) 186 + if templ_7745c5c3_Err != nil { 187 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 48, Col: 222} 188 + } 189 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7)) 190 + if templ_7745c5c3_Err != nil { 191 + return templ_7745c5c3_Err 192 + } 193 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "\">") 194 + if templ_7745c5c3_Err != nil { 195 + return templ_7745c5c3_Err 196 + } 197 + var templ_7745c5c3_Var8 string 198 + templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(slashDir(fi.Name(), fi.IsDir)) 199 + if templ_7745c5c3_Err != nil { 200 + return templ.Error{Err: templ_7745c5c3_Err, FileName: `repo_tree.templ`, Line: 48, Col: 256} 201 + } 202 + _, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8)) 203 + if templ_7745c5c3_Err != nil { 204 + return templ_7745c5c3_Err 205 + } 206 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</a></div>") 207 + if templ_7745c5c3_Err != nil { 208 + return templ_7745c5c3_Err 209 + } 210 + } 211 + templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "</div>") 212 + if templ_7745c5c3_Err != nil { 213 + return templ_7745c5c3_Err 214 + } 215 + return nil 216 + }) 217 + } 218 + 219 + var _ = templruntime.GeneratedTemplate
+1 -1
internal/html/tailwind.go
··· 5 5 6 6 func TailwindHandler(w http.ResponseWriter, r *http.Request) { 7 7 w.Header().Set("Content-Type", "text/css") 8 - w.Write([]byte("/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:\"\"}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}.latte{--ctp-rosewater:220,138,120;--ctp-flamingo:221,120,120;--ctp-pink:234,118,203;--ctp-mauve:136,57,239;--ctp-red:210,15,57;--ctp-maroon:230,69,83;--ctp-peach:254,100,11;--ctp-yellow:223,142,29;--ctp-green:64,160,43;--ctp-teal:23,146,153;--ctp-sky:4,165,229;--ctp-sapphire:32,159,181;--ctp-blue:30,102,245;--ctp-lavender:114,135,253;--ctp-text:76,79,105;--ctp-subtext1:92,95,119;--ctp-subtext0:108,111,133;--ctp-overlay2:124,127,147;--ctp-overlay1:140,143,161;--ctp-overlay0:156,160,176;--ctp-surface2:172,176,190;--ctp-surface1:188,192,204;--ctp-surface0:204,208,218;--ctp-base:239,241,245;--ctp-mantle:230,233,239;--ctp-crust:220,224,232}.mocha{--ctp-rosewater:245,224,220;--ctp-flamingo:242,205,205;--ctp-pink:245,194,231;--ctp-mauve:203,166,247;--ctp-red:243,139,168;--ctp-maroon:235,160,172;--ctp-peach:250,179,135;--ctp-yellow:249,226,175;--ctp-green:166,227,161;--ctp-teal:148,226,213;--ctp-sky:137,220,235;--ctp-sapphire:116,199,236;--ctp-blue:137,180,250;--ctp-lavender:180,190,254;--ctp-text:205,214,244;--ctp-subtext1:186,194,222;--ctp-subtext0:166,173,200;--ctp-overlay2:147,153,178;--ctp-overlay1:127,132,156;--ctp-overlay0:108,112,134;--ctp-surface2:88,91,112;--ctp-surface1:69,71,90;--ctp-surface0:49,50,68;--ctp-base:30,30,46;--ctp-mantle:24,24,37;--ctp-crust:17,17,27}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.absolute{position:absolute}.relative{position:relative}.right-0{right:0}.top-0{top:0}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-7{grid-column:span 7/span 7}.col-span-8{grid-column:span 8/span 8}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.my-10{margin-top:2.5rem;margin-bottom:2.5rem}.mb-1{margin-bottom:.25rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-5{margin-left:1.25rem}.mr-1{margin-right:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.grid{display:grid}.h-5{height:1.25rem}.w-5{width:1.25rem}.max-w-7xl{max-width:80rem}.cursor-pointer{cursor:pointer}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-1{row-gap:.25rem}.overflow-hidden{overflow:hidden}.text-ellipsis{text-overflow:ellipsis}.whitespace-pre{white-space:pre}.break-keep{word-break:keep-all}.rounded{border-radius:.25rem}.border{border-width:1px}.border-solid{border-style:solid}.border-rosewater{--tw-border-opacity:1;border-color:rgba(var(--ctp-rosewater),var(--tw-border-opacity))}.bg-base{--tw-bg-opacity:1;background-color:rgba(var(--ctp-base),var(--tw-bg-opacity))}.bg-base\\/50{background-color:rgba(var(--ctp-base),.5)}.bg-mantle{--tw-bg-opacity:1;background-color:rgba(var(--ctp-mantle),var(--tw-bg-opacity))}.stroke-mauve{stroke:rgb(var(--ctp-mauve))}.p-1{padding:.25rem}.p-3{padding:.75rem}.p-5{padding:1.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-0{padding-bottom:0}.pb-0\\.5{padding-bottom:.125rem}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.text-blue{--tw-text-opacity:1;color:rgba(var(--ctp-blue),var(--tw-text-opacity))}.text-mauve{--tw-text-opacity:1;color:rgba(var(--ctp-mauve),var(--tw-text-opacity))}.text-subtext0{--tw-text-opacity:1;color:rgba(var(--ctp-subtext0),var(--tw-text-opacity))}.text-subtext1{--tw-text-opacity:1;color:rgba(var(--ctp-subtext1),var(--tw-text-opacity))}.text-text{--tw-text-opacity:1;color:rgba(var(--ctp-text),var(--tw-text-opacity))}.text-text\\/80{color:rgba(var(--ctp-text),.8)}.underline{text-decoration-line:underline}.decoration-blue\\/50{text-decoration-color:rgba(var(--ctp-blue),.5)}.decoration-mauve\\/50{text-decoration-color:rgba(var(--ctp-mauve),.5)}.decoration-text\\/50{text-decoration-color:rgba(var(--ctp-text),.5)}.decoration-dashed{text-decoration-style:dashed}.markdown *{all:revert-layer;color:rgb(var(--ctp-text))}.markdown code,.markdown pre{background-color:rgb(var(--ctp-base))}.markdown a{color:rgb(var(--ctp-blue));text-decoration-line:underline;text-decoration-style:dashed}.markdown a:hover{text-decoration-style:solid}.markdown .chroma{border-radius:.25rem;padding:.75rem}.chroma *{background-color:rgb(var(--ctp-base))!important}.chroma table{border-spacing:5px 0!important}.chroma .lnt{color:rgb(var(--ctp-subtext1))!important}.chroma .lnt:focus,.chroma .lnt:target{color:rgb(var(--ctp-subtext0))!important}.chroma .line.active,.chroma .line.active *{background:rgb(var(--ctp-surface0))!important}.code>.chroma{overflow:scroll;border-radius:.25rem;padding:.75rem;font-size:.875rem;line-height:1.25rem}.bg,.chroma{color:#4c4f69;background-color:#eff1f5}.chroma .lntd:last-child{width:100%}.chroma .ln:target,.chroma .lnt:target{color:#4c4f69;background-color:#bcc0cc}.chroma .err{color:#d20f39}.chroma .lnlinks{outline:none;text-decoration:none;color:inherit}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0}.chroma .hl{background-color:#bcc0cc}.chroma .ln,.chroma .lnt{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#8c8fa1}.chroma .line{display:flex}.chroma .k{color:#8839ef}.chroma .kc{color:#fe640b}.chroma .kd{color:#d20f39}.chroma .kn{color:#179299}.chroma .kp,.chroma .kr{color:#8839ef}.chroma .kt{color:#d20f39}.chroma .na{color:#1e66f5}.chroma .bp,.chroma .nb{color:#04a5e5}.chroma .nc,.chroma .no{color:#df8e1d}.chroma .nd{color:#1e66f5;font-weight:700}.chroma .ni{color:#179299}.chroma .ne{color:#fe640b}.chroma .fm,.chroma .nf{color:#1e66f5}.chroma .nl{color:#04a5e5}.chroma .nn,.chroma .py{color:#fe640b}.chroma .nt{color:#8839ef}.chroma .nv,.chroma .vc,.chroma .vg,.chroma .vi,.chroma .vm{color:#dc8a78}.chroma .s{color:#40a02b}.chroma .sa{color:#d20f39}.chroma .sb,.chroma .sc{color:#40a02b}.chroma .dl{color:#1e66f5}.chroma .sd{color:#9ca0b0}.chroma .s2{color:#40a02b}.chroma .se{color:#1e66f5}.chroma .sh{color:#9ca0b0}.chroma .si,.chroma .sx{color:#40a02b}.chroma .sr{color:#179299}.chroma .s1,.chroma .ss{color:#40a02b}.chroma .il,.chroma .m,.chroma .mb,.chroma .mf,.chroma .mh,.chroma .mi,.chroma .mo{color:#fe640b}.chroma .o,.chroma .ow{color:#04a5e5;font-weight:700}.chroma .c,.chroma .c1,.chroma .ch,.chroma .cm,.chroma .cp,.chroma .cpf,.chroma .cs{color:#9ca0b0;font-style:italic}.chroma .cpf{font-weight:700}.chroma .gd{color:#d20f39;background-color:#ccd0da}.chroma .ge{font-style:italic}.chroma .gr{color:#d20f39}.chroma .gh{color:#fe640b;font-weight:700}.chroma .gi{color:#40a02b;background-color:#ccd0da}.chroma .gs,.chroma .gu{font-weight:700}.chroma .gu{color:#fe640b}.chroma .gt{color:#d20f39}.chroma .gl{text-decoration:underline}@media (prefers-color-scheme:dark){.bg,.chroma{color:#cdd6f4;background-color:#1e1e2e}.chroma .lntd:last-child{width:100%}.chroma .ln:target,.chroma .lnt:target{color:#cdd6f4;background-color:#45475a}.chroma .err{color:#f38ba8}.chroma .lnlinks{outline:none;text-decoration:none;color:inherit}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0}.chroma .hl{background-color:#45475a}.chroma .ln,.chroma .lnt{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f849c}.chroma .line{display:flex}.chroma .k{color:#cba6f7}.chroma .kc{color:#fab387}.chroma .kd{color:#f38ba8}.chroma .kn{color:#94e2d5}.chroma .kp,.chroma .kr{color:#cba6f7}.chroma .kt{color:#f38ba8}.chroma .na{color:#89b4fa}.chroma .bp,.chroma .nb{color:#89dceb}.chroma .nc,.chroma .no{color:#f9e2af}.chroma .nd{color:#89b4fa;font-weight:700}.chroma .ni{color:#94e2d5}.chroma .ne{color:#fab387}.chroma .fm,.chroma .nf{color:#89b4fa}.chroma .nl{color:#89dceb}.chroma .nn,.chroma .py{color:#fab387}.chroma .nt{color:#cba6f7}.chroma .nv,.chroma .vc,.chroma .vg,.chroma .vi,.chroma .vm{color:#f5e0dc}.chroma .s{color:#a6e3a1}.chroma .sa{color:#f38ba8}.chroma .sb,.chroma .sc{color:#a6e3a1}.chroma .dl{color:#89b4fa}.chroma .sd{color:#6c7086}.chroma .s2{color:#a6e3a1}.chroma .se{color:#89b4fa}.chroma .sh{color:#6c7086}.chroma .si,.chroma .sx{color:#a6e3a1}.chroma .sr{color:#94e2d5}.chroma .s1,.chroma .ss{color:#a6e3a1}.chroma .il,.chroma .m,.chroma .mb,.chroma .mf,.chroma .mh,.chroma .mi,.chroma .mo{color:#fab387}.chroma .o,.chroma .ow{color:#89dceb;font-weight:700}.chroma .c,.chroma .c1,.chroma .ch,.chroma .cm,.chroma .cp,.chroma .cpf,.chroma .cs{color:#6c7086;font-style:italic}.chroma .cpf{font-weight:700}.chroma .gd{color:#f38ba8;background-color:#313244}.chroma .ge{font-style:italic}.chroma .gr{color:#f38ba8}.chroma .gh{color:#fab387;font-weight:700}.chroma .gi{color:#a6e3a1;background-color:#313244}.chroma .gs,.chroma .gu{font-weight:700}.chroma .gu{color:#fab387}.chroma .gt{color:#f38ba8}.chroma .gl{text-decoration:underline}.dark\\:mocha{--ctp-rosewater:245,224,220;--ctp-flamingo:242,205,205;--ctp-pink:245,194,231;--ctp-mauve:203,166,247;--ctp-red:243,139,168;--ctp-maroon:235,160,172;--ctp-peach:250,179,135;--ctp-yellow:249,226,175;--ctp-green:166,227,161;--ctp-teal:148,226,213;--ctp-sky:137,220,235;--ctp-sapphire:116,199,236;--ctp-blue:137,180,250;--ctp-lavender:180,190,254;--ctp-text:205,214,244;--ctp-subtext1:186,194,222;--ctp-subtext0:166,173,200;--ctp-overlay2:147,153,178;--ctp-overlay1:127,132,156;--ctp-overlay0:108,112,134;--ctp-surface2:88,91,112;--ctp-surface1:69,71,90;--ctp-surface0:49,50,68;--ctp-base:30,30,46;--ctp-mantle:24,24,37;--ctp-crust:17,17,27}}.hover\\:bg-surface0:hover{--tw-bg-opacity:1;background-color:rgba(var(--ctp-surface0),var(--tw-bg-opacity))}.hover\\:decoration-solid:hover{text-decoration-style:solid}.focus\\:border-lavender:focus{--tw-border-opacity:1;border-color:rgba(var(--ctp-lavender),var(--tw-border-opacity))}.focus\\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\\:ring-0:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}@media (prefers-color-scheme:dark){.dark\\:bg-base\\/50{background-color:rgba(var(--ctp-base),.5)}.dark\\:bg-base\\/95{background-color:rgba(var(--ctp-base),.95)}.dark\\:text-lavender{--tw-text-opacity:1;color:rgba(var(--ctp-lavender),var(--tw-text-opacity))}.dark\\:decoration-lavender\\/50{text-decoration-color:rgba(var(--ctp-lavender),.5)}}@media (min-width:640px){.sm\\:col-span-1{grid-column:span 1/span 1}.sm\\:col-span-2{grid-column:span 2/span 2}.sm\\:col-span-3{grid-column:span 3/span 3}.sm\\:col-span-5{grid-column:span 5/span 5}.sm\\:col-span-6{grid-column:span 6/span 6}.sm\\:col-span-7{grid-column:span 7/span 7}.sm\\:mx-auto{margin-left:auto;margin-right:auto}.sm\\:mb-0{margin-bottom:0}.sm\\:grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.sm\\:grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}}")) 8 + w.Write([]byte("/*! tailwindcss v3.3.3 | MIT License | https://tailwindcss.com*/*,:after,:before{box-sizing:border-box;border:0 solid #e5e7eb}:after,:before{--tw-content:\"\"}html{line-height:1.5;-webkit-text-size-adjust:100%;-moz-tab-size:4;-o-tab-size:4;tab-size:4;font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;font-feature-settings:normal;font-variation-settings:normal}body{margin:0;line-height:inherit}hr{height:0;color:inherit;border-top-width:1px}abbr:where([title]){-webkit-text-decoration:underline dotted;text-decoration:underline dotted}h1,h2,h3,h4,h5,h6{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}b,strong{font-weight:bolder}code,kbd,pre,samp{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace;font-size:1em}small{font-size:80%}sub,sup{font-size:75%;line-height:0;position:relative;vertical-align:initial}sub{bottom:-.25em}sup{top:-.5em}table{text-indent:0;border-color:inherit;border-collapse:collapse}button,input,optgroup,select,textarea{font-family:inherit;font-feature-settings:inherit;font-variation-settings:inherit;font-size:100%;font-weight:inherit;line-height:inherit;color:inherit;margin:0;padding:0}button,select{text-transform:none}[type=button],[type=reset],[type=submit],button{-webkit-appearance:button;background-color:initial;background-image:none}:-moz-focusring{outline:auto}:-moz-ui-invalid{box-shadow:none}progress{vertical-align:initial}::-webkit-inner-spin-button,::-webkit-outer-spin-button{height:auto}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}::-webkit-search-decoration{-webkit-appearance:none}::-webkit-file-upload-button{-webkit-appearance:button;font:inherit}summary{display:list-item}blockquote,dd,dl,figure,h1,h2,h3,h4,h5,h6,hr,p,pre{margin:0}fieldset{margin:0}fieldset,legend{padding:0}menu,ol,ul{list-style:none;margin:0;padding:0}dialog{padding:0}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{opacity:1;color:#9ca3af}input::placeholder,textarea::placeholder{opacity:1;color:#9ca3af}[role=button],button{cursor:pointer}:disabled{cursor:default}audio,canvas,embed,iframe,img,object,svg,video{display:block;vertical-align:middle}img,video{max-width:100%;height:auto}[hidden]{display:none}.latte{--ctp-rosewater:220,138,120;--ctp-flamingo:221,120,120;--ctp-pink:234,118,203;--ctp-mauve:136,57,239;--ctp-red:210,15,57;--ctp-maroon:230,69,83;--ctp-peach:254,100,11;--ctp-yellow:223,142,29;--ctp-green:64,160,43;--ctp-teal:23,146,153;--ctp-sky:4,165,229;--ctp-sapphire:32,159,181;--ctp-blue:30,102,245;--ctp-lavender:114,135,253;--ctp-text:76,79,105;--ctp-subtext1:92,95,119;--ctp-subtext0:108,111,133;--ctp-overlay2:124,127,147;--ctp-overlay1:140,143,161;--ctp-overlay0:156,160,176;--ctp-surface2:172,176,190;--ctp-surface1:188,192,204;--ctp-surface0:204,208,218;--ctp-base:239,241,245;--ctp-mantle:230,233,239;--ctp-crust:220,224,232}.mocha{--ctp-rosewater:245,224,220;--ctp-flamingo:242,205,205;--ctp-pink:245,194,231;--ctp-mauve:203,166,247;--ctp-red:243,139,168;--ctp-maroon:235,160,172;--ctp-peach:250,179,135;--ctp-yellow:249,226,175;--ctp-green:166,227,161;--ctp-teal:148,226,213;--ctp-sky:137,220,235;--ctp-sapphire:116,199,236;--ctp-blue:137,180,250;--ctp-lavender:180,190,254;--ctp-text:205,214,244;--ctp-subtext1:186,194,222;--ctp-subtext0:166,173,200;--ctp-overlay2:147,153,178;--ctp-overlay1:127,132,156;--ctp-overlay0:108,112,134;--ctp-surface2:88,91,112;--ctp-surface1:69,71,90;--ctp-surface0:49,50,68;--ctp-base:30,30,46;--ctp-mantle:24,24,37;--ctp-crust:17,17,27}*,::backdrop,:after,:before{--tw-border-spacing-x:0;--tw-border-spacing-y:0;--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;--tw-pan-x: ;--tw-pan-y: ;--tw-pinch-zoom: ;--tw-scroll-snap-strictness:proximity;--tw-gradient-from-position: ;--tw-gradient-via-position: ;--tw-gradient-to-position: ;--tw-ordinal: ;--tw-slashed-zero: ;--tw-numeric-figure: ;--tw-numeric-spacing: ;--tw-numeric-fraction: ;--tw-ring-inset: ;--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:#3b82f680;--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000;--tw-shadow:0 0 #0000;--tw-shadow-colored:0 0 #0000;--tw-blur: ;--tw-brightness: ;--tw-contrast: ;--tw-grayscale: ;--tw-hue-rotate: ;--tw-invert: ;--tw-saturate: ;--tw-sepia: ;--tw-drop-shadow: ;--tw-backdrop-blur: ;--tw-backdrop-brightness: ;--tw-backdrop-contrast: ;--tw-backdrop-grayscale: ;--tw-backdrop-hue-rotate: ;--tw-backdrop-invert: ;--tw-backdrop-opacity: ;--tw-backdrop-saturate: ;--tw-backdrop-sepia: }.absolute{position:absolute}.relative{position:relative}.right-0{right:0}.start-1{inset-inline-start:.25rem}.top-0{top:0}.col-span-1{grid-column:span 1/span 1}.col-span-2{grid-column:span 2/span 2}.col-span-7{grid-column:span 7/span 7}.col-span-8{grid-column:span 8/span 8}.mx-5{margin-left:1.25rem;margin-right:1.25rem}.my-10{margin-top:2.5rem;margin-bottom:2.5rem}.mb-1{margin-bottom:.25rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.ml-5{margin-left:1.25rem}.mr-1{margin-right:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-5{margin-top:1.25rem}.block{display:block}.inline-block{display:inline-block}.inline{display:inline}.grid{display:grid}.hidden{display:none}.h-5{height:1.25rem}.w-5{width:1.25rem}.max-w-7xl{max-width:80rem}.cursor-pointer{cursor:pointer}.select-all{-webkit-user-select:all;-moz-user-select:all;user-select:all}.grid-cols-1{grid-template-columns:repeat(1,minmax(0,1fr))}.grid-cols-3{grid-template-columns:repeat(3,minmax(0,1fr))}.grid-cols-4{grid-template-columns:repeat(4,minmax(0,1fr))}.grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}.gap-1{gap:.25rem}.gap-2{gap:.5rem}.gap-x-3{-moz-column-gap:.75rem;column-gap:.75rem}.gap-y-1{row-gap:.25rem}.overflow-hidden{overflow:hidden}.text-ellipsis{text-overflow:ellipsis}.whitespace-pre{white-space:pre}.break-keep{word-break:keep-all}.rounded{border-radius:.25rem}.border{border-width:1px}.border-solid{border-style:solid}.border-rosewater{--tw-border-opacity:1;border-color:rgba(var(--ctp-rosewater),var(--tw-border-opacity))}.bg-base{--tw-bg-opacity:1;background-color:rgba(var(--ctp-base),var(--tw-bg-opacity))}.bg-base\\/50{background-color:rgba(var(--ctp-base),.5)}.bg-mantle{--tw-bg-opacity:1;background-color:rgba(var(--ctp-mantle),var(--tw-bg-opacity))}.stroke-mauve{stroke:rgb(var(--ctp-mauve))}.p-1{padding:.25rem}.p-3{padding:.75rem}.p-5{padding:1.25rem}.px-1{padding-left:.25rem;padding-right:.25rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.py-5{padding-top:1.25rem;padding-bottom:1.25rem}.pb-0{padding-bottom:0}.pb-0\\.5{padding-bottom:.125rem}.text-right{text-align:right}.align-middle{vertical-align:middle}.text-lg{font-size:1.125rem;line-height:1.75rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-xl{font-size:1.25rem;line-height:1.75rem}.font-bold{font-weight:700}.text-blue{--tw-text-opacity:1;color:rgba(var(--ctp-blue),var(--tw-text-opacity))}.text-mauve{--tw-text-opacity:1;color:rgba(var(--ctp-mauve),var(--tw-text-opacity))}.text-subtext0{--tw-text-opacity:1;color:rgba(var(--ctp-subtext0),var(--tw-text-opacity))}.text-subtext1{--tw-text-opacity:1;color:rgba(var(--ctp-subtext1),var(--tw-text-opacity))}.text-text{--tw-text-opacity:1;color:rgba(var(--ctp-text),var(--tw-text-opacity))}.text-text\\/80{color:rgba(var(--ctp-text),.8)}.underline{text-decoration-line:underline}.decoration-blue\\/50{text-decoration-color:rgba(var(--ctp-blue),.5)}.decoration-mauve\\/50{text-decoration-color:rgba(var(--ctp-mauve),.5)}.decoration-text\\/50{text-decoration-color:rgba(var(--ctp-text),.5)}.decoration-dashed{text-decoration-style:dashed}.markdown *{all:revert-layer;color:rgb(var(--ctp-text))}.markdown code,.markdown pre{background-color:rgb(var(--ctp-base))}.markdown a{color:rgb(var(--ctp-blue));text-decoration-line:underline;text-decoration-style:dashed}.markdown a:hover{text-decoration-style:solid}.markdown .chroma{border-radius:.25rem;padding:.75rem}.chroma *{background-color:rgb(var(--ctp-base))!important}.chroma table{border-spacing:5px 0!important}.chroma .lnt{color:rgb(var(--ctp-subtext1))!important}.chroma .lnt:focus,.chroma .lnt:target{color:rgb(var(--ctp-subtext0))!important}.chroma .line.active,.chroma .line.active *{background:rgb(var(--ctp-surface0))!important}.code>.chroma{overflow:scroll;border-radius:.25rem;padding:.75rem;font-size:.875rem;line-height:1.25rem}.bg,.chroma{color:#4c4f69;background-color:#eff1f5}.chroma .lntd:last-child{width:100%}.chroma .ln:target,.chroma .lnt:target{color:#4c4f69;background-color:#bcc0cc}.chroma .err{color:#d20f39}.chroma .lnlinks{outline:none;text-decoration:none;color:inherit}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0}.chroma .hl{background-color:#bcc0cc}.chroma .ln,.chroma .lnt{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#8c8fa1}.chroma .line{display:flex}.chroma .k{color:#8839ef}.chroma .kc{color:#fe640b}.chroma .kd{color:#d20f39}.chroma .kn{color:#179299}.chroma .kp,.chroma .kr{color:#8839ef}.chroma .kt{color:#d20f39}.chroma .na{color:#1e66f5}.chroma .bp,.chroma .nb{color:#04a5e5}.chroma .nc,.chroma .no{color:#df8e1d}.chroma .nd{color:#1e66f5;font-weight:700}.chroma .ni{color:#179299}.chroma .ne{color:#fe640b}.chroma .fm,.chroma .nf{color:#1e66f5}.chroma .nl{color:#04a5e5}.chroma .nn,.chroma .py{color:#fe640b}.chroma .nt{color:#8839ef}.chroma .nv,.chroma .vc,.chroma .vg,.chroma .vi,.chroma .vm{color:#dc8a78}.chroma .s{color:#40a02b}.chroma .sa{color:#d20f39}.chroma .sb,.chroma .sc{color:#40a02b}.chroma .dl{color:#1e66f5}.chroma .sd{color:#9ca0b0}.chroma .s2{color:#40a02b}.chroma .se{color:#1e66f5}.chroma .sh{color:#9ca0b0}.chroma .si,.chroma .sx{color:#40a02b}.chroma .sr{color:#179299}.chroma .s1,.chroma .ss{color:#40a02b}.chroma .il,.chroma .m,.chroma .mb,.chroma .mf,.chroma .mh,.chroma .mi,.chroma .mo{color:#fe640b}.chroma .o,.chroma .ow{color:#04a5e5;font-weight:700}.chroma .c,.chroma .c1,.chroma .ch,.chroma .cm,.chroma .cp,.chroma .cpf,.chroma .cs{color:#9ca0b0;font-style:italic}.chroma .cpf{font-weight:700}.chroma .gd{color:#d20f39;background-color:#ccd0da}.chroma .ge{font-style:italic}.chroma .gr{color:#d20f39}.chroma .gh{color:#fe640b;font-weight:700}.chroma .gi{color:#40a02b;background-color:#ccd0da}.chroma .gs,.chroma .gu{font-weight:700}.chroma .gu{color:#fe640b}.chroma .gt{color:#d20f39}.chroma .gl{text-decoration:underline}@media (prefers-color-scheme:dark){.bg,.chroma{color:#cdd6f4;background-color:#1e1e2e}.chroma .lntd:last-child{width:100%}.chroma .ln:target,.chroma .lnt:target{color:#cdd6f4;background-color:#45475a}.chroma .err{color:#f38ba8}.chroma .lnlinks{outline:none;text-decoration:none;color:inherit}.chroma .lntd{vertical-align:top;padding:0;margin:0;border:0}.chroma .lntable{border-spacing:0;padding:0;margin:0;border:0}.chroma .hl{background-color:#45475a}.chroma .ln,.chroma .lnt{white-space:pre;-webkit-user-select:none;-moz-user-select:none;user-select:none;margin-right:.4em;padding:0 .4em;color:#7f849c}.chroma .line{display:flex}.chroma .k{color:#cba6f7}.chroma .kc{color:#fab387}.chroma .kd{color:#f38ba8}.chroma .kn{color:#94e2d5}.chroma .kp,.chroma .kr{color:#cba6f7}.chroma .kt{color:#f38ba8}.chroma .na{color:#89b4fa}.chroma .bp,.chroma .nb{color:#89dceb}.chroma .nc,.chroma .no{color:#f9e2af}.chroma .nd{color:#89b4fa;font-weight:700}.chroma .ni{color:#94e2d5}.chroma .ne{color:#fab387}.chroma .fm,.chroma .nf{color:#89b4fa}.chroma .nl{color:#89dceb}.chroma .nn,.chroma .py{color:#fab387}.chroma .nt{color:#cba6f7}.chroma .nv,.chroma .vc,.chroma .vg,.chroma .vi,.chroma .vm{color:#f5e0dc}.chroma .s{color:#a6e3a1}.chroma .sa{color:#f38ba8}.chroma .sb,.chroma .sc{color:#a6e3a1}.chroma .dl{color:#89b4fa}.chroma .sd{color:#6c7086}.chroma .s2{color:#a6e3a1}.chroma .se{color:#89b4fa}.chroma .sh{color:#6c7086}.chroma .si,.chroma .sx{color:#a6e3a1}.chroma .sr{color:#94e2d5}.chroma .s1,.chroma .ss{color:#a6e3a1}.chroma .il,.chroma .m,.chroma .mb,.chroma .mf,.chroma .mh,.chroma .mi,.chroma .mo{color:#fab387}.chroma .o,.chroma .ow{color:#89dceb;font-weight:700}.chroma .c,.chroma .c1,.chroma .ch,.chroma .cm,.chroma .cp,.chroma .cpf,.chroma .cs{color:#6c7086;font-style:italic}.chroma .cpf{font-weight:700}.chroma .gd{color:#f38ba8;background-color:#313244}.chroma .ge{font-style:italic}.chroma .gr{color:#f38ba8}.chroma .gh{color:#fab387;font-weight:700}.chroma .gi{color:#a6e3a1;background-color:#313244}.chroma .gs,.chroma .gu{font-weight:700}.chroma .gu{color:#fab387}.chroma .gt{color:#f38ba8}.chroma .gl{text-decoration:underline}.dark\\:mocha{--ctp-rosewater:245,224,220;--ctp-flamingo:242,205,205;--ctp-pink:245,194,231;--ctp-mauve:203,166,247;--ctp-red:243,139,168;--ctp-maroon:235,160,172;--ctp-peach:250,179,135;--ctp-yellow:249,226,175;--ctp-green:166,227,161;--ctp-teal:148,226,213;--ctp-sky:137,220,235;--ctp-sapphire:116,199,236;--ctp-blue:137,180,250;--ctp-lavender:180,190,254;--ctp-text:205,214,244;--ctp-subtext1:186,194,222;--ctp-subtext0:166,173,200;--ctp-overlay2:147,153,178;--ctp-overlay1:127,132,156;--ctp-overlay0:108,112,134;--ctp-surface2:88,91,112;--ctp-surface1:69,71,90;--ctp-surface0:49,50,68;--ctp-base:30,30,46;--ctp-mantle:24,24,37;--ctp-crust:17,17,27}}.hover\\:bg-surface0:hover{--tw-bg-opacity:1;background-color:rgba(var(--ctp-surface0),var(--tw-bg-opacity))}.hover\\:decoration-solid:hover{text-decoration-style:solid}.focus\\:border-lavender:focus{--tw-border-opacity:1;border-color:rgba(var(--ctp-lavender),var(--tw-border-opacity))}.focus\\:outline-none:focus{outline:2px solid #0000;outline-offset:2px}.focus\\:ring-0:focus{--tw-ring-offset-shadow:var(--tw-ring-inset) 0 0 0 var(--tw-ring-offset-width) var(--tw-ring-offset-color);--tw-ring-shadow:var(--tw-ring-inset) 0 0 0 calc(var(--tw-ring-offset-width)) var(--tw-ring-color);box-shadow:var(--tw-ring-offset-shadow),var(--tw-ring-shadow),var(--tw-shadow,0 0 #0000)}@media (prefers-color-scheme:dark){.dark\\:bg-base\\/50{background-color:rgba(var(--ctp-base),.5)}.dark\\:bg-base\\/95{background-color:rgba(var(--ctp-base),.95)}.dark\\:text-lavender{--tw-text-opacity:1;color:rgba(var(--ctp-lavender),var(--tw-text-opacity))}.dark\\:decoration-lavender\\/50{text-decoration-color:rgba(var(--ctp-lavender),.5)}}@media (min-width:640px){.sm\\:col-span-1{grid-column:span 1/span 1}.sm\\:col-span-2{grid-column:span 2/span 2}.sm\\:col-span-3{grid-column:span 3/span 3}.sm\\:col-span-5{grid-column:span 5/span 5}.sm\\:col-span-6{grid-column:span 6/span 6}.sm\\:col-span-7{grid-column:span 7/span 7}.sm\\:mx-auto{margin-left:auto;margin-right:auto}.sm\\:mb-0{margin-bottom:0}.sm\\:grid-cols-10{grid-template-columns:repeat(10,minmax(0,1fr))}.sm\\:grid-cols-8{grid-template-columns:repeat(8,minmax(0,1fr))}}")) 9 9 }
+7
internal/http/http.go
··· 116 116 } 117 117 } 118 118 119 + func (rh repoHandler) repoBaseContext(repo *git.Repo) html.BaseContext { 120 + return html.BaseContext{ 121 + Title: repo.Name(), 122 + Description: repo.Meta.Description, 123 + } 124 + } 125 + 119 126 func (rh repoHandler) repoHeaderContext(repo *git.Repo, r *http.Request) html.RepoHeaderComponentContext { 120 127 ref := chi.URLParam(r, "ref") 121 128 if ref == "" {
+2 -2
internal/http/index.go
··· 60 60 }) 61 61 } 62 62 63 - if err := html.IndexTemplate(html.IndexContext{ 63 + if err := html.Index(html.IndexContext{ 64 64 BaseContext: rh.baseContext(), 65 65 Profile: html.IndexProfile{ 66 66 Username: rh.s.Profile.Username, ··· 68 68 Links: links, 69 69 }, 70 70 Repos: repos, 71 - }).Render(w); err != nil { 71 + }).Render(r.Context(), w); err != nil { 72 72 return httperr.Error(err) 73 73 } 74 74
+18 -19
internal/http/repo.go
··· 47 47 if path != "" { 48 48 back = filepath.Dir(path) 49 49 } 50 - if err := html.RepoTreeTemplate(html.RepoTreeContext{ 51 - Description: repo.Meta.Description, 52 - BaseContext: rh.baseContext(), 50 + if err := html.RepoTree(html.RepoTreeContext{ 51 + BaseContext: rh.repoBaseContext(repo), 53 52 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 54 53 RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path), 55 54 RepoTreeComponentContext: html.RepoTreeComponentContext{ ··· 61 60 ReadmeComponentContext: html.ReadmeComponentContext{ 62 61 Markdown: readmeContent, 63 62 }, 64 - }).Render(w); err != nil { 63 + }).Render(r.Context(), w); err != nil { 65 64 return httperr.Error(err) 66 65 } 67 66 ··· 100 99 } 101 100 } 102 101 103 - if err := html.RepoFileTemplate(html.RepoFileContext{ 104 - BaseContext: rh.baseContext(), 102 + if err := html.RepoFile(html.RepoFileContext{ 103 + BaseContext: rh.repoBaseContext(repo), 105 104 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 106 105 RepoBreadcrumbComponentContext: rh.repoBreadcrumbContext(repo, r, path), 107 106 Code: buf.String(), 108 107 Commit: commit, 109 108 Path: path, 110 - }).Render(w); err != nil { 109 + }).Render(r.Context(), w); err != nil { 111 110 return httperr.Error(err) 112 111 } 113 112 ··· 127 126 return httperr.Error(err) 128 127 } 129 128 130 - if err := html.RepoRefsTemplate(html.RepoRefsContext{ 131 - BaseContext: rh.baseContext(), 129 + if err := html.RepoRefs(html.RepoRefsContext{ 130 + BaseContext: rh.repoBaseContext(repo), 132 131 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 133 132 Branches: branches, 134 133 Tags: tags, 135 - }).Render(w); err != nil { 134 + }).Render(r.Context(), w); err != nil { 136 135 return httperr.Error(err) 137 136 } 138 137 ··· 147 146 return httperr.Error(err) 148 147 } 149 148 150 - if err := html.RepoLogTemplate(html.RepoLogContext{ 151 - BaseContext: rh.baseContext(), 149 + if err := html.RepoLog(html.RepoLogContext{ 150 + BaseContext: rh.repoBaseContext(repo), 152 151 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 153 152 Commits: commits, 154 - }).Render(w); err != nil { 153 + }).Render(r.Context(), w); err != nil { 155 154 return httperr.Error(err) 156 155 } 157 156 ··· 174 173 commit.Files[idx].Patch = patch.String() 175 174 } 176 175 177 - if err := html.RepoCommitTemplate(html.RepoCommitContext{ 178 - BaseContext: rh.baseContext(), 176 + if err := html.RepoCommit(html.RepoCommitContext{ 177 + BaseContext: rh.repoBaseContext(repo), 179 178 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 180 179 Commit: commit, 181 - }).Render(w); err != nil { 180 + }).Render(r.Context(), w); err != nil { 182 181 return httperr.Error(err) 183 182 } 184 183 ··· 218 217 } 219 218 } 220 219 221 - if err := html.RepoSearchTemplate(html.SearchContext{ 222 - BaseContext: rh.baseContext(), 220 + if err := html.RepoSearch(html.SearchContext{ 221 + BaseContext: rh.repoBaseContext(repo), 223 222 RepoHeaderComponentContext: rh.repoHeaderContext(repo, r), 224 223 Results: results, 225 - }).Render(w); err != nil { 224 + }).Render(r.Context(), w); err != nil { 226 225 return httperr.Error(err) 227 226 } 228 227
+1 -1
internal/ssh/ssh.go
··· 48 48 49 49 type noopLogger struct{} 50 50 51 - func (n noopLogger) Printf(format string, v ...interface{}) {} 51 + func (n noopLogger) Printf(format string, v ...any) {}
+19 -26
internal/ssh/wish.go
··· 12 12 "text/tabwriter" 13 13 14 14 "go.jolheiser.com/ugit/internal/git" 15 - "go.jolheiser.com/ugit/internal/tui" 16 15 17 16 "github.com/charmbracelet/ssh" 18 17 "github.com/charmbracelet/wish" ··· 100 99 } 101 100 } 102 101 103 - // No args, start TUI 102 + // Repo list 104 103 if len(cmd) == 0 { 105 - if err := tui.Start(s, repoDir); err != nil { 106 - slog.Error("failed to start TUI", "error", err) 107 - 108 - // Fall back to simple list on TUI error 109 - des, err := os.ReadDir(repoDir) 110 - if err != nil && err != fs.ErrNotExist { 111 - slog.Error("invalid repository", "error", err) 104 + des, err := os.ReadDir(repoDir) 105 + if err != nil && err != fs.ErrNotExist { 106 + slog.Error("invalid repository", "error", err) 107 + } 108 + tw := tabwriter.NewWriter(s, 0, 0, 1, ' ', 0) 109 + for _, de := range des { 110 + if filepath.Ext(de.Name()) != ".git" { 111 + continue 112 112 } 113 - tw := tabwriter.NewWriter(s, 0, 0, 1, ' ', 0) 114 - for _, de := range des { 115 - if filepath.Ext(de.Name()) != ".git" { 116 - continue 117 - } 118 - repo, err := git.NewRepo(repoDir, de.Name()) 119 - visibility := "โ“" 120 - if err == nil { 121 - visibility = "๐Ÿ”“" 122 - if repo.Meta.Private { 123 - visibility = "๐Ÿ”’" 124 - } 113 + repo, err := git.NewRepo(repoDir, de.Name()) 114 + visibility := "โ“" 115 + if err == nil { 116 + visibility = "๐Ÿ”“" 117 + if repo.Meta.Private { 118 + visibility = "๐Ÿ”’" 125 119 } 126 - fmt.Fprintf(tw, "%[1]s\t%[3]s\t%[2]s/%[1]s.git\n", strings.TrimSuffix(de.Name(), ".git"), cloneURL, visibility) 127 120 } 128 - tw.Flush() 121 + fmt.Fprintf(tw, "%[1]s\t%[3]s\t%[2]s/%[1]s.git\n", strings.TrimSuffix(de.Name(), ".git"), cloneURL, visibility) 129 122 } 130 - return 123 + tw.Flush() 131 124 } 132 125 sh(s) 133 126 } ··· 175 168 } 176 169 177 170 // Fatal prints to the session's STDOUT as a git response and exit 1. 178 - func Fatal(s ssh.Session, v ...interface{}) { 171 + func Fatal(s ssh.Session, v ...any) { 179 172 msg := fmt.Sprint(v...) 180 173 // hex length includes 4 byte length prefix and ending newline 181 174 pktLine := fmt.Sprintf("%04x%s\n", len(msg)+5, msg) 182 175 _, _ = wish.WriteString(s, pktLine) 183 176 s.Exit(1) // nolint: errcheck 184 - } 177 + }
-230
internal/tui/form.go
··· 1 - package tui 2 - 3 - import ( 4 - "fmt" 5 - "strings" 6 - 7 - "github.com/charmbracelet/bubbles/textinput" 8 - tea "github.com/charmbracelet/bubbletea" 9 - "github.com/charmbracelet/lipgloss" 10 - "go.jolheiser.com/ugit/internal/git" 11 - ) 12 - 13 - type repoForm struct { 14 - inputs []textinput.Model 15 - isPrivate bool 16 - focusIndex int 17 - width int 18 - height int 19 - done bool 20 - save bool 21 - selectedRepo *git.Repo 22 - } 23 - 24 - // newRepoForm creates a new repository editing form 25 - func newRepoForm() repoForm { 26 - var inputs []textinput.Model 27 - 28 - nameInput := textinput.New() 29 - nameInput.Placeholder = "Repository name" 30 - nameInput.Focus() 31 - nameInput.Width = 50 32 - inputs = append(inputs, nameInput) 33 - 34 - descInput := textinput.New() 35 - descInput.Placeholder = "Repository description" 36 - descInput.Width = 50 37 - inputs = append(inputs, descInput) 38 - 39 - tagsInput := textinput.New() 40 - tagsInput.Placeholder = "Tags (comma separated)" 41 - tagsInput.Width = 50 42 - inputs = append(inputs, tagsInput) 43 - 44 - return repoForm{ 45 - inputs: inputs, 46 - focusIndex: 0, 47 - } 48 - } 49 - 50 - // setValues sets the form values from the selected repo 51 - func (f *repoForm) setValues(repo *git.Repo) { 52 - f.inputs[0].SetValue(repo.Name()) 53 - f.inputs[1].SetValue(repo.Meta.Description) 54 - f.inputs[2].SetValue(strings.Join(repo.Meta.Tags.Slice(), ", ")) 55 - f.isPrivate = repo.Meta.Private 56 - 57 - f.inputs[0].Focus() 58 - f.focusIndex = 0 59 - } 60 - 61 - // setSize sets the form dimensions 62 - func (f *repoForm) setSize(width, height int) { 63 - f.width = width 64 - f.height = height 65 - 66 - for i := range f.inputs { 67 - f.inputs[i].Width = width - 10 68 - } 69 - } 70 - 71 - // isPrivateToggleFocused returns true if the private toggle is focused 72 - func (f *repoForm) isPrivateToggleFocused() bool { 73 - return f.focusIndex == len(f.inputs) 74 - } 75 - 76 - // isSaveButtonFocused returns true if the save button is focused 77 - func (f *repoForm) isSaveButtonFocused() bool { 78 - return f.focusIndex == len(f.inputs)+1 79 - } 80 - 81 - // isCancelButtonFocused returns true if the cancel button is focused 82 - func (f *repoForm) isCancelButtonFocused() bool { 83 - return f.focusIndex == len(f.inputs)+2 84 - } 85 - 86 - // Update handles form updates 87 - func (f repoForm) Update(msg tea.Msg) (repoForm, tea.Cmd) { 88 - var cmds []tea.Cmd 89 - 90 - switch msg := msg.(type) { 91 - case tea.KeyMsg: 92 - switch msg.String() { 93 - case "tab", "shift+tab", "up", "down": 94 - if msg.String() == "up" || msg.String() == "shift+tab" { 95 - f.focusIndex-- 96 - if f.focusIndex < 0 { 97 - f.focusIndex = len(f.inputs) + 3 - 1 98 - } 99 - } else { 100 - f.focusIndex++ 101 - if f.focusIndex >= len(f.inputs)+3 { 102 - f.focusIndex = 0 103 - } 104 - } 105 - 106 - for i := range f.inputs { 107 - if i == f.focusIndex { 108 - cmds = append(cmds, f.inputs[i].Focus()) 109 - } else { 110 - f.inputs[i].Blur() 111 - } 112 - } 113 - 114 - case "enter": 115 - if f.isSaveButtonFocused() { 116 - f.done = true 117 - f.save = true 118 - return f, nil 119 - } 120 - 121 - if f.isCancelButtonFocused() { 122 - f.done = true 123 - f.save = false 124 - return f, nil 125 - } 126 - 127 - case "esc": 128 - f.done = true 129 - f.save = false 130 - return f, nil 131 - 132 - case " ": 133 - if f.isPrivateToggleFocused() { 134 - f.isPrivate = !f.isPrivate 135 - } 136 - 137 - if f.isSaveButtonFocused() { 138 - f.done = true 139 - f.save = true 140 - return f, nil 141 - } 142 - 143 - if f.isCancelButtonFocused() { 144 - f.done = true 145 - f.save = false 146 - return f, nil 147 - } 148 - } 149 - } 150 - 151 - for i := range f.inputs { 152 - if i == f.focusIndex { 153 - var cmd tea.Cmd 154 - f.inputs[i], cmd = f.inputs[i].Update(msg) 155 - cmds = append(cmds, cmd) 156 - } 157 - } 158 - 159 - return f, tea.Batch(cmds...) 160 - } 161 - 162 - // View renders the form 163 - func (f repoForm) View() string { 164 - var b strings.Builder 165 - 166 - formStyle := lipgloss.NewStyle(). 167 - BorderStyle(lipgloss.RoundedBorder()). 168 - BorderForeground(lipgloss.Color("170")). 169 - Padding(1, 2) 170 - 171 - titleStyle := lipgloss.NewStyle(). 172 - Bold(true). 173 - Foreground(lipgloss.Color("170")). 174 - MarginBottom(1) 175 - 176 - b.WriteString(titleStyle.Render("Edit Repository")) 177 - b.WriteString("\n\n") 178 - 179 - b.WriteString("Repository Name:\n") 180 - b.WriteString(f.inputs[0].View()) 181 - b.WriteString("\n\n") 182 - 183 - b.WriteString("Description:\n") 184 - b.WriteString(f.inputs[1].View()) 185 - b.WriteString("\n\n") 186 - 187 - b.WriteString("Tags (comma separated):\n") 188 - b.WriteString(f.inputs[2].View()) 189 - b.WriteString("\n\n") 190 - 191 - toggleStyle := lipgloss.NewStyle() 192 - if f.isPrivateToggleFocused() { 193 - toggleStyle = toggleStyle.Foreground(lipgloss.Color("170")).Bold(true) 194 - } 195 - 196 - visibility := "Public ๐Ÿ”“" 197 - if f.isPrivate { 198 - visibility = "Private ๐Ÿ”’" 199 - } 200 - 201 - b.WriteString(toggleStyle.Render(fmt.Sprintf("[%s] %s", visibility, "Toggle with Space"))) 202 - b.WriteString("\n\n") 203 - 204 - buttonStyle := lipgloss.NewStyle(). 205 - Padding(0, 3). 206 - MarginRight(1) 207 - 208 - focusedButtonStyle := buttonStyle.Copy(). 209 - Foreground(lipgloss.Color("0")). 210 - Background(lipgloss.Color("170")). 211 - Bold(true) 212 - 213 - saveButton := buttonStyle.Render("[ Save ]") 214 - cancelButton := buttonStyle.Render("[ Cancel ]") 215 - 216 - if f.isSaveButtonFocused() { 217 - saveButton = focusedButtonStyle.Render("[ Save ]") 218 - } 219 - 220 - if f.isCancelButtonFocused() { 221 - cancelButton = focusedButtonStyle.Render("[ Cancel ]") 222 - } 223 - 224 - b.WriteString(saveButton + cancelButton) 225 - b.WriteString("\n\n") 226 - 227 - b.WriteString("\nTab: Next โ€ข Shift+Tab: Previous โ€ข Enter: Select โ€ข Esc: Cancel") 228 - 229 - return formStyle.Width(f.width - 4).Render(b.String()) 230 - }
-65
internal/tui/keymap.go
··· 1 - package tui 2 - 3 - import ( 4 - "github.com/charmbracelet/bubbles/key" 5 - ) 6 - 7 - // keyMap defines the keybindings for the TUI 8 - type keyMap struct { 9 - Up key.Binding 10 - Down key.Binding 11 - Edit key.Binding 12 - Delete key.Binding 13 - Help key.Binding 14 - Quit key.Binding 15 - Confirm key.Binding 16 - Cancel key.Binding 17 - } 18 - 19 - // ShortHelp returns keybindings to be shown in the mini help view. 20 - func (k keyMap) ShortHelp() []key.Binding { 21 - return []key.Binding{k.Help, k.Edit, k.Delete, k.Quit} 22 - } 23 - 24 - // FullHelp returns keybindings for the expanded help view. 25 - func (k keyMap) FullHelp() [][]key.Binding { 26 - return [][]key.Binding{ 27 - {k.Up, k.Down, k.Edit}, 28 - {k.Delete, k.Help, k.Quit}, 29 - } 30 - } 31 - 32 - var keys = keyMap{ 33 - Up: key.NewBinding( 34 - key.WithKeys("up", "k"), 35 - key.WithHelp("โ†‘/k", "up"), 36 - ), 37 - Down: key.NewBinding( 38 - key.WithKeys("down", "j"), 39 - key.WithHelp("โ†“/j", "down"), 40 - ), 41 - Edit: key.NewBinding( 42 - key.WithKeys("e"), 43 - key.WithHelp("e", "edit"), 44 - ), 45 - Delete: key.NewBinding( 46 - key.WithKeys("d"), 47 - key.WithHelp("d", "delete"), 48 - ), 49 - Help: key.NewBinding( 50 - key.WithKeys("?"), 51 - key.WithHelp("?", "help"), 52 - ), 53 - Quit: key.NewBinding( 54 - key.WithKeys("q", "ctrl+c"), 55 - key.WithHelp("q", "quit"), 56 - ), 57 - Confirm: key.NewBinding( 58 - key.WithKeys("y"), 59 - key.WithHelp("y", "confirm"), 60 - ), 61 - Cancel: key.NewBinding( 62 - key.WithKeys("n", "esc"), 63 - key.WithHelp("n", "cancel"), 64 - ), 65 - }
-50
internal/tui/main.go
··· 1 - package tui 2 - 3 - import ( 4 - "fmt" 5 - 6 - "github.com/charmbracelet/bubbles/help" 7 - "github.com/charmbracelet/bubbles/list" 8 - tea "github.com/charmbracelet/bubbletea" 9 - "github.com/charmbracelet/lipgloss" 10 - ) 11 - 12 - // Run runs the TUI standalone, useful for development or local usage 13 - func Run(repoDir string) error { 14 - model := Model{ 15 - repoDir: repoDir, 16 - help: help.New(), 17 - keys: keys, 18 - activeView: ViewList, 19 - repoForm: newRepoForm(), 20 - } 21 - 22 - repos, err := loadRepos(repoDir) 23 - if err != nil { 24 - return fmt.Errorf("failed to load repos: %w", err) 25 - } 26 - model.repos = repos 27 - 28 - items := make([]list.Item, len(repos)) 29 - for i, repo := range repos { 30 - items[i] = repoItem{repo: repo} 31 - } 32 - 33 - delegate := list.NewDefaultDelegate() 34 - delegate.Styles.SelectedTitle = delegate.Styles.SelectedTitle.Foreground(lipgloss.Color("170")) 35 - delegate.Styles.SelectedDesc = delegate.Styles.SelectedDesc.Foreground(lipgloss.Color("244")) 36 - 37 - repoList := list.New(items, delegate, 0, 0) 38 - repoList.Title = "Git Repositories" 39 - repoList.SetShowStatusBar(true) 40 - repoList.SetFilteringEnabled(true) 41 - repoList.Styles.Title = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("170")).Padding(0, 0, 0, 2) 42 - repoList.StatusMessageLifetime = 3 43 - 44 - model.repoList = repoList 45 - 46 - p := tea.NewProgram(model, tea.WithAltScreen(), tea.WithMouseCellMotion()) 47 - 48 - _, err = p.Run() 49 - return err 50 - }
-72
internal/tui/repo_item.go
··· 1 - package tui 2 - 3 - import ( 4 - "strings" 5 - 6 - "go.jolheiser.com/ugit/internal/git" 7 - ) 8 - 9 - // repoItem represents a repository item in the list 10 - type repoItem struct { 11 - repo *git.Repo 12 - } 13 - 14 - // Title returns the title for the list item 15 - func (r repoItem) Title() string { 16 - return r.repo.Name() 17 - } 18 - 19 - // Description returns the description for the list item 20 - func (r repoItem) Description() string { 21 - var builder strings.Builder 22 - 23 - if r.repo.Meta.Private { 24 - builder.WriteString("๐Ÿ”’") 25 - } else { 26 - builder.WriteString("๐Ÿ”“") 27 - } 28 - 29 - builder.WriteString(" โ€ข ") 30 - 31 - if r.repo.Meta.Description != "" { 32 - builder.WriteString(r.repo.Meta.Description) 33 - } else { 34 - builder.WriteString("No description") 35 - } 36 - 37 - builder.WriteString(" โ€ข ") 38 - 39 - builder.WriteString("[") 40 - if len(r.repo.Meta.Tags) > 0 { 41 - builder.WriteString(strings.Join(r.repo.Meta.Tags.Slice(), ", ")) 42 - } 43 - builder.WriteString("]") 44 - 45 - builder.WriteString(" โ€ข ") 46 - 47 - lastCommit, err := r.repo.LastCommit() 48 - if err == nil { 49 - builder.WriteString(lastCommit.Short()) 50 - } else { 51 - builder.WriteString("deadbeef") 52 - } 53 - 54 - return builder.String() 55 - } 56 - 57 - // FilterValue returns the value to use for filtering 58 - func (r repoItem) FilterValue() string { 59 - var builder strings.Builder 60 - builder.WriteString(r.repo.Name()) 61 - builder.WriteString(" ") 62 - builder.WriteString(r.repo.Meta.Description) 63 - 64 - if len(r.repo.Meta.Tags) > 0 { 65 - for _, tag := range r.repo.Meta.Tags.Slice() { 66 - builder.WriteString(" ") 67 - builder.WriteString(tag) 68 - } 69 - } 70 - 71 - return strings.ToLower(builder.String()) 72 - }
-321
internal/tui/tui.go
··· 1 - package tui 2 - 3 - import ( 4 - "fmt" 5 - "log/slog" 6 - "path/filepath" 7 - "strings" 8 - 9 - "github.com/charmbracelet/bubbles/help" 10 - "github.com/charmbracelet/bubbles/key" 11 - "github.com/charmbracelet/bubbles/list" 12 - "github.com/charmbracelet/bubbles/textinput" 13 - tea "github.com/charmbracelet/bubbletea" 14 - "github.com/charmbracelet/lipgloss" 15 - "github.com/charmbracelet/ssh" 16 - "go.jolheiser.com/ugit/internal/git" 17 - ) 18 - 19 - // Model is the main TUI model 20 - type Model struct { 21 - repoList list.Model 22 - repos []*git.Repo 23 - repoDir string 24 - width int 25 - height int 26 - help help.Model 27 - keys keyMap 28 - activeView View 29 - repoForm repoForm 30 - session ssh.Session 31 - } 32 - 33 - // View represents the current active view in the TUI 34 - type View int 35 - 36 - const ( 37 - ViewList View = iota 38 - ViewForm 39 - ViewConfirmDelete 40 - ) 41 - 42 - // New creates a new TUI model 43 - func New(s ssh.Session, repoDir string) (*Model, error) { 44 - repos, err := loadRepos(repoDir) 45 - if err != nil { 46 - return nil, fmt.Errorf("failed to load repos: %w", err) 47 - } 48 - 49 - items := make([]list.Item, len(repos)) 50 - for i, repo := range repos { 51 - items[i] = repoItem{repo: repo} 52 - } 53 - 54 - delegate := list.NewDefaultDelegate() 55 - delegate.Styles.SelectedTitle = delegate.Styles.SelectedTitle.Foreground(lipgloss.Color("170")) 56 - delegate.Styles.SelectedDesc = delegate.Styles.SelectedDesc.Foreground(lipgloss.Color("244")) 57 - 58 - repoList := list.New(items, delegate, 0, 0) 59 - repoList.Title = "Git Repositories" 60 - repoList.SetShowStatusBar(true) 61 - repoList.SetFilteringEnabled(true) 62 - repoList.Styles.Title = lipgloss.NewStyle().Bold(true).Foreground(lipgloss.Color("170")).Padding(0, 0, 0, 2) 63 - repoList.StatusMessageLifetime = 3 64 - 65 - repoList.FilterInput.Placeholder = "Type to filter repositories..." 66 - repoList.FilterInput.PromptStyle = lipgloss.NewStyle().Foreground(lipgloss.Color("170")) 67 - repoList.FilterInput.TextStyle = lipgloss.NewStyle() 68 - 69 - help := help.New() 70 - 71 - repoForm := newRepoForm() 72 - 73 - return &Model{ 74 - repoList: repoList, 75 - repos: repos, 76 - repoDir: repoDir, 77 - help: help, 78 - keys: keys, 79 - activeView: ViewList, 80 - repoForm: repoForm, 81 - session: s, 82 - }, nil 83 - } 84 - 85 - // loadRepos loads all git repositories from the given directory 86 - func loadRepos(repoDir string) ([]*git.Repo, error) { 87 - entries, err := git.ListRepos(repoDir) 88 - if err != nil { 89 - return nil, err 90 - } 91 - 92 - repos := make([]*git.Repo, 0, len(entries)) 93 - for _, entry := range entries { 94 - if !strings.HasSuffix(entry.Name(), ".git") { 95 - continue 96 - } 97 - repo, err := git.NewRepo(repoDir, entry.Name()) 98 - if err != nil { 99 - slog.Error("error loading repo", "name", entry.Name(), "error", err) 100 - continue 101 - } 102 - repos = append(repos, repo) 103 - } 104 - 105 - return repos, nil 106 - } 107 - 108 - // Init initializes the model 109 - func (m Model) Init() tea.Cmd { 110 - return nil 111 - } 112 - 113 - // Update handles all the messages and updates the model accordingly 114 - func (m Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) { 115 - var cmds []tea.Cmd 116 - 117 - switch msg := msg.(type) { 118 - case tea.KeyMsg: 119 - switch { 120 - case key.Matches(msg, m.keys.Quit): 121 - return m, tea.Quit 122 - case key.Matches(msg, m.keys.Help): 123 - m.help.ShowAll = !m.help.ShowAll 124 - } 125 - 126 - switch m.activeView { 127 - case ViewList: 128 - var cmd tea.Cmd 129 - m.repoList, cmd = m.repoList.Update(msg) 130 - cmds = append(cmds, cmd) 131 - 132 - if m.repoList.FilterState() == list.Filtering { 133 - break 134 - } 135 - 136 - switch { 137 - case key.Matches(msg, m.keys.Edit): 138 - if len(m.repos) == 0 { 139 - m.repoList.NewStatusMessage("No repositories to edit") 140 - break 141 - } 142 - 143 - selectedItem := m.repoList.SelectedItem().(repoItem) 144 - m.repoForm.selectedRepo = selectedItem.repo 145 - 146 - m.repoForm.setValues(selectedItem.repo) 147 - m.activeView = ViewForm 148 - return m, textinput.Blink 149 - 150 - case key.Matches(msg, m.keys.Delete): 151 - if len(m.repos) == 0 { 152 - m.repoList.NewStatusMessage("No repositories to delete") 153 - break 154 - } 155 - 156 - m.activeView = ViewConfirmDelete 157 - } 158 - 159 - case ViewForm: 160 - var cmd tea.Cmd 161 - m.repoForm, cmd = m.repoForm.Update(msg) 162 - cmds = append(cmds, cmd) 163 - 164 - if m.repoForm.done { 165 - if m.repoForm.save { 166 - selectedRepo := m.repoForm.selectedRepo 167 - repoDir := filepath.Dir(selectedRepo.Path()) 168 - oldName := selectedRepo.Name() 169 - newName := m.repoForm.inputs[0].Value() 170 - 171 - var renamed bool 172 - if oldName != newName { 173 - if err := git.RenameRepo(repoDir, oldName, newName); err != nil { 174 - m.repoList.NewStatusMessage(fmt.Sprintf("Error renaming repo: %s", err)) 175 - } else { 176 - m.repoList.NewStatusMessage(fmt.Sprintf("Repository renamed from %s to %s", oldName, newName)) 177 - renamed = true 178 - } 179 - } 180 - 181 - if renamed { 182 - if newRepo, err := git.NewRepo(repoDir, newName+".git"); err == nil { 183 - selectedRepo = newRepo 184 - } else { 185 - m.repoList.NewStatusMessage(fmt.Sprintf("Error loading renamed repo: %s", err)) 186 - } 187 - } 188 - 189 - selectedRepo.Meta.Description = m.repoForm.inputs[1].Value() 190 - selectedRepo.Meta.Private = m.repoForm.isPrivate 191 - 192 - tags := make(git.TagSet) 193 - for _, tag := range strings.Split(m.repoForm.inputs[2].Value(), ",") { 194 - tag = strings.TrimSpace(tag) 195 - if tag != "" { 196 - tags.Add(tag) 197 - } 198 - } 199 - selectedRepo.Meta.Tags = tags 200 - 201 - if err := selectedRepo.SaveMeta(); err != nil { 202 - m.repoList.NewStatusMessage(fmt.Sprintf("Error saving repo metadata: %s", err)) 203 - } else if !renamed { 204 - m.repoList.NewStatusMessage("Repository updated successfully") 205 - } 206 - } 207 - 208 - m.repoForm.done = false 209 - m.repoForm.save = false 210 - m.activeView = ViewList 211 - 212 - if repos, err := loadRepos(m.repoDir); err == nil { 213 - m.repos = repos 214 - items := make([]list.Item, len(repos)) 215 - for i, repo := range repos { 216 - items[i] = repoItem{repo: repo} 217 - } 218 - m.repoList.SetItems(items) 219 - } 220 - } 221 - 222 - case ViewConfirmDelete: 223 - switch { 224 - case key.Matches(msg, m.keys.Confirm): 225 - selectedItem := m.repoList.SelectedItem().(repoItem) 226 - repo := selectedItem.repo 227 - 228 - if err := git.DeleteRepo(repo.Path()); err != nil { 229 - m.repoList.NewStatusMessage(fmt.Sprintf("Error deleting repo: %s", err)) 230 - } else { 231 - m.repoList.NewStatusMessage(fmt.Sprintf("Repository %s deleted", repo.Name())) 232 - 233 - if repos, err := loadRepos(m.repoDir); err == nil { 234 - m.repos = repos 235 - items := make([]list.Item, len(repos)) 236 - for i, repo := range repos { 237 - items[i] = repoItem{repo: repo} 238 - } 239 - m.repoList.SetItems(items) 240 - } 241 - } 242 - m.activeView = ViewList 243 - 244 - case key.Matches(msg, m.keys.Cancel): 245 - m.activeView = ViewList 246 - } 247 - } 248 - 249 - case tea.WindowSizeMsg: 250 - m.width = msg.Width 251 - m.height = msg.Height 252 - 253 - headerHeight := 3 254 - footerHeight := 2 255 - 256 - m.repoList.SetSize(msg.Width, msg.Height-headerHeight-footerHeight) 257 - m.repoForm.setSize(msg.Width, msg.Height) 258 - 259 - m.help.Width = msg.Width 260 - } 261 - 262 - return m, tea.Batch(cmds...) 263 - } 264 - 265 - // View renders the current UI 266 - func (m Model) View() string { 267 - switch m.activeView { 268 - case ViewList: 269 - return fmt.Sprintf("%s\n%s", m.repoList.View(), m.help.View(m.keys)) 270 - 271 - case ViewForm: 272 - return m.repoForm.View() 273 - 274 - case ViewConfirmDelete: 275 - selectedItem := m.repoList.SelectedItem().(repoItem) 276 - repo := selectedItem.repo 277 - 278 - confirmStyle := lipgloss.NewStyle(). 279 - BorderStyle(lipgloss.RoundedBorder()). 280 - BorderForeground(lipgloss.Color("170")). 281 - Padding(1, 2). 282 - Width(m.width - 4). 283 - Align(lipgloss.Center) 284 - 285 - confirmText := fmt.Sprintf( 286 - "Are you sure you want to delete repository '%s'?\n\nThis action cannot be undone!\n\nPress y to confirm or n to cancel.", 287 - repo.Name(), 288 - ) 289 - 290 - return confirmStyle.Render(confirmText) 291 - } 292 - 293 - return "" 294 - } 295 - 296 - // Start runs the TUI 297 - func Start(s ssh.Session, repoDir string) error { 298 - model, err := New(s, repoDir) 299 - if err != nil { 300 - return err 301 - } 302 - 303 - // Get terminal dimensions from SSH session if available 304 - pty, _, isPty := s.Pty() 305 - if isPty && pty.Window.Width > 0 && pty.Window.Height > 0 { 306 - // Initialize with correct size 307 - model.width = pty.Window.Width 308 - model.height = pty.Window.Height 309 - 310 - headerHeight := 3 311 - footerHeight := 2 312 - model.repoList.SetSize(pty.Window.Width, pty.Window.Height-headerHeight-footerHeight) 313 - model.repoForm.setSize(pty.Window.Width, pty.Window.Height) 314 - model.help.Width = pty.Window.Width 315 - } 316 - 317 - p := tea.NewProgram(model, tea.WithAltScreen(), tea.WithMouseCellMotion(), tea.WithInput(s), tea.WithOutput(s)) 318 - 319 - _, err = p.Run() 320 - return err 321 - }